将预渲染的深度纹理绑定到 fbo 或片段着色器



在延迟着色框架中,我使用不同的framebufer对象来执行各种渲染通道。在第一遍中,我将整个场景的DEPTH_STENCIL_ATTACHMENT写成纹理,我们称之为DepthStencilTexture。要从不同的渲染通道(我使用不同的帧缓冲对象(访问存储在DepthStencilTexture中的深度信息,我知道两种方法:
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(。在其他情况下,我完全忽略模板,只需要存储在DepthStencilTexture中的深度,选项 1( 是否比更"自然"的选项 2( 有任何优势?

例如,我对此有一个(愚蠢的(怀疑.有时在我的片段着色器中,我会从深度计算世界位置。在案例 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是否也使用glDisable(GL_DEPTH_TEST)glDepthMask(GL_FALSE)从当前绑定的DEPTH_STENCIL_ATTACHMENT中读取?

严格按照OpenGL规范,不允许使用选项2如果你也在从这种纹理中阅读,那就不行了。

是的,我知道您正在使用写入掩码来防止深度写入。这不重要;OpenGL规范非常明确。根据 OpenGL 4.4 的 9.3.1,在以下情况下建立反馈循环:

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

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

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

您的代码就是这种情况。因此,从技术上讲,您具有未定义的行为。

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

话虽如此,如果您雇用NV_texture_barrier,则可以侥幸使用选项 2。尽管名称如此,但它在AMD硬件上非常广泛。这里要做的主要事情是在完成所有深度写入后发出屏障,以便保证所有后续读取都正常工作。屏障将完成您需要的所有缓存清除等。

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

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

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

最新更新