对数深度缓冲区OpenGL

时间:2014-03-12 22:06:18

标签: c++ opengl 3d depth-buffer

我已经设法在OpenGL中实现了一个对数深度缓冲区,主要是来自Outerra的文章(你可以阅读它们hereherehere) 。但是,我遇到了一些问题,我不确定这些问题是否是使用对数深度缓冲区所固有的,或者是否有一些我无法想到的解决方法。

刚开始,这就是我在顶点着色器中计算对数深度的方法:

gl_Position = MVP * vec4(inPosition, 1.0);
gl_Position.z = log2(max(ZNEAR, 1.0 + gl_Position.w)) * FCOEF - 1.0;
flogz = 1.0 + gl_Position.w;

这就是我在片段着色器中修复深度值的方法:

gl_FragDepth = log2(flogz) * HALF_FCOEF;

ZNEAR = 0.0001ZFAR = 1000000.0FCOEF = 2.0 / log2(ZFAR + 1.0)HALF_FCOEF = 0.5 * FCOEF。在我的例子中,C是1.0,以简化我的代码并减少计算。

对于初学者来说,我对我获得的精确程度非常满意。使用正常的深度缓冲(znear = 0.1,zfar = 1000.0),我会朝视距的边缘进行相当多的z-fighting。现在,随着我的进一步znear:zfar,我把第二个地平面放在第一个以下0.01个单位,我找不到任何z-fighting,无论我把相机放大多远(我得到一点z-战斗时只有0.0001(0.1毫米),但是meh)。

但是,我确实有一些问题/担忧。

1)我得到的平面剪裁比我的普通深度缓冲更多,看起来很难看。它发生在逻辑上它确实不应该的情况下。以下是我的意思截图:

剪掉地面。

Clipping the ground.

剪切网格。

Clipping a mesh.

这两种情况都是我没有使用普通深度缓冲区的情况,我宁愿看不到(特别是前者)。编辑:问题1是使用glEnable(GL_DEPTH_CLAMP)正式解决的。

2)为了使其工作,我需要写入gl_FragDepth。我试过不这样做,但结果是不可接受的。写入gl_FragDepth意味着我的显卡无法进行早期z优化。这将不可避免地让我陷入困境,所以我想尽快解决它。

3)我需要能够检索存储在深度缓冲区中的值(我已经有了帧缓冲和纹理),然后将其转换为线性视图空间坐标。我真的不知道从哪里开始这个,我之前做过它的方式涉及逆投影矩阵,但我不能在这里真正做到这一点。有什么建议吗?

3 个答案:

答案 0 :(得分:2)

近平面削波独立于深度测试,但通过剪切 cli空间体积。在现代OpenGL中,可以使用深度夹紧来使事情再次变得美观。见http://opengl.datenwolf.net/gltut/html/Positioning/Tut05%20Depth%20Clamping.html#d0e5707

答案 1 :(得分:1)

1)在您使用的等式中:   gl_Position.z = log2(max(ZNEAR,1.0 + gl_Position.w))* FCOEF - 1.0; 不应该有ZNEAR,因为那与它无关。这个常量只是为了避免log2参数为零,例如你可以在那里使用1e-6。

但是否则深度钳位将解决问题。

2)您可以避免仅在自适应细分中使用gl_FragDepth,这会将插值误差保持在边界内。例如,在Outerra中,地形被自适应地测量,因此在地形上不会出现明显的错误。但是当关闭时,对象需要片段深度写入,因为长屏幕空间三角形将具有线性插值和正确对数值之间的差异。

请注意,最新的AMD驱动程序现在支持NV_depth_buffer_float扩展名,因此现在可以使用Reversed floating-point depth buffer设置。据我所知,英特尔GPU尚不支持它。

3)此处描述了向视图空间深度的转换:https://stackoverflow.com/a/18187212/2435594

答案 2 :(得分:1)

回答可能有点迟了。 无论如何,重构Z使用log2版本:

realDepth = pow(2,(LogDepthValue + 1.0)/Fcoef) - 1.0;