Soft Alpha Cutoff from Reference Texture

To give a brief explanation, what I’m trying to smoothly transition from one camera to another. The first camera’s scene is rendered to a texture, which is displayed in front of the second camera, and then faded out to provide a smooth transition. The transition is blended using a second grayscale texture that provides the transition effect we desire.Said transition texture might look something like this:

I’m not very well experienced at writing shaders, but I put together something rather basic using a Cutoff range to control the current state of the transition. The shader is as follows:

Shader "Custom/TransitionShader" {
	Properties {
		_Cutoff ("Cutoff", Range (0,1)) = 0.5 
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_AlphaTex ("Mask", 2D) = "white" {}
	}
	SubShader {
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert alpha

		sampler2D _MainTex;
		sampler2D _AlphaTex;
		float _Cutoff;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			float d = tex2D (_AlphaTex, IN.uv_MainTex).r; //Doesn't matter what color we take since it's greyscale
			o.Albedo = c.rgb;

			if(d > _Cutoff)
				o.Alpha = 1;
			else
				o.Alpha = 0;
		}
		ENDCG
	} 
	Fallback "Diffuse"
}

So that works, but there’s two issues.

  • The cutoff is a hard edge; either it displays or it doesn’t. What I really want is a soft cutoff, like scale the alpha from a +/- range from the cutoff using a second range. So for example, So if cutoff is 0.6, and cutoff range is 0.1, a grayscale value of 0.5 should give alpha of 0, and a grayscale value of 0.7 should give alpha of 1. I’m not sure how I’d math this one out though.
  • This shader takes in lighting from the environment, which it shouldn’t since the rendertexture is already lit. Most things I’ve seen on the subject suggest I shouldn’t be using a cg surface shader if I don’t want lighting, or I could specify my own lighting, but I don’t really understand either option. Again I’m pretty dumb with shaders.

Any idea how I could handle these issues?

Edit:

I’ve solved the blending issue with the relatively simple (in hindsight) code:

			float r = _Cutoff * (1 + _CutoffRange * 2) - _CutoffRange;
			o.Alpha = (d - r) * (1 / (_CutoffRange));

Now just to figure out how to do an unlit cg surface shader…

Edit2:

I’ve resolved all the issues. For reference, here’s the final shader:

Shader "Custom/TransitionShader" {
	Properties {
		_Cutoff ("Cutoff", Range (0,1)) = 0.5 
		_CutoffRange ("Cutoff Range", Range (0,1)) = 0.1 
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_AlphaTex ("Mask", 2D) = "white" {}
	}
	SubShader {
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha
		LOD 200
		Lighting OFF
		
		CGPROGRAM
		#pragma surface surf Unlit alpha noambient novertexlights nodirlightmap nolightmap noforwardadd

		half4 LightingUnlit (SurfaceOutput s, half3 dir, half atten) {
			fixed4 c;
			c.rgb = s.Albedo;
			c.a = s.Alpha;
			return c;
		}

		sampler2D _MainTex;
		sampler2D _AlphaTex;
		half _Cutoff;
		half _CutoffRange;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			half d = tex2D (_AlphaTex, IN.uv_MainTex).r;
			o.Albedo = c.rgb;

			half r = _Cutoff * (1 + _CutoffRange * 2) - _CutoffRange;
			o.Alpha = (d - r) * (1 / (_CutoffRange));
		}
		ENDCG
	} 
	Fallback "Diffuse"
}

Feel free to point out any bad looking code. Here’s how it looks in motion:

1 Like

Great shader! Thanks a lot!

Handy shader, but you don’t really need surface shader on post process shaders. Its also faster without it.

if this part is making your image look weird

   float r = _Cutoff * (1 + _CutoffRange * 2) - _CutoffRange;
   o.Alpha = (d - r) * (1 / (_CutoffRange));

try this one:

o.Alpha = saturate((d - _Cutoff) / _CutoffRange);

Hey man, thanks! Exactly what I needed.