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. Dismiss Notice

Bug Weird effect on custom fresnel HLSL

Discussion in 'Shaders' started by KartMakerBrosU, Jun 7, 2023.

  1. KartMakerBrosU

    KartMakerBrosU

    Joined:
    Aug 14, 2021
    Posts:
    3
    Hello, im trying to write a custom fresnel effect in unitys hlsl and im getting a weird effect where it seems like the effect only works on the vertices of the object and not the normals of each screen pixel. Like the examples here:
    Unity:
    upload_2023-6-6_19-33-27.png

    How its supposed to look like (Blender):
    upload_2023-6-6_19-30-38.png
    If you zoom into the model in Unity, unless you are looking directly at a vertex, it will get lighter, not stay the same color.

    Here's my code:
    Code (CSharp):
    1.             v2f vert (appdata v)
    2.             {
    3.                 v2f o;
    4.                 o.vertex = UnityObjectToClipPos(v.vertex);
    5.                 o.normal = UnityObjectToWorldNormal(v.normal);
    6.                 o.viewDir = normalize(ObjSpaceViewDir(v.vertex));
    7.                 o.uv = TRANSFORM_TEX(v.uv, _NormalMap);
    8.                 o.uv2 = TRANSFORM_TEX(v.uv2, _Tex1);
    9.                 o.uv3 = TRANSFORM_TEX(v.uv3, _Tex2);
    10.                 o.color = v.color;
    11.                    
    12.                 return o;
    13.             }
    14.  
    15.             fixed4 frag (v2f i) : SV_Target
    16.             {
    17.                 float fresnelAmount = 1- max(0,dot(i.normal, i.viewDir));
    18.                 return fresnelAmount;
    19.             }
    20.             ENDCG
    upload_2023-6-6_19-30-38.png
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,221
    Don't normalize the viewDir in the vertex shader.
    Do normalize both the viewDir and normal in the fragment shader.

    Vectors, like all other values, are interpolated linearly between the vertices. This results in non-unit length vectors in the fragment shader when interpolating normalized vectors, making the resulting dot product produce slightly off results.

    However you can only accurately linearly interpolate positions, not directions. So you want to interpolate the offset vector from the camera position to the vertex position, and then normalize it in the fragment shader to get an accurate viewDir.

    Also you're using and object space view direction against a world space normal, which is only working because the object isn't rotated. You should either be using the world space view direction, or passing the original object space vertex normal unmodified.
     
    Last edited: Jun 7, 2023
    lilacsky824 likes this.
  3. KartMakerBrosU

    KartMakerBrosU

    Joined:
    Aug 14, 2021
    Posts:
    3
    Thank you so much, this fixed the issue. This was a major issue for a long time and I'm so glad I reached out instead of trying to solve it myself because, frankly, I have very little experience with handling vectors in shaders so thank you so much for helping me understand the issue.

    Here's the final code so in case others see this thread in the future and need it:
    Code (CSharp):
    1. v2f vert (appdata v)
    2. {
    3.     v2f o;
    4.     o.vertex = UnityObjectToClipPos(v.vertex);
    5.     o.normal  = UnityObjectToWorldNormal(v.normal);
    6.     o.viewDir = ObjSpaceViewDir(v.vertex);
    7.     return o;
    8. }
    9. fixed4 frag (v2f i) : SV_Target
    10. {
    11.     i.viewDir = normalize(i.viewDir);
    12.     i.normal = normlaize(i.normal);
    13.  
    14.     float fresnelAmount = max(0,dot(i.normal, i.viewDir));
    15.     return fresnelAmount;
    16. }