AABB相交判断只需检查x、y、z三轴投影是否均重叠,即对每轴验证!(max1 < min2 || max2 < min1),逻辑为全不分离才相交;须用min/max字段、避免center/size混用,注意浮点epsilon比较、边界包含性及世界坐标一致性。

直接用分离轴定理判断,只需检查三个坐标轴方向
两个 AABB 相交当且仅当它们在 x、y、z 三个轴上投影都重叠。这是 AABB 的核心性质,不需要做任何叉乘或法向量计算——AABB 的面天然对齐坐标轴,分离轴只有这三个。
常见错误是写成“只要有一个轴不重叠就相交”,逻辑反了;或者误用点到盒距离函数(比如 glm::distance)去判断,既慢又不准。
- 对每个轴(如 x),比较:box1 的
min.x是否 大于等于 box2 的max.x,或 box2 的min.x是否 大于等于 box1 的max.x;若任一成立,则该轴分离,整体不相交 - 只要 x、y、z 三者都未分离,就相交
- 注意浮点比较:若需鲁棒性,建议用 epsilon(如
1e-6f)做宽松比较,避免因计算误差导致本应相交的盒子被误判为分离
手写判断函数时,结构体字段命名要明确 min/max
很多 bug 来自字段语义模糊,比如用 center 和 size 表示 AABB,但没统一“size 是全尺寸还是半尺寸”。一旦混用,min = center - size 就可能错写成 min = center - size * 0.5f。
推荐统一用 min 和 max 成员(glm::vec3 min, max),直观且不易出错。若已有 center+halfSize 表示,先转成 min/max 再判断,别在条件里反复算。
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
if (abs(c1.x - c2.x) < h1.x + h2.x)—— 看似简洁,但当 halfSize 实际是 full size 时立刻失效 - 正确写法:
return !(b1.max.x < b2.min.x || b2.max.x < b1.min.x || b1.max.y < b2.min.y || b2.max.y < b1.min.y || b1.max.z < b2.min.z || b2.max.z < b1.min.z); - 可提取为内联函数,避免重复逻辑,也方便加 assert 或日志
使用 glm 库时别误调 glm::intersect —— 它不支持 AABB
glm::intersect 系列函数(如 glm::intersectRayAABB)只处理射线与 AABB,没有提供两个 AABB 之间的相交判断。试图传两个 glm::aabb 会编译失败,因为 glm 并未定义 glm::aabb 类型(它是 OpenGL 扩展里的,glm 不内置)。
常见误区是查文档看到 “glm intersect” 就以为有现成接口,结果卡在类型不匹配或找不到符号。
- glm 中标准做法仍是手写六次比较,或封装为
inline bool intersects(const glm::vec3& a_min, const glm::vec3& a_max, const glm::vec3& b_min, const glm::vec3& b_max) - 若项目已用
btAABB(Bullet Physics),可用其hasCollision方法,但注意它内部也是同样六次比较,无额外优化 - 不要为了“省几行代码”引入新依赖(如 nanoflann 的 AABB 工具),除非你同时需要 KD-tree 构建
嵌入物理或渲染管线时,注意 early-out 和内存布局
在每帧要检测上千对 AABB 的场景(如碰撞粗筛、视锥裁剪),性能关键点不在算法本身,而在访存和分支预测。连续判断多个 AABB 对时,若数据不是 AOS(Array of Structures)而是 SOA(Structure of Arrays),比如所有 min.x 存一起、所有 max.x 存一起,就能利用 SIMD 加速。
但多数情况用不到 SIMD,真正有效的是确保判断函数足够短小、无函数调用开销,并让编译器能内联。另一个易忽略点是:如果 AABB 数据来自变换后的模型(如动态物体),必须保证 min/max 值已按世界坐标更新完毕——否则拿局部坐标盒去和世界坐标盒比,必然错。
- 每次移动物体后,必须重新计算其 world-space AABB,不能复用 local-space 的
min/max - 判断前加一句
assert(!std::isnan(b1.min.x))能快速暴露变换矩阵异常(如含 NaN 的 scale)导致的误判 - 调试时可临时返回分离轴编号(0=x, 1=y, 2=z),方便定位哪一维总不重叠
实际写的时候,最常漏掉的是 z 轴比较,或者把 < 写成 <= 导致边界接触不算相交——而多数物理引擎要求“接触即相交”。这个细节,得看你的业务定义。


















