Search Unity

Question shader_feature? BEVEL_ON, GLOW_ON, UNDERLAY_ON

Discussion in 'Shaders' started by Unifikation, Mar 18, 2023.

  1. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    What are these things, and how do I get their state and set/copy their state from one material to another?

    TMP has these three "properties", listed in its shaders, under Pass { CGPROGRAM ...

    #pragma shader_feaature __ BEVEL_ON
    #pragma shader_feaature __ UNDERLAY_ON UNDERLAY_INNER
    #pragma shader_feaature __ GLOW_ON


    These are then treated like booleans:

    #if (UNDERLAY_ON || UNDERLAY_INNER) 
    // do stuff
    #endif


    I can't find where to, nor how to get their state, or how to set them.

    I may have a misunderstanding of what they are.
     
  2. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
  3. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
  4. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Can you set up some materials before-hand in the editor and then swap at runtime?

    While you can change these things, it will work in the editor, and then suddenly break in the player because of shader stripping. So you'll need to understand how shader stripping works, and possibly add some dummy materials to a built scene/resources with the relevant keywords enabled. Assuming the materials *aren't* being stripped, then you can use
    m.EnableKeyword("GLOW_ON");
    .
     
  5. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    Am trying to make an editor script to work around a couple of bugs in the Editor, and speed up instancing.

    https://forum.unity.com/threads/copy-material-properties-and-create-material-preset-broken.1413801/
     
  6. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
  7. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    So they're not booleans, they're something else that's active, or not active?

    I don't really understand what it means that they're a keyword, nor that a keyword can be active or inactive.

    Thank you!!!
     
  8. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Yes.

    What variant is chosen is based on several factors, including the combination of keywords. Every unique combination of keywords (including keywords defined as shader_feature, those with multi_compile, and some internal/global ones) form completely separate shader programs. From the perspective of the GPU, they might as well be on different disks; only one of them is selected to run. However, from the perspective of the CPU, a single shader can have thousands - sometimes even millions of variants. If you've ever compiled Unity and watched it be stuck on compiling shader variants for 2 hours, that's what it's doing -- preparing millions of completely separate computer programs to choose from.

    A boolean variable is a variable inside one of those programs (really in the constant buffer the app sends). Keywords OTOH determine which variant, which means a completely separate piece of code needs to be sent to the GPU for execution.
     
  9. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    Would it be somewhat accurate and reasonable to think of "keywords" as the names of functions/methods that are to be compiled and available within a shader's whole?
     
  10. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    No; it's better to think of them as booleans.

    Shaders are compiled based on a combination of keywords. With those 3 options, plus the
    multi_compile __ UNITY_UI_CLIP_RECT
    and
    multi_compile __ UNITY_UI_ALPHACLIP
    , there's 48 different possible programs...

    Code (csharp):
    1. UNITY_UI_CLIP_RECT    UNITY_UI_ALPHACLIP   BEVEL_ON   UNDERLAY_ON   UNDERLAY_INNER   GLOW_ON
    2. ==================    ==================   ========   ===========   ==============   =======
    3. OFF                   OFF                  OFF        OFF           OFF              OFF
    4. OFF                   OFF                  OFF        OFF           OFF              ON
    5. OFF                   OFF                  OFF        OFF           ON               OFF
    6. OFF                   OFF                  OFF        OFF           ON               ON
    7. OFF                   OFF                  OFF        ON            OFF              OFF
    8. OFF                   OFF                  OFF        ON            OFF              ON
    9. OFF                   OFF                  ON         OFF           OFF              OFF
    10. OFF                   OFF                  ON         OFF           OFF              ON
    11. OFF                   OFF                  ON         OFF           ON               OFF
    12. OFF                   OFF                  ON         OFF           ON               ON
    13. OFF                   OFF                  ON         ON            OFF              OFF
    14. OFF                   OFF                  ON         ON            OFF              ON
    15. OFF                   ON                   OFF        OFF           OFF              OFF
    16. OFF                   ON                   OFF        OFF           OFF              ON
    17. OFF                   ON                   OFF        OFF           ON               OFF
    18. OFF                   ON                   OFF        OFF           ON               ON
    19. OFF                   ON                   OFF        ON            OFF              OFF
    20. OFF                   ON                   OFF        ON            OFF              ON
    21. OFF                   ON                   ON         OFF           OFF              OFF
    22. OFF                   ON                   ON         OFF           OFF              ON
    23. OFF                   ON                   ON         OFF           ON               OFF
    24. OFF                   ON                   ON         OFF           ON               ON
    25. OFF                   ON                   ON         ON            OFF              OFF
    26. OFF                   ON                   ON         ON            OFF              ON
    27. ON                    OFF                  OFF        OFF           OFF              OFF
    28. ON                    OFF                  OFF        OFF           OFF              ON
    29. ON                    OFF                  OFF        OFF           ON               OFF
    30. ON                    OFF                  OFF        OFF           ON               ON
    31. ON                    OFF                  OFF        ON            OFF              OFF
    32. ON                    OFF                  OFF        ON            OFF              ON
    33. ON                    OFF                  ON         OFF           OFF              OFF
    34. ON                    OFF                  ON         OFF           OFF              ON
    35. ON                    OFF                  ON         OFF           ON               OFF
    36. ON                    OFF                  ON         OFF           ON               ON
    37. ON                    OFF                  ON         ON            OFF              OFF
    38. ON                    OFF                  ON         ON            OFF              ON\
    39. ON                    ON                   OFF        OFF           OFF              OFF
    40. ON                    ON                   OFF        OFF           OFF              ON
    41. ON                    ON                   OFF        OFF           ON               OFF
    42. ON                    ON                   OFF        OFF           ON               ON
    43. ON                    ON                   OFF        ON            OFF              OFF
    44. ON                    ON                   OFF        ON            OFF              ON
    45. ON                    ON                   ON         OFF           OFF              OFF
    46. ON                    ON                   ON         OFF           OFF              ON
    47. ON                    ON                   ON         OFF           ON               OFF
    48. ON                    ON                   ON         OFF           ON               ON
    49. ON                    ON                   ON         ON            OFF              OFF
    50. ON                    ON                   ON         ON            OFF              ON

    Every one of them is a completely separate program, and the code for them could be different. It would be the same as if someone just wrote 48 different separate shaders. However, that's annoying to do, so there's something called the preprocessor that takes special directives and rewrites the code 48 times with slightly different variations. For example, there's this code in TMP:

    Code (CSharp):
    1.             output.viewDir =    mul((float3x3)_EnvMatrix, _WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, vert).xyz);
    2.             #if (UNDERLAY_ON || UNDERLAY_INNER)
    3.             output.texcoord2 = float4(input.texcoord0 + bOffset, bScale, bBias);
    4.             output.underlayColor =    underlayColor;
    5.             #endif
    6.             output.textures = float4(faceUV, outlineUV);
    The preprocessor splits that up into...

    Code (CSharp):
    1.             output.viewDir =    mul((float3x3)_EnvMatrix, _WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, vert).xyz);
    2.             output.textures = float4(faceUV, outlineUV);
    And...

    Code (CSharp):
    1.             output.viewDir =    mul((float3x3)_EnvMatrix, _WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, vert).xyz);
    2.             output.texcoord2 = float4(input.texcoord0 + bOffset, bScale, bBias);
    3.             output.underlayColor =    underlayColor;
    4.             output.textures = float4(faceUV, outlineUV);
    And then compiles them separately. The GPU doesn't know anything about the preprocessor.

    Note that because the preprocessor is run before the main compiler, you can completely break syntax. Which can be (ab)used for parameter definitions in methods, for example...

    Code (CSharp):
    1. void applyLighting(float3 position, float3 normal, float4 tangent, float3 lightDir,
    2. #if POINT_LIGHT
    3.     float3 lightPosition, float lightRange,
    4. #endif
    5.     float3 lightColor)
    ===============================

    If you're not actually writing shaders, it's OK to think of them as a special type of boolean.
     
    Last edited: Mar 21, 2023
    Unifikation likes this.
  11. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    Argh...


    So... guessing... when I'm in the editor switching on and off Glow, Bevel and Underlay, that's like "flagging" for this material to have a unique combination of preprocessor settings along with whatever I've done to the colours, such that a unique Material is created with a unique combination of features used, thanks to these "flags" that tell the preprocessor how to compile/structure the Material's resultant/needed shader?
     
  12. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Yup! :)
     
    Unifikation likes this.
  13. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    Thank you!!!