Unity を検索

Spotlight チームのベストプラクティス:ヒエラルキーの最適化

2017年6月29日 カテゴリ: Engine & platform | 4 分 で読めます
取り上げているトピック
シェア

Is this article helpful for you?

Thank you for your feedback!

Spotlight チームでは、野心溢れる Unity 開発者の方々との共同作業により、Unity ゲームの可能性の限界を押し上げる取り組みを進めています。私達は日々、複雑なグラフィックス、パフォーマンス、デザインの問題に対する、革新的な優れたソリューションを目にしています。また、同じ問題が同じソリューションで繰り返し解決されている状況も目の当たりにしています。

本ブログシリーズでは、弊社がクライアントと共同作業をしている際に最も頻繁に発生した問題のいくつかをご紹介します。協力した様々なチームと共に多大な労力の末に獲得した知恵を、ここで全てのユーザーの皆様に共有できることを嬉しく思います。

これらの問題の多くは、実際にゲーム機やスマートフォンでの作業を開始した後や、膨大な量のゲームコンテンツを扱う段階になってから初めて発覚するものです。ここでご紹介する教訓を開発サイクルの初期から考慮しておくことで、制作の進行がよりスムーズになり、さらに高みを目指したゲームを開発できます。

「トランスフォーム変更」メッセージ

ゲームオブジェクトを移動するたびにそのトランスフォームが変更されるので、このことに関係しているすべてのゲームシステムにその移動について通知する必要があります。ゲームオブジェクトのレンダリング、物理演算、すべての親と子にこの移動を通知することで、それらを一致させる必要があるのです。ゲームのスコープが大きくなってゲームオブジェクトの数が急増するにつれて、これらのメッセージを送信するオーバーヘッドだけでもパフォーマンスにとって問題になります。

最近のプロジェクトの 1 つである『Shadow Tactics』を例に取ります。

これは、NPC のひとつで、構成要素をすべて持っています。次のスクリーンショットは、「ゲームオブジェクトを最適化する」を使用するためにすべてのリグを移動した後で撮影されました。このため、元のバージョンには、全てのゲームプレイオブジェクトとモデル構造だけでなく、NPC モデルのボーンが揃っていました。

これは、ゲームに対して期待される、まったく普通の設定です。レベルデザイナーが NPC のスポナーを配置している様子です。実行時に、これらのスポナーは自分の子として NPC インスタンスを作成します。Enemy_normal は NPC のルートです。これには NPC の移動を制御する「NavAgent」が含まれます。各 NPC にはゲームオブジェクトの一連の子が含まれており、これらの子が NPC の機能とチューニングを定義しています。これはどこもまったく間違っているわけではありません。

ただし、その意味は「全てのフレームで、NPC は、移動する際、トランスフォームが変更されたことを自身のすべての親と子に通知しなければならない」ということです。毎フレーム、すべての NPC が「トランスフォーム変更」メッセージを数百回送信し、そうするのに大量のフレームを消費することになります。

「トランスフォーム変更」メッセージにかかるフレームタイムを確認した後で、Mimimi Productions と話し合ったところ、同社はそれらのトランスフォームの生成をいくつかのシンプルな方法で変更しました。同社では、「Optimize Game Objects」をONに切り替えるだけでなく、シーンのルートレベルで NPC を生成するようになりました。また、「NPC Ability」ゲームオブジェクトをすべて NPC のルートに移動していたため、これらのオブジェクトは「NavAgent」の子にならなくなりました。これにより、NPC のビジュアルと物理演算だけが「NavAgent」の下に残りました。ターゲットハードウェアでは、これにより 10 FPS にも上るパフォーマンスの向上が得られました。

後ろにいる方たちのために、10 FPS とは何かをご説明すると、

毎秒 10 フレームという意味です。

ワークフローには大きく影響しません。また、戻って大量のコンテンツを開発し直す必要もありません。すでに持っているコンテンツを少し移動しただけです。

「トランスフォーム変更」メッセージを送信する

Unity 5.4 から、弊社ではトランスフォームと「トランスフォーム変更」メッセージに関連するすべてのコードを大幅に最適化しています。メモリのレイアウトを最適化し、外部からの変更を回避するための「SetPositionAndRotation」API を提供しています。弊社では、システムが「トランスフォーム変更」メッセージをエンジンのすべてのシステムにブロードキャストするのではなく、特定のトランスフォームのみをブロードキャストするように登録されるように現在、修正しています。

現在も継続中の最大の変更点のひとつは、遅延する、スレッド化された 「TransformChangeDispatch」システムに移行することです。これにより、完全に自己完結したヒエラルキーですべての「トランスフォーム変更」通知を待ち行列に登録し、メインスレッドからジョブ内で解決できます。弊社では、これらの通知をメインスレッド上で同期して作成するのでなく、これらの通知が送信されるように、できるだけ多くのシステムを移行している最中です。

このような改善が行われてはいますが、依然としてゲームを開発する際にはヒエラルキーの構造について考えることが非常に重要です。少し考慮しておくだけで、数フレーム分の実行時間を節約し、プレイヤーが関心を持つものにそれらのフレームを使用できるからです。

ヒエラルキー構造のガイドライン

  • 何かが毎フレーム動く場合は、その動くもののすべての子の位置にも注意する必要がある。子としては、レンダリング、物理演算、オーディオ、またはそのようなコアシステムのみを配置すること。
  • 実行時に作成するゲームオブジェクトを前述の理由でスポナーの子にする必要がない場合は、シーンのルートにゲームオブジェクトを生成する。
  • 生成するどのようなものでも登録し、スポナーの「ActiveInHeirarchy」状態を「OnEnable」と「OnDisable」を使用して渡すことが簡単にできる。
  • ルートごとに約 50 個のゲームオブジェクトになるように、移動するトランスフォームをグループ化してみる。これにより、スレッドあたりのワークロードが最適になるよう、「TransformChangeDispatch」ジョブが基盤となるシステムによってグループ化されるようになる。スレッドのオーバーヘッドに含まれるジョブはそれほど少なくない。また、スレッドの実行を待機するジョブはそれほど多くない。

末筆ながら、本記事の例としてゲーム『Shadow Tactics』の使用を快諾していただいたことを Mimimi Productions に感謝申し上げます。次回は、「リアルタイムグローバルイルミネーション」と「マルチシーン編集」を操作して学ぶレッスンを開催します。

2017年6月29日 カテゴリ: Engine & platform | 4 分 で読めます

Is this article helpful for you?

Thank you for your feedback!

取り上げているトピック
関連する投稿