💥

物理エンジンの接触判定トラブル(すり抜けとゴースト衝突)

2024/01/11に公開

VRゲームの開発時に遭遇した衝突判定のトラブルについて解説していきます.環境はUnityを想定していますが,UEやGazeboなどの他のシミュレーション環境でも発生する一般的な問題です.

衝突判定の基本

https://docs.unity3d.com/ja/2019.2/Manual/class-Rigidbody.html

  • Unityの接触判定はUnity内の物理エンジンで行われている.
  • 物理エンジンはRigidBodyとColliderの両方を持ったオブジェクト同士の接触を判定している.
  • 衝突判定にはDiscreteとContinuousの2のモードがあり,Continuousモードはさらに細かく別れている.
  • 高速で動いているオブジェクトはColliderが断続的にワープしている状態になる.ワープ中にすれ違った物体は接触指定なので判定されない(Discrete).
  • 上記のワープの問題に対処するために連続型衝突検知機能(ContinuousやContinuous Dynamic)が用意されている.

何が起こったのか

  • A) 振った棒が物体をすり抜ける(Discrete).
  • B) 棒に当たっていないのに接触したことになっている(Continuous Dynamic)

https://youtu.be/z8wzL6LiKlQ

物体のすり抜け(Tunneling)

これは物理エンジンでは有名な問題でTunnelingと呼ばれたりもしています.

まず,物理エンジンの中では連続的に運動している物体は存在しません.全ての物体は物理エンジンの計算間隔\Delta t毎にワープを繰り返しています.次の図では物体Aと物体Bが等速直線運動を行なっています.

それぞれの速さは v_Av_B です.物体A,物体Bは各フレームごとにそれぞれv_A \Delta t, v_B \Delta tだけワープしています.物体Bの方は物体の大きさに対してv_Bが大きく,前フレーム時との物体の重なりがありません.そのため,ワープ間に薄い物体がある場合にワープ中にすり抜けてしまいます.

連続物体検出

物体のすり抜けを防ぐために用意されているのが連続物体検出(Continuous Collision Detection, CCD)機能です.Unityでは3つのモードが用意されています.

  • Continuous: Static な rigidBodyを対象した並進運動に基づく予測を行う.
  • Continuous Dynamic: 全てのrigidBodyが対象を対象した並進運動に基づく予測を行う.
  • Continuous Speculative: 並進運動と回転運動に基づく予測を行う.

連続物体検出は物体の速度に基づいて,物体の起動を予測しています.

Colliderを速度方向に最大v \Delta tだけ滑らせて,滑り中に衝突がないかを判定しています.その特性上,弾丸のように等速直線運動を行なっている物体のすり抜けには効果的です.

ゴースト衝突 (Ghost Collision)

連続物体検出は速度に基づく予測を行うため,速度の変わらない運動には効果的です.しかし,下図のように速度が変わる運動に対しては,実際の物体の動きとは異なる予想をしてしまいます.この不適切な予測によって生じる衝突をゴースト衝突 (Ghost Collision)と言います.

速度の変わる運動,つまり物体に加速度(力)が働いている場合には連続物体検出は期待通りの動作をしなくなります.特に振動や回転では加速度の変化が大きいためゴースト衝突が発生しやすくなっています.

解決方法

  • 計算の間隔を短くする. 身も蓋もないですが,物理エンジンの計算間隔 \Delta tを短くすれば衝突の検出精度が上がります.一方で当然ですが計算的な負荷が増えます.デバイスの計算能力が低いと\Delta tを十分に小さくできないことがあります.特にOculusQuestなどのモバイルデバイスは計算能力が低いためこの問題が顕著になります.

  • Colliderを大きくする 物理的な挙動の正確さには興味がなく,すり抜けのみを問題とするならColliderを大きくすることですり抜けを回避することができます.ただし,メッシュの大きさとColliderの大きさの差が大きくなるため, 透明な物体当たるような挙動が発生しやすくなります.これを回避するには物体の速度に応じてColliderの大きさを変更するなどの工夫が必要になります.

  • 加速度や力も考慮する 加速度や力も考慮した予測(2次予測)を行えば,当然物体の運動の予測精度も上がります.自分で衝突判定の拡張機能を実装しなければならないので,難易度は高めで,計算負荷も大きなります.また,手持ち武器のようにOculusTouchなどのデバイスから加速度を与えている場合,デバイスのセンシング周波数がボトルネックになる可能性があります.


連続物体検出についてはUnityの公式ページの方でより詳しく解説されています.ただし,日本語訳が不適切なところが見られるので,原文(English)と並行して読んだ方が良さそうです.

https://docs.unity3d.com/ja/current/Manual/ContinuousCollisionDetection.html

  • UnityのページではSpeculativeを「投機的」と訳していますが,この文脈では「推測に基づく」と訳した方が適切です.
  • スイープ(sweep)は辞書にある意味とはニュアンスが違うのでここでは.「物体の動きの流れ」と解釈するのが良さそうです.sweep自体に(波が)押し流すという意味があり,この動きの流れには回転は含まれません.

Discussion