赞
踩
不知不觉中,这套【Unity学习笔记】写了100篇了,访问次数超过了37万,粉丝也渐渐开始涨上来了,每次看到大家的鼓励都很开心,这一路走来虽然时间不长,但也挺值得回味的,在这小感慨一下。这个过程中平台和朋友都劝我做知识付费我都没考虑。一方面不希望让这一切的驱动力由爱好转为利益;另一方面也不希望给自己太大的压力,毕竟志不在此。
今年黑猴发布了,看情形应该卖的还不错,算是给国内游戏行业长脸了,希望他们能真真正正的赚一笔,为下一款游戏奠定基础,带领国产游戏向着更有内容更有深度的方向发展,也能扭转一下国内蛋仔、二次元、648横行的尴尬局面。在这里解释一下,没有对某些游戏公司不敬的意思,我只是单方面的觉得这些骗小孩子时间骗年轻人钱的游戏 【都!是!垃!圾!】。没内容,没深度,没有社会责任感,“小学生不玩蛋仔就是不合群!”,“这个皮肤面数这么多,卖1888真的很良心了!”。一不小心情绪出来了,不讲这些负面的东西了,有这个时间还不如多写点东西推动国内游戏行业健康发展和迭代呢。
我应该会继续写下去,200篇、300篇,下一个专栏。希望后面的专栏都能是咱们自己国产的,比如Cocos,希望咱们国产引擎能越做越好,最好是百花齐放,推动显卡行业国产化进程,做出咱们自己的DirectX、OpenGL、Vulkan,让全世界的显卡都兼容中国的图形API。不然后面AI芯片还是会被人卡脖子。不做付费也有很大一部分原因是不希望国内游戏开发者的学习路线受到阻碍(起码在我这不会被阻碍),每次有评论和私信我都尽我的能力去帮忙,只希望我这一点点光能让国产游戏行业的天更加光辉灿烂!
书归正传,这一篇很重要,因为它的名字叫做----矩阵!
这!很!重!要! 这!很!重!要! 这!很!重!要!
矩阵的感性意义在于它为我们提供了一种简洁、直观、有力的数学工具来描述和理解现实世界的复杂现象和变化规律。无论是组织数值、描述变换、简化计算还是数学建模和感性认知等方面,矩阵都发挥着不可替代的重要作用。而在游戏开发行业中,矩阵是你从小白到大神 无法绕过的必修课 之一!
矩阵,英文名是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[ M1,1M1,2M1,3M2,1M2,2M2,3M3,1M3,2M3,3
矩阵是线性代数的基础内容之一,在解决线性方程组时,可以将系数和常数写成一个矩阵,然后使用矩阵运算来求解方程组。在图形变换(如旋转、缩放、平移)中,也常常使用矩阵来表示这些变换。
矩阵包含多种运算,如加法、减法、惩罚、转置、逆运算等。
简单的说,矩阵一方面可以用来存储一个物体的位置、旋转、缩放信息;另一方面也可以通过矩阵的运算实现物体的平移、旋转、缩放;通过矩阵的应用,还能实现让一个模型上的每一个点一步步的通过矩阵运算最终变成屏幕上的一个点的坐标等。可以说如果要搞懂3D数学、Shader这类知识,矩阵是必不可少的。
在Unity中,矩阵(Matrix)扮演着至关重要的角色,特别是在处理物体的位置、旋转和缩放等变换时。以下是矩阵在Unity中的主要作用:
当然,如果没有线性代数基础的话看到这些可能会比较懵,毕竟连变换是干嘛的都不知道呢。如果想进一步了解变换,可以到文末的目录中去找对应的章节,我将会把这两篇文章都放在一起。
下面是一些基本的矩阵算法,可能会有些枯燥,建议先看懂,然后收藏,等需要的时候过来查询。等后面用多了自然就习惯了,而且很多时候这些运算是不需要人脑来计算的,我们只需要知道这些运算能起到什么作用即可。
几何意义:矩阵加减就是对矩阵列空间下的基向量做变换。在图形和图像处理中,矩阵常常用来表示像素值的数组。在这种情况下,矩阵的加法可以用来混合或叠加两个图像(例如,在图像叠加或透明度混合中)。矩阵的减法可以用来检测图像之间的差异或进行背景消除等操作。
先决条件:只有同型的矩阵(两个矩阵的行数和列数相同)才可以做加减法运算。
满足定律:矩阵加减满足交换律和结合律。
计算方法:矩阵加法一般是指两个矩阵把其相对应元素加在一起的运算,减法反之。
例如:
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
[
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[ 123−13222313
几何意义:矩阵与标量的乘法在几何上表示对矩阵所代表的向量或向量集合的缩放操作。
应用场景:
先决条件:没什么限制,随便乘。
满足定律:
计算方法:矩阵和标量的乘法非常简单,就是矩阵的每个元素和该标量相乘。
公式如下:
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
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[ M1,1M1,2M1,3M2,1M2,2M2,3M3,1M3,2M3,3
矩阵与矩阵相乘是十分重要的矩阵计算方法,在游戏开发过程中使用矩阵时大多数都是使用乘法。我们想要对物体做平移、旋转、缩放时基本都是使用矩阵乘法,与矩阵与标量相乘不同的是,标量只能进行统一的缩放或其他操作,而矩阵相乘允许我们在不同轴向上对物体做不等量的变换操作。
几何意义:
先决条件:第一个矩阵的列数必须和第二个矩阵的行数相同。
满足定律:
计算方法:假设我们有两个矩阵 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[ B1,1B1,2B1,3B1,4B2,1B2,2B2,3B2,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[ 105−102649−1
特殊性质:
举个例子,比如
[
1
2
3
4
5
6
]
∗
[
7
10
8
11
9
12
]
=
[
50
68
124
167
]
\left[ 123456
[
50
68
124
167
]
T
=
[
50
124
68
167
]
\left[ 5068124167
如果用
A
T
∗
B
T
A^{T} * B^{T}
AT∗BT 就相当于
[
1
4
2
5
3
6
]
∗
[
7
8
9
10
11
12
]
\left[ 142536
计算结果为
(
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[ 789101112
【划重点】 在《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[ 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[ 100−4
有什么用?
对称矩阵在多个领域都有广泛应用:
对角元素是指行号和列号相等的元素,例如 M 2 , 2 M_{2,2} M2,2, M 4 , 4 M_{4,4} M4,4等。这些元素刚好在正方形的对角线上,所以被称为对角元素。
如果一个矩阵中除了对角元素外其他元素全为 0 ,那么这个矩阵就叫做对角矩阵。
例如
[
4
0
0
0
0
1
0
0
0
0
−
3
0
0
0
0
12
]
\left[ 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[ 3250126001
单位矩阵是一个特殊的矩阵,用 I n I_{n} In 表示,一个 3 ∗ 3 3 * 3 3∗3 的单位矩阵如下:
[
1
0
0
0
1
0
0
0
1
]
\left[ 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)。
条件:
性质:
应用:
正交矩阵(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[ −−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[ c1·c1c1·c2c1·c3c2·c1c2·c2c2·c3c3·c1c3·c2c3·c3
=
[
1
0
0
0
1
0
0
0
1
]
=
I
\\= \left[ 100010001
可以得出 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
可以得出以下结论:
要建立一个坐标空间需要制定一组基矢量,也就是我们常说的坐标轴。如果这些基矢量之间是互相垂直的,那么我们就把它称为是一组正交基(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[ M1,1M1,2M1,3M2,1M2,2M2,3M3,1M3,2M3,3
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[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[ xM1,1yM1,2zM1,3xM2,1yM2,2zM2,3xM3,1yM3,2zM3,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学习笔记目录整理
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。