ビルトインのシェーダー変数
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 つ(“off”)が使用されます。

multi_compile 行に複数の二つのキーワードがある場合もあり、例えば、これは 4 つのシェーダーバリアントが生成されます。

#pragma multi_compile SIMPLE_SHADING BETTER_SHADING GOOD_SHADING BEST_SHADING

名前のいずれかがすべてのアンダースコアの場合、次にシェーダーバリアントが定義されたプリプロセッサマクロなしで生成されます。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 )を生成。

これは、単一のシェーダー“feature”を制御するように各 multi_compile 行を考えるのがもっとも簡単です。シェーダーバリアントの総数はこのように本当に速く成長していることに注意してください。たとえば、10 の multi_compile“feature”と 2 つのオプションはそれぞれが合計で 1024 シェーダーバリアントを生産します。

キーワードリミット

シェーダーバリアントを使用する場合、Unity において 128 のキーワードの制限があることを注意してください。これらのいくつかは内部にて使われて、制限に影響します。複数のキーワードがいくつかの異なるシェーダーで定義されているとき、制限を超えないように注意する必要があり、キーワードは特定の Unity プロジェクト全体でグローバルに有効になります。

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

複数のシェーダー変異体をコンパイルするのに、いくつかの「ショートカット」の表記があります。それらは異なるライト、シャドーやライトマップタイプ等ほとんど Unity で対処します。詳しくは Unity のレンダリングパイプライン を参照してください。

  • multi_compile_fwdbaseは、ForwardBase(Forward Rendering ベース)pass 種類で必要とされるすべての変異体をコンパイルします。変異体は、異なるライトマップタイプやシャドウをオン/オフに切り替える主要な異なるライトで対処します。
  • multi_compile_fwdadd は、ForwardAdd (forward rendering additive) の pass タイプをコンパイルします。これは、次の種類(Directional、Point light、Spot)のライトを処理するためのバリアントとクッキーテクスチャによるバリアントをコンパイルします。
  • 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 などがそうです。互換性のレベルが異なる各々のハードウェアに向けて、それぞれに最適化したバリアントを提供するために、シェーダーハードウェアバリアントを使う事ができます。

シェーダーハードウェアバリアントの生成を可能にするためには、#pragma hardware_tier_variants renderer を加え、レンダラーshader program pragmas を利用可能なレンダリングプラットフォームの 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 シェーダープログラム