分离轴测试基于凸体:给定两凸体集A和B,若两集合不存在交集,则必定存在一个轴使得两凸体投影无重叠。若找不到该轴,则两凸体集相交。
对于对称几何体如线段、AABB、OBB、球体等,其包含中心C且为投影轴上投影区间的中心位置,只需计算其投影区间的1/2宽度或半径,求和并于二中心投影间的距离进行比较,若和小于中心投影间距离,则物体对象处于分离。如下图:
总体上讲,多面体对象间的分离测试需要考查下列轴:
平行于物体A的面法线的轴
平行于物体B的面法线的轴
平行于物体A、B各边生成的叉积向量的轴
一旦找到分离轴,测试即可立刻退出并返回“分离”信息。若全测试完且不存在,则对象间必定相交。
对于2D物体,只需要考查两物体所有边的法向量即可。
分离轴测试的健壮性:
物体间相应边的叉积向量可以构造分离轴,但是若两向量平行,则叉积结果为0向量,此时不适合用于分离轴。普遍采用以下方案:检测叉积向量是否为(准)0向量。若是,则重新生成与两个边向量垂直的新轴,或者仅忽略该轴。
下列代码片段针对边AB和CD,给出健壮的分离轴测试的实现方式:
- //Commpute a tentative separating axis for ab and cd
- Vector m = Cross(ab,cd);
- if(!IsZeroVector(m)) {
- //Edges ab and cd not parallel, continue with m as a potential separating axis
- ...
- } else {
- //Edges ab and cd must be(near) parallel, and therefore lie in some plane P.
- //Thus, as a separating axis try an axis perpendicular to ab and lying in P
- Vector n = Cross(ab, c - a);
- m = Cross(ab, n);
- if(!IsZeroVector(m)) {
- //continue with m as a potential separating axis
- ...
- }
- //ab and ac are parallel too, so edges must be on a line. Ignore testing
- //the axis for this combination of edges as it won’t be a separating axis.
- //(Alternatively, lest if edges overlap on this line, in which case the
- //objects are overlapping.)
- ...
- }
另外,若叉积向量过大,会导致计算过程中精度损失。如果并未限定输入向量的范围,则应在叉积计算之前对向量执行范化操作以保持相应的精度。