Geometry shader with shadows not displaying shadows properly

hey all,

I’ve been working for a while, trying to get a geometry shader that supports lighting shadows up and running, so far I have the geometry creating a quad (this is just a place holder for later), and thanks to a few helpful posts around the place, it correctly responds to lighting and casts shadows but when it comes to ‘catching’ the shadows, it seems to just display the shadows from the mesh behind.

1648465--102762--$shadow error.png
(the shadow drawing on top of the quad is actually its own shadow, if looked at from a steeper angle, there are no shadows on the quad itself)

I have tried placing a cube above the quad, which has the same effect.

Here’s the shader so far:

Shader "Custom/Geo_Unlit" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
		Tags {"Queue" = "Geometry" "RenderType"="Opaque" }
		LOD 200
		
        pass{
            Name "ForwardBase"
            Tags {"LightMode" = "ForwardBase"}
            
		    CGPROGRAM

		    sampler2D _MainTex;
            #pragma target 5.0

			#pragma vertex vert
			#pragma geometry geo
			#pragma fragment frag
			#pragma multi_compile_fwdbase

			#include "UnityCG.cginc"
			
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			struct vIn
			{
				float4 pos : POSITION;
				float4 col : COLOR;
			};
			
			struct gfIn
			{
				float4 pos: POSITION;
				float3 norm : NORMAL;
				float4 col : COLOR;
				float3 vlight: TEXCOORD0;
				LIGHTING_COORDS(1,2)
			};

			vIn vert(vIn v)
			{
				vIn o;
				o.pos = v.pos;
				o.col = v.col;
				return o;
			}

			[maxvertexcount(4)]	
			void geo(point vIn v[1], inout TriangleStream<gfIn> ts)
			{
				float h = .5f;
				float4 p[4];
				
				p[0] = float4(-h, 0.0f, -h, 0.0f);
				p[1] = float4(-h, 0.0f,  h, 0.0f);
				p[2] = float4( h, 0.0f, -h, 0.0f);
				p[3] = float4( h, 0.0f,  h, 0.0f);
				
				for (int i = 0; i < 4; ++i)
				{
					gfIn r;
					r.norm = float3(0,1,0);
					r.col = v[0].col;
					
				
					r.pos = mul( UNITY_MATRIX_MVP, v[0].pos + p[i]);
					r.vlight = normalize(ObjSpaceLightDir(v[0].pos + p[i]));
					TRANSFER_VERTEX_TO_FRAGMENT(r);
					ts.Append(r);
				}
			}

			float4 frag(gfIn fin) : COLOR
			{
				float4 t = fin.col;
				fin.vlight = normalize(fin.vlight);
				
				fixed atten = LIGHT_ATTENUATION(fin); 
				fixed diff = saturate(dot(normalize(fin.norm), normalize(fin.vlight)));
				
				fixed4 c;
				c.rgb = UNITY_LIGHTMODEL_AMBIENT.rgb * 2 * t.rgb; 
				c.rgb += (t.rgb * _LightColor0.rgb * diff) * (atten * 2);
				c.a = t.a + _LightColor0.a * atten;
				return c;
			}

		    ENDCG
        }//end pass

      
//////////////////////////////////////////////////////////////////////////////////////////////////////        
///////////////////////////////////Shadow Cast////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
pass{
			Name "ShadowCaster"
            Tags {"LightMode" = "ShadowCaster"}
            
            Fog {Mode Off}
			ZWrite On ZTest Less Cull Off
			Offset 1, 1
			
		    CGPROGRAM

		    sampler2D _MainTex;
            #pragma target 5.0

			#pragma vertex vert
			#pragma geometry geo
			#pragma fragment frag
			#pragma multi_compile_shadowcaster
			#pragma fragmentoption ARB_precision_hint_fastest
			#include "UnityCG.cginc"
			
			struct v2f{
				V2F_SHADOW_CASTER;
			};
			
			struct vIn
			{
				float4 pos : POSITION;
			};


			v2f vert(vIn v)
			{
				v2f o = (v2f)0;
				o.pos = v.pos;
				return o;
			}

			[maxvertexcount(4)]	
			void geo(point v2f v[1], inout TriangleStream<v2f> ts)
			{
				float h = .5f;
				float4 p[4];
				
				p[0] = float4(-h, 0.0f, -h, 0.0f);
				p[1] = float4(-h, 0.0f,  h, 0.0f);
				p[2] = float4( h, 0.0f, -h, 0.0f);
				p[3] = float4( h, 0.0f,  h, 0.0f);
				
				for (int i = 0; i < 4; ++i)
				{
				
					v2f r = v[0];
					r.pos = mul( UNITY_MATRIX_MVP, v[0].pos + p[i]);
					ts.Append(r);
				}
			}

			float4 frag(v2f fin) : COLOR
			{
				SHADOW_CASTER_FRAGMENT(fin)
			}

		    ENDCG
        }//end pass
    }
}

Without ever having written a single geometry shader in my whole life, here’s a hint: you have a forward pass and a shadow-caster pass but no “shadow-collector pass”. I have a hunch that writing one (extremely similar to shadow-caster-pass, check out some #pragma-debug surface shader or something) could well resolve this.

Thanks, that really did give me a nudge in the right direction.

Thought I should post the working shadow collector code.

    pass{
            Name "ShadowCollector"

            Tags {"LightMode" = "ShadowCollector" }

            ZWrite On
            ZTest Less

            CGPROGRAM

            #pragma target 5.0
            #pragma vertex vert
            #pragma geometry geo
            #pragma fragment frag
            #define SHADOW_COLLECTOR_PASS
            #pragma fragmentoption ARB_precision_hint_fastest
            #pragma multi_compile_shadowcollector
          
            #include "UnityCG.cginc"
          

            struct appdata {

                float4 vertex : POSITION;
            };

            struct v2f {
                V2F_SHADOW_COLLECTOR;
            };

            appdata vert (appdata v){
            return v;
            }
          
            [maxvertexcount(4)]  
            void geo(point appdata vert[1], inout TriangleStream<v2f> ts)
            {

              
                float h = .5f;
                float4 p[4];
              
                //offsets slightly along the normal, due to 'shadow acne'
                p[0] = float4(-h, 0.01f, -h, 0.0f);
                p[1] = float4(-h, 0.01f,  h, 0.0f);
                p[2] = float4( h, 0.01f, -h, 0.0f);
                p[3] = float4( h, 0.01f,  h, 0.0f);
              
                for (int i = 0; i < 4; ++i)
                {
                    v2f o;
                  
                    //unity's TRANSFER_SHADOW_COLLECTOR macro insists on using 'v', not 'v[0]', as the vertex position
                    appdata v;
                    v.vertex = vert[0].vertex + p[i];

                    TRANSFER_SHADOW_COLLECTOR(o)
                    ts.Append(o);
                  
                }
            }
  
            half4 frag (v2f i) : COLOR
            {
          
                SHADOW_COLLECTOR_FRAGMENT(i)
            }

        ENDCG

        }//end pass