《OGL dev》Etay Meiri Tutorial 12 - Perspective Projection 笔记
渲染流程:
- 将世界空间进行投影变换,变换到Clip Space(裁剪空间)。
- vertex shader不改变空间,gl_Position依旧输出到Clip Space。
- Clipper进行裁剪,边界的三角形裁剪为0-2个三角形。
- 屏幕映射:执行透视除法,将顶点坐标的所有分量都除以w分量,变换到NDC Space(Normalized Device Coordinates)。NDC Space的xyz坐标都处于[-1, 1]区间内。
- 屏幕映射:执行视口变换,从NDC Space变换到Screen Space(屏幕空间)。
- 光栅化:光栅器依draw call设定的拓扑(一般都是三角形)绘制图元,并进行插值。
- 光栅化:光栅器为每一个插值的结果调用fragment shader输出片元。
- 光栅化:光栅器对片元进行深度测试等一系列测试,然后绘制到屏幕上。
透视投影变换由以下四个值确定:
- aspect ratio(宽高比):作为投影目标的长方形区域的宽与高之间的比值,
aspect ratio = screen width / screen height
。 - vertical field of view(垂直视野):yz平面,摄影机张开的角度。
- 近Z平面的位置(z坐标):这允许我们剪除离摄影机太近的对象。
- 远Z平面的位置(z坐标):这允许我们剪除距离摄影机太远的对象。
- 隐含:摄影机处于原点,上方向为Y轴正方向,朝向z轴正方向。
推导透视投影矩阵:
- 假设vertical field of view角度为a,宽高比为ar,在投影变换前,近Z平面的z坐标为NearZ,远Z平面的z坐标为FarZ。可得:
- 近Z平面的y坐标区间为[-NearZ * tan(a / 2), NearZ * tan(a / 2)]。
- 近Z平面的x坐标区间为[-ar * NearZ * tan(a / 2), ar * NearZ * tan(a / 2)]。
- 远Z平面的y坐标区间为[-FarZ * tan(a / 2), FarZ * tan(a / 2)]。
- 远Z平面的x坐标区间为[-ar * FarZ * tan(a / 2), ar * FarZ * tan(a / 2)]。
- 透视投影变换将顶点的z坐标写入到w分量,供透视除法使用。
- 因为Clip Space除以w分量就得到NDC Space,近Z平面z坐标映射到-1,远Z平面z坐标映射到1。所以Clip Space中,近Z平面的z坐标为-NearZ,远Z平面的z坐标仍为FarZ。
- 因为NDC Space中xy坐标的区间也是[-1, 1],所以Clip Space中,近Z平面上xy坐标的区间为[-NearZ, NearZ],远Z平面上xy坐标的区间为[-FarZ, FarZ]。
- 综上透视投影变换使得:
- x坐标
- -ar * NearZ * tan(a / 2)变换到-NearZ。
- ar * NearZ * tan(a / 2)变换到NearZ。
- -ar * FarZ * tan(a / 2)变换到-FarZ。
- ar * FarZ * tan(a / 2)变换到FarZ。
- y坐标
- -NearZ * tan(a / 2)变换到-NearZ。
- NearZ * tan(a / 2)变换到NearZ。
- -FarZ * tan(a / 2)变换到-FarZ。
- FarZ * tan(a / 2)变换到FarZ。
- z坐标
- NearZ变换到-NearZ。
- FarZ不变。
- w坐标:从1变换到z。
- x坐标
- 反推透视投影矩阵:
- x轴,只进行缩放,缩放值为。因此,矩阵第一行为[, 0, 0, 0]。
- y轴,只进行缩放,缩放值为。因此,矩阵第二行为[0, , 0, 0]。
- z轴,先缩放后平移。因为区间从[NearZ, FarZ]变换到[-NearZ, FarZ],所以缩放值为。缩放值后,FarZ变换到,要变换到FarZ,需要平移FarZ - = 。经验证NearZ缩放后,平移,结果为-NearZ。因此,平移的值为,矩阵第三行为[0, 0, , ]。
- w分量,从1变换到z。因此,矩阵第四行为[0, 0, 1, 0]。
- 组成透视投影矩阵如下: