14
\$\begingroup\$

I've got a renderbuffer (DepthStencil) in an FBO and I need to get a texture from it. I can't have both a DepthComponent texture and a DepthStencil renderbuffer in the FBO, it seems, so I need some way to convert the renderbuffer to a DepthComponent texture after I'm done with it for use later down the pipeline.

I've tried plenty of techniques to grab the depth component from the renderbuffer for weeks but I always come out with junk. All I want at the end is the same texture I'd get from an FBO if I wasn't using a renderbuffer. Can anyone post some comprehensive instructions or code that covers this seemingly simple operation?

EDIT:

Linky to an extract version of the code http://dl.dropbox.com/u/9279501/fbo.cs

Screeny of the Depth of Field effect + FBO - without depth(!) https://i.sstatic.net/Hj9Oe.jpg

Screeny without Depth of Field effect + FBO - depth working fine https://i.sstatic.net/boOm1.jpg

\$\endgroup\$

4 Answers 4

2
\$\begingroup\$

Alternately, you can just blit from one FBO to another, such as from a renderbuffer-based one to a texture-based one. I do it this way:

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);

(In your case, where you want to depth buffer, you can use GL_DEPTH_BUFFER_BIT instead of GL_COLOR_BUFFER_BIT)

After blitting into the texture-based renderbuffer, you can then use the texture as normal; passing it into shaders as a uniform or whatever you like.

\$\endgroup\$
1
\$\begingroup\$

No, that's not possible. At most you can glReadPixels the data to the CPU, and create a texture of it, but that will be cumbersome and slow. Renderbuffers aren't meant for it, that functionality is only provided by textures.

\$\endgroup\$
10
  • \$\begingroup\$ Given that, what's the alternative? How can you maintain depth in your draw buffer and also acquire the depth component as a texture? \$\endgroup\$
    – Rushyo
    Commented Aug 23, 2010 at 6:24
  • \$\begingroup\$ @Rushyo : An alternative could be to get rid of the stencil buffer (if possible!) and make the depth renderbuffer a depth texture. Why are you using a stencil ? \$\endgroup\$
    – Calvin1602
    Commented Aug 23, 2010 at 8:34
  • \$\begingroup\$ Essentially whenever I acquire the depth texture, my depth tests break. If I attach a depth attachment to my FBO, the FBO doesn't write any depth information elsewhere - so when I try to retrieve the color attachment there's no depth testing on it (which their normally is if I don't have a depth attachment). I've tried every combination I can think of, including the aforementioned 'cumbersome and slow' method. Whatever I do I can't get both a 'typical' render of my scene in one texture and just the depth in another. \$\endgroup\$
    – Rushyo
    Commented Aug 23, 2010 at 8:49
  • \$\begingroup\$ @Calvin1602 When I was dabbling with the renderbuffer, I found that using the depth attachment without the stencil attachment produced unwanted results. \$\endgroup\$
    – Rushyo
    Commented Aug 23, 2010 at 9:13
  • \$\begingroup\$ @Rushyo I bet you're not setting up the texture correctly, posting code will allow us to help :) \$\endgroup\$
    – Dr. Snoopy
    Commented Aug 23, 2010 at 11:41
1
\$\begingroup\$

What you are asking is possible in OpenGL 3.2. I've got my FBO spitting out diffuse colour to a colour texture, normals to another colour texture, and depth to a depth texture -- no renderbuffers needed. In fact renderbuffers are just a problem, because you cannot sample from them, so you'd have to use glReadPixels(...) or otherwise somehow copy the data out of the RBO and into a texture on the CPU, instead of just maintaining everything in GPU memory. So...

If you really want to, you can write code in your first-pass shader to manually output stuff like depth, to a separate colour texture attachment in your FBO. That would be for use by you in your post-pass shaders. For OpenGL's use in its internal depth-testing, you would additionally need either an RBO or texture set as your FBO's GL_DEPTH_ATTACHMENT. But you can set up a single texture to serve both -- this is more efficient & easier to use.

My depth texture setup code looks like this (Java, just ignore the ByteBuffer stuff... and note I use "id" to refer to integer handles/pointers, since that concept doesn't really sit well in 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);

And later:

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

You can now pass gBufferDepthTexture (or what have you) as a uniform to your second, third pass fragment shaders. I think we can safely assume that you can do exactly the same thing with the stencil buffer.

\$\endgroup\$
0
\$\begingroup\$

You should be able to create a texture (instead of a RenderBuffer) using the GL_DEPTH_STENCIL format. I'm not sure of the exact process for using depth from such a texture in a shader program (which I assume you're using, since you're using FBOs), but the OpenGL spec should specify which color channels get which values (my guess would be that R,G, and B all get set to depth and A gets set to stencil).

I target OpenGL 3.2 these days, so you may need to verify that texture format is workable for you. I can never remember which versions introduce different features.

\$\endgroup\$
3
  • \$\begingroup\$ The trouble then isn't capturing the GL_DEPTH_STENCIL component in a texture, but the fact that all depth information is lost in the FBO whenever you do so. The FBO becomes useless for then rendering the scene to the draw buffer. Hence I was using a Renderbuffer in the hopes of bypassing this issue. I think for now I have no option but to make two passes to grab the depth + draw information separately =( expensive-as-hell until I can find a way around it. \$\endgroup\$
    – Rushyo
    Commented Sep 2, 2010 at 13:14
  • \$\begingroup\$ @Rushyo I posted an answer to this ancient question :) You might want to take a look, though you probably solved this years ago. \$\endgroup\$
    – Engineer
    Commented Oct 9, 2012 at 22:59
  • \$\begingroup\$ @NickWiggill I wish! Fudged something and moved on with my life. Can't actually test your answer until I recreate the assets that I used in this prototype. Might get around to that at some point... \$\endgroup\$
    – Rushyo
    Commented Apr 12, 2013 at 14:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .