Hero background image

スムーズなゲームプレイのための強化された物理パフォーマンス

このウェブページは、お客様の便宜のために機械翻訳されたものです。翻訳されたコンテンツの正確性や信頼性は保証いたしかねます。翻訳されたコンテンツの正確性について疑問をお持ちの場合は、ウェブページの公式な英語版をご覧ください。

これは、Unityプロジェクトの最適化のヒントを解説する一連の記事の5番目のものです。より少ないリソースで高いフレームレートで実行するためのガイドとして使用してください。これらのベストプラクティスを試したら、シリーズの他のページもぜひご覧ください:

物理は複雑なゲームプレイを生み出すことができますが、これにはパフォーマンスコストが伴います。これらのコストを理解すれば、シミュレーションを適切に管理するために調整できます。これらのヒントを使用して、目標フレームレート内に収め、Unityのビルトイン物理(NVIDIA PhysX)でスムーズな再生を実現してください。

Unity 6の開発者とアーティスト向けの最新の最適化ガイドをご覧ください:

コライダーを確認してください

物理で使用されるメッシュは、調理と呼ばれるプロセスを経ます。これにより、メッシュがレイキャスト、接触などの物理クエリで機能するように準備されます。

MeshColliderには、物理用にメッシュを検証するのに役立ついくつかのCookingOptionsがあります。メッシュにこれらのチェックが必要ないと確信している場合は、調理時間を短縮するためにそれらを無効にできます。

各MeshColliderのCookingOptionsでは、EnableMeshCleaning、WeldColocatedVertices、およびCookForFasterSimulationのチェックを外すだけです。これらのオプションは、ランタイムで手続き的に生成されたメッシュにとって価値がありますが、メッシュに適切な三角形がすでにある場合は無効にできます。

また、PCをターゲットにしている場合は、Use Fast Midphaseを有効に保つことを確認してください。これにより、シミュレーションの中間フェーズ中にPhysX 4.1からのより高速なアルゴリズムに切り替わります(これにより、物理クエリのために潜在的に交差する三角形の小さなセットを絞り込むのに役立ちます)。

詳細はCookingOptionsドキュメントで学べます。

UnityエディターのCooking Optionsインターフェース
メッシュのための調理オプション

Physics.BakeMeshを使用する

ゲームプレイ中に手続き的にメッシュを生成している場合は、ランタイムでMesh Colliderを作成できます。ただし、メッシュに直接MeshColliderコンポーネントを追加すると、メインスレッドで物理が調理/ベイクされます。これにより、CPU時間が大幅に消費される可能性があります。

Physics.BakeMeshを使用して、MeshColliderで使用するためのメッシュを準備し、メッシュ自体と一緒に焼き付けたデータを保存します。このメッシュを参照する新しいMeshColliderは、この事前焼き付けデータを再利用します(メッシュを再度焼き付けるのではなく)。これにより、シーンのロード時間や後のインスタンス化時間を短縮できます。

パフォーマンスを最適化するために、C#ジョブシステムを使用してメッシュの調理を別のスレッドにオフロードできます。

複数のスレッドでメッシュを焼き付ける方法の詳細については、この例を参照してください。

BakeMeshJob インターフェース
Profiler の BakeMeshJob

設定を調整する

Player Settingsで、可能な限りPrebake Collision Meshesをチェックしてください。プレイヤーとゲームメカニックオブジェクトが正しいレイヤーにあることを確認するために、Collision Matrixの設定を見直すことをお勧めします。

不要なレイヤーのトリガーからコールバックを削除することは大きな利点になる可能性があるため、Layer Collision Matrixを簡素化するようにしてください。Physics SettingsProject Settings > Physicsを介して編集できます。

Collision Matrixのドキュメントで詳細を学びましょう。

物理プロジェクト設定インターフェース
物理プロジェクト設定を変更して、より多くのパフォーマンスを引き出します。

シミュレーション頻度を変更する

物理エンジンは、固定時間ステップで実行されることによって機能します。プロジェクトが実行されている固定レートを確認するには、Edit > Project Settings > Timeに移動します。

