Unity は、シェーダーのソースファイルを個々のシェーダープログラムにコンパイルします。コンパイルされた各シェーダープログラムは、1 つまたは複数の バリアント を持っています。バリアントとはシェーダープログラムのバージョンのことで、シェーダーキーワード の異なる組み合わせで動作します。ランタイムに、Unity がジオメトリをレンダリングするとき、現在の要件に合うバリアントを使用します。Unity がどのようにシェーダーバリアントをロードして使用するかについては、シェーダーのロード を参照してください。
シェーダープログラムには、その時点のマテリアルに必要なコードだけが含まれているため、シェーダーバリアントはパフォーマンスを向上させるのに役立ちます。一般的にこの方法で最適化されるものは、テクスチャの読み込み、頂点の入力、インターポレーター、ループのような複雑なコードなどです。また、シェーダープログラム自体も小さくなります。
シェーダーバリアントは、同じシェーダーソースファイルを違う方法で使用できるため、ワークフローの改善にもつながります。例えば、様々なマテリアルのための設定、異なるハードウェアのための機能定義、ランタイムのシェーダーの動作の動的変更などが可能です。
しかし、潜在的なデメリットもあります。非常に多くのバリアンとを簡単に作れるため、以下が起こる可能性があります。
In larger projects, these issues can lead to significant problems with performance and workflow. It is therefore very important to understand how shader variants work, and how to exclude (“strip”) unneeded variants from compilation. For more information on shader stripping, see Shader variant stripping.
非常に多くのバリアントを持つシェーダーは、“メガシェーダー” または “ウーバーシェーダー” と呼ばれます。Unity のスタンダードシェーダーは、その一例です。
ビルド時に、Unity は現在のビルドターゲットの各グラフィックス API に対して 1 セットのシェーダーバリアントをコンパイルします。各グラフィックス API とビルドターゲットの組み合わせに対するバリアントの数は、シェーダーのソースファイルとシェーダーキーワードの使用に依存します。
Unity は現在のビルドターゲットの各グラフィックス API に対して 1 セットのシェーダーバリアントをコンパイルします。シェーダーは、各ビルドターゲットとグラフィックス API の組み合わせごとに異なります。例えば、Unity は iOS の Metal と macOS の Metal に対して、異なるシェーダーをコンパイルします。
シェーダープログラムやキーワードによっては、指定のグラフィックス API やビルドターゲットのみを対象とするものもあります。そのため、グラフィックス API とビルドターゲットの組み合わせごとのバリアントの数は異なります。ただし、これらのバリアントをコンパイルする手順は同じです。
現在のビルドターゲットのグラフィックス API のリストを表示および編集するには、Player 設定 ウィンドウ、または PlayerSettings API を使用します。
Unity は、現在のビルドターゲットとグラフィックス API の組み合わせに対して、コンパイルするシェーダープログラム数を決定する必要があります。
ビルドに含まれるシェーダーのソースファイルごとに、固有のシェーダープログラムをいくつ定義するかが決定されます。
ノート: シェーダーのソースファイルは、ビルドのシーンで参照されている場合、Resources フォルダーの何かによって参照されている場合、Graphics Settings ウィンドウの Always-included Shaders セクションに含まれている場合に、そのビルドに含まれます。
Unity は、現在のビルドターゲットとグラフィックス API に対して、コンパイルするシェーダープログラム数を決定し、次に、各シェーダープログラムに対してコンパイルしなければならないシェーダーバリアントの数を決定します。
各シェーダープログラムに対して、Unity はそのプログラムに影響を与えるシェーダーキーワードの組み合わせを決定します。これは以下によって構成されています。
Unity が 1 つのシェーダープログラムに対してコンパイルするシェーダーバリアントの数は、キーワードの積です。つまり、Unity は各セットから 1 つの要素を含むすべての組み合わせに対して 1 つのバリアントをコンパイルします。
例えば、このセットには 3 つのキーワードが含まれています。
このセットには 4 つのキーワードが含まれています。
これらのキーワードの影響を受けるシェーダープログラムは、以下の 12 種類のヴァリアントになります。
Unity がコンパイルするバリアントの数は、キーワードのセットを増やせば増や すほど急速に増えていきます。例えば、かなり典型的なユースケースを考えてみましょう。シェーダーが、それぞれ 2 つのキーワード (<feature name>_ON
と <feature name>_ OFF
) を持つ多くのキーワードセットを持っている場合です 。シェーダーがそのキーワードセットを 2 個持っている場合、これは 4 つのバリアントになります。シェーダーがそのキーワードセットを 10 個持っている場合は、1024 つのバリアントになります。
コンパイル後、Unity は同一パス内の同一バリアントを自動的に識別し、これらの同一バリアントが同じバイトコードを指すようにします。これを 重複排除 と呼びます。
Deduplication prevents identical variants in the same Pass from increasing file size; however, identical variants still result in wasted work during compilation, and increased memory usage and shader loading times at runtime. With this in mind, it is always best to strip unneeded variants.