本篇暂时记录一些ShaderLab关于计算方面的函数。
本篇只讨论ShaderLab相关的数学问题。
如需了解渲染流水线的配置部分,可参见ShaderLab笔记
如需了解ShaderLab函数部分,可参见ShaderLab函数

参与计算的元素

本篇所有的几何计算都发生在坐标系中,参考OpenGL标准,使用左手坐标系(模型空间/世界空间)。

相机的观察空间使用右手坐标系。
:描述二维坐标系或3维坐标系中的一个位置。(x,y)(x,y,z)。
矢量/向量:有方向性、长度,无位置,(x,y)(x,y,z)(x,y,z,w)。
标量/模(magnitude):长度/大小,部分标量有正负之分。
矩阵(matrix):表示一个有i排j列的矩阵。
在ShaderLab函数中,矩阵表示变换,将一个顶点或向量进行平移/旋转/缩放。

直角三角形下各曲线
π=180°
sin:对边/斜边;sin曲线:x=0,y=0;x=π/2,y=1;x=π,y=0;x=3π/2,y=-1;x=2π,y=0;
cos:临边/斜边;cos曲线:x=0,y=1;x=π/2,y=0;x=π,y=-1;x=3π/2,y=0;x=2π,y=1;
tan:对边/临边;
cot:临边/对边;

函数的几何意义

矢量*标量=矢量
标量作为系数可反转矢量的方向和调整长度。

矢量+/-矢量=矢量

得到的新矢量与参与计算的两个矢量构成三角形,在a+b=c中,起点是a的起点和b的终点。

矢量取模=标量
获得矢量的长度,设模为l,那么l²=x²+y²+z²,要开根号很废性能,只比较大小的话就带着平方用。

矢量归一化=矢量
归一化(normalization)后,矢量的方向不变,长度为1。

矢量·矢量=标量
点积,dot product,内积,inner product。ShaderLab语法:dot(a,b)。
矢量A中的每个元素分别与矢量B中的每个元素相乘后求和。
a·b=(b在a的方向上的分量的长度)*(a的长度)。
(4,0,0)·(4,3,0)=4x4+0x3+0x0=16。
a·b得到的标量有正负之分,可用于验证两个矢量之间的方向关系,为正时表示同向。
a·a得到a的模的平方,可用于对比两个向量的长短。
当a是单位向量时,a·b得到b在a方向上的分量的长度,也就是投影(projection)。
当a和b都是单位向量时,a·b得到两个单位向量之间角度的cos值。

矢量✖矢量=矢量
叉积,cross product,外积,outer product。
a✖b得到一个矢量,方向同时垂直于a和b,且在以a为X正轴和b创建的左手/右手三维坐标系中方向为Z轴正方向。
a✖b得到一个矢量,长度为(a的模)x(b的模)x(a和b夹角的sin值)
(x,y,z)✖(a,b,c)=(yc − zb,za − xc,xb − ya)
(4,0,0)✖(4.3.0)=(0x0-0x3,0x4-4x0,4x3-0x4)=(0,0,12)
(4,3,0)✖(4.0.0)=(3x0-0x0,0x4-4x0,4x0-3x4)=(0,0,-12)
a✖b可用于计算垂直于平面/三角形的矢量。

如何计算一个三角面片的朝向:
设三角面片的的三个顶点分别为:(4,0,0)(0,0,0)(0,3,0)。
MMD模型数据中,构成每个三角形的三个顶点,是按顺时针计算的,渲染引擎默认只渲染正面;
得到从第二个顶点相邻两条边构成的向量:(4,0,0)(0,3,0)
(4,0,0)✖(0,3,0)=(0x0-0x3,0x0-4x0,4x3-0x0)=(0,0,12)
设从相机坐标到原点的向量为(0,0,1)
(0,0,1)·(0,0,12)=12
结果为正,说明此三角面片朝向相机观察方向。

