发布于2026-07-14 阅读(0)
扫一扫,手机访问
一句话说清楚:如果两个AABB都在同一个世界坐标系下,那判断起来其实很简单——逐轴比较投影区间是否重叠就行。具体来说,就是x、y、z三个轴方向,各做一次区间交集判断,总共6次操作。别被“三维”“坐标系变换”这些名词吓到,核心原理就这么直接。
很多新手容易犯的错误是:试图先把AABB的8个顶点全部变换到另一个坐标系,再重新求凸包,或者直接套用通用的OBB碰撞检测函数。这种做法不仅慢,还容易因为浮点误差导致漏判。在实际项目里,只要两个AABB已经处于同一坐标系(比如都经过从模型空间到世界空间的变换),那么调用AABB::intersects(const AABB& other)时,就应该是一个纯粹的、按轴对齐的6次区间判断逻辑。
[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相交”的捷径。所谓“不同坐标系”,本质上是各自有独立的变换矩阵(4×4矩阵)。你不能拿A的 min/max 直接去和B的对比——它们的单位、方向、原点都不同,比较毫无意义。
正确的做法只有一种:把其中一个AABB变换到另一个的坐标系下(比如把B变换到A的世界系),然后再按上一节的方法判断。这里的关键不是“怎么变”,而是“变什么”:
newMin.x = min(dot(transformedVertex[i], x_axis)),其中 x_axis 是目标坐标系的x方向基向量(通常是变换矩阵的第0列)min/max 值——可以参考 transformAABB(const glm::mat4& m, const AABB& src) 的实现逻辑因为真的没必要。GJK适用于任意凸体,OBB适用于旋转后的包围盒,但AABB是OBB的一个特例——旋转分量为零。一旦你强行套用这些算法,结果往往是得不偿失:
除非你的“AABB”其实根本没有对齐(比如美术导出时带了非零旋转),那它本质上就不是AABB,应该用OBB检测。但这种情况,数据结构的名字就该叫 OBB 而不是 AABB。
在实际编码中,最让人头疼的往往不是逻辑本身,而是浮点表示和初始化问题:
min = {1e30, 1e30, 1e30}, max = {-1e30, -1e30, -1e30},如果忘记调用 reset() 或 encapsulate(point),会导致 min.x > max.x,后续所有相交判断恒返回 falsestd::numeric_limits::max() 初始化时要注意,它是正无穷大,参与运算可能产生 nan。建议用 1e30f 这类有限大值来初始化聊两句真正的经验:真正让人头疼的,从来不是“怎么写这个判断函数”,而是“谁负责保证坐标系一致”和“谁来兜底未初始化的包围盒”。这两个问题不解决,算法写得再漂亮也是白搭。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8