3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ドローコールからセットパスへ ― 描画コスト管理の10年間の変遷

3
Posted at

ドローコールからセットパスへ ― 描画コスト管理の10年間の変遷

「ドローコールを減らせ」――Unity開発者なら一度は聞いたことがあるアドバイスだ。検索すれば、Dynamic Batching、Static Batching、アトラス化、メッシュ結合…… 無数の「ドローコール削減テクニック」がヒットする。

しかし、その記事はいつ書かれたものだろうか。

Unity 6(URP / HDRP)の時代、最も重要な描画コスト指標はドローコール数ではなく、セットパスコール数に変わっている。SRP Batcherが標準搭載され、同じシェーダーを使うオブジェクトであれば、マテリアルのパラメータが異なっていても自動的に描画コストが最適化される。にもかかわらず、「ドローコールを減らそう」という古い情報が大量に残っているため、初学者は何を指標にすべきか分からない。

本記事では、描画コスト管理の歴史的変遷を辿り、「今、何を見て、何をすべきか」を明確にする。

本記事は「ゲームエンジンのレンダリング技術」シリーズの第1.5回です。シリーズ全体の構成は記事末尾をご覧ください。


描画の裏側: CPUとGPUの会話

ドローコールとは何か

ゲーム画面の1フレームを描くために、CPUは「このメッシュを、このマテリアルで、この位置に描け」という命令をGPUに送る。この命令1回分がドローコールだ。

ドローコールの仕組み

問題は、ドローコールそのものではなく、その前後に発生する状態変更にある。GPUに新しいメッシュを描かせるたびに、CPUは以下を準備する必要がある。

準備作業 内容 コスト
テクスチャ設定 使用テクスチャをVRAMに配置 高い
シェーダー切り替え GPUプログラムの変更 非常に高い
マテリアルパラメータ 色・光沢度などの値を送信 低い
トランスフォーム 位置・回転・スケール 低い

ここで注目すべきはコストの差だ。シェーダーやテクスチャの切り替えは重いが、マテリアルパラメータやトランスフォームの送信は軽い。この差が、後述するSRP Batcherの設計思想の根拠となる。

状態変更が本当のボトルネック

2000年代後半の計測データでは、状態変更なしなら1フレームで約6,000回のドローコールが可能だった。しかし、テクスチャを毎回変えると処理能力は1/3に落ち、シェーダーまで変えると1,000〜2,000回が上限になった。

状態変更なし:           ~6,000 ドローコール/フレーム
テクスチャ変更あり:      ~2,000 ドローコール/フレーム(3倍遅い)
シェーダー変更あり:      ~1,000 ドローコール/フレーム(6倍遅い)

つまり、ドローコールの「数」が問題なのではなく、ドローコール間の「状態変更の重さ」が問題だった。この事実が見落とされたまま「ドローコール数を減らせ」という簡略化されたアドバイスが広まった。


Unity 5時代: バッチングの全盛期

Dynamic Batching ― ランタイムでメッシュを結合

Unity 5以前の最適化の主役は Dynamic Batching だった。同じマテリアルを使う小さなメッシュを、ランタイムで1つのメッシュに結合して描画する。

結合前: 岩A(ドローコール) + 岩B(ドローコール) + 岩C(ドローコール) = 3ドローコール
結合後: [岩A+B+C](ドローコール) = 1ドローコール

しかし、制約が極めて多い。

制約 条件
頂点属性の合計 900以下(シンプルシェーダーで300頂点、複雑シェーダーで180頂点)
メッシュ数/バッチ 最大300
インデックス数 最大32,000
マテリアル 全オブジェクトが完全に同一のマテリアル参照
スケール 均一 or 非均一で統一(混在不可)
シャドウ リアルタイムシャドウ受け不可

さらに、バッチ結合の処理自体がCPU負荷を生む。バッチあたり数個しかメッシュがない場合、結合のオーバーヘッドが削減効果を上回るという本末転倒な状況も起きた。

Static Batching ― ビルド時にメッシュを結合

Static Batchingは、ビルド時に動かないオブジェクトのメッシュを結合する。Dynamic Batchingの頂点数制限を回避できるが、別の問題がある。

メモリの爆発: 同じ木のメッシュを1,000本配置すると、1,000個分のメッシュデータがメモリに複製される。元メッシュが1MBなら、1GBのメモリを消費する。

