Search code examples
unity-game-enginehlslurp

How do I get Phong Lighting to work on wave Vertex Shader HLSL Unity URP


I have a shader that is making a wave on a mesh and I added Phong lighting to it. But the valleys in the plane are not shaded.

How do I get the the UniversalFragmentBlinnPhong to correctly use the normal from the transforming mesh and not the original unchanged mesh?

Varyings vert(Attributes IN)
{
    // Declaring the output object (OUT) with the Varyings struct.
    Varyings OUT;
    // The TransformObjectToHClip function transforms vertex positions
    // from object space to homogenous space

    // ripple
    IN.positionOS.y += sin(_frequency* sqrt((IN.positionOS.x*IN.positionOS.x) + (IN.positionOS.z*IN.positionOS.z)) + _Time.y) *_amplitude;

    VertexPositionInputs posnInput = GetVertexPositionInputs(IN.positionOS);

    // lighting does not account for the change in the vertex
    VertexNormalInputs normalInputs = GetVertexNormalInputs(IN.normalOS);
    
    
    // In.uv.xy * _MainTex_ST.xy + _MainTex_ST.xy
    OUT.uv = TRANSFORM_TEX(IN.uv,_MainTex);
    
    OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);

    OUT.normalWS = IN.normalOS;
    
    
    OUT.positionWS = posnInput.positionWS;
    
    
    return OUT;
}

// The fragment shader definition.
// SV Target is a semantic that defines the output of the fragment shader.          
half4 frag(Varyings IN) : SV_Target
{
    half4 colorSample = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,IN.uv);

    // cast everything 
    InputData lightingInput = (InputData)0;
    lightingInput.positionWS = IN.positionWS;
    lightingInput.normalWS = normalize(IN.normalWS);
    lightingInput.viewDirectionWS = GetWorldSpaceNormalizeViewDir(IN.positionWS);
    
    SurfaceData surfaceInput = (SurfaceData)0;
    //surfaceInput.albedo = colorSample.rbg * _ColorTint.rbg;
    //surfaceInput.alpha = colorSample.a * _ColorTint.a;
    surfaceInput.albedo = _ColorTint.rbg;
    surfaceInput.alpha = _ColorTint.a;
    surfaceInput.specular = 1;
    surfaceInput.smoothness = _Smoothness;
    
    
    return UniversalFragmentBlinnPhong(lightingInput,surfaceInput);
}

Image of Plane Image of Wave Plane

Image of sphere with same material

The divot in the top should be all black, but it's shaded like it is a smooth sphere enter image description here


Solution

  • I had to calculate the normal by hand, does not look like there are any functions that would do it for me.

    Varyings vert(Attributes IN)
    {
        // Declaring the output object (OUT) with the Varyings struct.
        Varyings OUT;
        // The TransformObjectToHClip function transforms vertex positions
        // from object space to homogenous space
    
        // ripple
    
        // consider this the bump map
        float4 modifiedPos = IN.positionOS;
        modifiedPos.y += sin(_frequency* sqrt((modifiedPos.x*modifiedPos.x) + (modifiedPos.z*modifiedPos.z)) + (_Time.y*_Speed)) *_amplitude;
        
        
    
        
         
        VertexPositionInputs posnInput = GetVertexPositionInputs(modifiedPos);
        
        // lighting does not account for the change in the vertex
        VertexNormalInputs normalInputs = GetVertexNormalInputs(modifiedPos);
    
    
        // since we have the displacment funtion we can calculate the normal a plane runing parallel over the diff
        
        float3 posPlusTangent = IN.positionOS + normalInputs.tangentWS * 0.01;
        posPlusTangent.y += sin(_frequency* sqrt((posPlusTangent.x*posPlusTangent.x) + (posPlusTangent.z*posPlusTangent.z)) + (_Time.y*_Speed)) *_amplitude;
    
        float3 bitangent = cross(IN.normalOS, normalInputs.tangentWS);
        float3 posPlusBitangent = IN.positionOS + bitangent * 0.01;
        posPlusBitangent.y += sin(_frequency* sqrt((posPlusBitangent.x*posPlusBitangent.x) + (posPlusBitangent.z*posPlusBitangent.z)) + (_Time.y*_Speed)) *_amplitude;
    
        float3 modifiedTangent = posPlusTangent - modifiedPos;
        float3 modifiedBitangent = posPlusBitangent - modifiedPos;
    
        float3 modifiedNormal = cross(modifiedTangent, modifiedBitangent);
        
        // In.uv.xy * _MainTex_ST.xy + _MainTex_ST.xy
        OUT.uv = TRANSFORM_TEX(IN.uv,_MainTex);
    
        
        
        OUT.positionHCS = TransformObjectToHClip(modifiedPos.xyz);
        
        OUT.normalWS =  normalize(cross(modifiedTangent, modifiedBitangent));
        
        OUT.positionWS = posnInput.positionWS;
        
        
        return OUT;