【数学】矩阵
数学上,一个 m × n 的矩阵是指一个有 m 行 n 列元素的矩形阵列。
A=a11a21⋮am1a12a22⋮am2……⋱…a1na2n⋮amn
矩阵的作用
-
表示一个空间
矩阵由多个基向量构成,恰巧可以描述一个多维空间。
-
表示一种变换
当矩阵的基向量本质是另一个空间的向量时,该矩阵的向量,也可以重新转换回基向量所在的空间,这个过程就叫变换。
例如:物体空间实际是利用物体在世界空间中的三个向量组成的新空间,该空间矩阵可与其向量做乘法运算,使其向量转换回世界空间。
所以根据上述内容的分析可以得出常见矩阵之间的关系:
物体空间矩阵=物体变换矩阵=物体到世界空间变换矩阵。
矩阵的运算
余子式
将矩阵中某些行或列去除后,剩下的元素组成的新矩阵。
-
k 阶余子式
去除行或列的数量被称为余子式的阶数。
对于 1 阶余子式通常记作Mij,表示去除了 i 行 j 列。
-
代数余子式
一种拥有正负号的余子式叫做代数余子式,其正负号是通过移除的行列序号判断的。
如Mij的代数余子式记作 Cij=(−1)i+jMij。
行列式
输入一个矩阵,输出一个标量。记作 det(A) 或 ∣A∣ 。
-
求解 n 阶矩阵
设Sn是序列{1,2,…,n}(即列编号)的全部置换的合集(相关知识见“组合与排列”)
∣A∣=σ∈Sn∑sgn(σ)i=1∏nai,σ(i)
或者利用代数余子式计算(只验证过 3 阶矩阵可用):
∣A∣=j=0∑na1,j∣C1,j∣
-
求解 2 阶矩阵
a1,1a2,1a1,2a2,2=a1,1a2,2−a1,2a2,1
TRS 矩阵的表示
TRS 矩阵是最常用的变换矩阵,其本质就是平移、旋转、缩放矩阵的复合,其复合顺序为:
平移矩阵∗旋转矩阵∗缩放矩阵
平移矩阵(Translate)
100001000010xyz1
旋转矩阵(Rotate)
Z轴旋转矩阵=cos(z)sin(z)0−sin(z)cos(z)0001
X轴旋转矩阵=1000cos(x)sin(x)0−sin(x)cos(x)
Y轴旋转矩阵=cos(y)0−sin(y)010sin(y)0cos(y)
若旋转矩阵要同时表示 3 轴旋转,就是通过对 x、y、z 旋转矩阵的复合得出的,如 Unity 中的复合顺序为:
Z轴旋转矩阵∗X轴旋转矩阵∗Y轴旋转矩阵
推导复合顺序过程是这样的:
- 在 Unity 中放一个方块。
- 对其先后进行 x、y 旋转并逆序尝试。
- 发现 Y 旋转永远都是以世界 Y 轴为准而不受物体 Y 轴的影响。
- 说明 X 旋转无法干扰 Y 旋转,但反之可以。
- 故矩阵复合一定是先 Y 后 X,Z 同理推出。
缩放矩阵(Scale)
x000y000z
TRS 矩阵的拆解
从 TRS 矩阵中逆推出原本的位移、旋转、缩放。
部分情况下旋转是无法被真正逆推回来的,这也解释了为什么旋转到特定角度时继续旋转会出问题,因此旋转物体时要保留原始的旋转值,不能完全依靠矩阵。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| Vector3 position; Vector3 rotation; Vector3 scale; Matrix4x4 matrix4X4 = transform.localToWorldMatrix; position = matrix4X4.GetColumn(3); Matrix4x4 sqrScaleMatrix = matrix4X4.transpose * matrix4X4; scale = new Vector3(Mathf.Sqrt(sqrScaleMatrix.m00), Mathf.Sqrt(sqrScaleMatrix.m11), Mathf.Sqrt(sqrScaleMatrix.m22)); Matrix4x4 rotationMatrix = matrix4X4 * Matrix4x4.Scale(new Vector3(1 / scale.x, 1 / scale.y, 1 / scale.z)); if (Mathf.Abs(Mathf.Abs(rotationMatrix.m12) - 1) > 0.001f) { rotation.y = Mathf.Atan2(rotationMatrix.m02, rotationMatrix.m22); rotation.z = Mathf.Atan2(rotationMatrix.m10, rotationMatrix.m11); float cosX = rotationMatrix.m02 != 0 ? rotationMatrix.m02 / Mathf.Sin(rotation.y) : rotationMatrix.m22 / Mathf.Cos(rotation.y); rotation.x = cosX > 0 ? Mathf.Asin(-rotationMatrix.m12) : Mathf.PI - Mathf.Asin(-rotationMatrix.m12); } else { if (-rotationMatrix.m12 > 0) { float yMinusZ = Mathf.Atan2(rotationMatrix.m01,rotationMatrix.m00); rotation.z = 0; rotation.y = yMinusZ; rotation.x = Mathf.PI / 2; } else { float yAddZ = Mathf.Atan2(-rotationMatrix.m01,rotationMatrix.m00); rotation.z = 0; rotation.y = yAddZ; rotation.x = -Mathf.PI / 2; } } rotation *= Mathf.Rad2Deg;
|