矩阵*标量=矩阵

矩阵*矩阵=矩阵

设矩阵A有4排2列,矩阵B有2排4列,A*B=C,C则有4排4列。
矩阵C中第i行第j列的元素,等于矩阵A的所有i行的元素分别于矩阵B的所有j列的对应元素相乘后求和。
矩阵C中第i行第j列的元素,等于将矩阵A的第i行和矩阵B的第j列转化为对应的多维向量后进行点积

矩阵*矢量=矢量
在Unity中,矩阵*矢量时,矢量被转换为列矩阵且放在右侧,将得到的新矩阵转化为矢量
齐次坐标:将一个原本是n维的向量用一个n+1维向量来表示。

如何平移顶点:
将顶点(x,y,z)转化为齐次坐标(x,y,z,1),使用平移变换矩阵M*齐次坐标。

平移向量不会改变其方向,可将向量(x,y,z)转化为齐次坐标(x,y,z,0)参与平移计算。

如何绕x轴旋转向量:

将向量(0,4,0)围绕X轴顺时针旋转90度:
M*(0,4,0,0)=(1x0+0x4+0x0+0x0,0x0+cos90x4-sin90x0+0x0,0x0+sin90x4+cos90x0+0x0,0)=(0,0,4,0)

如何绕y轴旋转向量:

将向量(4,0,0)围绕Z轴顺时针旋转90度,忽略矩阵中的0元素:
M*(4,0,0,0)=(cos90x4+sin90x0,1x0,-sin90x4+cons90x0,0)=(0,0,-4,0)

如何绕z轴旋转向量:

将向量(4,0,0)围绕Z轴顺时针旋转90度,忽略矩阵中的0元素:
M*(4,0,0)=(cos90x4-sin90x0,sin90x4+cos90x0,1x0,0)=(0,4,0,0)

如何缩放向量:

将向量(1,2,3)沿X轴缩放2倍,沿Y轴缩放3倍,沿Z轴缩放4倍:
M*(1,2,3,0)=(2x1,3x2,4x3,0)=(2,6,12,0)

矩阵的结合律
(AB)C=A(BC),同一时间相乘的两个矩阵依然得满足排数和列数要求,且不能改变相乘的顺序。
BC得到结果的行数为B的行数,列数为C的列数,满足于A相乘的条件。
当矩阵C需要连续与多个矩阵相乘时,其他矩阵可以提前相乘。

复合变换
Unity中,我们约定变换的顺序为:缩放、旋转Z,旋转X,旋转Y、平移。
在Hierarchy窗口中,我们可以看到场景中物体的transform组件,我们从这里获取物体的位置信息。
设一个矢量(1,0,0),代表世界坐标系下的X轴向的单位矢量,向其应用一个transform,求最终矢量。
transform.localPositon=new Vect(3,3,3)
transform.localEulerAngles=new Vect(90,90,90)
transform.localScale=new Vect(2,3,4)
缩放:矢量(1,0,0)缩放(2,3,4)后为(2,0,0)
旋转Z:(2,0,0)绕Z轴旋转90度后为(0,2,0)
旋转X:(0,2,0)绕X轴旋转90度后为(0,0,2)
旋转Y:(0,0,2)绕Y轴旋转90度后为(2,0,0)
平移:向量平移后方向不变,最终矢量为(2,0,0)

