How to make clip() work with Ambient Occlusion?

Hey so I’ve made a shader that dithers the geometry behind the player so they’re always possible to be seen! But I think even the clipped geometry is writing in the depth buffer, causing a bug on this Ambient Occlusion effect. Is there any fix to this? Am I thinking this in the wrong way?

Here’s an image with the buggy outcome:177831-screenshotbugsmall.png

Here’s the shader code:

SubShader
    {
        Tags { "RenderType"="Opaque" "Queue" = "Geometry-2" }
        //Tags {"Queue" = "Transparent" "RenderType"="Transparent" }
        

        LOD 200
        //Blend SrcAlpha OneMinusSrcAlpha
        Cull Back
        ZWrite On
        ZTest LEqual
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 ground = tex2D (_GroundTex, IN.worldPos.xz) * _Color;
            fixed4 wallA = tex2D (_WallTex, IN.worldPos.xy) * _Color;
            fixed4 wallB = tex2D (_WallTex, IN.worldPos.zy) * _Color;

            fixed4 c = ground * abs(IN.worldNormal.y) + wallA * abs(IN.worldNormal.z) + wallB * abs(IN.worldNormal.x);
            o.Albedo = c.rgb;

            //float ditherValue = GetDitherValue(IN.screenPos.xy / IN.screenPos.w, _DitheringTex, _DitheringTex_TexelSize);
            float ditherValue = GetDitherValue(IN.screenPos.xy / IN.screenPos.w, _DitheringTex, _DitheringTex_TexelSize);
            
            ClipParts(IN, ditherValue);

            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
        
        LOD 200
        //Blend SrcAlpha OneMinusSrcAlpha
        Cull Front
        ZWrite On
        ZTest LEqual
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            //float ditherValue = GetDitherValue(IN.screenPos.xy / IN.screenPos.w, _DitheringTex, _DitheringTex_TexelSize);
            float ditherValue = GetDitherValue(IN.screenPos.xy / IN.screenPos.w, _DitheringTex, _DitheringTex_TexelSize);

            o.Albedo = fixed3(0.,0.,0.);
            ClipParts(IN, ditherValue);
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = 1.;

        }
        ENDCG
    }

I’ve removed some functions I call for the sake of making the question smaller.

Tell me if you need more info.

The depth texture is tied into the shadowcaster pass of a shader - in this case you are updating the visibility of the main shader without affecting the shadowcaster pass, so the depth texture will think the whole object is still being rendered. With surface shaders this is a fairly simple fix - just add the ‘addshadow’ parameter to the surface declaration;

#pragma surface surf Standard fullforwardshadows addshadow

From what I can see this shader can also be done in a single pass rather than two;

struct Input
{
    ...
    float3 viewDir;
    ...
};

...

Cull Off

CGPROGRAM
#pragma surface surf Standard fullforwardshadows addshadow
 
#pragma target 3.0

void surf (Input IN, inout SurfaceOutputStandard o)
{
    // Albedo comes from a texture tinted by color
    fixed4 ground = tex2D (_GroundTex, IN.worldPos.xz) * _Color;
    fixed4 wallA = tex2D (_WallTex, IN.worldPos.xy) * _Color;
    fixed4 wallB = tex2D (_WallTex, IN.worldPos.zy) * _Color;
 
    fixed4 c = ground * abs(IN.worldNormal.y) + wallA * abs(IN.worldNormal.z) + wallB * abs(IN.worldNormal.x);
    o.Albedo = c.rgb * (dot (IN.viewDir, IN.worldNormal) < 0);
 
    float ditherValue = GetDitherValue(IN.screenPos.xy / IN.screenPos.w, _DitheringTex, _DitheringTex_TexelSize);
             
    ClipParts(IN, ditherValue);
 
    o.Metallic = _Metallic;
    o.Smoothness = _Glossiness;
    o.Alpha = c.a;
}
ENDCG

The basic idea is to check if we are drawing a backface and just manipulate the parts that need to change on each side of the mesh (dot (viewDir, worldNormal) will be positive if we are drawing a backface).