1

在延迟着色框架中,我使用不同的帧缓冲区对象来执行各种渲染过程。在第一遍中,我将DEPTH_STENCIL_ATTACHMENT整个场景的纹理写入纹理,我们称之为DepthStencilTextureDepthStencilTexture要访问存储在不同渲染通道中的深度信息(为此我使用不同的帧缓冲区对象),我知道两种方法:
1)我将 绑定DepthStencilTexture到着色器并在片段着色器中访问它,在片段着色器中手动执行深度,例如这个

uniform vec2 WinSize; //windows dimensions
vec2 uv=gl_FragCoord.st/WinSize;
float depth=texture(DepthStencilTexture ,uv).r;
if(gl_FragCoord.z>depth) discard;

我也设置glDisable(GL_DEPTH_TEST)glDepthMask(GL_FALSE)

2)我将 绑定DepthStencilTexture到帧缓冲区对象DEPTH_STENCIL_ATTACHMENT并设置glEnable(GL_DEPTH_TEST)glDepthMask(GL_FALSE)(编辑:在这种情况下,我不会将 绑定DepthStencilTexture到着色器,以避免循环反馈,请参阅 Nicol Bolas 的答案,如果我需要深度我将使用片段着色器gl_FragCorrd.z

在某些情况下,例如绘制光量,我需要模板测试并写入模板缓冲区,我将采用解决方案 2)。在其他情况下,我完全忽略 Stencil,只需要存储在 中的深度DepthStencilTexture,选项 1) 是否比更“自然”的选项 2) 有任何优势?

例如,我对此有一个(我认为是愚蠢的)怀疑。有时在我的片段着色器中,我从深度计算 WorldPosition。在这种情况下 1) 它会是这样的

uniform mat4 invPV; //inverse PV matrix 
vec2 uv=gl_FragCoord.st/WinSize;
vec4 WorldPosition=invPV*vec4(uv, texture(DepthStencilTexture ,uv).r ,1.0f );
WorldPosition=WorldPosition/WorldPosition.w;

在情况 2)它会是这样的(编辑:这是错误的,gl_FragCoord.z 是当前片段的深度,而不是存储在纹理中的实际深度)

uniform mat4 invPV; //inverse PV matrix 
vec2 uv=gl_FragCoord.st/WinSize;
vec4 WorldPosition=invPV*vec4(uv, gl_FragCoord.z, 1.0f );
WorldPosition=WorldPosition/WorldPosition.w;

我假设gl_FragCoord.z情况 2) 将与texture(DepthStencilTexture ,uv).r情况 1) 相同,或者换句话说,存储在DepthStencilTexture. 这是真的吗?是 gl_FragCoord.z从当前绑定的DEPTH_STENCIL_ATTACHMENT还用glDisable(GL_DEPTH_TEST)and读取glDepthMask(GL_FALSE)吗?

4

1 回答 1

3

严格遵循 OpenGL 规范,不允许使用选项 2。如果您也从该纹理中读取,则不会。

是的,我意识到您正在使用写入掩码来防止深度写入。没关系; OpenGL规范很清楚。根据 OpenGL 4.4 的 9.3.1,在以下情况下建立反馈循环:

  • 来自纹理对象 T 的图像在附着点 A 处附加到当前绑定的绘制帧缓冲区对象

  • 纹理对象 T 当前绑定到纹理单元 U,并且

  • 当前可编程顶点和/或片段处理状态使得可以(见下文)从绑定到纹理单元 U 的纹理对象 T 中进行采样

您的代码就是这种情况。所以你在技术上有未定义的行为。

这是未定义的一个原因是,只需更改写入掩码就不必执行清除帧缓冲区和/或纹理缓存之类的操作。

话虽如此,如果您使用NV_texture_barrier,您可以摆脱选项 2 。尽管有这个名字,但它在 AMD 硬件上非常普遍。这里要做的主要事情是在完成所有深度写入后发出屏障,以保证所有后续读取都能正常工作。屏障将完成所有缓存清除以及您需要的操作。

否则,选项 1 是唯一的选择:手动进行深度测试。

我假设情况 2 中的 gl_FragCoord.z 与情况 1 中的纹理(DepthStencilTexture ,uv).r 相同),或者换句话说,存储在 DepthStencilTexture 中的深度。这是真的吗?

两者都不是真的。gl_FragCoord是正在处理的片段的坐标。这是光栅化器生成的片段基于被光栅化的图元的数据。它与帧缓冲区的内容无关。

于 2013-08-16T07:48:32.120 回答