多くの場合、固定されたシェーダーコードの断片の大部分を保持するだけでなく、わずかに異なるシェーダー「バリアント」を作成できるようにしておくと便利です。一般に「メガシェーダー」や「ウーバーシェーダー」と呼ばれ、ケースごとに異なるプリプロセッサーディレクティブでシェーダーコードを複数回コンパイルすることで達成されます。
Unity では、これは シェーダースニペットに #pragma multi_compile
または #pragma shader_feature
を追加することによって達成することができます。これも サーフェースシェーダー で動作します。
実行時には、適切なシェーダーバリアントは、マテリアルのキーワード (Material.EnableKeyword と DisableKeyword) またはグローバルシェーダーキーワード (Shader.EnableKeyword と DisableKeyword ) からピックアップされます。
以下はディレクティブの例です。
# pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
上のディレクティブは 2 つのシェーダーバリアント、FANCY_STUFF_OFF
定義のものと、FANCY_STUFF_ON
定義のものを生産します。実行時に、そのうちの 1 つは、マテリアルとグローバルシェーダーキーワードを基にアクティベートされます。これら 2 つのキーワードのどちらも使用可能になっていない場合、最初のもの (“off”) が使用されます。
multi_compile の行に複数の 2 つのキーワードがある場合もあります。例えば、これは 4 つのシェーダーバリアントを生成します。
# pragma multi_compile SIMPLE_SHADING BETTER_SHADING GOOD_SHADING BEST_SHADING
名前のいずれかがすべてのアンダースコアの場合、シェーダーバリアントはプリプロセッサーマクロの定義なしで生成されます。2 つのキーワードを使い果たすことを避けるために、これはシェーダー機能のために一般的に用いられます (下のキーワード制限の注意を参照してください)。例えば、下のディレクティブは 2 つのシェーダーバリアントを生成します。最初のは、何も定義されてないもので、2 番目は FOO_ON
定義されたものです。
# pragma multi_compile __ FOO_ON
#pragma shader_feature
は、#pragma multi_compile
と非常によく似ています。唯一の違いは、shader_feature のシェーダーの未使用のバリアントがゲームのビルドに含まれないことです。ですから、shader_feature はキーワードのためにもっとも理にかなっているマテリアル上に設定され、キーワードのための multi_compile はグローバルコードから設定されます。
さらに、1 つのキーワードから成る簡略表記があります。
# pragma shader_feature FANCY_STUFF
上記は #pragma shader_feature _ FANCY_STUFF
のためのショートカットです。すなわち、2 つのシェーダーバリアントに展開されます (最初のひとつは定義なし、もう 1 つは定義あり)。
複数の multi_compile の行が可能で、そして得られたシェーダーが行の可能な組み合わせすべてのためにコンパイルされます。
# pragma multi_compile A B C
# pragma multi_compile D E
これは、最初の行の 3 つのバリアントと 2 行目の 2 つ、または合計 6 のシェーダーバリアント( A+ D、B + D、C + D、A+ E、B+ E、C+ E )を生成します。
各 multi_compile 行を、制御を行う 1 つのシェーダー「関数」と考えると簡単です。シェーダーバリアントの総数は、このようにとても急速に増えることに注意してください。たとえば、 2 つのオプションがついた 10 の multi_compile 関数は、それぞれ合計で 1024 シェーダーバリアントを生成します。
シェーダーバリアントを使用する場合、Unity には 256個というキーワードの制限があり、約 60 個が内部で使用される (したがって使用可能な制限数が減る) ことに注意してください。 また、キーワードは特定の Unity プロジェクト全体でグローバルに有効になっています。そのため、複数のキーワードが複数の異なるシェーダで定義されている場合は、制限を超えないように注意が必要です。
複数のシェーダーバリアントをコンパイルするのに、いくつかの「ショートカット」表記があります。それらは Unity の異なる種類のライト、影、ライトマップに対処します。詳しくは Unity のレンダリングパイプライン を参照してください。
multi_compile_fwdbase
は、ForwardBase
(フォワードレンダリングベース)
パスタイプに必要なすべてのバリアントをコンパイルします。これらのバリアントは異なるライトマップタイプや、影をオン/オフに切り替える主要なディレクショナルライトに対応します。multi_compile_fwdadd
は、ForwardAdd
(付加的なフォワードレンダリング) のパスタイプのためのバリアントをコンパイルします。これは、ディレクショナルライト、スポットライト、ポイントライトタイプを処理するためのバリアントと、クッキーテクスチャを持つバリアントをコンパイルします。multi_compile_fwdadd_fullshadows
- 上記と同じですが、ライトにリアルタイムシャドウを加える機能も含まれています。multi_compile_fog
は、異なるフォグの種類(off/linear/exp/exp2)を処理するいくつかのバリアントを展開します。組み込みのショートカットのほとんどが、かなり多くのシェーダーバリアントを生成します。それらが不要なことを分かっている場合、#pragma skip_variants
を使用して、いくつかのコンパイルをスキップすることが可能です (以下はその例)。
# pragma multi_compile_fwdadd
// すべてのバリアントを作成します
// "POINT" と "POINT_COOKIE" はスキップされます
# pragma skip_variants POINT POINT_COOKIE
シェーダーバリアントを使用する一般的な理由の1つは、OpenGL ES などの 1 つのターゲットプラットフォーム内でハイエンドとローエンドのハードウェアがある場合、その両方で効率的に実行できるフォールバックまたは簡易化したシェーダを作成するためです。互換性のレベルが異なるハードウェアに対し、それぞれに最適化したバリアントを提供するために、シェーダーハードウェアバリアントを利用できます。
シェーダーハードウェアバリアントの生成を可能にするためには、#pragma hardware_tier_variants renderer
を加え、 renderer
を シェーダープログラム を利用可能なレンダリングプラットフォームの 1つにします。他のキーワードに関係なく、この #pragma
で、各シェーダーごとに 3つのシェーダーバリアントが生成されます。それぞれのバリアントは、以下の定義ざれたもののうち 1つを持ちます。
UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3
これらを使用して、ローエンドまたはハイエンドのために、条件付きフォールバックや追加機能を作成できます。ティアの変更を行える Graphics Emulation メニューを使用して、どのティアのテストもエディターで行えます。
これらのバリアントの影響をできるだけ少なく保つように、1組のシェーダーのみがプレイヤーに読み込まれます。さらに、例えば、特別なバージョンを TIER1 のみに書き、残りはすべて同じである場合にように、同一のシェーダーはすべて、ディスク上で余分なスペースを取りません。
読み込み時には、Unity は使用中の GPU を検証して、ティアの値を自動検出します。GPU が自動検出されない場合は、デフォルトで最も高いティア値へ設定します。Shader.globalShaderHardwareTier
を設定してこのティアの値をオーバーライドできます。ただし、変更したいシェーダーが読み込みされないうちに行わなくてはなりません。一度、シェーダーが読み込まれると、それに付随するバリアントがあるため、値が有効になりません。主要シーンを読み込む前に、読み込みをまだ行っていないシーンで行うとよいでしょう。
これらのシェーダーハードウェアティアは、プレイヤーの品質設定に関連していないことに注意してください。シェーダーは、プレイヤーが作動している GPU の相対的な能力を基に検出されます。
さまざまな端末ティアのシェーダーコードを調整する以外にも、Unity 内部の定義を調節したい場合があるかもしれません (例えば、モバイルでカスケードシャドウを強制する場合など)。これについての詳細は、UnityEditor.Rendering.PlatformShaderSettings を参照してください。ここでは、ティアごとにオーバーライドするために現在サポートされている機能の一覧を提供しています。 プラットフォームごと、ティアごとに、プラットフォームシェーダー設定を調節するには、UnityEditor.Rendering.EditorGraphicsSettings.SetShaderSettingsForPlatform を使用してください。
異なるティアに設定した PlatformShaderSetting
が異なる場合は、たとえ #pragma hardware_tier_variants
がなくても、ティアのバリアントはそのシェーダー用に生成されます。