げぇむぷろぐらみんぐ

日々の生活で得た知識、経験を書きます

【Unity】Canvasでパフォーマンスに関わることについて調べてみた

はじめに

今後UI周りに広く関わることになったので、Canvasに関して気になってはいたけど調べていなかったことについて調べてみました。

目次は以下です。

CanvasとSpriteAtlasの関係

はじめに、SpriteAtlasでまとめたSpriteを使うUIを複数Canvasに分ける場合と分けない場合でDrawCallにどんな違いが出るのかを調べました。 SpriteAtlasに関してはこちらを参照してください

描画したUIは以下のようなものです。 表示されているものをすべて一つのSpriteAtlasにまとめました。

f:id:siguma_sig:20180804162857p:plain

  • アトラス化なし、Canvas1つ f:id:siguma_sig:20180804162936p:plain

  • アトラス化あり、Canvas1つ f:id:siguma_sig:20180804162711p:plain

  • アトラス化なし、Canvas3f:id:siguma_sig:20180804163023p:plain

  • アトラス化あり、Canvas3f:id:siguma_sig:20180804163039p:plain

これらのことから、アトラス化により各UIで使われるSpriteが一つのSpriteAtlasになっていたとしても、Canvasが分かれていては別途DrawCallが発生してしまうことがわかります。 SpriteAtlasとして効果を発揮するならば、複数Canvasを用いてUIを構成する場合はCanvasごとにアトラス化するのが良さそうです。

動くUIと動かないUIでCanvasを分ける

先程の例をみるとCanvasを分けることにはデメリットしかないように見えますが、UnityのCanvasの仕様上Canvas内に一つでも動くUIが存在するとCanvas全体にRebuild処理が走り結構な負荷がかかるそうです。 そのため、動くUIと動かないUIに関してはCanvasを分けるべきだと言われています。

今回は、実際に動くUIと動かないUIを分割する場合としない場合でどれくらいの差があるのかを調べてみました。

動くUIとしてx方向にscaleするアニメーションをしたImageを、動かないUIとしてただのImageを用意しました。

  • 動くUI × 1 と 動かないUI ×1000を同じCanvasにしたとき f:id:siguma_sig:20180804180403p:plain

  • 動くUI × 1 と 動かないUI×1000を別のCanvasにしたとき f:id:siguma_sig:20180804180412p:plain

差を見ると分かる通り、動くUIが一つあるだけでUI全体に対して描画の更新がかかっているようです。

また、動くUIとはなんなのか曖昧だったので試してみたところ、ImageのColorを変えたり、enableを変更するだけでも更新がかかるようでした。

大きく分けるならば、常時動いているようなUIとたまに動くUIと全く動かないUIをそれぞれ3つのCanvasに分けてやるのが良さそうです。

まとめ

Canvasは分けすぎても良くないし、分けなくても良くないことがわかりました。 基本的には、常時動くUIとたまに動くUIと動かないUIでCanvasを分けて、それぞれでアトラス化をしてやれば良さそうです。

Profilerをあまり使い慣れていなくて計測が雑なので、もしもっと詳しく計測できる方法や間違っていることがあれば教えてください。

(追記) DeepProfileによる検証し直し

動くUIと動かないUIをCanvasとして分ける場合と分けない場合の違いについての計測で、DeepProfileを用いて計測し直した結果を残しておきます。

  • 動くUI × 1 と 動かないUI ×1000を同じCanvasにしたとき

DeepProfileのCalls f:id:siguma_sig:20180812195419p:plain

DeepProfileのHierarchy f:id:siguma_sig:20180812195435p:plain

  • 動くUI × 1 と 動かないUI×1000を別のCanvasにしたとき

DeepProfileのCalls f:id:siguma_sig:20180812195454p:plain

DeepProfileのHierarchy f:id:siguma_sig:20180812195506p:plain

DeepProfileで計測した結果が上記のようになりました。 動くUIを分けなかった場合、WaitForJobGroupIDで非常に時間がかかっていることがわかります。 実際は1000個も同じCanvasにUIが存在することは殆どないと思いますが、分けると分けないとで処理時間がかなり変わってくることがはっきりとわかったのでやっぱり分けたほうが良さそうです。

参考

unity3d.com