Version: 2021.1
シェーダーのコンパイル
シェーダーのロード

非同期シェーダーコンパイル

非同期シェーダーコンパイルはエディターのみの機能で、多くのシェーダーバリアントを持つ複雑なシェーダーオブジェクトがある場合、ワークフローを改善することができます。

このページには以下の情報が含まれています。

概要

Shader objects can contain of hundreds or thousands of shader variants. If the Editor compiled all variants when loading a Shader object, the import process would be very slow. Instead, the Editor compiles shader variants on-demand, the first time it encounters them.

これらのシェーダーバリアントをコンパイルすると、グラフィックス API やシェーダーオブジェクトの複雑さに応じて、エディターがミリ秒から数秒にわたってストール (待機) することがあります。このようなストールを避けるために、非同期シェーダーコンパイルを使用してシェーダーバリアントをバックグラウンドでコンパイルし、その間プレースホルダーシェーダーオブジェクトを使用することができます。

非同期シェーダーコンパイルのしくみ

非同期のシェーダーコンパイルは以下のように行われます。

  1. エディターがコンパイルされていないシェーダーバリアントに初めて遭遇すると、そのシェーダーバリアントをジョブスレッド上のコンパイルキューに追加します。エディターの右下にあるプログレスバーはコンパイルキューの状態を示しています。
  2. シェーダーバリアントのロード中、エディターはプレースホルダーシェーダーでジオメトリを描画します。これは無地のシアン色として表示されます。
  3. エディターがシェーダーバリアントのコンパイルを終了すると、シェーダーバリアントを使ってジオメトリを描画します。
Unity は、コンパイルが終了するまで、シアンのダミーシェーダーでコンパイルしているシェーダーバリアントをレンダリングします。右下のプログレスバーは、コンパイルキューの進行状況を示します。
Unity は、コンパイルが終了するまで、シアンのダミーシェーダーでコンパイルしているシェーダーバリアントをレンダリングします。右下のプログレスバーは、コンパイルキューの進行状況を示します。

例外

以下の例外があります。

  • DrawProceduralCommandBuffer.DrawProcedural を使用してジオメトリを描画する場合、エディターはダミーのシェーダーを使用しません。代わりに、エディターはシェーダーバリアントをコンパイルし終わるまで、このジオメトリの描画をスキップします。
  • Unity エディターは、Blit 操作による非同期シェーダーコンパイルを使用しません。これは、最も一般的な使用例で正しい出力を保証するためです。

プロジェクトの非同期シェーダーコンパイルを有効/無効にする

シェーダーの非同期コンパイルは、デフォルトで有効になっています。

シェーダーの非同期コンパイルを有効または無効にするには、以下を行います。

  1. Edit > Project Settings > Editor へ移動します。
  2. エディター設定の下の方の Shader Compilation で、Asynchronous Shader Compilation のチェックを入れます/外します。
Asynchronous Shader Compilation のチェックボックスは、Project Settings > Editor > Shader Compilation 以下にあります。
Asynchronous Shader Compilation のチェックボックスは、Project Settings > Editor > Shader Compilation 以下にあります。

ノート: この方法で非同期シェーダーコンパイレーションを有効/無効にすると、デフォルトでは シーンとゲームビューにのみ影響します。エディターの他の部分で使用したい場合は、カスタムエディターツールと非同期シェーダーコンパイル を参照してください。

特定のレンダリング呼び出しのための非同期シェーダーコンパイルを有効/無効にする

C# スクリプトで特定のレンダリングコマンドの非同期シェーダーコンパイルを有効または無効にすることができます。

以下の説明では、即時のスコープと、CommandBuffer のスコープで、機能を有効または無効にする方法を示しています。

即時スコープ

即時スコープでは、ShaderUtil.allowAsyncCompilation を使用します。

手順は以下のとおりです。

  1. ShaderUtil.allowAsyncCompilation の現在の状態を変数に格納します。
  2. レンダリングコマンドを呼び出す前に、ShaderUtil.allowAsyncCompilationfalse に設定します。
  3. レンダリングコマンドを呼び出します。
  4. レンダリングコマンドを呼び出した後、ShaderUtil.allowAsyncCompilation を以前の状態に戻します。

以下は擬似コードの例です。

// 現在の状況を保存
bool oldState = ShaderUtil.allowAsyncCompilation;

// 非同期コンパイルを無効にする
ShaderUtil.allowAsyncCompilation = false;

// プレースホルダーシェーダーを使用しないレンダリングコードを入力
Graphics.DrawMesh(...);

