Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 10 of 29

Thread: Reading the depth buffer into texture memory

Hybrid View

  1. #1
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    18

    Reading the depth buffer into texture memory

    Hello,

    I'm trying to get a simple shadowmapping demo up and running but I've run into a bit of a problem. I need to translate to the light's position, save the depth values into texture memory and finally generate texture coordinates based on the depth values. Now, my current code isn't working so I've been debugging it the whole day and I suspect the problem is with the transfer of depth buffer info into a texture.

    Here's my code:

    init:
    Code :
    glGenTextures(1, &shadowmap_);
    glBindTexture(GL_TEXTURE_2D, shadowmap_);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 512, 512, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);

    render:

    Code :
    // position the light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos_);
     
    // set up the projection parameters from the light's POV
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    	glLoadIdentity();
    	gluPerspective(lightFOV_, lightAspect_, lightNear_, lightFar_);
     
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    	glLoadIdentity();
    	// translate to the light's position
    	gluLookAt(lightPos_[0], lightPos_[1], lightPos_[2], -1.0f, 0.0f, 5.0f, 0.0f, 1.0f, 0.0f);
     
    	// render the scene to get the depth information
    	renderSceneElements();
    glPopMatrix();
     
    // end the projection modification
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
     
    // copy over the depth information
    glBindTexture(GL_TEXTURE_2D, shadowmap_);
    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 512, 512);
     
    // render a simple quad with the shadowmap for debugging
    glPushMatrix();
    	glEnable(GL_TEXTURE_2D);
    	glBindTexture(GL_TEXTURE_2D, shadowmap_);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     
    	glTranslatef(3.0f, 2.0f, 5.0f);
    	glBegin(GL_QUADS);
    		glTexCoord2f(0.0f, 0.0f);
    		glVertex3f(0.0f, 0.0f, 0.0f);
     
    		glTexCoord2f(1.0f, 0.0f);
    		glVertex3f(3.0f, 0.0f, 0.0f);
     
    		glTexCoord2f(1.0f, 1.0f);
    		glVertex3f(3.0f, 3.0f, 0.0f);
     
    		glTexCoord2f(0.0f, 1.0f);
    		glVertex3f(0.0f, 3.0f, 0.0f);
    	glEnd();
    	glDisable(GL_TEXTURE_2D);
    glPopMatrix();

    The result is a white quad :/

    renderSceneElements() contains a bunch of VAOs.

    Also, I know there's a way to copy over the depth buffer using FBOs. I want to implement that afterwards but first I'm curious as to what on Earth I'm doing wrong here.

    Thanks in advance!
    Last edited by dr4cula; 07-24-2013 at 10:55 AM.

  2. #2
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    498
    Quote Originally Posted by dr4cula View Post
    I'm trying to get a simple shadowmapping demo up and running but I've run into a bit of a problem. I need to translate to the light's position, save the depth values into texture memory and finally generate texture coordinates based on the depth values. Now, my current code isn't working so I've been debugging it the whole day and I suspect the problem is with the transfer of depth buffer info into a texture.
    Why do you think that the problem is with the transfer? If it's because it's a white quad, have you analysed what the expected range of values should be? The mapping between Z and depth is highly non-linear, particularly if the near plane is too close.

    Also: try storing your own data in the depth texture, to make sure that your debug code is working.
    Last edited by GClements; 07-24-2013 at 03:57 PM.

  3. #3
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    18
    Thanks for your reply!

    I decided to use FBOs: I can actually see the shadowmap when I map it onto a quad (it's faint but it's visible at least). However, my problems don't end there: now the entire scene is black (except for the textured quad and brownish glClearColor() defined background). I'm guessing my texture coordinate generation is wrong but not sure. Any help would be greatly appreciated!

    new init:
    Code :
    glGenTextures(1, &shadowmap_);
    glBindTexture(GL_TEXTURE_2D, shadowmap_);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 512, 512, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
     
    //glGenRenderbuffers(1, &renderbuffer_);
    //glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_);
    //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 512, 512);
     
    glGenFramebuffers(1, &framebuffer_);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
    //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer_);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowmap_, 0);

    new render:
    Code :
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
    //glDrawBuffer(GL_NONE);
    //glReadBuffer(GL_NONE);
     
    glClearColor(0.5, 0.2, 0.1, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // position the light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos_);
     
    // set up the projection parameters from the light's POV
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluPerspective(lightFOV_, lightAspect_, lightNear_, lightFar_);
     
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    // translate to the light's position
    gluLookAt(lightPos_[0], lightPos_[1], lightPos_[2], -1.0f, 0.0f, 5.0f, 0.0f, 1.0f, 0.0f);
     
    // render the scene to get the depth information
    renderSceneElements();
    glPopMatrix();
     
    // end the projection modification
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
     
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
    // copy over the depth information
    //glBindTexture(GL_TEXTURE_2D, shadowmap_);
    //glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 512, 512);
     
    // matrix defining the planes for S, Q, R, T components for texture generation
    float planeMatrix[16];
    glPushMatrix();
    glLoadIdentity();
    // compensate for the eye-coordinate to texture coordinate conversion: [-1,1] to [0,1]
    glTranslatef(0.5f, 0.5f, 0.0f);
    glScalef(0.5f, 0.5f, 1.0f);
     
    // do the perspective projection and translate to the light's position
    gluPerspective(lightFOV_, lightAspect_, lightNear_, lightFar_);
    gluLookAt(lightPos_[0], lightPos_[1], lightPos_[2], -1.0f, 0.0f, 5.0f, 0.0f, 1.0f, 0.0f);
     
    glGetFloatv(GL_MODELVIEW_MATRIX, planeMatrix);
    glPopMatrix();
     
    // go from OpenGL's column-major to row-major matrix form
    transposeMatrix16(planeMatrix); 
     
    // set up the type for texture generation
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
     
    // data for texture generation
    glTexGenfv(GL_S, GL_OBJECT_PLANE, &planeMatrix[0]);
    glTexGenfv(GL_T, GL_OBJECT_PLANE, &planeMatrix[4]);
    glTexGenfv(GL_R, GL_OBJECT_PLANE, &planeMatrix[8]);
    glTexGenfv(GL_Q, GL_OBJECT_PLANE, &planeMatrix[12]);
     
    glEnable(GL_TEXTURE_GEN_S);
    glEnable(GL_TEXTURE_GEN_T);
    glEnable(GL_TEXTURE_GEN_R);
    glEnable(GL_TEXTURE_GEN_Q);
     
     
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, shadowmap_);
     
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
    glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
     
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
     
    renderSceneElements();
     
    glDisable(GL_LIGHTING);
    glDisable(GL_LIGHT0);
     
    glDisable(GL_TEXTURE_2D);
     
    glDisable(GL_TEXTURE_GEN_Q);
    glDisable(GL_TEXTURE_GEN_R);
    glDisable(GL_TEXTURE_GEN_T);
    glDisable(GL_TEXTURE_GEN_S);
     
    glPushMatrix();
    glEnable(GL_TEXTURE_2D);
    //glBindTexture(GL_TEXTURE_2D, shadowmap_);
    glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_NONE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
    glTranslatef(3.0f, 2.0f, 5.0f);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
     
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(3.0f, 0.0f, 0.0f);
     
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(3.0f, 3.0f, 0.0f);
     
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(0.0f, 3.0f, 0.0f);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();

    Note that I had to explicitly bind the texture - I thought it would be automatically related to the framebuffer and hence enabling texturing would have caused that texture to be used? If I don't have that binding there, OpenGL selects my previously used texture.

    Thanks in advance!

  4. #4
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    498
    Quote Originally Posted by dr4cula View Post
    Code :
    // compensate for the eye-coordinate to texture coordinate conversion: [-1,1] to [0,1]
    glTranslatef(0.5f, 0.5f, 0.0f);
    glScalef(0.5f, 0.5f, 1.0f);
    You need to perform the same signed-to-unsigned conversion for the Z coordinate, as the depth values in the texture are returned as 0..1.

    Also, you should bind a renderbuffer (or texture) to GL_COLOR_ATTACHMENT0 even if you're not using it.

    Quote Originally Posted by dr4cula View Post
    Note that I had to explicitly bind the texture - I thought it would be automatically related to the framebuffer and hence enabling texturing would have caused that texture to be used?
    No. glFramebufferTexture2D() causes rendered output to be directed to the texture (or rather, a specific mipmap level of it). It doesn't associate the texture with a texture unit. In fact, having a texture used as both a source and destination simultaneously is undefined.

  5. #5
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948
    In fact, having a texture used as both a source and destination simultaneously is undefined.
    Only if you sample from the same image as you're writing to. Sampling from one mipmap level and writing to another is fine.

  6. #6
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    498
    Quote Originally Posted by Alfonse Reinheart View Post
    Only if you sample from the same image as you're writing to. Sampling from one mipmap level and writing to another is fine.
    That depends upon how you define "sampling". My understanding of the 4.3 specification (8.14.2.1) is that the behaviour is undefined if the attached level is within the range of levels available for reading, regardless of which levels are actually read. So if mipmapping is disabled and the attached level is GL_TEXTURE_BASE_LEVEL, or mipmapping is enabled and the attached level is within the range GL_TEXTURE_BASE_LEVEL to GL_TEXTURE_MAX_LEVEL, the behaviour is undefined.

  7. #7
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    18
    Quote Originally Posted by GClements View Post
    You need to perform the same signed-to-unsigned conversion for the Z coordinate, as the depth values in the texture are returned as 0..1.

    Also, you should bind a renderbuffer (or texture) to GL_COLOR_ATTACHMENT0 even if you're not using it.
    The Red Book suggested translation only in x- and y- directions which I found a bit odd. Changed it to translate in the z-direction as well and added the recommended renderbuffer. However, everything is still black in the scene :/

    Quote Originally Posted by GClements View Post
    No. glFramebufferTexture2D() causes rendered output to be directed to the texture (or rather, a specific mipmap level of it). It doesn't associate the texture with a texture unit. In fact, having a texture used as both a source and destination simultaneously is undefined.
    Ah, thanks for clarifying!

    I've uploaded the code to pastebin since the forum editing kinda sucks: http://pastebin.com/G1jT0FfR

    To be honest, I'm really confused as to how OpenGL will know how to map the shadowmap to the scene if, for example, I can't use it for texture mapping a quad. I suppose it's got something to do with the GL_COMPARE_R_TO_TEXTURE but I'm a bit confused Thoughts anyone?

    Thanks in advance!

  8. #8
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    498
    Quote Originally Posted by dr4cula View Post
    However, everything is still black in the scene :/
    Are you performing a glClear() for the physical framebuffer? I don't see it in the code, but that may just be because it's not part of the render function.

    You need to call glViewport(0, 0, 512, 512) for the FBO (then set it back to cover the window for the second pass).

    The depth is being offset by 0.5 but still scaled by 1.0. All 6 values should be 0.5.

    Quote Originally Posted by dr4cula View Post
    To be honest, I'm really confused as to how OpenGL will know how to map the shadowmap to the scene if, for example, I can't use it for texture mapping a quad. I suppose it's got something to do with the GL_COMPARE_R_TO_TEXTURE but I'm a bit confused
    When GL_TEXTURE_COMPARE_MODE is GL_COMPARE_R_TO_TEXTURE, the first two texture coordinates are used to sample the texture, and the third texture coordinate is compared to the sampled value using GL_TEXTURE_COMPARE_FUNC. If the test passes, the luminance (R,G,B), intensity (R,G,B,A) or alpha are one, otherwise they're zero.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •