从0开始制作游戏物理引擎(四)

这一章描述了判交和MTD算法,包括SAT等。

SAT算法

分离轴定律(Separate Axis Theory)是常见的判断两个凸多面体是否相交,同时可以求出最小挤出向量(MTD, Minimal Translation Direction)的算法。和GJK作为两大求解MTD算法。

分离轴定律基于一个事实:用一束平行光照射两个凸体,如果存在一个光的朝向,使他们在墙上(墙垂直于光)的投影不相交,那么这两个物体就不相交。

那么这个墙就叫做测试轴或者投影轴。本质上是在选定墙之后,将两个凸体投影到墙体上看投影是否相交。

在程序实现中不可能找“任意的”墙。对于凸体,需要:

  • 将每个面的法线当做墙进行投影
  • 将两个凸体中的每两对边的叉乘结果作为墙进行投影

如果存在任意投影不相交,那么这两个物体就不相交。

否则相交,并且投影之间的重叠距离就是最小挤出距离。投影轴的方向就是挤出方向。

对于两个OBB来说,一共需要对这些轴进行测试:

  • 第一个OBB的三个轴
  • 第二个OBB的三个轴
  • 每两对边(3x3 = 9)个轴(去掉朝向一样/相反的轴)

所以一共是15次测试。

这里有个问题:为什么要对边的叉乘结果也进行测试?参考3说的很清楚。简单来说就是存在某些情况,面法线全部判定为相交,但其实两个物体不相交的情况。

Support点

支撑点是指:给定某一个方向,找到这个方向上几何体中最远的点。

在概念上,经常用支撑点来描述SAT算法:给出一个投影轴,在这个轴的正方向和负方向上找到物体的支撑点。然后算两个物体各自支撑点所包含的区域是否相交。

但实际情况下不会真的调用两次计算支撑点的算法。因为Convex的支撑点算法是遍历所有顶点,将点投影在轴上,找到投影距离最大的那个点作为支撑点。

如果你要算正向和反向的支撑点,中间会有很多重复的投影。

SAT的应用场合

虽然SAT的概念很好理解,实现起来也很简单。但遗憾的是,在3D中几乎不会使用SAT。

SAT最耗时的地方是往不同的轴上投影。轴越多投影越多。在2D场景下,边的法线十分容易计算,而且也只需要边法线作为轴,不需要两个物体的一对边的叉乘作为轴。这个时候SAT的速度还是很快的。像Box2D中所有的几何几乎都采用SAT算法。

但在3D中情况有变:

  1. 计算凸体需要面法线,那你必须将面法线提前记录下来,因为得知道哪些顶点构成面。或者你使用凸体的拓扑形式,这样可以知道所有面然后根据边算面法线。但就算这样,要计算的面法线也越来越多
  2. 随着凸体边数增多,要计算两边叉乘产生的轴也越来越多(理论上是$V_{num1} * V_{num2}$是一个平方数量级),这导致投影操作大大增加

所以基本上除了OBB和OBB的判交可以用SAT(此时SAT和GJK+EPA的差别不大,但是更好写),所有的凸体算法中SAT都要比GJK+EPA慢。很多物理引擎中(比如PhysX,Bullet)都是AABB之间和OBB之间的MTD算法使用SAT。其他都使用GJK+EPA

OBB和OBB的SAT特化算法

由于OBB“方方正正”的特性(邻边互相垂直,对边互相平行),可以不对OBB的每个顶点进行投影。而是对轴进行投影。通过将每个轴投影,找到正向/反向最远的值作为支撑点在此轴上的坐标即可。这样大大简化了需要投影的点的个数(投影轴是15个,投影点本来是(8 + 8) * 15。现在是(3 + 3) * 15)。

凸体和球体的SAT

球体没有边。所以投影轴有两种:

  1. 凸体的面法线
  2. 球体到凸体顶点的连线

但不会有人在球和凸体上用SAT的。还是投影轴太多。

工程中使用的凸体和球体的判交/MTD算法

对于判交,工程中一把直接化成最近点算法:找到球体和凸体的最近点,然后看最近点是否在球体内。

$$ \begin{aligned} & \vec{d} = \vec{C_{circle}} - \vec{NearestPt} \\ & \vec{MTD} = (||\vec{d}|| - r)\frac{\vec{d}}{||\vec{d}||} \end{aligned} $$

如果在内部。那就得使用点到面距离来判断离四个面谁最近。这个时候挤出方向就是面法线,大小就是球心到面的距离+半径。

注意:只需要判断球心到面的距离,不需要判断球心到边的距离。因为总可以对面作垂线构造直角三角形,来证明到面的距离总是短于到边的距离:

到边的距离总是比到面的距离长

判断球体到四面体也是一样的方法。但这个时候就要判断到边的距离了(因为四面体不那么“方正”)

其他MTD求解方法

全部使用GJK。等到GJK的章节再说。

参考

  1. 实时碰撞检测算法技术 (豆瓣)
  2. 公式大全:Geometric Tools: About Geometric Tools for Computer Graphics
  3. separating axis theorem - How many and which axes to use for 3D OBB collision with SAT - Game Development Stack Exchange
updatedupdated2026-07-192026-07-19