Notes sur les directives multi_compile dans les shaders Unity

Fonctionnement des directives multi_compile

Dans Unity, la directive #pragma multi_compile permet de définir des mots-clés qui génèrent différentes variantes d'un shader. Chaque mot-clé déclenche une compilation conditionnelle avec #ifdef ou #if defined.

Activation et désactivation des mots-clés

Les mots-clés peuvent être activés via l'interface de debug des matériaux, où les mots-clés valides apparaissent automatiquement s'ils sont déclarés dans un multi_compile. En code, utilisez shader.EnableKeyword() pour tous les matériaux ou material.EnableKeyword() pour un matériau spécifique.

Calcul du nombre de variantes

Le nombre de variantes dépend de la syntaxe de multi_compile.

Cas avec un seul mot-clé

Par exemple, #pragma multi_compile X génère une seule variante, car le mot-clé X est toujours défini.

Shader "Demo/VarianteUnique"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile X
            struct appdata { float4 pos : POSITION; };
            struct v2f { float4 clipPos : SV_POSITION; };
            v2f vert(appdata v) {
                v2f o;
                o.clipPos = UnityObjectToClipPos(v.pos);
                return o;
            }
            fixed4 frag(v2f i) : SV_Target {
                fixed4 couleur;
                #if defined(X)
                couleur = fixed4(1.0, 0.0, 0.0, 1.0);
                #else
                couleur = fixed4(1.0, 1.0, 1.0, 1.0);
                #endif
                return couleur;
            }
            ENDCG
        }
    }
}

Cas avec un mot-clé et un underscore

La déclaration #pragma multi_compile Y _ crée deux variantes : une avec Y défini et une sans aucun mot-clé actif.

Shader "Demo/VarianteAvecUnderscore"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile Y _
            struct appdata { float4 pos : POSITION; };
            struct v2f { float4 clipPos : SV_POSITION; };
            v2f vert(appdata v) {
                v2f o;
                o.clipPos = UnityObjectToClipPos(v.pos);
                return o;
            }
            fixed4 frag(v2f i) : SV_Target {
                fixed4 couleur;
                #if defined(Y)
                couleur = fixed4(0.0, 1.0, 0.0, 1.0);
                #else
                couleur = fixed4(1.0, 1.0, 1.0, 1.0);
                #endif
                return couleur;
            }
            ENDCG
        }
    }
}

Cas avec plusieurs mots-clés

Pour #pragma multi_compile A B C, il y a trois variantes, et si aucun mot-clé n'est activé, le premier (A) est utilisé par défaut. L'ajout d'unn underscore, comme dans #pragma multi_compile D E _, permet une option où aucun mot-clé n'est sélectionné.

Exemple combiné

Considérons deux déclarations : #pragma multi_compile P Q R et #pragma multi_compile S T. Le nombre total de variantes est le produit des options de chaque ligne, soit 3 × 2 = 6. Voici un shader illustrant cela avec des noms de variables modifiés :

Shader "Demo/VariantesCombinees"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile P Q R
            #pragma multi_compile S T
            struct appdata { float4 position : POSITION; };
            struct v2f { float4 screenPos : SV_POSITION; };
            v2f vert(appdata v) {
                v2f o;
                o.screenPos = UnityObjectToClipPos(v.position);
                return o;
            }
            fixed4 frag(v2f i) : SV_Target {
                fixed4 pixel = fixed4(0.0, 0.0, 0.0, 1.0);
                #if defined(P)
                pixel += fixed4(0.2, 0.0, 0.0, 0.0);
                #endif
                #if defined(Q)
                pixel += fixed4(0.0, 0.2, 0.0, 0.0);
                #endif
                #if defined(R)
                pixel += fixed4(0.0, 0.0, 0.2, 0.0);
                #endif
                #if defined(S)
                pixel += fixed4(0.0, 0.0, 0.0, 0.2);
                #endif
                #if defined(T)
                pixel += fixed4(0.1, 0.1, 0.1, 0.0);
                #endif
                return pixel;
            }
            ENDCG
        }
    }
}

Différences avec shader_feature

La directive #pragma shader_feature fonctionne différemment : avec un seul mot-clé, elle génère automatiquement une variante où le mot-clé n'est pas défini. Avec plusieurs mots-clés (sans underscore), elle agit comme un sélecteur unique, utilisant le premier mot-clé par défaut si aucun n'est actif.

Par exemple, #pragma shader_feature U crée deux variantes (avec et sans U), tandis que #pragma shader_feature V W crée deux variantes correspondant à V et W, avec V comme défaut.

Règles de calcul des variantes

Pour multi_compile sans underscore, c'est une sélection obligatoire parmi les options, avec le premier comme défaut. Avec underscore, c'est une sélection optionnelle. Le nombre total de variantes est obtenu en multipliant les options de chaque directive.

Étiquettes: Unity Shader multi_compile shader_feature CGPROGRAM

Publié le 29 juin à 07h41