如何在GPU上将深度缓冲区复制到纹理?

10
我想把当前深度缓冲区渲染到纹理中,以便在着色器中访问。由于各种原因,我不能进行单独的深度通道,但需要复制已经渲染好的深度。
使用glReadPixels会涉及到CPU并可能降低性能,据我所知glBlitFramebuffer无法将深度复制到颜色,只能将深度复制到深度。
如何在GPU上完成这个任务?

我也遇到了同样的问题,你解决了吗? - Viktor Sehr
3个回答

7
现代的方法是使用FBO。将颜色和深度纹理附加到其中,进行渲染,然后禁用FBO并使用纹理作为着色器的输入,该着色器将渲染到默认帧缓冲区。
有关FBO的所有详细信息可以在此处找到。

我编写了一个C++类,用于设置深度优先FBO:https://github.com/mfichman/simple-fast-renderer/blob/master/src/DepthRenderTarget.cpp。如果启用深度优先FBO,则可以像平常一样进行渲染--但是在完成后,您将可以在纹理中使用深度信息。我使用它来执行阴影映射,但您也可以使用它。 - Matt Fichman

5
复制深度缓冲区到纹理很简单。如果您创建了一个未调用glTexImage*的新纹理,则可以使用glCopyTexImage2D。这将从帧缓冲区复制像素到纹理。要复制深度像素,您需要使用GL_DEPTH_COMPONENT格式。我建议使用GL_DEPTH_COMPONENT24。
如果您以前使用深度组件格式(即:第一帧后的任何时间)创建了纹理,则可以直接将其复制到此图像数据中,使用glCopyTexSubImage2D。
另外,似乎您在着色器中无法访问深度组件纹理,因为您想复制深度到颜色(这是不允许的)。如果是这样,那么您应该解决这个问题。
无论如何,复制应该是最后的手段。尽可能使用帧缓冲对象。直接渲染到您的纹理。

当你说“使用帧缓冲对象”时,是指使用glBlitFramebuffer()执行从一个到另一个的复制吗? - livin_amuk
@livin_amuk:不,我的意思是“直接渲染到你的纹理上”。如果你的目的是让你的纹理存储深度信息,那么一开始就不应该渲染到默认帧缓冲区。 - Nicol Bolas
@livin_amuk:那么对于你来说这是不可能的;因为你没有从渲染中获取深度信息,所以你无法“直接渲染到纹理”。因此它不适用于你的使用情况。 - Nicol Bolas
在我的特定情况下,深度信息已经存在。我正在编写一个Maya插件。您建议使用glBlitFramebuffer()复制方法吗? - livin_amuk
如果深度信息已经在纹理中,那么这个问题就不适用于您。这个问题是关于从默认帧缓冲区的深度缓冲区复制到纹理的。我的回答是直接渲染到该纹理。如果深度信息在某种CPU内存中,则需要进行像素传输到纹理中。如果您正在尝试读取Maya的帧缓冲区,则需要查看Maya如何向您公开并尽力而为。Blitting可能可行,但也可能不行。 - Nicol Bolas
在我的情况下,深度信息已经在默认帧缓冲区中。我需要制作一个临时副本(对我来说,将其放入FBO中最有意义,但我也愿意听取建议),然后执行一些操作,这些操作将改变原始深度缓冲区,并通过将副本复制回来来恢复原始深度缓冲区。Maya没有公开任何这些低级别的东西,但我已经找到了一种访问我所需内容的句柄的方法。假设我有它们的fbo句柄,你认为blitting是最好的方法吗? - livin_amuk

5

最好的方法是使用FBO(Frame Buffer Object),这样可以获得更好的性能和一些编码风格问题。如果您不感兴趣,请查看此代码。这是我年轻时的代码!(当时并不知道FBO的存在)

int shadowMapWidth = 512;
int shadowMapHeight = 512;
glGenTextures(1, &m_depthTexture);

glBindTexture(GL_TEXTURE_2D, m_depthTexture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 512,512);

1
如果您使用GL_DEPTH_COMPONENT24,效果会更好! - Amir Zadeh
为什么呢?你能解释一下吗? - Engineer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接