Sign in to follow this  

OpenGL Copying the depth buffer to a texture for use in post-processing

This topic is 2598 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

When I caught myself about to hurl my laptop across the room in frustration, I knew it was time to ask someone. It seems pathetic, given that this is such a fundamental thing that should just work, but I've been googling for two days now, including reading most of this forum for the past ten years, and I cannot get this to work.

I'm just trying to copy the depth buffer to a texture that I can pass to a shader. At the moment I have no shaders active, I just render the scene, copy the depth buffer to a texture, then render that texture in 2D. So far, the texture resolutely stays white, unless I don't copy anything to it, in which case it stays grey.

So, here's the relevant highlights of the code (it doesn't do much more than this, it's just a test app). First, the various depth flags:

  glEnable(GL_DEPTH_TEST);
glDepthMask(true);
glDepthFunc(GL_LEQUAL);
glClearDepth(1.0f);
glEnable(GL_DEPTH);


Then the depth texture creation:

  unsigned int uiDepthTextureID;
glGenTextures(1, &uiDepthTextureID);
glBindTexture(GL_TEXTURE_2D, uiDepthTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);


(I have tried various values other than GL_DEPTH_COMPONENT, including GL_DEPTH_COMPONENT24 and GL_LUMINENCE, this is just the state of the code as I write this).

The render (with a zn of 1 and a zf of 10000) g_p_vtxCube being an interleaved array:

  glInterleavedArrays(GL_T2F_C4F_N3F_V3F, 0, g_p_vtxCube);
glDrawElements(GL_TRIANGLES, g_uiNumIndices, GL_UNSIGNED_SHORT, g_p_usCube);


The depth copy:

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

glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, 1024, 1024, 0);


And the 2D render:

    glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1024, 768, 0, -1, 1); // I know, but I prefer the top-left as origin.

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
glTexCoord2f(1, 0); glVertex3f(256, 0, 0);
glTexCoord2f(1, 1); glVertex3f(256, 256, 0);
glTexCoord2f(0, 1); glVertex3f(0, 256, 0);
glEnd();


Now, I have changed every single value in there, types, modes, flags and values to every single permutation I can find on the web with no success. The texture stays white. It's like the depth values aren't getting saved, but the behaviour of the scene shows that they must be, so it must be the copy. The behaviour is the same on cards old and new, ATI and NVidia. And, for that matter, on Windows and Linux.

Can anyone tell me what idiotic thing I'm doing or not doing? I don't care if it makes me feel stupid. In fact, I might register www.howtocopythedepthbuffertoatextureinopengl.com and leave the answer there for future generations, so no-one has to go through this pain ever again. :)

Cheers.

[Edited by - subi211 on December 7, 2010 4:28:18 AM]

Share this post


Link to post
Share on other sites
I think you need to:

glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

before you call glCopy~~

though I would use a fbo so you render the depth directly to texture (rtt). You'' finf more on this if look to using fbo(frame buffer objects).

dont forget to set them back:
glDrawBuffer(GL_BACK);
glReadBuffer(GL_FRONT);

Share this post


Link to post
Share on other sites
No luck with using GL_NONE I'm afraid.

I'll try with an FBO, I assume you mean because the depth element on those is on a separate texture made with glGenRenderbuffersEXT? And that if I just glBindTexture that texture in the post-process step I can access it like any other in a shader?

Share this post


Link to post
Share on other sites
You create the depth texture the same way you create a color texture for the color attachments. So something along the lines of...
GLint depthTexture;
glGenTextures (1, &depthTexture);
glBindTexture (GL_TEXTURE_2D, depthTexture);

glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, screenwidth, screenheight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);

glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);

Or the equivalent with the EXT functions.

Share this post


Link to post
Share on other sites
Okay, got it. For reference, here's the FBO creation code:

  // Create a frame buffer object.
glGenFramebuffersEXT(1, &m_uiFramebufferID);
glBindFramebufferEXT(GL_FRAMEBUFFER, m_uiFramebufferID);

// Create texture.
unsigned int uiFBOWidth = 32;
while(uiFBOWidth < max(w, h))
{
uiFBOWidth *= 2;
}

