3、基础数学知识(下):矩阵运算、欧拉角与四元数、刚体变换
好,咱们接着聊。上一节我们把向量和点积、叉积这些基本功过了一遍。这一节要啃的,是真正让碰撞检测跑起来的核心数学工具——矩阵、欧拉角、四元数,以及它们怎么组合成刚体变换。
说实话,我刚入行那会儿,觉得矩阵就是用来算坐标的,欧拉角就是转几个角度,四元数?那玩意儿看着就头疼。直到我在一个物理沙盒项目里,被万向锁坑得死去活来……嗯,从那以后,我才老老实实把这几样东西的脾气摸透了。
3.1 矩阵运算:坐标变换的骨架
矩阵在碰撞检测里,说白了就是描述“怎么把一个点或向量,从一个地方弄到另一个地方”。最常见的,就是旋转矩阵和平移矩阵。
3.1.1 旋转矩阵
二维旋转大家可能都熟,绕原点转个θ角:
// 二维旋转矩阵
R(θ) = | cosθ -sinθ |
| sinθ cosθ |
三维里就复杂一点,得分别绕X、Y、Z轴转。我习惯把它们记成“哪个轴不动,哪一行/列就特殊”:
| 旋转轴 | 旋转矩阵(右手系,逆时针为正) |
|---|---|
| 绕X轴 | | 1 0 0 | | 0 cosθ -sinθ | | 0 sinθ cosθ | |
| 绕Y轴 | | cosθ 0 sinθ | | 0 1 0 | | -sinθ 0 cosθ | |
| 绕Z轴 | | cosθ -sinθ 0 | | sinθ cosθ 0 | | 0 0 1 | |
3.1.2 平移矩阵与齐次坐标
旋转是线性变换,但平移不是。为了把平移也塞进矩阵里,我们引入了齐次坐标。说白了,就是给二维点加一个1变成三维,给三维点加一个1变成四维。
// 齐次坐标下的平移矩阵(4x4)
T(tx, ty, tz) = | 1 0 0 tx |
| 0 1 0 ty |
| 0 0 1 tz |
| 0 0 0 1 |
你想想看,一个点 P = (x, y, z, 1),左乘这个矩阵,结果就是 (x+tx, y+ty, z+tz, 1)。干净利落。
3.2 欧拉角:直观但危险
欧拉角用三个角度(pitch、yaw、roll)来描述旋转。直观,好理解,调参数时很方便。
- Pitch(俯仰):绕X轴转,点头摇头。
- Yaw(偏航):绕Y轴转,左右看。
- Roll(滚转):绕Z轴转,歪头。
但欧拉角有个臭名昭著的问题——万向锁。当pitch达到±90°时,yaw和roll的旋转轴会重合,丢失一个自由度。我在一个飞行模拟器项目里遇到过,飞机翻转到90°俯仰时,控制直接乱套了。
3.3 四元数:旋转的正确姿势
四元数听起来玄乎,其实就是一个实部加三个虚部:q = w + xi + yj + zk。在碰撞检测里,我们只用单位四元数(模长为1)来表示旋转。
3.3.1 为什么用四元数?
- 无万向锁:这是最大的优点。
- 插值平滑:用球面线性插值(Slerp)可以在两个旋转之间平滑过渡。
- 组合高效:两个四元数相乘就能合成旋转,比矩阵乘法快。
3.3.2 核心操作
我个人觉得,记住下面几个操作就够了:
// 1. 用轴角构造四元数
// 绕单位轴 (ax, ay, az) 旋转 θ 弧度
q.w = cos(θ/2)
q.x = ax * sin(θ/2)
q.y = ay * sin(θ/2)
q.z = az * sin(θ/2)
// 2. 用四元数旋转向量 v
// 公式:v' = q * v * q_conjugate
// 注意:v 要当成纯四元数 (0, v.x, v.y, v.z)
// 3. 四元数乘法(组合旋转)
q_result = q1 * q2 // 先应用 q2,再应用 q1
// 4. 球面线性插值(Slerp)
// 数学库通常提供现成函数,比如 glm::slerp()
3.4 刚体变换:把一切串起来
一个刚体在空间中的位置和朝向,用一个变换矩阵或一对 (位置, 旋转) 来描述。这就是刚体变换。
3.4.1 变换矩阵形式
一个4x4的刚体变换矩阵长这样:
M = | R t |
| 0 1 |
其中:
R 是 3x3 旋转矩阵(正交,行列式为+1)
t 是 3x1 平移向量
最后一行是 [0, 0, 0, 1]
这个矩阵可以把一个点从局部坐标系变换到世界坐标系。反过来,求逆矩阵就能从世界坐标回到局部坐标。对于刚体变换,逆矩阵很好求:
M_inv = | R^T -R^T * t |
| 0 1 |
因为旋转矩阵的逆就是它的转置,省去了求逆的麻烦。
3.4.2 在碰撞检测中的应用
碰撞检测里,刚体变换无处不在:
- 将碰撞体顶点从局部坐标变换到世界坐标:用于空间划分和粗略检测。
- 将另一个物体的顶点变换到当前物体的局部坐标:用于精确的分离轴检测。
- 更新刚体的位置和旋转:每帧根据速度和角速度积分。
3.5 知识体系总览
下面这张图,把这一节的核心逻辑串起来了。你可以把它当成一个思维导图来记:
从这张图能看出来,矩阵是底层工具,欧拉角和四元数是两种不同的旋转表达方式,而刚体变换是它们的最终应用。我个人建议,你在写物理引擎时,内部统一用四元数+向量表示刚体状态,只在需要显示或序列化时转成矩阵或欧拉角。