从OpenGL中的渲染缓冲区获取纹理?


13

我在FBO中有一个渲染缓冲区(DepthStencil),我需要从中获取纹理。看来,在FBO中我无法同时拥有DepthComponent纹理和DepthStencil渲染缓冲区,因此我需要某种方法将渲染缓冲区转换为DepthComponent纹理,以便以后在管道中使用。

我尝试了很多技术,从渲染缓冲区中获取深度分量已有数周之久,但我总是会遇到垃圾。如果不使用渲染缓冲区,最后我想要的就是与FBO相同的纹理。谁能发布一些涵盖该看似简单操作的综合说明或代码?

编辑:

链接到代码http://dl.dropbox.com/u/9279501/fbo.cs的摘录版本

景深效果的筛选+ FBO-无深度(!) http://i.stack.imgur.com/Hj9Oe.jpg

没有场深效果+ FBO的画面-深度效果不错 http://i.stack.imgur.com/boOm1.jpg

Answers:


2

或者,您可以从一个FBO到另一个FBO,例如从基于渲染缓冲区的FBO到基于纹理的FBO。我这样做:

glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_renderBufferSurface->m_fbo);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_textureSurface->m_fbo);
glBlitFramebufferEXT(0, 0, m_renderBufferSurface->m_width, m_renderBufferSurface->m_height, 0, 0, m_textureSurface->m_width, m_textureSurface->m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

(在您的情况下,要深度缓冲,可以使用GL_DEPTH_BUFFER_BIT而不是GL_COLOR_BUFFER_BIT)

转入基于纹理的渲染缓冲区后,您可以照常使用纹理。将其作为制服或任何喜欢的东西传递到着色器中。


1

不,那不可能。最多可以将数据glReadPixels送到CPU,并为其创建纹理,但这将非常麻烦且缓慢。Renderbuffers并不适合它,该功能仅由纹理提供。


鉴于此,还有什么选择?如何在绘制缓冲区中保持深度并获取深度分量作为纹理?
Rushyo

@Rushyo:一种替代方法是摆脱模板缓冲区(如果可能!),并使depth renderbuffer成为深度纹理。为什么要使用模具?
Calvin1602

基本上,每当我获得深度纹理时,我的深度测试都会中断。如果我在FBO上附加了深度附件,则FBO不会在其他位置写入任何深度信息-因此,当我尝试检索颜色附件时,就不会对其进行深度测试(通常是在没有深度附件的情况下进行深度测试) )。我已经尝试过我能想到的每种组合,包括上述的“繁琐而缓慢”的方法。无论我做什么,我都无法在一种纹理中同时获得场景的“典型”渲染,而在另一种纹理中既无法获得深度。
Rushyo

@ Calvin1602当我涉嫌渲染缓冲区时,我发现使用没有模板附件的深度附件会产生不需要的结果。
Rushyo

@Rushyo我敢打赌,您没有正确设置纹理,发布代码可以帮助我们:)
Matias Valdenegro 2010年

1

您要问的是在OpenGL 3.2中是可能的。我的FBO将漫反射颜色分散为一种颜色纹理,法线为另一种颜色纹理,以及深度为深度纹理-不需要渲染缓冲区。实际上,渲染缓冲区只是一个问题,因为您无法从中进行采样,因此必须使用glReadPixels(...)或以其他方式将数据从RBO中复制出来并复制到CPU的纹理中,而不是仅将所有内容保留在GPU内存中。所以...

如果确实需要,可以在首遍着色器中编写代码,以将诸如深度之类的内容手动输出到FBO中的单独颜色纹理附件。那将供在通过后着色器中使用。对于OpenGL 在其内部深度测试中使用,您还需要一个RBO或纹理集作为FBO的GL_DEPTH_ATTACHMENT。但是您可以设置单个纹理来同时使用两种纹理-这更高效且更易于使用。

我的深度纹理设置代码如下(Java,请忽略ByteBuffer之类的东西,并请注意,我使用“ id”指代整数句柄/指针,因为该概念在Java中并不适合):

        gBufferDepthTexture = new Texture();
        gBufferDepthTexture.id = glGenTextures();
        gBufferDepthTexture.unit = 2;
        gBufferDepthTexture.width = Display.getWidth();
        gBufferDepthTexture.height = Display.getHeight();
        gBufferDepthTexture.bytes = ByteBuffer.allocateDirect(Display.getWidth()*Display.getHeight() * 4);
        glActiveTexture(gBufferDepthTexture.unit + GL_TEXTURE0); //eg. 0 + 33984 = GL_TEXTURE0, while 31 + 33984 = GL_TEXTURE31.
        glBindTexture(GL_TEXTURE_2D, gBufferDepthTexture.id);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, gBufferDepthTexture.width, gBufferDepthTexture.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, gBufferDepthTexture.bytes);
        //...GL_UNSIGNED_INT or GL_UNSIGNED_BYTE may work better for you, instead... YMMV.

        //glPixelStorei(GL_PACK_ALIGNMENT, 4);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

然后:

        glBindFrameBuffer(GL_DRAW_FRAMEBUFFER, fbo.id);
        //your existing glFramebufferTexture2D(...) calls here
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gBufferDepthTexture.id, 0);

现在,您可以将gBufferDepthTexture制服作为制服传递(或拥有)到第二,第三遍片段着色器。我认为我们可以放心地假设您可以使用模板缓冲区执行完全相同的操作。


0

您应该能够使用GL_DEPTH_STENCIL格式创建纹理(而不是RenderBuffer)。我不确定在着色器程序中使用这种纹理的深度的确切过程(我假设您正在使用,因为您正在使用FBO),但是OpenGL规范应该指定哪些颜色通道获得哪些值(我的猜测是R,G和B都设置为深度,而A设置为模具)。

这些天我的目标是OpenGL 3.2,因此您可能需要验证纹理格式对您而言是否可行。我永远不记得哪个版本引入了不同的功能。


然后,问题就不在捕捉纹理中的GL_DEPTH_STENCIL组件,而是事实是,无论何时,所有深度信息都会在FBO中丢失。FBO对于随后将场景渲染到绘制缓冲区变得毫无用处。因此,我正在使用Renderbuffer来绕过此问题。我想,现在我别无选择,只能做两道抢深度+独立获取信息=(昂贵,如地狱,直到我能找到办法解决它。
Rushyo

@Rushyo我针对这个古老的问题发布了答案:)尽管您可能在几年前就解决了,但您可能想看看。
工程师

我希望@NickWiggill!捏一些东西,继续我的生活。在我重新创建此原型中使用的资产之前,无法实际测试您的答案。可能会在某个时候解决这个问题
Rushyo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.