本文章用于帮助自己学习,因此只记录一些个人认为比较重要或者还不够熟悉的内容。
原作者:http://blog.csdn.net/candycat1992/article/
第四章 学习Shader所需的数学基础
4.1笛卡尔坐标系
4.1.1三维笛卡尔坐标系
3个坐标轴和一个原点,构成一个三维笛卡尔坐标系。
这3个坐标轴也被称为是该坐标系的基矢量(basis vector)。
3个坐标轴之间互相垂直,且长度为1的基矢量被称为标准正交基(orthonormal basis)。
互相垂直但长度不为1的基矢量被称为正交基(orthogonal basis)。
4.1.2左手坐标系和右手坐标系
举起左手,用食指和大拇指摆出一个“L”的 手势,并且让食指指向上大拇指指向右。伸出中指,指向前方。此时己经得到了一个左手坐标系了!大拇指、食指和中指分别对应了+x、+y和+z轴的方向,在右手坐标系中同理,如图所示。
除了坐标轴朝向不同之外,左手坐标系和右手坐标系对于正向旋转的定义也不同,即在初高 中物理中学到的左手法则(left-hand rule)和右手法则(right-hand rule)。
在左手坐标系中,应用左手法则:还是举起左手,握拳,伸出大拇指让它指向旋转轴的正方向,那么旋转的正方向就是剩下4个手指的弯曲方向。在右手坐标系中同理,如图所示。
4.1.3Unity使用的坐标系
在模型空间和世界空间,Unity使用的是左手坐标系。
在观察空间,Unity使用的是右手坐标系。这个坐标系中,摄像机的前向是z轴的负方向,z轴坐标的减少意味着场景深度的增加,如图所示。
4.2点和矢量
矢量是指n维空间中一种包含了模(magnitude)和方向(direction)的有 向线段。
- 矢量的模指的是这个矢量的长度。
- 矢量的方向则描述了这个矢量在空间中的指向。
表示方法:用v=(x,y,z)来表示三维矢量.
- 对于标量,我们使用小写字母来表示,如b, x, y, z, a等。
- 对于矢量,我们使用小写的粗体字母来表示,如a, b, u, v等。
通常,矢量被用于表示相对于某 个点的偏移(displacement),也就是说它是一个相对量。
4.2.1矢量运算
1.矢量的加法和减法
可以把矢量a的头连接到矢量b的尾,然后画一条从a 的尾到b的头的矢量,来得到a和b相加后的矢量。
想要计算点b相对于点a的位移,可以通过把b和a相减得到。
2.矢量的模
三维矢量模的计算公式:
3.单位矢量
在很多情况下,我们只关心矢量的方向而不是模。例如,在计算光照模型时,我们往往需要得到顶点的法线方向和光源方向,此时我们不关心这些矢量有多长。在这些情况下,我们就需要计算单位矢量(unit vector)。
单位矢量也被称为被归一化的矢量(normalized vector)o 对任何给定的非零矢量,把它转换成单位矢量的过程就被称为归一化(normalization)。
5.矢量的点积
矢量的两种乘法:点积(dot product*也被称为内积,inner product)和叉积(cross product,也被称为外积,outer product)。
点积的一个几何意义就是投影(projection )。
任何两个矢量的点积a·b等同于b在a方向上的投影值,再乘以a的长度。
很多情况下,只是需要比较两个矢量的长度大小,因此可以直接使用点积的结果。
公式二:
a-b=|a||b|cosθ
两个矢量的点积可以表示为两个矢量的模相乘,再乘以它们之间夹角的余弦值。
5.矢量的叉积
矢量叉积的结果仍是一个矢量,而非标量。
公式:
这个公式比较绕脑,我个人记住的方法是,结果矢量的每一个分量的值,就是向量a的它的后一个分量的值乘以向量b的剩下的一个分量的值,再减去向量b的它的后一个分量的值乘以向量a的剩下的一个分量的值。以x分量为例,它的后一个分量是y,除了x和y剩下的分量是z,因此就是ay乘以bz,再减去az乘以by。
对两个矢量进行叉积的结果会得到一个同时垂直于这两个矢量的新矢量。
axb的长度等于a和b的模的乘积再乘以它们之间夹角的正弦值。
axb的方向:
把手心放在 a和b的尾部交点处,然后张开手掌让手掌方向和a的方向重合,再弯曲四指让它们向b的方向靠拢,最后伸出大拇指,大拇指指向的方向就是右手坐标系中axb的方向了。
叉积的作用:
最常见的一个应用就是计算垂直于一个平面、三角形的矢量。另外,还可以用于判断三角面片的朝向。
4.3矩阵
是一个相对量。
4.3.1和矢量的联系
矢量可以看成是nx1的列矩阵(column matrix)或1xn的行矩阵(row matrix)。
4.3.2特殊的矩阵
1. 方块矩阵
方块矩阵(square matrix),简称方阵,是指那些行和列数目相等的矩阵。在三维渲染里,最常使用的就是3X3和4X4的方阵。
2. 单位矩阵
单位矩阵(identity matrix)用In表示,任何矩阵和它相乘的结果还是原来的矩 阵,一个3x3的单位矩阵如下:
3. 转置矩阵
转置矩阵(transposed matrix)实际是对原矩阵的一种运算,即转置运算。转置后,原矩阵的第i行变成了第i列,而第j列变成了第j行。
性质一:矩阵转置的转置等于原矩阵。
性质二:矩阵串接的转置,等于反向串接各个矩阵的转置,公式如下。
4. 逆矩阵
逆矩阵最重要的性质就是,如果我们把M和M^-1相乘,那么它们的结果将会是一个单位矩阵。
5. 正交矩阵
如果一个方阵 M和它的转置矩阵的乘积是单位矩阵的话,我们就说这个矩阵是正交的(orthogonal)。
如果一个矩阵是正交的,那么它的转置矩阵和逆矩阵是一样的。
根据正交矩阵的定义,有:
可以得出9个等式:
可以得出:
- 矩阵的每一行,即C1、C2和C3是单位矢量,因为只有这样它们与自己的点积才能是1;
- 矩阵的每一行,即C1、C2和C3之间互相垂直,因为只有这样它们之间的点积才能是0。
可以发现,一组标准正交基可以精确地满足上述条件。
一个坐标空间需要指定一组基矢量,也就是坐标轴。 如果这些基矢量之间是互相垂直的,那么我们就把它们称为是一组正交基(orthogonal basis)。如果它们的长度是1的话,我们就说它们是一组标准正交基(orthonormal basis)。因此,一个正交矩阵的行和列之间分别构成了一组标准正交基。
4.3.3行矩阵还是列矩阵
在Unity中,常规做法是把矢量放在矩阵的右侧,即把矢量转换成列矩阵来进行运算。
使用列向量的结果是,阅读顺序是从右到左,即先对v使用A进行变换,再使用B进行变换,最后使用C进行变换。
4.4矩阵的变换
4.4.1什么是变换
线性变换指的是那些可以保留矢量加和标量乘的变换。例如缩放(scale)和旋转(rotation)。
但是,平移变换满足标量乘法,但不满足矢量加法。
这样,就有了仿射变换(affine transform)仿射变换就是合并线性变换和平移变换的变换类型。仿射变换可以使用一个4x4的矩阵来表示,为此,我们需要把矢量扩展到四维空间下,这就是齐次坐标空间(homogeneous space)。
4.4.2齐次坐标
把矩阵扩展到了 4X4的矩阵,还需要把原来的三维矢量转换成四维矢量, 也就是齐次坐标(homogeneous coordinate)。
对于 一个点,从三维坐标转换成齐次坐标是把其w分量设为1,而对于方向矢量来说,需要把其w分量设为0。
这样的设置就会导致,当用一个4*4矩阵对一点进行变换时,平移、旋转、缩放都会施加于该点。但是如果是用于变换一个方向矢量,平移的效果就会被忽略。
4.4.3分解基础变换矩阵
一个基础变换矩阵可以分解成4个组成部分:
其中左上角的矩阵M(3x3)用于表示旋转和缩放,右上角的t(3x1)表示平移,左下角的 0(1x3) 是零矩阵,右下角的元素是标量1。
4.4.4 平移矩阵
可以使用矩阵乘法来表示对一个点进行平移变换:
如果对一个方向矢量进行平移变换,结果如下:
可以发现,平移变换不会对方向矢量产生任何影响。
平移矩阵的逆矩阵就是反向平移得到的矩阵,即:
可以看出,平移矩阵并不是一个正交矩阵。
4.4.5 缩放矩阵
我们可以对一个模型沿空间的X轴、y轴和z轴进行缩放。同样,我们可以使用矩阵乘法来 表示一个缩放变换:
对方向矢量可以使用同样的矩阵进行缩放:
缩放矩阵的逆矩阵是使用原缩放系数的倒数来对点或方向矢量进行缩放,即:
缩放矩阵一般不是正交矩阵.
4.4.6 旋转矩阵
如果我们需要把点绕着x轴旋转θ度,可以使用下面的矩阵:
y轴的可以使用如下矩阵:
z轴的可以使用如下矩阵:
旋转矩阵的逆矩阵是旋转相反角度得到的交换矩阵。旋转矩阵是正交矩阵,而且多个旋转矩阵之间的串联同样是正交的。
4.4.7 复合变换
在绝大多数情况下,约定变换的顺序就是先缩放,再旋转,最后平移。
当同时绕3个轴旋转时,需要定义一个旋转顺序。在Unity中,这个旋转顺序是zxy。
4.5坐标空间
我们需要在不同的情况下使用不同的坐标空间, 因为一些概念只有在特定的坐标空间下才有意义, 才更容易理解。
4.5.2 坐标空间的变换
每个坐标空间都是另一个坐标空间的子空间,反过来说,每个空间都有一个父(parent)坐标空间。对坐标空间的变换实际上就是在父空间和子空间之间对点和矢量进行变换。
4.5.3顶点的坐标空间变换过程
在渲染流水线中,一个顶点要经过多个坐标空间的变换才能最终被画在屏幕上。一 个顶点最开始是在模型空间中定义的,最后它将会变换到屏幕空间中,得到真正的 屏幕像素坐标。
4.5.4模型空间
模型空间(model space),如它的名字所暗示的那样,是和某个模型或者说是对象有关的。 有时模型空间也被称为对象空间(object space)或局部空间(local space)。
4.5.5世界空间
世界空间(world space)是一个特殊的坐标系,因为它建立了我们所关心的最大的空间。
顶点变换的第一步,就是将顶点坐标从模型空间变换到世界空间中。这个变换通常叫做模型变换(model transform)。
4.5.6观察空间
观察空间(view space)也被称为摄像机空间(camera space)。
Unity在模型空间和世界空间中选用的都是左手坐标系,而在观察空间中使用的是右手坐标系。
在观察空间中,摄像机位于原点,摄像机的正前方指向的是-z轴方向。
顶点变换的第二步,就是将顶点坐标从世界空间变换到观察空间中。这个变换通常叫做观察变换(view transform)。
4.5.7裁剪空间
顶点接下来要从观察空间转换到裁剪空间(clip space,也被称为齐次裁剪空间)中,这个用于变换的矩阵叫做裁剪矩阵(clip matrix),也被称为投影矩阵(projection matrix)。
4.5.8屏幕空间
经过投影矩阵的变换后,我们可以进行裁剪操作。当完成了所有的裁剪工作后,就需要进行真正的投影了,也就是说,我们需要把视锥体投影到屏幕空间(screen space)中。经过这一步变换,我们会得到真正的像素位置,而不是虚拟的三维坐标。
在Unity中,从裁剪空间到屏幕空间的转换是由Unity帮我们完成的。顶点着色器只需要把顶点转换到裁剪空间即可。
4.6法线变换
在游戏中,模型 的一个顶点往往会携带额外的信息,而顶点法线就是其中一种信息。当我们变换一个模型的时候, 不仅需要变换它的顶点,还需要变换顶点法线,以便在后续处理(如片元着色器)中计算光照等。
由于切线是由两个顶点之间的差值计算得到 的,因此我们可以直接使用用于变换顶点的变换矩阵M来变换切线。但如果直接使用M来变换法线,得到的新的法线方向可能就不会与表面垂直了,如图。
通过T·N=0可以推导出,使用原变换矩阵的逆转置矩阵来变换法线就可以得到正确的结果。
如果变换只包括旋转变换,那么这个变换矩阵就是正交矩阵。如果变换矩阵M是正交矩阵,那么可以使用用于变换顶点的变换矩阵来直接变换法线。
4.7Unity Shader的内置变量
本节将给出Unity内置的用于空间变换和摄像机以及屏幕参数的内置变量。这 些内置变量可以在UnityShaderVariables.cginc文件中找到定义和说明。
4.7.1变换矩阵
其中有一个矩阵比较特殊,即UNITY_MATRIX_T_MV矩阵。如果 UNITY_MATRIX_MV是一个正交矩阵的话,那么UNITY_MATRIX_T_MV就是它的逆矩阵,也 就是说,我们可以使用UNITY_MATRIX_T_MV把顶点和方向矢量从观察空间变换到模型空间。
可以截取UNITY_MATRIX_T_MV的前3行前3列来把方向矢量从观察空间变换到模型空间(前提是只存在旋转变换和统一缩放)。对于方向矢量,我们可以在使用前对它们进行归一化处理,来消除统一缩放的影响。
4.7.2摄像机和屏幕参数
4.8
- CG中,矩阵 乘法是通过mul函数实现的。
- 通常在变换顶点时,我们都是使用右乘的方式来按列 矩阵进行乘法。
- CG使用的是行优先的方法,即是一行一行地填充矩阵的。
- 当我们在CG中访问一个矩阵中的元素时,也是按行来索引的。