【Unity最適化】Static BatchingでDraw Callsを減らせ!FPSあげよう!٩( ''ω'' )و

インスペクタの「Static」にチェックいれると…? (‘ω‘ )?

そのゲームオブジェクトは「Static Batching」の対象になります。
「Static Batching」にするとDraw Callsを減らすことができ、CPUへの負荷や間接的にはGPUへの負荷が減らせます。
今日はこのあたりのことをまとめるよー。



【この記事を書いたときの環境】
・ Unity 2022.3.37f1 Personal (Windows64bit)

そもそもDraw Callsってなんだっけ

CPUがGPUにだす「メッシュの描画」命令の回数のことである。(SetPass Callsのことじゃないよ)
なので、この回数が減ることはCPU+GPUの負荷を減らすことができる。
ただ問題になりやすいのはCPU側のことが多いのでCPUへの効果が主になる。

CPUへの負荷が高いと、FPS低下や最悪クラッシュがおきることもあるので負担がかからないようにしておきたいわけだ。

モバイル向けのゲームの場合、Draw Calls 100以下を目安にするといい位。

Draw Callsの回数は、ProfilerのRendering項目で確認することができるよ。

Static Batching ?

「Static Batching」の話にもどります。そもそもBatchingってなに?ってところから。

Batching(バッチング)?

Batching(バッチング)というのは、複数のオブジェクトのメッシュを1つのメッシュにまとめて、Draw Callsを減らす技術。
Batchingには、Static BatchingとDynamic Batchingの2つの手法がある。※詳細は後述
もちろんなんでもまとめられるわけではなく、
同じマテリアルであること。だったり、頂点数の制限があり、2つの手法で条件も異なる(Staticのほうが頂点数は多い)。

概要はこんなところで、具体例を出して確認してみよう。
同じマテリアルを持つ「Cube」10個+「Sphere」1個+カメラ*1だけがあるシーンを用意する。
 

まずバッチングをしない場合(PlayerSettingsでStatic/Dynamic BatchingのOn/Offを切り替えられるよ)、
結果は Draw Calls=11になる。11個のオブジェクトを描画するからだ。

Dynamic Batching と Static Batching

Batching には、Dynamic Batching と Static Batching の2つあると上述した。

Dynamic Batchingを試してみよう

「Dynamic Batching」はその名の通り、動的=毎フレームバッチングしてから描画するということだ。

先ほどのシーンでDynamic Batchingの挙動を確認しよう。
PlayerSettingを変更しておらず、ゲームオブジェクトの「Static」をデフォルトのOFFのままにしていればDynamic Batchingで処理されるので、
通常このあたりを気にしてない人はDynamic Batchingでなっているはずだ。

→Dynamic Batchingする=毎フレームバッチングすることによる負担のほうがDraw Callsよりもオーバーヘッドになる場合もあるため、
デフォルトはOFFでした。Dynamic Batchingが有益かどうかはよく調査してから導入する必要がある。

結果は Draw Calls=2になる。11個のオブジェクトを描画しているが、
その内「Cube」10個は「Dynamic Batching」により1個にまとめられて、
「Cube」10個→1回と「Sphere」1個→1回の合計2回の描画命令が行われていることがわかる。

これはFrameDebbugerでも2回描画が走ってることが見てわかるよ。

Static Batchingを試してみよう

次に本題の「Static Batching」を見てみる。PlayerSettingsの「Static Batching」をONにしておくこと。

「Static Batching」は、ビルド時やシーン起動時など事前にメッシュをまとめており、
Dynamic Batchingのように実行中毎フレーム行わないため、CPUへの負荷が発生しない。

実際に動きを見てみる。ゲームオブジェクトの「Static」にチェックをいれよう。
Staticの横の▼をおして「Static Batching」にチェックが入っていることも確認しておこう。

結果は Draw Calls=1になる。11個のオブジェクトを描画しているが、
11個すべて「Static Batching」により事前に1個にまとめられて、合計1回の描画命令が行われていることがわかる。


ここまでの結果をみて、「Static Batching」を使うことで
よりDraw Calls=描画数が減っている=CPUへの負担が減ることがわかった。
また、同じオブジェクトでもDynamic Batchingとはまとめられる数が違うことから、
バッチングが効く=まとめられる条件が「Static Batching」と「Dynamic Batching」で違うこともわかる。

どういうときに使える?

CPU負荷が減るため積極的に使っていきたいが、事前にメッシュをまとめる、という特性から使えるケースは絞られる。
Transformの値(位置、回転、スケール)を変えるものは使えない点に注意だ。
つまり、一切動かないモデル(例:建物や地面とか)にのみ有効だ。

Static Baching対象にしたゲームオブジェクトを動かしたらどうなる?と疑問に思って試してみたが、
事前に作ったメッシュとの整合性がとれなくなったのか、
インスペクタ上でTransformの位置を変更してるのにGame上は動いていない状態になったので注意が必要。(特にエラーとかでないので気づきにくいかも)

メモリ占有量は増える

もう1つ注意点がある。
事前にメッシュをまとめる、という特性から、
まとめられたメッシュは常にメモリに展開されることになる。

これはMemory Profilerだと「Mesh」項目でメモリ占有量が増えていることがわかる。

▼Static Batchingを使った場合

▼Dynamic Batchingを使った場合

ただこれは、texture等よりもメッシュのデータ自体は軽量なことが多いためそこまで問題になることは少ないようだ。

まとめ

モバイル向けゲームだとDraw Calls(CPU→GPUへの描画命令回数) 100以下が目安
「Batching」は描画するメッシュをまとめることによってDraw Callsを減らせる技術まとめるには同じマテリアルである必要がある。
・デフォルトでは「Dynamic Batching」が使われているが、「Static Batching」を使うことでDraw Callsがさらに減らせる。
「Static Batching」はTransformの値(Positon, Rotate, Scaleすべて)が変わらないオブジェクトに対してのみ使うこと。
・「Static Batching」はまとめたメッシュの分、メモリ占有量は若干増えるが問題になるケースは少ない見込み。

*1:ClearFlagsを「Solid Color」、MSAAもOFFにしてるとわかりやすいよ