Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question How to hide an object with semi transparent material behind another object with the same material?

Discussion in 'Shaders' started by boruds, Jun 3, 2021.

  1. boruds

    boruds

    Joined:
    Aug 7, 2020
    Posts:
    28
    I am new to writing shaders, I have 2 semi transparent planes with diffuse color. They both have the same material. I want to achieve an effect when one goes behind other, the one behind is hidden so I don't see the objects overlapping. How can I achieve this?

    Is there a way to achieve this in shader graph?

    Thanks
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Certainly, you just need to ...

    ... oh.

    If you're using the URP, there's nothing you can do with Shader Graph alone to make this happen. Unity does not expose the features you'd need to make it possible. They kind of exist for the HDRP, but even there it can't be done with shaders alone.

    To do this you need to use either stencils or ZWrite, and render them in reverse order from what they would normally render in as transparent objects. Or you need to render both planes twice, once both using an invisible ZWrite shader, and a second time using whatever basic shader you already have.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Minimal ZWrite Only shader
    Code (csharp):
    1. Shader "ZWrite Only"
    2. {
    3.     SubShader
    4.     {
    5.         Tags { "Queue"="Transparent" "RenderType"="Transparent" }
    6.  
    7.         Pass {
    8.             ColorMask 0
    9.             CGPROGRAM
    10.             #pragma vertex vert
    11.             #pragma fragment frag
    12.  
    13.             #include "UnityCG.cginc"
    14.  
    15.             float4 vert(float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); }
    16.             fixed4 frag() : SV_Target { return 0; }
    17.  
    18.             ENDCG
    19.         }
    20.     }
    21. }
     
  4. boruds

    boruds

    Joined:
    Aug 7, 2020
    Posts:
    28
    @bgolus Thanks, I will give this a spin, I don't necessarily need to achieve this using shader graph, so shader lab code is fine.
    The idea here is that I should have 2 render passes where the first one writes to the depthBuffer and the second pass does what the shader actually renders.
    I believe 2 ways to achieve this is having 2 materials on the plane one with the zwrite only shader and other with the normal renderer.
    Or
    I guess I can do it in one shader where I write the ZWrite subshader on top of the normal rendering shader. Is that correct?
    I think the second approach is the way to go.
    Sorry I am learning about shaders so my concepts might be a bit weak.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Yes, if you use different queues for the ZWrite only and regular materials to ensure the ZWrite only material renders for both planes before either render the other material.

    Using a single shader with two passes would only work 100% of the time if both planes were in a single combined mesh. If they're separate mesh renderers, Unity may sort them back to front and render the ZWrite only material for the further plane, then the regular material for that plane, then the ZWrite only material and regular material for the closer plane.

    It might also sometimes render both of the planes using the ZWrite Only pass and then both planes using the regular pass, though I think this will only happen if they're part of the opaque queue and not transparent.

    It all depends on how Unity decides to sort the meshes and materials, and both options are totally valid and possible. I also don't have a ton of experience with the SRPs to know what the sorting behavior with multi-pass materials is since they don't really like multi-pass materials.


    The "best" option that would ensure the render order works exactly how you want it to would be two use a SortingGroup component, and 4 planes. Two with the ZWrite Only material, and two with the regular material. Then add a script on the planes that sets the
    renderer.sortingOrder
    of the two ZWrite Only planes to be -1. Alternatively you could manually combine the planes into a single mesh from script, or by abusing a particle system.
     
    boruds likes this.
  6. boruds

    boruds

    Joined:
    Aug 7, 2020
    Posts:
    28
    @bgolus So I don't know if the SortingGroup will work in my case. I don't have 2 planes actually, I am applying the material on ARKit generated meshes when I scan the room. So the meshes are separate objects and they have the same material.
     
  7. skoteskote

    skoteskote

    Joined:
    Feb 15, 2017
    Posts:
    87
    @boruds Did you find a solution to this? Running into a similar issue for the same use-case (AR planes).