Search Unity

Problem with ZWrite and sorting objects

Discussion in 'Shaders' started by Sly88, May 9, 2019.

  1. Sly88

    Sly88

    Joined:
    Feb 22, 2016
    Posts:
    73
    hi guys,
    I have some problem with my shader/models. Maybe at the beginning of I describe what I want to achieve.
    I use 2d (Sprite Renderer) and 3d objects in my project and I use one camera to render both. I would like to sort object depend on position on map. I use the same sorting layer for both and change order in layer depend on position. Everything works great when shader have Zwrite Off but in this case, I have some problem with textures on an object (https://prnt.sc/nmb00h)

    When I set Zwrite On in the shader object looks good but I have some problem with sorting. 3D object is always on top (https://prnt.sc/nmb04u)

    I will be very grateful for any advice on how to fix the problem
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    ZWrite On exists for the sole purpose of making the render order not matter for opaque objects. If you want to use “both”, you’re going to have a bad time, or you have to actually position your sprites in 3D space.

    There are some kind of nasty hacks that are possible, like using a shader to push the 3D objects further away in screen space so they still sort between themselves properly, but don’t intersect with transparent objects. Or you could have a multi-pass shader for 3D objects which renders the object with ZWrite On, then renders it again pushed to the far plane in screen space, and using ZTest Always and ColorMask 0 so it clears the depth buffer where it rendered. That second option will cause problems if there are 3D objects you really do want to have depth sort properly.

    Then there’s the old school option. The “what did they do when they didn’t have a z buffers?” Like for PS1 and PS2 games. They did fully 3D games, but there was no depth buffer, so the render order mattered. The solution was the triangles were all individually sorted before rendering. You could do that to your meshes, either manually in the program the mesh was built in or with a script. The trick is to detach all of the faces and one by one attach them together in from the bottom up, then make sure to turn off any mesh optimization in Unity’s import settings. As long as the camera is mostly looking down from above like those example images, it should look mostly correct (assuming your modeling tool isn’t reshuffling the triangle order on you). Since your meshes look fairly low poly, you might be able to get away with sorting the per mesh triangles using a script in real time.
     
    Tony_Max and Sly88 like this.
  3. Sly88

    Sly88

    Joined:
    Feb 22, 2016
    Posts:
    73
    hi @bgolus

    Thank you for your prompt response.

    Do you have some reference to script to sorting mesh triangles or multi-pass shader?

    Now my shader is really simple

    Code (CSharp):
    1.  Shader "Shader" {
    2. Properties {
    3.      _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    4.      _Color ("Color", Color) = (1,1,1,1)
    5. }
    6. SubShader {
    7.      Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
    8.        
    9.         ZWrite Off
    10.        
    11.         Lighting Off
    12.         Fog { Mode Off }
    13.  
    14.         Blend SrcAlpha OneMinusSrcAlpha
    15.  
    16.         Pass {
    17.             Color [_Color]
    18.             SetTexture [_MainTex] { combine texture * primary }
    19.         }
    20. }
    21. }
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    https://forum.unity.com/threads/order-triangles-to-view-sort-your-mesh-for-alpha-blending.182141/
    (There's no guarantee that script still works as is, as it is 6 years old, but it can be used for reference.)

    As a warning, you really only want to do this on your 3d meshes. You could do it on everything, but it's needlessly wasteful on sprites as they gain no benefit.

    Use ZWrite On and add this pass after the one you already have:
    Code (csharp):
    1. Pass {
    2.     Name "Z Clear"
    3.     ColorMask 0
    4.     ZWrite On
    5.     ZTest Always
    6.  
    7.     CGPROGRAM
    8.     #pragma vertex vert
    9.     #pragma fragment frag
    10.     #include "UnityCG.cginc"
    11.  
    12.     float4 vert (float4 vertex : POSITION) : SV_Position
    13.     {
    14.         float4 pos = UnityObjectToClipPos(vertex);
    15.     #if defined(UNITY_REVERSED_Z)
    16.         pos.z = 1.0e-9f;
    17.     #else
    18.         pos.z = pos.w - 1.0e-6f;
    19.     #endif
    20.        return pos;
    21.     }
    22.  
    23.     void frag() {}
    24. }
    An explanation of the funky pos.z stuff:
    https://aras-p.info/blog/2019/02/01/Infinite-sky-shader-for-Unity/

    I'd also remove the Blend line entirely as presumably these are always opaque 3D objects, so you don't need the blending at all. If you do plan on fading the meshes out using the color, you probably want to also have a depth pre-pass in the shader, like this:
    Code (csharp):
    1. Pass {
    2.     Name "Z Prepass"
    3.     ColorMask 0
    4.     ZWrite On
    5.  
    6.     CGPROGRAM
    7.     #pragma vertex vert
    8.     #pragma fragment frag
    9.     #include "UnityCG.cginc"
    10.  
    11.     float4 vert (float4 vertex : POSITION) : SV_Position
    12.     {
    13.         return UnityObjectToClipPos(vertex);
    14.     }
    15.  
    16.     void frag() {}
    17. }
    This goes before the pass you already have, so the order would be Z Prepass > normal shader > Z Clear.


    One additional thing.
    The example shader you have is a deprecated fixed function shader. Unity still "supports" those by automatically converting it into a vertex fragment shader. I would suggest if you're interested in shaders at all you read up on vertex fragment shaders and ignore anything that has the kind of syntax that shader uses with the "SetTexture" and "combine". Basically if the shader doesn't have CGPROGRAM in it someplace, I wouldn't recommend spending much time looking it.
    https://www.alanzucconi.com/2015/06/10/a-gentle-introduction-to-shaders-in-unity3d/
     
    EAST-DATA and Sly88 like this.
  5. Sly88

    Sly88

    Joined:
    Feb 22, 2016
    Posts:
    73
    thank you again, you save me a lot of time! I saw script to sort triangles before but not work well.
    I try to modify the shader.

    Thanks and have a nice day!