碰撞检测(基础)
🔴 球体碰撞 (Circle / Sphere)
这是最简单、计算成本最低的碰撞检测,常用于子弹、粒子、或者近似圆形的角色(如2 D游戏中的吃豆人、3 D游戏中的滚动球)。
1. 需要哪些数据?
要描述一个圆(2D)或球体(3D),只需要两个核心数据:
- 中心点 (Center):一个二维向量 (x,y) 或三维向量 (x,y,z) ,表示圆心在世界坐标系中的位置。
- 半径 (Radius):一个标量(单一数值) rr ,表示中心到边缘的距离。
2. 数学原理
判断两个圆(A和B)是否碰撞,核心逻辑极其直观:如果两个圆心的距离,小于或等于它们的半径之和,则发生碰撞。
- 计算距离:利用向量减法得到从 A 指向 B 的方向向量 \vec{D} = Center_B - Center_A 。
- 计算长度:利用勾股定理(毕达哥拉斯定理)计算该向量的模长(即两点间的直线距离):d = \sqrt{D_x^2 + D_y^2}
- 判定条件:如果 d \le r_A + r_B ,则碰撞。
💡 核心优化思维(平方比较法): 在计算机中,开平方根(\sqrt{})是非常耗时的运算**。因为等式两边都是正数,我们可以直接将两边平方,把判定条件改为: D_x^2 + D_y^2 \le (r_A + r_B)^2 这样全程只需要乘法和加法,极大地提升了性能。
3. 用到的数学知识
- 向量代数:向量的减法(求相对位置)。
- 解析几何:欧几里得距离公式(勾股定理在坐标系中的应用)。
- 不等式变换:利用单调递增函数的性质,将开方运算转化为平方运算。
🔴 轴对齐包围盒碰撞 (AABB vs AABB)
AABB (Axis-Aligned Bounding Box) 是指边永远平行于坐标轴(X/Y/Z轴)的矩形或长方体。它不能旋转,一旦物体旋转,AABB 就必须重新计算扩大。它是游戏引擎中最常用的粗略碰撞体(如墙壁、地板、静态道具)。
1. 需要哪些数据?
描述一个 AABB 通常有两种数据表示法(数学上等价):
- 极值表示法:
- 2 d 空间记录矩形在坐标系中的最小点 (minX, minY) 和 最大点 (maxX, maxY)。
- 3 D 空间记录这个长方体在三维世界中,最靠近原点的那个角(最小点),和最远离原点的那个对角(最大点)
- 最小点 P_{min}:(x_{min},y_{min},z_{min})
- 最大点 P_{max}:(x_{max},y_{max},z_{max})
- 中心 + 半尺寸表示法(引擎更常用):
- 2 d 空间记录中心点 (cx, cy) 和 半宽/半高 (hw, hh)。
- 记录长方体的几何中心,以及它在 X、Y、Z 三个方向上“厚度”的一半。
- 中心点 C:(c_{x},c_{y},c_{z})
- 半尺寸 H:(h_{x},h_{y},h_{z}) (即半宽、半高、半深)
2. 数学原理(2 D)
AABB 碰撞检测的数学本质是一维区间的重叠判定。
AABB 碰撞检测的数学本质是一维区间的重叠判定。 在二维空间中,两个矩形碰撞的充要条件是:它们在 X 轴上的投影区间重叠,并且在 Y 轴上的投影区间也重叠。只要有一个轴存在缝隙,就不碰撞。
-
如果用“极值表示法”(区间交集原理):
- X轴重叠:A.maxX \ge B.minX 且 A.minX \le B.maxX
- Y轴重叠:A.maxX \ge B.minX 且 A.minX \le B.maxX
- 两者同时满足即碰撞。
-
计算两个中心点在 X 轴上的绝对距离:|cx_A - cx_B|
-
计算两个矩形在 X 轴上的“安全半径之和”:hw_A + hw_B
-
X轴重叠条件:|cx_A - cx_B| \le hw_A + hw_B
-
Y轴同理。两者同时满足即碰撞。
3. 用到的数学知识(2 D)
- 区间数学 (Interval Arithmetic):一维线段的重叠与交集判定。
- 绝对值与不等式:利用绝对值表示无方向的距离。
- 降维思想:将复杂的二维面积重叠问题,拆解为两个独立的一维线段重叠问题(这在数学上称为正交分解)。
3D 空间实战推演(具体例子)
要判断两个 3D 长方体是否相交,最笨的办法是算体积,但这在数学上极其复杂。
这里用到的核心数学思想是:正交分解(降维)。
原理:两个 3D 长方体发生碰撞的充要条件是:它们在 X 轴、Y 轴、Z 轴上的投影(也就是 3 条一维线段)同时发生重叠
反证法:只要它们在任意一个轴(比如 Z 轴)上的投影存在缝隙(不重叠),那么这两个长方体在 3D 空间中就绝对不可能碰到对方
这就把复杂的“3D 体积相交”问题,拆解成了 3 个极其简单的“1D 线段重叠”问题
假设我们在开发一个 3D 动作游戏。
-
物体 A(玩家角色)
:我们用“中心+半尺寸”来描述。
- 中心点C_{A}=(2,3,5)
- 半尺寸 H_{A}=(1,2,1)(代表半宽1,半高2,半深1)
-
物体 B(场景里的一个木箱)
- 中心点 C_{B}=(4,4,6)
- 半尺寸 C_{B}=(1.5,1,1.5)
判定步骤:
🔴使用中心距离法
对于每一个轴,我们计算两个中心点在该轴上的绝对距离,然后与两个半尺寸之和进行比较。如果距离 ≤ 半尺寸之和,说明该轴重叠。
1. 检查 X 轴(左右方向)
- 中心点在 X 轴的距离: ∣CxA−CxB∣=∣2−4∣=2
- X 轴的“安全半径之和”: HxA+HxB=1+1.5=2.5
- 判定:因为 2≤2.5 ,所以 X 轴重叠。(玩家和箱子在左右方向上有交集)
2. 检查 Y 轴(上下方向)
- 中心点在 Y 轴的距离: ∣CyA−CyB∣=∣3−4∣=1
- Y 轴的“安全半径之和”: HyA+HyB=2+1=3
- 判定:因为 1≤3 ,所以 Y 轴重叠。(玩家和箱子在上下方向上有交集)
3. 检查 Z 轴(前后方向,通常是 3D 游戏的深度)
- 中心点在 Z 轴的距离: ∣CzA−CzB∣=∣5−6∣=1
- Z 轴的“安全半径之和”: HzA+HzB=1+1.5=2.5
- 判定:因为 1≤2.5 ,所以 Z 轴重叠。(玩家和箱子在前后方向上有交集)
最终结论:因为 X、Y、Z 三个轴同时重叠,所以玩家角色和木箱在 3D 空间中发生了碰撞!
圆如果用“极值表示法”怎么算?(区间交集法)
有些游戏引擎(如早期的物理系统)喜欢用最小/最大点来计算。它的数学本质是一维区间的交集判定。
假设我们已知:
- 物体 A 的 X 轴区间是 [1,3] (即 Cx−Hx 到 Cx+Hx )
- 物体 B 的 X 轴区间是 [2.5,5.5]
X 轴重叠的数学条件:
Amax≥Bmin 并且 Amin≤Bmax
代入数据:3≥2.5 (成立) 且 1≤5.5 (成立)。所以 X 轴重叠。
Y 轴和 Z 轴同理推算。
🔴圆形与轴对齐包围盒碰撞 (Circle vs AABB)
“圆形与轴对齐包围盒碰撞”(在 2D 中是 圆 vs 矩形,在 3D 中是 球体 vs 长方体)是游戏开发中最经典、也最能体现数学优雅之美的碰撞检测之一。
它的核心数学思想非常巧妙:它不直接计算两个复杂形状的交集,而是通过“降维转化”,把“形状 vs 形状”的问题,变成了最简单的“点 vs 形状”的问题。
下面我们以 2D(圆 vs 矩形)为主线进行深度拆解,并在最后说明如何无缝扩展到 3D。
一、 我们需要哪些数据?
为了计算方便,我们通常采用以下数据表示法:
- 圆形 (Circle):
- **圆心 **C:坐标 (c_x, c_y)。
- **半径 **r:一个标量数值。
- 轴对齐包围盒 (AABB / 矩形):
- 这里使用极值表示法最直观。
- **最小点 **P_{min}:(min_x, min_y),即矩形左下角的坐标。
- **最大点 **P_{max}:(max_x, max_y),即矩形右上角的坐标。
二、 核心数学原理:寻找“最近点”
想象一下,如果圆和矩形发生了碰撞,或者它们靠得非常近,那么矩形上必然存在一个点,它是整个矩形中距离圆心“最近”的点。
我们把这个点称为 **最近点 **P(p_x, p_y)。
核心逻辑:
只要我们找到了这个最近点 P,问题就瞬间简化了!我们只需要计算**点 P 到圆心 C 的距离 **d。
- 如果 d \le r(距离小于等于半径),说明圆碰到了矩形(或者圆心已经在矩形里面了),发生碰撞。
- 如果 d > r,说明圆还没碰到矩形,未碰撞。
那么,数学上的终极问题来了:如何不写一大堆复杂的 **if-else**,用纯数学公式直接算出这个最近点 P 呢?
三、 数学魔法:Clamp(钳制/截断)函数
这里需要引入一个极其重要的数学/计算机函数:Clamp(钳制)。
它的作用是把一个数值“限制”在某个指定的区间 [min, max] 内。
数学表达式为:
Clamp(value, min, max) = \max(min, \min(value, max))
原理解析:
- 先用 \min(value, max):如果 value 超过了上限 max,就把它拉回到 max;否则保持原样。
- 再用 \max(min, \dots):如果上一步的结果低于下限 min,就把它拉回到 min;否则保持原样。
计算最近点 P 的坐标:
我们将圆心的坐标,分别在 X 轴和 Y 轴上,向矩形的边界进行 Clamp 操作:
- p_x = Clamp(c_x, min_x, max_x)
- p_y = Clamp(c_y, min_y, max_y)
就这么简单!通过这两个公式,我们瞬间就找到了矩形上距离圆心最近的点 P。
四、 深度剖析:为什么 Clamp 能找到最近点?(Voronoi 区域划分)
你可能会疑惑,矩形周围有那么多点,为什么这两个简单的公式就能准确找到最近点?
这背后隐藏着解析几何中的 Voronoi 区域划分(泰森多边形/空间划分) 思想。
Clamp 函数在数学上隐式地将矩形周围的 2D 空间划分成了 9 个区域。我们来看看圆心 C 落在不同区域时,Clamp 是如何自动处理的:
- 区域 1:圆心在矩形“正上方”(对应矩形的上边)
- c_x 在 min_x 和 max_x 之间,所以 p_x = c_x。
- c_y 大于 max_y,所以 p_y 被 Clamp 拉回到了 max_y。
- 结果:最近点 P 刚好是圆心正下方、矩形上边缘的垂足。完全正确!
- 区域 2:圆心在矩形的“左上角”外侧
- c_x < min_x,所以 p_x 被拉回到 min_x。
- c_y > max_y,所以 p_y 被拉回到 max_y。
- 结果:最近点 P 刚好是矩形的左上角顶点。完全正确!
- 区域 3:圆心在矩形“内部”
- c_x 和 c_y 都在区间内,Clamp 不做任何改变。
- 结果:p_x = c_x, p_y = c_y。最近点 P 就是圆心 C 本身。此时距离 d = 0,因为 0 \le r,判定为碰撞。逻辑依然完美自洽!
总结:Clamp 函数利用最值运算,自动且优雅地处理了这 9 种几何情况(4个角、4条边、1个内部),完全不需要写任何条件分支语句。
五、 完整的数学判定流程
结合上面的原理,完整的数学推导步骤如下:
**步骤 1:求最近点 **P
- p_x = \max(min_x, \min(c_x, max_x))
- p_y = \max(min_y, \min(c_y, max_y))
**步骤 2:求距离向量 **\vec{D}
- 计算从最近点 P 指向圆心 C 的向量:\vec{D} = C - P
- 即:D_x = c_x - p_x, D_y = c_y - p_y
步骤 3:距离平方比较(核心优化)
- 根据勾股定理,真实距离 d = \sqrt{D_x^2 + D_y^2}。
- 判定条件是 d \le r。
- 数学优化:因为两边都是非负数,根据不等式的单调性,两边同时平方,消除耗时的开根号运算。
- 最终判定条件变为:D_x^2 + D_y^2 \le r^2
如果该不等式成立,则发生碰撞。
六、 无缝扩展到 3D 空间(球体 vs 长方体)
在 3D 游戏中(如角色球体碰撞体撞击墙壁),原理完全一模一样,仅仅是多了一个 Z 轴(深度)的维度。
3D 所需数据:
- 球体:圆心 C(c_x, c_y, c_z),半径 r。
- AABB:最小点 (min_x, min_y, min_z),最大点 (max_x, max_y, max_z)。
3D 判定步骤:
- 三维 Clamp 求最近点:
- p_x = Clamp(c_x, min_x, max_x)
- p_y = Clamp(c_y, min_y, max_y)
- p_z = Clamp(c_z, min_z, max_z)
- 求距离向量:
- D_x = c_x - p_x, \quad D_y = c_y - p_y, \quad D_z = c_z - p_z
- 三维距离平方比较:
- 判定条件:D_x^2 + D_y^2 + D_z^2 \le r^2
在 3D 空间中,Clamp 函数隐式地将空间划分成了 27 个区域(3x3x3),包括 1 个内部、6 个面、12 条边、8 个角。而数学公式依然只有寥寥几行,这就是数学降维打击的威力。
七、 总结:用到的核心数学知识
- 分段函数与最值函数 (Min/Max):构建 Clamp 函数,实现坐标的边界截断。
- 空间区域划分 (Voronoi Regions):理解算法背后的几何意义,明白为什么简单的公式能覆盖所有碰撞情况(角、边、面、内部)。
- 向量代数 (Vector Algebra):利用向量减法计算两点间的相对位置向量。
- 欧几里得距离与勾股定理 (Euclidean Distance):计算空间两点间的直线距离。
- 不等式变换 (Inequality Transformation):利用平方操作消除根号,将复杂的无理数比较转化为简单的整数/浮点数多项式比较。
🔴有向包围盒(OBB, Oriented Bounding Box)碰撞
课程1
相比于“永远横平竖直”的 AABB,有向包围盒(OBB, Oriented Bounding Box) 解除了“不能旋转”的封印。它可以随着游戏物体任意旋转、倾斜,从而更紧密地贴合物体的真实轮廓。
但也正因为 “能旋转” ,AABB 那套简单的“比较 X/Y/Z 最大最小值”的方法彻底失效了。为了检测两个任意旋转的 OBB 是否碰撞,我们需要引入碰撞检测领域最著名、也最优雅的数学定理:分离轴定理(SAT, Separating Axis Theorem)。
下面我们从 2D 到 3D,把 OBB vs OBB 的碰撞检测彻底拆解。
一、 在数学上,如何描述一个 OBB?
因为 OBB 可以旋转,我们不能再用简单的“世界坐标下的最小/最大点”来描述它了。在引擎底层,一个 OBB 通常由以下三组数据定义:
- **中心点 **C:几何中心的坐标 (c_x, c_y, c_z)。
- **半尺寸 **H:在自身局部坐标系下的半宽、半高、半深 (h_x, h_y, h_z)。
- 方向轴(局部坐标轴):描述它旋转姿态的单位向量。
- 2D 中:2 个互相垂直的单位向量 \vec{u}, \vec{v}(代表局部的 X 轴和 Y 轴)。
- 3D 中:3 个互相正交的单位向量 \vec{u}, \vec{v}, \vec{w}(通常构成一个 3 \times 3 的旋转矩阵)。
二、 核心数学灵魂:分离轴定理 (SAT)
分离轴定理(SAT) 的核心思想极其反直觉但非常有效:
“如果两个凸多边形(或多面体)没有相交,那么必然存在至少一条直线(或平面),能够将它们完全分隔在两侧。这条线/面就是‘分离轴’。”
反过来说(判定碰撞的逻辑):
如果我们检查了所有“可能”成为分离轴的候选轴,发现两个物体在每一条轴上的投影都发生了重叠,那么这两个物体必然发生了碰撞。
注:AABB 其实就是 SAT 的特例。因为 AABB 永远对齐世界坐标轴,所以它的“候选轴”永远只有固定的世界 X、Y、Z 轴。而 OBB 旋转了,所以我们需要动态去寻找这些“候选轴”。
三、 2D 空间实战:旋转矩形 vs 旋转矩形
假设我们在 2D 平面上有两个任意旋转的矩形(OBB A 和 OBB B)。
步骤 1:寻找“候选分离轴”
在 2D 中,两个凸多边形如果分离,分离线必然平行于其中某个多边形的一条边。因此,候选轴就是这两个矩形各条边的“法线(垂直线)”。
- 矩形 A 有 4 条边,提取出 2 个独立的法线轴:\vec{A_1}, \vec{A_2}(即 A 的局部 X 轴和 Y 轴)。
- 矩形 B 有 4 条边,提取出 2 个独立的法线轴:\vec{B_1}, \vec{B_2}(即 B 的局部 X 轴和 Y 轴)。
结论:在 2D 中,我们只需要检查 4 条候选轴(\vec{A_1}, \vec{A_2}, \vec{B_1}, \vec{B_2})。
步骤 2:将两个 OBB 投影到候选轴上
对于每一条候选轴(假设为单位向量 \vec{L}),我们需要把矩形 A 和矩形 B 都“拍扁”投影到这条轴上,得到两条一维线段。
数学投影计算:
一个 OBB 在某条轴 \vec{L} 上的投影,可以看作是一个中心点投影加上一个“投影半径”。
- 中心点投影:将 OBB 的中心点 C 点乘候选轴 \vec{L},得到投影中心 p = C \cdot \vec{L}。
- **投影半径 **r:OBB 在轴 \vec{L} 上占据的“半宽”。利用 OBB 的局部轴和半尺寸计算:
r = h_x |\vec{u} \cdot \vec{L}| + h_y |\vec{v} \cdot \vec{L}|
(这里的点乘取绝对值,是因为我们要计算的是最大延伸距离)
步骤 3:检查一维线段是否重叠
现在我们有了 A 的投影区间 [p_A - r_A, p_A + r_A] 和 B 的投影区间 [p_B - r_B, p_B + r_B]。
它们重叠的数学条件非常简单:
两个投影中心的距离 \le 两个投影半径之和
即:|p_A - p_B| \le r_A + r_B
最终判定:
依次检查这 4 条轴。
- 如果在任意一条轴上,|p_A - p_B| > r_A + r_B(找到了分离轴),立刻停止计算,未碰撞。
- 如果 4 条轴全部重叠,发生碰撞。
四、 升维打击:3D 空间中的 OBB vs OBB
到了 3D 空间,情况变得复杂得多。两个 3D 长方体(OBB)如果分离,分离面可能平行于 A 的面、平行于 B 的面,还可能平行于 A 的一条边和 B 的一条边所构成的平面(边-边分离)。
因此,3D 中的“候选分离轴”数量暴增到了 15 条!
1. 寻找 15 条候选轴
假设 OBB A 的局部轴为 \vec{A_x}, \vec{A_y}, \vec{A_z},OBB B 的局部轴为 \vec{B_x}, \vec{B_y}, \vec{B_z}。
- A 的 3 个面法线:\vec{A_x}, \vec{A_y}, \vec{A_z} (3条)
- B 的 3 个面法线:\vec{B_x}, \vec{B_y}, \vec{B_z} (3条)
- A 的边与 B 的边的叉乘(边-边轴):\vec{A_i} \times \vec{B_j} (3 \times 3 = 9 条)
总计:3 + 3 + 9 = 15 条候选轴。
(注:叉乘 \times 的几何意义是求出一个同时垂直于两个向量的法向量,正好代表了“边-边”构成的分离平面的法线。)
2. 投影与重叠检测(3D 版)
对于这 15 条轴中的每一条(设为 \vec{L}),计算逻辑与 2D 完全一致:
- 计算投影中心距离:D = |(C_B - C_A) \cdot \vec{L}|
- 计算 A 的投影半径:r_A = h_{Ax}|\vec{A_x}\cdot\vec{L}| + h_{Ay}|\vec{A_y}\cdot\vec{L}| + h_{Az}|\vec{A_z}\cdot\vec{L}|
- 计算 B 的投影半径:r_B = h_{Bx}|\vec{B_x}\cdot\vec{L}| + h_{By}|\vec{B_y}\cdot\vec{L}| + h_{Bz}|\vec{B_z}\cdot\vec{L}|
- 判断:如果 D > r_A + r_B,则分离,未碰撞。
如果 15 条轴全部检测完都没有分离,则发生碰撞。
五、 引擎底层的极限优化:相对投影法
如果直接按上面的公式算 15 条轴,需要做大量的向量点乘和叉乘,性能开销很大。现代物理引擎(如 Box2D, PhysX)会使用相对坐标系进行极限优化。
核心思想:把 OBB B 转换到 OBB A 的局部坐标系中。
- 计算相对位置向量 \vec{T} = C_B - C_A。
- 计算 B 的局部轴在 A 的局部坐标系下的表示(通过矩阵乘法或点乘),得到一个 3 \times 3 的**旋转相对矩阵 **R。
R_{ij} = \vec{A_i} \cdot \vec{B_j} - 利用矩阵 R 和相对位置 \vec{T},可以将 15 次投影计算转化为简单的查表和代数加减法,彻底消除运行时的三角函数和复杂的向量运算。
六、 总结:OBB 碰撞背后的数学知识库
OBB vs OBB 是游戏物理引擎中最基础也最硬核的算法之一,它几乎调动了线性代数的所有核心工具:
- 分离轴定理 (SAT):将复杂的 3D 体积相交问题,转化为多个 1D 线段重叠问题的核心指导思想。
- 向量点乘 (Dot Product):用于计算向量在某个轴上的“投影长度”(a \cdot b = |a||b|\cos\theta)。
- 向量叉乘 (Cross Product):用于在 3D 空间中寻找“边-边”分离轴(求两个方向向量的公垂线)。
- 矩阵与基变换 (Matrix & Change of Basis):通过构建相对旋转矩阵,将一个物体的坐标转换到另一个物体的局部空间,从而实现计算降维和性能优化。
- 绝对值与不等式:用于处理投影时的方向无关性,以及最终的 1D 区间重叠判定。
一句话总结:
AABB 碰撞是“比大小”,Circle vs AABB 是“找最近点”,而 OBB 碰撞则是“在 15 个特定方向上玩 1D 投影重叠游戏”。
课程2
OBB(Oriented Bounding Box,有向包围盒)碰撞,本质上是在解决:
“两个任意旋转的矩形/盒子是否相交”。
它比 AABB(轴对齐包围盒)难很多,因为:
- AABB 永远和世界坐标轴平行
- OBB 可以任意旋转
所以:
不能再用简单的 x/y/z 区间重叠判断
而 OBB 的核心数学原理,其实只有一个:
分离轴定理(SAT)
一、SAT 的真正思想
SAT(Separating Axis Theorem)说:
如果两个凸物体没有碰撞,那么一定存在一条轴,使它们在这条轴上的投影不重叠。
反过来:
如果所有可能轴上的投影都重叠,那么它们一定碰撞。
这是 OBB 的整个数学基础。
注意关键词:
“投影”
因为:
碰撞问题被转化成了“一维区间重叠问题”
这就是 SAT 最厉害的地方。
二、为什么“投影”能判断碰撞?
先想二维。
假设两个旋转矩形:
A
B
很难直接判断。
但如果你拿一条轴,例如:
→
然后把两个矩形都“压扁”到这条线上。
你会得到:
线段区间
例如:
A: [2,5]
B: [6,8]
如果区间不重叠:
说明一定没碰撞
因为:
存在“空隙”
这条轴就叫:
分离轴
三、为什么只检查特定轴?
这是 SAT 最关键的数学结论。
二维 OBB 只需要检查:
- A 的两个边法线
- B 的两个边法线
总共:
4 条轴
因为:
如果两个凸多边形存在分离轴,那么它一定垂直于某条边。
这是凸几何的重要定理。
四、OBB 的数据结构
二维 OBB 一般包含:
center
halfExtents
rotation
也可以写成:
center
axisX
axisY
halfWidth
halfHeight
其中:
center:中心点axisX:盒子右方向axisY:盒子上方向
注意:
axisX / axisY 必须是单位向量
因为它们本质是:
局部坐标轴
五、投影真正怎么计算?
现在来到核心。
假设有一条检测轴:
L
单位向量。
我们要计算:
OBB 在 L 上的投影范围
六、为什么点积能做投影?
因为点积:
a\cdot b=|a||b|\cos\theta
本质就是:
一个向量在另一个方向上的投影长度。
所以:
点积 = 投影
七、OBB 投影半径公式
这是 SAT 最核心公式之一。
二维 OBB 在轴 L 上的投影半径:
r=e_x|L\cdot A_x|+e_y|L\cdot A_y|
这里:
e_x:半宽e_y:半高A_x:OBB 的 x 轴A_y:OBB 的 y 轴
八、这个公式为什么成立?
这是真正数学本质。
OBB 可以看成:
两个轴方向的组合
即:
横向贡献 + 纵向贡献
现在:
我们想知道:
这个盒子在 L 上能延伸多远
于是:
- 横轴在 L 上的投影长度
- 纵轴在 L 上的投影长度
加起来。
横向贡献:
e_x|L\cdot A_x|
纵向贡献:
e_y|L\cdot A_y|
相加后:
r=e_x|L\cdot A_x|+e_y|L\cdot A_y|
这就是投影半径。
九、真正碰撞判断
现在:
两个 OBB:
A
B
中心差:
T=C_B-C_A
投影到轴 L:
d=|T\cdot L|
得到:
两个中心在轴上的距离
然后:
如果:
d>r_A+r_B
说明:
出现分离
即:
没有碰撞
否则继续检查下一条轴。
十、二维 OBB 为什么只检查 4 条轴?
因为矩形边只有两种方向:
- x轴方向
- y轴方向
法线也只有两种。
两个矩形:
2 + 2 = 4
十一、三维 OBB 更复杂
3D OBB vs OBB 需要检查:
- A 的 3 个轴
- B 的 3 个轴
- 两两叉积生成的 9 个轴
总共:
15 条轴
即:
3 + 3 + 9
十二、为什么还要检查叉积轴?
因为在三维里:
边与边之间可能形成新的分离方向
二维不存在这个问题。
十三、OBB 为什么比 AABB 贵?
AABB:
只比较 min/max
OBB:
大量 dot
因为 SAT 本质上是:
不停做向量投影
十四、为什么游戏引擎很少直接大量用 OBB?
因为:
太贵
通常:
- Broad Phase:AABB
- Narrow Phase:OBB / SAT / GJK
先粗筛。
十五、你现在真正应该理解的核心
OBB vs OBB 本质不是:
“盒子碰撞”
而是:
“凸体在不同轴上的投影是否分离”
整个算法核心只有三件事:
1. 选轴
SAT。
2. 点积投影
因为:
dot = 投影长度
3. 区间重叠
如果:
所有轴都重叠
则碰撞。
这就是 OBB 的真正数学原理。
评论区