Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

DeferredDecal shader questions

Discussion in 'Shaders' started by thefonet, Mar 12, 2020.

  1. thefonet

    thefonet

    Joined:
    Apr 9, 2014
    Posts:
    10
    Hello
    I have been taking a look at the Unity demo project RenderingCommandBuffers whichshows how to implement a decal system using CommandBuffers and looking at the code there are a couple of things that I don't understand.

    Posting the frag and vertex shader here for context.

    Code (CSharp):
    1.     v2f vert (float3 v : POSITION)
    2.             {
    3.                 v2f o;
    4.                 o.pos = UnityObjectToClipPos (float4(v,1));                              
    5.                 o.screenUV = ComputeScreenPos (o.pos);                                  
    6.                 o.ray = mul (UNITY_MATRIX_MV, float4(v,1)).xyz * float3(1,1,-1);
    7.                 o.orientation = mul ((float3x3)unity_ObjectToWorld, float3(0,1,0));      
    8.                 return o;
    9.             }
    10.  
    11.             sampler2D _MainTex;
    12.             sampler2D_float _CameraDepthTexture;
    13.             sampler2D _NormalsCopy;
    14.  
    15.        
    16.             fixed4 frag(v2f i) : SV_Target
    17.             {
    18.                 i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
    19.                
    20.                 float2 uv = i.screenUV.xy / i.screenUV.w;
    21.                 // read depth and reconstruct world position
    22.                 float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
    23.                 depth = Linear01Depth (depth);
    24.                 float4 vpos = float4(i.ray * depth,1);
    25.                 float3 wpos = mul (unity_CameraToWorld, vpos ).xyz;
    26.                 float3 opos = mul (unity_WorldToObject, float4(wpos ,1)).xyz;
    27.  
    28.                 clip(float3(0.5,0.5,0.5) - abs(opos ));
    29.  
    30.                
    31.                 half3 normal = tex2D(_NormalsCopy, uv).rgb;
    32.                 fixed3 wnormal = normal.rgb * 2.0 - 1.0;
    33.                 clip (dot(wnormal, i.orientation) - 0.3);
    34.  
    35.                 uv = opos.xz + 0.5;
    36.                 fixed4 col = tex2D (_MainTex, uv);
    37.                
    38.                
    39.                 return col;
    40.             }

    First. Why is the ray multiplied with (1,1,-1)? Does it have anything to do with V being the inverse of the transformation matrix of the camera?

    Code (CSharp):
    1. o.ray = mul (UNITY_MATRIX_MV, float4(v,1)).xyz * float3(1,1,-1);

    Secondly. Why is this done? this seems to be scaling up the ray so it covers the whole frustum. This way it can be later scaled now by a normalized depth. Is that right?

    Code (CSharp):
    1.  i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
    Thanks for your help!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,256
    “V” here is the camera (aka View) matrix. “M” is the object to world (aka Model) matrix. Nothing super fancy there, just calculating the view space position of the vertex. However on the GPU view space forward is -Z, so multiplying it by float3(1,1,-1) makes the z value positive (if it’s visible).

    Correct. The i.ray is scaled to a position on the the far clip plane, then scaled by the normalized depth resulting in the view space position from the depth buffer.
     
  3. thefonet

    thefonet

    Joined:
    Apr 9, 2014
    Posts:
    10
    That's the bit I was missing!

    Thanks for your help.
     
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    Before you spend infinite amount of time on these decals (like I did), here's a warning:

    They're not compatible with lightmaps. And never will be. Be aware of that.
    And realtime shadows will tear your performance.

    Look into DBuffer decal approach instead (that are supported by HDRP by default)
    (High quantity per frame with lightmap support)

    Or mesh decals (alike EasyDecals).
    (Low quantity per frame, since slowdown due to mesh baking)