Troubleshooting Dark Shadows and Material Darkness in Custom URP Shader

I’m writing a custom shader in the URP, and I’m having trouble figuring two things out with it.

  • Dark Shadows: The shadows on materials using my shader are unnaturally dark. For instance, if the ground has a texture, it is too dark to be seen in these shadowed areas.

  • Material Darkness: Materials rendered with this shader seem slightly darker overall compared to those rendered with Unity’s default URP materials set to the same color.

Any clues on how to fix this? I’d appreciate the help.

shader:

Shader "Custom/TestShader" {
    Properties{
        [Header(Surface options)]
        [MainTexture] _ColorMap("Color", 2D) = "white" {}
        [MainColor] _ColorTint("Tint", Color) = (1, 1, 1, 1)
        _Smoothness("Smoothness", Range(0, 1)) = 0
    }

    SubShader{
        Tags{
            "RenderPipeline" = "UniversalPipeline"
        }

        Pass {
            Name "ForwardLit"
            Tags{"LightMode" = "UniversalForward"}

            HLSLPROGRAM

           
            #if UNITY_VERSION >= 202120
                #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
            #else
                #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
                #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            #endif
            #pragma multi_compile_fragment _ _SHADOWS_SOFT

            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            TEXTURE2D(_ColorMap); SAMPLER(sampler_ColorMap);
            float4 _ColorMap_ST;
            float4 _ColorTint;
            float _Smoothness;


            struct appdata {
                float3 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct v2f {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 positionWS : TEXCOORD1;
                float3 normalWS : TEXCOORD2;
            };

            v2f vert(appdata v) {
                v2f o;

                VertexPositionInputs posnInputs = GetVertexPositionInputs(v.positionOS);
                VertexNormalInputs normInputs = GetVertexNormalInputs(v.normalOS);

                o.positionCS = posnInputs.positionCS;
                o.uv = TRANSFORM_TEX(v.uv, _ColorMap);
                o.normalWS = normInputs.normalWS;
                o.positionWS = posnInputs.positionWS;
                return o;
            }

            float4 frag(v2f i) : SV_TARGET{
                float2 uv = i.uv;
                float4 colorSample = SAMPLE_TEXTURE2D(_ColorMap, sampler_ColorMap, uv);

                InputData lightingInput = (InputData)0;
                lightingInput.positionWS = i.positionWS;
                lightingInput.normalWS = normalize(i.normalWS);
                lightingInput.viewDirectionWS = GetWorldSpaceNormalizeViewDir(i.positionWS);
                lightingInput.shadowCoord = TransformWorldToShadowCoord(i.positionWS);
               
                SurfaceData surfaceInput = (SurfaceData)0;
                surfaceInput.albedo = colorSample.rgb * _ColorTint.rgb;
                surfaceInput.alpha = colorSample.a * _ColorTint.a;
                surfaceInput.specular = 1;
                surfaceInput.smoothness = _Smoothness;

                return UniversalFragmentPBR(lightingInput, surfaceInput);
            }

            ENDHLSL
        }

        Pass {
            Name "ShadowCaster"
            Tags{"LightMode" = "ShadowCaster"}

            ColorMask 0

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            struct appdata {
                float3 positionOS : POSITION;
                float3 normalOS : NORMAL;
            };

            struct v2f {
                float4 positionCS : SV_POSITION;
            };

            float3 _LightDirection;

            float4 GetShadowCasterPositionCS(float3 positionWS, float3 normalWS) {
                float3 lightDirectionWS = _LightDirection;
                float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
                #if UNITY_REVERSED_Z
                    positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE);
                #else
                    positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE);
                #endif
                return positionCS;
            }

            v2f vert(appdata input) {
                v2f output;

                VertexPositionInputs posnInputs = GetVertexPositionInputs(input.positionOS);
                VertexNormalInputs normInputs = GetVertexNormalInputs(input.normalOS);

                output.positionCS = GetShadowCasterPositionCS(posnInputs.positionWS, normInputs.normalWS);
                return output;
            }

            float4 frag(v2f input) : SV_TARGET {
                return 0;
            }
            ENDHLSL
        }
    }
}

Still stuck after a full day of troubleshooting. Can someone direct me to relevant resources, or offer some guidance? I can’t move forward with my project until this is resolved.

Quick update: I tried merging my custom shader with Unity’s default URP shader by copy/pasting the properties and the pass from my shader into the other. Didn’t work.
I still have the same issues with lighting and shadows. Plus, now I’ve lost access to my old shader properties due to the default URP shader’s custom inspector. At this point, I feel like I’m grasping at straws with desperate attempts to make this work.

Looks like objects using the custom shader lack environment lighting.

Not sure if this is relevant, but you can try calculating the missing lightingInput.normalizedScreenSpaceUV and see if it works.

Link to repo:

lightingInput.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS);