Unityパフォマンス最適化シリーズーー物理モジュール

4年前、Unityの各主要なモジュールのパフォーマンス最適化知識（初心者向け版）を1つずつ説明しました。近年、エンジン自体、ハードウェアデバイス、製作基準などのアップグレードに伴って、UWAは引き続き規則や方法を更新して、各開発者に提供しつつあります。「アップグレード版」のパフォーマンス最適化マニュアルとして、**【Unityパフォーマンス最適化シリーズ】**はより多くの開発者が利用できるように、シンプルでわかりやすい表現を心がけています。今回、物理モジュールに関連する知識を共有します。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/c5dcfb0d-0a8c-29b8-e8ff-0c93eda23e43.png)

Unityプリインストールの物理エンジンでは、物理モジュールの時間コストは主に、FixedUpdate.PhysicsFixedUpdateと、ロジックコードの放射線検出および衝突検出に起因します。
FixedUpdate.PhysicsFixedUpdate関数の時間コスト構造は、主に2つの部分で構成されています。1つはPhysics.Processingで、もう1つはPhysics.Simulateです。一般的には、これら2つの関数のスタックに注意を払い、さらにスタック関数のコール回数と時間コストの割合から原因を特定する必要があります。パフォーマンスと最適化の対策に影響を与える一般的な要因は次のとおりです。
 
---

##一、プロジェクトには本当に物理モジュールが必要か？##

 
まず、UnityのAuto Simulationオプションの切り替えメカニズムを理解する必要があります。このオプションはUnity2017.4より前では公開されておらず、プロジェクトに物理コンテンツがあるかどうかに応じてエンジンが自動的にオンまたはオフになります。Unity2017.4以降では、このオプションは公開されており、デフォルトはオンです。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/8c03b00f-7471-b9c1-2345-85b55d0cfcba.png)

多くのプロジェクトでは、物理モジュールがオンであるかオフであるかに注意を払わないことで、不必要なパフォーマンスの浪費を引き起こします。開発チームは、プロジェクトの状況に応じて物理モジュールをオンにするかどうかを検討することをお勧めします。また、物理モジュールの役割を他のソリューションに置き換えて、物理パーツの時間コストを節約することも検討できます。
 
---

 
##二、物理的なコール回数を制御する

 
UWAの実機レポートの物理モジュールでは、物理の更新数が統計されておりました。

![３.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/1900d08e-6bb7-1558-c2ab-425298fb173c.jpeg)

 
物理のコール回数は、次の2つのパラメーターに焦点を当てる必要があります。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/05c05fbc-dee6-4207-044d-acb2db91ac28.png)
 
###1）Fixed Timestep

FixedUpdateの更新間隔はこれによって決定されます。この値が大きいほど、フレームあたりの物理更新回数は少なくなります。ただし、物理更新頻度が低すぎる場合は、一部のメカニズムが異常になる可能性があります。開発チームは、許容範囲内で可能な限りFixed Timestepの数値を上げることをお勧めします。
 
###2）Maximum Allowed Timestep

ここでは、物理システム自体の特性を知る必要があります。つまり、**ゲームは前のフレームがフリーズすると、Unityは現在のフレームの非常に早い段階でFixedUpdate.PhysicsFixedUpdateを連続的にN回ほど呼び出します。Maximum Allowed Timestepはまさに物理更新回数を制限する役割を果たします。**

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/6bdec5fa-2178-8a77-b84f-2de215569b8c.png)

 
Maximum Allowed TimeStepは、単一フレームの物理最大コール回数を決定します。この値が小さいほど、単一フレームの物理最大コール回数は少なくなります。Fixed Timestepが20 msを前提に、Maximum Allowed Timestepを333msから100msへと下げさせたら、スタック状態に関係なく、このフレームは最大17回ではなく、5回だけ呼び出します。
 
さらに、次のフレームの物理更新回数を減らすために、まずは他のモジュールを最適化することをお勧めします。
 
---
 
##三、Contact数は妥当か？

 
Contact数が異常になるのは、普通次の2つの状況があります。
 
###1）Contact数が多すぎる

盾と地面の衝突など、不必要な物理的衝突検出があるかどうかを考慮する必要があります。

![６.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/71e9ebb0-02d2-6d22-59f0-be632ad87aa2.jpeg)

 
###2）Contact数が0で、且つ物理時間が存在している

Contact数が0ということは、プロジェクトに衝突またはTriggerがないことを意味しています。クロスシミュレーションなどのような物理特性を使用しない場合は、物理モジュールをオフにする、つまりAutoSimulationをオフにすることを検討できます。

![７.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/bedf36f0-44bf-b865-748c-387f4e51c71c.jpeg)

---
 
###四、Raycastの使用を減らす

 
Raycastとは、放射線検出と呼ばれたものです。その時間は放射線の数に比例します。ということは、 Raycastの時間を制御したいと、最も簡単な方法は、放射線の数を制御することです。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/e85adfaf-7a91-4737-c5ad-b04462806b64.png)


 
ただし、一部のプロジェクトでは確かに多くのRaycastが必要です。たとえば、弾幕ゲームでのRaycast数が多くあります。この場合、Job SystemでのRaycastCommandを利用して、Raycastの時間をメインスレッドから子スレッドに転送することによってその時間を減らします。
 
 ---

##五、Auto Sync Transforms

 
Auto Sync Transformsを選択すると、Physics Queryが発生したら、UnityはRigidbody / ColliderのTranformの変更をPosition、Scaleなどの物理エンジンに同期します。さらに、AutoSimulationが選択されている場合、Unityは物理更新するたびにRigidbodyとColliderを自動的に同期します。したがって、AutoSimulationがオフになっていた後に、プロジェクトで放射線検出またはNGUIが使用されている場合は、通常、Auto SyncTransformsを選択する必要があります。そうしないと、放射線検出の結果が正しくなくなるか、UIイベントが応答しなくなるかのことが発生する可能性があります。
 
一般に、同期操作のパフォーマンスコストは非常に低いです。非常に大きなシーンで、さらに多数のオブジェクトがシーンにロードされるの状況しか、時間コストが高い問題が発生しません。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/476318b6-73cf-d473-94c9-e5ec194292e2.png)

 
 ---

##六、ロジックコードについて

 
ここでのロジックコードは、MonoBehaviorスクリプトのvoid FixedUpdate関数を指します。通常、Profilerではxxx.FixedUpdateとして表示されます。この関数のコール回数は、物理更新回数に影響されます。
![10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/cd8f3f9f-be5c-d9cc-c673-e80c271c55e3.jpeg)


 
たとえば、Monster.csがシーンにマウントされているmobは10個があり、このスクリプトはvoidFixedUpdateにロジックコードを書き込みました。という場合に、現在のフレームの物理更新回数が3であると、このフレームのMonoster.FixedUpdateが10 * 3 = 30回呼び出されることがProfilerに表示されます。
 
通常、コードをできるだけUpdate関数に書き込むことをお勧めします。これなら、対応するロジックの実行回数が減り、ロジックコードの時間が短縮されます。

 ---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

今なら、UWA GOTローカルツールが**15日間に無償試用**できます！！
よければ、ぜひ！

UWA公式サイト：https://jp.uwa4d.com
UWA GOT OnlineレポートDemo：https://jp.uwa4d.com/u/got/demo.html
UWA公式ブログ：https://blog.jp.uwa4d.com