ビルトインのシェーダー変数
GLSL シェーダープログラム

複数のシェーダープログラムのバリアントを作る

多くの場合、固定されたシェーダーコードの断片の大部分を保持するだけでなく、わずかに異なるシェーダー“変異体”を製造ができるようにしておくと便利です。一般に“メガシェーダー”や“ウーバーシェーダー”と呼ばれ、おのおののケースのために異なるプリプロセッサー指令でシェーダーコード複数回コンパイルすることで達成されます。

Unity では、これは シェーダースニペット#pragma multi_compile または #pragma shader_feature を追加することによって達成することができます。これも サーフェースシェーダー で動作します。

実行時には、適切なシェーダーバリアントは、マテリアルのキーワード(Material.EnableKeyword と DisableKeyword)またはグローバルシェーダーキーワード( Shader.EnableKeyword と DisableKeyword )からピックアップされます。

どのように multi_compile の作業をするか

以下はディレクティブの例です。

#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

shader_feature と multi_compile の違い

#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 ラインの組み合わせ

複数の 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 プロジェクト全体でグローバルに有効になっています。そのため、複数のキーワードが複数の異なるシェーダで定義されている場合は、制限を超えないように注意が必要です。

ビルトイン multi_compile ショートカット

複数のシェーダーバリアントをコンパイルするのに、いくつかの「ショートカット」表記があります。それらは 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
// will make all variants containing
// "POINT" or "POINT_COOKIE" be skipped
#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 がなくても、ティアのバリアントはそのシェーダー用に生成されます。

関連項目

ビルトインのシェーダー変数
GLSL シェーダープログラム