Transparent shader for DOF - needs to add to zbuffer

OK, I really can’t solve this problem and I need your help.
Here is my situation: 2 cells with an opaque nucleus and semi-transparent envelope (see attached image).
The first bigger cell is in front of the smaller one. The Depth of Field effect acts correctly on nucleus - the foreground nucleus is blurred and the background nucleus is in a sharp zone. The problem is with semitransparent envelopes. Transparent shader does not modify z-buffer and that’s why each envelope is blurred. The effect would be acceptable to me if the first/closest envelope would set z-buffer to its depth.
How to do this?
My transparent shader code:

Shader "CHMIEL/Transparent Diffuse ZWrite" {
   
    Properties{
        _Color("Main Color", Color) = (1,1,1,1)
        _MainTex("Base (RGB) Trans (A)", 2D) = "white" {}
    }

        SubShader{
        Tags{ "Queue" = "Transparent-20" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
        LOD 200
        ZWrite On
        ZTest LEqual

        CGPROGRAM
#pragma surface surf Lambert alpha

        sampler2D _MainTex;
    fixed4 _Color;

    struct Input {
        float2 uv_MainTex;
    };

    void surf(Input IN, inout SurfaceOutput o) {
        fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
        o.Albedo = c.rgb;
        o.Alpha = c.a;
    }
    ENDCG
    }

        Fallback "Transparent/VertexLit"
}

Transparency writes in forward pass after depth and opaque so any depth of field will only affect opaque. There are several strategies for tackling it but that needs much more information because they’re all hacks.

Looking at the picture, I would instead modify the shader to get depth from position and blur it yourself to match, either via lower mip maps or with lerping between a sharp cell* image for focused parts and a blurry cell* image for unfocused parts.

  • semi-transparent envelope

Oh, is it impossible to render the transparent objects as transparent but with modifying z-buffer as opaque objects do?

Unity does not include objects that are part of the transparent queues in the depth texture used by the DOF effect. The depth texture isn’t necessarily the same as the z buffer / depth buffer, though it generally matches the depth buffer just after the opaque queues have finished rendering. If you’re rendering using the deferred path the depth texture is a copy of the depth buffer, and has to match the depth of the opaque objects that have rendered for opaque lighting to work properly. For the forward path the depth texture is generated before rendering the main scene as a separate render pass of the entire view. This may or may not match the depth buffer from the opaque pass, but it still only contains those objects rendered during the opaque queue.

If you want to inject transparent objects into the depth texture you would need to either render your transparent objects as part of the opaque queue, which may cause problems with sorting, or you can render another object during the opaque queue that doesn’t actually render anything visible during the opaque pass, but has a shadow caster pass or Fallback "VertexLit".

1 Like

Thanks a lot. This is exactly what I was looking for. For anyone looking for information on Shadow Caster pass, refer to THIS thread. To stop anything rendering during opaque pass, simply call discard in fragment shader. Solved issue for me. If there are better ways to achieve this, kindly let me know. :slight_smile:

Two better ways:

  • Have a vertex shader that sets the vertex positions / output position to float4(0.0, 0.0, 0.0, 0.0). That’ll make the GPU skip trying to render it with the fragment shader at all.
  • Set the renderer component’s shadow type to be Shadows Only.
1 Like

Thanks a lot for improvement suggestions :slight_smile: