Search Unity

[SOLVED] Shader.EnableKeyword does nothing

Discussion in 'General Graphics' started by HarryCodder, Apr 10, 2015.

  1. HarryCodder

    HarryCodder

    Joined:
    Feb 20, 2015
    Posts:
    84
    Hello everyone,

    I though I could use Shader.EnableKeyword and Shader.DisableKeyword to change shaders behaviour in different materials automatically but I can't make it work, maybe I'm doing something wrong.

    I've setup a test scene with a cube rendering with a material with the simplest custom shader I could do :

    Code (Shader):
    1. Shader "Custom/Test"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.     }
    7.  
    8.     SubShader
    9.     {
    10.         Tags { "Queue" = "Geometry" "RenderType"="Opaque" "ForceNoShadowCasting" = "True" }
    11.         LOD 200
    12.        
    13.         Pass
    14.         {
    15.             Name "FORWARD"
    16.             Tags{ "LightMode" = "ForwardBase" }
    17.  
    18.             CGPROGRAM
    19.  
    20.             #pragma target 2.0
    21.  
    22.             #pragma multi_compile_fwdbase
    23.  
    24.             #pragma multi_compile KEYWORD_OFF KEYWORD_ON
    25.  
    26.             #pragma vertex vert
    27.             #pragma fragment frag
    28.  
    29.             half4 _Color;
    30.  
    31.             struct vin
    32.             {
    33.                 float4 vertex : POSITION;
    34.             };
    35.  
    36.             struct vout
    37.             {
    38.                 float4 pos : SV_POSITION;
    39.             };
    40.  
    41.             vout vert(vin v)
    42.             {
    43.                 vout o;
    44.                 UNITY_INITIALIZE_OUTPUT(vout, o);
    45.  
    46.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    47.  
    48.                 return o;
    49.             };
    50.  
    51.             half4 frag(vout i) : SV_Target
    52.             {
    53.                 #ifdef KEYWORD_ON
    54.                     return half4(0,0,0,1);
    55.                 #else
    56.                     return _Color;
    57.                 #endif
    58.             };
    59.  
    60.             ENDCG
    61.         }
    62.     }
    63.     FallBack "Unlit/Color"
    64. }
    65.  
    and made a really simple script to test it :

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [ExecuteInEditMode]
    5. public class Test : MonoBehaviour
    6. {
    7.     public bool activateShaderKeyword = false;
    8.     protected bool m_activateShaderKeyword = false;
    9.  
    10.     void Update ()
    11.     {
    12.         if (activateShaderKeyword != m_activateShaderKeyword)
    13.         {
    14.             m_activateShaderKeyword = activateShaderKeyword;
    15.             if (activateShaderKeyword)
    16.             {
    17.                 Debug.Log("Enabling Keyword \"KEYWORD_ON\"");
    18.                 Shader.EnableKeyword("KEYWORD_ON");
    19.             }
    20.             else
    21.             {
    22.                 Debug.Log("Enabling Keyword \"KEYWORD_OFF\"");
    23.                 Shader.EnableKeyword("KEYWORD_OFF");
    24.             }
    25.         }
    26.     }
    27. }
    So whenever I change the "activateShaderKeyword" box in my script, it should render my cube black instead of its color.

    But it actually does nothing...

    I've search for answers and found nothing helpful so if you have an idea, I'm interested.
    Thanks in advance !
     
  2. raja-bala

    raja-bala

    Joined:
    Jul 11, 2012
    Posts:
    29
    I think you should be using #if defined(KEYWORD_ON) instead of #if def. See if that helps.
    I don't know if Shader.Enable* is the right way to use it. I generally invoke it from the material.

    void SetKeyword(Material m, bool firstOn, string firstKeyword, string secondKeyword){
    m.EnableKeyword(firstOn? firstKeyword : secondKeyword);
    m.DisableKeyword(firstOn? secondKeyword : firstKeyword);
    }

    SetKeyword(myMat, myBool, "KEYWORD_ON", "KEYWORD_OFF");
     
  3. HarryCodder

    HarryCodder

    Joined:
    Feb 20, 2015
    Posts:
    84
    Hello,

    I couldn't find a case where #if defined behave differently than #ifdef but maybe there are.

    In the end, I managed to make it work and the solution is pretty simple,
    you just have to also disable the currently activated keyword like that:
    Code (CSharp):
    1. Shader.EnableKeyword("KEYWORD_ON");
    2. Shader.DisableKeyword("KEYWORD_OFF");
    I don't know why I thought this would be automatic, maybe it should be added to the documentation.
     
    CGPal and antoniolea like this.
  4. FabioZocklabs

    FabioZocklabs

    Joined:
    Jul 11, 2019
    Posts:
    17
    I didn't test it yet, but I guess, you need to do
    Code (CSharp):
    1. #pragma shader_feature KEYWORD_ON
    instead of
    Code (CSharp):
    1. #pragma multi_compile KEYWORD_OFF KEYWORD_ON
     
    l1q, jonathan_timmerlid and a3dline like this.
  5. jonathan_timmerlid

    jonathan_timmerlid

    Joined:
    Feb 15, 2018
    Posts:
    7
    This worked in one of our cases.