Search Unity

Wrong order of ForwardBase and ForwardAdd passes

Discussion in 'Shaders' started by l_skupkov, May 20, 2019.

  1. l_skupkov

    l_skupkov

    Joined:
    Jan 30, 2019
    Posts:
    3
    I'm trying to write a shader that will work like a regular Diffuse, but I can change the transparency from the code in runtime. To solve the problem of the z order I added a pre-pass, as I have been advised everywhere:

    Code (CSharp):
    1. Pass {
    2.     ColorMask 0
    3.     ZWrite On
    4. }
    But I got a problem, the solution of which I can not find: if the object is illuminated with a per-pixel light (Point or Spot light) pass in some cases ForwardAdd pass is called before ForwardBase. Because of this, pixel light is not visible on the object. I see the wrong order of calls in Frame Debugger.
    For some reason, this depends on the position of the camera: when I move the camera, the object is illuminated either correctly or incorrectly.

    Is it possible to solve this problem?
    My shader:

    Code (CSharp):
    1. Shader "Transparent_Diffuse"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Main Color", Color) = (1,1,1,1)
    6.         _MainTex("Base (RGB)", 2D) = "white" {}
    7.     }
    8.  
    9.     SubShader
    10.     {
    11.         Tags {"Queue" = "Transparent" "RenderType" = "Transparent"}
    12.  
    13.         Pass
    14.         {
    15.             ZWrite On
    16.             ColorMask 0
    17.         }
    18.  
    19.         CGPROGRAM
    20.         #pragma surface surf Lambert alpha:fade
    21.  
    22.         sampler2D _MainTex;
    23.  
    24.         fixed4 _Color;
    25.  
    26.         struct Input {
    27.             float2 uv_MainTex;
    28.  
    29.         };
    30.  
    31.         void surf(Input IN, inout SurfaceOutput o) {
    32.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    33.             o.Albedo = c.rgb;
    34.             o.Alpha = _Color.a;
    35.         }
    36.         ENDCG
    37.     }
    38.  
    39.     Fallback "Mobile/VertexLit"
    40. }
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,334
    That ... should not happen. It's certainly not something I've ever seen occur or am able to reproduce, and I often rely heavily on shader pass execution order being consistent. It sounds like a bug on Unity's side, there's not anything you should be able to do to cause that. I would recommend you report it as a bug from the editor; Help > Report Bug...

    If you remove the extra pass, does it still happen? If not, as a work around you might be able to use two separate materials, one with just the depth write pass, and the other with the surface shader passes.
     
  3. l_skupkov

    l_skupkov

    Joined:
    Jan 30, 2019
    Posts:
    3
    The problem is in the extra path, if I remove it, everything works correctly.
     
  4. l_skupkov

    l_skupkov

    Joined:
    Jan 30, 2019
    Posts:
    3
    Update:
    1) The problem is absent for a single object, this only happens when there are many objects on the scene with this shader and at least 2 light points.
    2) This happens with the usual Legacy Diffuse shader, if you add a pre-pass to it
     
  5. paolo_m_ts

    paolo_m_ts

    Joined:
    Oct 22, 2018
    Posts:
    2
    We have the same problem (reproduced in Unity 2018.3.7f1). Adding a depth pre-pass to a surface shader seems to cause ForwardAdd to be sometimes drawn before ForwardBase, depending on the camera's transform.
     
  6. empika

    empika

    Joined:
    Jul 12, 2012
    Posts:
    19
    I have this issue with a surface shader in 2019.1.7 I'm using to help draw a silhouette of the player.

    The shader has an additional pass via UsePass that writes to the stencil buffer, the shader on the player then reads the buffer and draws the silhouette. If I remove the UsePass then the pass order is correct.

    One weird thing is that this only occurs on meshes with the material+shader applied. A sprite renderer using the same material+shader always has correct pass order, I presume this is something to do with the dynamic batching.

    Did anyone manage to fix this? Or did anyone submit the bug? If so a link would be great.
    Thanks!
     
  7. empika

    empika

    Joined:
    Jul 12, 2012
    Posts:
    19
  8. naelstrof

    naelstrof

    Joined:
    Sep 12, 2017
    Posts:
    5
    Can confirm, I have the same problem. Though I'm not using UsePass, I just have extra passes written in for some grass.
    Here's a video for proof: https://files.catbox.moe/2ahpt6.mp4
     
  9. naelstrof

    naelstrof

    Joined:
    Sep 12, 2017
    Posts:
    5
    I fixed the problem by adding the "DisableBatching"="True" to my tags, and it works great as a work-around.
     
  10. empika

    empika

    Joined:
    Jul 12, 2012
    Posts:
    19
    Can confirm, DisableBatching=True fixes the issue. Though obviously this disables batching.