aabb相交判断只需检查x、y、z三轴投影是否均重叠,即对每轴验证!(max1
直接用分离轴定理判断,只需检查三个坐标轴方向
两个 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 再判断,别在条件里反复算。
- 错误写法:
if (abs(c1.x - c2.x) —— 看似简洁,但当 halfSize 实际是 full size 时立刻失效- 正确写法:
return !(b1.max.x- 可提取为内联函数,避免重复逻辑,也方便加 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 轴比较,或者把
写成 <code> 导致边界接触不算相交——而多数物理引擎要求“接触即相交”。这个细节,得看你的业务定义。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!












