Fragment/Vertex shader Casting and Receiving shadows

 There're two parts to this - lets focus on the first Pass block - 

The first block allows the shader to receive shadows. The previous ones were all flat.

The LightMode tag sets it to Forward lighting, which changes it from the default Deferred lighting that Unity uses.  We have some extra #pragma stuff that I don't really understand - apparently it's there so we can have complete control over the lighting?

Some extra #includes are present as well...more functions to do with lighting.

In our appdata struct we're using the NORMAL now.

In the v2f we call the "position"  variable "pos", because later on a TRANSFER_SHADOW function requires that specific name within the struct. It won't recognise "vertex". There's also a SHADOW_COORDS variable, to tell the shadow where to go.

In our vert function we convert the vertex to screenspace, calculate its worldspace normal, then get the dot product between the normal & the light's position. This value is multiplied against the light colour to get our diffuse contribution.
In the frag function we then get the texture info as usual, the strength of the cast shadow (SHADOW_ATTENUATION) and multiply them together.

________________________________________________________________________

The second part to this is the casting of shadows, which is maybe simpler than the receiving...

Firstly there is a "LightMode" = "ShadowCaster" Tag - to state that this pass is casting shadows

There's also a #pragma that does this too 

The appdata is fairly standard, whilst the v2f,  frag and vert parts of this pass all contain short code snippets that just deal with the shadow casting process!

It is probably most important to learn that casting and receiving shadows is defined on the object itself.

Hopefully I can find some more advanced examples of frag/vert shaders that also use things like Specular and maybe even SSS.


 

 Shader "Dave/Unlit/VF_DIFFSHADOWS"
{
    Properties{
        _MainTex("Texture",2D) = "white"{}
    }

    SubShader{

        Pass{
        Tags{"LightMode"="ForwardBase"}//forward lighting
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
        #include "UnityCG.cginc"
        #include "UnityLightingCommon.cginc" //functions to do with lighting
        #include "Lighting.cginc"
        #include "AutoLight.cginc"

        struct appdata{
            float4 vertex :POSITION;
            float4 normal :NORMAL;
            float4 texcoord :TEXCOORD0;
            
                       
        };

        struct v2f{
            float2 uv :TEXCOORD0;
            fixed4 diff : COLOR0;
            //float4 vertex :SV_POSITION; was vertex, now pos
            float4 pos : SV_POSITION;
            SHADOW_COORDS(1)
        };

        v2f vert(appdata v)
        {
            v2f o;
            //o.vertex = UnityObjectToClipPos(v.vertex); //changed to pos for the transfer shadow
            o.pos = UnityObjectToClipPos(v.vertex); //<-v.vertex is coming from appdata, so remains "vertex"
            o.uv = v.texcoord;
            half3 worldNormal = UnityObjectToWorldNormal(v.normal);
            half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
            o.diff = nl * _LightColor0;
            TRANSFER_SHADOW(o)
            return o;            
        }

        sampler2D _MainTex;

        fixed4 frag(v2f i): SV_Target
        {
            fixed4 col = tex2D(_MainTex,i.uv);
            fixed4 shadow = SHADOW_ATTENUATION(i);
            col *= i.diff*shadow;
            return col;

        }
            ENDCG
        }


        Pass //pass for casting shadows
        {
            Tags{"LightMode" = "ShadowCaster"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_shadowcaster//tells compliler we are casting shadows
            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;

            };

            struct v2f {
            V2F_SHADOW_CASTER;//appdata gets converted to shadow caster

            };

            v2f vert(appdata v) {
                v2f o;
                TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
                return o;
            }


            float4 frag(v2f i):SV_Target
            {
                SHADOW_CASTER_FRAGMENT(i)
            }
        

            ENDCG


        
        
        }

    }
             

}

Comments

Popular posts from this blog

setting VFX graph properties using C#

scripting custom render texture creation, assignment, shaders