This Unity grayscale shader allows everything behind an object mask be rendered in grayscale.
Set the material of a Unity Canvas Image / Raw Image or NGUI UITexture to this shader and everything with a lower depth index will be rendered in grayscale (black and white).
Try the grayscale shader yourself!
Save the shader below and if you’re using Unity Canvas add a custom material using the shader to your sprite renderer. If you’re using NGUI create a UI Texture as the overlay texture and set the shader to the grayscale shader.
Make sure the depth layer of the grayscale texture is higher than the other textures you’re wanting to be affected. If you want certain objects to ignore the grayscale effect too you can just render them in front of the mask overlay.
Shader "Unity3dTips/GrayscaleTransparent" { Properties { _MainTex ("Texture", 2D) = "white" {} _Color("Color", Color) = (1,1,1,1) } SubShader { GrabPass { "_BackgroundTexture" } Pass { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } ZWrite Off ZTest Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _BackgroundTexture; sampler2D _MainTex; fixed4 _MainTex_ST; struct v2f { fixed4 vertex : SV_POSITION; fixed4 grabUV : TEXCOORD1; }; struct appdata { fixed4 vertex : POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.grabUV = ComputeGrabScreenPos(o.vertex); return o; } fixed4 frag(v2f i) : SV_Target { fixed4 bgc = tex2Dproj(_BackgroundTexture, i.grabUV); return (bgc.r + bgc.g + bgc.b) / 3; } ENDCG } } FallBack Off }
How the Unity grayscale shader works
The shader uses a grabpass which reads the render of the screen prior to this active shader render then calculates the coordinates of the mask sprite so only the area which the mask covers is rendered, simulating transparency.
The RGB colour data from the pixels is averaged with red plus green plus blue then divided by 3 to get the wanted colour of the gray pixel.
amazing tips
how do i save the shader?
Make a new file named GrayscaleTransparent.shader (or any name is fine) then copy the shader code from here into that file.
Then on your material you can select the shader from Unity3dTips > GrayscaleTransparent in the shader menu (or just drag the shader from the hierarchy onto your material)
Hey there. I tried all that, but I get:
“Shader properties can’t be added to this global property sheet. Trying to add _BackgroundTexture (type 3 count 1)UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)”
a number of times. Any idea as to what causes that?
Also, your term “Unity Canvas Sprite Renderer” is confusing. There’s no such thing as far as I see in 2019.2. You’re either talking about the Canvas Renderer or the Sprite Renderer (not a canvas object).
Pity its not working with mask.. I need everything which is out of some radius around player (top-down 2D game) to be grayscale , and place around player to be colorfull. Is there a way how to achieve that? I would like to use big sprite with hole in center to use it as mask. Sorry for my English.. hope you understand me. 🙂 Thanks
Great, thanks a lot! The only question is how can I add alpha support, I want it to fade in
Thanks.
Hi, great shader!
I’ve modified it a bit so the alpha control the effect amount
Shader “UI/GrayscaleTransparent”
{
Properties
{
_MainTex(“Texture”, 2D) = “white” {}
_Color(“Color”, Color) = (1,1,1,1)
}
SubShader
{
GrabPass { “_BackgroundTexture” }
Pass
{
Tags { “Queue” = “Transparent” “RenderType” = “Transparent” }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
ZTest Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include “UnityCG.cginc”
sampler2D _BackgroundTexture;
sampler2D _MainTex;
fixed4 _MainTex_ST;
fixed4 _Color;
struct v2f
{
fixed4 vertex : SV_POSITION;
fixed4 color : COLOR;
fixed4 grabUV : TEXCOORD1;
};
struct appdata
{
fixed4 vertex : POSITION;
fixed4 color : COLOR;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.grabUV = ComputeGrabScreenPos(o.vertex);
o.color = v.color * _Color;
return o;
};
fixed4 frag(v2f i) : SV_Target
{
fixed4 texcol = tex2Dproj(_BackgroundTexture, i.grabUV);
texcol.rgb = lerp(texcol.rgb, dot(texcol.rgb, float3(0.3, 0.59, 0.11)), texcol.a);
texcol = texcol * i.color;
return texcol;
};
ENDCG
}
}
FallBack Off
}
Hey, great shader!
Do you know how to use this shader using Universal Render Pipeline? At this moment, GrabPass is not supported anymore, so, do you have a way to do this?
I’ve read something about CameraTextureOpaque and other stuff, but I’m not sure about how to proceed with that.
Thanks!