Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Help Wanted Surface Shader lighting independent of geometry

Discussion in 'Shaders' started by sAmmY17, Jul 21, 2020.

  1. sAmmY17

    sAmmY17

    Joined:
    Dec 30, 2016
    Posts:
    6
    Hi there,

    I´m trying to render a sphere by some simple raytracing inside a cube mesh using a surface shader and shade the sphere correctly. This is the shader I build for this:

    Code (CSharp):
    1. Shader "Custom/SurfaceSDF"
    2. {
    3.     SubShader
    4.     {
    5.         Tags {"RenderType" = "Opaque" "Queue" = "Geometry"}
    6.         LOD 200
    7.  
    8.         CGPROGRAM
    9.  
    10.         #pragma surface surf NoLighting
    11.         #pragma target 3.0
    12.  
    13.         struct Input
    14.         {
    15.             float3 worldPos;
    16.         };
    17.  
    18.         UNITY_INSTANCING_BUFFER_START(Props)
    19.         UNITY_INSTANCING_BUFFER_END(Props)
    20.  
    21.         fixed4 LightingNoLighting(SurfaceOutput s, fixed3 lightDir, fixed atten)
    22.         {
    23.             return fixed4(s.Albedo, s.Alpha);
    24.         }
    25.  
    26.         float intersect(in float3 ro, in float3 rd, in float3 ce, in float ra)
    27.         {
    28.             float3 oc = ro - ce;
    29.             float b = dot(oc, rd);
    30.             float c = dot(oc, oc) - ra * ra;
    31.             float h = b * b - c;
    32.             if (h < 0.0) return -1.0; // no intersection
    33.             h = sqrt(h);
    34.             return -b - h;
    35.         }
    36.  
    37.         void surf (Input IN, inout SurfaceOutput o)
    38.         {
    39.             float3 rd = normalize(IN.worldPos - _WorldSpaceCameraPos);
    40.             float d = intersect(_WorldSpaceCameraPos, rd, float3(0, 0, 0), 1);
    41.            
    42.             clip(d);
    43.  
    44.             float3 hit = _WorldSpaceCameraPos + d * rd;
    45.             float3 norm = normalize(mul(unity_WorldToObject, hit - float3(0, 0, 0)));
    46.             o.Normal = norm;
    47.             o.Albedo = o.Normal*0.5 + 0.5;
    48.             o.Alpha = 1;
    49.         }
    50.         ENDCG
    51.     }
    52.     FallBack "Diffuse"
    53. }
    In general, this works and gives a correctly rendered sphere with correct normals when I use the NoLighting light model as you can see in the first image. But when I use the Lambert or Standard lighting model, the edges of the Cube give strange shading effects, as you can see in the second image.

    So my question is, if the underlying mesh somehow has an effect on the lighting and not only the computed normals? If yes how could I resolve this issue so that the sphere is shaded correctly?

    Thanks for your help in advance!
    Screenshot (9).png Screenshot (8).png
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    8,979
    Surface Shaders always expect the
    o.Normal
    value to be a tangent space normal vector. In other words a normal direction relative to the mesh's texture UV orientation. If you output world or object space normals, it doesn't know that, and will still treat them as tangent space normals, and transform whatever value you give to it from tangent space to world space. For this shader to work you need to either edit the generated code to comment out the one line that does that transform, or convert the SDF normal into tangent space.

    I have an example of doing that in my triplanar normal mapping Surface Shader example here:
    https://github.com/bgolus/Normal-Ma...der/blob/master/TriplanarSurfaceShader.shader
    See the
    WorldToTangentNormalVector
    function. It does require the Input struct have both
    float3 worldNormal;
    and
    INTERNAL_DATA
    to work.

    Be aware that this particular implementation is an approximation. If you're using something like the default Unity cube it'll be pretty close to the same as ground truth. If you're still seeing weird artifacts, you may need to use the correct inverse matrix version here:
    https://forum.unity.com/threads/flat-lighting-without-separate-smoothing-groups.280183/#post-5057189
     
    sAmmY17 likes this.
  3. sAmmY17

    sAmmY17

    Joined:
    Dec 30, 2016
    Posts:
    6
    Thanks so much, that helped a lot!
     
unityunity