Search Unity

Question How to remove viewdirection-dependent lighting (specular?) from the standard shader?

Discussion in 'Shaders' started by dogs_, Aug 14, 2022.

  1. dogs_

    dogs_

    Joined:
    Mar 14, 2016
    Posts:
    32
    I have noticed recently that Unity's standard shader seems to have a base level of smoothness that cannot be eliminated even when setting the smoothness value to zero or hard overriding the value in the shader itself (this remains the case regardless of the smoothness source), which means that all surface shaders have a slight sheen to them and a small amount of Fresnel lighting, which is especially noticeable at acute angles or when standing on a large flat plane.
    Ordinarily this wouldn't be a huge problem, but I am using a palette limiter which makes these small differences in colour extremely obvious and potentially confusing.
    I looked all over for a solution and couldn't seem to find anything, until I revisited this page of the Unity docs and noticed that the example shader seems not to have the persistent shine. So I copied the code and compared it to the standard shader and, sure enough, the sheen is gone and the colour is the same at all angles. Below are some examples of the standard shader compared to the example one from the docs, with and without post-processing:

    standard_vs_example_multi.png

    Problem solved right? Just use the example shader from the docs! Unfortunately that shader only comes with support for a single directional light and no other light types. :mad:
    So I'm left with two choices: follow some huge in-depth tutorial on adding support for multiple lights and all the other things that the standard shader affords, or find out how to remove the unwanted smoothness from the standard shader and keep everything else the same.
    The latter seems more sensible to me, so how do I go about doing that? How do I eliminate the smoothness/Fresnel from the standard shader?
     
  2. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    If you want to kill it for good, place a reflection probe and instead of having it capture the environment point it to a pure black texture.
     
  3. dogs_

    dogs_

    Joined:
    Mar 14, 2016
    Posts:
    32
    Damn this is so close to working. Good call.
    If I place a black reflection probe I actually get the inverse problem; at acute angles surfaces tend towards black instead of white. Playing around with the colour of the probe produces some good results. If I match the probe colour with that of the surface I can totally remove all angle-dependent colour differences and artifacting. Unfortunately this only works for one colour at a time, and obviously I have a scene full of differently coloured and textured objects. Might work as a stopgap, but not a scalable solution.
    This does seem to reveal that it's actually reflections that are the problem, not Fresnel or smoothness.
     
  4. dogs_

    dogs_

    Joined:
    Mar 14, 2016
    Posts:
    32
    SOLVED: It was the specular all along.
    I had a look at this page on surface shader lighting examples and had a good long look at the different custom lighting implementations and in particular the simple specular model which looked like something I could read and manipulate. So I brought it into my project and removed all specular calculations while still maintaining light attenuation support and voila:

    NoSpecularWithShadowSupport_multi.png

    Full parity with the example shader. No colour aberration at acute angles. Full light and shadow support.

    This is what the shader code looks like:
    Code (CSharp):
    1. Shader "Custom/DiffuseWithoutSpecular"
    2. {
    3.   Properties
    4.   {
    5.       _Color ("Color", Color) = (1,1,1,1)
    6.       _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.   }
    8.   SubShader
    9.   {
    10.       Tags { "RenderType"="Opaque" }
    11.       LOD 200
    12.  
    13.       CGPROGRAM
    14.       // Custom no specular lighting model with full multi-shadow support
    15.       #pragma surface surf NoSpecular fullforwardshadows
    16.       // Use shader model 3.0 target, to get nicer looking lighting
    17.       #pragma target 3.0
    18.  
    19.  
    20.       half4 LightingNoSpecular (SurfaceOutput s, half3 lightDir, half atten) {
    21.         half diff = max (0, dot (s.Normal, lightDir));
    22.         return half4 ((s.Albedo * _LightColor0.rgb * diff) * atten, s.Alpha);
    23.       }
    24.  
    25.       struct Input
    26.       {
    27.           float2 uv_MainTex;
    28.       };
    29.  
    30.       sampler2D _MainTex;
    31.       fixed4 _Color;
    32.  
    33.       void surf (Input IN, inout SurfaceOutput o)
    34.       {
    35.           fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    36.           o.Albedo = c.rgb;
    37.           o.Alpha = c.a;
    38.       }
    39.       ENDCG
    40.   }
    41.   FallBack "Diffuse"
    42. }
    43.  
     
    Radivarig likes this.
  5. dogs_

    dogs_

    Joined:
    Mar 14, 2016
    Posts:
    32
    and exactly a year later this problem rears its ugly head yet again: the above shader does not seem to support baked lightmaps, at least not fully. after baking this test scene, at first things look more or less fine, although materials using the NoSpecular shader are quite a bit darker than the default material using the same albedo (this seems to be mitigated by changing the scene environmental lighting source to a colour rather than the skybox).
    Screenshot (2053).png
    the blocks in the foreground are using the NoSpecular shader, and everything else is using the default shader.

    however, upon moving closer (within realtime shadow distance) it becomes apparent that something is wrong:
    Screenshot (2054).png
    the realtime shadows are completely black and no bounced or ambient light seems to be taken into account. this behaviour is the same in-game as well; it's not just an editor artifact.
    there are also no cascade splits as far as i can tell. it's either all baked or all HD realtime and nothing in between. this is not the case on the default material.

    the NoSpecular shader currently looks like this:
    Code (HLSL):
    1. Shader "Custom/DiffuseWithoutBullshit"
    2. {
    3.   Properties
    4.   {
    5.       _Color ("Color", Color) = (1,1,1,1)
    6.       _Emission ("Emission", Color) = (0,0,0,0)
    7.       _MainTex ("Albedo (RGB)", 2D) = "white" {}
    8.       _NormalMap ("Normal Map", 2D) = "bump" {}
    9.   }
    10.   SubShader
    11.   {
    12.       Tags {
    13.           "RenderType"="Opaque"
    14.       }
    15.       LOD 200
    16.       CGPROGRAM
    17.       // Custom no specular lighting model with full multi-shadow support
    18.       #pragma surface surf NoSpecular fullforwardshadows
    19.       // Use shader model 3.0 target, to get nicer looking lighting
    20.       #pragma target 3.0
    21.  
    22.  
    23.       half4 LightingNoSpecular (SurfaceOutput s, half3 lightDir, half atten) {
    24.           half diff = max (0, dot (s.Normal, lightDir));
    25.           return half4 ((s.Albedo * _LightColor0.rgb * diff) * atten, s.Alpha);
    26.       }
    27.  
    28.       struct Input {
    29.           float2 uv_MainTex;
    30.           float2 uv_NormalMap;
    31.       };
    32.  
    33.       sampler2D _MainTex, _NormalMap;
    34.       fixed4 _Color, _Emission;
    35.  
    36.       void surf (Input IN, inout SurfaceOutput o) {
    37.           fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    38.           o.Albedo = c.rgb;
    39.           o.Alpha = c.a;
    40.           o.Emission = _Emission;
    41.           o.Normal = UnpackNormal (tex2D (_NormalMap, IN.uv_NormalMap));
    42.       }
    43.       ENDCG
    44.   }
    45.   FallBack "Diffuse"
    46. }
    47.  
    pretty similar to the above, but now with normal and emission support.
    so what's going on here? what do i need to do to get it to support lightmaps? i think i read somewhere that custom GI for deferred rendering is a bit of a problem so if that's the case i guess i might need to go down another path. :( but in theory i don't want custom GI i just want support for the standard GI... :confused:
     
  6. dev_project

    dev_project

    Joined:
    Jan 31, 2020
    Posts:
    23
    Hi, did manage to overcome this issue in the end? I'm having the same issue and I was initially bringing smoothness to 0 but it still "fills" the surface with specular highlights, which is especially noticeable for flat objects like walls, furniture etc And they only appear when I'm moving the camera and lights remain static which simply doesn't make sense from when noticing this.
    I'm surprised that this isn't a widely discussed issue or has everybody switched to URP/HDRP?

    I'm falling back to the legacy shaders for now but I'm sure it will be an issue down the line when I try to improve the visuals.
     
  7. dev_project

    dev_project

    Joined:
    Jan 31, 2020
    Posts:
    23
    hopeful likes this.