前言
碰撞检测是游戏引擎中最隐秘却又最核心的基石。很多初学者以为碰撞只是简单的坐标重叠,但当物体旋转、加速或者形状变得复杂时,简单的逻辑就会崩塌。
AABB(Axis Aligned Bounding)算法
判断两个AABB,就像在坐标轴上比大小,只要最大值和最小值没有交集就一定没撞上
最大短板:拒绝旋转,若旋转会产生大量的多余碰撞区(空气墙)
圆形包围体(Bounding Circle)
两个球体可以直接计算距离(半径)就可以知道是否碰撞,不受旋转约束,这也是最大的优点和缺点。一个棍状物,使用圆形包围,就会产生大量的空气墙。
有向包围盒:OBB(Oriented Bounding Box)
可以让盒子跟着物体一起转,这也导致,OBB不能和AABB一样,简单的比较坐标了,比如:
此时明显是分离状态,但用坐标进行比较(和AABB一样)的话,就是碰撞状态。
因此,引入分离轴定理:SAT(Separating Axis Theorem)
原理类似于使用手电旋转照射并投影,只要能找到一个角度,在这个角度下两个物体的投影不重叠,就视为分离
凸多边形与凹多边形

任意两点的连线都在内部则为凸,若存在一条不完全在内即为凹
由于凹多边形处理较为复杂,一般先转化为凸进行处理:
如何使用有限次检测,来找到分离两个多边形的轴线?
沿每条边的法线方法作为轴,将各个顶点投影在这些轴上即可。
例子:一个四边形和三角形做碰撞检测,共有7条边,因此有7个法线向量作为投影轴,若其中任意一次两个图形的投影是分离的,则证明没有发生碰撞。
此时就可以说明是分离的
其实,在AABB中,利用的也是投影法,只不过投影到x、y轴上罢了
本质:降维(二维到一维)
在边较多时,效率会急速下降,那么,有没有更好的方法呢?
GJK(Gilbert Johnson Keerthi Algorithm)算法
前置知识:闵可夫斯基差 把两个多边形中所有的点进行两两相减后,得到所有C点 C = A - B = {a - b|a∈A, b ∈ B}
所有的C点构成了一个新的多边形C,有什么用?
我们知道,若产生碰撞,则必定存在点P(x, y),既存在于三角形的内部,也存在月四边形的内部,此时,用A中的点p与B中的点p相减(都是同一个点)得到的是原点(0, 0),所以得出结论:若C包括原点,则说明产生了碰撞
有什么办法可以快速确定闵可夫斯基差吗?在闵可夫斯基差空间中,构建出一个包含原点的三角形单纯形,就说明发生了碰撞