オクルージョンカリングとの相性: バッチ内の1オブジェクトでも可視なら、バッチ全体が描画される。壁の向こうの見えないオブジェクトも含めて描画してしまう。

この時代の指標: Statsウィンドウの「Batches」

Unity 5時代、開発者が見ていたのはGame ビューの Stats ウィンドウに表示される「Batches」の数だった。この数を減らすことが最適化の目標とされていた。


転換点: SRP Batcherの登場

セットパスコールという新しい指標

2018年、Unity が Scriptable Render Pipeline(SRP)と共に導入した SRP Batcher は、描画コスト管理のパラダイムを根本から変えた。

セットパスコールの概念

SRP Batcherが変えたのは、「何を削減対象とするか」 だ。

時代 削減対象 手段
Unity 5以前 ドローコール数 メッシュ結合(バッチング)
SRP Batcher以降 セットパスコール数 シェーダーバリアント単位の状態キャッシュ

セットパスコール(SetPass Call) とは、GPUのシェーダープログラムを切り替える操作のことだ。前述の「状態変更のコスト」のうち、最も重い「シェーダー切り替え」に対応する。

SRP Batcherの仕組み: CBufferによるキャッシュ

SRP Batcherの核心は、マテリアルのプロパティをGPU側のConstant Buffer(CBuffer) にキャッシュする仕組みだ。

SRP BatcherのCBufferキャッシュ

従来のパイプライン:

オブジェクトA描画:
  → シェーダー設定 → マテリアルパラメータ送信 → トランスフォーム送信 → 描画

オブジェクトB描画(同シェーダー、別マテリアル):
  → シェーダー設定 → マテリアルパラメータ送信 → トランスフォーム送信 → 描画
  ↑ シェーダーが同じでも毎回再設定していた

SRP Batcher:

オブジェクトA描画:
  → シェーダー設定(1回だけ)
  → CBuffer[A]のマテリアルパラメータ参照 → CBuffer[A]のトランスフォーム参照 → 描画

オブジェクトB描画(同シェーダー、別マテリアル):
  → シェーダーはそのまま(セットパス不要)
  → CBuffer[B]のマテリアルパラメータ参照 → CBuffer[B]のトランスフォーム参照 → 描画

各マテリアルのプロパティはGPUメモリに常駐し、描画時はバッファのポインタを切り替えるだけで済む。シェーダーを再設定する必要がないため、セットパスコールが発生しない

何がセットパスコールを発生させるのか

ここが初学者が最も混乱するポイントだ。整理しよう。

状況 セットパス発生? 理由
同シェーダー、同マテリアル No 何も変わらない
同シェーダー、色が違うマテリアル No パラメータはCBufferで管理。シェーダーは同じ
同シェーダー、テクスチャが違うマテリアル No テクスチャもCBufferのリソース参照で管理
違うシェーダーのマテリアル Yes GPUプログラムの切り替えが必要
同シェーダーだがバリアント違い(キーワード差分) Yes 内部的に別シェーダープログラム
Shader Graphの同グラフでSurface Optionsが異なる Yes Transparent / Opaque で別バリアント

核心: SRP Batcherが気にするのは「シェーダーバリアント」が同じかどうかだけだ。マテリアルのパラメータ(色、テクスチャ、数値)がいくら違っても、同じシェーダーバリアントなら追加コストは発生しない。


今、何を見て、何をすべきか

指標: Frame Debuggerを使う

Stats ウィンドウの「Batches」はもう最重要指標ではない。代わりにFrame Debugger(Window → Analysis → Frame Debugger)を開き、以下を確認する。

確認項目 見るべき場所 目標
セットパスコール数 Frame Debugger左パネルの階層 シェーダー切り替え回数を最小化
SRP Batcherの効果 各ドローコールの「SRP Batcher」表示 「SRP Batch: X draw calls」が大きいほど良い
バッチ破壊の原因 ドローコール間の変更理由 「Different shader」が多い場合は改善余地あり

やるべきこと: 5つの実践ルール

描画コスト最適化の実践チェックリスト

1. SRP対応シェーダーを使う

SRP Batcherの恩恵を受けるには、シェーダーが SRP Batcher互換である必要がある。

  • Shader Graph: 自動的にSRP互換。何もしなくてよい
  • URP Lit / Unlit: SRP互換
  • カスタムHLSL: UnityPerMaterial CBuffer にプロパティを正しく配置する必要がある
