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

Normal reconstruction via DDXY

Discussion in 'Shaders' started by sewy, Mar 7, 2019.

  1. sewy

    sewy

    Joined:
    Oct 11, 2015
    Posts:
    150
    Hi,

    I am trying to reconstruct flat shaded normals for vertex displaced mesh. I am using ddx, ddy approach which can be found on the web, but the result is not working as expected.
    Am I missing something obvious here?

    Thanks.

    pic3.JPG pic2.JPG pic1.JPG

    Code (CSharp):
    1. Shader "Custom/VertexDispl" {
    2.     Properties {
    3.         _NoiseTex("Albedo (RGB)", 2D) = "white" {}
    4.         _Multiplier("_Multiplier", float) = 1
    5.     }
    6.     SubShader {
    7.         Tags { "RenderType"="Opaque" }
    8.         LOD 200
    9.  
    10.         CGPROGRAM
    11.         #pragma surface surf StandardSpecular fullforwardshadows vertex:vert
    12.         #pragma target 3.0
    13.  
    14.         sampler2D _NoiseTex;
    15.         float _Multiplier;
    16.  
    17.         struct Input {
    18.             float3 worldPos;
    19.         };
    20.  
    21.         void vert(inout appdata_full v, out Input o) {
    22.  
    23.             float2 uv = v.vertex.xz;
    24.             float noise = tex2Dlod(_NoiseTex, float4(uv / 64, 0, 0)).a; //64 is _NoiseTex size
    25.             noise = noise * 2 - 1; //remap from 0_1 to -1_1
    26.             v.vertex.y += noise * _Multiplier;
    27.  
    28.             o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    29.         }
    30.  
    31.         void surf(Input i, inout SurfaceOutputStandardSpecular o) {
    32.             o.Albedo = float3(0, 0, 0.5);
    33.  
    34.             o.Normal = -normalize(cross(ddx(i.worldPos), ddy(i.worldPos)));
    35.  
    36.             o.Specular = float3(0.2, 0.2, 0.2);
    37.             o.Smoothness = 1;
    38.         }
    39.     ENDCG
    40.     }
    41. }
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The using the derivatives of the world space position are going to get you world space normals, but Unity's Surface Shaders assume the normals output by the surf function are in tangent space. Basically a Surface Shader will always apply the tangent to world matrix transform to the surf function normals, so you need to convert your world space normals into tangent space.

    https://forum.unity.com/threads/flat-lighting-without-separate-smoothing-groups.280183/#post-3696988

    Note, in that shader I'm passing camera relative world positions from the vertex shader to the surf function rather than relying on the built in worldPos. I do this because of precision issues when moving away from world 0,0,0 can cause noise to appear on the surface.
     
    brainwipe likes this.
  3. sewy

    sewy

    Joined:
    Oct 11, 2015
    Posts:
    150
    DUH...

    Thank you shader guru!