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

Question Switch shader by quality

Discussion in 'Shaders' started by thang_unity516, Sep 13, 2023.

  1. thang_unity516

    thang_unity516

    Joined:
    Oct 29, 2021
    Posts:
    30
    I intend to have my shaders switched by using shader keyword: multi_compile QUALITY_LOW QUALITY_MED QUALITY_HIGH. It worked in vert or frag shader. But I wonder:

    1. Can I switch SubShader?
    2. Can I switch Pass?
    3. Can I use Amplify Shader Editor to do those things on the above?

    Thanks for your concern
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,236
    You can't switch pass, but you can switch SubShader using the ShaderLab LOD.
    https://docs.unity3d.com/Manual/SL-ShaderLOD.html

    The LOD value are completely arbitrary, so you're free to assign whatever LOD levels you want. If you're using Unity's built in shaders and don't want to disable them, you can just use LOD levels higher than those used by Unity. And then the global Shader LOD can be set via script or via quality settings.

    However this method is mostly not used today. You can set an LOD for a SubShader in ASE, but I don't think it supports multiple SubShaders, so I think the multi_compile method may be the easier option.
     
    thang_unity516 likes this.
  3. Amplify_David

    Amplify_David

    Joined:
    Mar 29, 2023
    Posts:
    111
    thang_unity516 likes this.
  4. thang_unity516

    thang_unity516

    Joined:
    Oct 29, 2021
    Posts:
    30
    Thanks for your quick reply. I test the LOD and it works. But I have some more questions. Here is my test shader to specific the section for each quality, which high quality use LOD and low + med use multi compile (code diff in frag shader only)

    Code (CSharp):
    1. Shader "Test/ShaderKeywordTest"
    2. {
    3.     //high quality here, using LOD to define
    4.     SubShader
    5.     {
    6.         LOD 600
    7.         Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
    8.  
    9.         ZTest On
    10.         ZWrite Off
    11.  
    12.         Blend SrcAlpha OneMinusSrcAlpha
    13.  
    14.         Pass
    15.         {
    16.             HLSLPROGRAM
    17.  
    18.             #include "UnityCG.cginc"
    19.             #include "UnityUI.cginc"
    20.  
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.  
    24.             struct appdata
    25.             {
    26.                 half4 vertex : POSITION;
    27.                 half2 uv : TEXCOORD0;
    28.                 half4 color    : COLOR;
    29.             };
    30.  
    31.             struct v2f
    32.             {
    33.                 half2 uv : TEXCOORD0;
    34.                 half4 vertex : SV_POSITION;
    35.                 half alpha : TEXCOORD1;
    36.                 float4 worldPosition : TEXCOORD2;
    37.             };
    38.  
    39.             v2f vert (appdata v)
    40.             {
    41.                 v2f o;
    42.                 o.worldPosition = v.vertex;
    43.                 o.vertex = UnityObjectToClipPos(v.vertex);
    44.                 o.uv = v.uv;
    45.                 o.alpha = v.color.a;
    46.                 return o;
    47.             }
    48.        
    49.             half4 frag(v2f input) : SV_Target
    50.             {
    51.                     return half4(0,0,1,0.5);
    52.             }
    53.        
    54.             ENDHLSL
    55.         }
    56.     }
    57.  
    58.     //low and med quality here, using multi_compile keyword
    59.     SubShader
    60.     {
    61.         LOD 300
    62.  
    63.         Tags{ "Queue" = "Geometry" "RenderType" = "Opaque" }
    64.  
    65.         Pass
    66.         {
    67.             HLSLPROGRAM
    68.  
    69.             #include "UnityCG.cginc"
    70.             #include "UnityUI.cginc"
    71.             #pragma multi_compile QUALITY_LOW QUALITY_MED
    72.  
    73.             #pragma vertex vert
    74.             #pragma fragment frag
    75.        
    76.             struct appdata
    77.             {
    78.                 half4 vertex : POSITION;
    79.                 half2 uv : TEXCOORD0;
    80.                 half4 color    : COLOR;
    81.             };
    82.  
    83.             struct v2f
    84.             {
    85.                 half2 uv : TEXCOORD0;
    86.                 half4 vertex : SV_POSITION;
    87.                 half alpha : TEXCOORD1;
    88.                 float4 worldPosition : TEXCOORD2;
    89.             };
    90.  
    91.             v2f vert (appdata v)
    92.             {
    93.                 v2f o;
    94.                 o.worldPosition = v.vertex;
    95.                 o.vertex = UnityObjectToClipPos(v.vertex);
    96.                 o.uv = v.uv;
    97.                 o.alpha = v.color.a;
    98.                 return o;
    99.             }
    100.  
    101.             #if QUALITY_LOW
    102.        
    103.             half4 frag(v2f input) : SV_Target
    104.             {
    105.                     return half4(1,0,0,1);
    106.             }
    107.        
    108.             #elif QUALITY_MED
    109.        
    110.             half4 frag(v2f input) : SV_Target
    111.             {
    112.                     return half4(0,1,0,1);
    113.             }
    114.        
    115.             #endif
    116.        
    117.             ENDHLSL
    118.         }
    119.     }
    120.  
    121. }
    So, I what I wonder are:
    1. How many variants does this compile? Will they be:
    LOD 600
    LOD 300

    QUALITY_LOW
    and
    LOD 600
    LOD 300

    QUALITY_MED
    2. I have a warning said that this shader might be expensive. Which part makes it expensive? If the cause is multi subshaders, is that the reason why it is not common use nowadays?
    ---------------------------------------------------------------------------------------------
    About the multi_compile, as I remember, I can only use this keyword in the HLSL section, aren't I? That means I can modify in the Pass section cause that's the only place I put my HLSL codes. Also means that, I can't change the Pass or the SubShader using shader keyword. Please correct me if I'm wrong.
     
    Last edited: Sep 18, 2023
  5. thang_unity516

    thang_unity516

    Joined:
    Oct 29, 2021
    Posts:
    30
    Thanks for your reply, Amplify_David
    upload_2023-9-14_16-26-55.png
    I don't remind any nodes can do something like this (the extreme, ultra and high ones). Is that in the template and those nodes are passes?

    I saw this node. Unfortunately, my team use 4 quality defined instead of 3 so I make my own keyword and use static switch instead
    ---------------------------------------------------------------------------------------------------------------
    BTW, can I make the pass section use different vert, frag or even data make use of shader keyword? It may look like this:
    Code (CSharp):
    1.  
    2.            #if QUALITY_LOW
    3.            
    4.             half4 frag(v2f input) : SV_Target
    5.             {
    6.                     return half4(1,0,0,1);
    7.             }
    8.            
    9.             #elif QUALITY_MED
    10.            
    11.             half4 frag(v2f input) : SV_Target
    12.             {
    13.                     return half4(0,1,0,1);
    14.             }
    15.            
    16.             #endif
    17.  
    The reason is our artist make the low and high quality shader so different. Instead of turn on off different features in frag or vert function, I think it's easier this way
     
  6. thang_unity516

    thang_unity516

    Joined:
    Oct 29, 2021
    Posts:
    30
    After sometimes checking the doc, I think I can combine SubShader LOD and fallback for this.

    For example:
    - Shader High: LOD 600, fallback to shader med
    - Shader Med: LOD 300
    - Material will be assigned with shader high (the one with highest LOD)
    - Then I will control which shader can work using set shader LOD (650 for high to run, 350 for med to run)

    The only problem to resolve is the performance. I'll take the test with ARM streamline, yet does anybody know the cost of subshader switched? I searched but have no info about this