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

Depth/Fog Non-linear shader

Discussion in 'Shaders' started by error17, Dec 15, 2019.

  1. error17

    error17

    Joined:
    Mar 13, 2015
    Posts:
    5
    Hey, I need some help.
    I am writing a Post Processing shader for LWRP.
    The post processing shader is for the LWRP volume, it looks like this


    To create a custom shader for this Ive been using this: https://docs.unity3d.com/Packages/com.unity.postprocessing@2.0/manual/Writing-Custom-Effects.html

    and I want to make a fog effect shader, but it has to be spherical or range based.

    Ive looked up online and found some images that demonstrate what I mean:

    consider this plane-based (linear). when the camera turns something that wasnt in the fog can now be in the fog etc.
    Unity's fog already does this, and its the undesired result.


    consider this range-based (non-linear). when the camera turns the fog is fixed in world space.

    Is it possible to make use of the depth texture to produce this result?
     
  2. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,924
    In theory, yes - there are many examples of sampling the depth texture both ways online. The first case is faster and uses the fact that you can take raw values from the texture, so it's the one people generally use by preference.

    You take the view direction down the center-line (center pixel on screen) which is correct by definition, and then as you go left/right/up/down in screenspace, instead of taking the raw depth (which looks like your first images), you use basic trig to calculate the length of the ray through that pixel.

    (PS: your first image is hugely incorrect, not that it matters).

    In practice - last time I tried to do this, the results didn't quite work visually, and I couldn't figure out what was going wrong in Unity. The math was correct (checked it in a different OpenGL engine, and checked my hand-written version against other people's versions online), but in Unity it kept displaying slightly wrong curvature that should NOT have changed with view angle, but did (slightly). I suspected there was something wrong going on with my conversion out of NDC / clip space (1:1:1) and into final screen space (that was the mostly likely thing that would explain the slight curvature I saw), but couldn't seem to get it right.
     
    error17 likes this.
  3. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,924
    Off the top of my head:

    1. D0 = depth along center line
    2. Dnp = depth to near plane
    3. Wnp = width left/right across screen of the pixel you're rendering
    4. Dx = depth of the pixel you're rendering (note: this is the "linear" depth as you described it)
    5. Wx = x at depth D0

    => Wx = x at depth D0 = (ratio of Dnp : D0 * Wnp)
    => Lx = true length along X-ray = sqrt( Wx*Wx + D0*D0)

    i.e. you're using two trig rules. Firstly the one about two triangles that share an angle and one is just an extrapolation of the other (the ratio of the congruent lengths is the same as the ratio of the crosswise lengths).

    Secondly pythagoras's theorem that if you know 2 sides of a right-angled triangle then you get the third by squaring them, adding them, then square rooting.
     
    Last edited: Dec 18, 2019
    error17 likes this.
  4. error17

    error17

    Joined:
    Mar 13, 2015
    Posts:
    5
    Hey thanks for your proposed solution. I will try implement this within the next few weeks and I'll post back the full source code for anyone who is subscribed to this.
     
  5. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,924
    There are probably some examples of people implementation it before on the unity forums (I'd search with google and "site:forum.unity.com"), if you search for linear depth, linear-vs-actual depth, ray depth, ray length from depth texture - things like that.
     
  6. error17

    error17

    Joined:
    Mar 13, 2015
    Posts:
    5
    I have a solution, but its not necessarily for post processing, but the fragment shader.

    Code (CSharp):
    1. float fogDepth = distance(IN.worldPos, _WorldSpaceCameraPos);
    2. float start = 330;
    3. float end = 1250;
    4. fogDepth = 1-saturate((end - fogDepth) / (end - start));
    and you could use a lerp to apply it:

    col.rgb = lerp(col.rgb, fogDayColor, fogDepth);
     
    Last edited: Dec 4, 2020