I want to access the depth buffer value at the currently processed pixel in a pixel shader.
我想在一个像素着色器中访问当前处理过的像素的深度缓冲值。
How can we achieve this goal? Basically, there seems to be two options:
我们如何实现这个目标?基本上,似乎有两种选择:
- Render depth to texture. How can we do this and what is the tradeoff?
- 渲染纹理深度。我们怎么做,什么是权衡?
- Use the value provided by gl_FragCoord.z - But: Is this the correct value?
- 使用gl_FragCoord提供的值。z -但是:这是正确的值吗?
2 个解决方案
#1
22
On question 1: You can't directly read from the depth buffer in the fragment shader (unless there are recent extensions I'm not familiar with). You need to render to a Frame Buffer Object (FBO). Typical steps:
关于问题1:您不能直接从片段着色器的深度缓冲区中读取(除非最近有我不熟悉的扩展)。您需要渲染到帧缓冲对象(FBO)。典型的步骤:
- Create and bind an FBO. Look up calls like
glGenFramebuffers
andglBindFramebuffer
if you have not used FBOs before. - 创建并绑定一个FBO。如果您以前没有使用过FBOs,可以查找glgenframebuffer和glBindFramebuffer之类的调用。
- Create a texture or renderbuffer to be used as your color buffer, and attach it to the
GL_COLOR_ATTACHMENT0
attachment point of your FBO withglFramebufferTexture2D
orglFramebufferRenderbuffer
. If you only care about the depth from this rendering pass, you can skip this and render without a color buffer. - 创建一个纹理或renderbuffer作为您的颜色缓冲区,并将它与glFramebufferTexture2D或glFramebufferRenderbuffer连接到FBO的GL_COLOR_ATTACHMENT0附件。如果您只关心这个呈现传递的深度,您可以跳过这个,并在没有颜色缓冲区的情况下呈现。
- Create a depth texture, and attach it to the
GL_DEPTH_ATTACHMENT
attachment point of the FBO. - 创建一个深度纹理,并将其附加到FBO的GL_DEPTH_ATTACHMENT连接点上。
- Do your rendering that creates the depth you want to use.
- 你的渲染创造了你想要使用的深度。
- Use
glBindFramebuffer
to switch back to the default framebuffer. - 使用glBindFramebuffer切换回默认的framebuffer。
- Bind your depth texture to a sampler used by your fragment shader.
- 将您的深度纹理绑定到您的片段着色器使用的采样器。
- Your fragment shader can now sample from the depth texture.
- 您的片段着色器现在可以从深度纹理中取样。
On question 2: gl_FragCoord.z
is the depth value of the fragment that your shader is operating on, not the current value of the depth buffer at the fragment position.
问题2:gl_FragCoord。z是着色器正在操作的片段的深度值,而不是片段位置上深度缓冲区的当前值。
#2
5
gl_FragCoord.z
is the window-space depth value of the current fragment. It has nothing to do with the value stored in the depth buffer. The value may later be written to the depth buffer, if the fragment is not discard
ed and it passes a stencil/depth test.
gl_FragCoord。z是当前片段的窗口空间深度值。它与存储在深度缓冲区中的值无关。如果这个片段没有被丢弃,并且通过了一个模板/深度测试,那么这个值可能会被写入到深度缓冲区中。
Technically there are some hardware optimizations that will write/test the depth early, but for all intents and purposes gl_FragCoord.z
is not the value stored in the depth buffer.
从技术上讲,有一些硬件优化可以早期编写/测试深度,但是对于所有意图和目的gl_FragCoord。z不是存储在深度缓冲区中的值。
Unless you render in multiple passes, you cannot read and write to the depth buffer in a fragment shader. That is to say, you cannot use a depth texture to read the depth and then turn around and write a new depth. This is akin to trying to implement blending in the fragment shader, unless you do something exotic with DX11 class hardware and image load/store, it just is not going to work.
除非在多个通道中呈现,否则无法在片段着色器中读取和写入到深度缓冲区。也就是说,你不能使用深度纹理来读取深度,然后转身并写一个新的深度。这类似于尝试在片段着色器中实现混合,除非您使用DX11类硬件和图像加载/存储来做一些奇异的事情,否则它不会起作用。
If you only need the depth of the final drawn scene for something like shadow mapping, then you can do a depth-only pre-pass to fill the depth buffer. In the second pass, you would read the depth buffer but not write to it.
如果您只需要像阴影映射那样的最终绘制场景的深度,那么您就可以进行深度预传递来填充深度缓冲区。在第二个通道中,您将读取深度缓冲区,但不会写入它。
#1
22
On question 1: You can't directly read from the depth buffer in the fragment shader (unless there are recent extensions I'm not familiar with). You need to render to a Frame Buffer Object (FBO). Typical steps:
关于问题1:您不能直接从片段着色器的深度缓冲区中读取(除非最近有我不熟悉的扩展)。您需要渲染到帧缓冲对象(FBO)。典型的步骤:
- Create and bind an FBO. Look up calls like
glGenFramebuffers
andglBindFramebuffer
if you have not used FBOs before. - 创建并绑定一个FBO。如果您以前没有使用过FBOs,可以查找glgenframebuffer和glBindFramebuffer之类的调用。
- Create a texture or renderbuffer to be used as your color buffer, and attach it to the
GL_COLOR_ATTACHMENT0
attachment point of your FBO withglFramebufferTexture2D
orglFramebufferRenderbuffer
. If you only care about the depth from this rendering pass, you can skip this and render without a color buffer. - 创建一个纹理或renderbuffer作为您的颜色缓冲区,并将它与glFramebufferTexture2D或glFramebufferRenderbuffer连接到FBO的GL_COLOR_ATTACHMENT0附件。如果您只关心这个呈现传递的深度,您可以跳过这个,并在没有颜色缓冲区的情况下呈现。
- Create a depth texture, and attach it to the
GL_DEPTH_ATTACHMENT
attachment point of the FBO. - 创建一个深度纹理,并将其附加到FBO的GL_DEPTH_ATTACHMENT连接点上。
- Do your rendering that creates the depth you want to use.
- 你的渲染创造了你想要使用的深度。
- Use
glBindFramebuffer
to switch back to the default framebuffer. - 使用glBindFramebuffer切换回默认的framebuffer。
- Bind your depth texture to a sampler used by your fragment shader.
- 将您的深度纹理绑定到您的片段着色器使用的采样器。
- Your fragment shader can now sample from the depth texture.
- 您的片段着色器现在可以从深度纹理中取样。
On question 2: gl_FragCoord.z
is the depth value of the fragment that your shader is operating on, not the current value of the depth buffer at the fragment position.
问题2:gl_FragCoord。z是着色器正在操作的片段的深度值,而不是片段位置上深度缓冲区的当前值。
#2
5
gl_FragCoord.z
is the window-space depth value of the current fragment. It has nothing to do with the value stored in the depth buffer. The value may later be written to the depth buffer, if the fragment is not discard
ed and it passes a stencil/depth test.
gl_FragCoord。z是当前片段的窗口空间深度值。它与存储在深度缓冲区中的值无关。如果这个片段没有被丢弃,并且通过了一个模板/深度测试,那么这个值可能会被写入到深度缓冲区中。
Technically there are some hardware optimizations that will write/test the depth early, but for all intents and purposes gl_FragCoord.z
is not the value stored in the depth buffer.
从技术上讲,有一些硬件优化可以早期编写/测试深度,但是对于所有意图和目的gl_FragCoord。z不是存储在深度缓冲区中的值。
Unless you render in multiple passes, you cannot read and write to the depth buffer in a fragment shader. That is to say, you cannot use a depth texture to read the depth and then turn around and write a new depth. This is akin to trying to implement blending in the fragment shader, unless you do something exotic with DX11 class hardware and image load/store, it just is not going to work.
除非在多个通道中呈现,否则无法在片段着色器中读取和写入到深度缓冲区。也就是说,你不能使用深度纹理来读取深度,然后转身并写一个新的深度。这类似于尝试在片段着色器中实现混合,除非您使用DX11类硬件和图像加载/存储来做一些奇异的事情,否则它不会起作用。
If you only need the depth of the final drawn scene for something like shadow mapping, then you can do a depth-only pre-pass to fill the depth buffer. In the second pass, you would read the depth buffer but not write to it.
如果您只需要像阴影映射那样的最终绘制场景的深度,那么您就可以进行深度预传递来填充深度缓冲区。在第二个通道中,您将读取深度缓冲区,但不会写入它。