顶点空间转换
设子坐标空间的3个坐标轴在父坐标空间下用3个向量表示x,y,z。以及其原点位置(a,b,c)。
现给定子空间坐标中的顶点(d,e,f),求其在父坐标空间下的位置。
首先,子坐标系/父坐标系只是一种称呼而已,任何两个坐标系都可以互相转换。
用来描述子坐标系的变量,如x,y,z,a,b,c这些都是在父坐标系角度去描述的。
当发生空间转换时,如从父空间切换到子空间时,依次发生了缩放、旋转、平移,x/y/z的值由缩放/旋转共同影响,a/b/c由平移影响。
顶点d/e/f的值是用子坐标系角度去描述的,相当于其在父坐标系中,从原点位置(a,b,c)沿着矢量x方向移动d,沿着矢量y方向移动e,沿着矢量z方向移动f。
那么我们用父坐标系的角度去描述顶点(d,e,f)的位置:(a,b,c)+xd+ye+zf
其中向量x,y,z都可以展开,得到其在父坐标系中的三个方向的分量:
(a,b,c)+()d+()e+()f
获得了xd+ye+zf在父坐标系中三个方向的分量后,就可以将其表示为顶点了,这里我将其也顺带转化为齐次坐标。
(a,b,c,1)+

现在我们得到了子坐标系中的顶点(d,e,f)在父坐标系中的位置。

如果上面的公式可以转化为一个矩阵乘以顶点(d,e,f,1)的话,那么就可以实现用矩阵将一个坐标系中的顶点转换到另一个坐标系。

这个矩阵中的每列分别由x,y,z,(a,b,c)的三个分量填充,本篇中称之为竖向填充矩阵。

单位矩阵:斜对角均为1,任何矩阵和单位矩阵相乘的结果都还是原来的矩阵。
转置矩阵:将原矩阵的行列对调后得到转置矩阵。
正交矩阵:如果一个矩阵和他的转置矩阵的乘积是单位矩阵的话,我们就说这个矩阵是正交的(orthogonal)。
逆矩阵:有矩阵X,Y,A,B,其中X*A = B,求A。设Y为X的逆矩阵,等式两边同时乘以Y,A=B*Y。
如果一个矩阵是正交的,那么它的转置矩阵和逆矩阵是一样的。
如果一个方阵有逆矩阵,那么这个方阵和他的逆矩阵的乘积是单位矩阵,不是所有的矩阵都有逆矩阵。
直接计算逆矩阵会很麻烦,我们可以通过判断3X3的正交矩阵与其转置矩阵相乘判断其特点。
标准正交基:三个轴互相垂直且为单位矢量。
如果一个3X3矩阵是正交的,那么构成其坐标系的3个轴是单位矢量。

顶点空间转换的条件:
模型空间和世界空间可以互相转化,本质上没有父子之分,我们认为世界空间的档次更高是因为世界空间中包含很多个物体,而每个物体都有自己的模型空间。
通常我们都知道顶点在当前空间A的坐标,要求顶点在另外一个空间B的坐标。
我们还需要知道:
A坐标系的原点(0,0,0,1)在B坐标系的位置;
A坐标系的3个轴对应B坐标系的3个矢量;
但是:我们通常并不能直接获得这两个数据,需要进行一些转换,本篇中称之为可推导的空间转换

矢量的空间转换:
矢量平移后不会改变方向,计算矢量的缩放和旋转无需用到齐次坐标,保留变换矩阵的前3排3列数据即可。
常见的矢量有法线、光照方向、摄像机方向,在计算矢量转换时使用3X3的矩阵。

