Hero background image

Unity UI の最適化のヒント

キャンバスとレイアウトグループの分割、UI オブジェクトのプールなどのヒントから、UI を完全に最適化する方法をご確認ください。
このウェブページは、お客様の便宜のために機械翻訳されたものです。翻訳されたコンテンツの正確性や信頼性は保証いたしかねます。翻訳されたコンテンツの正確性について疑問をお持ちの場合は、ウェブページの公式な英語版をご覧ください。

これは、PC およびコンソールゲームを最適化する方法に関する詳細なガイダンスを提供するいくつかのページの 1 つです。無料のeブック「Optimize your console and PC game performance」には、パフォーマンス最適化のための80以上の実用的なヒントとベストプラクティスが満載です。

キャンバスを分割する

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

Canvas は Unity UI の基本コンポーネントです。UI に配置された UI 要素を表現するメッシュを生成し、UI 要素が変更された場合はメッシュを再生成します。そして、UI が実際に表示されるように GPU に対してドローコールを発行します。

これらのメッシュの生成にはコストがかかる場合があります。UI 要素は、できるだけ少ないドローコールで描画されるように、バッチに収集する必要があります。バッチ生成は負荷が高いため、必要なときにのみ再生成する必要があります。問題は、キャンバス上で 1 つ以上の要素が変更された場合、その要素を最適に描画する方法を見つけるために、キャンバス全体をもう一度分析する必要があることです。

多くのユーザーは、何千もの要素を含む 1 つのキャンバス上にゲームの UI 全体を構築しています。1 つの要素を変更すると、数ミリ秒の CPU スパイクが発生する可能性があります。再構築にコストがかかる理由については、こちらの Unite セッションの 24:55 をご覧ください。

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

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

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

Graphic Raycaster インターフェース

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

問題:Graphic Raycaster の不適切な使用

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

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

課題は、すべての UI Elements が更新を受け取りたいわけではないことです。

解決策:非インタラクティブ UI キャンバスから Graphic Raycaster を削除し、静的または非インタラクティブ要素の Raycast Target をオフにします。

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

問題:Graphic Raycaster がレイキャスターとして機能することもあります。

キャンバスのレンダーモードを「Worldspace Camera」または「Screen Space Camera」に設定すると、ブロッキングマスクを追加できます。ブロッキングマスクは、レイキャスターが 2D 物理と 3D 物理のどちらでレイを照射するかを決定し、何らかの物理オブジェクトがユーザーの UI 操作の妨げになっていないかを決定します。

解決策:2D または 3D 物理演算によるレイのキャストは負荷が高いため、この機能は控えめに使用してください。

Graphic Raycaster を非インタラクティブな UI Canvas から除外することで、その数を最小限に抑えます。この場合、インタラクションイベントをチェックする理由はないからです。

Graphic Raycaster の詳細については、このドキュメントを参照してください。

グリッドインターフェース

コストのかかる UI 要素を避ける

問題:大規模なリスト、グリッドビュー、多数のオーバーレイ UI 要素にはコストがかかります。

大きなリストビューやグリッドビューは負荷が高く、多数の UI 要素を重ねる(カードバトルゲームでカードを重ねる)とオーバードローが発生します。

解決策:多数のオーバーレイ UI 要素は避けてください。

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

何百ものアイテムがあるインベントリ画面など、大きなリストビューやグリッドビューを作成する必要がある場合は、各アイテムに 1 つの UI 要素を使用するのではなく、小さな UI 要素のプールを再使用することを検討してください。

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

レイアウトグループのインターフェース

可能な場合はレイアウトグループの使用を避ける

問題:レイアウトをダーティにしようとする各 UI 要素は、少なくとも 1 回の GetComponent 呼び出しを実行します。

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

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

さて、現在の問題について:レイアウトを「ダーティ」にマークしたすべての UI 要素は、少なくとも 1 回の GetComponent 呼び出しを実行します。この呼び出しは、レイアウト要素の親で有効なレイアウトグループを探します。見つかった場合は、レイアウトグループの検索を停止するか、ヒエラルキーのルートに到達するかのいずれか早い方まで、Transform ヒエラルキーを遡り続けます。そのため、各レイアウトグループは、各子レイアウト要素のダーティ化プロセスに 1 つの GetComponent 呼び出しを追加し、ネストされたレイアウトグループはパフォーマンスが非常に悪くなります。

解決策:可能な場合はレイアウトグループの使用を避ける。

プロポーショナルレイアウトにはアンカーを使用します。動的な UI 要素数を持つホット UI では、レイアウトを計算する独自のコードを作成することを検討してください。変更のたびに使用するのではなく、必要に応じて使用してください。

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

オブジェクトプーリングのインターフェース

UI オブジェクトをスマートにプールする

問題:UI オブジェクトのプーリングを誤った方法で行う

UI オブジェクトは、多くの場合、親子関係を変えて無効化することでプールされ、不要なダーティ化を引き起こします。

解決策:まずオブジェクトを無効にしてから、プールに親子関係を持たせます。

古いヒエラルキーを一度ダーティにしますが、一度親にすると、古いヒエラルキーをもう 1 度ダーティにすることがなくなり、新しいヒエラルキーをダーティにすることもありません。プールからオブジェクトを削除する場合は、まずオブジェクトを親子関係にして、データを更新してから有効にします。

Unity のオブジェクトプールの基本概念の詳細をご覧ください。

UI Canvas コンポーネント

キャンバスを非表示にする方法

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

UI 要素やキャンバスを隠すと便利な場合があります。しかし、これを効率的に行うにはどうすればよいでしょうか。

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

Canvas コンポーネントを無効にすると、Canvas が GPU にドローコールを発行しなくなります。これでキャンバスが見えなくなります。ただし、キャンバスは頂点バッファを破棄せず、すべてのメッシュと頂点を保持します。再度有効にすると、リビルドはトリガーされず、描画が再開されます。

さらに、Canvas コンポーネントを無効にしても、Canvas ヒエラルキーを介した高負荷の OnDisable/OnEnable コールバックはトリガーされません。フレーム単位の高コストなコードを実行する子コンポーネントを無効にすることにご注意ください。

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

UI 要素でのアニメーターの最適使用

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

アニメーターは、アニメーションの値が変化しなくても、毎フレーム UI 要素をダーティにします。

解決策:UI Animation のコードを使用します。

常に変化する動的な UI 要素にのみアニメーターを配置します。めったに変更されない要素や、イベントに応じて一時的に変更される要素については、独自のコードを記述するか、トゥイーンシステムを使用してください。アセットストアでは、これに対応する優れたソリューションを多数提供しています。

全画面 UI を使用する場合は、その他をすべて非表示にする

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

一時停止画面やスタート画面がシーン全体を覆う表示になっている場合、残りのゲームは引き続きバックグラウンドでレンダリングされるため、パフォーマンスに影響を与える可能性があります。

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

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

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

その他のリソース

ゲームパフォーマンスの最適化

無料の e ブックを入手して詳細を見る

プレイヤーに可能な限り最高のゲーム体験を提供します。Unity のエキスパートエンジニアによる 80 以上の実用的なヒントとベストプラクティスを活用して、PC およびコンソールゲームを最適化することができます。

Unity の Success チームと Unity Studio Productions チームによって作成されたこれらの詳細なプラクティスは、トップスタジオとの実際のエンゲージメントから収集されたもので、ゲーム全体のパフォーマンスを向上させるのに役立ちます。