天天看点

透视矫正插值

1、介绍

我们将推导(并证明)一种在屏幕空间通过线性插值实现透视校正插值的方法。在线性图形基元(如直线和多边形)的光栅化过程中,直接的屏幕空间顶点属性线性插值通常不会产生正确的透视结果。

在传统的光栅图形中,颜色、纹理坐标和法向量等属性通常与图形基元的顶点相关联[1,2]。在三维空间中,每个属性的值在每个图形基元中都是线性变化的,在三维顶点通过透视投影投影到二维图像平面(或屏幕)之后,三维空间中属性值的这种线性变化不会转化为屏幕空间中类似的线性变化。因此,如果对屏幕空间中的这些属性值应用直接的线性插值,通常会在图像中得到错误的结果。图1显示了这样一个例子。

透视矫正插值

图1:屏幕空间(或图像平面)中属性值的直接线性插值并不总是产生透视正确的结果。

为了便于说明,图1仅显示了二维空间中投影到一维图像平面上的一条直线,但相同的参数也可以应用于投影到二维图像平面上的三维线性几何图元。图中,二维空间中AB线的A点和B点分别投影到一维图像平面中的A点和B点上。顶点处的属性值是强度值。在A处,强度值为0.0,在B处,强度值为1.0。因此,a和b处的强度值分别为0.0和1.0。假设c是图像平面中a和b之间的中点。如果我们在图像平面(或屏幕空间)线性插值a和b处的强度值,则c处的强度值为0.5。但是,如果我们将点c“取消投影”到AB线上的点C上,我们可以看到C不必是A和B之间的中点。由于强度值在A到B之间呈线性变化(在3D空间中),如果C不是A和B之间的中点,则C处的强度值不应为0.5。

尽管如此,仍然可以通过在屏幕空间中进行线性插值来获得透视校正结果。这可以通过插值属性的某些函数的值来实现,而不是直接插值属性。然后,每个插值结果由另一个函数(逆函数)进行变换,以获得屏幕空间中所需点的最终属性值。您将看到这些函数使用顶点的z值

2、插值z值

在透视投影将基本体的三维顶点投影到二维图像平面上之前,许多图形渲染系统假定虚拟摄影机已经位于三维空间的原点,并沿-z或+z方向进行观察。这定义了一个称为相机坐标系的坐标系。相机的固定观察方向还允许我们始终有一个垂直于z轴的图像平面,这大大简化了透视投影计算。在不丧失一般性的情况下,我们假设摄像机正朝+z方向看,并且图像平面在摄像机前面的距离d处(见图2)。

许多光栅图形渲染系统使用z缓冲区[1,2]来执行隐藏曲面移除。这要求在屏幕上投影基本体的每个像素处,必须知道基本体上相应3D点的z坐标(z值)。但是,由于实际只投影基本体的顶点,因此它们在屏幕空间中对应的2D图像点是屏幕空间中已知z值的唯一位置。为了更快的光栅化,我们希望使用已知的顶点图像点的z值来导出其他像素的z值。

z值可以被视为一个属性,其值在3D线性基本体中线性变化。与我们在图1中看到的示例一样,屏幕空间中z值的直接线性插值并不总是产生透视正确的结果。但是,我们将在下面看到,我们实际上可以线性插值z值的倒数,以获得正确的结果。

与图1类似,图2显示了二维相机坐标系中投影到一维图像平面上的一条线。标题解释了我们将在公式推导中使用的符号。在图中,s是图像平面上的插值参数,t是基本体上的插值参数。

透视矫正插值

图2:虚拟摄像机在摄像机坐标系中以+z方向观察。图像平面在相机前面距离d处。A、 B和C分别是基本体上属性值为I1、I2和It的点,它们在图像平面上的图像分别是A、B和C。s和t是用于线性插值的参数。

我们的目标是导出公式,以便在屏幕空间中正确地插值z值。同样的推导可以直接应用于投影到二维图像平面上的三维线性基本体的情况。参照图2,通过相似的三角形,我们得到

透视矫正插值

通过在图像平面(或屏幕空间)中进行线性插值,我们得到

透视矫正插值

通过对摄像机坐标系中的基元进行线性插值,我们得到

透视矫正插值

将(4)和(5)代入(3),

透视矫正插值

将(1)和(2)代入(7),

透视矫正插值

将(6)代入(8),

透视矫正插值

可以简化为

透视矫正插值

把(10)带入(6),我们得到,

透视矫正插值
透视矫正插值

方程(12)告诉我们,只要在1/Z1和1/Z2之间进行线性插值,就可以正确地导出图像平面中c点的z值,然后计算插值结果的倒数。对于z缓冲区,甚至不需要计算最终的倒数,因为我们只需要在z值比较期间反转比较操作。

3、插值属性值

在这里,我们希望导出公式,以便在屏幕空间中正确地插值其他属性值。请再次参考图2。通过在摄像机坐标系中的基元上对属性值进行线性插值,我们得到

透视矫正插值

把(10)带入(13),我们得到,

透视矫正插值

可以重新排列成

透视矫正插值

从(12),我们可以看到(15)中的分母是1/Zt。因此,

透视矫正插值

(16)的意思是,只需在I1/Z1和I2/Z2之间进行线性插值,就可以正确地导出图像平面中c点的属性值,然后将插值结果除以1/Zt,其本身可以通过屏幕空间中的线性插值导出,如(12)所示。

参考文献

[1]詹姆斯福利,安德里斯范达姆,史蒂文费纳和约翰休斯。计算机图形学:原理与实践,第二版。Addison Wesley,1990。[2]Mason Woo,Jackie Neider,Tom Davis,Dave Shreiner(OpenGL架构评审委员会)。OpenGL编程指南,第三版:学习OpenGL的官方指南,1.2版。艾迪森·韦斯利,1999年。