8

私は、3D宇宙飛行、惑星/恒星重力、船の推力、相対論的効果を組み込んだ物理エンジン/シミュレーターを書いています。これまでのところ、非常にうまくいっていますが、私が助けを必要としていることの1つは、衝突検出アルゴリズムの計算です。

私が使用している動きの反復シミュレーションは、基本的に次のとおりです。

(注:3Dベクトルはすべて大文字です。)

For each obj

    obj.ACC = Sum(all acceleration influences)

    obj.POS = obj.POS + (obj.VEL * dT) + (obj.ACC * dT^2)/2     (*EQ.2*)

    obj.VEL = obj.VEL + (obj.ACC * dT)

Next

どこ:

obj.ACC is the acceleration vector of the object
obj.POS is the position or location vector of the object
obj.VEL is the velocity vector of the object

obj.Radius is the radius (scalar) of the object

dT is the time delta or increment

基本的に私がする必要があるのは、上記の(EQ.2)から派生した2つのオブジェクト(obj1、obj2)の効率的な式を見つけて、それらが衝突するかどうか、衝突する場合はいつかを判断することです。正確な時刻が必要なのは、それがこの特定の時間増分にあるかどうかを判断できるようにするため(加速度は時間増分ごとに異なるため)と、正確な位置を特定できるようにするためです(これは、時間)

このエンジンでは、すべてのオブジェクトを球としてモデリングしています。この式/アルゴリズムで行う必要があるのは、どのポイントであるかを把握することだけです。

(obj1.POS - obj2.POS).Distance = (obj1.Radius + obj2.Radius)

ここで、.Distanceは正のスカラー値です。(これが簡単な場合は、.Distance計算に暗黙的に含まれる平方根関数を回避するために、両側を2乗することもできます)。

(はい、私は他の多くの衝突検出の質問を知っていますが、それらの解決策はすべてそれらのエンジンと仮定に非常に特有であるようであり、シミュレーションの増分内で適用される3D、球、および加速度の条件に一致するものはないようです。私が間違っているかどうか教えてください。)


いくつかの説明:

1)時間増分の前後で2つの球の交差をチェックするだけでは不十分です。多くの場合、それらの速度と位置の変化はそれらの半径をはるかに超えます。

2)RE:効率性、衝突の可能性のある候補を決定することに関して(とにかくこの時点で)助けは必要ありません、私はそれをカバーしていると思います。


たくさん出てくるように思われる別の説明:

3)増分移動の私の方程式(EQ.2 )は、速度加速度の両方を適用する2次方程式です。

obj.POS = obj.POS + (obj.VEL * dT) + (obj.ACC * dT^2)/2

私が見た物理エンジン(そして確かに私が今まで聞いたすべてのゲームエンジン)では、速度のみを適用する増分運動の線形方程式のみ:

obj.POS = obj.POS + (obj.VEL * dT)

これが、StackOverflow、Wikipedia、およびWeb全体で見られる、2つの線分の交差/最も近いアプローチの検出など、一般的に公開されている衝突検出ソリューションを使用できない理由です。私のシミュレーションでは、結果の基本となる可変加速度を扱っているため、必要なのは2つの放物線セグメントの交差/最も近いアプローチです。

4

4 に答える 4

5

AShelleyが参照しているWebページでは、2つのオブジェクトが一定の速度で移動する場合に最も近いアプローチのポイントメソッドが開発されています。ただし、2つのオブジェクトが両方とも一定の非ゼロ加速度(二次時間依存性)で移動している場合は、同じベクトル計算法を使用して結果を導き出すことができると思います。

この場合、距離2次関数の時間微分は、1次ではなく3次(3次)です。したがって、最も近いアプローチの時間には3つの解決策があります。これは、両方のオブジェクトのパスが湾曲しているため、複数の交差が可能であるため、驚くことではありません。このアプリケーションでは、現在のシミュレーションステップで定義された間隔内にあるtの最も早い値を使用することをお勧めします(そのような時間が存在する場合)。

