9

I want to get the current depth buffer to a texture, to access it in a shader. For various reasons I can't do a separate depth pass, but would need to copy the already-rendered depth.

glReadPixels would involve the CPU and potentially kill performance, and as far as I know glBlitFramebuffer can't blit depth-to-color, only depth-to-depth.

How to do this on the GPU?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Anon
  • 91
  • 1
  • 1
  • 2

3 Answers3

7

The modern way of doing this would be to use a FBO. Attach a color and depth texture to it, render, then disable the FBO and use the textures as inputs to a shader that will render to the default framebuffer.

All the details you need about FBO can be found here.

Nicolas Lefebvre
  • 4,247
  • 1
  • 25
  • 29
  • I've written a C++ class that sets up a depth-only FBO: https://github.com/mfichman/simple-fast-renderer/blob/master/src/DepthRenderTarget.cpp. If you enable the depth-only FBO, then you can render as normal -- but you'll have the depth info available in a texture when you're done. I use this to do shadow-mapping, but it should work for you too. – Matt Fichman Apr 10 '14 at 19:05
5

Copying the depth buffer to a texture is pretty simple. If you have created a new texture that you haven't called glTexImage* on, you can use glCopyTexImage2D. This will copy pixels from the framebuffer to the texture. To copy depth pixels, you use a GL_DEPTH_COMPONENT format. I'd suggest GL_DEPTH_COMPONENT24.

If you have previously created a texture with a depth component format (ie: anytime after the first frame), then you can copy directly into this image data with glCopyTexSubImage2D.

It also seems as though you're having trouble accessing depth component textures in your shader, since you want to copy depth-to-color (which is not allowed). If you are, then that is a problem you should get fixed.

In any case, copying should be the method of last resort. You should use framebuffer objects whenever possible. Just render directly to your texture.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • When you say "use framebuffer objects", do you mean perform a copy from one to the other using `glBlitFramebuffer()`? – livin_amuk Oct 17 '22 at 11:57
  • @livin_amuk: No, I meant "just render directly to your texture". If your intent is to have your texture store your depth information, you shouldn't have rendered to the default framebuffer to begin with. – Nicol Bolas Oct 17 '22 at 13:33
  • @livin_amuk: Then it's not "possible" for you; you cannot "render directly to your texture" because you didn't get depth information from rendering. So it doesn't apply to your use case. – Nicol Bolas Oct 17 '22 at 21:47
  • In my particular case the depth information is already there. I'm wriitng a Maya plugin. Is a `glBlitFramebuffer()` copy the approach you would suggest? – livin_amuk Oct 17 '22 at 21:51
  • @livin_amuk: If the depth information is already in a texture, then this question doesn't apply to you. This question is about copying from the default framebuffer's depth buffer to a texture. My response is to just render to that texture to begin with. If the depth information is in some kind of CPU memory, then you need to do a pixel transfer to the texture. If you're trying to read Maya's framebuffer, then you're going to have to look at how Maya exposes that to you and do what you can from there. Blitting might be viable, but it might not. – Nicol Bolas Oct 17 '22 at 22:21
  • In my case the depth information is already in the default frame buffer. I need to make a temporary copy (into an FBO makes most sense to me but I'm open to suggestions) and then perform some work which will mutate the original depth buffer, and to then restore the original by copying the copy back in. Maya doesn't expose any of this low level stuff but I have found a way to access handles to the things I need. Assuming I have their fbo handle, do you think blitting is the best approach? – livin_amuk Oct 19 '22 at 02:28
4

Best way would be using FBOs, for better performance and some coding style issues whatsoever. If you are not interested take a look at this code. It is from the days when I was much younger!(and didn't know FBOs exist)

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);
Amir Zadeh
  • 3,481
  • 2
  • 26
  • 47