glGenTextures(1, &m_uiRenderbufferID);
glBindTexture(GL_TEXTURE_2D, m_uiRenderbufferID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, uiFBOWidth, uiFBOWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiRenderbufferID, 0);

// Create depth texture.
glGenTextures(1, &m_uiRenderbufferDepthID);
glBindTexture(GL_TEXTURE_2D, m_uiRenderbufferDepthID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, uiFBOWidth, uiFBOWidth, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_uiRenderbufferDepthID, 0);

// Check everything worked.
GLenum eStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
if(eStatus != GL_FRAMEBUFFER_COMPLETE)
{
return false;
}


That gives me the depth information in m_uiRenderbufferDepthID, and when I bind and render that I can see the depth buffer.

As a further question, I know the depth effect is subtle (unless the camera is close) as depth buffers aren't linear. I wasn't expecting them to be THAT subtle though - in fact, I can't see how there can be enough difference to be useful in post-processing. Is there anything to be done about that?

Share this post


Link to post
Share on other sites
You can create a custom depth in a 1 channel texture.
By using a GL_R32F texture format instead. You can write to the that channel in the shader.

float depth = (-viewPos.z-near)/(far-near);

http://www.gamerendering.com/category/rendering-methods/page/3

Share this post


Link to post
Share on other sites
I did a quick check:

  glBindTexture(GL_TEXTURE_2D, sgl.m_uiRenderbufferDepthID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

float* p_fTexture = (float*)malloc(1024 * 1024 * sizeof(float));
glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, p_fTexture);

FILE* p_f = fopen("DEPTH.RAW", "wb");
for(int i = 0; i < (1024 * 1024); i++)
{
unsigned char c = (unsigned char)(pow(10.0f, p_fTexture[i]) * 255.0f);
fwrite(&c, 1, 1, p_f);
}
fclose(p_f);
free(p_fTexture);


... and the information IS there, so no worries. I shall adjust my z-values for a better range.

Thanks guys!

