FBO depth buffer empty :( !

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 :frowning: !

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)wglGetProcAddress("glFramebufferTexture2DEXT");
		glCheckFramebufferStatusEXT	= (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("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, &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, &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, &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
");

	// 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(&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 :frowning: !

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

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)wglGetProcAddress("glFramebufferTexture2DEXT");
		glCheckFramebufferStatusEXT	= (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("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, &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, &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, &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
");

	// 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(&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();
}




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.