Search Unity

Transparent shader for DOF - needs to add to zbuffer

Discussion in 'Shaders' started by trzmiel, Feb 13, 2018.

  1. trzmiel

    trzmiel

    Joined:
    Nov 5, 2013
    Posts:
    28
    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:
    Code (CSharp):
    1. Shader "CHMIEL/Transparent Diffuse ZWrite" {
    2.    
    3.     Properties{
    4.         _Color("Main Color", Color) = (1,1,1,1)
    5.         _MainTex("Base (RGB) Trans (A)", 2D) = "white" {}
    6.     }
    7.  
    8.         SubShader{
    9.         Tags{ "Queue" = "Transparent-20" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
    10.         LOD 200
    11.         ZWrite On
    12.         ZTest LEqual
    13.  
    14.         CGPROGRAM
    15. #pragma surface surf Lambert alpha
    16.  
    17.         sampler2D _MainTex;
    18.     fixed4 _Color;
    19.  
    20.     struct Input {
    21.         float2 uv_MainTex;
    22.     };
    23.  
    24.     void surf(Input IN, inout SurfaceOutput o) {
    25.         fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    26.         o.Albedo = c.rgb;
    27.         o.Alpha = c.a;
    28.     }
    29.     ENDCG
    30.     }
    31.  
    32.         Fallback "Transparent/VertexLit"
    33. }
     

    Attached Files:

  2. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    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
     
  3. trzmiel

    trzmiel

    Joined:
    Nov 5, 2013
    Posts:
    28
    Oh, is it impossible to render the transparent objects as transparent but with modifying z-buffer as opaque objects do?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    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".
     
    FusRoDahh likes this.
  5. FusRoDahh

    FusRoDahh

    Joined:
    Jan 20, 2015
    Posts:
    21
    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. :)
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Two better ways:
    1. 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.
    2. Set the renderer component's shadow type to be Shadows Only.
     
    FusRoDahh likes this.
  7. FusRoDahh

    FusRoDahh

    Joined:
    Jan 20, 2015
    Posts:
    21
    Thanks a lot for improvement suggestions :)