UI の最適化に関するその他のヒントとテクニック

確認済のバージョン: 5.3

-

難易度: Advanced

UI の最適化は、時として、クリーンな方法で行うことが不可能な場合があります。この章では、UIのパフォーマンスを向上するための提案をいくつか紹介していますが、その一部は構造的に「クリーンではない」場合や、維持・管理に困難を伴う場合、望ましくない副作用を伴う場合もあります。また、UI内の挙動の代替策となり得る方法も紹介されています。その目的は初期開発を簡素化することですが、パフォーマンスの問題が起こりやすくなるという欠点も持っています。

RectTransformを基にしたLayout

Layout コンポーネントは、ダーティとマークされるたびに子要素のサイズと位置を再計算する必要があるため、比較的負荷が高くなります。(詳細はUnity UIの基礎の章のGraphicリビルドの項を参照してください。)比較的小さい要素が固定数含まれる、比較的単純な構造のLayoutは、RectTransformベースのレイアウトに置き換えられる場合もあります。

RectTransform のアンカーを割り当てることで、そのRectTransformの位置とサイズがその親に基づいてスケールされるように設定することができます。例えば、2つの列を持つ単純なレイアウトなら2つのRectTransformsで実現できます。

  • 左の列のアンカーはXが(0, 0.5)、Yが(0, 1)
  • 左の列のアンカーはXが(0.5, 1)、Yが(0, 1)

RectTransform のサイズと位置の計算は、ネイティブのコードでTransformシステム自体によって行われます。Layoutシステムに依存するよりも、基本的にこの方が効率的です。また、RectTransformベースのLayoutをセットアップするMonoBehaviourを書くことも可能です。ただしこれは比較的複雑なタスクであり、その解説はこのガイド内には収まらないため、省略します。

Canvas Renderer の無効化

UI の各部の表示・非表示を個別に切り替える際は、そのUIのルートでGameObjectの有効・無効を切り替えるのが一般的です。この方法だと、無効化されたUIのコンポーネントが入力やUnityコールバックを受け取らなくなります。

ただし、これを行うと、CanvasからVBOデータが削除されます。Canvasを再有効化する場合、そのCanvas(および全てのSub-canvas)によってリビルドとリバッチの処理が実行される必要があります。これが頻繁に行われるとCPUの使用率が高くなり、アプリケーションのフレームがカクつきを起こす可能性があります。

正攻法とは言えませんが可能な回避策のひとつは、その UIを、専用のCanvasまたはSub-canvas上に、表示あるいは非表示になるように配置し、そのCanvasあるいはSub-canvasに付属するCanvas Rendererコンポーネントの有効・無効を切り替える方法です。

これを行うとUIのメッシュは描画されなくなりますがメモリ内には残り、元々のバッチは保持されます。さらに、UIのヒエラルキー内でOnEnableOnDisableコールバックが呼び出されなくなります。

ただし、これによって UIのGraphicsがGraphicRegistryから削除されることはないので、それらのGraphicsはGraphic Raycastが確認するコンポーネントの一覧上には残ります。非表示UI内のMonoBehaviourは無効化されないので、そのMonoBehaviourがUnityのライフサイクル・コールバック([例]Updateなど)を受け取らなくなる訳ではありません。

この問題を回避するためには、上記の方法で無効化される UIのMonoBehaviourに関しては、Unityのライフサイクル・コールバックを直接実装するのではなく、UIのルートゲームオブジェクトの“Callback Manager” MonoBehaviourからコールバックを受け取るようにします。この「Callback Manager」は、UIの表示・非表示が切り変わるたびにそれを検知したり、必要に応じてライフサイクルイベントが伝播されるように(あるいは伝播されないように)することができます。この「Callback Manager」のパターンに関する詳細な説明は、このガイドの範疇には収まらないため省略します。

Event Camera の割り当て

World Space モードや Screen Space – CameraモードでのレンダリングにUnityビルトインのInput ManagerをCanvasのセットと併せて使用している場合は常に、前者の場合はEvent Cameraプロパティ、後者の場合はRender Cameraプロパティを設定することが重要です。これはスクリプトからはworldCameraプロパティとして常に利用可能です。

このプロパティが設定されていない場合、Unity UIはMain Cameraタグの付属したゲームオブジェクトのCameraコンポーネントを検索し、メインカメラを探します。この検索は、各World SpaceあるいはCamera Space Canvasで最低1回実行されます。GameObject.FindWithTagは時間が掛かることが分かっているため、デザイン時間または初期化時間では、全てのWorld SpaceとCamera Space Canvas にCameraプロパティを割り当てるようにすることが強く推奨されます。

Overlay Canvas に関しては、この問題は起こりません。