Unity系列文章目录

文章目录

  • Unity系列文章目录
  • 前言
  • 点和矢量
    • 4.3.1 点和矢量的区别
  • 参考

前言

点(point)是n 维空间(游戏中主要使用二维和三维空间)中的一个位置,它没有大小、宽度这类概念。在笛卡儿坐标系中,我们可以使用2 个或3 个实数来表示一个点的坐标,如:P=(Px,
Py),表示二维空间的点,P=(Px, Py,Pz)表示三维空间中的点。
矢量(vector,也被称为向量)的定义则复杂一些。在数学家看来,矢量就是一串数字。你
可能要问了,点的表达式不也是一串数字吗?没错,但矢量存在的意义更多是为了和标量(scalar)
区分开来。通常来讲,矢量是指n 维空间中一种包含了模(magnitude)和方向(direction)的有
向线段,我们通常讲到的速度(velocity)就是一种典型的矢量。例如,这辆车的速度是向南80km/h
(向南指明了矢量的方向,80km/h 指明了矢量的模)。而标量只有模没有方向,生活中常常说到
的距离(distance)就是一种标量。例如,我家离学校只有200 米(200 米就是一个标量)。
具体来讲。
 矢量的模指的是这个矢量的长度。一个矢量的长度可以是任意的非负数。
 矢量的方向则描述了这个矢量在空间中的指向。
矢量的表示方法和点类似。我们可以使用v=(x,y)来表示二维矢量,用v=(x,y,z)来表示三维矢
量,用v=(x,y,z,w)来表示四维矢量。
为了方便阐述,我们对不同类型的变量在书写和印刷上使用不同的样式:
 对于标量,我们使用小写字母来表示,如a,b,x,y,z,,等;
 对于矢量,我们使用小写的粗体字母来表示,如a,b,u,v 等;
 对于后面要学习的矩阵,我们使用大写的粗体字母来表示,如A,B,S,M,R 等。
在图4.15 中,一个矢量通常由一个箭头来表示。我们有时会讲到一个矢量的头(head)和尾
(tail)。矢量的头指的是它的箭头所在的端点处,而尾指的是另一个端点处,如图4.15 所示。
那么一个矢量要放在哪里呢?从矢量的定义来看,它只有模和方向两个属性,并没有位置信
息。这听起来很难理解,但实际上在生活中我们总是会和这样的矢量打交道。例如,当我们讲到
一个物体的速度时,可能会这样说“那个小偷正在以100km/h 的速度向南逃窜”(快抓住他!),
这里的“以100km/h 的速度向南”就可以使用一个矢量来表示。通常,矢量被用于表示相对于某
个点的偏移(displacement),也就是说它是一个相对量。只要矢量的模和方向保持不变,无论放
在哪里,都是同一个矢量。

点和矢量

4.3.1 点和矢量的区别

回顾一下,点是一个没有大小之分的空间中的位置,而矢量是一个有模和方向但没有位置的
量。从这里看,点和矢量具有不同的意义。但是,从表示方式上两者非常相似。
在上一节中我们提到,矢量通常用于描述偏移量,因此,它们可以用于描述相对位置,即相
对于另一个点的位置,此时矢量的尾是一个位置,那么矢量的头就可以表示另一个位置了。而一
个点可以用于指定空间中的一个位置(即相对于原点的位置)。如果我们把矢量的尾固定在坐标系
原点,那么这个矢量的表示就和点的表示重合了。图4.16 表示了两者之间的关系。

尽管上面的内容看起来显而易见,但区分点和矢量之间的不同是非常重要的,尽管它们在数
学表达式上是一样的,都是一串数字而已。如果一定要给它们之间建立一个联系的话,我们可以
认为,任何一个点都可以表示成一个从原点出发的矢量。为了明确点和矢量的区别,在本书后面
的内容中,我们将用于表示方向的矢量称为方向矢量。
4.3.2 矢量运算
在下面的内容里,我们将给出一些最常见的矢量运算。幸运的是,这些运算大都很好理解。
对于每种运算,我们会先给出数学上的描述,然后再给出几何意义上的解释。同样,为了让读者
加深印象,我们会在最后给出一些练习题。相信读完本节后,你一定可以快速地解决它们!
1.矢量和标量乘法/除法
还记得吗?标量是只有模没有方向的量,虽然我们不能把矢量和标量进行相加/相减的运算
(想象一下,你会把速度和距离相加吗),但可以对它们进行乘法运算,结果会得到一个不同长度
且可能方向相反的新的矢量。
公式非常简单,我们只需要把矢量的每个分量和标量相乘即可:
kv=(kvx,kvy, kvz)
类似的,一个矢量也可以被一个非零的标量除。这等同于和这个标量的倒数相乘:
v
k
 (x, y, z)
k
 1
k
(x, y, z)  x
k
, y
k
, z
k

 

 
,k  0
下面给出一些例子:
2(1,2,3)=(2,4,6)
−3.5(2, 0)=(−7, 0)
(1,2,3)
2
 (0.5,1,1.5)
注意,对于乘法来说,矢量和标量的位置可以互换。但对于除法,只能是矢量被标量除,而
不能是标量被矢量除,这是没有意义的。
从几何意义上看,把一个矢量v 和一个标量k 相乘,意味着对矢量v 进行一个大小为|k|的缩
放。例如,如果想要把一个矢量放大两倍,就可以乘以2。当k<0 时,矢量的方向也会取反。图
4.17 显示了这样的一些例子。
2.矢量的加法和减法
我们可以对两个矢量进行相加或相减,其结果是一个相同维度的新矢量。
我们只需要把两个矢量的对应分量进行相加或相减即可。公式如下:
a+b=(ax+bx,ay+by, az+bz)
a–b=(ax−bx,ay-by, az−bz)
下面是一些例子:
(1,2,3)+(4,5,6)=(5,7,9)
(5,2,7) − (3,8,4)=(2, −6,3)
需要注意的是,一个矢量不可以和一个标量相加或相减,或者是和不同维度的矢量进行运算。
从几何意义上来看,对于加法,我们可以把矢量a 的头连接到矢量b 的尾,然后画一条从a
的尾到b 的头的矢量,来得到a 和b 相加后的矢量。也就是说,如果我们从一个起点开始进行了
一个位置偏移a,然后又进行一个位置偏移b,那么就等同于进行了一个a+b 的位置偏移。这被称为矢量加法的三角形定则(triangle rule)。矢量的减法是类似的。如图4.18 所示。


读者需要时刻谨记,在图形学中矢量通常用于描述位置偏移(简称位移)。因此,我们可以利
用矢量的加法和减法来计算一点相对于另一点的位移。
假设,空间内有两点a 和b。还记得吗,我们可以用矢量a 和b 来表示它们相对于原点的位
移。如果我们想要计算点b 相对于点a 的位移,就可以通过把b 和a 相减得到,如图4.19 所示。
3.矢量的模
正如我们之前讲到的一样,矢量是有模和方向的。矢量的模是一个标量,可以理解为是矢量
在空间中的长度。它的表示符号通常是在矢量两旁分别加上一条垂直线(有的文献中会使用两条
垂直线)。三维矢量的模的计算公式如下:
|v|= 2 2 2
vx  vy  vz
其他维度的矢量的模计算类似,都是对每个分量的平方相加后再开根号得到。
下面给出一些例子:
| (1, 2,3) | 12  22  32  1 4  9  14  3.742
| (3, 4) | 32  42  9 16  25  5
我们可以从几何意义来理解上述公式。对于二维矢量来说,我们可以对任意矢量构建一个三
角形,如图4.20 所示。


从图4.20 可以看出,对于二维矢量,其实就是使用了勾股定理,矢量的两个分量的绝对值对
应了三角形两个直角边的长度,而斜边的长度就是矢量的模。
4.单位矢量
在很多情况下,我们只关心矢量的方向而不是模。例如,在计算光照模型时,我们往往需要
得到顶点的法线方向和光源方向,此时我们不关心这些矢量有多长。在这些情况下,我们就需要
计算单位矢量(unit vector)。
单位矢量指的是那些模为1 的矢量。单位矢量也被称为被归一化的矢量(normalized vector)。
对任何给定的非零矢量,把它转换成单位矢量的过程就被称为归一化(normalization)。
给定任意非零矢量v,我们可以计算和v 方向相同的单位矢量。在本书中,我们通过在一个
矢量的头上添加一个戴帽符号来表示单位矢量,例如^ v 。为了对矢量进行归一化,我们可以用矢
量除以该矢量的模来得到。公式如下:
^ =
| |
v v
v
,v 是任意非零矢量
下面给出一些例子:
(3,4)
| (3,4) |
 (3,4)
32  (4)2
 (3,4)
25
 (3,4)
5
 3
5
, 4
5

 

 
 (0.6,0.8)
零矢量(即矢量的每个分量值都为0,如v=(0,0,0))是不可以被归一化的。这是因为做除法
运算时分母不能为0。
从几何意义上看,对二维空间来说,我们可以画一个单位圆,
那么单位矢量就可以是从圆心出发、到圆边界的矢量。在三维空
间中,单位矢量就是从一个单位球的球心出发、到达球面的矢量。
图4.21 给出了二维空间内的一些单位矢量。
需要注意的是,在后面的章节中我们将会不断遇到法线方向
(也被称为法矢量)、光源方向等,这些矢量不一定是归一化后
的矢量。由于我们的计算往往要求矢量是单位矢量,因此在使用
前应先对这些矢量进行归一化运算。
5.矢量的点积
矢量之间也可以进行乘法,但是和标量之间的乘法有很大不同。矢量的乘法有两种最常用的
种类:点积(dot product,也被称为内积,inner product)和叉积(cross product,也被称为外
积,outer product)。在本节中,我们将讨论第一种类型:点积。
读者可能认为上面几节的内容都很简单,“这些都显而易见嘛”。那么从这一节开始,我们就
会遇到一些真正需要花费力气(真的只要一点点)去记忆的公式。幸运的是,绝大多数公式是有
几何意义的,也就是说,我们可以通过画图的方式来理解和帮助记忆。
比仅仅记住这些公式更加重要的是,我们要真正理解它们是做什么的。只有这样,我们才能
在需要时想起来,“噢,这个需求我可以用这个公式来实现!”在我们编写Shader 的过程中,通常
程序接口都会提供这些公式的实现,因此我们往往不需要手工输入这些公式。例如,在Unity Shader
中,我们可以直接使用形如dot(a, b)的代码来对两个矢量值进行点积的运算。
点积的名称来源于这个运算的符号:a·b。中间的这个圆点符号是不可以省略的。点积的公式
有两种形式,我们先来看第一种。两个三维矢量的点积是把两个矢量对应分量相乘后再取和,最
后的结果是一个标量。
公式一:
a·b=(ax, ay, az) ·(bx, by, bz)= axbx+ ayby+azbz


下面是一些例子:
(1,2,3) ·(0.5,4,2.5)=0.5+8+7.5=16
(−3,4,0)·(5, −1,7)= −15+−4+0=−19
矢量的点积满足交换律,即a·b=b·a
点积的几何意义很重要,因为点积几乎应用到了图形学的各个方面。其中一个几何意义就是
投影(projection)。
假设,有一个单位矢量^a 和另一个长度不限的矢量b。现在,我们希望得到b 在平行于^a 的
一条直线上的投影。那么,我们就可以使用点积^a ·b 来得到b 在^a 方向上的有符号的投影。
那么,投影到底是什么意思呢?这里给出一个通俗的解释。我们可以认为,现在有一个光源,
它发出的光线是垂直于^a 方向的,那么b 在^a 方向上的投影就是b 在^a 方向上的影子,如图4.22
所示。
需要注意的是,投影的值可能是负数。投影结果的正负号与^a 和b 的方向有关:当它们的方
向相反(夹角大于90°)时,结果小于0;当它们的方向互相垂直(夹角为90°)时,结果等于0;
当它们的方向相同(夹角小于90°)时,结果大于0。图4.23 给出了这3 种情况的图示。

