OBB能精准贴合旋转物体,而AABB因轴对齐导致包围盒急剧膨胀,引发漏判或误判;OBB碰撞检测依赖分离轴定理(SAT),需测试15个候选轴(3+3+9),任一轴投影不重叠即分离,全部重叠才相交。

为什么直接用 AABB 判定会漏掉旋转物体的碰撞
当模型绕任意轴旋转后,其轴对齐包围盒(AABB)会急剧膨胀,导致大量误判——看似没撞,实际已穿透;或者看似快撞了,但 AABB 早早就报警。OBB 的核心价值是紧贴物体姿态,而 SAT 是目前最实用、可验证、能同时支持相交/分离/穿透深度计算的通用判定方法。
关键前提是:两个凸体若不相交,则必存在一个分离轴,使得它们在该轴上的投影不重叠。OBB 是凸的,所以 SAT 适用。
OBB 的表示方式直接影响 SAT 实现复杂度
别用 8 个顶点存 OBB——每次投影都要算 8 次点积,且无法快速获取边方向和中心。推荐结构体包含:
-
center:世界坐标系下的中心点vec3 -
axes[3]:三个单位正交轴(即局部 x/y/z 在世界空间的朝向),顺序必须与半长extents对应 -
extents[3]:沿各轴的半长(标量,非向量)
这样,任意轴 n 上的投影半宽可直接算:abs(dot(axes[0], n)) * extents[0] + abs(dot(axes[1], n)) * extents[1] + abs(dot(axes[2], n)) * extents[2] —— 这就是 OBB 在 n 上的“投影半径”。
哪些轴必须测试?一共只有 15 个,不是无限多
两个 OBB(A 和 B)共需测试 3 + 3 + 3×3 = 15 个潜在分离轴:
- A 的 3 个本地轴(转到世界空间后)
- B 的 3 个本地轴(同上)
- A 的每个轴 × B 的每个轴 → 共 9 个叉积轴(
cross(axesA[i], axesB[j])),注意跳过接近零向量的情况(用length() 判)
只要其中任一轴上两 OBB 投影不重叠(即中心距 > 半径和),就立即返回 false;全部 15 个都重叠,才判定为相交。顺序建议先测自身轴(开销小),再测叉积轴(开销大且可能归零)。
数值不稳定时 SAT 容易误判,必须加容差和提前退出
浮点误差会让本该重叠的投影看起来有微小间隙,或让本该分离的投影看起来重叠。不要用 == 0 判断叉积是否为零,也不要直接比 distance > radiusSum。
- 所有比较用容差,例如:
if (overlap (overlap = radiusSum - abs(centerDistance)) - 对叉积轴做归一化前先检查长度,避免除零或 NaN 传播
- 一旦发现分离轴立刻返回,别硬跑完 15 个——多数情况在前 3~5 个轴就出结果
- 如果需要穿透深度,得记录最小正值
overlap对应的轴,但注意:最小 overlap 不一定对应最小平移向量,真要 MTV 需额外处理
真正麻烦的从来不是公式推导,而是 axes 是否正交归一、extents 符号是否一致、容差设在哪一级、以及叉积轴重复或退化时怎么跳过——这些细节错一个,SAT 就变成“偶尔工作”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











