商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C++如何判断两个三维坐标系下的AABB包围盒是否发生几何空间相交碰撞

C++如何判断两个三维坐标系下的AABB包围盒是否发生几何空间相交碰撞

  发布于2026-07-14 阅读(0)

扫一扫,手机访问

一句话说清楚:如果两个AABB都在同一个世界坐标系下,那判断起来其实很简单——逐轴比较投影区间是否重叠就行。具体来说,就是x、y、z三个轴方向,各做一次区间交集判断,总共6次操作。别被“三维”“坐标系变换”这些名词吓到,核心原理就这么直接。

很多新手容易犯的错误是:试图先把AABB的8个顶点全部变换到另一个坐标系,再重新求凸包,或者直接套用通用的OBB碰撞检测函数。这种做法不仅慢,还容易因为浮点误差导致漏判。在实际项目里,只要两个AABB已经处于同一坐标系(比如都经过从模型空间到世界空间的变换),那么调用AABB::intersects(const AABB& other)时,就应该是一个纯粹的、按轴对齐的6次区间判断逻辑。

  • 假设A的包围盒范围是 [minA.x, maxA.x][minA.y, maxA.y][minA.z, maxA.z],B同理
  • 相交的条件是:minA.x <= maxB.x && maxA.x >= minB.x && minA.y <= maxB.y && maxA.y >= minB.y && minA.z <= maxB.z && maxA.z >= minB.z
  • 注意边界处理:用 <=>= 而不是 <>,否则像 maxA.x == minB.x 这种刚好贴边的情况会被误判为不相交

当两个AABB处于不同局部坐标系时,必须先统一到同一坐标系再判断

没有“跨坐标系直接判断AABB相交”的捷径。所谓“不同坐标系”,本质上是各自有独立的变换矩阵(4×4矩阵)。你不能拿A的 min/max 直接去和B的对比——它们的单位、方向、原点都不同,比较毫无意义。

正确的做法只有一种:把其中一个AABB变换到另一个的坐标系下(比如把B变换到A的世界系),然后再按上一节的方法判断。这里的关键不是“怎么变”,而是“变什么”:

  • 不要只变换8个顶点再重新计算AABB——这会放大误差,而且变换后的AABB可能已经不再是轴对齐的了(实际上变成了OBB)
  • 应该使用AABB-to-AABB的保守变换方法:对每个轴,分别计算变换后8个顶点在该轴上的投影极值,即 newMin.x = min(dot(transformedVertex[i], x_axis)),其中 x_axis 是目标坐标系的x方向基向量(通常是变换矩阵的第0列)
  • 更高效的做法是:利用变换矩阵的旋转部分(3×3子矩阵)和位移,直接推导出新AABB的 min/max 值——可以参考 transformAABB(const glm::mat4& m, const AABB& src) 的实现逻辑

为什么不用GJK或通用OBB碰撞检测

因为真的没必要。GJK适用于任意凸体,OBB适用于旋转后的包围盒,但AABB是OBB的一个特例——旋转分量为零。一旦你强行套用这些算法,结果往往是得不偿失:

  • 性能开销大:GJK需要迭代收敛,OBB需要计算15条分离轴(3+3+3×3),而AABB只需要6次标量比较,差距巨大
  • 数值不稳定:GJK在面共面、边共线的情况下容易震荡;OBB的轴叉积计算会引入额外的浮点误差
  • 接口复杂:需要传顶点数组、法向量、支持函数,而AABB本质上只有6个float值,完全是杀鸡用牛刀

除非你的“AABB”其实根本没有对齐(比如美术导出时带了非零旋转),那它本质上就不是AABB,应该用OBB检测。但这种情况,数据结构的名字就该叫 OBB 而不是 AABB

容易被忽略的浮点陷阱和边界情况

在实际编码中,最让人头疼的往往不是逻辑本身,而是浮点表示和初始化问题:

  • 未初始化的AABB是最常见的坑。比如 min = {1e30, 1e30, 1e30}, max = {-1e30, -1e30, -1e30},如果忘记调用 reset()encapsulate(point),会导致 min.x > max.x,后续所有相交判断恒返回 false
  • std::numeric_limits::max() 初始化时要注意,它是正无穷大,参与运算可能产生 nan。建议用 1e30f 这类有限大值来初始化
  • 当物体缩放为负值(比如镜像)时,变换后的AABB仍然可以用上述方法处理,但必须确保从变换矩阵中提取的旋转部分已经归一化——否则基向量长度不为1,投影会失真

聊两句真正的经验:真正让人头疼的,从来不是“怎么写这个判断函数”,而是“谁负责保证坐标系一致”和“谁来兜底未初始化的包围盒”。这两个问题不解决,算法写得再漂亮也是白搭。

本文转载于:https://www.php.cn/faq/2819784.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注