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

时间:2013-08-16 07:29:03

标签: opengl fbo deferred-shading

在延迟着色框架中,我使用不同的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绑定到framebuffer对象DEPTH_STENCIL_ATTACHMENT并设置glEnable(GL_DEPTH_TEST)glDepthMask(GL_FALSE)(编辑:在这种情况下,我不会绑定DepthStencilTexture 1}}到着色器,为了避免循环反馈,请看Nicol Bolas的答案,如果我需要片段着色器中的深度,我将使用gl_FragCorrd.z

在某些情况下,例如绘制光量,我需要模板测试并写入模板缓冲区,我将寻求解决方案2)。 在其他情况下,我完全忽略了模板,只需要存储在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;

我假设情况2中的gl_FragCoord.z与情况1)中的texture(DepthStencilTexture ,uv).r相同,或者换句话说,存储在DepthStencilTexture中的深度。这是真的吗? gl_FragCoord.z是否也会使用DEPTH_STENCIL_ATTACHMENTglDisable(GL_DEPTH_TEST)从当前绑定的glDepthMask(GL_FALSE)中读取?{/ 1}

1 个答案:

答案 0 :(得分:3)

严格遵守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是正在处理的片段的坐标。这是由 rasterizer 生成的片段,基于被栅格化的图元的数据。它与帧缓冲区的内容无关。