Vertex Transformation

Posted by Peinan on March 18, 2019

顶点变换 (Vertex Transformation)

最近在学Shader编程中有关深度纹理(Depth Texture)的使用,里面涉及到比较多的空间转换和顶点变换,之前看的已经忘得差不多了,拿出来重新复习一下。

齐次坐标 (homogeneous coordinate)

表示一个点在某个空间的位置通常可以用三维坐标,如(x, y, z),但在空间转换中,通常用四维齐次坐标(简称齐次坐标)来表示一个点。

对于一个点,三维坐标(x, y, z)对应齐次坐标(x, y, z, 1)

对于一个空间矢量(表示方向),三维坐标(x, y, z)对应齐次坐标(x, y, z, 0)

采用齐次坐标来代替普通的三维坐标进行计算有以下优点

  1. 可以有效区分空间矢量,前者w分量非0,后者w分量为0,由此我们可以得知在平移、旋转、缩放三种变换中(即进行矩阵乘法),点会进行全部三种变换,而空间矢量只会进行其中的旋转和缩放,因为平移对矢量是无意义的。

  2. 齐次坐标的w分量在投影矩阵变换(观察空间->裁剪空间)和最后的投影到屏幕空间中发挥重要的作用

模型空间 (object space)

又叫做物体空间,即以某个特定的场景物体为基准建立的三维空间。对于特定的物体,模型空间坐标系会随着物体的变化而发生相应的变化。

模型空间的原点和坐标轴由模型本身决定,模型空间的主要作用是描述物体内部不同位置点的相对坐标。

在Shader编程中,模型空间下的顶点坐标是最初能够从Mesh中调用得到的顶点坐标。通过一系列的变换,我们把模型空间下的坐标转化到其它空间中进行深入计算。

世界空间 (world space) 世界空间比较好理解,它是一个宏观的概念,可以说是一个包含了场景所有物体的标准化空间。

将顶点从模型空间变换到世界空间是顶点变换的第一步,而这个参与运算的矩阵系数就由Transform组件中的相关信息(position, rotation, scale)来决定。

在世界空间中进行光照等计算是合适的。

观察空间 (view space) 观察空间是一种特殊的模型空间,即摄像机的模型空间。需要注意的是,其它坐标系在Unity中全部都是左手坐标系,而观察坐标系是右手坐标系(具体来说,x轴指向右,y轴指向上时,z轴指向相机的后方)。因此,当我们调用Camera.cameraToWorldMatrix以及Camera.worldToCameraMatrix进行空间转换时,要注意坐标轴方向不同带来的差异。

将顶点从世界空间变换到观察空间是顶点变换的第二步,参与变换的矩阵叫做观察矩阵,矩阵系数由摄像机Transform组件中的相关信息(position, rotation, scale)来决定。

要注意观察空间与裁剪空间的区分。

裁剪空间 (clip space) 裁剪空间的目的是对渲染图元进行裁剪,即舍去位于裁剪空间外部的图元,裁剪与裁剪空间相交的图元。

对于透视投影(Perspective Projection),使用金字塔型视锥体进行裁剪。透视投影的投影矩阵如下: 透视投影的投影矩阵

透视投影的投影矩阵

对于正交投影(Orthographic Projection),使用长方体视锥体进行裁剪。正交投影的投影矩阵如下: 正交投影的投影矩阵

正交投影的投影矩阵

关于投影矩阵的推导,我们可以从结果出发,即我们希望将原坐标归一化到处理后的坐标,需要进行一次坐标变换,这次坐标变换的变换矩阵就是上面给出的矩阵。

无论是透视投影还是正交投影,投影变换都可以看作是把顶点的x, y, z坐标进行不同程度的缩放(类似归一化),其中z坐标还涉及到一个平移,缩放的目的是为了方便裁剪。

此时,如果一个顶点在视锥体之内,那么变换后的坐标应该满足:

-w <= x <= w

-w <= y <= w

-w <= z <= w

屏幕空间 (screen space) 需要注意的是,投影矩阵变换实际上和投影没有关系,只是完成了裁剪。这里我们就要进行真正的投影,来把裁剪空间中的顶点变换到屏幕空间中,从而得到二维的屏幕坐标。

这一步的本质时进行一次齐次除法,就是使用齐次坐标的w分量去除x, y, z分量(对于正交投影,w分量始终等于1,因此相当于不做任何处理),对于透视投影,经过齐次出发后,原来的金字塔型视锥体会变成一个正方体(这和正交投影的结果一致)。

在这个对于两种投影方式都相同的正方体中(该正方体的两个端点分别为(-1, -1, -1)点和(1, 1, 1)点),顶点的坐标被称为归一化的设备坐标(Normalized Device Coordinates, NDC),经过这一步后,我们就可以根据顶点的远近关系来绘制屏幕的图像了。

需要注意的是,NDC的x, y坐标范围是[-1, 1],而Unity屏幕像素坐标范围是[0, 1],因此这里要进行一次线性变换。

透视投影的投影变换与齐次除法示意图

正交投影的投影变换与齐次除法示意图

模型变换、观察变换与投影变换在Vertex Shader中通常串联成一个矩阵即MVP矩阵,用于把顶点从模型空间中直接转换到裁剪空间中。UnityObjectToClipPos(vertex)函数,输出为裁剪空间坐标

切线空间 (tangent space) 在处理法线贴图时,经常要用到切线空间,这是因为我们使用的法线贴图通常是在切线空间中绘制的。

切线空间是相对模型的某个定点而言的,即不同的顶点拥有不同的切线空间。

切线空间的坐标轴由顶点的法线(normal)、切线(tangent)和副切线(binormal)三条相互垂直的线组成。

图片来自《Unity Shader入门精要》