为了简化碰撞计算,原碰撞体(如武器的碰撞)只使用长方体(OBB)和球(sphere)。对于立方体,
8 个顶点投影基本算法如图所示,平面 P P P 的单位法线向量为 n n n , p p p 为平面上任一点。
求任意点 a a a 到平面 P P P 的投影点的向量解法为:
最小OBB 就是包围点云最小体积的 Bounding Box 的方法。采用的方法为主成分分析。
主成分分析(Principal Component Analysis, PCA) 是一种常用的降维技术,旨在通过特征值和特征向量将高维数据转换为低维数据,同时尽量保留原始数据的方差(信息)。
PCA 的步骤:
计算协方差矩阵:计算数据集的协方差矩阵,捕捉数据中各特征之间的相关性。
求特征值和特征向量:计算协方差矩阵的特征值和特征向量。特征向量表示新的基向量(主成分方向),特征值表示这些方向上的方差大小(信息量)。
选择主成分:按特征值的大小对特征向量进行排序,选择特征值较大的几个特征向量作为主成分。这些主成分对应了数据集的主要变化方向。
转换数据:将原始数据投影到这些主成分上,从而实现降维。
下面介绍一下协方差矩阵。
协方差矩阵是一个方阵,其中每个元素代表了一对变量之间的[[协方差]]。对于随机向量 X = ( X 1 , X 2 , . . . , X n ) X = (X_1, X_2, ..., X_n) X=(X1,X2,...,Xn),其协方差矩阵 Σ \Sigma Σ 定义为:
Σ = [ σ 1 , 1 σ 1 , 2 ⋯ σ 1 , n σ 2 , 1 σ 2 , 2 ⋯ σ 2 , n ⋮ ⋮ ⋱ ⋮ σ n , 1 σ n , 2 ⋯ σ n , n ] \Sigma = \begin{bmatrix} \sigma_{1,1} & \sigma_{1,2} & \cdots & \sigma_{1,n} \\ \sigma_{2,1} & \sigma_{2,2} & \cdots & \sigma_{2,n} \\ \vdots & \vdots & \ddots & \vdots \\ \sigma_{n,1} & \sigma_{n,2} & \cdots & \sigma_{n,n} \end{bmatrix} Σ= σ1,1σ2,1⋮σn,1σ1,2σ2,2⋮σn,2⋯⋯⋱⋯σ1,nσ2,n⋮σn,n
其中, σ i , j \sigma_{i,j} σi,j 是 X i X_i Xi 和 X j X_j Xj 之间的协方差,计算公式为:
σ i , j = E [ ( X i − μ i ) ( X j − μ j ) ] \sigma_{i,j} = E[(X_i - \mu_i)(X_j - \mu_j)] σi,j=E[(Xi−μi)(Xj−μj)]
μ i \mu_i μi 和 μ j \mu_j μj 分别是 X i X_i Xi 和 X j X_j Xj 的期望值。
协方差矩阵是一种统计量,描述点云的方向分布和扩展。它的主方向(最大特征值对应的特征向量)可以用来估计点云的主要方向,进而可以确定 OBB 的方向和大小。
以下是几种主要的求解矩阵特征值和特征向量数值方法的对比。这些方法各有优劣,适用场景也不同,具体对比如下:
方法 | 适用矩阵类型 | 特征值求解 | 特征向量求解 | 优点 | 缺点 |
---|---|---|---|---|---|
QR 分解法 | 任意矩阵 | 所有特征值 | 所有特征向量 | 能求所有特征值和特征向量,适用于稠密矩阵 | 实现复杂度高,计算量大,适用于中小型矩阵 |
Jacobi 方法 | 对称矩阵 | 所有特征值 | 所有特征向量 | 简单易实现,适合小型对称矩阵,数值稳定 | 仅适用于对称矩阵,效率低于 QR 法 |
分而治之法 | 对称矩阵 | 所有特征值 | 所有特征向量 | 高效,适合对称矩阵,能并行计算 | 实现复杂,适用性较窄(仅对称矩阵) |
Lanczos 方法 | 大型稀疏矩阵 | 部分特征值 | 部分特征向量 | 高效,内存消耗低,适用于大规模稀疏矩阵 | 数值稳定性差,需稳定化处理,不适合稠密矩阵 |
因为要求解的矩阵是 3 维协方差矩阵,属于小型对称矩阵,并且需要稳定高精度的解,所以推荐使用 Jacobi 方法。
Jacobi 方法的核心思想是不断应用旋转变换来消除矩阵中的非对角元素,逐步将矩阵逼近一个对角矩阵。每次迭代选择一个最大的非对角元素,将它变为零,最终,矩阵的对角元素就是特征值,对角化过程中形成的旋转矩阵乘积则为特征向量矩阵。
关键步骤包括:
因为最终结果应为 OBB,所以可以对求解出的特征向量采用施密特正交化(Schmidt Orthogonalization)来进行正交化。
考虑相机是透视视角的,投影OBB正常应该拉伸成一个截头锥体(frustum),但 frustrum 的碰撞计算过于耗费性能。又由于透视效果并不是很大,并且保证碰撞体景深方向距离尽可能小,所以替换为使用立方体来模拟。也是因为透视,在碰撞体原位置进行投影后拉伸即能保证最正确的视觉效果。
需要注意的一点时,会进行碰撞检测的任意两个碰撞组之间只需要有一方进行投影拉伸即可保证碰撞事件的触发,另一方也可以采用一些精度较高精度的碰撞体。