Fixed Timestepフィールドは、各物理ステップで使用される時間デルタを定義します。例えば、0.02秒(20ms)のデフォルト値は、50fpsまたは50Hzに相当します。

Unityの各フレームは変数の時間を要するため、物理シミュレーションと完全に同期しているわけではありません。エンジンは次の物理時間ステップまでカウントアップします。フレームがわずかに遅くまたは速く実行される場合、Unityは経過時間を使用して、適切な時間ステップで物理シミュレーションを実行するタイミングを知ります。

フレームの準備に長い時間がかかる場合、これがパフォーマンスの問題につながる可能性があります。例えば、ゲームがスパイクを経験する場合(例えば、多くのGameObjectをインスタンス化したり、ディスクからファイルを読み込んだりする場合)、フレームの実行に40ms以上かかることがあります。デフォルトの20ms固定時間ステップでは、次のフレームで「追いつく」ために2つの物理シミュレーションが実行されることになります。

追加の物理シミュレーションは、フレームを処理するための時間をさらに追加します。低性能のプラットフォームでは、これがパフォーマンスの悪化を引き起こす可能性があります。

次のフレームの準備に時間がかかると、物理シミュレーションのバックログも長くなります。これにより、さらに遅いフレームと、フレームごとに実行する必要のあるシミュレーションが増えます。その結果、パフォーマンスがどんどん悪化します。

最終的に、物理更新の間隔が最大許可時間を超える可能性があります。このカットオフの後、Unityは物理更新をドロップし、ゲームがカクつきます。

物理に関するパフォーマンスの問題を避けるために:

  • シミュレーションの頻度を減らします。低性能のプラットフォームでは、固定時間ステップをターゲットフレームレートよりも少し高く設定します。例えば、モバイルで30psの場合は0.035秒を使用します。これにより、パフォーマンスの悪化を防ぐことができるかもしれません。
  • 最大許可時間を減少させます。小さい値(例えば0.1秒)を使用すると、物理シミュレーションの精度が犠牲になりますが、1フレームで発生できる物理更新の数も制限されます。プロジェクトの要件に合う値を見つけるために、値を試してみてください。

必要に応じて、フレームの更新フェーズ中にシミュレーションモードを選択して物理ステップを手動でシミュレートします。これにより、物理ステップを実行するタイミングを制御できます。Time.deltaTimeをPhysics.Simulateに渡して、物理をシミュレーション時間と同期させます。このアプローチは、複雑な物理や非常に変動するフレーム時間を持つシーンで物理シミュレーションの不安定性を引き起こす可能性があるため、注意して使用してください。

Physics.Simulate ドキュメントで詳細を学びます。

Unity エディターのデフォルトの「Fixed Timestep」
プロジェクト設定のデフォルトの固定タイムステップは0.02秒(1秒あたり50フレーム)です。

大規模シーンのためにボックスプルーニングを使用する

Unityの物理エンジンは2つのステップで実行されます:

  • ブロードフェーズ、これはスイープとプルーンアルゴリズムを使用して潜在的な衝突を収集します。
  • ナローフェーズ、ここではエンジンが実際に衝突を計算します。

スイープとプルーンブロードフェーズのデフォルト設定(編集 > プロジェクト設定 > 物理 > ブロードフェーズタイプ)は、一般的に平坦で多くのコライダーを持つワールドに対して誤検出を生成する可能性があります。シーンが大きくほとんど平坦な場合は、この問題を避けるために自動ボックスプルーニングまたはマルチボックスプルーニングブロードフェーズに切り替えてください。これらのオプションは、ワールドをグリッドに分割し、各グリッドセルがスイープとプルーンを実行します。

マルチボックスプルーニングブロードフェーズでは、ワールドの境界とグリッドセルの数を手動で指定できますが、自動ボックスプルーニングはそれを自動的に計算します。

物理プロパティの完全なリストはこちらで確認できます。

「Broadphase Type」インターフェース
物理オプションのブロードフェーズタイプ

ソルバーの反復回数を変更する

特定の物理ボディをより正確にシミュレートしたい場合は、そのRigidbody.solverIterationsを増やしてください。

