Learn OpenGL 笔记5.1 Depth testing

本文详细介绍了深度缓冲区的概念,包括其在渲染过程中的作用、早期深度测试的优化以及深度值的精度。深度测试通过GL_DEPTH_TEST启用,并使用GL_DEPTH_FUNC设置比较运算符,如GL_LESS,确保正确绘制层次。此外,文章还讨论了非线性深度方程、深度值的可视化以及Z-fighting现象。通过对深度缓冲区的理解,可以优化3D图形渲染的性能和效果。
摘要由CSDN通过智能技术生成

基础知识

1.depth-buffer

深度缓冲区是一个缓冲区,就像颜色缓冲区(存储所有片段颜色:视觉输出)一样,存储每个片段的信息,并且具有与颜色缓冲区相同的宽度和高度。深度缓冲区由窗口系统自动创建,并将其深度值存储为 16、24 或 32 位浮点数。在大多数系统中,您会看到精度为 24 位的深度缓冲区。

启用深度测试后,OpenGL 会根据深度缓冲区的内容测试片段的深度值。 OpenGL 执行深度测试,如果该测试通过(此深度未被其他深度覆盖),则渲染片段并使用新的深度值更新深度缓冲区(覆盖别人)。如果深度测试失败,直接不渲染这个片段了。

今天,大多数 GPU 都支持一种称为早期深度测试的硬件功能。 早期深度测试允许在片段着色器运行之前运行深度测试。 每当很明显一个片段将不可见(它在其他对象后面)时,我们可以早点地丢弃该片段

片段着色器通常非常昂贵,所以我们应该尽量避免运行它们。 用于早期深度测试的片段着色器的一个限制是您不应给片段设置深度值。 如果片段着色器将写入其深度值,则不可能进行早期深度测试; OpenGL 将无法事先计算出深度值。

开启深度测试:次片段测试通过才显示

glEnable(GL_DEPTH_TEST);  

如果您启用了深度测试,您还应该在每帧之前使用 GL_DEPTH_BUFFER_BIT 清除深度缓冲区; 否则你会被最后一帧的深度值困住:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  

某些时刻,你只想获取深度信息,不像更新写入他们,此时应该禁用深度信息的写入

glDepthMask(GL_FALSE);  

1.Depth test function (深度测试函数)

我们可以通过调用 glDepthFunc 来设置比较运算符(或深度函数):

glDepthFunc(GL_LESS);  
FunctionDescription
GL_ALWAYSThe depth test always passes.(这个fragment总是显示)
GL_NEVERThe depth test never passes.(这个fragment总是被跳过不显示)
GL_LESSPasses if the fragment's depth value is less than the stored depth value.(比当前存在的其他人的depth小,则覆盖他们,正常一般都用这个)
GL_EQUALPasses if the fragment's depth value is equal to the stored depth value.(和当前存在的其他人的depth相等,则覆盖他们)
GL_LEQUALPasses if the fragment's depth value is less than or equal to the stored depth value.(<=)
GL_GREATERPasses if the fragment's depth value is greater than the stored depth value.( >)
GL_NOTEQUALPasses if the fragment's depth value is not equal to the stored depth value.(!=)
GL_GEQUALPasses if the fragment's depth value is greater than or equal to the stored depth value (>=)

GL_ALWAYS 总是通过,则后来的fragment总是覆盖前面的

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS); 

 

用GL_LESS,depth小的放前面,就正常了

2.Depth value precision (深度值精度)

 深度缓冲区包含介于 0.0 和 1.0 之间的深度值。我们需要某种方法将这些视图空间 z 值转换到 [0,1] 的范围内, 以下(线性)方程将 z 值转换为介于 0.0 和 1.0 之间的深度值:

 

near and far values we used to provide to the projection matrix to set the visible frustum (视锥体的近值near和远值far).

The equation takes a depth value z within the frustum and transforms it to the range [0,1]. (在视锥体中取得的深度z)

实践中的方法:

然而在实践中,几乎不用这种线性深度缓冲区。 由于投影特性,使用了与 1/z 成比例的非线性深度方程。 当 z 很小时我们要得到极大的精度,而当 z 很远时我们得到的精度要求就低一些。

 

 

 3.Visualizing the depth buffer (可视化-深度缓冲区)

 让越近的越黑(#000000黑色),越远的越白(#ffffff白色),和前文的曲线拟合

fs代码:

#version 330 core
out vec4 FragColor;

float near = 0.1; 
float far = 100.0; 

//根据深度,来获取颜色值,把depth信息变换成0-1范围内的信息
float LinearizeDepth(float depth) 
{
    //将0-1的信息,投影平铺至-1到1的坐标系中
    float z = depth * 2.0 - 1.0; // back to NDC Normalize Device Space 标准化设备空间,范围只有0到1,中央为原点
    //曲线化
    return (2.0 * near * far) / (far + near - z * (far - near));	
}

void main()
{             
    //获取深度,以及颜色值信息
    float depth = LinearizeDepth(gl_FragCoord.z) / far; // divide by far to get depth in range [0,1] for visualization purposes
    FragColor = vec4(vec3(depth), 1.0);
}

 4.Z-fighting (Z值打架)

z靠得太近,而缓冲区精度不够的时候,就会出这种问题:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值