Unity Shader入门精要个人学习笔记
Unity Shader入门精要
渲染流水线
数学基础
1.点和矢量
类型 | 定义 | 表达 | 含义 | 性质 |
---|---|---|---|---|
点(point) | 点 (point) 是n 维空间(游戏中主要使用二维和三维空间)中的一个位置,它没有大小、宽度这类概念。 | |||
矢量(vector) | 是指n 维空间中一种包含了模 (magnitude) 和方向 (direction) 的有向线段 | 小写的粗体字母 | 矢量被用于表示相对于某个点的偏移 (displacement) ,也就是说它是一个相对量。只要矢量的模和方向保持不变,无论放在哪里,都是同一个矢量。 | |
标量(scalar) | 只有长度没有方向 | 小写字母 | ||
矩阵(matrix) | 它是由m ×n 个标量组成的长方形数组。 | 大写的粗体字母 | 性质一:矩阵乘法并不满足交换律。性质二:矩阵乘法满足结合律。(AB )C =A (BC ) |
2.矢量运算
1.矢量与标量
方法 | 公式 | 注释 |
---|---|---|
乘法 | kv =(kvx ,kvy , kvz ) | |
除法 | 一个矢量也可以被一个非零的标量除。这等同于和这个标量的倒数相乘: |
2.矢量与矢量
方法 | 公式 | 注释 | 应用 | 性质 |
---|---|---|---|---|
加减 | 对应分量进行相加或相减(三角形定则(triangle rule) | 可以利用矢量的加法和减法来计算一点相对于另一点的位移。 | ||
点积(dot product) | a ·b =(ax , ay , az ) ·(bx , by , bz )= ax bx + ay by +az bz | 几何意义就是投影 (projection) | 两个矢量对应分量相乘后再取和,最后的结果是一个标量。 | 性质一:点积可结合标量乘法。 (k a )·b = a ·(k b )=k (a ·b ) 性质二:点积可结合矢量加法和减法,和性质一类似。性质三:一个矢量和本身进行点积的结果,是该矢量的模的*方a ·b =|a ||b |cosθ;两个单位矢量的点积等于它们之间夹角的余弦值。 |
叉积(cross product) | a ×b =(ax , ay , az )×(bx , by , bz )=(ay bz −az by , az bx −ax bz , ax by −ay bx ) | 叉积不满足交换律和结合律,即a ×b≠b×a;但是满足反交换律;它的模。a ×b 的长度等于a 和b 的模的乘积再乘以它们之间夹角的正弦值 | 它的模。a ×b 的长度等于a 和b 的模的乘积再乘以它们之间夹角的正弦值。公式如下: |
|a×b |=|a ||b |sinθ |
点A到点B的向量C=B-A
在渲染中我们时常会需要判断一个三角面片是正面还是背面,这可以通过判断三角形的3个顶点在当前空间中是顺时针还是逆时针排列来得到。
在三维空间中,可以通过以下步骤使用叉积判断三角形的方向:
-
构建向量
- 已知三角形的三个顶点ABC
- 构建向量AB和AC。
-
计算叉积
- 计算和的叉积,根据叉积公式可得:
-
根据叉积结果判断方向
- 右手坐标系:如果使用的是右手坐标系,当得到的向量与设定的观察方向一致(例如从某个方向观察,叉积结果向量指向观察者),则三角形的顶点顺序是逆时针方向,此时看到的是三角形的正面;如果叉积结果向量与观察方向相反,则顶点顺序是顺时针方向,看到的是三角形的背面。
- 左手坐标系:在左手坐标系中,情况则相反。当得到的向量与观察方向一致时,三角形的顶点顺序是顺时针方向,为三角形的正面;叉积结果向量与观察方向相反时,顶点顺序是逆时针方向,为三角形的背面。
3.矢量的模
|v |=
4.单位矢量
单位矢量指的是那些模为1的矢量。单位矢量也被称为被归一化的矢量 (normalized vector) 。对任何给定的非零矢量,把它转换成单位矢量的过程就被称为归一化 (normalization)
5.零向量
零矢量 (即矢量的每个分量值都为0,如v =(0,0,0))是不可以被归一化的。这是因为做除法运算时分母不能为0。
3.矩阵运算
1.矩阵和标量的乘法
矩阵的每个元素和该标量相乘。
2.矩阵和矩阵的乘法
一个r ×n 的矩阵A 和一个n ×c 的矩阵B 相乘,它们的结果AB 将会是一个r ×c 大小的矩阵。
行列关系:第一个矩阵的列数必须和第二个矩阵的行数相同,它们相乘得到的矩阵的行数是第一个矩阵的行数,而列数是第二个矩阵的列数。
总结:设有r ×n 的矩阵A 和一个n ×c 的矩阵B ,它们相乘会得到一个r ×c 的矩阵C =AB 。那么,C 中的每一个元素cij 等于A 的第i 行所对应的矢量和B 的第j 列所对应的矢量进行矢量点乘的结果
4.特殊矩阵
1.方块矩阵(square matrix)
如果一个矩阵除了对角元素外的所有元素都为0,那么这个矩阵就叫做对角矩阵 (diagonal matrix)
特性:
1.对角元素 (diagonal elements):行号和列号相等的元素
2.单位矩阵(identity matrix),用I n 来表示。
特性:任何矩阵和它相乘的结果都还是原来的矩阵:MI =IM =M
3.转置矩阵 (transposed matrix),对原矩阵的一种运算,即转置运算
特性:给定一个r ×c 的矩阵M ,它的转置可以表示成M T ,这是一个c ×r 的矩阵
性质一:矩阵转置的转置等于原矩阵。(M T ) T =M
性质二:矩阵串接的转置,等于反向串接各个矩阵的转置。(AB ) T =B T A T
4.逆矩阵(inverse matrix)
特性:不是所有的矩阵都有逆矩阵,第一个前提就是,该矩阵必须是一个方阵。
给定一个方阵M ,它的逆矩阵用M −1 来表示。逆矩阵最重要的性质就是,如果我们把M 和M -1 相乘,那么它们的结果将会是一个单位矩阵。也就是说,
MM −1 = M −1 M =I
如果一个矩阵有对应的逆矩阵,我们就说这个矩阵是可逆的 (invertible) 或者说是非奇异的 (nonsingular) ;相反的,如果一个矩阵没有对应的逆矩阵,我们就说它是不可逆的 (noninvertible) 或者说是奇异的 (singular)
如果一个矩阵的行列式 (determinant) 不为0,那么它就是可逆的。
性质一:逆矩阵的逆矩阵是原矩阵本身。
假设矩阵M 是可逆的,那么(M −1 )−1 =M
性质二:单位矩阵的逆矩阵是它本身。即I −1 =I
性质三:转置矩阵的逆矩阵是逆矩阵的转置。即(M T )−1 =(M −1 ) T
性质四:矩阵串接相乘后的逆矩阵等于反向串接各个矩阵的逆矩阵。即(AB )−1 =B −1 A −1
这个性质也可以扩展到更多矩阵的连乘,如:(ABCD )−1 =D −1 C −1 B −1 A −1
几何意义:
如果我们使用变换矩阵M 对矢量v 进行了一次变换,然后再使用它的逆矩阵M −1 进行另一次变换,那么我们会得到原来的矢量。这个性质可以使用矩阵乘法的结合律很容易地进行证明:
M −1 (Mv )=(M −1 M)v=Iv =v
5.正交矩阵 (orthogonal matrix)
特性:
如果一个方阵M 和它的转置矩阵的乘积是单位矩阵的话,我们就说这个矩阵是正交的 (orthogonal) 。反过来也是成立的。也就是说,矩阵M 是正交的等价于:
MM T = M T M =I
如果一个矩阵是正交的,那么它的转置矩阵和逆矩阵是一样的。也就是说,矩阵M 是正交的等价于: M T =M −1
一个矩阵满足上面的条件,那么它就是一个正交矩阵。结论:
矩阵的每一行,即c 1 、c 2 和c 3 是单位矢量,因为只有这样它们与自己的点积才能是1;
矩阵的每一行,即c 1 、c 2 和c 3 之间互相垂直,因为只有这样它们之间的点积才能是0。
上述两条结论对矩阵的每一列同样适用,因为如果M 是正交矩阵的话,M T 也会是正交矩阵。
在Unity中,常规做法是把矢量放在矩阵的右侧,即把矢量转换成列矩阵来进行运算。
使用列向量的结果是,我们的阅读顺序是从右到左,即先对v 使用A 进行变换,再使用B 进行变换,最后使用C 进行变换。
上面的计算等价于下面的行矩阵运算:
线性变换 (linear transform)
线性变换指的是那些可以保留矢量加和标量乘的变换。用数学公式来表示这两个条件就是:
f (x )+f (y )=f(x +y )
k f (x )=f (k x )
1.缩放(scale)
2.旋转(rotation)
3.错切 (shear)
4.镜像 (mirroring, 也被称为 reflection)
5.正交投影 (orthographic projection)等
仿射变换 (affine transform)
仿射变换就是合并线性变换和*移变换的变换类型。仿射变换可以使用一个4×4的矩阵来表示,为此,我们需要把矢量扩展到四维空间下,这就是齐次坐标空间 (homogeneous space) 。
常见的变换种类和它们的特性(N表示不满足该特性,Y表示满足该特性)
变换名称 | 是线性变换吗 | 是仿射变换吗 | 是可逆矩阵吗 | 是正交矩阵吗 |
---|---|---|---|---|
*移矩阵 | N | Y | Y | N |
绕坐标轴旋转的旋转矩阵 | Y | Y | Y | Y |
绕任意轴旋转的旋转矩阵 | Y | Y | Y | Y |
按坐标轴缩放的缩放矩阵 | Y | Y | Y | N |
错切矩阵 | Y | Y | Y | N |
镜像矩阵 | Y | Y | Y | Y |
正交投影矩阵 | Y | Y | N | N |
透视投影矩阵 | N | N | N | N |
齐次坐标(homogeneous coordinate)
三维矢量转换成齐次坐标(一个4×4的矩阵来表示*移、旋转和缩放)
分解基础变换矩阵
左上角的矩阵M 3×3 用于表示旋转和缩放,t 3×1 用于表示*移,0 1×3 是零矩阵,即0 1×3 =[0 0 0],右下角的元素就是标量1
1.*移矩阵
矩阵乘法来表示对一个点进行*移变换
*移矩阵的逆矩阵就是反向*移得到的矩阵,即
可以看出,*移矩阵并不是一个正交矩阵。
2.缩放矩阵
矩阵乘法来表示一个缩放变换
对方向矢量可以使用同样的矩阵进行缩放:
如果缩放系数kx =ky =kz ,我们把这样的缩放称为统一缩放 (uniform scale) ,否则称为非统一缩放 (nonuniform scale) 。
缩放矩阵的逆矩阵是使用原缩放系数的倒数来对点或方向矢量进行缩放,即
缩放矩阵一般不是正交矩阵。
3.旋转矩阵
把点绕着x 轴旋转θ 度
绕y 轴的旋转也是类似的:
绕z 轴的旋转:
旋转矩阵的逆矩阵是旋转相反角度得到的变换矩阵。旋转矩阵是正交矩阵,而且多个旋转矩阵之间的串联同样是正交的。
复合变换
例如,可以对一个模型先进行大小为(2, 2, 2)的缩放,再绕y 轴旋转30°,最后向z 轴*移4个单位。复合变换可以通过矩阵的串联来实现。上面的变换过程可以使用下面的公式来计算:
变换的结果是依赖于变换顺序的,由于矩阵乘法不满足交换律,因此矩阵的乘法顺序很重要。
在绝大多数情况下,我们约定变换的顺序就是先缩放,再旋转,最后*移。
组合旋转变换矩阵:
实际上,有一个非常重要的东西我们没有说明白,那就是旋转时使用的坐标系。给定一个旋转顺序(例如这里的zxy ),以及它们对应的旋转角度(θx ,θy ,θz ),有两种坐标系可以选择。
绕坐标系E下的z 轴旋转θz ,绕坐标系E下的y 轴旋转θy ,绕坐标系E下的x 轴旋转θx ,即进行一次旋转时不一起旋转当前坐标系。
绕坐标系E下的z 轴旋转θz ,在坐标系E下绕z 轴旋转θz 后的新坐标系E'下的y 轴旋转θy ,在坐标系E'下绕y 轴旋转θy 后的新坐标系E''下的x 轴旋转θx ,即在旋转时,把坐标系一起转动。
坐标空间的变换
坐标空间会形成一个层次结构——每个坐标空间都是另一个坐标空间的子空间,反过来说,每个空间都有一个父 (parent)坐标空间。对坐标空间的变换实际上就是在父空间和子空间之间对点和矢量进行变换。
例:M c → p,已知子坐标空间C 的3个坐标轴在父坐标空间P 下的表示x c 、y c 、z c ,以及其原点位置 O c 。当给定一个子坐标空间中的一点
4个步骤来确定其在父坐标空间下的位置:
1.从坐标空间的原点开始
这很简单,我们已经知道了子坐标空间的原点位置Oc
2.向x 轴方向移动a 个单位
仍然很简单,因为我们已经知道了x 轴的矢量表示,因此可以得到
3.向y 轴方向移动b 个单位
同样的道理,这一步就是:
4.向z 轴方向移动c 个单位
最后,就可以得到
“|”符号表示是按列展开的。
为了得到一个更漂亮的结果,我们把上面的式子扩展到齐次坐标空间中,得
一旦求出来M c → p ,M p → c 就可以通过求逆矩阵的方式求出来,因为从坐标空间C 变换到坐标空间P 与从坐标空间P 变换到坐标空间C 是互逆的两个过程。
从这个变换矩阵反推来获取子坐标空间的原点和坐标轴方向
已知从模型空间到世界空间的一个4×4的变换矩阵,可以提取它的第一列再进行归一化后(为了消除缩放的影响)来得到模型空间的x 轴在世界空间下的单位矢量表示。同样的方法可以提取y 轴和z 轴。我们可以从另一个角度来理解这个提取过程。因为矩阵M c → p 可以把一个方向矢量从坐标空间C 变换到坐标空间P 中,那么,我们只需要用它来变换坐标空间C 中的x 轴(1,0,0,0),即使用矩阵乘法M c → p [1 0 0 0] T ,得到的结果正是M c → p 的第一列。
对矢量的坐标空间变换就可以使用3×3的矩阵来表示
可以通过求M c → p 的逆矩阵的方式求解出来反向变换M p → c 。但有一种情况我们不需要求解逆矩阵就可以得到M p → c ,这种情况就是M c → p 是一个正交矩阵。如果它是一个正交矩阵的话,M c → p 的逆矩阵就等于它的转置矩阵。
按列展开的规则
设A=(aij)是n阶行列式,那么按第j列展开的公式是D=a1jA1j+a2jA2j+…+anjAnj,其中aij是第i行第j列的元素,Aij=(-1)i+jMij叫aij做的代数余子式,Mij是划去aij所在的第i行和第j列后剩下的(n-1)阶行列式。
顶点的坐标空间变换过程
1.模型空间(model space)也被称为对象空间 (object space) 或局部空间 (local space) 。
2.世界空间 (world space)
我们可以想象成还有一个虚拟的根模型,这个根模型的模型空间就是世界空间,所有的游戏对象都附属于这个根模型。同样,Transform中的Rotation和Scale也是同样的道理。
3.模型变换 (model transform)
顶点变换的第一步,就是将顶点坐标从模型空间变换到世界空间中。
4.观察空间 (view space) 也被称为摄像机空间 (camera space) 。
观察空间是一个三维空间,而屏幕空间是一个二维空间。从观察空间到屏幕空间的转换需要经过一个操作,那就是投影 (projection) 。
5.为了得到顶点在观察空间中的位置,我们可以有两种方法。
一种方法是计算观察空间的三个坐标轴在世界空间下的表示,然后根据4.6.2节中讲到的方法,构建出从观察空间变换到世界空间的变换矩阵,再对该矩阵求逆来得到从世界空间变换到观察空间的变换矩阵。
另一种方法,即想象*移整个观察空间,让摄像机原点位于世界坐标的原点,坐标轴与世界空间中的坐标轴重合即可。
由Transform组件可以知道,摄像机在世界空间中的变换是先按(30, 0, 0)进行旋转,然后按(0, 10, −10)进行了*移。那么,为了把摄像机重新移回到初始状态(这里指摄像机原点位于世界坐标的原点、坐标轴与世界空间中的坐标轴重合),我们需要进行逆向变换,即先按(0, −10, 10)*移,以便将摄像机移回到原点,再按(−30, 0, 0)进行旋转,以便让坐标轴重合。
由于观察空间使用的是右手坐标系,因此需要对z 分量进行取反操作。
M view =M negate z M view
用它来对妞妞的鼻子进行顶点变换
P view =M view P world
得到了观察空间中妞妞鼻子的位置—— (9, 8.84,−27.31)。
6.裁剪空间
裁剪空间的目标是能够方便地对渲染图元进行裁剪:完全位于这块空间内部的图元将会被保留,完全位于这块空间外部的图元将会被剔除,而与这块空间边界相交的图元就会被裁剪。
顶点接下来要从观察空间转换到裁剪空间 (clip space, 也被称为齐次裁剪空间 ) 中,这个用于变换的矩阵叫做裁剪矩阵 (clip matrix) ,也被称为投影矩阵(projection matrix) 。
视锥体指的是空间中的一块区域,这块区域决定了摄像机可以看到的空间。视锥体由六个*面包围而成,这些*面也被称为裁剪*面 (clip planes) 。视锥体有两种类型,这涉及两种投影类型:一种是正交投影 (orthographic projection) ,一种是透视投影 (perspective projection) 。
在视锥体的6块裁剪*面中,有两块裁剪*面比较特殊,它们分别被称为*剪裁*面 (near clip plane) 和远剪裁*面 (far clip plane) 。它们决定了摄像机可以看到的深度范围。
投影矩阵有两个目的:
首先是为投影做准备。真正的投影发生在后面的齐次除法 (homogeneous division) 过程中。
其次是对x 、y 、z 分量进行缩放。
7.透视投影
可以通过Camera组件的Field of View(简称FOV)属性来改变视锥体竖直方向的张开角度,而Clipping Planes中的Near和Far参数可以控制视锥体的*裁剪*面和远裁剪*面距离摄像机的远*。这样,我们可以求出视锥体*裁剪*面和远裁剪*面的高度,也就是:
Unity中,一个摄像机的横纵比由Game视图的横纵比和Viewport Rect中的W和H属性共同决定
现在,我们可以根据已知的Near、Far、FOV和Aspect的值来确定透视投影的投影矩阵。如下:
一个顶点和上述投影矩阵相乘后,可以由观察空间变换到裁剪空间中,结果如下:
P clip =M frustumPview
从结果可以看出,这个投影矩阵本质就是对x 、y 和z 分量进行了不同程度的缩放(当然,z 分量还做了一个*移),缩放的目的是为了方便裁剪。
现在,我们就可以按如下不等式来判断一个变换后的顶点是否位于视锥体内。如果一个顶点在视锥体内,那么它变换后的坐标必须满足:
−w ≤x ≤w
−w ≤y ≤w
−w ≤z ≤w
任何不满足上述条件的图元都需要被剔除或者裁剪。图4.39显示了经过上述投影矩阵后,视锥体的变化。
4个关键点经过投影矩阵变换后的结果。从这些结果可以看出x 、y 、z 和w 分量的范围发生的变化
裁剪矩阵会改变空间的旋向性:空间从右手坐标系变换到了左手坐标系。这意味着,离摄像机越远,z 值将越大。(越远越高)
8.正交投影
正交投影中的6个裁剪*面是如何定义的。和透视投影类似,在Unity中,它们也是由Camera组件中的参数和Game视图的横纵比共同决定
视锥体*裁剪*面和远裁剪*面的高度,也就是:
nearClipPlaneHeight=2 ·Size
farClipPlaneHeight=nearClipPlaneHeight
缺乏横向的信息。同样,我们可以通过摄像机的横纵比得到。假设,当前摄像机的横纵比为Aspect:
nearClipPlaneWidth=Aspect ·nearClipPlaneHeight
farClipPlaneWidth=nearClipPlaneWidth
根据已知的Near、Far、Size和Aspect的值来确定正交投影的裁剪矩阵。如下:
一个顶点和上述投影矩阵相乘后的结果如下:
P clip =M ortho P view
和透视投影不同的是,使用正交投影的投影矩阵对顶点进行变换后,其w 分量仍然为1。本质是因为投影矩阵最后一行的不同,透视投影的投影矩阵的最后一行是[0 0 −1 0],而正交投影的投影矩阵的最后一行是[0 0 0 1]。
判断一个变换后的顶点是否位于视锥体内使用的不等式和透视投影中的一样
同样,裁剪矩阵改变了空间的旋向性。可以注意到,经过正交投影变换后的顶点实际已经位于一个立方体内了。
计算妞妞它的鼻子在裁剪空间中的位置。
透视摄像机。摄像机参数和Game视图的横纵比(在正交投影中,投影矩阵对顶点进行了缩放。图中标注了4个关键点经过投影矩阵变换后的结果。从这些结果可以看出x 、y 、z 和w 分量范围发生的变化。)
知道透视投影的参数:FOV为60°,Near为5,Far为40,Aspect为4/3 = 1.333。对应的投影矩阵就是:
用这个投影矩阵来把妞妞的鼻子从观察空间转换到裁剪空间中。如下:
P clip =M frustum P view
求出了妞妞的鼻子在裁剪空间中的位置—— (11.691, 15.311, 23.692, 27.31)。
接下来,Unity会判断妞妞的鼻子是否需要裁剪。通过比较得到,妞妞的鼻子满足下面的不等式:
−w ≤x ≤w →−27.31≤11.691≤27.31
−w ≤x ≤y →−27.31≤15.311≤27.31
−w ≤z ≤w →−27.31≤23.692≤27.31
由此,我们可以判断,妞妞的鼻子位于视锥体内,不需要被裁剪。
8.屏幕空间
把视锥体投影到屏幕空间 (screen space) 中。经过这一步变换,我们会得到真正的像素位置,而不是虚拟的三维坐标。
把顶点从裁剪空间投影到屏幕空间中,来生成对应的2D坐标。
首先,我们需要进行标准齐次除法 (homogeneous division) ,也被称为透视除法 (perspective division) 。就是用齐次坐标系的w 分量去除以x 、y 、z 分量。在OpenGL中,我们把这一步得到的坐标叫做归一化的设备坐标 (Normalized Device Coordinates,NDC) 。经过这一步,我们可以把坐标从齐次裁剪坐标空间转换到NDC中。
按照OpenGL的传统,这个立方体的x 、y 、z 分量的范围都是[−1, 1]。但在DirectX这样的API中,z 分量的范围会是[0, 1]。而Unity选择了OpenGL这样的齐次裁剪空间。
对于正交投影来说,它的裁剪空间实际已经是一个立方体了,而且由于经过正交投影矩阵变换后的顶点的w 分量是1,因此齐次除法并不会对顶点的x 、y 、z 坐标产生影响。
经过齐次除法后,正交投影的裁剪空间会变换到一个立方体
在Unity中,屏幕空间左下角的像素坐标是(0, 0),右上角的像素坐标是(pixelWidth, pixelHeight)。由于当前x 和y 坐标都是[−1, 1],因此这个映射的过程就是一个缩放的过程。
齐次除法和屏幕映射的过程可以使用下面的公式来总结:
通常,z 分量会被用于深度缓冲。一个传统的方式是把
的值直接存进深度缓冲中,但这并不是必须的。通常驱动生产商会根据硬件来选择最好的存储格式。
在Unity中,从裁剪空间到屏幕空间的转换是由底层帮我们完成的。我们的顶点着色器只需要把顶点转换到裁剪空间即可。
假设,当前屏幕的像素宽度为400,高度为300。首先,我们需要进行齐次除法,把裁剪空间的坐标投影到NDC中。然后,再映射到屏幕空间中。这个过程如下:
由此,我们知道了妞妞鼻子在屏幕上的位置——(285.617, 234.096)。
9.总结
一个顶点如何从模型空间变换到屏幕坐标的过程。
顶点着色器的最基本的任务就是把顶点坐标从模型空间转换到裁剪空间中。
渲染流水线中顶点的空间变换过程
Unity中各个坐标空间的旋向性
法线变换
1.法线变换
法线 (normal) ,也被称为法矢量 (normal vector) 。在上面我们已经看到如何使用变换矩阵来变换一个顶点或一个方向矢量,但法线是需要我们特殊处理的一种方向矢量。
一般来说,点和绝大部分方向矢量都可以使用同一个4×4或3×3的变换矩阵M A → B 把其从坐标空间A 变换到坐标空间B 中。
另一种方向矢量——切线 (tangent) ,也被称为切矢量 (tangent vector) 。与法线类似,切线往往也是模型顶点携带的一种信息。它通常与纹理空间对齐,而且与法线方向垂直
顶点的切线和法线。切线和法线互相垂直
由于切线是由两个顶点之间的差值计算得到的,因此我们可以直接使用用于变换顶点的变换矩阵来变换切线。假设,我们使用3×3的变换矩阵M A → B 来变换顶点(注意,这里涉及的变换矩阵都是3×3的矩阵,不考虑*移变换。这是因为切线和法线都是方向矢量,不会受*移的影响),可以由下面的式子直接得到变换后的切线:
T B =M A → B T A
其中T A 和T B 分别表示在坐标空间A下和坐标空间B下的切线方向。但如果直接使用M A → B 来变换法线,得到的新的法线方向可能就不会与表面垂直了。图4.48给出了这样的一个例子。
知道同一个顶点的切线T A 和法线T A N A N A 必须满足垂直条件,即T A ·N A =0。给定变换矩阵M A → B ,我们已经知道T B =M A → B T A 。我们现在想要找到一个矩阵G 来变换法线N A ,使得变换后的法线仍然与切线垂直。即
T B ·N B =(M A → B T A )·(GN A )=0
对上式进行一些推导后可得
Unity数学基础
//来源《unity shader 入门精要》作者:冯乐乐
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)