これはPhysics.defaultSolverIterationsをオーバーライドし、編集 > プロジェクト設定 > 物理 > デフォルトソルバーイテレーションでも見つけることができます。

物理シミュレーションを最適化するには、プロジェクトのdefaultSolveIterationsに比較的低い値を設定してください。次に、詳細が必要な個々のインスタンスに対して高いカスタムRigidbody.solverIterations値を適用します。

Rigidbody.solverIterationsに関する詳細情報を取得します。

デフォルトのソルバーイテレーション
Rigidbodyごとのデフォルトソルバーイテレーションをオーバーライド

自動変換同期を無効にする

デフォルトでは、Unityは物理エンジンとTransformの変更を自動的に同期しません。代わりに、次の物理更新まで待つか、手動でPhysics.SyncTransformsを呼び出します。これが有効になっていると、そのTransformまたはその子のColliderRigidbodyが物理エンジンと自動的に同期します。

手動で同期するタイミング

autoSyncTransformsが無効になっている場合、UnityはFixedUpdateの物理シミュレーションステップの前またはPhysics.Simulateを介して明示的に要求されたときにのみ変換を同期します。Transformの変更と物理更新の間に物理エンジンから直接読み取るAPIを使用する場合、追加の同期を行う必要があるかもしれません。例としては、Rigidbody.positionにアクセスすることや、Physics.Raycastを実行することが含まれます。

パフォーマンスのベストプラクティス

autoSyncTransformsは最新の物理クエリを保証しますが、パフォーマンスコストがかかります。各物理関連API呼び出しは同期を強制し、特に複数の連続クエリがある場合、パフォーマンスを低下させる可能性があります。これらのベストプラクティスに従ってください:

  • 必要でない限りautoSyncTransformsを無効にする:ゲームメカニクスにとって正確で継続的な同期が重要な場合のみ有効にしてください。
  • 手動同期を使用する:パフォーマンスを向上させるために、最新のTransformデータが必要な呼び出しの前にPhysics.SyncTransforms()でTransformsを手動で同期してください。このアプローチは、autoSyncTransformsをグローバルに有効にするよりも効率的です。

Physics.SyncTransformsについて詳しく知る。

シーンで自動同期が無効になっている
自動同期が無効になっている状態でUnityのシーンをプロファイリングする

衝突コールバックを再利用する

接触配列は一般的に非常に高速であり、一般的な推奨は衝突コールバックを再利用するのではなく、それらを使用することです。ただし、特定の使用ケースがある場合は次のことを考慮してください。

コールバックMonoBehaviour.OnCollisionEnterMonoBehaviour.OnCollisionStay、およびMonoBehaviour.OnCollisionExitはすべて衝突インスタンスをパラメーターとして受け取ります。この衝突インスタンスはマネージヒープに割り当てられ、ガーベジコレクションされる必要があります。

生成されるゴミの量を減らすために、Physics.reuseCollisionCallbacksを有効にします(プロジェクト設定 > 物理 > 衝突コールバックの再利用<2>でも見つかります)。これがアクティブな場合、Unityは各コールバックに対して単一の衝突ペアインスタンスのみを割り当てます。これにより、ガーベジコレクタの無駄が減り、パフォーマンスが向上します。

一般的な推奨事項は、パフォーマンスの利点のために常に衝突コールバックの再利用を有効にすることです。この機能は、コードが個々のCollisionクラスインスタンスに依存しているレガシープロジェクトに対してのみ無効にするべきです。個々のフィールドを保存するのが非現実的になります。

Physics.reuseCollisionCallbacksについて詳しく学びます。

単一衝突インスタンス
Unity コンソールウィンドウの「Collision Entered」と「Collision Stay」に、単一衝突インスタンスがあります。

静的コライダーを移動する

静的コライダーは、Rigidbodyを持たないColliderコンポーネントを持つGameObjectです。

「静的」という用語とは反対に、静的コライダーを移動できることに注意してください。そのためには、物理ボディの位置を単純に変更します。位置の変更を蓄積し、物理更新の前に同期します。静的コライダーを移動するために、Rigidbodyコンポーネントを追加する必要はありません。

