Help with understanding GrabPass

I made a shader for my particle system that blends the alpha values, writes it to the alpha channel, grabs the screen content using GrabPass { } and determines if the combined alpha blended values written are passed a certain threshold. If they are, I write a color. If not, write nothing.

The problem I’m having is that when I use just GrabPass { }, it works perfectly. But when I try to used GrabPass { “some name” }, it stops working. After some debugging, I found that the alpha its getting from the _some name texture is 0 sometimes and correct all the other times, which makes my particles flicker. Any idea why using GrabPass { “some name” } is causing this problem?

Shader "Kolora/KoloraPaint" {
Properties {
_Color ("Color", Color) = (1.0, 1.0, 1.0, 1.0)
	_MainTex ("Main Texture", 2D) = "" {}
	_DarknessRamp ("Darkness Ramp", 2D) = "" {}
	_Threshold ("Alpha Threshold", Range(0,1)) = 0.6
	_OutlineWidth ("Outline Width", Range(0.0,0.2)) = 0.2
}
Category {

	Tags { "Queue"="Transparent" }
	
	Cull Off Lighting Off ZWrite Off

	BindChannels 
	{
		Bind "Color", color
		Bind "Vertex", vertex
		Bind "TexCoord", texcoord
	}

	SubShader {
		Pass 
		{	
			ColorMask A
			Blend SrcAlpha One

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest 
			#pragma multi_compile_particles
			#include "UnityCG.cginc"

			sampler2D _MainTex;
			fixed4 _Color;
			float4 _MainTex_ST;

			struct appdata {
				float4 vertex : POSITION;
				fixed4 color : COLOR;
				half2 texcoord : TEXCOORD0;
			};

			struct v2f {
				float4 vertex : POSITION;
				fixed4 color : COLOR;
				half2 texcoord : TEXCOORD0;
			};

			v2f vert(appdata v) {
				v2f o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
				o.color = v.color * _Color;
				return o;
			}

			fixed4 frag (v2f i) : COLOR
			{
				fixed4 col = i.color * tex2D(_MainTex, i.texcoord);
				return col;
			}
			ENDCG
		}

		GrabPass { "_PaintTexture" }

		Pass
		{
			ColorMask RGB
			Blend SrcAlpha OneMinusSrcAlpha

			CGPROGRAM
// Upgrade NOTE: excluded shader from Xbox360; has structs without semantics (struct v2f members screenPos)
#pragma exclude_renderers xbox360
			#pragma vertex vert
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest 
			#pragma multi_compile_particles
			#include "UnityCG.cginc"

			float _Threshold;
			fixed4 _Color;
			sampler2D _PaintTexture;
			float _OutlineWidth;
			sampler2D _MainTex;
			float4 _MainTex_ST;

			struct appdata {
				float4 vertex : POSITION;
				fixed4 color : COLOR;
				half2 texcoord : TEXCOORD0;
			};

			struct v2f {
				float4 pos : POSITION;
				float4 color : COLOR;
				float2 texcoord : TEXCOORD0;
				float4 screenPos;
			};

			v2f vert(appdata v) {
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.color = v.color * _Color;
				o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
				o.screenPos = ComputeGrabScreenPos(o.pos);
				return o;
			}

			fixed4 frag (v2f i) : COLOR
			{
				float4 alpha = tex2D(_MainTex, i.texcoord).a;

				if(alpha == 0)
					return fixed4(0,0,0,0);
				else
				{
					alpha = tex2Dproj(_PaintTexture, UNITY_PROJ_COORD(i.screenPos)).a;
				
					if(alpha >= _Threshold)
					{
						return i.color;
					}
					else if(alpha > _Threshold - _OutlineWidth)
					{
						return fixed4(0,0,0,i.color.a);
					}
					else if(alpha == 0)
						return fixed4(0,0,0,.5);
					else
						return fixed4(1,.5,1,.5);
				}
			}

			ENDCG
		}
	}
	// ---- Dual texture cards
	SubShader {
		Pass {
			SetTexture [_MainTex] {
				constantColor [_TintColor]
				combine constant * primary
			}
			SetTexture [_MainTex] {
				combine texture * previous DOUBLE
			}
		}
	}
	
	// ---- Single texture cards (does not do color tint)
	SubShader {
		Pass {
			SetTexture [_MainTex] {
				combine texture * primary
			}
	}
}
}
}

Hi tbugrara,

From your description Id say that the problem you are having is that the GrabPass{“something”} functionality is different to the GrabPass{} functionality in that it only grabs a copy of the screen content once per frame. Even when you call it multiple times. After Its grabbed the screen the first time, that captured data is reused. So any changes made in your scene after the first grab will not be updated.

Cheers
Bruno