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.