ただし、静的コライダーが他の物理ボディとより複雑に相互作用するようにしたい場合は、キネマティックRigidbodyを与えます。Transformコンポーネントにアクセスするのではなく、Rigidbody.positionRigidbody.rotationを使用して移動します。これにより、物理エンジンからのより予測可能な動作が保証されます。

注:個々の静的コライダー2Dをランタイムで移動または再構成する必要がある場合は、Rigidbody 2Dコンポーネントを追加し、静的ボディタイプに設定します。コライダー2Dが独自のRigidbody 2Dを持っていると、シミュレーションが速くなります。ランタイムでコライダー2Dのグループを移動または再構成する必要がある場合は、各GameObjectを個別に移動するよりも、単一の隠れた親Rigidbody 2Dの子としてすべてを持つ方が速くなります。

リジッドボディについての詳細情報を取得します。

非割り当てクエリを使用する

特定の距離と特定の方向で3Dプロジェクト内のコライダーを検出して収集するには、レイキャストやBoxCastのような他の物理クエリを使用します。注意してください、

複数のコライダーを配列として返す物理クエリ(OverlapSphereOverlapBoxなど)は、マネージヒープ上にこれらのオブジェクトを割り当てる必要があります。これは、ガーベジコレクタが最終的に割り当てられたオブジェクトを収集する必要があることを意味し、間違ったタイミングで発生するとパフォーマンスが低下する可能性があります。

このオーバーヘッドを削減するために、NonAllocバージョンのクエリを使用してください。例えば、OverlapSphereを使用してポイント周辺のすべての潜在的なコライダーを収集する場合は、代わりにOverlapSphereNonAllocを使用してください。

これにより、コライダーの配列(結果パラメーター)をバッファとして渡すことができます。NonAllocメソッドは、ガーベジを生成せずに動作します。そうでなければ、対応する割り当てメソッドのように機能します。

NonAllocメソッドを使用する際には、十分なサイズの結果バッファを定義する必要があることに注意してください。バッファは、スペースが不足しても成長しません。

2D 物理演算

上記のアドバイスは、Unityの2D物理システムでは適用されないことに注意してください。なぜなら、2D物理システムのメソッドには「NonAlloc」サフィックスがないからです。代わりに、複数の結果を返すメソッドを含むすべての2D物理メソッドは、配列またはリストを受け入れるオーバーロードを提供します。例えば、3D物理システムにはRaycastNonAllocのようなメソッドがありますが、2Dの同等のものは、配列またはListをパラメーターとして受け取るRaycastのオーバーロードバージョンを単に使用します。

var results = new List();

int hitCount = Physics2D.Raycast(origin, direction, contactFilter, results);

オーバーロードを使用することで、特別なNonAllocメソッドを必要とせずに2D物理システムで非割り当てクエリを実行できます。

NonAllocメソッドのドキュメントで詳細を学んでください。


レイキャスト用のクエリをバッチ処理する

Physics.Raycastを使用してレイキャストクエリを実行できます。ただし、大量のレイキャスト操作(例:10,000エージェントの視線を計算するなど)がある場合、これにはかなりのCPU時間がかかる可能性があります。

C#ジョブシステムを使用してクエリをバッチ処理するには、RaycastCommandを使用してください。これにより、メインスレッドから作業がオフロードされ、レイキャストが非同期で並行して実行できるようになります。

RaycastCommandsのドキュメントで例を参照してください。

物理デバッガーで可視化する

物理デバッグウィンドウ(ウィンドウ > 分析 > 物理デバッガー)を使用して、問題のあるコライダーや不一致をトラブルシューティングします。これは、互いに衝突できるGameObjectの色分けされたインジケーターを示します。

詳細については、物理デバッガーのドキュメントを参照してください。

「Physics Debugger」のインターフェース
unityキーアート21 11
Unityの開発者やクリエイター向けのさらなるヒント

Unityのベストプラクティスハブから、さらに多くのベストプラクティスやヒントを見つけてください。業界の専門家やUnityのエンジニア、テクニカルアーティストが作成した30以上のガイドから選択し、Unityのツールセットやシステムを使って効率的に開発する手助けをします。