胶囊和凸多边形的动态碰撞检测
在使用广义碰撞阶段迅速排除了大量物体以后,将会使用精确到多边形级别的精确碰撞,比如两个凸包之间的碰撞,凸包和面片之间的碰撞,以及2次曲面和多边形面片的碰撞,在游戏中常用的两次曲面有,椭圆体,圆柱体,胶囊,球体等等。对于两个凸包之间的碰撞算法目前比较流行的是SAT,分离轴测试算法可以静态和动态的计算出两个凸包之间的碰撞时间法向量等等。但是对于面数较多的凸包以及2次曲面却不大适合,此时一般使用GJK算法但是GJK算法本身强壮性的实现问题一直是一个较难的问题。在我的一项使用BSP进行碰撞检测的实验中,人物以胶囊来模拟,房屋内部通过非SOLID 的LEAFY BSP来构造,在使用BSP剔除了大量面片以后,遇到这样一个问题:如何在最后筛选下的三角形面片进行碰撞测试,以确定碰撞发生的时间,法向量等。
本文提出一种简单,易懂,准确的方法用来确定一个以速度v前进的胶囊和一个凸多边形第一次发生碰撞的时间。
首先 一个胶囊是所有到某根线段的距离等于某个值r的点的集合:
如图:虚线表示该线段这里以ab表示,r代表所有点到该线段的长度:
首先观察静态情况下的碰撞情况。当一个多边形面片和胶囊碰撞的时候,实际上是该多边形面片中存在一些点,这些点到线段ab的距离小于了r,这是因为在胶囊外部的点到线段ab的距离均大于r(胶囊是所有到某根线段的距离等于某个输r的点的集合)。所以在两个物体都静止的情况下相交测试实际上是测试线段ab到多边形的最短距离,如果该距离 如图这里以一个三角形为例子,左图中该三角形的所有点到线段ab的距离均大于r所以和该胶囊不相交,而右图中三角形的黑色区域中的点到线段ab的距离小于r所以该三角形和胶囊相交。 所以实际上只要计算一条线段到某个多边形的距离,然后和r作比较就可以知道是否发生碰撞。而一条线段和一个多边形的距离计算,需要分以下几个步骤(以三角形为例) A将线段ab的2个端点投影到三角形所在平面,并检查投影点是否落在三角形内部,如果是的话将该投影距离作为一个候选值 B分别计算线段ab和三角形的三条边的最短距离点对,并检查该点对中的点是否落在线段中(ab线段和三角形的边线段中)如果是的话将该点对的距离作为一个候选值。 C分别计算线段ab的两个端点到三角形每条边的投影(实际上是计算最近点对),并检查该投影是否落在边的线段中如果是的话作为一个候选值保存。 D分别计算三角形的3个顶点到线段ab上的投影,并检查该投影是否落在线段ab中。如果是的话作为一个候选值保存。 E 分别计算三角形的3个顶点到线段ab的两个顶点,把距离作为候选值保存。 这样一来碰撞检测就归结为,点和线段,线段和线段,以及点和面的最短点对的计算了, 最后将上述的候选值进行比较,结果最小的那个就是三角形中到线段ab的距离。 上述方法非常容易推广到动态的情况也就是:当胶囊以速度v运动时第一次和三角形发生碰撞的时间。问题归结为 在哪个时间T线段ab到三角形的距离等于半径r,而这又归结为上述A,B,C,D,E 5个子问题。如果能够分别求出这5个子问题的时间,t1,t2,t3,t4,t5那么取这5个时间中的最小值就是胶囊和三角形发生碰撞的确切时间了。 下面以两条直线,一条静止,另外一条以速度v移动作为例子,来说明求得时间的过程。问题等同于: 给定一条静止,另外一条以速度v移动的直线,求出在哪个时间T这两条直线的距离等于半径r。 对于两条直线,假设直线的方程分别为: L1:P1+r1*t; L2:P2+r2*t; 现在架设直线L2以速度v={vx,vy,vz}移动; 根据两条直线的距离公式 d=|P1P2 .(r1Xr2)| /|(r1Xr2)| 其中P1P2是向量代表 P2-P1,X代表叉积,.代表点积 由于r1,r2是常量不会随着直线的移动而改变,这里令(r1Xr2)=r ={x*,y*,z*} P1={x1,y1,z1}不变,P2={x2+vx*t, y2+vy*t, z2+vz*t}其中t代表时间是个变量 带入公式d=|P1P2 .(r1Xr2)| /|(r1Xr2)|可得 d(t)=x*(x2-x1)+y*(y2-y1)+z*(z2-z1)+(x*vx+y*vy+z*vz)t 令(x*vx+y*vy+z*vz)=a; x*(x2-x1)+y*(y2-y1)+z*(z2-z1)=b; 那么d(t) = at+b —————————–(1) 公式1就是两条直线之间的距离随着时间t变化的函数,这是一个带符号的距离,两边平方可得 d^2(t)= (at+b)^2 这是一个两次方程,假设胶囊半径为r 那么只要求解方程(at+b)^2=r^2这个方程就可以求出子问题B的时间了,同时注意计算出时间t之后还需要计算出该时间两条直线的线最近点对是否都处在两条对应的线段上,如果是的话才是一个合理的时间否则就抛弃该时间。 通过同样的推导可以分别求出其他子问题的时间取这些时间,取这些时间的最小值就是碰撞第一次发生的时间,当然在求解2次方程过程中要考虑到delta<或者=0的情况这些情况都有自己的物理意义,以上面两条线段距离为例d^2(t)= (at+b)^2中如果a=0
那么方程恒等于b^2,考察a=0的物理意义,a=0也就是(x*vx+y*vy+z*vz)=0;其中x*,y*,z*是这两条直线所组成的面的法向量
这表面移动速度平行于这两条直线所组成的面。显然距离是恒定不变的。
结论:
以上方法很容易推广到凸多边形,以及求出碰撞的法向量(根据最短时间是由上述A,BCDE中那种情况所引起的)。
在一般网游的室内环境检测中,使用胶囊模拟人物已经足够了,结合BSP的漂亮剪枝能力,可以做出比较满意和快速的碰撞检测,人物和其他物件的碰撞可以采用凸包比较或者GJK方法等。
Categories: Garfield's Diary