[SOLVED] Shader.EnableKeyword does nothing

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 :

Shader "Custom/Test"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags { "Queue" = "Geometry" "RenderType"="Opaque" "ForceNoShadowCasting" = "True" }
        LOD 200
       
        Pass
        {
            Name "FORWARD"
            Tags{ "LightMode" = "ForwardBase" }

            CGPROGRAM

            #pragma target 2.0

            #pragma multi_compile_fwdbase

            #pragma multi_compile KEYWORD_OFF KEYWORD_ON

            #pragma vertex vert
            #pragma fragment frag

            half4 _Color;

            struct vin
            {
                float4 vertex : POSITION;
            };

            struct vout
            {
                float4 pos : SV_POSITION;
            };

            vout vert(vin v)
            {
                vout o;
                UNITY_INITIALIZE_OUTPUT(vout, o);

                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

                return o;
            };

            half4 frag(vout i) : SV_Target
            {
                #ifdef KEYWORD_ON
                    return half4(0,0,0,1);
                #else
                    return _Color;
                #endif
            };

            ENDCG
        }
    }
    FallBack "Unlit/Color"
}

and made a really simple script to test it :

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class Test : MonoBehaviour
{
    public bool activateShaderKeyword = false;
    protected bool m_activateShaderKeyword = false;

    void Update ()
    {
        if (activateShaderKeyword != m_activateShaderKeyword)
        {
            m_activateShaderKeyword = activateShaderKeyword;
            if (activateShaderKeyword)
            {
                Debug.Log("Enabling Keyword \"KEYWORD_ON\"");
                Shader.EnableKeyword("KEYWORD_ON");
            }
            else
            {
                Debug.Log("Enabling Keyword \"KEYWORD_OFF\"");
                Shader.EnableKeyword("KEYWORD_OFF");
            }
        }
    }
}

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 !

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”);

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:

Shader.EnableKeyword("KEYWORD_ON");
Shader.DisableKeyword("KEYWORD_OFF");

I don’t know why I thought this would be automatic, maybe it should be added to the documentation.

2 Likes

I didn’t test it yet, but I guess, you need to do #pragma shader_feature KEYWORD_ON instead of #pragma multi_compile KEYWORD_OFF KEYWORD_ON

3 Likes

This worked in one of our cases.