【Unity】Physics.Raycast のパフォーマンスはシーンに存在するColliderの数に影響するのか
- 概要
- 動作環境
- Raycastについて
- 検証の集計に関して
- 検証
- 調査結果のまとめ考察
- 余談:謎の高負荷が起きる現象
- 今後やってみたいこと
- 今回使用したプロジェクト
- 雑談
概要
Physics.Raycast のパフォーマンスはシーンに存在するColliderの数に影響するのかを調べてみました。
経緯はRaycastを使用するスクリプトを書いているときに、ふと気になったからです。
動作環境
Raycastについて
Raycastのアルゴリズムは「Rayの直線とColliderが交わるかを調べる」、そして「Rayの開始位置に近いColliderを選ぶ」ことです。
逆に言えばRayとすべてのColliderを検証する必要があるため、Colliderの数が多ければ多いほどRaycastのパフォーマンスは悪化すると考えられます。
検証の集計に関して
今回は簡易的に調査結果を記載します。
本格的な調査としてのデータが欲しい場合は検証対象を複数回行い、その平均を取ることが望ましいです。
検証
検証方法
- Profilerを使用して
Physics.Raycast
メソッドの時間を計測 Physics.Raycast
は1サンプリングに10000回行う- 1サンプリングに1回だと差異が小さすぎるため
Build and Run
より検証- Playだと同一シーンでも差が出てしまったため
以下はコードのイメージ
Profiler.BeginSample(samplingName); for (int i = 0; i < 10000; ++i) { Physics.Raycast(...); } Profiler.EndSample();
使用するCollider
CapsuleCollider
を使用Rigidbody
を付与、かつuseGravity=false
- 動的Colliderとして設定
検証1. ボックス状にコライダーを複数配置し、Raycastの時間を検証
以下のようにコライダーとRaycastを配置し、Raycastの時間を検証
- ボックス状にコライダーを配置
- 中心付近と8隅のColliderに真っ先に当たるRaycastを用意
- Colliderの検証順番がワールド座標でソートされている可能性を考慮
- どのColliderにも当たらないRaycastを用意
- RaycastのMaxDistance: 10000で固定
2 x 2 x 2 合計1000の結果
10 x 10 x 10 合計1000の結果
40 x 40 x 40 合計8000の結果
検証1での考察
40x40x40のパターンは10x10x10の64倍のCollider数の差があるにも関わらず、Timeの増加はそれほど大きくありませんね。 また、特徴的な点として「どのColliderにも当たらないRaycast (Raycast to Empty)」は、他のRaycastと比べるとTimeが短いですね。
Physics.Raycast
はoriginに最も近いColliderを返すため、距離でのソート処理が発生すると考えられます。
Rayと交わるColliderが1つもない場合はソート処理が発生しないのでTimeも短くなるのかもしれません。
よって「Raycastでソート処理対象のColliderの数」は「シーンにあるColliderの数」よりさらにパフォーマンスに大きく影響するのかもしれません。
GPU Usageの確認
今回の時間の差異の様子からシングルスレッドではなくマルチスレッドで処理されていると予想しGPU Usageを確認してみました。
Colliderの数の差がはっきりと現れていますね。
GPU側で各ColliderごとにRaycastの並列処理を行っていると思われます。
検証2. ソート対象になるようにColliderを配置し、Raycastの時間を検証
- Rayの直線状に並ぶColliderの数を変える
Colliderの数(ソート対象)が100の結果
Colliderの数(ソート対象)が1000の結果
Colliderの数(ソート対象)が10000の結果
検証2の考察
検証結果からRaycast時のソート対象が多いほど、Physics.Raycast
にかかる時間が増える傾向にあると思われます。
検証3. MaxDistanceでソート対象が絞られるようにRaycastを設定し、Raycastの時間を検証
- MaxDistanceを変える
- Rayの直線状に並ぶColliderの数は一定
- 必ずMaxDistanceの範囲を超えて生成されるように配置
- マージン: 5, Collider数: 10000
MaxDistance: 100(ソート対象は約20)
MaxDistance: 1000(ソート対象は約200)
MaxDistance: 10000(ソート対象は約2000)
検証3の考察
ソート対象の数に比例してTimeの増加しているため、やはりソート対象が多いとPhysics.Raycast
にかかる時間が増えると思われます。
調査結果のまとめ考察
※PCの場合での考察
Physics.Raycast
の時間は以下のような傾向がある- シーンに存在するColliderの数に少し依存する
- originに最も近いColliderを算出する際のソート対象数に大きく依存する
- ソート対象なしの場合、早く終了する
Physics.Raycast
1回のコストはそれほど大きくない- 今回の検証が10000回の合計であることを考えると、1回あたりの時間は大きくないと考える
Physics.Raycast
のGPUのコストはシーンに存在するCollider数に依存
余談:謎の高負荷が起きる現象
以下のようにソート対象がないにも関わらず高負荷になるパターンがありました。
調査してみましたが残念ながら原因は不明です。。。
現象が起きるパターンは以下の画像のようにRaycastをする場合です。
Profilerでは「Raycaster maxDistance 1000.0 Ex」という名前で表示されています。
うまく説明はできませんが、発生する条件は以下のような感じです。
- Collider群のうち、X座標がColliderたちの中で端よりの内側
- 逆に外側だとソート対象なしと同様になります。。。
- ColliderとColliderの間にRayの直線が通るようにRaycast
- 1つでもColliderにぶつかるようにすると解消される
- 「Raycaster maxDistance 1000.0 Ex」の目の前にColliderを配置するなど
バグなのかどうかは不明ですが、判明したことがあれば共有します。
今後やってみたいこと
- 上記謎現象の原因解明
- TerrainなどのMeshColliderの場合での検証
- プラットフォーム毎の
Physics.Raycast
の差異- 特にOculus Quest (Android)
今回使用したプロジェクト
雑談
Raycastのパフォーマンスが気になって調査してみましたが、よく言われているみたいに時間的には低コストみたいで安心しました。
RaycastのアルゴリズムやGPU向け処理などの最適化を裏側でやってくれているので、Physics.Raycast
のありがたさを改めて実感した気がします。
ただ、Oculus Questなどのモバイル端末だと変わってきそうなので、日を見て調査してみようと思います。
また、まだ謎な部分もあるのでもし何かご存知の方がいらっしゃいましたら共有いただけると嬉しいです!
それでは~