可推导的空间转换
当我们要把一个世界空间下的顶点转化到模型空间,且已知模型空间在世界空间下的x轴,y轴,z轴和原点位置(a,b,c)时,因为位置信息并不在目标空间,所以这里并不能直接使用竖向填充来获得变换矩阵,我们还需要知道在模型空间下对世界空间的位置描述。
这时,我们可以尝试通过获得竖向填充矩阵的逆矩阵来间接获得变换矩阵,但是强行计算逆矩阵是很复杂的。
因为空间转换可以拆分为缩放、绕某个轴旋转多少度、平移等多个步骤,这些操作我们可以执行逆操作,所以竖向填充矩阵绝对可逆。
如果竖向填充矩阵是一个标准正交基,那么其逆矩阵才是其转置矩阵,这里我们判断一下竖向填充矩阵成为标准正交基的可能性:
竖向填充矩阵对应的三个轴之间互相垂直吗?垂直的,如果信不过模型空间可以x和y轴相乘一下。
竖向填充矩阵对应的三个轴是单位向量吗?如果发生过缩放就不是,可以归一化为单位向量。
通过对竖向填充矩阵的三个轴进行归一化,我们获得了一个去除了缩放影响的标准正交基,是个3X3矩阵。
竖向填充矩阵归一化后,再转置,即可得到世界空间在模型空间下的x轴,y轴,z轴。
我们还需要继续探讨如何获得世界空间的原点在模型空间的位置。
在竖向填充矩阵归一化后,我们得到的是3X3矩阵,貌似丢失了位置信息。
这个归一化的过程相当于我们在Hierarchy窗口中,对一个Transform组件设置缩放倍数。
当我们设置scale为(1,1,1)或者(3,2,1),模型的位置(原点)并没有发生变化,我们可以放心逆推回去。
逆推世界空间的原点在模型空间位置的过程:
Transform组件上写的坐标是最终偏移量,但是我们约定空间按照缩放、旋转Z,旋转X,旋转Y、平移的顺序变换。
通过竖向填充矩阵归一化后的轴向,其旋转角度和平移量一定存在,但是计算起来贼困难。我们可以理解为:在世界空间中,模型空间的原点位置是固定的,也就是说其长度和方向都不会发生变化,但是站在归一化后的模型空间的角度去看的话,一旦模型空间旋转了,那么世界空间的原点也会绕着模型空间的原点旋转。
我们可以在Scene窗口中,旋转模型的各个轴向来进行确认。

结论:竖向填充矩阵归一化后可逆,其归一化后再转置得到的矩阵本篇中称为横向填充矩阵。
横向填充矩阵是3X3的,可用于在已知在转换前的空间下对目标空间轴向描述时,计算矢量的空间转换。
竖向填充矩阵是4X4的,可用于在已知在转换后的空间下对当前空间轴向和位置的描述时,计算顶点的空间变换。
降维的竖向填充矩阵是3X3的,可以代替4X4的版本与未变换为齐次坐标的矢量相乘,计算矢量的空间变换。
降维的竖向填充矩阵中无论是否归一化三个轴向量,不影响矢量的空间变换。

补充:计算在模型空间下世界空间原点对应坐标:
原点位置(a,b,c)在转化空间后已经失去了方向意义,这里仅保留其长度g。
在模型空间的角度下去描述世界空间的3个坐标轴,此时模型空间已经归一化(归一化横向填充矩阵),原点是(0,0,0),世界空间也是归一化的。
归一化的意义是:使两个空间中的长度等价,这样在世界空间中的长度g转换到模型空间后长度依然为g。
从归一化的横向填充矩阵中,取第一列的3个值,获得模型空间下世界空间的x轴方向单位矢量h。以此类推获得y轴i,z轴j。
现在的情况是:h,i,j均为互相垂直的单位矢量,其交点P(x,y,z)与原点(0,0,0)的距离为g。

关于这个问题本篇就推导到这里,主要是为了说明横向填充矩阵的几何意义。

从模型空间到屏幕

这部分计算一次模型上的一个点经过多次转换最终映射到屏幕上的过程。

模型空间-世界空间

在Unity里面不能直接看到模型空间,也无法直接得知指定顶点在模型空间下的具体坐标。
模型空间可以在3D模型编辑软件内查看,在编辑模式下选择顶点,就可以查看顶点位置。
MMD:切换到顶点列表页面,编辑框中选中顶点后,顶点列表中自动高亮被选中的顶点。
Blender:没有发现直接面板查看顶点,但是有一个叫做Python Console的界面可以自己做脚本输出日志信息。
通用方法:模型空间都有网状的参考线,通过数格子的方法可以估计出顶点坐标。
默认模型空间中地上一格的宽度,和Unity中1个单位的距离是一样的。
在模型导入面板和模型的Transform面板都可以设置缩放比例。
通常在3D建模时,建模师可能会用一个默认的Cube为基础形体创建头部或者身体,人物躯干的宽度一般在2-4个单位。
这里我使用Blender中的默认Cube,并给其中一个面绘制贴图来表示正面,这个面的右上角P就是我想要计算的顶点。

