【C++游戏引擎开发】第31篇:物理引擎(Bullet)—碰撞检测系统
一、碰撞检测数学基础
1.1 空间分割理论
空间划分类型:
- 均匀网格:将空间划分为等体积单元,适合均匀分布场景
- 八叉树:递归细分空间至指定深度,复杂度 O ( log n ) O(\log n) O(logn)
- BSP树:通过超平面分割空间,适合静态场景
AABB(轴向包围盒):
数学定义:
AABB = [ min x , max x ] × [ min y , max y ] × [ min z , max z ] \text{AABB} = [\min x, \max x] \times [\min y, \max y] \times [\min z, \max z] AABB=[minx,maxx]×[miny,maxy]×[minz,maxz]
快速相交测试:
intersect ( A , B ) = ( max x A > min x B ) ∧ ( min x A < max x B ) ∧ . . . \text{intersect}(A,B) = (\max_x^A > \min_x^B) \land (\min_x^A < \max_x^B) \land ... intersect(A,B)=(xmaxA>xminB)∧(xminA<xmaxB)∧...
1.2 几何相交算法
1.2.1 GJK算法
核心思想:通过迭代计算闵可夫斯基差集的最近点
算法步骤:
- 初始化方向向量 d ⃗ \vec{d} d
- 计算支持点:
S A − B ( d ⃗ ) = argmax p ∈ A p ⃗ ⋅ d ⃗ − argmax q ∈ B q ⃗ ⋅ d ⃗ S_{A-B}(\vec{d}) = \mathop{\text{argmax}}\limits_{p \in A} \vec{p} \cdot \vec{d} - \mathop{\text{argmax}}\limits_{q \in B} \vec{q} \cdot \vec{d} SA−B(d)=p∈Aargmaxp⋅d−q∈Bargmaxq⋅d - 构建单纯形并判断包含原点性
- 更新搜索方向,直至收敛
收敛条件:
∣ d ⃗ ⋅ v ⃗ ∣ < ϵ |\vec{d} \cdot \vec{v}| < \epsilon ∣d⋅v∣<ϵ
1.2.2 EPA算法
作用:在GJK检测到相交后计算穿透深度
执行流程:
- 扩展GJK生成的初始单纯形
- 迭代寻找最近边/面
- 计算接触法线和穿透深度
误差控制:
δ = ∣ n ⃗ ⋅ p ⃗ ∣ ∣ n ⃗ ∣ ≤ tolerance \delta = \frac{|\vec{n} \cdot \vec{p}|}{|\vec{n}|} \leq \text{tolerance} δ=∣n∣∣n⋅p∣≤tolerance
1.3 分离轴定理(SAT)
定理扩展:对于两个凸多面体,需测试以下候选轴:
- 物体A的面法线
- 物体B的面法线
- 所有边对的叉积方向
投影计算:
proj O ( a x i s ⃗ ) = [ min v ∈ V ( v ⋅