げぇむぷろぐらみんぐ

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

【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

エンジニア以外にも使ってほしい!PlantUMLのススメ

はじめに

最近一から設計を考えて実装をする機会が多く、実装前にチームメンバーに自分の考えを共有しなければならないことが多くありました。 その際に、PlantUMLによって自分の考えを図示してから話し合いを行うことで様々な利点があったので共有します。

まだPlantUML歴2週間程度のひよっこなので間違ってるところがあったらぜひ教えてください。

(書いてから思いましたが、UMLをオススメする記事になってしまった気がします)

UML

PlantUMLについて説明をする前に、UMLについての説明をします。

UMLとはWikipediaから引用すると、

統一モデリング言語(とういつモデリングげんご、UML、英: Unified Modeling Language)は、主にオブジェクト指向分析や設計のための、記法の統一がはかられた(Unified)モデリング言語(Modeling Language)である。

だそうです。

簡単に言うと、ソフトウェアに関する設計や処理の流れやデータ構造といったものを図示していくための記法を定めたものです。

UMLは、データ構造などの構造を表す構造図と動作や変化を表す振る舞い図の大きく二種類に分類されます。

構造図としては、クラス図、パッケージ図、オブジェクト図などがあります。 振る舞い図としては、アクティビティ図、ユースケース図、状態遷移図などがあります。

今回は、それぞれの図の具体的な使いみちは他のサイトに譲りますが、UMLがどんなものか見てもらうためにクラス図についてのみ紹介します。

クラス図

その名の通り、ソフトウェアを構成するクラスがどのような関連を持っているかを図示するものです。 あるクラスが他のクラスとどんな関係にあり、どんな変数を保持しているかが図でわかるようになります。

具体的なクラス図は以下です。

f:id:siguma_sig:20180721225035p:plain

この図を見ると、Animalが抽象クラスで、Dog、Cat、Humanはそれを実装したクラスとなり、ZooはAnimalのリストを持ってるクラスだということがわかります。

PlantUML

PlantUMLとは、上記で説明したUMLDSLを記述することですばやく作成できるものです。

先程のクラス図は以下のように記述することで生成されます。

@startuml
abstract class Animal {
    - type
    - color
    + run
}

class Dog {
    + run
    + eat
}
class Cat {
    + run
    + sleep
}

class Human {
    + run
    + talk
}

class Zoo {
    - animalList
}

Animal <|-- Dog
Animal <|-- Cat
Animal <|-- Human
Zoo *-- Animal
@enduml

このように、テキストベースでUMLを記述することができるのがPlantUMLです。(UML以外にも図示できるらしいです)

各図を作図するためにある程度記法を覚える必要がありますが、慣れてしまえばdraw.ioなどで図を書くよりも早く、そしてきれいに図示できると思います。

PlantUML(UML)の利点

PlantUML(UML)を使っていて感じた利点としては以下のようなものがありました。

図を作成することで思考の整理ができる

コードを実際に書く前に設計を図示しておくことで自分の思考が整理され、曖昧だった箇所がはっきりして実装時の手戻りが減ります。

人との考えの共有ができる

言葉で設計について相談するよりも、このようなツールで図示をしてそれをベースに相談したほうが圧倒的に精度が高いと感じました。 言葉の受け取り方は人それぞれな部分もあり、自分が思っていたことと相手の思っていたことが違い手戻りが発生してしまうようなことがあります。 しかし、図示をして相談をすればそういった不明確な要素を排除できます。

実装が楽になる

あらかじめ設計を図示しておくことで、あとはそのとおりに作っていくだけでよくなるので実装時の負担が減ります。 実装中に設計を考えながらやると行き当たりばったりな実装になりがちで、良くないコードになってしまいます。

ドキュメントとして残せる

PlantUMLはテキストベースなのでGit管理もしやすく、ドキュメントとして残す際に便利です。

PlantUMLの欠点

記法を覚えるのが大変

僕も未だに記法をしっかりと覚えられていないので、書くときに少し時間がかかってしまいます。 頑張って覚えましょう。

どの図を使っていいかわからない

UMLについてしっかりと理解しないと、クラス図で書くべきなのかオブジェクト図で書くべきなのかがわからなくなってしまったりします。 頑張って理解しましょう。

まとめ

PlantUMLはエンジニアだけが使うツールではないと思います。 例えば、プランナーさんがエンジニアに仕様を伝える際にも、ユースケース図やシーケンス図が活きてくると思います。

是非みんなでPlantUMLを覚えて、適切な議論ができるようにしていきましょう!

【Unity】ToggleボタンのOnOffの状態によって画像を変える

はじめに

タイトルの通り、ToggleボタンのOnOff状態によって表示するボタンの画像を変える方法です。 ノンコーディングなのでサクッと書きます。

続きを読む

【Unity】ディレクトリごとにアセットのインポート設定を変える

はじめに

アセットをインポートするとき、AssetPostprocessorを用いることでインポート設定を変更したり加工したりできます。 例えば、OnPreprocessTextureだとテクスチャのインポート時にこのメソッドが呼ばれ、処理を行うことができます。 しかし、このままだとインポートした全テクスチャに対して同じ処理が適用されてしまうことになるので、今回はインポートしたディレクトリごとに設定を変える実装をしてみました。 Postprocessor系の勉強で実装したので、実用性があるかはわかりません。

続きを読む

【Unity】ScriptableObjectを作成するエディタ拡張

はじめに

色々なパラメータをアセットデータとして保持することができるScriptableObjectですが、一般的に以下のようなクラスを作成して作ります。

using UnityEngine;
using UnityEditor;

[CreateAssetMenu(menuName = "ScriptableObject/ExampleAsset")]
public class ExampleAsset : ScriptableObject
{
}

このように書くと、以下のようなMenuが追加されExampleAssetの作成が可能となります。

f:id:siguma_sig:20180617165745p:plain

しかし、開発が進むにつれて作成したいScriptableObjectの数が増えてくるとともに、Menuに追加される項目も増えます。 丁寧に階層分けをするようにパスを記述しても良いですが、めんどくさいので今回はScriptableObjectを渡すと任意の場所にアセットを作成してくれるエディタ拡張を書いたので、コードを載せておきます。

続きを読む

ReactNative+TypeScript+Formikでフォーム画面を作る

はじめに

ReactNative上でログイン機能を実装するために、フォームを実装する必要があったのですが、Formikが想像以上に良かったので書き残します。 説明雑なので、コードを参考にする程度で読んでいただければと思います。

環境は、

  • ReactNative 0.55.3
  • Formik 1.0.0-alpha.6
  • Yup 0.24.1
  • TypeScript 2.7.2
続きを読む