オブジェクトの描画処理は高負荷である
オブジェクトをスクリーンに描画する際は、グラフィックス API (OpenGL や Direct3D 等) に対してドローコールが行なっている。
グラフィックスAPI内では多数の処理を行うためCPUを多く消費する。
Unityでは負荷を押さえるために2つのテクニックがある。
- 動的バッチ処理: かなり小さいメッシュ用に、その頂点を CPU 上に変換して多数の類似したものを群にし、ひとまとめにして描画します。
- 静的バッチ処理: 静的 (つまり、動かない) ゲームオブジェクトを大きなメッシュと結合して、それを高速でレンダリングします。
バッチ処理を有効にする大前提
出来るだけ同じマテリアルを共有するようにする
まとめてバッチ処理できるのは、同じマテリアルを共有しているゲームオブジェクトのみ。
例えばテクスチャが違うだけのオブジェクトを、別のマテリアルとして作成してしまうとバッチ処理は走らない。
#動的なバッチ処理を有効に使うための勘所
動的なバッチ処理はCPUを多く消費する。
動的バッチ処理は、オブジェクトを描画する際に
個別に描画するコスト > 動的バッチ処理のコスト + バッチ化されたドローコールの処理コスト
際に有効になる。
すなわち動的バッチ処理が有効なのは、グラフィックス APIの処理コストが高い場合である。
Apple の Metal のような最新の API など、処理負荷が低いグラフィックス APIを使用する場合は利点がないことがある。
動的バッチ処理を有効にするための工夫
頂点属性 900 以下で、頂点数が 300 以下にする
頂点数を少なくする。
動的なゲームオブジェクトのバッチ処理では 頂点ごとにある程度オーバーヘッドが発生します。そのため、頂点属性 900 以下で、頂点数が 300 以下のメッシュにしかバッチ処理は適用されません。
Transform にミラーリングを含む場合は、オブジェクトはバッチ処理は適用されない
Transform:オブジェクトの変換操作。
https://docs.unity3d.com/ScriptReference/Transform.html
x軸のscaleを-1にするとミラーリング(鏡写し)になる。
https://answers.unity.com/questions/326905/how-to-mirror-an-object-reverse-its-sides.html
静的なバッチ処理
静的バッチ処理はCPU上で頂点の変換を行わないため動的バッチ処理よりもCPUは低負荷だが、メモリを多く消費する。
静的なバッチ処理がメモリを多く消費するのは、合成したジオメトリを保存するために余分なメモリを消費するからである。
静的バッチを利用するには、そのオブジェクトが静的で、ゲーム内で移動、回転、スケールを行わないということを明示的に設定する必要がある。
そのためにインスペクターの Static チェックボックスをオンにする必要がある。
静的なバッチ処理を使わない方が良い場合
密集した森林において木を静的なバッチ処理をする場合などは、メモリ使用量が膨大になり、許容範囲を超える場合がある。
その場合はレンダリングのパフォーマンス劣化を許容して、静的なバッチ処理を外す方が良いこともある。
描画順序の入れ替えによる最適化
オブジェクトごとのRender Queueを調整する
Render Queueはデフォルトでは全て2000で設定されている。
同じマテリアルであればダイナミックバッチングの対象になるが、バッチ化されるのは描画順が連続している場合である。
A,Bのマテリアルがあり、A,Bを元にしたオブジェクトA1,A2,B1,B2がある場合。
例1:連続していないのでバッチ化されない
A1→B1→A2→B2
例1:連続しているのでバッチ化される
A1→A2→B1→B2
この順序で描画させるためには
- AのRender Queueを2001
- BのRender Queueを2002
として、Rebder Queueの値をマテリアルごとに一意にしてやればいい。
参考
ドローコールのバッチ処理