Hero background image
Unity UIの最適化のヒント
キャンバスとレイアウト グループの分割、UI オブジェクトのプールなどに関するヒントを使用して、UI を完全に最適化する方法を学びます。

これは、PC およびコンソール ゲームを最適化する方法についての詳細なガイダンスを提供する複数のページのうちの 1 つです。パフォーマンスの最適化に関する 80 以上の実用的なヒントとベスト プラクティスが満載の無料電子書籍「 コンソールと PC ゲームのパフォーマンスを最適化する」に、完全なコレクションが掲載されています。

キャンバスを分割する

問題UI キャンバス上の 1 つの要素が変更されると、キャンバス全体が変更されます。

Canvas は Unity UI の基本コンポーネントです。配置された UI 要素を表すメッシュを生成し、UI 要素が変更されたときにメッシュを再生成し、UI が実際に表示されるように GPU に描画呼び出しを発行します。

これらのメッシュを生成するにはコストがかかる可能性があります。UI 要素は、できるだけ少ない描画呼び出しで描画されるようにバッチにまとめる必要があります。バッチ生成はコストがかかるため、必要な場合にのみ再生成する必要があります。問題は、Canvas 上の 1 つ以上の要素が変更された場合、その要素を最適に描画する方法を判断するために、Canvas 全体を再度分析する必要があることです。

多くのユーザーは、何千もの要素を含む単一のキャンバス上にゲームの UI 全体を構築します。1 つの要素を変更すると、数ミリ秒かかる CPU スパイクが発生する可能性があります。再建になぜそれほど費用がかかるのかについて詳しく知るには、 この Unite セッションの 24:55 のマークをご覧ください。

解決策:キャンバスを分割します。

各キャンバスは、その要素を他のキャンバスの要素から分離する島です。キャンバスをスライスして複数のキャンバスをサポートする UGUI の機能を活用して、Unity UI のバッチ処理の問題を解決します。

また、キャンバスをネストすることもできます。これにより、デザイナーはキャンバス全体のさまざまな要素が画面上のどこにあるかを考える必要がなくなり、大規模な階層型 UI を作成できます。子キャンバスは、親キャンバスと兄弟キャンバスの両方からコンテンツを分離します。独自のジオメトリを維持し、独自のバッチ処理を実行します。分割方法を決定する 1 つの方法は、更新の頻度に基づいて決定することです。静的な UI 要素を別のキャンバスに保持し、同時に更新される動的な要素を小さなサブキャンバスに保持します。また、各キャンバス上のすべての UI 要素の Z 値、マテリアル、テクスチャが同じであることを確認します。

Graphic Raycaster インターフェース
グラフィックレイキャスターを制限し、レイキャストターゲットを無効にする

問題グラフィックレイキャスターの不適切な使用

Graphic Raycaster は、入力を UI イベントに変換するコンポーネントです。具体的には、画面のクリックや画面上のタッチ入力を UI イベントに変換し、それを対象の UI 要素に送信します。サブキャンバスを含む、入力を必要とするすべてのキャンバスに Graphic Raycaster が必要です。ただし、画面上のすべての入力ポイントをループし、それらが UI の RectTransform 内にあるかどうかをチェックするため、オーバーヘッドが発生する可能性があります。

名前にもかかわらず、Graphic Raycaster は実際にはレイキャスターではありません。デフォルトでは、UI グラフィックのみをテストします。特定のキャンバスで入力を受け取ることに関心のある UI 要素のセットを取得し、交差チェックを実行します。たとえば、Graphic Raycaster の Canvas 上の各 UI 要素の RectTransform に対して入力イベントが発生するポイントがインタラクティブとしてマークされているかどうかを確認します。

問題は、すべての UI 要素が更新の受信に関心があるわけではないことです。

解決策:非インタラクティブな UI キャンバスからグラフィック レイキャスターを削除し、静的または非インタラクティブな要素のレイキャスト ターゲットをオフにします。

特に、レイキャスト ターゲットをオフにするボタン上のテキストは、グラフィック レイキャストが各フレームで実行する必要がある交差チェックの数を直接削減します。

問題場合によっては、Graphic Raycaster がレイキャスターとして機能することもあります。

キャンバスのレンダリング モードをワールド空間カメラまたはスクリーン空間カメラに設定すると、ブロッキング マスクを追加できます。ブロッキング マスクは、Raycaster が 2D または 3D 物理を介してレイをキャストするかどうかを決定し、何らかの物理オブジェクトがユーザーの UI との対話をブロックしているかどうかを判断します。

解決策:2D または 3D の物理法則を使用してレイをキャストするとコストがかかる可能性があるため、この機能は控えめに使用してください。

この場合、インタラクション イベントをチェックする必要がないため、非インタラクティブな UI キャンバスからグラフィック レイキャスターを除外して、グラフィック レイキャスターの数を最小限に抑えます。

このドキュメントで Graphic Raycaster について詳しく学んでください。

グリッドインターフェース
高価なUI要素を避ける

問題大きなリスト、グリッド ビュー、および多数のオーバーレイされた UI 要素はコストがかかります。

大規模なリスト ビューとグリッド ビューはコストが高く、多数の UI 要素 (カード バトル ゲームで積み重ねられたカードなど) を重ねるとオーバードローが発生します。

解決策:多数の UI 要素が重なり合うことは避けてください。

コードをカスタマイズして、実行時に階層化された UI 要素をより少ない要素とバッチにマージします。

