未限制范围的 OpenGL 深度测试

问题描述 投票:0回答:1

我正在使用带有顶点和片段着色器的 OpenGL 管道,因此需要启用早期片段测试。

因此,深度测试始终使用顶点着色器输出

gl_Position.z
完成,其(在透视划分之后)需要介于 -1 和 +1 之间。因此,顶点着色器需要将顶点的 Z 值从其全部可能范围标准化为
[-1, +1]
。但在这种情况下,事先并不知道顶点的全部范围。

有没有办法让 OpenGL 接受任何深度测试值,而不需要固定到

[-1, +1]
?深度纹理/渲染缓冲区具有
GL_FLOAT
 格式,因此它应该能够处理任何浮点值。

我已经尝试过

glEnable(GL_DEPTH_CLAMP)
,但这只允许将超出此范围的值转发到片段着色器(转换为窗口空间),但仍然不对此类值进行深度测试。

似乎有一个带有新深度缓冲区格式的扩展“GL_NV_depth_buffer_float”

DEPTH_COMPONENT32F_NV
可以禁用此钳位,但我还没有让它工作,而且它仅适用于 NVidia。

我还尝试用片段着色器中的自定义实现替换深度测试,该实现在图像上执行

imageAtomicMax()
(将
float
深度值转换为
uint
值,以便它们具有相同的顺序),但是避免竞争条件似乎是不可能的。片段着色器需要将输出写入多个帧缓冲区颜色附件,具体取决于深度测试结果。

另一种方法似乎是在顶点着色器中使用诸如

atan()
之类的函数(将
[-inf, +inf]
映射到
[-1, +1]
,但这可能会减慢速度,并且实际的Z值最终可能会彼此非常接近)浮点精度已经无法区分它们了。

opengl glsl fragment-shader vertex-shader depth-testing
1个回答
0
投票

你想要的可以通过“Reverse-Z”技术来完成。

由于相机平面的奇点,近平面裁剪是必要的。需要裁剪几何体,以便我们看不到相机后面的内容。

远平面裁剪实际上可以通过将其设置为无穷大来回避。通常,由于精度损失,定点深度缓冲区无法完成此操作。然而,使用浮点深度缓冲区,可以按如下方式实现。

使用以下命令将剪切平面设置为 0 和 1(而不是 -1 和 1):

glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);

反转深度测试:

glDepthFunc(GL_GREATER); // default is GL_LESS
glClearDepth(0); // default is 1

并调整投影矩阵,使无穷远处的远平面投影为 0,近平面投影为 1:

A  0  0  0
0  B  0  0
0  0  0  n
0  0  -1 0

这里

A
B
决定了你的视野,
n
是近平面的位置。该技术为您在整个半无限范围内提供统一的相对精度。您可以将近平面任意设置为接近,但会牺牲尾数的远端。

来源:

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.