也就是说,点积的符号可以让我们知道两个矢量的方向关系。
那么,如果^a 不是一个单位矢量会如何呢?这很容易想到,任何两个矢量的点积a·b 等同于b
在a 方向上的投影值,再乘以a 的长度。
点积具有一些很重要的性质,在Shader 的计算中,我们会经常利用这些性质来帮助计算。
性质一:点积可结合标量乘法。
上面的“结合”是说,点积的操作数之一可以是另一个运算的结果,即矢量和标量相乘的结
果。公式如下:
(ka)·b= a·(kb)=k(a·b)
也就是说,对点积中其中一个矢量进行缩放的结果,相当于对最后的点积结果进行缩放。
性质二:点积可结合矢量加法和减法,和性质一类似。
这里的“结合”指的是,点积的操作数可以是矢量相加或相减后的结果。用公式表达就是:
a·(b+ c)= a·b+ a·c
把上面的c 换成−c 就可以得到减法的版本。
性质三:一个矢量和本身进行点积的结果,是该矢量的模的平方。
这点可以很容易从公式验证得到:
v·v=vxvx+ vyvy+ vzvz=|v|2
这意味着,我们可以直接利用点积来求矢量的模,而不需要使用模的计算公式。当然,我们
需要对点积结果进行开平方的操作来得到真正的模。但很多情况下,我们只是想要比较两个矢量
的长度大小,因此可以直接使用点积的结果。毕竟,开平方的运算需要消耗一定性能。
现在是时候来看点积的另一种表示方法了。这种方法是从三角代数的角度出发的,这种表示
方法更加具有几何意义,因为它可以明确地强调出两个矢量之间的角度。
我们先直接给出第二个公式。
公式二:
a·b=|a||b|cos
初看之下,似乎和公式一没有什么联系,怎么会相等呢?我们先来看最简单的情况。假设,
我们对两个单位矢量进行点积,即^a · ^b ,如图4.24 所示。
到了产生魔法的时间了!我们知道^ b 的模为1,且读者应
该记得cos =
邻边
斜边
。我们可以发现,图中^a · ^ b 的结果刚好就
是cos 对应的直角边。因此,由图4.24 可以得到:
^a · ^ b =
邻边
斜边
=cos
这也就是说,两个单位矢量的点积等于它们之间夹角的
余弦值。再应用性质一就可以得到公式二了:
a·b=(|a| ^a )·(|b| ^ b )=|a||b|( ^a · ^ b )=|a||b|cos
也就是说,两个矢量的点积可以表示为两个矢量的模相乘,再乘以它们之间夹角的余弦值。
从这个公式也可以看出,为什么计算投影时两个矢量的方向不同会得到不同符号的投影值:当夹
角小于90°时,cos>0;当夹角等于90°时,cos=0;当夹角大于90°时,cos<0。
利用这个公式我们还可以求得两个向量之间的夹角(在0°~180°):
=arcos( ^a · ^ b ),假设^a 和^ b 是单位矢量。
其中,arcos 是反余弦操作。
6.矢量的叉积
另一个重要的矢量运算就是叉积(cross product),也被称为外积(outer product)。与点积
不同的是,矢量叉积的结果仍是一个矢量,而非标量。
和点积类似,叉积的名称来源于它的符号:a×b。同样,这个叉号也是不可省略的。两个矢
量的叉积可以用如下公式计算:
a×b=(ax, ay, az)×(bx, by, bz)=(aybz−azby, azbx−axbz, axby−aybx)
上面的公式看起来很复杂,但其实是有一定规律的。图4.25 给出了这样的规律图示。
▲图4.25 三维矢量叉积的计算规律。不同颜色的线表示了计算结果矢量中对应颜色的分量的计算路径。
以红色为例,即结果矢量的第一个分量,它是从第一个矢量的y 分量出发乘以第二个矢量的z 分量,
再减去第一个矢量的z 分量和第二矢量的y 分量的乘积



