Search Unity

Resolved Right way to disable and skip "Specular Highlights" and "Environment Reflections" on custom shaders?

Discussion in 'Shader Graph' started by Ben_at_Work, Jul 28, 2022.

  1. Ben_at_Work

    Ben_at_Work

    Joined:
    Mar 16, 2022
    Posts:
    83
    Many of Unity's built in shaders, like the URP/Lit shader, have checkboxes to entirely disable Specular Highlights and Environment Reflections and I'd like to know if Shader Graph can prune those two features to the same degree. Intuitively, zeroing values out would seem like something that could be detected and pruned at build-time, but I'd rather be certain.

    toggleSpecular.PNG

    It's easy enough to set the smoothness, specular, and metallic parameters to zero, or even to delete the nodes from the fragment shader displayed on the graph, but which if either of these will definitively cut those layers from the shader? If zeroing is enough, will it still be recognized with a boolean attached even if it's passing the same zeroed value?

    So to rephrase the question, when, if ever, will Shader Graph entirely skip its specular and reflection layers? Is environment reflection accessible in the same way to begin with?
     
    ArtemZZZZ likes this.
  2. Shaggy21

    Shaggy21

    Joined:
    Oct 2, 2014
    Posts:
    24
    also interested
     
  3. bnmguy

    bnmguy

    Joined:
    Oct 31, 2020
    Posts:
    137
    You can use shader keywords:
    _SPECULARHIGHLIGHTS_OFF
    _ENVIRONMENTREFLECTIONS_OFF
    as boolean keywords. Set them as local shader features in fragment and make sure to check the "exposed" checkbox to allow toggling in the editor. Note enabling these keywords actually turns these features off.
    They don't need to exist in the graph itself, just in the properties panel.
     
    Last edited: Aug 11, 2022
  4. melos_han_tani

    melos_han_tani

    Joined:
    Jan 11, 2018
    Posts:
    79
    I've done this in a shadergraph (in 2021.3.20f1) , but sometimes it seems like a material will ignore one of the settings and randomly flip it. (The inspector for the material will show "Environment Reflections Off" as checked, but reflections will show. Is there some way other scripts/materials could be interfering with this? (There are no scripts on my end that would be setting either keyword). Maybe skybox stuff?
     
    acur97 likes this.
  5. bnmguy

    bnmguy

    Joined:
    Oct 31, 2020
    Posts:
    137
    Check the generated shader code and see what keywords are being set. I'd start there.
     
  6. Ben_at_Work

    Ben_at_Work

    Joined:
    Mar 16, 2022
    Posts:
    83
    For clarity, here's the pattern I use in Shadergraph. The keyword reference may fall out of sync with your display name so double check that those are identical to what was posted above. I use negative tense names to match the actual toggle state.

    lightChannel_01.PNG lightChannel_02.PNG
     
    sismach likes this.
  7. DavidMiranda

    DavidMiranda

    Joined:
    Nov 30, 2012
    Posts:
    617
    Really helpful!
    What I have seen is that it still returns a color when we enable _ENVIRONMENTREFLECTIONS_OFF
    334004b6b891df4b141aa08e2408604f.gif

    So I checked the function GlossyEnvironmentReflection to find what's going on and I found something that I would change. They return _GlossyEnvironmentColor.rgb * occlusion; when _ENVIRONMENTREFLECTIONS_OFF is ON. Why? I don't know. I just want it to return 0.
    I did a custom version of the function returning 0 and it behaves now as I expected.

    e81f36fd87e3325519c22f923f12446d.gif

    Here is the code. I put it in a .hlsl

    Code (CSharp):
    1.  
    2. half3 GlossyEnvironmentReflectionFix(half3 reflectVector, float3 positionWS, half perceptualRoughness, half occlusion, float2 normalizedScreenSpaceUV)
    3. {
    4. #if !defined(_ENVIRONMENTREFLECTIONS_OFF)
    5.     half3 irradiance;
    6.  
    7. #if defined(_REFLECTION_PROBE_BLENDING) || USE_FORWARD_PLUS
    8.     irradiance = CalculateIrradianceFromReflectionProbes(reflectVector, positionWS, perceptualRoughness, normalizedScreenSpaceUV);
    9. #else
    10. #ifdef _REFLECTION_PROBE_BOX_PROJECTION
    11.     reflectVector = BoxProjectedCubemapDirection(reflectVector, positionWS, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
    12. #endif // _REFLECTION_PROBE_BOX_PROJECTION
    13.     half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
    14.     half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));
    15.  
    16.     irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
    17. #endif // _REFLECTION_PROBE_BLENDING
    18.     return irradiance * occlusion;
    19. #else
    20.     //FIX!
    21.     return 0;
    22.     //return _GlossyEnvironmentColor.rgb * occlusion;
    23. #endif // _ENVIRONMENTREFLECTIONS_OFF
    24. }
    25.  
    26. #if !USE_FORWARD_PLUS
    27. half3 GlossyEnvironmentReflectionFix(half3 reflectVector, float3 positionWS, half perceptualRoughness, half occlusion)
    28. {
    29.     return GlossyEnvironmentReflectionFix(reflectVector, positionWS, perceptualRoughness, occlusion, float2(0.0f, 0.0f));
    30. }
    31. #endif
    32.  
    33. half3 GlossyEnvironmentReflectionFix(half3 reflectVector, half perceptualRoughness, half occlusion)
    34. {
    35. #if !defined(_ENVIRONMENTREFLECTIONS_OFF)
    36.     half3 irradiance;
    37.     half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
    38.     half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));
    39.  
    40.     irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
    41.  
    42.     return irradiance * occlusion;
    43. #else
    44.     //FIX!
    45.     return 0;
    46.     //return _GlossyEnvironmentColor.rgb * occlusion;
    47. #endif // _ENVIRONMENTREFLECTIONS_OFF
    48. }
    49.  
    Another way. Do this somewhere in the code. I put it in a function in Amplify
    _GlossyEnvironmentColor = 0;

    2024-01-05 09_39_28-SSS Obje.._.jpg
     
    Last edited: Jan 5, 2024
  8. Ben_at_Work

    Ben_at_Work

    Joined:
    Mar 16, 2022
    Posts:
    83
    Interesting. I'll have to dig into this at some point. Working through Shadergraph makes it hard to tell when features are completely eliminated since I didn't include them in the first place. I've always wondered if passing a zeroed value to the normal map channel, for example, is as performant as not having that channel in the first place.

    In any case, getting the intended visual result is the first half of the challenge and I'm curious to see if I get a different in my context if I implement that. Looks like you're using very reflective materials which is different than my poorly-lit standalone VR scenario.
     
  9. DavidMiranda

    DavidMiranda

    Joined:
    Nov 30, 2012
    Posts:
    617
    Well, after many days dealing with this problem I finally found the
    Right way to disable and skip "Specular Highlights" and "Environment Reflections" on custom shaders

    First, this is not enough:

    Code (CSharp):
    1. SSS_mat.EnableKeyword("_ENVIRONMENTREFLECTIONS_OFF");
    2. SSS_mat.EnableKeyword("_SPECULARHIGHLIGHTS_OFF");
    It will always return to normal state. Why? Because there is a float property in the shader that is turning it on all the time. So do this:

    Code (CSharp):
    1. SSS_mat.SetFloat("_SpecularHighlights", 0);
    2. SSS_mat.SetFloat("_EnvironmentReflections", 0);
    By doing so you are free to do your custom lighting experiments.
     
    Sluggy and Ben_at_Work like this.
  10. Entretoize

    Entretoize

    Joined:
    Feb 27, 2015
    Posts:
    59
    Where do you do that ? Is it a special node you need to add ?
     
  11. Ben_at_Work

    Ben_at_Work

    Joined:
    Mar 16, 2022
    Posts:
    83
    In the Blackboard, add a pair of variables to the shader using the Keyword > Boolean type, then, to match their toggle behavior, rename them to:
    • Disable Specular Highlights
    • Disable Environment Reflections

    In the Graph Inspector, select each of those variables and change their Reference name to:
    • _SPECULARHIGHLIGHTS_OFF
    • _ENVIRONMENTREFLECTIONS_OFF
    If you're working with HLSL directly, DavidMiranda posted the code they use above.