PDA

View Full Version : FBO depth buffer empty :( !



nicolasbol
02-04-2009, 08:30 PM
I'm trying to render to a FBO and then draw the color texture and depth texture to screen (before moving foward and go for shadowmapping)

The color buffer is populated as expected (the color from the light POV)...but the depth color is empty !

I tried to debug with gDEBugg, looked inside the FBO and I can confirm there is only 0 inside the depth buffer texture.

It looks like this:

The lower part shows the camera POV, cube is there, on a black background, as expected. I draw the color texture from the light FBO on the upper right: it's correct. I draw the depth texture to the upper left: It's a big blank rectangle :( !

http://fabiensanglard.net/shadowmapping/fbo.png

The code C ANSI and uses GLUT for portability, it is one file:



#ifdef _WIN32
#include "windows.h"
#endif

#include "GLUT/glut.h"
#include "glext.h"
#include <stdio.h>


#ifdef _WIN32
// As microsoft did not maintain openGL after version 1.1, Windows platform need to go throught this crap ; macosX and Linux are fine.
// This block simply retries openGL function needed for this example.
// I recommend to use GLEW instead of going this way. This is done this way only to ease beginner's compilation and portability


PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;

// FrameBuffer (FBO) gen, bin and texturebind
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT ;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT ;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT ;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT ;


void getOpenGLFunctionPointers(void)
{
glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) wglGetProcAddress("glGenFramebuffersEXT");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) wglGetProcAddress("glBindFramebufferEXT");
glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddres s("glFramebufferTexture2DEXT");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddr ess("glCheckFramebufferStatusEXT");

}
#endif

// Expressed as float so gluPerspective division returns a float and not 0 (640/480 != 640.0/480.0).
#define RENDER_WIDTH 640.0
#define RENDER_HEIGHT 480.0

#define SHADOW_MAP_RATIO 1

//Camera position
float p_camera[3] = {0,3,0};

//Camera lookAt
float l_camera[3] = {2,0,-10};

//Light position
float p_light[3] = {0,3,0};

//Camera lookAt
float l_light[3] = {0,0,-5};

// Hold id of the framebuffer for light POV rendering
GLuint fboId;

// Z values will be rendered to this texture when using fboId framebuffer
GLuint depthTextureId;

GLuint colorTextureId;

void generateShadowFBO()
{
int shadowMapWidth = RENDER_WIDTH/SHADOW_MAP_RATIO;
int shadowMapHeight = RENDER_HEIGHT/SHADOW_MAP_RATIO;

GLenum FBOstatus;

glGenTextures(1, &amp;colorTextureId);
glBindTexture(GL_TEXTURE_2D, colorTextureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadowMapWidth, shadowMapHeight, 0, GL_RGBA, GL_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);


// Try to use a texture depth component
glGenTextures(1, &amp;depthTextureId);
glBindTexture(GL_TEXTURE_2D, depthTextureId);

// Normally filtering on depth texture is done bia GL_NEAREST, but Nvidia has a built-in support for Hardware filtering: use GL_LINEAR
// On ATI cards this fallback to GL_NEAREST anyway.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

// Three next lines are necessary if we wan to use the convenient shadow2DProj function in the shader.
// Otherwise we have to rely on texture2DProj
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);

glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, GL_DEPTH_COMPONENT, GL_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

// create a framebuffer object
glGenFramebuffersEXT(1, &amp;fboId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);

// attach the texture to FBO color attachment point
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, colorTextureId, 0);
// attach the texture to FBO depth attachment point
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, depthTextureId, 0);

// check FBO status
FBOstatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(FBOstatus != GL_FRAMEBUFFER_COMPLETE_EXT)
printf("GL_FRAMEBUFFER_COMPLETE_EXT failed, CANNOT use FBO\n");

// switch back to window-system-provided framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void setupMatrices(float position_x,float position_y,float position_z,float lookAt_x,float lookAt_y,float lookAt_z)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(75,RENDER_WIDTH/RENDER_HEIGHT,1,200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(position_x,position_y,position_z,lookAt_ x,lookAt_y,lookAt_z,0,1,0);
}

void update(void)
{

}

void drawObjects(void)
{
glPushMatrix();
glTranslatef(2,0,-5);
glutSolidCube(1);
glPopMatrix();
}

void renderScene(void)
{

update();

//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA,GL_ONE);

glViewport(0,0,RENDER_WIDTH,RENDER_HEIGHT);

//First step: Render from the light POV to a FBO
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fboId); //Rendering offscreen

