2017年2月17日金曜日

UnityのUIが重いならCanvasを分割するといいかも

初めましてこんにちは。UnityでUIを作っています。UIの数が増えるにしたがってパフォーマンスが出なくなってきたので、軽量化の方法を調べてみました。

UIをアニメーションさせるのが良くない

とにかくアニメーション(移動、回転、拡大縮小)をさせるのが良くないようです。UIをアニメーションさせるとその Canvas 内のUIを全て再構築するので重くなるそうです。アニメーションさせる場合は、キャンバスを分けることで軽くなる場合があるようなので、いくつかのパターンを実験してみました。

実験してみた

以下の結果は、UIを毎フレームランダムで移動させた場合の Profile の Canvas.RenderOverlays の数値です。Unity 5.5 でPC上で実行しています。

実験1 ) 1個の Canvas 内に、Image 500個をランダムに移動

結果 5.5ms(msは1/1000秒です)

試しに Image のサイズを倍にしてみたら 18ms で、半分にすると 1ms でした。サイズもパフォーマンスに与える影響が大きいみたいですね。また、全く移動させない場合は何個表示させてもほぼ 0ms でした。やはりアニメーションが重いようです。次はキャンバスを分けてみましょう。

実験2 ) 2個の Canvas それぞれに、Image 250個(合計500個)

結果 1.5ms + (Canvas.BuildBatch 0.08ms)

かなり軽くなりました。Canvasを分けるのは有効ですね。もっと分けてみましょう。

実験3 ) 50個の Canvas それぞれに、Image 10個(合計500個)

結果 0.2ms + (Canvas.BuildBatch 0.2ms)

さらに軽くなりました。Canvas.BuildBatch がわずかに増えていますが無視できる範囲です。分けるのが楽しくなってきましたね。さあ、さらにキャンバスを分けましょう。

実験4 ) 250個の Canvas それぞれに、Image 2個(合計500個)

結果 1.2ms + (Canvas.BuildBatch 0.7ms)

だめですね。Canvas.BuildBatch も増えていますが Canvas.RenderOverlays が増えているのがショックですね。環境によって変わってくるでしょうが、分け過ぎは良くないみたいです。Imageはここまでにして、次はテキストを試してみましょう。

実験5 ) 1個の Canvas 内に、Text 500個

結果 0.02ms

テキストは移動させても問題ないようです。分けるまでもないですね。次は親子関係で試してみましょう。

実験6 1個の Canvas 内に、子に Text を持つ Image 500個

結果 55ms

致命的に重いですね。なんか間違えたかなってくらいです。でも大丈夫。さあ、Canvasを分けましょう。

実験7 ) 50個の Canvas それぞれに、子に Text を持つ Image 10個(合計500個)

結果 0.4ms + (Canvas.BuildBatch 0.2ms)

すごいですね。55msから0.4msになりました。親子関係があっても有効でしたね。次はカラーのアニメーション(フェードアウト等)を試してみましょう。Profiler 的には Canvas.SendWillRenderCanvases に影響するみたいですので、結果はその数値です。

実験8 ) 1個の Canvas 内に、Image 500個の Color の alpha を毎フレーム Lerp で書き換える。

結果 10.5ms

UIを500個同時にフェードアウトする機会に恵まれるかどうかは別として、軽い処理ではないことが分かります。でも大丈夫。Canvasを分ければね。

実験9 ) 50個の Canvas  それぞれに、Image 10個づつ入れてLerp(合計500個)

結果 10.5ms

全くダメでした。Canvas分割はColorのLerpでの処理を軽くすることは出来ないようです。

まとめ

UIをアニメーションさせる場合はキャンバスを分割するほど早くなるが、分割し過ぎには注意すること。

以上です。