moderngl环境下OpenGL深度测试结果不符合预期问题排查
深度测试结果不符合预期的原因
核心原因是你混淆了归一化设备坐标(NDC)的z值范围和深度缓冲区存储的窗口深度值范围,两者之间存在固定管线自动执行的线性映射,不是直接相等的关系。
写入gl_Position的坐标属于裁剪坐标,因为你设置w=1,透视除法后得到的NDC坐标z值和你写的position.y完全一致,范围是[-0.5, 0.5]。但NDC坐标的z分量取值范围约定为[-1, 1](对应近平面到远平面),在进入深度测试前,硬件会自动执行视口深度映射,把[-1,1]的NDC z值线性转换到[0,1]的窗口深度区间(默认glDepthRange设置为0到1),转换公式为:
窗口深度值 = (NDC_z + 1) / 2
这个转换和gl_Position的w分量是否为1没有关系,w只影响透视除法步骤,透视除法完成后无论w值是多少,都会执行这一步深度范围映射。
你的测试现象完全符合这个映射规则
把你代码里的顶点z值代入公式计算,就能对应上所有观测结果:
- 四边形底部顶点y=-0.5,NDC_z=-0.5,对应窗口深度值 = (-0.5 + 1)/2 = 0.25
- 四边形顶部顶点y=0.5,NDC_z=0.5,对应窗口深度值 = (0.5 + 1)/2 = 0.75
也就是说你的四边形渲染时,所有片元的实际深度值是从底部0.25线性过渡到顶部0.75:
- 清空深度为0.25、深度函数设为
>时:所有片元深度≥0.25,除了最底部边缘线外全部满足测试条件,因此显示几乎完整的四边形,不会出现你预期的遮挡底部四分之一的效果 - 清空深度为0.25、深度函数设为
<时:没有片元深度小于0.25,因此四边形完全不可见 - 清空深度改为0.5时:深度0.5刚好对应四边形y=0的水平中线,深度函数为
>时只有上半部分(深度0.50.75)通过测试,深度函数为`<`时只有下半部分(深度0.250.5)通过测试,和你观测到的半屏显示效果完全一致。
实现预期效果的调整方法
如果你想让自定义的z值直接对应[0,1]范围的深度值,只需要在顶点着色器里手动把目标深度值转换到NDC要求的[-1,1]范围即可。比如你最初想让深度值随y坐标从底部到顶部在0~1之间线性变化,只需要把gl_Position的z值做如下修改:
// 目标深度depth = y + 0.5(y=-0.5时depth=0,y=0.5时depth=1) // NDC_z = depth * 2 - 1 = 2*(y+0.5) -1 = 2*y gl_Position = vec4(position, 2 * position.y, 1.0);
修改后再测试:清空深度为0.25、深度函数为>时,深度小于0.25的区域(对应y < -0.25,也就是底部四分之一高度)会被遮挡,就和你最初的预期一致了。
内容的提问来源于stack exchange,提问作者user2649681
相关产品推荐
相关产品推荐

