Search Unity

Question How to write fragment depth in Standard surface shader?

Discussion in 'Shaders' started by agus_r, Sep 5, 2021.

  1. agus_r

    agus_r

    Joined:
    Oct 8, 2020
    Posts:
    15
    Hi, I am having problems with z-fighting between some objects, and I thought a simple solution would be to slightly change the z depth of the fragments of one material so that it is always visible in front of the other one, and thus avoiding the z-fight.
    In this case, I think this trick should work.
    I have a bit of experience with opengl, and I remember doing something similar to this, it is solved by simply adding the line
    Code (CSharp):
    1. gl_FragDepth(currentdepth - 0.005)
    , however this function is not defined
    when compiling in unity, is there an equivalent one?
    I am using the standard surface shader, so I guess this modification should be inside the function
    Code (CSharp):
    1. void surf (Input IN, inout SurfaceOutputStandard o)
    , but I have no idea if I have to change a value of the struct "SurfaceOutputStandard" (which one?), or what. I couldn't find any solution on the forum.
    Thank you in advance
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Unity uses HLSL. The equivalent of GLSL’s
    gl_FragDepth
    is the
    SV_Depth
    fragment shader output semantic. To use an output semantic you need to define an out variable of the main fragment shader function to use that semantic. Unfortunately Unity’s Surface Shaders do not give you any direct control over how the main fragment shader function is defined, so it’s not possible to do this. The
    surf
    function is one that’s called from the main fragment shader function with data calculated prior to calling it, and then passes that data on to other functions that produce the output values. The only way to set the
    SV_Depth
    is by writing the shader code from scratch, or modifying the generated shader.

    I do want to note that a constant offset of the depth like what you’re trying to do is far more easily, and efficiently done by modifying the vertex position, specifically modifying the output clip space position, though that’s also not really possible since, again, the vertex function you can call in a Surface Shader isn’t the actual main vertex shader function, but a function the main function is calling, and the clip space position is calculated later. But you can get something close-ish by calculating the object space view direction and offsetting the position ever so slightly there.