shader_featureやmulti_compileでシェーダのバリアントを作る方法です。
Unity2018.2
用途
shader_featureやmulti_compileを使うと「キーワード」を定義できます。
// キーワードRED, GREENを定義 #pragma shader_feature RED GREEN
キーワードを定義すると、キーワード毎に分岐した処理を書けます。
fixed4 frag () : SV_Target { // キーワード毎に処理を分岐 #ifdef RED return fixed4(1, 0, 0, 1); #elif GREEN return fixed4(0, 1, 0, 1); #endif }
こうすると分岐毎に内部的に違うシェーダファイル(バリアント)が作られるので、
他の分岐の不要な処理をすることが無くシェーダを最適化できます。
// 内部的には下記の処理が書かれた別々のシェーダが生成されるイメージ // 1個目 fixed4 frag () : SV_Target { return fixed4(1, 0, 0, 1); } // 2個目 fixed4 frag () : SV_Target { return fixed4(0, 1, 0, 1); }
また、shader_featureは実際に使われているバリアントだけを生成します。
これに対してmulti_compileは定義されているキーワードすべての分のバリアントを生成します。
よってバリアントの数はshader_featureのほうが抑えられます。
ただしビルドには含まれないので動的にキーワードを変えるときには注意が必要です。
shader_featureの使い方
shader_featureは次のように使います。
(CGPROGRAM内のみ抜粋)
CGPROGRAM #pragma vertex vert #pragma fragment frag // キーワードを4つ定義 // _ (何も定義されていない状態), RED, GREEN, BLUE #pragma shader_feature _ RED GREEN BLUE #include "UnityCG.cginc" float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); } fixed4 frag () : SV_Target { // それぞれのキーワードが定義されているかどうかで処理を分ける #ifdef RED return fixed4(1, 0, 0, 1); #elif GREEN return fixed4(0, 1, 0, 1); #elif BLUE return fixed4(0, 0, 1, 1); #else return fixed4(1, 1, 1, 1); #endif } ENDCG
multi_compileの使い方
multi_compileは前節のshader_featureの部分を書き換えるだけです。
CGPROGRAM #pragma vertex vert #pragma fragment frag // キーワードを4つ定義 // _ (何も定義されていない状態), RED, GREEN, BLUE #pragma multi_compile _ RED GREEN BLUE #include "UnityCG.cginc" float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); } fixed4 frag () : SV_Target { // それぞれのキーワードが定義されているかどうかで処理を分ける #ifdef RED return fixed4(1, 0, 0, 1); #elif GREEN return fixed4(0, 1, 0, 1); #elif BLUE return fixed4(0, 0, 1, 1); #else return fixed4(1, 1, 1, 1); #endif } ENDCG
キーワードの切り換え方①
キーワードはMaterial.EnableKeyword()とMaterial.DisableKeyword()によって書き換えられます。
material.DisableKeyword("BLUE"); material.EnableKeyword("RED");
キーワードの切り換え方②
複数マテリアルに共通のキーワード(グローバルキーワード)を書き換えるにはShaderクラスを使います。
Shader.EnableKeyword("RED"); Shader.DisableKeyword("GREEN");
キーワードの切り換え方➂
KeywordEnumアトリビュートを使うとシェーダのプロパティから適用するキーワードを選べます。
Shader "Example" { Properties { [KeywordEnum(RED, GREEN, BLUE)] _Color ("Color", Float) = 0 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // 「プロパティ名_KeywordEnumの名前」を大文字にしたものがキーワードとなる #pragma shader_feature _COLOR_RED _COLOR_GREEN _COLOR_BLUE #include "UnityCG.cginc" float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); } fixed4 frag () : SV_Target { #ifdef _COLOR_RED return fixed4(1, 0, 0, 1); #elif _COLOR_GREEN return fixed4(0, 1, 0, 1); #elif _COLOR_BLUE return fixed4(0, 0, 1, 1); #else return fixed4(1, 1, 1, 1); #endif } ENDCG } } }
インスペクタからドロップダウンリストで選べます。
キーワードの切り換え方④
Toggleアトリビュートを使うとシェーダのプロパティからキーワードをON/OFFできます。
Shader "Example" { Properties { [Toggle] _Red ("Is Red?", Float) = 0 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // 「プロパティ名_ON」という名前のキーワードが定義される #pragma shader_feature _ _RED_ON #include "UnityCG.cginc" float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); } fixed4 frag () : SV_Target { #ifdef _RED_ON return fixed4(1, 0, 0, 1); #else return fixed4(1, 1, 1, 1); #endif } ENDCG } } }
キーワードの名前を明示的に指定することもできます。
Shader "Example" { Properties { [Toggle(IS_RED)] _Red ("Is Red?", Float) = 0 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // 指定した名前のキーワードが定義される #pragma shader_feature _ IS_RED #include "UnityCG.cginc" float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); } fixed4 frag () : SV_Target { #ifdef IS_RED return fixed4(1, 0, 0, 1); #else return fixed4(1, 1, 1, 1); #endif } ENDCG } } }
インスペクタにはトグルが表示されます。