Unity Grayscale Shader for Sprite Overlays & More!

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).

Grayscale shader example with a square sprite on NGUI (Next Generation UI)

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.

9 Comments on “Unity Grayscale Shader for Sprite Overlays & More!”

    1. 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)

  1. 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?

  2. 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).

  3. 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

  4. 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
    }

  5. 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!

Leave a Reply

Your email address will not be published.