我现在将这个Cube导入到Unity中。模型导入设置中反选掉Convert Units,拖入场景,Reset模型GameObject的Transform属性。

这个模型我没有命名,所以就叫做untitled,可以看到模型的宽度就相当于Unity中的两格。
Blender中使用的是右手坐标系,Unity使用的是左手坐标系。
加载模型的时候Unity将模型空间转换为了自己的那一套,我们直接以Unity中的为准。
此时P在世界空间中的位置为(1,-1,1),因为其变换矩阵为标准正交基,P点在模型空间同值。
为了让我贴图了的那一面正着显示在屏幕上,我将Rotation设置为(180,0,0),计算P位置:
cos180=-1,sin180=0,得到点(1,1,-1)。

这个变化可以更加复杂,比如缩放设置为(1,2,3),再绕Y轴旋转30度,再+X轴方向平移1格。
这里不做更多计算,单步计算需要遵守变换顺序,参考复合变换

Transform组件的使用
我们一般从Transform组件获取位置数据,如scale、rotation、position。
在计算相对位置的时候,就需要考虑是是正着推导还是逆着推导,比如旋转30°或者-30°。
我们必须要铭记,竖向填充矩阵中的数据是用目标空间的角度去描述的。
A物体有Transform组件,Transform组件上的数据是用父级角度去描述的(Transform.localScale)。
如果要切换到A的模型空间,需要将Transform组件上的数据全部取负值。
一般A的父级并不是世界空间,可能一层一层套了很多层空间,但最后总能转换到世界空间。

世界空间-观察空间

观察空间是从摄像机的观察角度去描述空间关系,Unity中观察空间使用右手坐标系
观察空间是一个未经缩放过的三维空间,对摄像机进行旋转、平移可以调整观察空间位置。
我们可以从相机组件的Transform获取相机的旋转和平移,其缩放属性不会生效。
因为相机的Transform是在世界空间角度去描述的,要转换到观察空间需要使用
这里,我的场景是新建的默认场景,相机的rotation为(0,0,0),position为(0,1,-10)。
那么用相机的模型空间去描述世界空间的Transform,其rotation为(0,0,0),positon(0,-1,10)
使用(0,-1,10)去构建平移矩阵即可。

在上一步中,在世界空间中,点P的位置为(1,1,-1),计算其在相机的模型空间中的位置,得到(1,0,9):

相机的模型空间与观察空间的差别是Z轴相反,可与Z分量取反矩阵相乘。
Z分量取反矩阵如下:

P点其实没有动过,它在不同空间里面有不同的版本只是换了一个描述角度而已。
到这里,我们获得了在观察空间下P点的位置(1,0,-9)。

观察空间-裁剪空间

观察空间换了个角度去描述世界空间,裁剪空间则进一步模拟我们的视角。
视椎体:描述当前相机观察角度下,可被观察到的空间范围。
本篇的意义不在推导公式,而是去描述裁剪过程的几何意义,应注意在不同空间下对视椎体的描述。
Aspect为屏幕的宽度/高度,由Game视图的横纵比和像机的W和H属性共同决定。
Aspect = nearClipPlaneWidth/nearClipPlaneHeight = farClipPlaneWidth/farClipPlaneHeight

透视相机的裁剪空间:
透视相机可以模拟出近大远小的效果,物体与相机的距离不同占视口的比例不同。
从观察空间的角度去看视椎体的范围,就像俯瞰金字塔的顶端,但是在裁剪空间内去看视椎体是立方体。
从裁剪空间的角度去描述观察空间是非常困难的,因为其不是等比例缩放的,也就是透视裁剪矩阵

这个观察空间→裁剪空间的矩阵中对x、y、z分量进行的不同程度的缩放,z分量还做了平移。
这样的缩放的意义在于便于计算一个顶点是否在视椎体内。

左边是从观察空间去看视椎体,并标注了其中4个点的位置。
右边可以说是从观察空间或者裁剪空间去看视椎体,标注了其在裁剪空间中的位置。
结论:
在观察空间中,能被看到的顶点其Z分量永远小于0,对应裁剪空间中的w分量永远大于0。
视椎体在被从观察空间转化到裁剪空间后依然是金字塔状,原点朝视椎体方向移动了一段距离。
观察空间中的点(0,0,-2·Near·Far/(Far+Near))转换到裁剪空间后坐标为(0,0,0),这个偏移量在裁剪空中相当于2·Near的距离,两个空间的距离不等价。
在裁剪空间中,原点离近视口距离为Near,离远视口距离为Far。
在裁剪空间中,在视椎体内的顶点x、y、z、w分量均有范围限制,随着z值的变化,要满足顶点保持在视椎体内,其x、y值的范围也在发生变化,这种变化的曲线是线性的。

设一个点距离远视口a,求这个点的切面中在视椎体内的顶点的x分量的最大值b。
b=Far-a·(Far-Near)/(Far+Near)
其中a的最小值为0,最大值为(Far+Near)。
因为这个范围限制变化是线性的,我们有机会通过在空间转换时保存一个数值作为范围的临界点,观察空间中顶点的Z轴值的取反刚好能满足需求,以上解释了为什么要使用裁剪矩阵,以及裁剪空间中w分量为何不等于1
如果一个顶点在视椎体内,那么它变换到裁剪空间后的坐标必须满足:
−w ≤ x ≤ w; −w ≤ y ≤ w; −w ≤ z ≤ w;

正交相机的裁剪空间:
正交相机看物体不会因为物体的远近变化而改变大小,其视椎体是长方形,Near=Far。
相机的Size属性X2 = 视椎体的高度
从观察空间到正交相机的裁剪空间变换矩阵,也就是正交裁剪矩阵

这个观察空间→裁剪空间的矩阵中对x、y、z分量进行的不同程度的缩放,z分量还做了平移。
这样的缩放的意义在于使视椎体从长方体变成了正方体,便于计算一个顶点是否在视椎体内。

在上一步中,我得到了点P在观察空间中的位置(1,0,-9)。
Game窗口中,我设置屏幕比例为4:3。
相机是透视模式,Near=5,Far=10,角度为60度。cot30=√3,√3=1.732。
使用透视裁剪矩阵乘以(1,0,-9,1)后得到(3·√3/4,0,7,9),在视椎体内。
现在我得到了点P在透视裁剪空间下的坐标(1.299,0,7,9)。

透视裁剪空间-NDC

现在我们已经将顶点P从观察空间变换到了透视裁剪空间。
接下来需要对透视裁剪空间中的顶点P进行齐次去除,x、y、z分量都除以w分量。
相当于透视裁剪空间下金字塔形状的视椎体变成了宽度为2的正方体,和正交裁剪空间中的视椎体一样了。
点P的x、y、z分量除以W分量后得到新顶点(0.1443,0,0.7778),四舍五入到小数点后第四位。
正交裁剪空间中顶点的w分量固定为1,没有必要做齐次去除。
这样得到的坐标称为归一化的设备坐标(NDC,Normalized Device Coordinates)。

NDC-屏幕空间

