Math 加速球之间的碰撞检测

Math 加速球之间的碰撞检测,math,3d,simulation,physics,collision-detection,Math,3d,Simulation,Physics,Collision Detection,我正在写一个物理引擎/模拟器,它包含了3D空间飞行、行星/恒星引力、飞船推力和相对论效应。到目前为止,进展很顺利,但是,我需要帮助的一件事是碰撞检测算法的数学 我使用的运动迭代模拟基本如下: # 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

我正在写一个物理引擎/模拟器,它包含了3D空间飞行、行星/恒星引力、飞船推力和相对论效应。到目前为止,进展很顺利,但是,我需要帮助的一件事是碰撞检测算法的数学

我使用的运动迭代模拟基本如下:

# 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')
(注意:三维矢量都是大写。)

其中:

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
我基本上需要做的是找到一个有效的公式,从上面的(等式2)中推导出两个物体(obj1,obj2),并告诉他们是否发生过碰撞,如果是,在什么时候。我需要准确的时间,这样我就可以确定它是否在这个特定的时间增量中(因为加速度在不同的时间增量中是不同的),也可以确定准确的位置(给定时间,我知道如何做)

对于这个引擎,我将所有对象建模为球体,这个公式/算法需要做的就是找出在哪些点:

(obj1.POS - obj2.POS).Distance = (obj1.Radius + obj2.Radius)
其中,距离是一个正的标量值。(如果这更容易,您也可以将两边都平方,以避免.Distance计算中隐含的平方根函数)

(是的,我知道许多其他碰撞检测问题,但是,他们的解决方案似乎都非常特定于他们的引擎和假设,没有一个与我的条件相匹配:3D、球体和模拟增量中应用的加速度。如果我错了,请告诉我。)


一些澄清:

1) 对于我来说,在时间增量之前和之后检查两个球体的交点是不够的。在许多情况下,它们的速度和位置变化将远远超过它们的半径

2) RE:效率,我不需要帮助(在这一点上无论如何)来确定可能的碰撞候选,我想我已经涵盖了这一点


另一个澄清,似乎有很多:

3) 我的增量运动方程式(方程式2)是一个二次方程式,同时应用了速度和加速度:

obj.POS = obj.POS + (obj.VEL * dT) + (obj.ACC * dT^2)/2
在我所看到的物理引擎中(当然还有我所听说的每一个游戏引擎),只有增量运动的线性方程只适用于速度:

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

这就是为什么我不能使用StackOverflow、Wikipedia和整个Web上常见的冲突检测解决方案的原因,例如查找两条线段的交点/最接近点。我的模拟处理的是对结果至关重要的可变加速度,因此我需要的是两个抛物线段的交点/最近点的接近度。

看起来您想要的是。如果它小于半径之和,则发生碰撞。链接中有示例代码。您可以使用当前速度计算每一帧,并检查CPA时间是否小于您的刻度大小。您甚至可以缓存cpa时间,并且仅当加速度应用于任一项时才更新。

在每个球体的开始位置和结束位置之间绘制一条线。如果生成的线段与球体相交,那么球体肯定会在某个点发生碰撞,一些聪明的数学可以找到碰撞发生的时间。还要确保检查线段之间的最小距离(如果它们不相交)是否小于2*半径。这也表示发生了碰撞

从那个里你们可以后退你们的delta时间,精确地发生在碰撞时,这样你们就可以正确地计算力


你有没有考虑过使用一个已经做这项工作的物理图书馆?许多库使用更先进、更稳定(更好的积分器)的系统来求解您正在使用的方程组。我想到了。

在AShelley提到的网页上,最近接近点方法是针对两个物体以恒定速度移动的情况开发的。然而,我相信同样的向量演算方法可以用于推导两个物体都以恒定非零加速度运动(二次时间依赖性)的情况下的结果

在这种情况下,距离平方函数的时间导数是三阶(立方)而不是一阶。因此,最近接近时间将有3种解决方案,这并不奇怪,因为两个物体的路径都是弯曲的,因此可能有多个交点。对于此应用程序,您可能希望使用t的最早值,该值在当前模拟步骤定义的间隔内(如果存在此时间)

我算出了导数方程,它应该给出最接近的时间:

0=|D|ACC^2*t^3+3*点(D|ACC,D|VEL)*t^2+2*[D|D|VEL^2+点(D|POS,D|ACC)]*t+2*点(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

(请注意,可以使用点(A,A)计算幅值的平方
|A ^^2

要解决t的问题,您可能需要使用以下公式

当然,这只会给你最接近的时刻。此时需要测试距离(使用类似于等式2的方法)。如果大于
(obj1.Radius+obj2.Radius)
,则可以忽略该值(即无碰撞)。但是,如果距离较短,则表示球体在此时刻之前碰撞。然后可以使用迭代搜索在早期测试距离。也可以提出另一个(甚至更复杂的)考虑到尺寸的推导,或者可以找到其他一些解析解,而不必诉诸迭代求解

编辑:由于阶数较高,该方程的某些解实际上是mom
# 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')