UnityのScriptable Render Pipeline (URP/HDRP) には、CPU側の描画命令のオーバーヘッドを劇的に削減する「SRP Batcher」という強力なバッチング機構が備わっています。しかし、Shader Graphを用いて草木が風に揺れる表現や波の動きなどの「頂点アニメーション(Vertex Positionの変形)」を実装した途端、それまで正常に機能していた SRP Batcher が無効化され、ドローコール(Draw Calls)が数百〜数千へと爆発的に増加し、ゲーム全体のパフォーマンスが激しく低下する問題に陥ることがあります。

本記事では、Shader Graphの頂点変形処理がなぜ SRP Batcher を阻害するのか、そのメカニズムを解説し、ドローコール爆発を回避して高速描画を維持するための具体的な解決アプローチを紹介します。

初心者向け:この問題を現実で例えると?

SRP Batcherのバッチ処理と、頂点アニメーションによる破綻の関係を「テーマパークのアトラクション乗車」に例えてみましょう。

アトラクションの乗り口には、案内係(SRP Batcher)が立っています。同じデザインの服を着た大量のツアー客(同じマテリアルを持つオブジェクト)がやってきた時、案内係は「皆さん同じグループですね。全員一緒にこの大型バス(1回のドローコール)に乗ってください!」と、一括で素早く乗車手続きを行います。これがバッチングによる超高速化です。

しかし、Shader Graphで無造作に頂点変形を仕込むと、ツアー客たちが「風に揺れるため、各自バラバラなタイミングで奇妙なダンスを踊りながら歩く」ようになります。服のデザイン(マテリアル)は同じでも、一人ひとりが全く違うタイミングや異なる動きでダンスをする(個別の頂点変形パラメータを持つ)ため、案内係は「危険ですので、全員まとめて案内することはできません。お一人ずつ個別のタクシー(個別のドローコール)で出発してください」と指示せざるを得なくなります。結果として、ツアーバス1台で済んでいた輸送が、大量のタクシーの列(ドローコール爆発)に変わり、アトラクションは大渋滞してしまいます。これを解消するために、全員で同じダンスを踊るための合図(GPUインスタンシングの有効化)や、添乗員が管理しやすい並び方を再設計してあげる必要があります。

不具合の症状と具体的な現象

このバグが発生した際、以下のような症状が見られます。

  • シーンに風で揺れる草木のアセットを大量に配置した際、プロファイラー(Profiler)や統計パネル(Stats)の Batches(または Draw Calls)がオブジェクト数に比例して極端に増大する。
  • Frame Debuggerで確認すると、描画パスで SRP Batcher [Disabled] もしくは Not Compatible というエラー理由が表示され、バッチが細切れに断片化している。
  • 頂点変形ノード(Positionへの接続)を取り外すと、ドローコールが劇的に減少しバッチングが再開される。

想定される原因:なぜSRP Batcherが効かなくなるのか?

SRP Batcherが機能するための大原則は、「同じシェーダーコードを共有し、かつシェーダー内のグローバルなプロパティ定数バッファ(UnityPerMaterial CBUFFER)のサイズや構造が完全に一致していること」です。

Shader Graphで頂点アニメーション(Vertex Positionの接続)を行う際、マテリアルごとに固有の変形用パラメータ(揺れの速度、オブジェクト個別の位置に依存するランダムシード値など)を定義することがあります。これらのプロパティが UnityPerMaterial 定数バッファの外で定義されたり、オブジェクト固有のローカル座標変換の計算方法がSRP Batcherの互換性から逸脱していると、Unityは「このオブジェクトはマテリアルプロパティが一定ではない」と判断し、SRP Batcherの高速ルートから除外してしまいます。その結果、マテリアルが同一であっても毎回CPUからGPUへ再バインドが発生し、ドローコールが激増するのです。また、GPUインスタンシングとの併用設定が噛み合っていない場合も同様です。

具体的な解決方法とアプローチ

このドローコール爆発を回避するには、以下の2つのアプローチを検討します。

アプローチ A:GPU Instancing (GPUインスタンシング) の明示的併用

同一の草木や岩などのアセットを大量に並べる場合、SRP Batcherではなく GPU Instancing を優先して効かせるのが最も効率的です。 Shader Graphのマテリアル設定で、最下部にある Enable GPU Instancing チェックボックスを明示的にONにします。

[Material Inspector Settings]
☑ Enable GPU Instancing  <-- これを有効化する
(これにより、同一メッシュ&同一マテリアルの大量描画が1つのインスタンスコールに集約されます)

さらに、Shader Graphの設定(Graph Settings)で Support GPU Instancing が有効になっていることを確認します。これにより、頂点アニメーションによる変形が行われていても、GPU側で一括描画(インスタンス化)が行われるようになり、ドローコールが劇的に減少します。

アプローチ B:SRP Batcher互換性を保つシェーダー設計

SRP Batcherを効かせたい場合は、Shader Graphの頂点入力に入力するすべてのカスタムプロパティが、UnityPerMaterial 定数バッファに含まれるように設計しなければなりません。具体的には、プロパティノードのインスペクター設定で Override Property Declaration をデフォルトの Global または Hybrid Per-Instance にし、バッファを破壊するような特殊な設定を避ける必要があります。

実務で役立つ確認チェックリスト

ビルド前のドローコール爆発対策用のチェックリストです。

確認項目 確認・対処手順
Frame Debuggerの理由 Frame Debuggerで描画項目を選択し、バッチが非対応(Not Compatible)になっている原因文字列を解読する。
GPU Instancingの有効化 大量に配置するPrefabの該当マテリアルで Enable GPU Instancing がチェックされているか。
定数バッファの整合 Shader Graphで生成されたC#コードやHLSL内で、プロパティが CBUFFER_START(UnityPerMaterial) 内に綺麗に収まっているか。

まとめ

Shader Graphにおける頂点アニメーションは豊かな演出を可能にしますが、描画パイプラインの仕組みを意識しないとドローコールの爆発を招きます。量産する草木やエフェクトでは GPU Instancing を積極的に併用し、SRP Batcherの互換ルールを守るようマテリアルとグラフ設定を整えることで、美しさと滑らかなフレームレートを高いレベルで両立させましょう。