AABB碰撞判断只需检查x、y、z三轴投影是否重叠,即box1.min.x ≤ box2.max.x且box1.max.x ≥ box2.min.x,同理y、z轴;三者同时成立才相交。

用分离轴定理(SAT)判断AABB碰撞最直接
两个轴对齐长方体(AABB)是否相交,本质是看它们在x、y、z三个轴上的投影是否有重叠。只要任一轴上投影不重叠,就一定没碰撞;三轴都重叠,才相交。
别写一堆几何计算——AABB没有旋转,根本不需要叉乘或面法向量。直接比坐标:
box1.min.x = box2.min.xbox1.min.y = box2.min.ybox1.min.z = box2.min.z
三个条件全为真,就碰撞。顺序不能错:必须用min和max严格对应,否则会漏判。常见错误是把box1.max.x 当“不碰撞”条件单独写,但忘了取反逻辑——直接写重叠判断更稳。
如果长方体是OBB(有旋转),必须用SAT+投影
OBB不能只看坐标轴,得检查所有可能的分离方向:每个盒子的3个面法向量,加上两两法向量的叉积(共3 + 3 + 3×3 = 15个轴)。实际中只需检查9个有效轴(3个自身轴 + 6个叉积轴,去掉零向量)。
立即学习“C++免费学习笔记(深入)”;
核心步骤是:对每个候选轴axis,把两个OBB所有8个顶点投影到该轴上,得到各自的投影区间[min1, max1]和[min2, max2],再按AABB方式判断是否重叠。
关键细节:
- 投影用点积:
proj = dot(vertex, normalize(axis)) - 必须归一化轴向量,否则投影长度失真
- 叉积轴可能为零向量(两轴平行),要跳过
- 浮点比较要用epsilon,比如
fabs(max1 - min2) 不算分离
用GLM或Eigen时,别手写投影逻辑
GLM自带glm::project但不适用——那是屏幕投影。你需要的是向量点积。直接用glm::dot即可:
float proj = glm::dot(vertex, axis_norm);
Eigen同理:vertex.dot(axis_norm)。别自己实现归一化——glm::normalize或axis.norm()更可靠。容易踩的坑是传入未归一化的轴导致投影值放大,区间判断失效;还有把顶点当vec4传入却没忽略w分量。
性能敏感场景下,先做粗筛再精判
真实游戏或物理引擎里,不会对每对OBB都跑满9轴SAT。典型做法:
- 先用包围球快速剔除:
distance(center1, center2) > radius1 + radius2 - 再用AABB包围盒(OBB的轴对齐外盒)预判:
aabb1.intersects(aabb2) - 仅当预判为真,才走完整SAT
注意:AABB预判用的是OBB的最小外接AABB,不是原坐标系下的min/max——得先把OBB顶点变换到世界坐标,再求包围盒。漏掉这步,预判会漏掉大量本该剔除的对。


