例如:
(1,2,3)×(−2, −1,4)=((2)(4) − (3)(−1),(3)(−2) − (1)(4),(1)(−1)−(2)(−2))
=(8−(−3),(−6)−4,(−1)−(−4))=(11,−10,3)
需要注意的是,叉积不满足交换律,即a×b≠b×a。实际上,叉积是满足反交换律的,即
a×b=−(b×a)。而且叉积也不满足结合律,即 (a×b) ×c≠a×(b×c)。
从叉积的几何意义出发,我们可以更加深入地理解它的用处。对两个矢量进行叉积的结果会
得到一个同时垂直于这两个矢量的新矢量。我们已经知道,矢量是由一个模和方向来定义的,那
么这个新的矢量的模和方向是什么呢?
我们先来看它的模。a×b 的长度等于a 和b 的模的乘积再乘以它们之间夹角的正弦值。公式
如下:
|a×b|=|a||b|sin
读者可能已经发现,上述公式和点积的计算公式很类似,不同的是,这里使用的是正弦值。
如果读者对中学数学还有记忆的话,可能还会发现,这和平行四边形的面积计算公式是一样的。
如果你忘记了,没关系,我们在这里回忆一下。
如图4.26 所示,我们使用a 和b 构建一个平行四边形。
我们知道,平行四边形的面积可以使用|b|h 来得到,即底乘以高。而h 又可以使用|a|和夹角
来得到,即
A=|b|h=|b|(|a|sin)=|a||b|sin=|a×b|
你可能会问,如果a 和b 平行(可以是方向完全相同,也可以是完全相反)怎么办,不就不
能构建平行四边形了吗?我们可以认为构建出来的平行四边形面积为0,那么a×b=0。注意,这
里得到的是零向量,而不是标量0。
下面,我们来看结果矢量的方向。你可能会说:“方向?不是已经说了方向了嘛,就是和两个
矢量都垂直就可以了啊。”但是,如果你仔细想一下就会发现,实际上我们有两个方向可以选择,
这两个方向都和这两个矢量垂直。那么,我们要选择哪个方向呢?
这里就要和之前提到的左手坐标系和右手坐标系联系起来了,如图4.27 所示。

这个结果是怎么得到的呢?来,举起你的双手!哦,不……先举起你的右手。在右手坐标系
中,a×b 的方向将使用右手法则来判断。我们先想象把手心放在了a 和b 的尾部交点处,然后张
开你的手掌让手掌方向和a 的方向重合,再弯曲你的四指让它们向b 的方向靠拢,最后伸出你的
大拇指!大拇指指向的方向就是右手坐标系中a×b 的方向了。如果你实在不明白怎么摆放和扭动
你的手,那么就看图4.28 好了。

同理,我们可以使用左手法则来判断左手坐标系中
a×b 的方向。赶紧举起你的左手试试吧(你可能会发现
这个姿势比较扭曲)!
需要注意的是,虽然看起来左右手坐标系的选择会
影响叉积的结果,但这仅仅是“看起来”而已。从叉积
的数学表达式可以发现,使用左手坐标系还是右手坐标
系不会对计算结果产生任何影响,它影响的只是数字在
三维空间中的视觉化表现而已。当从右手坐标系转换为
左手坐标系时,所有点和矢量的表达和计算方式都会保
持不变,只是当呈现到屏幕上时,我们可能会发现,“咦,
怎么图像反过来了!”。当我们想要两个坐标系达到同样
的视觉效果时,可能就需要改变一些数学运算公式,这
不在本书的范畴内。有兴趣的读者可以参考本章的扩展
阅读部分。
那么,叉积到底有什么用呢?最常见的一个应用就是计算垂直于一个平面、三角形的矢量。
另外,还可以用于判断三角面片的朝向。读者可以在本节的练习题中找到这些应用。

参考

Unity Shader入门精要
作者:冯乐乐

