视口(viewport)是渲染结果最终落到的屏幕矩形区域。
在本博客中,我们约定视口矩形由左下角位置 (x0,y0) 和宽高 (wvp,hvp) 描述。我们会将 NDC坐标 映射到视口矩形,这是 屏幕映射 的最后一步。
映射就是一次普通的缩放加平移:x、y 从 [−1,1] 拉到视口的宽高,z 单独映射成深度值写进深度缓冲。
xscreen=2wvp(xndc+1)+x0,yscreen=2hvp(yndc+1)+y0
zdepth=2zndc+1(fvp−nvp)+nvp
其中 [nvp,fvp] 是深度范围,OpenGL 的 glDepthRange 默认取 [0,1]。所以"z 保持在 [−1,1] 不变"只在深度范围取 [−1,1] 时才成立,而 zndc∈[−1,1] 经默认深度范围映射后同样是线性的(不会影响深度测试的相对顺序)。
视口和窗口是完全不同的概念:窗口是操作系统中窗口管理器给应用的像素画布与事件接受的总和,视口只是画布上的一个矩形。两者的关系决定了它的三种典型用法:
- 一个窗口可以有多个视口:分屏双人、小地图、编辑器里同时开好几个 3D 预览
- 视口可以小于窗口,也可以超出窗口之外(当然多余的部分会被裁剪)
- 视口矩形之外的片元不会被生成,所以视口隐式地充当了一次矩形裁剪