URL
status
type
date
slug
summary
tag
category
password
icon
主要是对书中一系列的空间变换过程做出的归纳总结。
复合变换子坐标空间→父坐标空间模型空间→世界空间世界空间→观察空间观察空间→裁剪空间透视投影正交投影裁剪空间→屏幕空间上部分总结法线变换Unity Shader的内置变量(数学篇)Unity内置的变换矩阵摄像机和屏幕参数答疑解惑使用3×3还是4×4的变换矩阵Cg中的矢量和矩阵类型几种“点”的概念Unity中的屏幕坐标:ComputeScreenPos/VPOS/WPOS扩展阅读
复合变换
矩阵右乘,先缩放,后旋转,再平移,是Unity在绝大多数情况下约定俗成的变换顺序。
而若经过多次旋转,旋转矩阵就不是上图只绕Y轴旋转那么简单,就要分开计算了。
子坐标空间→父坐标空间
Xc,Yc,Zc是子坐标空间的坐标轴(矢量方向)在父坐标空间下的表示,Oc是子坐标空间的原点在父坐标空间下的表示。
可以看出来,变换矩阵Mc→p实际上可以通过坐标空间C在坐标空间P中的原点和坐标轴的矢量表示来构建出来:把3个坐标轴依次放入矩阵的前3列,把原点矢量放到最后一列,再用0和1填充最后一行即可。
需要注意的是,这里我们并没有要求3个坐标轴Xc、Yc和Zc是单位矢量,事实上,如果存在缩放的话,这3个矢量值很可能不是单位矢量。
模型空间→世界空间
模型空间→世界空间就是子坐标空间→父坐标空间的最后一步,模型
有时模型空间也被称为对象空间(object space)或局部空间(local space)。每个模型都有自己独立的坐标空间,当它移动或旋转的时候,模型空间也会跟着它移动和旋转。
Unity中,世界空间的原点是游戏世界的“中心”,一个物体如果没有任何父物体,那么它的Position就是世界空间的位置;一个物体如果有父物体,那么它的Position是相对于其父物体的模型空间的。
模型空间变化矩阵的拆分
tx,ty,tz代表位移,𝚹代表Y轴的旋转角(以Y轴旋转为例),kx,ky,kz代表缩放。
要将模型空间中点的坐标,转化为世界空间中点的坐标,需要将模型变换的变换矩阵右乘模型空间中点的坐标矢量。
世界空间→观察空间
顶点变换的第二步,就是将顶点坐标从世界空间变换到观察空间中。这个变换通常叫做观察变换
(view transform)。
观察空间(view space)也被称为摄像机空间(camera space)。观察空间可以认为是模型空间的一个特例——在所有的模型中有一个非常特殊的模型,即摄像机(虽然通常来说摄像机本身是不可见的),它的模型空间值得我们单独拿出来讨论,也就是观察空间。Unity在模型空间和世界空间中选用的都是左手坐标系,而在观察空间中使用的是右手坐标系。这是符合OpenGL传统的,在这样的观察空间中,摄像机的正前方指向的是-z轴方向。
构建出从观察空间变换到世界空间的变换矩阵,再对该矩阵求逆来得到从世界空间变换到观察空间的变换矩阵。我们还可以使用另一种方法,即想象平移整个观察空间,让摄像机原点位于世界坐标的原点,坐标轴与世界空间中的坐标轴重合即可。
以x轴旋转为例,Mview的变换矩阵是这样的,但是,由于观察空间使用的是右手坐标系,因此需要对z分量进行取反操作。我们可以通过乘以另一个特殊的矩阵来得到最终的观察变换矩阵:
最后对世界空间进行变换
观察空间→裁剪空间
顶点接下来要从观察空间转换到裁剪空间(clip space,也被称为齐次裁剪空间)中,这个用于变换的矩阵叫做裁剪矩阵(clip matrix),也被称为投影矩阵(projection matrix)。
投影又分为透视投影和正交投影
透视投影
摄像机的参数Near、Far、FOV如图所示
可以求出近裁剪片面和远裁剪片面的高度,即
nearClipPlaneHeight=2·Near·tan(FOV/2)
farClipPlaneHeight=2·Far·tan(FOV/2).
在Unity中,一个摄像机的横纵比由Game视图的横纵比和Viewport Rect中的W和H属性共同决定。
当前摄像机的横纵比为Aspect,我们定义
Aspect=nearClipPlaneWidth/nearClipPlaneHeight
Aspect=farClipPlaneWidth/farClipPlaneHeight
可以根据已知的Near、Far、FOV和Aspect的值来确定透视投影的投影矩阵。
需要注意的是,这里的投影矩阵是建立在Unity对坐标系的假定上面的,也就是说,我们针对的是观察空间为右手坐标系,使用列矩阵在矩阵右侧进行相乘,且变换后z分量范围将在[-w,w]之间的情况。而在类似DirectX这样的图形接口中,它们希望变换后z分量范围将在[0, w]之间,因此就需要对上面的透视矩阵进行一些更改。
而一个顶点和上述投影矩阵相乘后,可以由观察空间变换到裁剪空间中,结果如下:
从结果可以看出,这个投影矩阵本质就是对x、y和z分量进行了不同程度的缩放(当然,z分量还做了一个平移),缩放的目的是为了方便裁剪。我们可以注意到,此时顶点的w分量不再是1,而是原先z分量的取反结果。现在,我们就可以按如下不等式来判断一个变换后的顶点是否位于视锥体内。如果一个顶点在视锥体内,那么它变换后的坐标必须满足:
−w≤x≤w
−w≤y≤w
−w≤z≤w
任何不满足上述条件的图元都需要被剔除或者裁剪。
正交投影
和透视投影类似,在Unity中,正交投影视锥体的6个裁剪平面也是由Camera组件中的参数和Game视图的横纵比共同决定。
正交投影的视锥体是一个长方体,因此计算上相比透视投影来说更加简单。
nearClipPlaneHeight=farClipPlaneHeight=2·
Size
nearClipPlaneWidth=farClipPlaneWidth=Aspect·nearClipPlaneHeight
根据已知的Near、Far、Size和Aspect的值来确定正交投影的裁剪矩阵。如下:
注意到,和透视投影不同的是,使用正交投影的投影矩阵对顶点进行变换后,其w分量仍然为1。本质是因为投影矩阵最后一行的不同,透视投影的投影矩阵的最后一行是[0 0 −1 0],而正交投影的投影矩阵的最后一行是[0 0 0 1]。这样的选择是有原因的,是为了为齐次除法做准备。
判断一个变换后的顶点是否位于视锥体内使用的不等式和透视投影中的一样,这种通用性也是为什么要使用投影矩阵的原因之一。图4.41显示了经过上述投影矩阵后,正交投影的视锥体的变化。
同样,裁剪矩阵改变了空间的旋向性。可以注意到,经过正交投影变换后的顶点实际已经位于一个立方体内了。
裁剪空间→屏幕空间
经过投影矩阵的变换后,我们可以进行裁剪操作。当完成了所有的裁剪工作后,就需要进行真正的投影了,也就是说,我们需要把视锥体投影到屏幕空间(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这样的齐次裁剪空间。如图4.43所示。
▲图4.43 经过齐次除法后,透视投影的裁剪空间会变换到一个立方体
而对于正交投影来说,它的裁剪空间实际已经是一个立方体了,而且由于经过正交投影矩阵变换后的顶点的w分量是1,因此齐次除法并不会对顶点的x、y、z坐标产生影响。如图4.44所示。
▲图4.44 经过齐次除法后,正交投影的裁剪空间会变换到一个立方体
经过齐次除法后,透视投影和正交投影的视锥体都变换到一个相同的立方体内。现在,我们可以根据变换后的x和y坐标来映射输出窗口的对应像素坐标。
在Unity中,屏幕空间左下角的像素坐标是(0, 0),右上角的像素坐标是(pixelWidth, pixelHeight)。由于当前x和y坐标都是[−1, 1],因此这个映射的过程就是一个缩放的过程。
齐次除法和屏幕映射的过程可以使用下面的公式来总结:
上面的式子对x和y分量都进行了处理,那么z分量呢?通常,z分量会被用于深度缓冲。一个传统的方式是把clipz/clipw的值直接存进深度缓冲中,但这并不是必须的。通常驱动生产商会根据硬件来选择最好的存储格式。此时clipw也并不会被抛弃,虽然它已经完成了它的主要工作——在齐次除法中作为分母来得到NDC,但它仍然会在后续的一些工作中起到重要的作用,例如进行透视校正插值。
在Unity中,从裁剪空间到屏幕空间的转换是由底层帮我们完成的。我们的顶点着色器只需要把顶点转换到裁剪空间即可。
上部分总结
以上就是一个顶点如何从模型空间变换到屏幕坐标的过程。图4.45总结了这些空间和用于变换的矩阵。
顶点着色器的最基本的任务就是把顶点坐标从模型空间转换到裁剪空间中。这对应了图4.45中的前3个顶点变换过程。而在片元着色器中,我们通常也可以得到该片元在屏幕空间的像素位置。我们会在4.9.3节中看到如何得到这些像素位置。
在Unity中,坐标系的旋向性也随着变换发生了改变。图4.46总结了Unity中各个空间使用的坐标系旋向性。从图4.46中可以发现,只有在观察空间中Unity使用了右手坐标系。
需要注意的是,这里仅仅给出的是一些最重要的坐标空间。还有一些空间在实际开发中也会遇到,例如切线空间(tangent space)。切线空间通常用于法线映射。
法线变换
法线(normal),也被称为法矢量(normal vector)。在上面我们已经看到如何使用变换矩阵来变换一个顶点或一个方向矢量,但法线是需要我们特殊处理的一种方向矢量。在游戏中,模型的一个顶点往往会携带额外的信息,而顶点法线就是其中一种信息。当我们变换一个模型的时候,不仅需要变换它的顶点,还需要变换顶点法线,以便在后续处理(如片元着色器)中计算光照等。
一般来说,点和绝大部分方向矢量都可以使用同一个4×4或3×3的变换矩阵MA→B
把其从坐标空间A变换到坐标空间B中。但在变换法线的时候,如果使用同一个变换矩阵,可能就无法确保维持法线的垂直性。下面就来了解一下为什么会出现这样的问题。
我们先来了解一下另一种方向矢量——切线(tangent),也被称为切矢量(tangent vector)。与法线类似,切线往往也是模型顶点携带的一种信息。它通常与纹理空间对齐,而且与法线方向垂直,如图4.47所示。
▲图4.47 顶点的切线和法线。切线和法线互相垂直
由于切线是由两个顶点之间的差值计算得到的,因此我们可以直接使用用于变换顶点的变换矩阵来变换切线。假设,我们使用3×3的变换矩阵MA→B来变换顶点(注意,这里涉及的变换矩阵都是3×3的矩阵,不考虑平移变换。这是因为切线和法线都是方向矢量,不会受平移的影响),可以由下面的式子直接得到变换后的切线:
▲图4.48 进行非统一缩放时,如果使用和变换顶点相同的变换矩阵来变换法线,就会得到错误的结果,即变换后的法线方向与平面不再垂直
那么,应该使用哪个矩阵来变换法线呢?我们可以由数学约束条件来推出这个矩阵。我们知道同一个顶点的切线TA和法线NA必须满足垂直条件,即TA·NA=0。给定变换矩阵MA→B,我们已经知道TB=MA→BTA。我们现在想要找到一个矩阵G来变换法线NA,使得变换后的法线仍然与切线垂直。即
TB·NB=(MA→BTA)·(GNA)=0
上式推导后得到
法线变换矩阵G=切线变换矩阵,也是顶点变换矩阵的逆转置矩阵
Unity Shader的内置变量(数学篇)
使用Unity写Shader的一个好处在于,它提供了很多内置的参数,这使得我们不再需要自己手动计算一些值。本节将给出Unity内置的用于空间变换和摄像机以及屏幕参数的内置变量。这些内置变量可以在UnityShaderVariables.cginc文件中找到定义和说明。
Unity内置的变换矩阵
变量名 | 描述 |
UNITY_MATRIX_MVP | 当前的模型观察投影矩阵,用于将顶点/方向矢量从模型空间变换到裁剪空间 |
UNITY_MATRIX_MV | 当前的模型观察矩阵,用于将顶点/方向矢量从模型空间变换到观察空间 |
UNITY_MATRIX_V | 当前的观察矩阵,用于将顶点/方向矢量从世界空间变换到观察空间 |
UNITY_MATRIX_P | 当前的投影矩阵,用于将顶点/方向矢量从观察空间变换到裁剪空间 |
UNITY_MATRIX_VP | 当前的观察投影矩阵,用于将顶点/方向矢量从世界空间变换到裁剪空间 |
UNITY_MATRIX_T_MV | UNITY_MATRIX_MV的转置矩阵 |
UNITY_MATRIX_IT_MV | UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可用于得到UNITY_MATRIX_MV的逆矩阵 |
_Object2World | 当前的模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间 |
_World2Object | _Object2World的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间 |
变量名记忆方式:UNITY_MATRIX_(T)_[空间类型1][空间类型2]([空间类型3])
含义:能够从空间1变换到空间2(再变换到空间3)的矩阵,转置需要单独讨论。
含义 | 形式 |
UNITY_MATRIX_ | 内置变换矩阵前缀 |
T_/IT_ | 转置/逆转置 |
M | 模型(Model) |
V | 观察(View) |
P | 投影(Projection) |
UNITY_MATRIX_T_MV
其中有一个矩阵比较特殊,即模型观察矩阵的转置UNITY_MATRIX_T_MV
对于正交矩阵来说,它的逆矩阵就是转置矩阵。因此,如果UNITY_MATRIX_MV是一个正交矩阵的话,那么UNITY_MATRIX_T_MV就是它的逆矩阵,也就是说,我们可以使用UNITY_MATRIX_T_MV把顶点和方向矢量从观察空间变换到模型空间。
那么问题是,UNITY_MATRIX_MV什么时候是一个正交矩阵呢?答案是只经过旋转变换时是正交矩阵。总结一下,如果一个模型的变换只包括旋转,那么UNITY_MATRIX_MV就是一个正交矩阵。这个条件似乎有些苛刻,我们可以把条件再放宽一些,如果只包括旋转和统一缩放(假设缩放系数是k),那么UNITY_MATRIX_MV就几乎是一个正交矩阵了。为什么是几乎呢?因为统一缩放可能会导致每一行(或每一列)的矢量长度不为1,而是k。
这不符合正交矩阵的特性,但我们可以通过除以这个统一缩放系数,来把它变成正交矩阵。在这种情况下,UNITY_MATRIX_MV的逆矩阵就是UNITY_MATRIX_T_MV。
而且,如果我们只是对方向矢量进行变换的话,条件可以放得更宽,即不用考虑有没有平移变换,因为平移对方向矢量没有影响。因此,我们可以截取UNITY_MATRIX_T_MV的前3行前3列来把方向矢量从观察空间变换到模型空间(前提是只存在旋转变换和统一缩放)。对于方向矢量,我们可以在使用前对它们进行归一化处理,来消除统一缩放的影响。
UNITY_MATRIX_IT_MV
还有一个矩阵需要说明一下,那就是UNITY_MATRIX_IT_MV矩阵。我们在4.7节已经知道,法线的变换需要使用原变换矩阵的逆转置矩阵G。因此UNITY_MATRIX_IT_MV可以把法线从模型空间变换到观察空间。但只要我们做一点手脚,它也可以用于直接得到UNITY_MATRIX_MV的逆矩阵——我们只需要对它进行转置就可以了。因此,为了把顶点或方向矢量从观察空间变换到模型空间(V2M),我们可以使用类似下面的代码:
摄像机和屏幕参数
Unity提供了一些内置变量来让我们访问当前正在渲染的摄像机的参数信息。这些参数对应了摄像机上的Camera组件中的属性值。
变量名 | 类型 | 描述 |
_WorldSpaceCameraPos | float3 | 该摄像机在世界空间中的位置 |
_ProjectionParams | float4 | X=1.0(或-1.0,如果正在使用一个翻转的投影矩阵进行渲染),y= Near,2= Far,w=1.0+ 1.0/Far,其中Near和Far分别是近裁剪平面和远裁剪平面和摄像机的 |
_ScreenParams | float4 | X= width,y= height, 2=1.0 + 1.0/width,w= 1.0+ 1.0/height,其中width和height分别是该摄像机的渲染目标 (render target)的像素宽度和高度 |
_ZBufferParams | float4 | X=1- Far/Near,y= Far/Near,2=x/Far,w=y/Far,该变量用于线性化 缓存中的深度值(可参考13.1节) |
unity_OrthoParams | float4 | x= width,y= heigth,z 没有定义,w=1.0(该摄像机是正交摄像机)或w=0.0(该摄像机是透视摄像机),其中width和height是正交投影摄像机的宽度和高度 |
unity_CameraProjection | float4x4 | 该摄像机的投影矩阵 |
unity_CameralnvProjection | float4x4 | 该摄像机的投影矩阵的逆矩阵 |
unity_CameraWorldClipPlanes[6] | float4 | 该摄像机的6个裁剪平面在世界空间下的等式,按如下顺序:左、右、下、上、近、远裁剪平面 |
答疑解惑
使用3×3还是4×4的变换矩阵
对于线性变换(例如旋转和缩放)来说,仅使用3×3的矩阵就足够表示所有的变换了。但如果存在平移变换,我们就需要使用4×4的矩阵。因此,在对顶点的变换中,我们通常使用4×4的变换矩阵。当然,在变换前我们需要把点坐标转换成齐次坐标的表示,即把顶点的w分量设为1。而在对方向矢量的变换中,我们通常使用3×3的矩阵就足够了,这是因为平移变换对方向矢量是没有影响的。
Cg中的矢量和矩阵类型
我们通常在Unity Shader中使用Cg作为着色器编程语言。
在Cg中变量类型有很多种,但在本节我们是想解释如何使用这些类型进行数学运算。因此,我们只以float家族的变量来做说明。
在Cg中,矩阵类型是由float3x3、float4x4等关键词进行声明和定义的。而对于float3、float4等类型的变量,我们既可以把它当成一个矢量,也可以把它当成是一个1×n的行矩阵或者一个n×1的列矩阵。这取决于运算的种类和它们在运算中的位置。例如,当我们进行点积操作时,两个操作数就被当成矢量类型,如下:
但在进行矩阵乘法时,参数的位置将决定是按列矩阵还是行矩阵进行乘法。在Cg中,矩阵乘法是通过mul函数实现的。例如:
因此,参数的位置会直接影响结果值。通常在变换顶点时,我们都是使用右乘的方式来按列矩阵进行乘法。这是因为,Unity提供的内置矩阵(如UNITY_MATRIX_MVP等)都是按列存储的。但有时,我们也会使用左乘的方式,这是因为可以省去对矩阵转置的操作。
需要注意的一点是,Cg对矩阵类型中元素的初始化和访问顺序。在Cg中,对float4x4等类型的变量是按行优先的方式进行填充的。什么意思呢?我们知道,想要填充一个矩阵需要给定一串数字,例如,如果需要声明一个3×4的矩阵,我们需要提供12个数字。那么,这串数字是一行一行地填充矩阵还是一列一列地填充矩阵呢?这两种方式得到的矩阵是不同的。例如,我们使用(1, 2, 3, 4, 5, 6, 7, 8, 9)去填充一个3×3的矩阵,如果是按照行优先的方式,得到的矩阵是
如果是按照列优先的方式,得到的矩阵是:
Cg使用的是行优先的方法,即是一行一行地填充矩阵的。因此,如果需要自己定义一个矩阵时(例如,自己构建用于空间变换的矩阵),就要注意这里的初始化方式。类似地,当我们在Cg中访问一个矩阵中的元素时,也是按行来索引的。例如:
之所以Unity Shader中的矩阵类型满足上述规则,是因为使用的是Cg语言。换句话说,上面的特性都是Cg的规定。
Unity在脚本中提供了一种矩阵类型——Matrix4x4。脚本中的这个矩阵类型则是采用列优先的方式。这与这与Unity Shader中的规定不一样。
几种“点”的概念
- 顶点(vertex):图元(如线段、三角形、圆等几何图形)由顶点+边组成,由用户及其建立的模型确定.
- 图元(primitive):描述对象的几何要素的输出图元,称为几何图元,简称图元. 如点、直线段、圆、二次曲线、曲面等.
- 片元(fragment):光栅化过程的产物,光栅化将一个图元转变成二维图像,每个图像点都包含颜色、深度、纹理等数据,将该点和相关信息称为一个片元.
- 像素(pixel):最终呈现在屏幕上的点,包含RGBA值的图像最小单元.
它们生成顺序是这样的:
顶点 -> 图元 -> 片元 -> 像素
Unity中的屏幕坐标:ComputeScreenPos/VPOS/WPOS
VPOS/WPOS
在顶点/片元着色器中,有两种方式来获得片元的屏幕坐标。一种是在片元着色器的输入中声明VPOS或WPOS语义(关于什么是语义,可参见5.4节)。VPOS是HLSL中对屏幕坐标的语义,而WPOS是Cg中对屏幕坐标的语义。两者在Unity Shader中是等价的。我们可以在HLSL/Cg中通过语义的方式来定义顶点/片元着色器的默认输入,而不需要自己定义输入输出的数据结构。
用这种方法,可以在片元着色器中这样写:
得到的效果如下
▲图4.49 由片元的像素位置得到的图像
ComputeScreenPos
另一种方式是通过Unity提供的
ComputeScreenPos
函数。这个函数在UnityCG.cginc
里被定义。通常的用法需要两个步骤:1.首先在顶点着色器中将ComputeScreenPos
的结果保存在输出结构体中,2.在片元着色器中进行一个齐次除法运算后得到视口空间下的坐标。例如:上面代码的实现效果和图4.49中的一样。我们现在来看一下这种方式的实现细节。这种方法实际上是手动实现了屏幕映射的过程,而且它得到的坐标直接就是视口空间中的坐标。我们在4.6.8节中已经看到了如何将裁剪坐标空间中的点映射到屏幕坐标中。
4.6.8 屏幕空间用齐次坐标系的w分量去除以x、y、z分量。在OpenGL中,我们把这一步得到的坐标叫做归一化的设备坐标(Normalized Device Coordinates,NDC)经过这一步,我们可以把坐标从齐次裁剪坐标空间转换到NDC中。经过透视投影变换后的裁剪空间,经过齐次除法后会变换到一个立方体内。
据此,我们可以得到视口空间中的坐标,公式如下:
上面公式的思想就是,首先对裁剪空间下的坐标进行齐次除法,得到范围在[−1, 1]的NDC,然后再将其映射到范围在[0, 1]的视口空间下的坐标。那么ComputeScreenPos究竟是如何做到的呢?我们可以在UnityCG.cginc文件中找到ComputeScreenPos函数的定义。如下:
ComputeScreenPos的输入参数pos是经过MVP矩阵变换后在裁剪空间中的顶点坐标。UNITY_HALF_TEXEL_OFFSET是Unity在某些DirectX平台上使用的宏,在这里我们可以忽略它。这样,我们可以只关注#else的部分。_ProjectionParams.x在默认情况下是1(如果我们使用了一个翻转的投影矩阵的话就是−1,但这种情况很少见)。那么上述代码的过程实际是输出了:
经过除法操作后,我们就可以得到该片元在视口空间中的坐标了,也就是一个xy范围都在[0, 1]之间的值。那么它的zw值是什么呢?可以看出,我们在顶点着色器中直接把裁剪空间的zw值存进了输出结构体中,因此片元着色器输入的就是这些插值后的裁剪空间中的zw值。这意味着,如果使用的是透视投影,那么z值的范围是[-Near, Far],w值的范围是[Near, Far];如果使用的是正交投影,那么z值范围是[−1, 1],而w值恒为1。
扩展阅读
计算机图形学使用的数学还有很多,本书仅涵盖了其中非常小的一部分。如果读者想要深入学习这些知识的话,书籍[1][2]是非常好的图形学数学学习资料,读者可以在那里找到更多类型的变换及其数学表示。关于如何从左手坐标系转换到右手坐标系同时又保持视觉效果一样,可以参考资料[3]。关于如何得到线性的深度值可以参考资料[4]。
[1] Fletcher Dunn, Ian Parberry. 3D Math Primer for Graphics and Game Development (2nd Edition). November 2, 2011 by A K Peters/CRC Press。
[2] Eric Lengyel. Mathematics for 3D game programming and computer graphics (3rd Edition). 2011 by Charles River Media。
[3] David Eberly. Conversion of Left-Handed Coordinates to Right-Handed Coordinates。
[4] http://www.humus.name/temp/Linearize depth.txt
摘录来自
Unity Shader入门精要
冯乐乐
- 作者:Cloud
- 链接:https://cloud09.xyz/article/a045427e-8827-4a3d-a6b4-2ddac05efeeb
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。