私は最も近いアプローチの時間を与えるはずの微分方程式を計算しました:

0 = |D_ACC|^2 * t^3 + 3 * dot(D_ACC, D_VEL) * t^2 + 2 * [ |D_VEL|^2 + dot(D_POS, D_ACC) ] * t + 2 * dot(D_POS, D_VEL)

どこ:

D_ACC = ob1.ACC-obj2.ACC

D_VEL = ob1.VEL-obj2.VEL(更新前)

D_POS = ob1.POS-obj2.POS(更新前も)

dot(A, B) = A.x*B.x + A.y*B.y + A.z*B.z

(大きさの2乗は|A|^2を使用して計算できることに注意してくださいdot(A, A)

これをtについて解決するには、おそらくWikipediaにあるような式を使用する必要があります。

もちろん、これはあなたに最も近いアプローチの瞬間を与えるだけです。この時点で距離をテストする必要があります(式2のようなものを使用)。より大きい場合は(obj1.Radius + obj2.Radius)無視できます(つまり、衝突はありません)。ただし、距離が短い場合は、この瞬間の前に球が衝突することを意味します。次に、反復検索を使用して、以前の時間に距離をテストできます。サイズを考慮に入れた別の(さらに複雑な)導出を考え出すことも、反復解法に頼ることなく他の分析解を見つけることも可能かもしれません。

編集:高次のため、方程式の解のいくつかは実際には最も遠い分離の瞬間です。私はすべての場合において、3つの解決策のうちの1つまたは3つの解決策のうちの2つが最も離れた時間になると信じています。時間に関して2次導関数を評価することにより、最小または最大のどちらにいるかを分析的にテストできます(1次導関数をゼロに設定して見つけたtの値で)。

D''(t) = 3 * |D_ACC|^2 * t^2 + 6 * dot(D_ACC, D_VEL) * t + 2 * [ |D_VEL|^2 + dot(D_POS, D_ACC) ]

二階導関数が正の数と評価された場合、与えられた時間tの間、距離は最大ではなく最小であることがわかります。

于 2009-12-16T19:26:07.057 に答える
2

各球の開始位置と終了位置の間に線を引きます。結果の線分が球と交差する場合、ある時点で球が確実に衝突し、衝突が発生した時刻を巧妙な数学で見つけることができます。また、セグメント間の最小距離(交差していない場合)が2*半径未満であるかどうかを確認してください。これも衝突を示します。

そこから、デルタ時間をバックステップして衝突時に正確に発生させることができるため、力を正しく計算できます。

すでにこれが機能している物理ライブラリの使用を検討しましたか?多くのライブラリは、使用している連立方程式を解くために、はるかに高度で安定した(より優れたインテグレータ)システムを使用しています。BulletPhysicsが思い浮かびます。

于 2009-12-16T17:53:42.537 に答える
2

opは衝突の時間を求めました。わずかに異なるアプローチで正確に計算されます...

位置射影方程式は次のとおりです。

NEW_POS=POS+VEL*t+(ACC*t^2)/2

、、、およびforオブジェクトを置き換えるPOSD_POS=POS_A-POS_B、次のようになります。VELD_VEL=VEL_A-VEL_BACC=ACC_A-ACC_BAB

$D_NEW_POS=D_POS+D_VEL*t+(D_ACC*t^2)/2

これは、オブジェクト間のベクトル距離の式です。それらの間のスカラー距離の2乗を取得するために、この方程式の2乗をとることができます。これは、展開後は次のようになります。

distsq(t) = D_POS^2+2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4

衝突が発生する時間を見つけるために、半径の合計の2乗に等しい方程式を設定し、次のように解くことができますt

0 = D_POS^2-(r_A+r_B)^2 + 2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4

これで、四次方程式を使用して方程式を解くことができます。

四次方程式は4つの根を生成しますが、実際の根にのみ関心があります。二重の実根がある場合、2つのオブジェクトはちょうど1つの時点でエッジに接触します。実際のルートが2つある場合、オブジェクトはルート1とルート2の間で継続的にオーバーラップします(つまり、ルート1は衝突が開始する時間であり、ルート2は衝突が停止する時間です)。4つの実根は、オブジェクトが2回衝突し、ルートペア1、2、および3,4の間で連続的に衝突することを意味します。

Rでは、私はpolyroot()次のように解決していました。

# initial positions
POS_A=matrix(c(0,0),2,1)
POS_B=matrix(c(2,0),2,1)
# initial velocities
VEL_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
VEL_B=matrix(c(-sqrt(2)/2,sqrt(2)/2),2,1)
# acceleration
ACC_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
ACC_B=matrix(c(0,0),2,1)
# radii
r_A=.25
r_B=.25
# deltas
D_POS=POS_B-POS_A
D_VEL=VEL_B-VEL_A
D_ACC=ACC_B-ACC_A


# quartic coefficients
z=c(t(D_POS)%*%D_POS-r*r, 2*t(D_POS)%*%D_VEL, t(D_VEL)%*%D_VEL+t(D_POS)%*%D_ACC, t(D_ACC)%*%D_VEL, .25*(t(D_ACC)%*%D_ACC))
# get roots
roots=polyroot(z)
# In this case there are only two real roots...
root1=as.numeric(roots[1])
root2=as.numeric(roots[2])

# trajectory over time
pos=function(p,v,a,t){
  T=t(matrix(t,length(t),2))
  return(t(matrix(p,2,length(t))+matrix(v,2,length(t))*T+.5*matrix(a,2,length(t))*T*T))
}

# plot A in red and B in blue
t=seq(0,2,by=.1) # from 0 to 2 seconds.
a1=pos(POS_A,VEL_A,ACC_A,t)
a2=pos(POS_B,VEL_B,ACC_B,t)
plot(a1,type='o',col='red')
lines(a2,type='o',col='blue')

# points of a circle with center 'p' and radius 'r'
circle=function(p,r,s=36){
  e=matrix(0,s+1,2)
  for(i in 1:s){
    e[i,1]=cos(2*pi*(1/s)*i)*r+p[1]
    e[i,2]=sin(2*pi*(1/s)*i)*r+p[2]
  }
  e[s+1,]=e[1,]
  return(e)
}

# plot circles with radius r_A and r_B at time of collision start in black
lines(circle(pos(POS_A,VEL_A,ACC_A,root1),r_A))
lines(circle(pos(POS_B,VEL_B,ACC_B,root1),r_B))
# plot circles with radius r_A and r_B at time of collision stop in gray
lines(circle(pos(POS_A,VEL_A,ACC_A,root2),r_A),col='gray')
lines(circle(pos(POS_B,VEL_B,ACC_B,root2),r_B),col='gray')

オブジェクトの軌道と衝突の開始/停止位置を示す結果のRプロット

オブジェクトAは、左下から右上に向かって赤い軌道をたどります。オブジェクトBは、右下から左上に向かって青い軌道をたどります。2つのオブジェクトは、時間0.9194381と時間1.167549の間で連続的に衝突します。2つの黒い円がちょうど接触し、オーバーラップの開始を示します。オーバーラップは、オブジェクトが灰色の円の位置に到達するまで時間とともに続きます。

于 2018-12-28T17:34:05.570 に答える
1

最接近点(CPA)が必要なようです。半径の合計よりも小さい場合は、衝突が発生しています。リンクにサンプルコードがあります。現在の速度で各フレームを計算し、CPA時間がティックサイズよりも小さいかどうかを確認できます。cpa時間をキャッシュして、いずれかのアイテムにアクセラレーションが適用された場合にのみ更新することもできます。

于 2009-12-16T17:42:47.660 に答える