[Edited by - subi211 on December 7, 2010 9:29:38 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Similar Content

    • By xhcao
      Does sync be needed to read texture content after access texture image in compute shader?
      My simple code is as below,
      glUseProgram(program.get());
      glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
      glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
      glDispatchCompute(1, 1, 1);
      // Does sync be needed here?
      glUseProgram(0);
      glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
      glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                     GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
      glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
       
      Compute shader is very simple, imageLoad content from texture[0], and imageStore content to texture[1]. Does need to sync after dispatchCompute?
    • By Jonathan2006
      My question: is it possible to transform multiple angular velocities so that they can be reinserted as one? My research is below:
      // This works quat quaternion1 = GEQuaternionFromAngleRadians(angleRadiansVector1); quat quaternion2 = GEMultiplyQuaternions(quaternion1, GEQuaternionFromAngleRadians(angleRadiansVector2)); quat quaternion3 = GEMultiplyQuaternions(quaternion2, GEQuaternionFromAngleRadians(angleRadiansVector3)); glMultMatrixf(GEMat4FromQuaternion(quaternion3).array); // The first two work fine but not the third. Why? quat quaternion1 = GEQuaternionFromAngleRadians(angleRadiansVector1); vec3 vector1 = GETransformQuaternionAndVector(quaternion1, angularVelocity1); quat quaternion2 = GEQuaternionFromAngleRadians(angleRadiansVector2); vec3 vector2 = GETransformQuaternionAndVector(quaternion2, angularVelocity2); // This doesn't work //quat quaternion3 = GEQuaternionFromAngleRadians(angleRadiansVector3); //vec3 vector3 = GETransformQuaternionAndVector(quaternion3, angularVelocity3); vec3 angleVelocity = GEAddVectors(vector1, vector2); // Does not work: vec3 angleVelocity = GEAddVectors(vector1, GEAddVectors(vector2, vector3)); static vec3 angleRadiansVector; vec3 angularAcceleration = GESetVector(0.0, 0.0, 0.0); // Sending it through one angular velocity later in my motion engine angleVelocity = GEAddVectors(angleVelocity, GEMultiplyVectorAndScalar(angularAcceleration, timeStep)); angleRadiansVector = GEAddVectors(angleRadiansVector, GEMultiplyVectorAndScalar(angleVelocity, timeStep)); glMultMatrixf(GEMat4FromEulerAngle(angleRadiansVector).array); Also how do I combine multiple angularAcceleration variables? Is there an easier way to transform the angular values?
    • By dpadam450
      I have this code below in both my vertex and fragment shader, however when I request glGetUniformLocation("Lights[0].diffuse") or "Lights[0].attenuation", it returns -1. It will only give me a valid uniform location if I actually use the diffuse/attenuation variables in the VERTEX shader. Because I use position in the vertex shader, it always returns a valid uniform location. I've read that I can share uniforms across both vertex and fragment, but I'm confused what this is even compiling to if this is the case.
       
      #define NUM_LIGHTS 2
      struct Light
      {
          vec3 position;
          vec3 diffuse;
          float attenuation;
      };
      uniform Light Lights[NUM_LIGHTS];
       
       
    • By pr033r
      Hello,
      I have a Bachelor project on topic "Implenet 3D Boid's algorithm in OpenGL". All OpenGL issues works fine for me, all rendering etc. But when I started implement the boid's algorithm it was getting worse and worse. I read article (http://natureofcode.com/book/chapter-6-autonomous-agents/) inspirate from another code (here: https://github.com/jyanar/Boids/tree/master/src) but it still doesn't work like in tutorials and videos. For example the main problem: when I apply Cohesion (one of three main laws of boids) it makes some "cycling knot". Second, when some flock touch to another it scary change the coordination or respawn in origin (x: 0, y:0. z:0). Just some streng things. 
      I followed many tutorials, change a try everything but it isn't so smooth, without lags like in another videos. I really need your help. 
      My code (optimalizing branch): https://github.com/pr033r/BachelorProject/tree/Optimalizing
      Exe file (if you want to look) and models folder (for those who will download the sources):
      http://leteckaposta.cz/367190436
      Thanks for any help...

    • By Andrija
      I am currently trying to implement shadow mapping into my project , but although i can render my depth map to the screen and it looks okay , when i sample it with shadowCoords there is no shadow.
      Here is my light space matrix calculation
      mat4x4 lightViewMatrix; vec3 sun_pos = {SUN_OFFSET * the_sun->direction[0], SUN_OFFSET * the_sun->direction[1], SUN_OFFSET * the_sun->direction[2]}; mat4x4_look_at(lightViewMatrix,sun_pos,player->pos,up); mat4x4_mul(lightSpaceMatrix,lightProjMatrix,lightViewMatrix); I will tweak the values for the size and frustum of the shadow map, but for now i just want to draw shadows around the player position
      the_sun->direction is a normalized vector so i multiply it by a constant to get the position.
      player->pos is the camera position in world space
      the light projection matrix is calculated like this:
      mat4x4_ortho(lightProjMatrix,-SHADOW_FAR,SHADOW_FAR,-SHADOW_FAR,SHADOW_FAR,NEAR,SHADOW_FAR); Shadow vertex shader:
      uniform mat4 light_space_matrix; void main() { gl_Position = light_space_matrix * transfMatrix * vec4(position, 1.0f); } Shadow fragment shader:
      out float fragDepth; void main() { fragDepth = gl_FragCoord.z; } I am using deferred rendering so i have all my world positions in the g_positions buffer
      My shadow calculation in the deferred fragment shader:
      float get_shadow_fac(vec4 light_space_pos) { vec3 shadow_coords = light_space_pos.xyz / light_space_pos.w; shadow_coords = shadow_coords * 0.5 + 0.5; float closest_depth = texture(shadow_map, shadow_coords.xy).r; float current_depth = shadow_coords.z; float shadow_fac = 1.0; if(closest_depth < current_depth) shadow_fac = 0.5; return shadow_fac; } I call the function like this:
      get_shadow_fac(light_space_matrix * vec4(position,1.0)); Where position is the value i got from sampling the g_position buffer
      Here is my depth texture (i know it will produce low quality shadows but i just want to get it working for now):
      sorry because of the compression , the black smudges are trees ... https://i.stack.imgur.com/T43aK.jpg
      EDIT: Depth texture attachment:
      glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24,fbo->width,fbo->height,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fbo->depthTexture, 0);
  • Popular Now