透视矫正插值
传统的GPU渲染流水线(管线)是基于光栅化的一套流程,之所以要强调传统,是为了将之区别于基于光线追踪(ray trace)的流水线和基于体素化的流水线。在光栅管线中,最基本的2个着色器是顶点着色器和像素着色器,在下图中,除了2个着色器可编程,中间三个时钟节点都是固定的,只能配置不可编程。
想要了解什么是“透视矫正插值”,先要知道什么是插值,插值发生在流水线的光栅化阶段,这一阶段将根据三角形三个顶点的顶点属性值(坐标、法线、UV、颜色等)决定其中每一个像素的插值属性。
最简单的插值办法就是线性插值,所以我们先来了解一下什么是线性变换。如果2个变量之间可以用y=kx+b表示,那么x和y就是线性相关,从x变换到y就是线性变换,比如下图中,每个顶点乘上一个同维度的线性矩阵后,新的形状保持了一些特性:平行线仍然是平行的,各处密度均匀,原点不变。如果原点位置变化的话那就得加上平移,线性矩阵变成仿射矩阵。
那什么是线性插值呢?即均匀地插值,比如线段的中点的插值一定是两端之和处以2,这个例子是一维的插值,多维也是类似。下图中列举了顶点色和顶点法线的线性插值。
线性插值有问题吗,为什么要对它进行矫正??这要看情况,如果是正交投影后的光栅阶段,线性插值是正确的,但透视投影就比较复杂了。在上个月的分享《视锥体:初等几何解析》中,我们探讨了透视投影中最重要的几何模型:视椎体。在这个模型中物体有“近大远小”的客观自然规律,所以屏幕三角形中不同部位的密度是不均匀的。
关于“密度”可以这样理解:在原始三角形上均匀的撒一些散点,待它被投影到屏幕三角形上之后,这些点是否仍然分布均匀?想象一下,很显然在正交投影的情况下,是均匀的,但透视投影中,距离相机近的部位散点更稀疏,远处的散点更密集。
于是我们以UV插值为例,如果仍然使用线性插值,会出现下图中中间那种情况:三角形中每个方块都是面积相等的平行四边形。但这不符合自然规律,正确但景象应该是下图右边的样子。
所以怎么办呢,不能简单的线性插值,所以我们要找到插值和插值点之间真正的函数关系,所以我引入了下面的视锥侧剖图:其中O点是摄像机,L是近截面,ax+bz=c是三角形。我们抽象一个虚拟的插值点t,范围是0~1,t从(P1,-e)出发,匀速运动至(p2,-e),t的值也匀速地从0增长至1。图中可以看出,近截面上的均匀散点反投影到三角形上时变得不均匀了,此外还能得出,插值点的x坐标P与t线性相关。
如果我们做如下图的相似三角形,还能得出x/z与t也线性相关。
然后我们将上图中的等式带入到原三角线的方程中又得到如下图的等式,其中红色字符都是变量,因此1/z和t也线性相关。根据线性相关的传递性,x与z与Q都线性相关,最终我们能推导出Q/z与t线性相关。
于是能够得出结论:在原始三角形上,插值与插值点的位置线性相关,但在透视投影后的屏幕三角形上,插值与Z的比值与插值点的位置线性相关。所以这就是矫正的方法:不能按照线性函数来插值,而应该按照下图中非线性的公式来插值。
以上公式的详细推导过程可以参考下面列举的参考资料。