引言

上一节我们完成了光照、材质、模型的导入,已经拥有了一个场景的雏形。这节我们来深入讨论一下测试、混合、高级数据和着色器相关的内容。

Part1. 深度测试

靠前的物体能够挡住靠后的物体,本质原因是靠前的物体深度值更小,而靠后的物体深度值更大,我们默认用深度值小的像素去替换掉深度值大的像素,这样就完成了遮挡关系的判断。当然,是否要取深度值小的、抛弃深度值大的,其实也可以交给用户自定义,通过glDepthFunc()方法可以修改逻辑:GL_ALWAYS永远通过测试、GL_LESS最常用的浅值通过测试、GL_GREATER深值通过测试;

同时,由于投影变换的缘故,导致在屏幕空间下,所有物体的像素深度与相机空间下的真实深度距离之间不再是线性关系,这是因为投影变换将z值做了一个压缩。所以如果我们想得到相机空间下的真实深度,只能通过屏幕空间下的深度值先做一个“逆NDC转换”,再做一个“逆投影变换”。

我们先看一下正投影变换的变换矩阵:

假设相机空间下的空间坐标是(x,y,z,w),投影变换后的空间坐标是(x',y',z',w'),NDC空间下的空间坐标是(x_NDC,y_NDC,z_NDC,w_NDC),而屏幕空间下的深度为depth,则有:

$$z' = z * \frac{far + near}{far-near} + w * \frac{2 * near * far}{near - far}$$

$$z_{NDC} = \frac{z'}{-z}$$

$$depth = \frac{z_{NDC} + 1}{2}$$

可以反推:

$$z_{NDC} = \frac{far + near}{near - far} - \frac{2 * near * far}{z * (near - far)}$$

$$\frac{2 * near * far}{z * (near - far)} = \frac{far + near}{near - far} - z_{NDC}$$

$$z = \frac{2 * near * far}{far + near - z_{NDC} * (far - near)}$$

这样z、z_NDC和depth之间的关系我们就捋清楚了,z就是真实线性深度,depth是屏幕空间的非线性深度,之间做个转换即可:

#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;
    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);
}

这样就能显示线性的深度信息了: