Shadow problem of android platform [Vert Frag Shader]

Hello, I’m experience weird issue about shadow on Android platform.

As you can see in the screenshot, Direction Light cast big shadow near the horizon.

I’m using
‘Receiving shadows’
Example Shader on this document (page below)

This issue happen when you switching platform to android.

I guess this issue related with shadow distance but not sure.
How can I fix this issue?

Is there any workaround not using ‘LIGHTING_COORDS’ or ‘SHADOW_COORDS’ in vert, frag shader?

Thanks!

[Unity version: 2018.3.12.f1 / 2019.1.2f1]

[Unity Example Code for Receiving shadows]

Shader "Lit/Diffuse With Shadows"
{
    Properties
    {
        [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            Tags {"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            // compile shader into multiple variants, with and without shadows
            // (we don't care about any lightmaps yet, so skip these variants)
            #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
            // shadow helper functions and macros
            #include "AutoLight.cginc"

            struct v2f
            {
                float2 uv : TEXCOORD0;
                SHADOW_COORDS(1) // put shadows data into TEXCOORD1
                fixed3 diff : COLOR0;
                fixed3 ambient : COLOR1;
                float4 pos : SV_POSITION;
            };
            v2f vert (appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                half3 worldNormal = UnityObjectToWorldNormal(v.normal);
                half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
                o.diff = nl * _LightColor0.rgb;
                o.ambient = ShadeSH9(half4(worldNormal,1));
                // compute shadows data
                TRANSFER_SHADOW(o)
                return o;
            }

            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                // compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
                fixed shadow = SHADOW_ATTENUATION(i);
                // darken light's illumination with shadow, keep ambient intact
                fixed3 lighting = i.diff * shadow + i.ambient;
                col.rgb *= lighting;
                return col;
            }
            ENDCG
        }

        // shadow casting support
        UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
    }
}

@ruel Did you find a solution to this issue?
I’ve run into this as well just now.

@Devil_Inside can you try using the “UNITY_SHADOW_COORDS” / “UNITY_TRANSFER_SHADOW” / “UNITY_SHADOW_ATTENUATION” instead of the older macros without “UNITY_” prefix?

UNITY_SHADOW_ATTENUATION and UNITY_TRANSFER_SHADOW require a different set of parameters than their “non UNITY” counterpart. I can’t find any documentation on these macros.
What else should I pass to these macros?

Shader "Unlit/Ground"
{
    SubShader
    {
        Pass
        {
            Tags
            {
                "LightMode" = "ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase
            #include "AutoLight.cginc"


            struct v2f
            {
                float4 pos : SV_POSITION;
                UNITY_SHADOW_COORDS(0)
            };


            v2f vert(appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                UNITY_TRANSFER_SHADOW(o)

                return o;
            }

            fixed4 frag(v2f i) : COLOR
            {
                float attenuation = UNITY_SHADOW_ATTENUATION(i);
                fixed4 c = UNITY_LIGHTMODEL_AMBIENT;
                c += fixed4(1.0, 0.0, 0.0, 0.0) * attenuation;
                return c;
            }
            ENDCG
        }
    }
    Fallback "VertexLit"
}

#define UNITY_TRANSFER_SHADOW(a, coord)
“a” is the name of your v2f parameter, “coord” is lightmap UV channel in app2v. No lightmap - put any UV from the app in there.
#define UNITY_SHADOW_ATTENUATION(a, worldPos)
“a” is the name of your v2f parameter, worldPos is the fragment’s position in world space.

1 Like

That worked!
Thanks!
I think a good idea would be to update the documentation here: https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html
and also the Mobile-VertexLit-OnlyDirectionalLights shader that comes built-in with Unity and is affected by this issue.

1 Like

Just tested the new macros in a build and unfortunately one scene, that had very small shadow distance, was glitching, and all the other scenes had slightly worse performance than my previous method.
The method that I was using as a workaround previously is a lerp to cut off any shadows past certain distance:

fixed attenuation = saturate(lerp(SHADOW_ATTENUATION(i), 1.0, (distance(i.worldPos, _WorldSpaceCameraPos) - _Dist)));

Yes, we’re working on shader documentation update :slight_smile:

Can you please submit a bug report?

Just ran into this issue and solved it with the information in this thread. The documentation should really be updated. Unity - Manual: Custom shader fundamentals

I got bitten by this today but shadows still seem to not work with these functions for me. I tried to create a minimal shader that implements this, is it correct?

Shader "Custom/ReceiveShadow" {
    Properties {
        [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight

            #include "UnityCG.cginc"
            #include "AutoLight.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f {
                float2 uv : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                UNITY_SHADOW_COORDS(2)
                float4 pos : SV_POSITION;
            };

            sampler2D _MainTex;

            v2f vert (appdata v) {
                v2f o;
                o.worldPos = mul(UNITY_MATRIX_M, v.vertex);
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                UNITY_TRANSFER_SHADOW(o, float2(0.0, 0.0));
                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                fixed4 col = tex2D(_MainTex, i.uv);
                col *= UNITY_SHADOW_ATTENUATION(i, i.worldPos);
                return col;
            }
            ENDCG
        }
    }
}

The resulting shadows are “flat”, as if they were on the floor but rendered on top of the object. So strange. I am using Unity 2021.38492933--1130024--2022-10-05_23-07.png

I’m having a hard time implementing this with a mixed lighting setup. If I have an object with a vert/frag shader that uses the UNITY_SHADOW_ATTENUATION and has baked lightmap with shadowmask, the behaviour is odd. Up close, it looks correct, but as I get farther away and approach the shadow distance (set in Quality settings), the object becomes dark (shadow_attenuation becomes 0). But once I go far away enough, the object becomes bright again (shadow_attenuation becomes 1)