// 古い状態を復元
ShaderUtil.allowAsyncCompilation = oldState;

CommandBuffer スコープ

CommandBuffer スコープでは、ShaderUtil.SetAsyncCompilationShaderUtil.RestoreAsyncCompilation を使用できます。

  1. レンダリングコマンドを呼び出す直前に、ShaderUtil.SetAsyncCompilation を呼び出して false に設定します。CommandBuffer の後続のコマンドでは非同期コンパイルはできません。
  2. レンダリングコマンドを CommandBuffer に加えます。
  3. レンダリングコマンドの後、Shader.Util.RestoreAsyncCompilation を呼び出して、非同期シェーダーコンパイルの状態を復元します。

以下はその例です。

// CommandBuffer を作成
CommandBuffer cmd = new CommandBuffer();

// 後続のコマンドの非同期コンパイルを無効にします
ShaderUtil.SetAsyncCompilation(cmd, false);

/// プレースホルダーシェーダーを使用しないレンダリングコマンドを入力
cmd.DrawMesh(...);

// 古い状態を復元
ShaderUtil.RestoreAsyncCompilation(cmd);

特定のシェーダーオブジェクトの非同期コンパイルを無効にする

強制的に、特定のシェーダーオブジェクトの非同期シェーダコンパイルを無効にするようにし、常に同期的にコンパイルすることができます。これは、レンダリングの開始時に常に存在するデータ生成シェーダーオブジェクトに適したオプションで、比較的短時間でコンパイルできます。これは、高度なレンダリング を行っている場合に、必要となる可能性が高いでしょう。

シェーダーオブジェクトの同期コンパイルを強制するには、#pragma editor_sync_compilation ディレクティブ をシェーダーのソースコードに加えます。

ノート: レンダリング中に新しいシェーダーバリアントに遭遇する複雑なシェーダーオブジェクトに対して、強制的に同期コンパイルを行うべきではありません。エディターでのレンダリングが滞る可能性があります。

非同期のシェーダーコンパイルの検出

C# の API を使って、非同期のシェーダコンパイルの状態を監視し、その状態が変化したときに操作を行うことができます。

これは 高度なレンダリング で最も有効な方法です。プレースホルダーのシェーダーが生成されたデータを汚染する場合は、コンパイルが完了するまで待って、汚染されたデータを破棄し、正しいシェーダーバリアントで新しい一揃いを再生成できます。

調べたいマテリアルがすでにわかっている場合は、ShaderUtil.IsPassCompiled を使って、シェーダーバリアントのコンパイル状況を確認することができます。ステータスが Uncompiled から Compiled に変わると、コンパイルが完了です。

どのマテリアルを調べたいのかわからない場合や、複数のマテリアルを調べたい場合は、 ShaderUtil.anythingCompiling を使って、Unity がシェーダーバリアントを非同期にコンパイルしているかどうかを検出することができます。これが true から false に変わると、現在のすべてのコンパイルは完了です。

エディターでの高度なレンダリングと非同期のシェーダーコンパイル

高度なレンダリングソリューションでは、データを一度生成し、後のフレームで再利用することが重要です。エディターがこのプロセスでプレースホルダーシェーダーを使用すると、生成されたデータを汚染する可能性があります。これが発生すると、シェーダーバリアントのコンパイルが終わった後でも、シーンにシアン色やその他のレンダリングアーティファクトが表示されます。

これを回避するには、以下を行います。

カスタムエディターツールと非同期シェーダーコンパイル

デフォルトでは、 非同期シェーダーコンパイルはゲームビューとシーンビューで動作します。カスタム製のエディターツールで使用したい場合は、カスタムツールの C# を使って有効にできます。

そのために、特定のレンダリングコールに対して非同期シェーダーコンパイルを有効 にします。

コンパイル時のレンダリングのカスタマイズ

カスタムツールを使って、マテリアルごとのプレースホルダーシェーダー以外のものを描画することができます。このようにして、シアンになる可能性のあるシェーダーバリアントでレンダリングすることを避け、代わりにシェーダーバリアントのコンパイル中に何か他のものを描画することができます。

特定のシェーダーバリアントがコンパイルされたかどうかを確認するには、非同期シェーダーコンパイルの検出 を参照してください。

手動でコンパイルを開始するには、ShaderUtil.CompilePass を使います。このようにして、シアンのプレースホルダーでのレンダリングを避け、代わりにシェーダバリアントのコンパイル中に他のものを描画することができます。

シェーダーのコンパイル
シェーダーのロード