OpenGL学习笔记(二十)

深度缓冲的可视化

片段着色器中,内建gl_FragCoord向量的z值包含了那个特定片段的深度值。如果我们将这个深度值输出为颜色,就可以显示场景中所有片段的深度值。我们可以根据片段的深度值返回一个颜色向量来完成这一工作:
void main()
{
FragColor = vec4(vec3(gl_FragCoord.z), 1.0);
}
如果运行程序的话,会注意到所有东西都是白色的,看起来就像所有的深度值都是最大的1.0。所以为什么没有靠近0.0(即变暗)的深度值呢?

你可能还记得在上一部分中说到,屏幕空间中的深度值是非线性的,即它在z值很小的时候有很高的精度,而z值很大的时候有较低的精度。片段的深度值会随着距离迅速增加,所以几乎所有的顶点的深度值都是接近于1.0的。如果我们小心地靠近物体,你可能会最终注意到颜色会渐渐变暗,显示它们的z值在逐渐变小。这就是深度值的非线性性质。近处的物体比起远处的物体对深度值有着更大的影响。只需要移动几厘米就能让颜色从暗完全变白。

然而,我们也可以让片段非线性的深度值变换为线性的。要实现这个,我们需要仅仅反转深度值的投影变换。这也就意味着我们需要首先将深度值从[0, 1]范围重新变换到[-1, 1]范围的标准化设备坐标(裁剪空间)。接下来我们需要像投影矩阵那样反转这个非线性方程,并将这个反转的方程应用到最终的深度值上。最终的结果就是一个线性的深度值了。

首先将深度值变换为NDC:
float z = depth * 2.0 - 1.0;

接下来使用获取到的z值,应用逆变换来获取线性的深度值:
float linearDepth = (2.0 * near * far) / (far + near - z * (far - near));

这个方程是用投影矩阵推导得出的,返回一个near与far之间的深度值。

将屏幕空间中非线性的深度值变换至线性深度值的完整片段着色器如下:
#version 330 core
out vec4 FragColor;

float near = 0.1;
float far = 100.0;

float LinearizeDepth(float depth)
{
float z = depth * 2.0 - 1.0; // back to NDC
return (2.0 * near * far) / (far + near - z * (far - near));
}

void main()
{
float depth = LinearizeDepth(gl_FragCoord.z) / far;
FragColor = vec4(vec3(depth), 1.0);
}

由于线性化的深度值处于near与far之间,它的大部分值都会大于1.0并显示为完全的白色。通过在main函数中将线性深度值除以far,我们近似地将线性深度值转化到[0, 1]的范围之间。这样子我们就能逐渐看到一个片段越接近投影平截头体的远平面,它就会变得越亮,更适用于展示目的。

如果我们现在运行程序,我们就能看见深度值随着距离增大是线性的了。颜色大部分都是黑色,因为深度值的范围是0.1的近平面到100的远平面,它离我们还是非常远的。结果就是,我们相对靠近近平面,所以会得到更低的(更暗的)深度值。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页