Search Unity

SubShader with "ZWrite Off" visible in Scene View but not in Game Preview

Discussion in 'Shaders' started by BrightBit, Sep 19, 2014.

  1. BrightBit

    BrightBit

    Joined:
    Jan 22, 2013
    Posts:
    265
    I wrote a small shader for a sun object that needs to be drawn right after the skybox. Every other geometry should be drawn on top of the sun. By disabling ZWrite in the SubShader section of my cg shader, I was able to get the result but only in the scene view. The game view won't show the sun at all anymore.

    Do you know why?



    Code (CSharp):
    1. Shader "CustomShaders/SunShader"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Main Color (A=Opacity)", Color) = (1,1,1,1)
    6.         _MainTex ("Base (A=Opacity)", 2D) = "" {}
    7.         _Cutoff ("Alpha cutoff", Range (0,1)) = 0.5
    8.     }
    9.  
    10.     SubShader
    11.     {
    12.         Tags {"Queue" = "Background" }
    13.  
    14.         Pass
    15.         {
    16.             Fog { Mode Off }
    17.  
    18.             ZWrite Off // <-- ###### I'm only changing this line! ######
    19.  
    20.             AlphaTest Greater [_Cutoff]
    21.             Material
    22.             {
    23.                 Diffuse (1,1,1,1)
    24.                 Ambient (1,1,1,1)
    25.             }
    26.             Lighting Off
    27.             SetTexture [_MainTex] { combine texture }
    28.         }
    29.     }
    30. }
     
  2. BrightBit

    BrightBit

    Joined:
    Jan 22, 2013
    Posts:
    265
    One of the answers here lead me to the root of my problem: Transparent shader in background queue

    It seems that Unity forces SkyBoxes to be rendered in the queue "Background+1500". I've changed my sun shader accordingly and this is what I'll get:



    You can see a part of the sun now but the rest is covered by the SkyBox, i.e. the SkyBox will be rendered in the Queue at index 2500 according to the Manual for SubShader Tags. However, this results in another question: Why is the sun in front of the terrain while the SkyBox is not? The geometry queue starts at 2000! Can someone explain that to me?

    I don't get it!

    Here's my SkyBox shader:

    Code (CSharp):
    1. Shader "CustomShaders/Skybox"
    2. {
    3.     /*property stuff removed for better readability*/
    4.  
    5.     SubShader
    6.     {
    7.         Tags { "Queue"="Background" "IgnoreProjector"="True" "RenderType"="Background"}
    8.  
    9.         Cull Off
    10.         Fog { Mode Off }
    11.         Lighting Off    
    12.         Color [_Tint]
    13.         Pass
    14.         {
    15.             SetTexture [_FrontTex] { combine texture }
    16.             SetTexture [_FrontTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
    17.             SetTexture [_FrontTex2] { combine previous +- primary, previous * primary }
    18.         }
    19.         /*several passes removed for better readability*/
    20.     }
    21. }
    Edit: Using "Queue"="Background+1501" resulted in the sun being in front of the SkyBox!
     
    Last edited: Sep 19, 2014
  3. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Same problem here, which is super-annoying!

    I'm trying to use a shader that creates an outline by having an additional pass that moves vertices a bit along the normal.
    This outline works fine, but is always occluded by the skybox.

    I tried to solve it for a complete day, but gave up on it.

    Any comment from a Unity dev? There has to be a good reason for it.
     
  4. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    Just came across this issue today in Unity 5.3. I'm trying to render clouds in a transparent background layer, directly in front of the skybox but behind everything else in the scene. No matter what combination of renderqueues I try, I either get clouds behind the skybox (and therefore completely invisible) or in front of objects in the scene.
     
  5. stanislavdol

    stanislavdol

    Joined:
    Aug 3, 2013
    Posts:
    282
    Having the same issue
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    It has to do with the difference in how the skybox is rendered.

    In the scene view the skybox is rendered first, then the background queue, then geometry (default) queue, etc. Everything works as expected.

    However in the game view the background queue is rendered first, then geometry and alpha test, and then the skybox is rendered. When it gets rendered it renders anywhere that the depth buffer is empty, i.e. it won't draw where objects with zwrite on have already rendered, but that means anything that didn't zwrite will get stepped on.

    There are two solutions.
    Draw your own skybox object and disable the default one. This will let you force the render order to be first instead of the optimization of rendering it after alpha test.
    Draw the objects you want in the background with zwrite on, but push them very, very far away. This can be done manually, though you'll start running into issues with the camera far distance, or you can do it in the shader. This can be done somewhat trivially for vertex fragment shaders with this bit of code:

    // find the part if your shader that looks like this
    o.pos = UnityObjectToClipPos(v.vertex);
    // push the screen space position to just less than the far plane.
    o.pos.z = 0.9999;
     
  7. Fonserbc

    Fonserbc

    Joined:
    Aug 7, 2012
    Posts:
    6
    Same problem.

    In my case I had a flat floor I wanted rendered under everything except the skybox.
    Then I have some flat meshes right on the floor.

    I ended up having to change the material of the meshes on top of the floor to use an:
    Offset -1, -1
    for the depth buffer.

    But still, it is a workaround, not how I should be supposed to do it.