Version: 2020.1
詳細な ShaderLab トピック
Asynchronous Shader compilation

Optimizing shader variants

シェーダーは GPU 上で実行する小さなプログラムであり、それらをロードするには時間がかかることがあります。個々の GPU プログラムは一般的にロードするのに時間がかかりませんが、シェーダーは、多くの場合、内部にバリアントがたくさんあります。

たとえば、スタンダードシェーダー 。完全にコンパイルされると、結局、わずかに異なる何千もの GPU プログラムになります。これによって 2 つの問題の可能性が発生します。

  • これらの多数のシェーダーバリアントは、ゲームのビルド時間とゲームのデータサイズを増加させます。
  • Loading large numbers of shader variants at runtime is slow and takes up memory.

Build time stripping

While building the game, Unity can detect that some of the internal shader variants are not used by the game, and exclude (“strip”) them from build data. Build-time stripping is done for:

  • For shaders that use #pragma shader_feature, Unity automatically checks whether variants are used. If none of the Materials in a build use a variant, that variant it is not included into the build. See internal shader variants documentation. The Standard shader uses this.
  • いずれのシーンでも使用されていないフォグとライトマップモードを処理するシェーダーバリアントは、ゲームデータに含まれません。この動作をオーバーライドしたい場合は、Graphics ウィンドウを参照してください。
  • You can also manually identify variants and tell Unity to exclude them from a build using using the OnProcessShader API.

上記の組み合せは、シェーダーデータサイズをしばしば大幅に減らします。例えば、完全にコンパイルしたスタンダードシェーダーは数百メガバイトを消費することもあります。しかし、典型的なプロジェクトでは、大抵、わずか数メガバイトを消費します (アプリケーションのパッケージングプロセスによってさらに圧縮されることもよくあります)。

デフォルトの Unity シェーダーのロードの動作

Under all default settings, Unity loads the shaderlab Shader object into memory at runtime, but does not create the internal shader variants until they are actually needed.

This means that all shader variants that are included in the build can still potentially be used, but there’s no memory or load time cost paid until they are needed. For example, a shader might always include a variant to handle point lights with shadows, but if you never end up using a point light with shadows in your game, then there’s no point in loading this particular variant.

One downside of this default behavior, however, is a possible hiccup for when a shader variant is needed for the first time - since a new GPU program code has to be loaded into the graphics driver. This is often undesirable during gameplay, so Unity has ShaderVariantCollection assets to help solve that.

シェーダーバリアントコレクション

ShaderVariantCollection is an asset that is basically a list of Shaders, and for each of them, a list of Pass types and shader keyword combinations to load in advance, rather than wait until they are needed.

シェーダーバリアントコレクションのインスペクター
シェーダーバリアントコレクションのインスペクター

実際に使用されたシェーダーとそのバリアントに基づいてアセットの作成を支援するために、エディターは実際に使用されているシェーダーとそのバリアントを追跡することができます。Graphics ウィンドウに、現在追跡しているシェーダーから新しいシェーダーバリアントコレクションを作成するボタンと、現在追跡しているシェーダーリストを削除するボタンがあります。

エディターで使用するシェーダーから ShaderVariantCollection を作成
エディターで使用するシェーダーから ShaderVariantCollection を作成

ShaderVariantCollection アセットをいくつか取得したら、これらのバリアントを (Graphics Settings の Preloaded Shaders の下にある) アプリケーションのロード中に自動的にプリロードされるか、またはスクリプトから個々のシェイダーバリアントコレクションをプリロードするようにように設定することができます。

Preloaded Shaders リストは、頻繁に使用されるシェーダーを対象としています。ここにリストされているシェーダーのバリアントは、アプリケーションの生存期間にわたってメモリに読み込まれます。これによって、多数のバリアントを含む ShaderVariantCollections アセットに著しい量のメモリが使用される場合があります。これを避けるには、ShaderVariantCollection アセットをより細かく作成し、スクリプトから読み込む必要があります。1つの方法としては、各シーンに使用されているシェーダーバリアントを記録し、別々の ShaderVariantCollections アセットに保存し、それらをシーン起動時に読み込むことです。

ShaderVariantCollection スクリプトクラスを参照してください。

参照

詳細な ShaderLab トピック
Asynchronous Shader compilation