UnityShader——基础篇之学习Shader所需的数学基础——下

裁剪空间

  顶点接下来要从观察空间转换到裁剪空间(也被称为齐次裁剪空间) 中,这个用于变换的矩阵叫做裁剪矩阵,也被称为投影矩阵

  裁剪空间的目标是能够方便地对渲染图元进行裁剪:完全位于这块空间内部的图元将会被保留,完全位于这块空间外部的图元将会被剔除,而与这块空间边界相交的图元就会被裁剪。这块空间是由视锥体来决定

  视锥体指的是空间中的一块区域,这块区域决定了摄像机可以看到的空间。视锥体由六个平面鲍威尔成,这些平面也被称为裁剪平面。视锥体有两种类型,这涉及两种投影类型:一种是正交投影,一种是透视投影。下图显示了从同一位置、同一角度渲染同一个场景的两种摄像机的渲染结果

在这里插入图片描述
  从图中可以发现,在透视投影中,地板上的平行线并不会保持平行,离摄像机越近网格越大,离摄像机越远网格越小。而在正交投影中,所有的网格大小都一样,而且平行线会一直保持平行。可以注意到,透视投影模拟了人眼看世界的方式,而正交投影则完全保留了物体的距离和角度。因此,在追求真实感的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=2Neartan2FOVfarClipPlaneHeight=2Fartan2FOV

  现在还缺少缺乏横向的信息。这可以通过摄像机的横纵比得到。在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= Aspectcot2FOV00002cot2FOV0000FarNearFar+Near100FarNear2NearFar0

  需要注意的是,这里的投影矩阵是建立在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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值