数百のアイテムを含むインベントリ画面など、大規模なリスト ビューまたはグリッド ビューを作成する必要がある場合は、アイテムごとに 1 つの UI 要素を使用するのではなく、より小さな UI 要素のプールを再利用することを検討してください。

最適化されたスクロール リストの例については、この GitHub プロジェクト をご覧ください。

レイアウトグループのインターフェース
可能な限りレイアウトグループを避ける

問題レイアウトを変更しようとするすべての UI 要素は、少なくとも 1 回の GetComponent 呼び出しを実行します。

レイアウト システムで 1 つ以上の子 UI 要素が変更されると、レイアウトは「ダーティ」になります。変更された子要素は、それを所有するレイアウト システムを無効にします。

レイアウト システムは、レイアウト要素のすぐ上にある連続した レイアウト グループ のセットです。レイアウト要素は、レイアウト要素コンポーネント (UI イメージ、テキスト、スクロール Rect) だけではなく、レイアウト要素も含みます (スクロール Rect もレイアウト グループです)。

さて、当面の問題に関してですが、レイアウトを「ダーティ」としてマークするすべての UI 要素は、少なくとも 1 回の GetComponent 呼び出しを実行します。この呼び出しは、レイアウト要素の親にある有効なレイアウト グループを検索します。見つかった場合は、レイアウト グループの検索を停止するか、階層ルートに到達するまで、Transform 階層を上っていきます (どちらか早い方)。そのため、各レイアウト グループは、各子レイアウト要素のダーティ化プロセスに 1 つの GetComponent 呼び出しを追加するため、ネストされたレイアウト グループのパフォーマンスが著しく低下します。

解決策:可能な場合はレイアウト グループを避けてください。

比例レイアウトにはアンカーを使用します。UI 要素の数が動的に変化するホット UI では、レイアウトを計算する独自のコードを記述することを検討してください。毎回の変更ではなく、必要に応じてこれを使用してください。

レイアウト グループの詳細については、 ドキュメントをご覧ください。

オブジェクトプーリングのインターフェース
UIオブジェクトをスマートにプールする

問題UI オブジェクトを間違った方法でプールする

多くの場合、UI オブジェクトを再親子化してから無効にすることでプールしますが、これにより不要なダーティ化が発生します。

解決策:まずオブジェクトを無効にし、次にそれをプールに再配置します。

古い階層は一度ダーティになりますが、親を変更すると、古い階層が 2 度目にダーティになることがなくなり、新しい階層もまったくダーティになりません。プールからオブジェクトを削除する場合は、まずオブジェクトの親を変更し、データを更新してから有効にします。

Unity の基本的なオブジェクト プーリングの概念について詳しく学びます。

UI Canvas コンポーネント
キャンバスを非表示にする方法

問題キャンバスを非表示にする方法がわからない

UI 要素とキャンバスを非表示にすると便利な場合があります。しかし、どうすればこれを効率的に行うことができるのでしょうか?

解決策:Canvas コンポーネント自体を無効にします。

Canvas コンポーネントを無効にすると、Canvas は GPU に描画呼び出しを発行しなくなります。こうすると、キャンバスは表示されなくなります。ただし、Canvas は頂点バッファを破棄せず、メッシュと頂点をすべて保持します。その後、再度有効にすると、再構築はトリガーされず、再び描画が開始されます。

さらに、Canvas コンポーネントを無効にしても、Canvas 階層を介してコストのかかる OnDisable/OnEnable コールバックはトリガーされません。フレームごとにコストのかかるコードを実行する子コンポーネントを無効にするように注意してください。

Canvas コンポーネントの詳細については 、こちらをご覧ください。

UI要素におけるアニメーターの最適な使用

問題UI でアニメーターを使用する

アニメーターは、アニメーション内の値が変わらない場合でも、フレームごとに UI 要素を汚します。

解決策:UI アニメーションのコードを使用します。

常に変化する動的な UI 要素にのみアニメーターを配置します。ほとんど変更されない要素や、イベントに応じて一時的に変更される要素の場合は、独自のコードを記述するか、トゥイーン システムを使用します。Asset Storeには、この問題に対する優れたソリューションが数多く用意されています。

フルスクリーンUIを使用する場合は、他のすべてを非表示にします

問題フルスクリーンUIでのパフォーマンスが悪い

ゲームでシーン全体をカバーする一時停止画面または開始画面が表示される場合、ゲームの残りの部分はバックグラウンドでレンダリングされているため、パフォーマンスに影響する可能性があります。

解決策:その他はすべて非表示にします。

シーン内の他のすべてを覆う画面がある場合は、3D シーンをレンダリングするカメラを無効にします。同様に、上部の Canvas の背後に隠れている Canvas 要素を無効にします。

フルスクリーン UI では 60 fps で更新する必要はないため、Application.targetFrameRate を下げることを検討してください。

その他のリソース
ゲームパフォーマンスの最適化
詳細は無料電子書籍をご覧ください

プレイヤーに最高のゲーム体験を提供します。Unity の専門エンジニアによる 80 を超える実用的なヒントとベストプラクティスを活用して、PC ゲームやコンソール ゲームを最適化できます。

Unity の Success およびAccelerate Solutionsエンジニアリング チームによって作成された、具体的にはトップ スタジオとの実際の取り組みから収集されたこれらの詳細なプラクティスは、ゲームの全体的なパフォーマンスの向上に役立ちます。

このコンテンツは役に立ちましたか?