// SRP Batcher互換のカスタムシェーダー例
CBUFFER_START(UnityPerMaterial)
    float4 _BaseColor;
    float _Smoothness;
    float4 _BaseMap_ST;
CBUFFER_END

UnityPerMaterial CBuffer の外にプロパティを置くと、SRP Batcherが無効になる。

2. シェーダーバリアントを減らす

同じShader Graphでも、#pragma multi_compile#pragma shader_feature で大量のバリアントが生成される。Shader Graphの Surface Options が異なるマテリアルは別バリアントになる。

悪い例: オブジェクトごとに Opaque / Transparent を混在
良い例: 不透明オブジェクトは全て同じ Lit シェーダー(Opaque)で統一

3. マテリアルの違いは気にしない

SRP Batcher時代において、「マテリアルを共有してメモリを節約する」旧来の最適化は優先度が下がった。色やテクスチャが異なる100個のマテリアルがあっても、同じシェーダーなら描画コストは変わらない。

旧時代: 赤い壁と青い壁 → 同じマテリアルに統合(テクスチャアトラス化)
現代:   赤い壁と青い壁 → 別マテリアルでOK(SRP Batcherが処理)

4. GPU Instancingは「同一メッシュ大量描画」に限定

GPU Instancingは、同一メッシュ + 同一マテリアルを大量に描画する場合にのみ有効だ(草、パーティクル、群衆など)。SRP Batcherと併用はできない(どちらか一方が適用される)。

ケース 推奨
異なるメッシュ、同じシェーダー SRP Batcher
同一メッシュを数千個配置 GPU Instancing
大量の草・木 GPU Instancing + Indirect描画

5. Dynamic / Static Batchingの位置づけ

SRP Batcher有効時、Dynamic BatchingとStatic Batchingは基本的に不要だ。

  • Dynamic Batching: URP設定でデフォルトOFF。ONにするとSRP Batcherと競合し、かえって遅くなる場合がある
  • Static Batching: メモリ消費が大きいため、SRP Batcherで十分な場合は無効にすることを検討する

歴史の対比: 同じシーンで何が変わったか

100個のオブジェクト(10種類のシェーダー × 各10色のマテリアル)を描画する場合:

描画コスト管理の変遷比較

手法 ドローコール セットパスコール 状態変更
バッチングなし(Unity 4) 100 100 毎回フル
Dynamic Batching(Unity 5) ~30 ~30 バッチ単位
SRP Batcher(Unity 6) 100 10 シェーダー単位

SRP Batcherではドローコール数は減らない(100のまま)。しかし、セットパスコールが10(シェーダー数)に激減する。ドローコール間の状態変更コストが消えるため、100回のドローコールが高速に連続実行される。

SRP Batcherの本質は「ドローコールを減らす」のではなく「ドローコールを軽くする」ことだ。


まとめ

観点 要点
歴史 ドローコール削減(Unity 5)→ セットパスコール削減(SRP Batcher)へパラダイムが移行した
本質 描画コストの主因は「シェーダー切り替え」であり、マテリアルのパラメータ差異ではない
指標 Stats の Batches ではなく、Frame Debugger でセットパスコール数を確認する
実践 SRP互換シェーダーを使い、シェーダーバリアントを減らす。マテリアルの統合は優先度低
注意 Dynamic Batching は SRP Batcher と競合する。GPU Instancing は同一メッシュ大量描画に限定

シリーズ案内: ゲームエンジンのレンダリング技術

テーマ
第1回 レンダリングパイプラインの全体像
第1.5回(本記事) ドローコールからセットパスへ
第2回 ライティングとライトマップの技術
第3回 シャドウとアンビエントオクルージョン
第4回 アンチエイリアシング完全ガイド
第5回 ポストプロセスで画をつくる

参考情報

資料 著者/出典 内容
Unity 5 Game Optimization Chris Dickinson Dynamic/Static Batchingの詳細制約
Video Game Optimization Eric Preisz ドローコール計測とステート変更コストの実測
SRP Batcher: Speed up your rendering Unity Technologies SRP Batcherの公式解説
GAMES104 Lecture 07 Wang Xi レンダリングパイプラインの包括的講義

本記事は UniMCP4CC プロジェクトの技術知見を基に執筆しています。Unity × Claude Code でのゲーム開発に興味がある方はぜひご覧ください。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?