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

Is it possible to normalize two depth maps into a single coherent one?

Discussion in 'Shaders' started by Mr_Admirals, Dec 19, 2018.

  1. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    Okay, so this question might be a bit difficult to articulate.

    For those that frequent the forums, you'll know I'm working on a snow deformation shader. Currently, the snow mesh can only be believably deformed on flat plane. This is the same tech that Batman: Arkham Origins uses to handle their snow deformation. What I want to do is extend beyond what they did by making the tech work on arbitrarily shaped surfaces.

    I think I'm close to making it work, but have hit a bit of a wall.

    Here's what I currently have:
    Code (CSharp):
    1. Shader "Hidden/NormalizeDepthMaps"
    2. {
    3.     Properties
    4.     {
    5.         _GroundTex ("-", 2D) = "white" {}
    6.         _ObjectTex("-", 2D) = "white" {}
    7.         _Displacement("-", Range(0, 1)) = 0.3
    8.     }
    9.  
    10.     CGINCLUDE
    11.  
    12.     #include "UnityCG.cginc"
    13.  
    14.     sampler2D_float _GroundTex;
    15.     sampler2D_float _ObjectTex;
    16.     float _Displacement;
    17.  
    18.     half4 NormalizeDepth(v2f_img i, out float outDepth : SV_Depth) : SV_Target
    19.     {
    20.         float objectDepth = SAMPLE_DEPTH_TEXTURE(_ObjectTex, i.uv);
    21.         float groundDepth = SAMPLE_DEPTH_TEXTURE(_GroundTex, float2(1-i.uv.x,i.uv.y));
    22.  
    23.         //float object = 5 + (objectDepth - 0)*(5.2 - 5) / (1 - 0);
    24.         //float upperBounds = 5 + (groundDepth + _Displacement - 0)*(5.2 - 5) / (1 - 0);
    25.         //float lowerBounds = 5 + (clamp(groundDepth, 0, 1) - 0)*(5.2 - 5) / (1 - 0);
    26.  
    27.         //float depth = 0 + (object - lowerBounds)*(1 - 0) / (upperBounds-lowerBounds);
    28.         float depth = groundDepth;
    29.  
    30.         outDepth = depth;
    31.         return 0;
    32.     }
    33.  
    34.     ENDCG
    35.  
    36.     SubShader
    37.     {
    38.         Pass
    39.         {
    40.             ZTest Always Cull Off ZWrite On
    41.             CGPROGRAM
    42.             #pragma vertex vert_img
    43.             #pragma fragment NormalizeDepth
    44.             ENDCG
    45.         }
    46.     }
    47. }
    If you'll note, I was messing around with remapping the values to different ranges in an attempt to get them to fit.

    Currently, my orthographic view box extends all the way down to the collider, to the very top of the mesh. This leaves a lot of empty space to capture objects that are likely above the snow. To counter that, I have a camera placed above the mesh aimed down to capture the depth, and I'm attempting to use that to "flatten" out the final depth map so that it doesn't care about the given height of whatever pixel the shader is currently on.

    Imagine this is an arbitrary pixel on the mesh:

    Orthographic Viewing Box
    - 0
    | Mesh to collider range
    | - 0.4
    | | --- Object Depth 0.6
    | - 0.8
    |
    - 1

    What I want to do is reparameterize the mesh to collider range and object depth to be 0 to 1. Unfortunately, what I've found online doesn't seem to work (hence why my code is commented out: it's simply not working at the moment).

    Something I picked up that may be of some importance is this: "Pixel values in the Depth Texture range between 0 and 1, with a non-linear distribution."

    As I said, I feel like I'm very close, but am just missing something obvious. I hope at least, haha.

    Recently I've been looking into writing a shader to change how the camera renders objects, but no luck in getting the shader to actually affect the camera's output.
     
    Last edited: Dec 19, 2018
  2. Mr_Admirals

    Mr_Admirals

    Joined:
    May 13, 2017
    Posts:
    86
    Welp, I've got good news! The answer is "Yes"!

    After tackling the problem for a few hours after posting this and trying to brute-force my way through the problem, I concluded that it was possible. Well, it was more of a feeling. Anyway, I called up my brother who's a programming and math wiz, and gave the problem to him. After helping him understand how my code works (he's not familiar with shaders at all) he sent me this:

    "Humor me and try

    Clamp((groundHeight-objectHeight)/displacement, 0, 1)
    And if that doesn't work then swap object height and ground height around
    That's assuming displacement is 0.2 on the scale of 0 to 1. If it's 0.2 in the same units of The view box height (1.43) then multiply the numerator by 1.43"

    So, in my brute-forcing, the "Clamp((groundHeight-objectHeight)/displacement, 0, 1)" was actually the closest I had gotten it to working but I knew I was missing something because the displacement height wasn't quite right. Well, that 1.43 (the orthographic view box height) managed to finish normalizing the value. In my searching online, the standard way of normalizing values to a certain range was "v’ = (v-min)/(max-min) * (newmax-newmin) + newmin"

    Because I wanted to keep it between 0 and 1, it didn't occur to me that the actual range was between 0 and 1.43.

    Anyway, I hope this makes some sense. My head is still whirling, but the results are fantastic - deformable snow on an arbitrary surface:

    upload_2018-12-19_0-22-41.png
     
    hippocoder likes this.