Search Unity

[Surface Shader] Wrong normals after vertex modification

Discussion in 'Shaders' started by cod3ophis, Sep 2, 2017.

  1. cod3ophis

    cod3ophis

    Joined:
    Dec 26, 2011
    Posts:
    22
    Hello,

    I'm having an issue related (I think) to normals.

    I'm trying to make a bending effect (horizontally) on a surface shader (lighting is important in my scenario). Currently I've added the following vertex calculations on the surface shader:

    Code (Shader):
    1.  
    2. struct appdata
    3. {
    4.             float4 vertex : POSITION;
    5.             float2 texcoord : TEXCOORD0;
    6.             float4 color : COLOR;
    7.             float3 normal : NORMAL;
    8. };
    9.  
    10. void vert(inout appdata v)
    11. {
    12.             float4 pos = UnityObjectToClipPos(v.vertex);
    13.             float dist = UNITY_Z_0_FAR_FROM_CLIPSPACE(pos.z);
    14.             v.vertex.y -= 0.00008 * dist * dist * _ProjectionParams.y;
    15. }
    The bending effect is OK but the shadows are all wrong:



    I'm a little confused on what to do to fix the problem, should the normals be recalculated on the go? Isn't a demanding process? Or is a completely different problem? :)

    Thanks!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    It's not the normal. That's from not updating the shadow caster pass, which gets used for both shadow casting and the camera depth texture. The way Unity does directional shadows it actually casts upon the depth texture. The result is if you're not applying the bend to the shadow caster pass the shadows won't match.

    With a surface shader you can add addshadow to the #pragma surface line. However you can't use UnityObjectToClipPos() to do the bend, since in the shadow map pass that'll get the distance from the light, not from the game camera. You'll want to get the distance to _WorldSpaceCameraPos or use unity_WorldToCamera.
     
  3. cod3ophis

    cod3ophis

    Joined:
    Dec 26, 2011
    Posts:
    22
    Ah! That did the trick! :)
    Many thanks, the end result is the following:



    In the shader, I've added the 'addshadow' and changed the following calculations:

    Code (Shader):
    1. void vert(inout appdata v)
    2.         {
    3.             float4 world_space_vertex = mul(unity_ObjectToWorld, v.vertex);
    4.             float dist = world_space_vertex.z - _WorldSpaceCameraPos.z ;
    5.             v.vertex.y -= 0.00005  * dist * dist * _ProjectionParams.y;  
    6.         }

     
    Last edited: Sep 2, 2017