Unity Shader入门精要--第4 章 学习Shader 所需的数学基础:点和矢量相关推荐

  1. Unity Shader入门精要--第4 章 学习Shader 所需的数学基础

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 4.1 背景:农场游戏 4.2 笛卡儿坐标系 4.2.2 三维笛卡儿坐标系 4.2.3 左手坐标系和右手坐标系 4.2.4 Unity ...

  2. Unity Shader入门精要第七章 基础纹理之遮罩纹理

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.实践 参考 前言 遮罩纹理(mask texture)是本章要介绍的最后一种纹理,它非常有用,在很多商业游戏中 都可以见到它的身影. ...

  3. Unity Shader入门精要第四章:学习Shader 所需的数学基础--坐标空间

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.4.6.1 为什么要使用这么多不同的坐标空间 二.4.6.3 顶点的坐标空间变换过程 4.6.4 模型空间 4.6.6 观察空间 4 ...

  4. Unity Shader入门精要——第3章 Unity Shader基础

    Unity Shader入门精要读书笔记系列 第1章 欢迎来到Shader的世界 第2章 渲染流水线 第3章 Unity Shader基础 文章目录 Unity Shader入门精要读书笔记系列 前言 ...

  5. Unity Shader入门精要第3 章 Unity Shader 基础

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.Unity Shader 概述 二.使用步骤 1.3.1.2 Unity 中的材质 2.Unity 中的Shader 3.Unity ...

  6. Unity Shader入门精要第七章 基础纹理 凹凸映射之在世界空间下计算

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.pandas是什么? 二.使用步骤 2.Unity 中的法线纹理类型 参考 前言 现在,我们来实现第二种方法,即在世界空间下计算光照 ...

  7. Unity Shader入门精要第七章 基础纹理渐变纹理

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.渐变纹理是什么 参考 前言 尽管在一开始,我们在渲染中使用纹理是为了定义一个物体的颜色,但后来人们发现,纹理 其实可以用于存储任何表 ...

  8. Unity Shader入门精要 第4章 笛卡尔坐标系 读书笔记

    第4章 学习Shader所需的数学基础-笛卡尔坐标系 注意:图片的来源基本来自作者冯乐乐的GitHub,感谢作者分享 https://github.com/candycat1992/Unity_Sha ...

  9. TA课程笔记01——光照(主要为shader入门精要第六章)

    //老师在这里简单的简述了一下渲染流水线,我在之前的图形学笔记中很详细的讲述了渲染流水线的过程,便不再赘述 //因为老师很详细的将几种常见的光照模型都讲了一遍,但都是美术方向,前面的案例也都缺少代码, ...

最新文章

  1. 修改Ubuntu的启动logo
  2. gatsby_将您的GraphCMS数据导入Gatsby
  3. 图像处理、语音处理的应用及前沿技术_华北工控:工业平板电脑在智慧医院中的广泛应用...
  4. SQLSERVER2005登录时出错
  5. ASP.NET MVC 学习1
  6. App 不想被“点名”,mPaaS 隐私合规检测为开发者护航数字生态建设
  7. Struts1工作原理
  8. Linux环境变量详解
  9. oracle设置缓冲区大小设置,描述Oracle优化库高速缓冲区
  10. 如何将一个字典转换为玲阶矩阵_每日一课 | Python循环字典
  11. 云计算的核心技术,主要有哪些?
  12. JavaWeb笔记(一)Java网络编程
  13. AllenNLP框架学习笔记(数据篇之一)
  14. android正反面切换,普通安卓手机数据线可以正反插吗?你一定猜错了
  15. python 爬取微博展开全文数据 BeautifulSoup
  16. Flex富文本编辑器
  17. 浙江环宇集团“营改增”项目启动会成功举办
  18. 路由 IS-IS NSR
  19. 文笔极佳的郭靖夫妇悼文
  20. 数据结构-算法题分享1

热门文章

  1. 基于Bandersnatch搭建本地pypi源
  2. 学习、生活、工作心得记录
  3. 推荐手机H5应用快速开发 UI库(Framework7、SUI(淘宝)、MUI、WeUI(微信)、GMU(百度)、Frozen UI(QQ))
  4. flexslider 轮播图片
  5. 新单位工作一个月了,应该写点东西总结一下了
  6. HNU-电子测试平台与工具-三人表决器实验报告
  7. 关于函数strtok和strtok_r的使用要点和实现原理(一)
  8. css选择器 :nth-of-type(1)、:nth-child(1)、:first-child、 :first-of-type
  9. 性能测试之MySQL的监控
  10. JavaScript学习笔记——编写战舰游戏 Part2:JavaScript部分