裁剪空间
顶点接下来要从观察空间转换到裁剪空间(也被称为齐次裁剪空间) 中,这个用于变换的矩阵叫做裁剪矩阵,也被称为投影矩阵
裁剪空间的目标是能够方便地对渲染图元进行裁剪:完全位于这块空间内部的图元将会被保留,完全位于这块空间外部的图元将会被剔除,而与这块空间边界相交的图元就会被裁剪。这块空间是由视锥体来决定
视锥体指的是空间中的一块区域,这块区域决定了摄像机可以看到的空间。视锥体由六个平面鲍威尔成,这些平面也被称为裁剪平面。视锥体有两种类型,这涉及两种投影类型:一种是正交投影,一种是透视投影。下图显示了从同一位置、同一角度渲染同一个场景的两种摄像机的渲染结果
从图中可以发现,在透视投影中,地板上的平行线并不会保持平行,离摄像机越近网格越大,离摄像机越远网格越小。而在正交投影中,所有的网格大小都一样,而且平行线会一直保持平行。可以注意到,透视投影模拟了人眼看世界的方式,而正交投影则完全保留了物体的距离和角度。因此,在追求真实感的3D游戏中往往会使用透视投影,而在一些2D游戏或渲染小地图等其他HUD元素时会使用正交投影
在视锥体的六块裁剪平面中,有两块裁剪平面比较特殊,它们分别被称为近剪裁平面和远剪裁平面。它们决定了摄像机可以看到的深度范围。正交投影和透视投影的视锥体如下图所示:
由上图可以看出,透视投影的视锥体是一个金字塔型,侧面的四个裁剪平面将会在摄像机处相交。它更符合视锥体这个词语。正交投影的视锥体是一个长方体。前文提到,需求是根据视锥体围成的区域对图元进行裁剪,但是,如果直接使用视锥体定义的空间来进行裁剪,那么不同的视锥体就需要不同的处理过程,而且对于透视投影的视锥体来说,想要判断一个顶点是否处于一个金字塔内部是比较麻烦的。因此,需要一种更加通用、方便和整洁的方式来进行裁剪的工作,这种方式就是通过一个投影矩阵把顶点转换到一个裁剪空间中。
投影矩阵有两个目的:
- 首先是为投影做准备。虽然投影矩阵的名称包含了投影二字,但是它并没有进行真正的投影工作,而是在为投影做准备。真正的投影发生在后面的齐次除法过程中。而经过投影矩阵的变换后,顶点的 w w w分量将会具有特殊的意义
- 其次是对 x , y , z x,y,z x,y,z分量进行缩放,前文说过直接使用视锥体的六个裁剪平面来进行裁剪会比较麻烦。而经过投影矩阵的缩放后,可以直接使用 w w w分量作为一个范围值,如果 x , y , z x,y,z x,y,z分量都位于这个范围内,就说明该顶点位于裁剪空间内
透视投影
视锥体的意义在于定义了场景中的一块三维空间。所有位于这块空间内的物体将会被渲染,否则就会被剔除或裁剪。前文说到,这块区域由六个裁剪平面定义,在Unity中,它们由Camera 组件中的参数和 Game 试图的横纵比共同决定,如下图所示:
由上图可以看出,通过 Camera 组建的 Field of View(简称FOV)属性来改变视锥体垂直方向的张开角度,而 Clipping Planes 中的 Near 和 Far 参数可以控制视锥体的近裁剪平面和远裁剪平面的远近。这样可以求出视锥体近裁剪平面和远裁剪平面的高度,也就是:
n e a r C l i p P l a n e H e i g h t = 2 ⋅ N e a r ⋅ tan F O V 2 f a r C l i p P l a n e H e i g h t = 2 ⋅ F a r ⋅ tan F O V 2 nearClipPlaneHeight = 2\cdot Near\cdot \tan\frac{FOV}{2}\\ farClipPlaneHeight=2\cdot Far\cdot\tan\frac{FOV}{2} nearClipPlaneHeight=2⋅Near⋅tan2FOVfarClipPlaneHeight=2⋅Far⋅tan2FOV
现在还缺少缺乏横向的信息。这可以通过摄像机的横纵比得到。在Unity中,一个摄像机的横纵比由Game视图得到横纵比和Viewport Rect中的W和H属性共同决定(实际上,Unity允许在脚本里通过Camera.aspect进行更改,但这里不做讨论)。假设,当前摄像机的横纵比为Aspect,定义为:
A s p e c t = n e a r C l i p P l a n e W i d t h n e r a C l i p P l a n e H e i g h t Aspect = \frac{nearClipPlaneWidth}{neraClipPlaneHeight} Aspect=neraClipPlaneHeightnearClipPlaneWidth
A s P e c t = f a r C l i p P l a n e W i d t h f a r C l i p P l a n e H H e i g h t AsPect=\frac{farClipPlaneWidth}{farClipPlaneHHeight} AsPect=farClipPlaneHHeightfarClipPlaneWidth
现在可以根据已知的Near、Far、FOV和Aspect的值来确定透视投影的投影矩阵。如下:
M f r u s t u m = [ c o t F O V 2 A s p e c t 0 0 0 0 c o t F O V 2 2 0 0 0 0 − F a r + N e a r F a r − N e a r − 2 ⋅ N e a r ⋅ F a r F a r − N e a r 0 0 − 1 0 ] \mathbf{M}_{frustum}=\begin{bmatrix} \frac{cot\frac{FOV}{2}}{Aspect}&0&0&0\\ 0&\frac{cot\frac{FOV}{2}}{2}&0&0\\ 0&0&-\frac{Far+Near}{Far-Near}&-\frac{2\cdot Near\cdot Far}{Far-Near}\\ 0&0&-1&0 \end{bmatrix} Mfrustum= Aspectcot2FOV00002cot2FOV0000−Far−NearFar+Near−100−Far−Near2⋅Near⋅Far0
需要注意的是,这里的投影矩阵是建立在Unity对坐标系的假定上面的,也就是说,针对的是观察空间和右手坐标系,使用列矩阵在矩阵右侧进行相乘,且变换后 z z z分量范围将在 [ − w , w ] [-w,w] [−w,w]之间的情况。而在类似Direct X这样的图形接口中,它们希望变换后 z z z分量范围将在 [ 0 , w ] [0,w] [0,w]之间,因此就需要对上面的透视矩阵进行一个更改。这不在本文的谈论范围之内
而一个顶点和上述投影矩阵相乘后,可以由观察空间变换到裁剪空间中,结果如下:
P c l i p = M f r u s t u m P v i e w = [ c o t F O V 2 A s p e c t 0 0 0 0 c o t F O V 2 2 0 0 0 0 − F a r + N e a r F a r − N e a r − 2 ⋅ N e a r ⋅ F a r F a r − N e a r 0 0 − 1 0 ] [ x y z 1 ] = [ x c o t F O V 2 2 y c o t F O V 2 − z F a r + N e a r F a r − N e a r − 2 ⋅ N e a r ⋅ F a r F a r − N e a r − z ] \begin{aligned} \mathbf{P}_{clip} &= \mathbf{M}_{frustum}\mathbf{P}_{view}\\ &=\begin{bmatrix} \frac{cot\frac{FOV}{2}}{Aspect}&0&0&0\\ 0&\frac{cot\frac{FOV}{2}}{2}&0&0\\ 0&0&-\frac{Far+Near}{Far-Near}&-\frac{2\cdot Near\cdot Far}{Far-Near}\\ 0&0&-1&0 \end{bmatrix}\begin{bmatrix} x\\y\\z\\1 \end{bmatrix}\\ &=\begin{bmatrix} x\frac{cot\frac{FOV}{2}}{2}\\ ycot\frac{FOV}{2}\\ -z\frac{Far+Near}{Far-Near} - \frac{2\cdot Near \cdot Far}{Far-Near}\\ -z \end{bmatrix} \end{aligned} Pclip=MfrustumPview= Aspectcot2FOV00002cot2FOV0000−Far−NearFar+Near−100−Far−Near2⋅Near⋅Far0 xyz1 = x2cot2FOVycot2FOV−zFar−NearFar+Near−Far−Near2⋅Near⋅Far−z
从结果可以看出,这个投影矩阵本质就是对 x , y , z x,y,z x,y,z分量进行了不同程度的缩放(当然, z z z分量还做了一个平移),缩放的目的是为了裁剪。可以注意到,这时顶点的 w w w分量不再是1,二十原先 z z z分量的取反结果。现在就可以按如下不等式来判断一个变换后的顶点是否位于视锥体内。如果一个顶点在视锥体内,那么它变化后的坐标必须满足:
− w ≤ x ≤ w − w ≤ y ≤ w − w ≤ z ≤ w -w\leq x \leq w\\ -w\leq y \leq w\\ -w\leq z \leq w −w≤x≤w−w≤y≤w−w≤z≤w
任何不满足上述条件的图元都需要被剔除或者裁剪。下图显示了经过上述投影矩阵后视锥体的变化
在透视投影钟,投影矩阵对顶点进行了缩放。图中标注了4个关键点经过投影矩阵变换后的结果。从这些结果可以看出 x , y , z x,y,z x,y,z和 w w w分量的范围发生的变化
上图还可以注意到,裁剪矩阵会改变空间的旋向性:空间从右手坐标系变换到了左手坐标系。这意味着,离摄像机越远, z z z值越大
正交投影
和透视投影类似,在Unity中,正交投影的六个裁剪平面也是由Camera组件中的参数和Game视图的横纵比共同决定,如下图所示:
正交投影的视锥体是一个长方体,因此计算上相比透视投影来说更加简单。由上图可以看出,可以通过Camera组件的Size属性来改变视锥体竖直方向上高度的一般,而Clipping Planes中的Near和Far参数可以控制是重罪提的近裁剪平面和远裁剪平面距离摄像机的远近。这样就可以求出视锥体近裁剪平面和远裁剪平面的高度,也就是:
n e a r C l i p P l a n e H e i g h t = 2 ⋅ S i z e f a r C l i p P l a n e H e i g h t = n e a r C l i p P l a n e H e i g h t nearClipPlaneHeight=2\cdot Size\\ farClipPlaneHeight=nearClipPlaneHeight nearClipPlaneHeight=2⋅SizefarClipPlaneHeight=nearClipPlaneHeight
现在还缺乏横向的信息。同样可以通过摄像机的横纵比得到。假设,当前摄像机的横纵比为Aspect,那么:
n e a r C l i p P l a n e W i d t h = A s p e c t ⋅ n e a r C l i p P l a n e H e i g h t f a r C l i p P l a n e W i d t h = n e a r C l i p P l a n e W i d t h nearClipPlaneWidth=Aspect\cdot nearClipPlaneHeight\\ farClipPlaneWidth=nearClipPlaneWidth nearClipPlaneWidth=Aspect⋅nearClipPlaneHeightfarClipPlaneWidth=nearClipPlaneWidth
现在可以根据已知的Near、Far、Size和Aspect的值来确定正交投影的裁剪矩阵。如下:
M o r t h o = [ 1 A s p e c t ⋅ S i z e 0 0 0 0 1 S i z e 0 0 0 0 − 2 F a r − N e a r − F a r + N e a r F a r − N e a r 0 0 0 1 ] \mathbf{M}_{ortho}=\begin{bmatrix} \frac{1}{Aspect\cdot Size}&0&0&0\\ 0&\frac{1}{Size}&0&0\\ 0&0&-\frac{2}{Far-Near}&-\frac{Far+Near}{Far-Near}\\ 0&0&0&1 \end{bmatrix} Mortho= Aspect⋅Size10000Size10000−Far−Near2000−Far−NearFar+Near1
同样,这里的投影是建立在 Unity 对坐标系的假定上面的
一个顶点和上述投影相乘后的结果如下:
P c l i p = M o r t h o P v i e w = [ 1 A s p e c t ⋅ S i z e 0 0 0 0 1 S i z e 0 0 0 0 − 2 F a r − N e a r − F a r + N e a r F a r − N e a r 0 0 0 1 ] [ x y z 1 ] = [ x A s p e c t ⋅ S i z e y S i z e − 2 z F a r − N e a r − F a r + N e a r F a r − N e a r 1 ] \begin{aligned} \mathbf{P}_{clip}&=\mathbf{M}_{ortho}\mathbf{P}_{view}\\ &=\begin{bmatrix} \frac{1}{Aspect\cdot Size}&0&0&0\\ 0&\frac{1}{Size}&0&0\\ 0&0&-\frac{2}{Far-Near}&-\frac{Far+Near}{Far-Near}\\ 0&0&0&1 \end{bmatrix}\begin{bmatrix} x\\y\\z\\1 \end{bmatrix}\\ &=\begin{bmatrix} \frac{x}{Aspect\cdot Size}\\\frac{y}{Size}\\-\frac{2z}{Far-Near}-\frac{Far+Near}{Far-Near}\\1 \end{bmatrix} \end{aligned} Pclip=MorthoPview= Aspect⋅Size10000Size10000−Far−Near2000−Far−NearFar+Near1 xyz1 = Aspect⋅SizexSizey−Far−Near2z−Far−NearFar+Near1
可以注意到,和透视投影不同的是,使用正交投影的投影矩阵对顶点进行变换后,其 w w w分量仍然为1。本质是因为投影矩阵最后一行的不同,透视投影的投影矩阵的最后一行是 [ 0 0 − 1 0 ] \begin{bmatrix}0&0&-1&0\end{bmatrix} [00−10]。这样的选择是有原因的,是为了为齐次除法做准备。
判断一个变换后的顶点是否位于视锥体内使用的不等式和透视投影中的一样,这种通用性也是为什么要使用投影矩阵的原因之一,下图显示了经过上述投影矩阵后,正交投影的视锥体的变化
同样,裁剪矩阵改变了空间的旋向性。可以注意到,经过正交投影变换后的顶点实际已经位于一个立方体内了
屏幕空间
经过投影矩阵的变换后,可以进行裁剪操作。当完成了所有的裁剪工作后,就需要进行真正的投影了,也就是说需要把视锥体投影到屏幕空间中。经过这一步变换会得到真正的像素位置,而不是虚拟的三维坐标
屏幕空间是一个二维空间,因此必须把顶点从裁剪空间投影到屏幕空间中,来生成对应的2D坐标。这个过程可以理解成有两个步骤
首先需要进行标准齐次除法,也被称为透视除法。虽然这个步骤听起来很陌生,但是他实际上非常简单,也就是用齐次坐标系的 w w w分量去除 x , y , z x,y,z x,y,z分量,在OpenGL中,把这一步得到的坐标叫做归一化的设备坐标。经过这一步,可以把坐标从齐次裁剪坐标空间转换到NDC中。经过透视投影变换后的裁剪空间,经过齐次除法后变换到一个立方体内。按照 OpenGL 的传统,这个立方体的 x , y , z x,y,z x,y,z分量的范围都是[-1,1]。但在 DirectX 这样的 API 中, z z z分量的范围会是[0,1]。而Unity选择了OpenGL这样的齐次裁剪空间,如下图所示
对于正交投影来说,它的裁剪空间实际已经是一个立方体了,而且由于经过正交投影矩阵变换后的顶点的 w w w分量是1,因此齐次除法并不会对顶点的 x , y , z x,y,z x,y,z坐标产生影响。如下图所示
经过齐次除法后,透视投影和正交投影的视锥体都变换到一个相同的立方体内。现在可以根据变换后的 x x x和 y y y坐标来映射输出窗口的对应像素坐标
在Unity中,屏幕空间的左下角的像素坐标是(0,0),右上角的像素是(pixelWidth,pixelHeight)。由于当前 x x x和 y y y坐标都是[-1,1]。因此这个映射的过程就是一个缩放的过程
齐次除法和屏幕映射的过程可以使用下面的公式来总结:
s c r e e n x = c l i p x ⋅ p i x e l W i d t h 2 ⋅ c l i p w + p i x e l W i d t h 2 s c r e e n y = c l i p y ⋅ p i x e l H e i g h t 2 ⋅ c l i p w + p i x e l H e i g h t 2 screen_x=\frac{clip_x\cdot pixelWidth}{2\cdot clip_w}+\frac{pixelWidth}{2}\\ screen_y=\frac{clip_y\cdot pixelHeight}{2\cdot clip_w}+\frac{pixelHeight}{2} screenx=2⋅clipwclipx⋅pixelWidth+2pixelWidthscreeny=2⋅clipwclipy⋅pixelHeight+2pixelHeight
通常 z z z分量会被用于深度缓冲。一个传统的方式是把 c l i p z c l i p w \frac{clip_z}{clip_w} clipwclipz的值直接存进深度缓冲中,但这并不是必须的。通常驱动生产商会根据硬件来选择最好的存储格式。此时 c l i p w clip_w clipw也不会被抛弃,尽管它已经完成了它的主要工作——在齐次除法中作为分母来得到NDC,但它仍然会在后续的一些工作中起到重要的作用,例如进行透视矫正插值
在Unity中,从裁剪空间到屏幕空间的转换是由底层实现的,顶点着色器只需要把顶点转换到裁剪空间即可
总结
下图总结了这些空间和用于变换的矩阵
顶点着色器的最基本的任务就是把顶点坐标从模型空间转换到裁剪空间中。这对应了上图中的前三个顶点变换过程。而在片元着色器中通常也可以得到该片元在屏幕空间的像素位置。
在Unity中,坐标系的旋向性也随着变化发生了改变。下图总结了Unity中各个空间使用的坐标系旋向性
上图可以发现,只有在观察空间中Unity使用了右手坐标系
需要注意的是,这里仅仅给出的是一些最重要的坐标空间。还有一些空间在实际开发中也会遇到,例如切线空间。切线空间通常用于法线映射
法线变换
法线,也被称为法矢量,法线是需要特殊处理的一种方向矢量。在游戏中,模型的一个顶点往往会携带额外的信息,而顶点法线就是其中一种信息。当变换一个模型的时候,不仅需要变换它的顶点,还需要变换顶点法线,以便在后续处理(如片元着色器)中计算光照等
一般来说,点和绝大部分方向矢量都可以使用 4 × 4 4\times 4 4×4或 3 × 3 3\times 3 3×3的变换矩阵 M A − > B \mathbf{M}_{A->B} MA−>B把其从坐标空间 A \mathbf{A} A变换到坐标空间 B \mathbf{B} B中。但在变换法线的时候,如果使用同一个变换矩阵,可能就无法确保维持发现的垂直性
另一种方向适量——切线,也被称为切矢量。与法线类似,切线往往也是模型顶点携带的一种信息。它通常与纹理空间对齐,而且与法线方向垂直,如下图所示
由于切线是由两个顶点之间的差值计算得到的,因此可以直接使用用于变换顶点的变换矩阵来变换切线。建设使用 3 × 3 3\times 3 3×3的变换矩阵 M A − > B \mathbf{M}_{A->B} MA−>B来变换顶点(注意,这里涉及的变换矩阵都是 3 × 3 3\times 3 3×3的矩阵,不考虑平移变换。这是因为切线和法线都是方向矢量,不会受平移的影响),可以由下面的式子直接得到变换后的切线:
T B = M A − > B T A \mathbf{T}_B=\mathbf{M}_{A->B}\mathbf{T}_A TB=MA−>BTA
其中 T A \mathbf{T}_A TA和 T B \mathbf{T}_B TB分别表示在坐标空间A下和坐标空间B下的切线方向。但如果直接使用 M A − > B \mathbf{M}_{A->B} MA−>B来变换法线,得到的新的发现方向可能就不会与表面垂直了,如下图所示
应该使用哪个矩阵来变换法线呢?可以由数学约束条件来推出这个矩阵。因为同一个顶点的切线 T A \mathbf{T}_A TA和法线 N A \mathbf{N}_A NA必须满足垂直条件,即 T A ⋅ N A \mathbf{T}_A\cdot\mathbf{N}_A TA⋅NA。给定变换矩阵 M A − > B \mathbf{M}_{A->B} MA−>B,已经知道 T B = M A − > B T A \mathbf{T}_B=\mathbf{M}_{A->B}\mathbf{T}_A TB=MA−>BTA。现在想要找到一个矩阵 G \mathbf{G} G来变换法线 N A \mathbf{N}_A NA,使得变换后的法线仍然与切线垂直。即:
T B ⋅ N B = ( M A − > B T A ) ⋅ ( G N A ) = 0 \mathbf{T}_B\cdot\mathbf{N}_B=(\mathbf{M}_{A->B}\mathbf{T}_A)\cdot(\mathbf{GN}_A)=0 TB⋅NB=(MA−>BTA)⋅(GNA)=0
对上式进行一些推导后可得
( M A − > B T A ) ⋅ ( M A − > B T A ) T ( G N A ) = T A T M A − > B T G N A = T A T ( M A − > B T G ) N A = 0 (\mathbf{M}_{A->B}\mathbf{T}_A)\cdot(\mathbf{M}_{A->B}\mathbf{T}_A)^T(\mathbf{GN}_A)=\mathbf{T}_A^T\mathbf{M}_{A->B}^T\mathbf{GN}_A=\mathbf{T}_A^T(\mathbf{M}_{A->B}^T\mathbf{G})\mathbf{N}_A=0 (MA−>BTA)⋅(MA−>BTA)T(GNA)=TATMA−>BTGNA=TAT(MA−>BTG)NA=0
由于 T A ⋅ N A \mathbf{T}_A\cdot\mathbf{N}_A TA⋅NA,因此如果 M A − > B T G = I \mathbf{M}_{A->B}^T\mathbf{G}=\mathbf{I} MA−>BTG=I,那么上式即可成立。也就是说,如果 G = ( M A − > B − 1 ) T \mathbf{G}=(\mathbf{M}_{A->B}^{-1})^T G=(MA−>B−1)T,即使用原变换矩阵的逆转矩阵来变换法线就可以得到正确的结果
值得注意的是,如果变换矩阵 M A − > B \mathbf{M}_{A->B} MA−>B是正交矩阵,那么 M A − > B − 1 = M A − > B T \mathbf{M}_{A->B}^{-1}=\mathbf{M}_{A->B}^T MA−>B−1=MA−>BT,因此 ( M A − > B T ) − 1 = M A − > B (\mathbf{M}_{A->B}^T)^{-1}=\mathbf{M}_{A->B} (MA−>BT)−1=MA−>B,也就是说可以使用用于变换顶点的变换矩阵来直接变换法线。如果变换只包含旋转变换,那么这个变换矩阵就是正交矩阵。而如果变换只包含旋转和统一缩放,而不包含非统一缩放,利用统一缩放系数 k k k来得到变换矩阵 M A − > B \mathbf{M}_{A->B} MA−>B的逆转置矩阵 ( M A − > B T ) − 1 = 1 k M A − > B (\mathbf{M}_{A->B}^T)^{-1}=\frac{1}{k}\mathbf{M}_{A->B} (MA−>BT)−1=k1MA−>B。这样就可以避免计算逆矩阵的过程。如果变换中包含了非统一变换,那么就必须要求解逆矩阵来得到变换法线的矩阵
Unity Shader 的内置变量(数学篇)
变换矩阵
首先是用于坐标空间变换的矩阵。下表给出了Unity5.2版本提供的所有内置变换矩阵。下面所有的矩阵都是 float 4 × 4 4\times 4 4×4 类型的
变量名 | 描述 |
---|---|
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提供了一些内置变量来允许访问当前正在渲染的摄像机参数信息。这些参数对应了摄像机上的Camera组件中的属性值。下表给出了Unity5.2 版本提供的这些变量
变量名 | 类型 | 描述 |
---|---|---|
_WorldSpaceCameraPos | float3 | 该摄像机在世界空间中的位置 |
_ProjectionParams | float4 | x x x=1.0(或-1.0,如果正在使用一个反转的投影矩阵进行渲染), y = N e a r , z = F a r , w = 1.0 + 1.0 / F a r y=Near,z=Far,w=1.0+1.0/Far y=Near,z=Far,w=1.0+1.0/Far,其中Near和Far分别是近裁剪平面和远裁剪平面和摄像机的距离 |
_ScreenParams | float4 | x = w i d t h , y = h e i g h t , z = 1.0 + 1.0 / h e i g h t x=width,y=height,z=1.0+1.0/height x=width,y=height,z=1.0+1.0/height,其中 width 和 height 分别是该摄像机的渲染目标的像素宽度和高度 |
_ZBufferParams | float4 | x = 1 − F a r / N e a r , y = F a r / N e a r , z = x / F a r , w = y / F a r x=1-Far/Near,y=Far/Near,z=x/Far,w=y/Far x=1−Far/Near,y=Far/Near,z=x/Far,w=y/Far,该变量用于线性化 Z 缓存中的深度值 |
unity_OrthoParams | float4 | x = w i d t h , y = h e i g h t , z x=width,y=height,z x=width,y=height,z没有定义, w = 1.0 w=1.0 w=1.0(该摄像机是正交摄像机)或 w = 0.0 w=0.0 w=0.0(该摄像机是透视摄像机),其中width和height是正交投影摄像机的宽度和高度 |
unity_CameraProjection | float4 x 4 | 该摄像机的投影矩阵 |
unity_CameraInvProjection | float4 x 4 | 该摄像机的投影矩阵的逆矩阵 |
unity_CameraWorldClipPlanes[6] | float4 | 该摄像机的6个裁剪平面在世界空间下的等式,按如下顺序:左、右、下、上、近、远裁剪平面 |