文章目录
- 矩阵(Matrix)
- 矩阵能干啥?
- 矩阵基本运算
- 矩阵加减法
- 矩阵和标量的乘法
- 矩阵和矩阵的乘法
- 矩阵的转置
- 矩阵相等
- 特殊的矩阵
- 方块矩阵
- 对称矩阵
- 对角元素(Diagonal Elements)
- 对角矩阵(Diagonal Matrix)
- 三角形矩阵
- 单位矩阵
- 逆矩阵
- 正交矩阵
- 行矩阵还是列矩阵
- 小结
不知不觉中,这套【Unity学习笔记】写了100篇了,访问次数超过了37万,粉丝也渐渐开始涨上来了,每次看到大家的鼓励都很开心,这一路走来虽然时间不长,但也挺值得回味的,在这小感慨一下。这个过程中平台和朋友都劝我做知识付费我都没考虑。一方面不希望让这一切的驱动力由爱好转为利益;另一方面也不希望给自己太大的压力,毕竟志不在此。
今年黑猴发布了,看情形应该卖的还不错,算是给国内游戏行业长脸了,希望他们能真真正正的赚一笔,为下一款游戏奠定基础,带领国产游戏向着更有内容更有深度的方向发展,也能扭转一下国内蛋仔、二次元、648横行的尴尬局面。在这里解释一下,没有对某些游戏公司不敬的意思,我只是单方面的觉得这些骗小孩子时间骗年轻人钱的游戏 【都!是!垃!圾!】。没内容,没深度,没有社会责任感,“小学生不玩蛋仔就是不合群!”,“这个皮肤面数这么多,卖1888真的很良心了!”。一不小心情绪出来了,不讲这些负面的东西了,有这个时间还不如多写点东西推动国内游戏行业健康发展和迭代呢。
我应该会继续写下去,200篇、300篇,下一个专栏。希望后面的专栏都能是咱们自己国产的,比如Cocos,希望咱们国产引擎能越做越好,最好是百花齐放,推动显卡行业国产化进程,做出咱们自己的DirectX、OpenGL、Vulkan,让全世界的显卡都兼容中国的图形API。不然后面AI芯片还是会被人卡脖子。不做付费也有很大一部分原因是不希望国内游戏开发者的学习路线受到阻碍(起码在我这不会被阻碍),每次有评论和私信我都尽我的能力去帮忙,只希望我这一点点光能让国产游戏行业的天更加光辉灿烂!
书归正传,这一篇很重要,因为它的名字叫做----矩阵!
这!很!重!要! 这!很!重!要! 这!很!重!要!
矩阵的感性意义在于它为我们提供了一种简洁、直观、有力的数学工具来描述和理解现实世界的复杂现象和变化规律。无论是组织数值、描述变换、简化计算还是数学建模和感性认知等方面,矩阵都发挥着不可替代的重要作用。而在游戏开发行业中,矩阵是你从小白到大神 无法绕过的必修课 之一!
矩阵(Matrix)
矩阵,英文名是Matrix。在数学中,矩阵是一个矩形阵列,其中的元素可以是数字、符号或数学表达式等。矩阵的维度由其行数和列数确定。一个m×n的矩阵是一个由m行n列的元素组成的矩形阵列。
[ M 1 , 1 M 1 , 2 M 1 , 3 M 2 , 1 M 2 , 2 M 2 , 3 M 3 , 1 M 3 , 2 M 3 , 3 ] \left[ \begin{matrix} M_{1,1} & M_{1,2} & M_{1,3} \\ M_{2,1} & M_{2,2} & M_{2,3} \\ M_{3,1} & M_{3,2} & M_{3,3} \end{matrix} \right] M1,1M2,1M3,1M1,2M2,2M3,2M1,3M2,3M3,3
矩阵是线性代数的基础内容之一,在解决线性方程组时,可以将系数和常数写成一个矩阵,然后使用矩阵运算来求解方程组。在图形变换(如旋转、缩放、平移)中,也常常使用矩阵来表示这些变换。
矩阵包含多种运算,如加法、减法、惩罚、转置、逆运算等。
矩阵能干啥?
简单的说,矩阵一方面可以用来存储一个物体的位置、旋转、缩放信息;另一方面也可以通过矩阵的运算实现物体的平移、旋转、缩放;通过矩阵的应用,还能实现让一个模型上的每一个点一步步的通过矩阵运算最终变成屏幕上的一个点的坐标等。可以说如果要搞懂3D数学、Shader这类知识,矩阵是必不可少的。
在Unity中,矩阵(Matrix)扮演着至关重要的角色,特别是在处理物体的位置、旋转和缩放等变换时。以下是矩阵在Unity中的主要作用:
- 描述变换:矩阵主要用于描述物体的变换,包括位置、旋转和缩放。Unity内部使用齐次矩阵(通常是4x4矩阵)来存储这些信息。例如,一个物体的Transform组件就包含了其位置、旋转和缩放信息,这些信息实际上是通过矩阵来存储和处理的。
- 构建变换矩阵:在Unity中,可以通过 Matrix4x4 的静态方法来构建变换矩阵。例如,使用 Matrix4x4.Translate 来构建平移矩阵,Matrix4x4.Rotate 来构建旋转矩阵,以及 Matrix4x4.Scale 来构建缩放矩阵。
- 应用变换矩阵:一旦构建了变换矩阵,就可以将其应用到物体上,以实现物体的位置、旋转或缩放等变换。这些变换可以直接在物体的Transform组件中进行设置,也可以通过直接操作矩阵来实现。
- 合成变换:在3D图形中,一个物体可能需要进行多个变换(如先旋转再平移)。在Unity中,可以通过矩阵乘法来合成这些变换。通常,变换的顺序是先缩放,然后旋转,最后平移。
- 变换点和向量:在Unity中,还可以使用矩阵来变换点和向量。例如,可以使用一个物体的localToWorldMatrix来将一个局部坐标转换到世界坐标。
- 投影矩阵:在Unity中,投影矩阵通常用于将三维物体投影到二维屏幕上。Unity提供了多种投影方式,如正交投影和透视投影,这些方式都可以通过设置Camera组件的Projection属性来实现。
- 自定义矩阵:除了Unity内置的Matrix4x4结构,还可以使用自定义的矩阵类或结构。自定义的矩阵类或结构可以包含更多的方法和属性,以便更好地满足特定的需求。
当然,如果没有线性代数基础的话看到这些可能会比较懵,毕竟连变换是干嘛的都不知道呢。如果想进一步了解变换,可以到文末的目录中去找对应的章节,我将会把这两篇文章都放在一起。
矩阵基本运算
下面是一些基本的矩阵算法,可能会有些枯燥,建议先看懂,然后收藏,等需要的时候过来查询。等后面用多了自然就习惯了,而且很多时候这些运算是不需要人脑来计算的,我们只需要知道这些运算能起到什么作用即可。
矩阵加减法
几何意义:矩阵加减就是对矩阵列空间下的基向量做变换。在图形和图像处理中,矩阵常常用来表示像素值的数组。在这种情况下,矩阵的加法可以用来混合或叠加两个图像(例如,在图像叠加或透明度混合中)。矩阵的减法可以用来检测图像之间的差异或进行背景消除等操作。
先决条件:只有同型的矩阵(两个矩阵的行数和列数相同)才可以做加减法运算。
满足定律:矩阵加减满足交换律和结合律。
计算方法:矩阵加法一般是指两个矩阵把其相对应元素加在一起的运算,减法反之。
例如:
− − − − − − − − − − − − − − − − − − − − − − [ 12 3 − 1 3 22 2 3 1 3 ] + [ − 2 2 − 9 8 1 12 2 3 6 ] − − − − − − − − − − − − − − − − − − − − − − = [ 12 − 2 3 + 2 − 1 − 9 3 + 8 22 + 1 2 + 12 3 + 2 1 + 3 3 + 6 ] − − − − − − − − − − − − − − − − − − − − − − = [ 10 5 − 10 11 23 14 5 4 9 ] − − − − − − − − − − − − − − − − − − − − − − \\ ---------------------- \\\left[ \begin{matrix} 12 & 3 & -1 \\ 3 & 22 & 2 \\ 3 & 1 & 3 \end{matrix} \right] + \left[ \begin{matrix} -2 & 2 & -9 \\ 8 & 1 & 12 \\ 2 & 3 & 6 \end{matrix} \right] \\ ---------------------- \\ = \left[ \begin{matrix} 12 - 2 & 3 + 2 & -1 -9 \\ 3 + 8 & 22 + 1 & 2 + 12 \\ 3 + 2 & 1 + 3 & 3 + 6 \end{matrix} \right] \\ ---------------------- \\ = \left[ \begin{matrix} 10 & 5 & -10 \\ 11 & 23 & 14 \\ 5 & 4 & 9 \end{matrix} \right]\\ ---------------------- −−−−−−−−−−−−−−−−−−−−−− 12333221−123 + −282213−9126 −−−−−−−−−−−−−−−−−−−−−−= 12−23+83+23+222+11+3−1−92+123+6 −−−−−−−−−−−−−−−−−−−−−−= 101155234−10149 −−−−−−−−−−−−−−−−−−−−−−
矩阵和标量的乘法
几何意义:矩阵与标量的乘法在几何上表示对矩阵所代表的向量或向量集合的缩放操作。
- 当标量大于1时,矩阵代表的向量或向量集合会在各个维度上被拉伸(stretch);
- 当标量在0和1之间时,它们会被压缩(shrink);
- 当标量为0时,结果会是一个行列数不变的零矩阵;
- 当标量小于0和-1之间时,它们会被压缩(shrink),且方向与原方向相反;
- 当标量小于-1时,矩阵代表的向量或向量集合会在各个维度上被拉伸(stretch),且方向与原方向相反。
应用场景:
- 数据处理:在数据分析和处理中,标量乘法经常用于数据的缩放或归一化。通过调整标量的大小,可以将数据的范围调整到特定的区间内,以便于后续的分析或计算。比如在机器学习领域就经常需要对特征进行归一化处理,以提高模型的训练效果和性能;
- 图形变换:在计算机图形学中,标量乘法常用于图形的缩放变换。通过调整标量的大小,可以改变图形的大小而不改变其形状或方向。在游戏开发领域属于非常常用的应用场景;
- 物理学模拟:物体膨胀、热胀冷缩等情况都可以使用标量乘法来实现;
- 矩阵计算:在矩阵运算时也经常需要用到标量乘法结合其他矩阵运算。
先决条件:没什么限制,随便乘。
满足定律:
- 矩阵和标量的乘法满足分配率,即 k(A + B) = kA + kB;
- 矩阵和标量的乘法满足结合律,即 (jk)A = j(kA);
- 矩阵和标量的乘法不满足交换律。
计算方法:矩阵和标量的乘法非常简单,就是矩阵的每个元素和该标量相乘。
公式如下:
− − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − k ∗ M = M ∗ k = k [ M 1 , 1 M 1 , 2 M 1 , 3 M 2 , 1 M 2 , 2 M 2 , 3 M 3 , 1 M 3 , 2 M 3 , 3 ] = [ k M 1 , 1 k M 1 , 2 k M 1 , 3 k M 2 , 1 k M 2 , 2 k M 2 , 3 k M 3 , 1 k M 3 , 2 k M 3 , 3 ] − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − \\ --------------------------------- \\k*M = M*k = k\left[ \begin{matrix} M_{1,1} & M_{1,2} & M_{1,3} \\ M_{2,1} & M_{2,2} & M_{2,3} \\ M_{3,1} & M_{3,2} & M_{3,3} \end{matrix} \right] = \left[ \begin{matrix} kM_{1,1} & kM_{1,2} & kM_{1,3} \\ kM_{2,1} & kM_{2,2} & kM_{2,3} \\ kM_{3,1} & kM_{3,2} & kM_{3,3} \end{matrix} \right]\\ --------------------------------- −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−k∗M=M∗k=k M1,1M2,1M3,1M1,2M2,2M3,2M1,3M2,3M3,3 = kM1,1kM2,1kM3,1kM1,2kM2,2kM3,2kM1,3kM2,3kM3,3 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
矩阵和矩阵的乘法
矩阵与矩阵相乘是十分重要的矩阵计算方法,在游戏开发过程中使用矩阵时大多数都是使用乘法。我们想要对物体做平移、旋转、缩放时基本都是使用矩阵乘法,与矩阵与标量相乘不同的是,标量只能进行统一的缩放或其他操作,而矩阵相乘允许我们在不同轴向上对物体做不等量的变换操作。
几何意义:
- 平移、旋转、缩放:通过矩阵的乘法可以描述物体的平移、旋转、缩放等基本物理操作,这部分的细节内容会在下一章节中详细讲述;
- 坐标空间的变换:对于高维矩阵,其乘法可以看作是对整个空间进行线性变换。例如,在三维空间中,一个3x3的矩阵可以描述一个旋转、缩放或错切等变换。通过矩阵乘法,我们可以将一个空间中的点或向量转换到另一个空间中。比如,将模型空间坐标系下的物体变换通过乘法转换到世界空间(也可以是其他空间坐标系)下。
- 线性变换的复合:矩阵和矩阵的乘法可以理解为两个线性变换的复合。当矩阵A乘以矩阵B时,可以理解为首先进行B所代表的线性变换,然后再进行A所代表的线性变换。这种复合变换可以包含旋转、缩放、剪切等多种效果。举个例子,比如我想让一个物体先向A矩阵方向平移,再向B矩阵方向平移,实际上就等于让物体向 “A × B” 方向平移,再说明白点就是满足交换律。
- 方向和长度的改变:矩阵乘法可以改变向量的方向和长度。具体来说,一个矩阵乘以一个向量,得到的结果是一个新的向量,这个新向量的方向和长度都可能发生了改变。
先决条件:第一个矩阵的列数必须和第二个矩阵的行数相同。
满足定律:
- 矩阵乘法不满足交换律,即AB ≠ BA;
- 矩阵乘法满足结合律,即 (AB)C = A(BC),再进一步可以满足 ABCDE = ((A(BC))D)E = (AB)(CD)E ,也就相当于分配率。
计算方法:假设我们有两个矩阵 A 和 B,其中 A 是一个 m×n 的矩阵,B 是一个 n×p 的矩阵。它们的乘积 C = AB 将是一个 m×p 的矩阵。C中的每一个元素 C i , j C_{i,j} Ci,j等于A的第i行对应的矢量和B的第j列所对应的矢量点乘后的结果。
举个例子:
[ B 1 , 1 B 1 , 2 B 1 , 3 B 1 , 4 B 2 , 1 B 2 , 2 B 2 , 3 B 2 , 4 ] [ A 1 , 1 A 1 , 2 A 2 , 1 A 2 , 2 A 3 , 1 A 3 , 2 A 4 , 1 A 4 , 2 ] [ C 1 , 1 C 1 , 2 C 1 , 3 C 1 , 4 C 2 , 1 C 2 , 2 C 2 , 3 C 2 , 4 C 3 , 1 C 3 , 2 C 3 , 3 C 3 , 4 C 4 , 1 C 4 , 2 C 4 , 3 C 4 , 4 ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~\left[ \begin{matrix} B_{1,1} & B_{1,2} & B_{1,3} & B_{1,4} \\ B_{2,1} & B_{2,2} & B_{2,3} & B_{2,4} \end{matrix} \right] \\~ \\~ \left[ \begin{matrix} A_{1,1} & A_{1,2}\\ A_{2,1} & A_{2,2}\\ A_{3,1} & A_{3,2}\\ A_{4,1} & A_{4,2} \end{matrix} \right] ~ \left[ \begin{matrix} C_{1,1} & C_{1,2} & C_{1,3} & C_{1,4} \\ C_{2,1} & C_{2,2} & C_{2,3} & C_{2,4} \\ C_{3,1} & C_{3,2} & C_{3,3} & C_{3,4} \\ C_{4,1} & C_{4,2} & C_{4,3} & C_{4,4} \end{matrix} \right] [B1,1B2,1B1,2B2,2B1,3B2,3B1,4B2,4] A1,1A2,1A3,1A4,1A1,2A2,2A3,2A4,2 C1,1C2,1C3,1C4,1C1,2C2,2C3,2C4,2C1,3C2,3C3,3C4,3C1,4C2,4C3,4C4,4
其中 C 2 , 3 C_{2,3} C2,3的计算方式为 ( A 2 , 1 A_{2,1} A2,1 * B 1 , 3 B_{1,3} B1,3) + ( A 2 , 2 A_{2,2} A2,2 * B 2 , 3 B_{2,3} B2,3),也就是 A 的第 2 行矢量 [ A 2 , 1 , A 2 , 2 ] [A_{2,1}, A_{2,2}] [A2,1,A2,2] 点乘 B 的第 3 列矢量的 [ B 1 , 3 , B 2 , 3 ] [B_{1,3}, B_{2,3}] [B1,3,B2,3] 的结果。
矩阵的转置
矩阵的转置也是一个矩阵,实际上也可以算作是对原矩阵的一种运算,即转置运算。给定一个 m ∗ n m * n m∗n 的矩阵 M ,它的转置可以表示为 M T M^{T} MT ,这是一个 n ∗ m n * m n∗m 的矩阵。实际上矩阵的转置就是沿着对角线把矩阵翻过来,原矩阵的第 i 行变成第 i 列,而第 j 列变成了第 j 行。数学公式为: M i , j T = M j , i M^{T}_{i,j} = M_{j,i} Mi,jT=Mj,i 。
例如:
[ 10 5 − 10 2 6 4 9 − 1 ] T = [ 10 6 5 4 − 10 9 2 − 1 ] \left[ \begin{matrix} 10 & 5 & -10 & 2 \\ 6 & 4 & 9 & -1 \end{matrix} \right]^{T} = \left[ \begin{matrix} 10 & 6 \\ 5 & 4 \\ -10 & 9 \\ 2 & -1 \end{matrix} \right] [10654−1092−1]T= 105−102649−1
特殊性质:
- 矩阵转置的转置等于原矩阵:这个应该很好理解,翻转过去再翻转回来,结果是完全一致的。公式为: ( M T ) T = M (M^{T})^{T} = M (MT)T=M。
- 矩阵相乘的转置,等于反向相乘各矩阵的转置: ( A B ) T = B T ∗ A T (AB)^{T} = B^{T} * A^{T} (AB)T=BT∗AT。
举个例子,比如 [ 1 2 3 4 5 6 ] ∗ [ 7 10 8 11 9 12 ] = [ 50 68 124 167 ] \left[ \begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{matrix} \right] * \left[ \begin{matrix} 7 & 10 \\ 8 & 11 \\ 9 & 12 \end{matrix} \right] = \left[ \begin{matrix} 50 & 68 \\ 124 & 167 \end{matrix} \right] [142536]∗ 789101112 =[5012468167]
[ 50 68 124 167 ] T = [ 50 124 68 167 ] \left[ \begin{matrix} 50 & 68 \\ 124 & 167 \end{matrix} \right]^{T} = \left[ \begin{matrix} 50 & 124 \\ 68 & 167 \end{matrix} \right] [5012468167]T=[5068124167]
如果用 A T ∗ B T A^{T} * B^{T} AT∗BT 就相当于 [ 1 4 2 5 3 6 ] ∗ [ 7 8 9 10 11 12 ] \left[ \begin{matrix} 1 & 4 \\ 2 & 5 \\ 3 & 6 \end{matrix} \right] * \left[ \begin{matrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{matrix} \right] 123456 ∗[710811912]结果很明显是一个 3 ∗ 3 3 * 3 3∗3 的矩阵,与原结果一定不同,所以正确的算法应该是 ( A B ) T = B T ∗ A T (AB)^{T} = B^{T} * A^{T} (AB)T=BT∗AT ,用 B 的转置去乘以 A 的转置,最后的结果才能是正确的 2 ∗ 2 2 * 2 2∗2 矩阵。
计算结果为 ( A B ) T = B T ∗ A T = [ 7 8 9 10 11 12 ] ∗ [ 1 4 2 5 3 6 ] = [ 50 124 68 167 ] (AB)^{T} = B^{T} * A^{T}=\left[ \begin{matrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{matrix} \right] * \left[ \begin{matrix} 1 & 4 \\ 2 & 5 \\ 3 & 6 \end{matrix} \right] = \left[ \begin{matrix} 50 & 124 \\ 68 & 167 \end{matrix} \right] (AB)T=BT∗AT=[710811912]∗ 123456 =[5068124167],这样才得到了正确的结果。
【划重点】 在《Unity Shader入门精要》书中,这句话的原文为 “矩阵串接的转置,等于反向串接各矩阵的转置” ,这句话对我造成了很大的困扰。因为我基础不太好,不知道矩阵串接的具体意义,我查找了Steven J.Leon著的《线性代数》、Fletcher Dunn著的《3D数学基础:图形和游戏开发》以及《计算机图形学原理及实践》的基础篇和进阶篇,都没有找到关于矩阵串接的说法,只在《线性代数》一书中的分块矩阵章节中找到了矩阵复合这个说法,还在网上找到了一些关于矩阵的串联和扩展的相关内容,按照我的理解(实际上我还问了AI),矩阵的串接应该理解为一种串联或者说拼接,就是直接把两个矩阵的元素拼接到一起,只扩展矩阵的行或列,而不去改变其中元素的内容,下面贴一段大模型的回答:
基于上述内容,我将《Unity Shader入门精要》原文中的 “串接” 一词改为了 “相乘” 。一方面觉得数学这个东西应该非常严谨,另一方面又怕误导别人,所以纠结了一下,如果改的不对,还请各位大神不吝赐教,多谢了。
矩阵相等
若两个矩阵相等,则他们的维数以及他们对应的元素必相等。
特殊的矩阵
有一些特殊的矩阵类型在Shader中经常见到,这些特殊矩阵往往具有一些重要的性质。
方块矩阵
方块矩阵(Square Matrix),简称方阵。方阵是指那些行数和列数一致的矩阵,例如 3 ∗ 3 3 * 3 3∗3 矩阵和 4 ∗ 4 4 * 4 4∗4 矩阵。
对称矩阵
对称矩阵(Symmetric Matrices)是线性代数中的一个重要概念,对称矩阵是指以主对角线为对称轴,各元素对应相等的矩阵。在线性代数中,对称矩阵是一个方形矩阵,其转置矩阵和自身相等。即,如果矩阵A满足 A = A T A= A^T A=AT(A的转置等于A),则称A为对称矩阵。
定义:一个方形矩阵,其元素以主对角线为对称轴对应相等,即对于所有 i i i 和 j j j ,都有 A i j = A j i A_{ij} = A_{ji} Aij=Aji。同时,对称矩阵的转置矩阵等于其自身,即 A T = A A^T = A AT=A。
举个例子:如果一个矩阵转置以后跟原来一样,那这个矩阵就叫对称矩阵,比如:
若 A = [ 10 5 5 4 ] 则 A T = [ 10 5 5 4 ] 若A = \left[ \begin{matrix} 10 & 5 \\ 5 & 4 \end{matrix} \right] 则 A^{T} = \left[ \begin{matrix} 10 & 5 \\ 5 & 4 \end{matrix} \right] 若A=[10554]则AT=[10554]
A转置后的结果与转置前相同,则A为“对称矩阵”。
再搞几个对称矩阵的例子:
[ 1 0 0 − 4 ] − − − [ 2 3 8 3 − 4 5 8 5 3 ] − − − [ − 4 5 3 5 1 − 2 3 − 2 12 ] \left[ \begin{matrix} 1 & 0 \\ 0 & -4 \end{matrix} \right] ---\left[ \begin{matrix} 2 & 3 & 8 \\ 3 & -4 & 5 \\ 8 & 5 & 3 \end{matrix} \right] ---\left[ \begin{matrix} -4 & 5 & 3 \\ 5 & 1 & -2 \\ 3 & -2 & 12 \end{matrix} \right] [100−4]−−− 2383−45853 −−− −45351−23−212
有什么用?
对称矩阵在多个领域都有广泛应用:
- 物理学:在量子力学和统计力学中,对称矩阵用于描述系统的哈密顿量、密度矩阵等;
- 工程学:在结构力学、电路分析和信号处理中,对称矩阵用于表示系统的刚度矩阵、阻抗矩阵等;
- 数学:在数值分析和优化问题中,对称矩阵的性质被广泛应用于求解线性方程组、特征值问题等;
- 在Shader编程中,利用对称矩阵的性质(如对角线上的元素相等)可能有助于优化代码和提高性能。例如,在某些情况下,可以只存储矩阵的一半元素来减少内存使用,并在计算时利用对称性来避免不必要的计算。
对角元素(Diagonal Elements)
对角元素是指行号和列号相等的元素,例如 M 2 , 2 M_{2,2} M2,2, M 4 , 4 M_{4,4} M4,4等。这些元素刚好在正方形的对角线上,所以被称为对角元素。
对角矩阵(Diagonal Matrix)
如果一个矩阵中除了对角元素外其他元素全为 0 ,那么这个矩阵就叫做对角矩阵。
例如 [ 4 0 0 0 0 1 0 0 0 0 − 3 0 0 0 0 12 ] \left[ \begin{matrix} 4 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -3 & 0 \\ 0 & 0 & 0 & 12 \end{matrix} \right] 4000010000−3000012 就是一个对角矩阵。
三角形矩阵
一个 n ∗ n n * n n∗n 矩阵 A A A,当 i > j i>j i>j 时, a i j = 0 a_{ij}=0 aij=0 ,则称 A A A 为上三角形的;当 i < j i<j i<j 时, a i j = 0 a_{ij}=0 aij=0 ,则称 A A A 为下三角形的。同时,若 A A A 为上三角形的或下三角形的,则称 A A A 为三角形的。
例如, 3 ∗ 3 矩阵 [ 3 2 5 0 12 6 0 0 1 ] 和 [ 6 0 0 2 − 1 0 6 8 1 ] 均为三角形的,其中第一个为上三角形,第二个为下三角形的。 例如,3 * 3矩阵\left[ \begin{matrix} 3 & 2 & 5 \\ 0 & 12 & 6 \\ 0 & 0 & 1 \end{matrix} \right] 和 \left[ \begin{matrix} 6 & 0 & 0 \\ 2 & -1 & 0 \\ 6 & 8 & 1 \end{matrix} \right]均为三角形的,其中第一个为上三角形,第二个为下三角形的。 例如,3∗3矩阵 3002120561 和 6260−18001 均为三角形的,其中第一个为上三角形,第二个为下三角形的。
单位矩阵
单位矩阵是一个特殊的矩阵,用 I n I_{n} In 表示,一个 3 ∗ 3 3 * 3 3∗3 的单位矩阵如下:
[ 1 0 0 0 1 0 0 0 1 ] \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] 100010001
这个矩阵就和标量中的1一样,任何矩阵与单位矩阵相乘的结果都是原来的矩阵。
其实这样很能体现矩阵乘法的特色,就是如果想让原矩阵不变,要做的不是把每个元素都变成 1,而是只要把对角线上的元素变成 1 就可以了。这样就能只把想要位置的元素复制一遍,其他的全变成0,这时候累加的结果就只是对应行列的那个唯一结果了。
逆矩阵
逆矩阵是指对于一个给定的方阵(即行数和列数相等的矩阵),如果存在另一个方阵,使得这两个方阵相乘(无论是左乘还是右乘)的结果都是单位矩阵,则称这两个方阵互为逆矩阵。即: M M − 1 = M − 1 M = I MM^{-1} = M^{-1}M = I MM−1=M−1M=I , M M M 为 n ∗ n n * n n∗n 方阵, I I I 为 n ∗ n n * n n∗n 方阵的单位矩阵。当上述条件满足时,则 M M M 和 M − 1 M^{-1} M−1 互为逆矩阵。
如果一个矩阵没有逆矩阵,这个矩阵就可以被称为不可逆的(noninvertible)或者称为奇异的(singular)。
条件:
- 只有方阵才有逆矩阵;
- 不是所有方阵都有逆矩阵,比如所有元素都为0的矩阵;
- 如果一个矩阵的行列式(关于行列式的内容,我会在后面的章节记录下来)不为0,那么他就是可逆的。
性质:
- 逆矩阵的逆矩阵是原矩阵本身:假设矩阵 M M M 是可逆的,那么 ( M − 1 ) − 1 = M (M^{-1})^{-1}=M (M−1)−1=M。
- 单位矩阵的逆矩阵是它本身,即: I − 1 = I I^{-1}=I I−1=I 。
- 转置矩阵的逆矩阵是逆矩阵的转置,即: ( M T ) − 1 = ( M − 1 ) T (M^{T})^{-1}=(M^{-1})^{T} (MT)−1=(M−1)T。
- 两个矩阵相乘后的逆矩阵等于两个矩阵的逆矩阵反向相乘,即: ( A B ) − 1 = B − 1 A − 1 (AB)^{-1}=B^{-1}A^{-1} (AB)−1=B−1A−1。
- 多个矩阵连乘的逆矩阵等于每个矩阵的逆矩阵反向连乘,即: ( A B C D ) − 1 = D − 1 C − 1 B − 1 A − 1 (ABCD)^{-1}=D^{-1}C^{-1}B^{-1}A^{-1} (ABCD)−1=D−1C−1B−1A−1
- 【重点】使用逆矩阵获得反向变换。使用变换矩阵 M M M 对矢量 v v v 进行一次变换,再使用它的逆矩阵 M − 1 M^{-1} M−1 进行另一次变换,会得到原来的矢量 v v v 。也就是说逆矩阵是原矩阵的反向操作,如果我们要使物体反向移动就可以利用这个性质。
应用:
- 撤销变换
逆矩阵在几何上非常有用,因为它使得我们可以计算变换的“反向”或相反变换功能。如果向量v用矩阵M来进行变换,接着用M的逆矩阵进行变换,将会得到原来的向量。这在游戏开发中尤其重要,因为开发者可能需要撤销之前的变换操作,比如当玩家取消某个操作或需要回到变换前的状态时,逆矩阵就派上了用场。 - 物理模拟
在物理引擎中,逆矩阵可以用于计算物体之间的碰撞响应、模拟重力等。例如,在模拟物体运动时,如果应用了某种变换(如旋转、平移或缩放),可能需要计算这些变换的逆变换来确保物理模拟的准确性和稳定性。逆矩阵在这个过程中起到了关键的作用。 - 相机与视角控制
在3D游戏开发中,相机和视角的控制是至关重要的。通过逆矩阵,开发者可以轻松地实现相机的旋转、平移等操作的逆变换,从而确保相机能够按照预期的方式移动和旋转。这对于创建流畅且逼真的游戏体验至关重要。 - 光照与渲染
在场景渲染中,逆矩阵也可以用于计算光照效果。通过将光源位置、光源强度等信息与物体表面颜色等信息组合在一起,并使用逆矩阵来撤销某些不必要的变换,可以更加精确地计算光照效果,从而实现更加逼真的渲染效果。 - 人工智能与NPC行为
在人工智能方面,逆矩阵可以用于计算NPC(非玩家角色)的行为和决策。通过将NPC的状态、环境信息等信息组合在一起,并使用逆矩阵来撤销或调整某些决策,可以使NPC的行为更加符合逻辑和预期。 - 矩阵运算优化
在游戏开发中,矩阵运算是一个常见的计算任务。通过使用逆矩阵,可以优化某些矩阵运算过程,减少计算量并提高计算效率。这对于提高游戏性能和响应速度至关重要。
正交矩阵
正交矩阵(orthogonal matrix)跟逆矩阵是有点像的,逆矩阵是自己跟逆矩阵相乘等于单位矩阵,正交矩阵是矩阵和他的转置矩阵相乘结果为单位矩阵。
定义:如果一个方阵 M M M 和它的转置矩阵的乘积为单位矩阵,则这个矩阵为正交矩阵。反之亦然。即: M M T = M T M = I MM^T = M^TM = I MMT=MTM=I。
结合前面逆矩阵的公式 M M − 1 = M − 1 M = I MM^{-1} = M^{-1}M = I MM−1=M−1M=I 可以得出一个很重要的性质,即如果一个矩阵是正交的,那么它的转置矩阵和逆矩阵是一样的。也就是说矩阵 M M M 是正交的话就相当于: M T = M − 1 M^{T}=M^{-1} MT=M−1 , 也就是说正交矩阵的转置和逆矩阵相等。这很重要,因为在三维变换中我们经常会需要使用逆矩阵来求解反向的变换,而逆矩阵的计算复杂度很高,而转置矩阵却非常容易求解。
虽然这个性质很好用,但我们如何知道何时才能使用这个性质呢?总不能每次使用之前去判断是否正交吧?万一不正交岂不是判断的计算也浪费掉了?这时候就需要了解正交矩阵的几何意义了。
我们来看一下 3 ∗ 3 3*3 3∗3 正交矩阵的特点。根据正交矩阵的定义,可以得出:
M M T = [ − − c 1 − − − − c 2 − − − − c 3 − − ] [ ∣ ∣ ∣ c 1 c 2 c 3 ∣ ∣ ∣ ] MM^T = \left[ \begin{matrix} -- & c_1 & -- \\ -- & c_2 & -- \\ -- & c_3 & -- \end{matrix} \right]\left[ \begin{matrix} | & | & | \\ c_1 & c_2 & c_3 \\ | & | & | \end{matrix} \right] MMT= −−−−−−c1c2c3−−−−−− ∣c1∣∣c2∣∣c3∣
= [ c 1 ⋅ c 1 c 1 ⋅ c 2 c 1 ⋅ c 3 c 2 ⋅ c 1 c 2 ⋅ c 2 c 2 ⋅ c 3 c 3 ⋅ c 1 c 3 ⋅ c 2 c 3 ⋅ c 3 ] \\=\left[ \begin{matrix} c_1·c_1 & c_1·c_2 & c_1·c_3 \\ c_2·c_1 & c_2·c_2 & c_2·c_3 \\ c_3·c_1 & c_3·c_2 & c_3·c_3 \end{matrix} \right] = c1⋅c1c2⋅c1c3⋅c1c1⋅c2c2⋅c2c3⋅c2c1⋅c3c2⋅c3c3⋅c3
= [ 1 0 0 0 1 0 0 0 1 ] = I \\= \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] = I = 100010001 =I
可以得出 9 个等式:
c 1 ⋅ c 1 = 1 , c 1 ⋅ c 2 = 0 , c 1 ⋅ c 3 = 0 c_1·c_1=1,c_1·c_2=0,c_1·c_3=0 c1⋅c1=1,c1⋅c2=0,c1⋅c3=0
c 2 ⋅ c 1 = 0 , c 2 ⋅ c 2 = 1 , c 2 ⋅ c 3 = 0 c_2·c_1=0,c_2·c_2=1,c_2·c_3=0 c2⋅c1=0,c2⋅c2=1,c2⋅c3=0
c 3 ⋅ c 1 = 0 , c 3 ⋅ c 2 = 0 , c 3 ⋅ c 3 = 1 c_3·c_1=0,c_3·c_2=0,c_3·c_3=1 c3⋅c1=0,c3⋅c2=0,c3⋅c3=1
可以得出以下结论:
- 矩阵的每一行,即 c 1 、 c 2 、 c 3 c_1、c_2、c_3 c1、c2、c3 是单位矢量,因为只有这样它们与自己的点积才能是1;
- 矩阵的每一行,即 c 1 、 c 2 、 c 3 c_1、c_2、c_3 c1、c2、c3 之间互相垂直,因为只有这样它们之间的点积才能是0;
- 上述两条结论对矩阵的每一列同样适用,因为如果 M M M 是正交矩阵的话, M T M^T MT 也会是正交矩阵。
要建立一个坐标空间需要制定一组基矢量,也就是我们常说的坐标轴。如果这些基矢量之间是互相垂直的,那么我们就把它称为是一组正交基(orthotonal basis),但它们的长度并不要求一定是 1 。如果它们的长度的确是 1 的话,我们就说它们是一组标准正交基(orthonormal basis)。因此,一个正交矩阵的行和列之间分别构成了一组标准正交基。
行矩阵还是列矩阵
矩阵与矢量相乘是种十分常用的计算方法(比如平移)。决定矩阵是否可以相乘时有一个前置条件,即:前面矩阵的列数要等于后面矩阵的行数。如果一个向量 v = ( x , y , z ) v=(x,y,z) v=(x,y,z) 想要和矩阵 M = [ M 1 , 1 M 1 , 2 M 1 , 3 M 2 , 1 M 2 , 2 M 2 , 3 M 3 , 1 M 3 , 2 M 3 , 3 ] M=\left[ \begin{matrix} M_{1,1} & M_{1,2} & M_{1,3} \\ M_{2,1} & M_{2,2} & M_{2,3} \\ M_{3,1} & M_{3,2} & M_{3,3} \end{matrix} \right] M= M1,1M2,1M3,1M1,2M2,2M3,2M1,3M2,3M3,3 相乘,会有两种情况: v M 和 M v vM和 Mv vM和Mv ,由于计算顺序的不同且不满足交换律,两种情况产生的结果也完全不同,就连结果的格式也不同。
v M = [ x m 11 + y m 21 + z m 31 x m 12 + y m 22 + z m 32 x m 13 + y m 23 + z m 33 ] vM=\left[\begin{matrix}xm_{11}+ym_{21}+zm_{31} & xm_{12}+ym_{22}+zm_{32} & xm_{13}+ym_{23}+zm_{33}\end{matrix}\right] vM=[xm11+ym21+zm31xm12+ym22+zm32xm13+ym23+zm33]
M v = [ x M 1 , 1 y M 1 , 2 z M 1 , 3 x M 2 , 1 y M 2 , 2 z M 2 , 3 x M 3 , 1 y M 3 , 2 z M 3 , 3 ] Mv=\left[ \begin{matrix} xM_{1,1} & yM_{1,2} & zM_{1,3} \\ xM_{2,1} & yM_{2,2} & zM_{2,3} \\ xM_{3,1} & yM_{3,2} & zM_{3,3} \end{matrix} \right] Mv= xM1,1xM2,1xM3,1yM1,2yM2,2yM3,2zM1,3zM2,3zM3,3
所以,矩阵相乘时使用行矩阵还是列矩阵矢量是非常重要的,因为这决定了矩阵乘法的书写次序和结果值。
在 Unity 中,常规做法是把矢量放在矩阵右侧,即把矢量转换为列矩阵来进行运算,所以大部分的情况使用的都是列矩阵。这意味着,我们的矩阵乘法通常都是右乘,例如:
C B A v = ( C ( B ( A v ) ) ) CBAv=(C(B(Av))) CBAv=(C(B(Av)))
使用列向量的结果是,我们的阅读顺序是从右到左,即先对 v v v 使用 A A A 进行变换,再使用 B B B 进行变换,最后使用 C C C 进行变换。
上面的计算等价于下面的行矩阵运算:
v A T B T C T = ( ( ( v A T ) B T ) C T ) vA^{T}B^{T}C^{T}=(((vA^{T})B^{T})C^{T}) vATBTCT=(((vAT)BT)CT)
小结
本章主要围绕矩阵进行了初步的讲解,但在线性代数学科以及更广泛的范围内,矩阵的相关内容还有很多,包括但不限于初等矩阵、等价方程组、分块矩阵、分块乘法、外积展开 等,由于这些内容与Unity开发的相关性相对较小,所以没有在本章中赘述,如果有兴趣的可以参考《线性代数》相关书籍,或者联系我,有机会的话我会给矩阵章节写个续集~
本文部分内容参考了冯乐乐老师的《Unity Shader入门精要》,很好的一本书,无论是技美、游戏程序、元宇宙、数字孪生方向都建议看看。
另外还参考了Steven J.Leon著的《线性代数》以及清华大学出版的《3D数学基础:图形和游戏开发(第2版)》中的部分内容,《线性代数》在线性代数方面讲的比《Unity Shader入门精要》要更细致一些。当然,也更枯燥一些,如果不是真的显得O疼的不建议去看,容易被劝退,哈哈。
难以想象如果上学那会学习这么认真现在的我会是什么样的?
《Unity Shader入门精要》学习打卡
更多内容请查看总目录【Unity】Unity学习笔记目录整理