glClearColor(1,0,0,1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//glDepthMask(GL_TRUE);
//glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //Disable color rendering, we only want to write to the Z-Buffer

setupMatrices(p_light[0],p_light[1],p_light[2],l_light[0],l_light[1],l_light[2]);

glColor4f(1,1,1,1);
drawObjects();


// Now rendering from the camera POV, using the FBO to generate shadows
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); //Rendering to screen

//glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); //Enabling color write (previously disabled for light POV z-buffer rendering)
setupMatrices(p_camera[0],p_camera[1],p_camera[2],l_camera[0],l_camera[1],l_camera[2]);

glColor4f(1,1,1,1);
drawObjects();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-RENDER_WIDTH/2,RENDER_WIDTH/2,-RENDER_HEIGHT/2,RENDER_HEIGHT/2,1,200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//glColor4f(1,1,1,1);
//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
//glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,colorTextureId);

glTranslated(0,0,-1);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex2d(0,0);
glTexCoord2d(0,1);glVertex2d(0,RENDER_HEIGHT/2);
glTexCoord2d(1,1);glVertex2d(RENDER_WIDTH/2,RENDER_HEIGHT/2);
glTexCoord2d(1,0);glVertex2d(RENDER_WIDTH/2,0);
glEnd();

//glTranslated(-RENDER_HEIGHT/2,0,0);
glBindTexture(GL_TEXTURE_2D,depthTextureId);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex3f(0,0,0);
glTexCoord2d(0,1);glVertex3f(0,RENDER_HEIGHT/2,0);
glTexCoord2d(1,1);glVertex3f(-RENDER_WIDTH/2,RENDER_HEIGHT/2,0);
glTexCoord2d(1,0);glVertex3f(-RENDER_WIDTH/2,0,0);
glEnd();

glDisable(GL_TEXTURE_2D);

glutSwapBuffers();
}

void processNormalKeys(unsigned char key, int x, int y) {

if (key == 27)
exit(0);
}


int main(int argc, char** argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(RENDER_WIDTH,RENDER_HEIGHT);
glutCreateWindow("GLSL Shadow mapping");

// This call will grab openGL extension function pointers.
// This is not necessary for macosx and linux
#ifdef _WIN32
getOpenGLFunctionPointers();
#endif
generateShadowFBO();

glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);

glutKeyboardFunc(processNormalKeys);

glutMainLoop();
}


I'm suspect the error is in the FBO creation function: generateShadowFBO but I can't spot it :( !

Help me obi-wan kenoby you are my only hope !

nicolasbol
02-05-2009, 09:23 AM
Finally found the solution !

I looks like the following line:



glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);





Despite being requiered for shadow sampling in the GLSL will make the texture appear all white. I commented out and it's now working. I still need to uncomment if I want my shadow2DProj function in GLSL to work.

Depth testing still works though, whether lines are commented or not.

Anyone can explain ?

Anyway, if anybody come across this, here is the fixed code: How to render the depth buffer on screen for debugging:



#ifdef _WIN32
#include "windows.h"
#endif

#include "GLUT/glut.h"
#include "glext.h"
#include <stdio.h>


#ifdef _WIN32
// As microsoft did not maintain openGL after version 1.1, Windows platform need to go throught this crap ; macosX and Linux are fine.
// This block simply retries openGL function needed for this example.
// I recommend to use GLEW instead of going this way. This is done this way only to ease beginner's compilation and portability


PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;

// FrameBuffer (FBO) gen, bin and texturebind
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT ;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT ;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT ;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT ;


void getOpenGLFunctionPointers(void)
{
glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) wglGetProcAddress("glGenFramebuffersEXT");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) wglGetProcAddress("glBindFramebufferEXT");
glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddres s("glFramebufferTexture2DEXT");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddr ess("glCheckFramebufferStatusEXT");

}
#endif

// Expressed as float so gluPerspective division returns a float and not 0 (640/480 != 640.0/480.0).
#define RENDER_WIDTH 640.0
#define RENDER_HEIGHT 480.0

#define SHADOW_MAP_RATIO 1

//Camera position
float p_camera[3] = {0,2,0};

//Camera lookAt
float l_camera[3] = {2,0,-10};

//Light position
float p_light[3] = {5,3,0};

//Camera lookAt
float l_light[3] = {0,0,-5};

// Hold id of the framebuffer for light POV rendering
GLuint fboId;

// Z values will be rendered to this texture when using fboId framebuffer
GLuint depthTextureId;

GLuint colorTextureId;

