uGUIのリビルドの仕組みと、それによるパフォーマンス低下の対策についてまとめました。
Unity2018.3.9
はじめに
uGUIのパフォーマンスを低下させる大きな原因として、GraphicのリビルドとLayoutのリビルドがあります。
この記事ではこれらについて紹介して対策を考えていきます。
uGUIのパフォーマンスの低下の主な要因としては、リビルド以外にも
フィルレートやセットパスコール数などがありますが、これはまた別記事にまとめようと思います。
Graphicのリビルド
さて、uGUIは描画をするときに同じアトラス&同じマテリアルのものをバッチングして描画します。
つまり、頂点情報を一つのメッシュにまとめたようなものを作ってそれをGPUに送ります。
これによりドローコールが削減され、効率的な描画を行うことができます。
また、こうして一度まとめられた頂点情報は次のフレームの描画にも使いまわされます。
ただし、頂点情報が一つでも変わってしまうとまた頂点情報をまとめなおさなければいけません。
このように、Canvas配下のGraphicの位置やマテリアル、表示/非表示がランタイムで変化することにより、
頂点情報をまとめなおす処理が走ることをリビルドといいます。
この処理は重いので、よくパフォーマンス低下の原因となります。
GraphicのリビルドはProfilerではこのように確認できます。
メインスレッドとは別のスレッドで処理がされていることがわかります。
Layoutのリビルド
Graphicのリビルドとは別にLayoutのリビルドがあります。
これは、VerticalLayoutGroupやGridLayoutGroupなどでAuto Layoutを行うときに配下のTransformが変化することで発生します。
試しにGridLayoutGroupであるPanelの下に1000個のChildを配置してみます。
この状態で、ChildのScaleなどを変更するとリビルドが走ります。
このリビルド処理はGridLayoutGroupの配下の1000個のChildすべてに対して走るため、大きな処理負荷が発生します。
Profilerで見るとこんな感じです。
Graphicのリビルドとは違い、メインスレッドで処理されていることがわかります。
またChildはImage(Graphic)なのでGraphicのリビルドも同時に走っていることが見て取れます。
Graphicのリビルドを防ぐ
それではリビルドによるパフォーマンスの低下を小さくするためにはどうしたらいいでしょうか。
Graphicに関してはまず第一リビルドを発生させないことが重要です。
つまり、同じCanvasにあるGraphicをできるだけ移動させない、マテリアルを変えないようにします。
リビルドが発生する場合、同じCanvasにあるGraphicが多いほどリビルドの処理負荷は増えます。
このため、Canvasを分けたりSubCanvas化したりすることでリビルド時の処理を分散させるとパフォーマンスの低下が抑えられます。
特にアニメーションするようなものは小さいCanvasに切り分けておくことが重要です。
Layoutのリビルドを防ぐ
Layoutのリビルドに関しては、まずはそもそもLayoutを使いすぎないように注意します。
使わなくても実装できるところは使わずに実装すべきです。
またGraphicと同様、移動させないことでそもそもリビルドを発生させないことも重要です。
なお、Layoutが影響する範囲のものでなければ移動させてもLayoutのリビルドは発生しないようです。
下図のうち、Childを動かすとLayoutがリビルドされますが、GrandChildを動かしても発生しませんでした。
またLayoutのリビルドはテクスチャの変更などでも走るらしいので注意が必要です。
まとめ
以上のことから、uGUIのリビルドへの対策としては以下のことが言えそうです。
- そもそもできるだけ動かさない
- 頻繁に動くGraphicは小さいCanvasに切り出す
- Layoutはできるだけ使わない
- Layoutの影響下のUIを頻繁に動かさない