齐次去除后的视椎体中的顶点,x、y、z分量的范围都是[-1,1],z分量会被用于记录点的深度。
所有在视椎体范围内的顶点会铺满屏幕,左下角为(-1,-1),右上角为(1,1),点P在屏幕中央稍微靠右的位置。
视口空间
一个过渡概念,用于描述点在屏幕上相对位置的一种描述方法,左下角为(0,0),右上角为(1,1)。
X轴比例的为(x+1)/2,Y轴的比例为(y+1)/2,得到点P在视口空间中的位置为(0.57215,0.5)。
如果屏幕有400X300像素,那么点P在的屏幕空间中的位置为(229,150)。

使用QQ截图可以观察图片的大概尺寸,会有2像素左右的误差。
我这里截图后在PS中去除了多余的部分,得到了一张229X150像素的图片,说明计算结果与显示结果一致。

几何计算规律

转置矩阵定义:将矩阵的横排与列排交换,总能转置。

当B是由矢量b转化为的矩阵时,因为结果矩阵转置后再转换为矢量是等价的:


逆矩阵定义:能取消一个矩阵的相乘效果的矩阵,几何上总能逆。


逆转置矩阵:一个矩阵先求逆再转置,或者转置换再求逆,几何上总能逆转置。



正交矩阵:正交矩阵与其置换矩阵相乘=单位矩阵,一个矩阵不一定是正交矩阵。


正交矩阵条件:构成矩阵的三个轴是互相垂直的单位向量,也就是标准正交基

阅读顺序的问题
矢量与向量相乘时,默认从右往左阅读,矢量进行列排序且保持在公式的最右侧。

当矢量使用横排序时,阅读顺序变成从左到右,且参与计算的矩阵全部转置。

这两个公式里面,v和A其实都发生了转置,其结果也发生了转置,相当于转置矩阵的第一个特性。
两个向量AB的点积=A的横排序矩阵乘以B的竖排列矩阵

转置矩阵的使用
通常判断矩阵是否是正交矩阵,然后用转置矩阵代替逆矩阵。
正交矩阵的三个轴是互相垂直的单位向量,有缩放+旋转+位移的矩阵需要去除位移→归一化三个轴。
在矩阵是正交矩阵时,可以使用其置换矩阵代替逆矩阵,如:1/k·UNITY_MATRIX_T_MV,k为缩放系数。

逆转置矩阵的使用
法线方向
当模型应用矩阵M被非等比例缩放时,用矩阵M乘以法线得到的新矢量和转换后的切线之间不再垂直。
使用M的逆转置矩阵来变换法线可以得到正确的法线方向,求证方法:

其中第一个箭头指的是将向量点积转化为两个矩阵相乘,G为M的逆转置矩阵时可正确转换法线。
但是逆转置矩阵只有当矩阵是正交矩阵时才可以轻松得到结果,非正交矩阵需要进行归一化。
使用Unity提供的逆转置参数如:UNITY_MATRIX_IT_MV。
注:相比转置矩阵,让Unity去计算逆矩阵可能非常的消耗性能。

线性变换:可以保留矢量加和标量乘的变换,使用3X3矩阵。

其中f()表示一个变换处理。
矢量x和矢量y先变换后相加=先相加后再变换,标量x先变换再缩放=先缩放再变换。
符合线性变换规律的有:缩放、旋转、错切、镜像、正交投影。
错切(shear):比如移动正方形的一边使其变成一个平行四边形。
正交投影:观察空间-正交裁剪空间,去除位移部分。相当于把一个长方形变成正方形。

仿射变换:合并了线性变换和平移的变换类型,使用4X4矩阵。
这里贴出女神书上关于变换特性的描述,我没懂为什么正交/透视投影不能逆,求告知。

其他问题

切线是如何计算的
切线(Tangent)为该点纹理坐标U轴的方向,副法向量(Binormal)为该点纹理坐标V轴的方向。
法线、切线、副法向量互相垂直,法线信息保存在顶点数据中。
暂时无法判断切线是否包括在CPU发送给GPU的数据里,可能是即时计算出来的

欢迎留言新增问题或解答问题


关注成长,注重因果。