void generateShadowFBO()
{
int shadowMapWidth = RENDER_WIDTH/SHADOW_MAP_RATIO;
int shadowMapHeight = RENDER_HEIGHT/SHADOW_MAP_RATIO;

GLenum FBOstatus;

glGenTextures(1, &amp;colorTextureId);
glBindTexture(GL_TEXTURE_2D, colorTextureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadowMapWidth, shadowMapHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);


// Try to use a texture depth component
glGenTextures(1, &amp;depthTextureId);
glBindTexture(GL_TEXTURE_2D, depthTextureId);

// Normally filtering on depth texture is done bia GL_NEAREST, but Nvidia has a built-in support for Hardware filtering: use GL_LINEAR
// On ATI cards this fallback to GL_NEAREST anyway.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

// Three next lines are necessary if we wan to use the convenient shadow2DProj function in the shader.
// Otherwise we have to rely on texture2DProj
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
//glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);

glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

// create a framebuffer object
glGenFramebuffersEXT(1, &amp;fboId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);

// attach the texture to FBO color attachment point
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, colorTextureId, 0);
// attach the texture to FBO depth attachment point
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, depthTextureId, 0);

// check FBO status
FBOstatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(FBOstatus != GL_FRAMEBUFFER_COMPLETE_EXT)
printf("GL_FRAMEBUFFER_COMPLETE_EXT failed, CANNOT use FBO\n");

// switch back to window-system-provided framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void setupMatrices(float position_x,float position_y,float position_z,float lookAt_x,float lookAt_y,float lookAt_z)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(75,RENDER_WIDTH/RENDER_HEIGHT,0.5f,200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(position_x,position_y,position_z,lookAt_ x,lookAt_y,lookAt_z,0,1,0);
}

void update(void)
{

}

float delta = 0;

void drawObjects(void)
{
glPushMatrix();
glTranslatef(0,1,-2-delta);
glColor4f(0,1,0,1);
glutSolidCube(4);
glPopMatrix();

glPushMatrix();
glTranslatef(0,0,-5);
//glRotatef(-90,1,0,0);
glColor4f(1,0,1,1);
glutSolidCube(4);
glPopMatrix();

delta += 0.01;
}

void renderScene(void)
{

update();

//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA,GL_ONE);

glViewport(0,0,RENDER_WIDTH,RENDER_HEIGHT);

//First step: Render from the light POV to a FBO
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fboId); //Rendering offscreen

glClearColor(1,0,0,1.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//glDepthMask(GL_TRUE);
//glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //Disable color rendering, we only want to write to the Z-Buffer

setupMatrices(p_light[0],p_light[1],p_light[2],l_light[0],l_light[1],l_light[2]);


drawObjects();


// Now rendering from the camera POV, using the FBO to generate shadows
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); //Rendering to screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); //Enabling color write (previously disabled for light POV z-buffer rendering)
setupMatrices(p_camera[0],p_camera[1],p_camera[2],l_camera[0],l_camera[1],l_camera[2]);


drawObjects();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-RENDER_WIDTH/2,RENDER_WIDTH/2,-RENDER_HEIGHT/2,RENDER_HEIGHT/2,1,20000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glColor4f(1,1,1,1);
//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
//glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,colorTextureId);


glTranslated(0,0,-1);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex2d(0,0);
glTexCoord2d(0,1);glVertex2d(0,RENDER_HEIGHT/2);
glTexCoord2d(1,1);glVertex2d(RENDER_WIDTH/2,RENDER_HEIGHT/2);
glTexCoord2d(1,0);glVertex2d(RENDER_WIDTH/2,0);
glEnd();

//glTranslated(-RENDER_HEIGHT/2,0,0);
glBindTexture(GL_TEXTURE_2D,depthTextureId);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex3f(0,0,0);
glTexCoord2d(0,1);glVertex3f(0,RENDER_HEIGHT/2,0);
glTexCoord2d(1,1);glVertex3f(-RENDER_WIDTH/2,RENDER_HEIGHT/2,0);
glTexCoord2d(1,0);glVertex3f(-RENDER_WIDTH/2,0,0);
glEnd();

glDisable(GL_TEXTURE_2D);

glutSwapBuffers();
}

void processNormalKeys(unsigned char key, int x, int y) {

if (key == 27)
exit(0);
}


int main(int argc, char** argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(RENDER_WIDTH,RENDER_HEIGHT);
glutCreateWindow("GLSL Shadow mapping");

// This call will grab openGL extension function pointers.
// This is not necessary for macosx and linux
#ifdef _WIN32
getOpenGLFunctionPointers();
#endif
generateShadowFBO();

glEnable(GL_DEPTH_TEST);

glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);

glutKeyboardFunc(processNormalKeys);

glutMainLoop();
}

-Ekh-
02-05-2009, 10:52 AM
I guess it's because you use shaders, so the depth comparison is done inside the shaders but not inside OpenGL.

Forgive me if I'm wrong.