Thats a interesting idea that it has to do with my FBO setup, but I attach a depth buffer for all my FBO’s.
Here is my FBO code:
/*
================
R_CreateShadowLightTexture
================
*/
image_t *jmvImageManager::CreateShadowLightTexture( const char *name, int shadowMapSize, int maxShadowLights ) {
image_t *lightShadowMap;
// Allocate our light shadow map inside of the engine.
lightShadowMap = R_AllocImage( name, shadowMapSize * 4, shadowMapSize * 3 );
// Generate our FBO texture.
qglGenFramebuffersEXT(1, &lightShadowMap->fboHandle);
// Bind our FBO.
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, lightShadowMap->fboHandle);
// Create and setup our lightShadowMap texture.
qglBindTexture( GL_TEXTURE_2D_ARRAY_EXT, lightShadowMap->texnum );
qglTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Use PCF if available; otherwise, this falls
qglTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // back to nearest neighbor
qglTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
qglTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
//qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.5f);
qglTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
qglTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
qglTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
qglTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_DEPTH_COMPONENT32, shadowMapSize * 4, shadowMapSize * 2, maxShadowLights, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
// Attach this texture as a DEPTH ONLY texture.
GLuint depthbuffer;
qglGenRenderbuffersEXT(1, &depthbuffer);
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuffer);
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, lightShadowMap->texnum, 0);
qglDrawBuffer(GL_NONE);
qglReadBuffer(GL_NONE);
// Get the status of our framebuffer object.
GLenum status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(status != GL_FRAMEBUFFER_COMPLETE_EXT) {
return NULL;
}
// Unbind our FBO
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return lightShadowMap;
}
/*
================
R_CreateFrameBufferObject
================
*/
image_t *jmvImageManager::CreateFrameBufferObject( const char *name, int width, int height, int numColorAttachments, bool depthCompare ) {
GLuint depthBuffer;
GLuint stencil_rb;
GLuint diffuseBuffers[ 16 ];
image_t *images[ 16 ];
// Generate our FBO.
images[ 0 ] = R_AllocImage( name, width, height );
qglGenFramebuffersEXT(1, &images[ 0 ]->fboHandle);
qglGenFramebuffersEXT(1, &images[ 0 ]->multiSampleFBO);
// Bind our FBO.
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, images[ 0 ]->fboHandle);
if( numColorAttachments == -1 ) {
qglBindTexture(GL_TEXTURE_2D, images[ 0 ]->texnum);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
qglTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.5f);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GEQUAL);
qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
//qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
GLuint depthbuffer;
qglGenRenderbuffersEXT(1, &depthbuffer);
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuffer);
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, images[ 0 ]->texnum, 0);
qglDrawBuffer(GL_NONE);
qglReadBuffer(GL_NONE);
}
else {
// Create our texture attach FBO.
for( int i = 0; i < numColorAttachments; i++ ) {
if( i != 0 ) {
images[ i ] = R_AllocImage( name, width, height );
}
qglBindTexture(GL_TEXTURE_2D, images[ i ]->texnum );
if( i == 4 ) {
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
}
else {
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
}
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if( depthCompare ) {
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
}
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, images[ i ]->texnum, 0);
}
GLenum status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(status != GL_FRAMEBUFFER_COMPLETE_EXT) {
return NULL;
}
// Create our multi sample FBO.
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, images[ 0 ]->multiSampleFBO);
// Generate our frame and render buffers.
qglGenRenderbuffersEXT(1 , &depthBuffer);
qglGenRenderbuffersEXT(1 , &stencil_rb);
qglGenFramebuffersEXT(numColorAttachments , diffuseBuffers);
// Create our render buffers.
for( int i = 0; i < numColorAttachments; i++ ) {
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, diffuseBuffers[ i ]);
// This isn't a ugly hack....:/
if( i == 4 ) {
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 4, GL_RGB32F_ARB, width, height);
}
else {
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 4, GL_RGB16F_ARB, width, height);
}
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_RENDERBUFFER_EXT, diffuseBuffers[ i ] );
}
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 4,GL_DEPTH_COMPONENT24, width, height);
//qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBuffer);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBuffer);
}
// Get the status of our framebuffer object.
GLenum status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(status != GL_FRAMEBUFFER_COMPLETE_EXT) {
char errorMessage[ 1024 ];
switch(status)
{
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
//Choose different formats
strcpy(errorMessage, "Framebuffer object format is unsupported by the video hardware. (GL_FRAMEBUFFER_UNSUPPORTED_EXT)(FBO - 820)");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
strcpy(errorMessage, "Incomplete attachment. (GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT)(FBO - 820)");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
strcpy(errorMessage, "Incomplete missing attachment. (GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT)(FBO - 820)");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
strcpy(errorMessage, "Incomplete dimensions. (GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT)(FBO - 820)");
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
strcpy(errorMessage, "Incomplete formats. (GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT)(FBO - 820)");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
strcpy(errorMessage, "Incomplete draw buffer. (GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT)(FBO - 820)");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
strcpy(errorMessage, "Incomplete read buffer. (GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT)(FBO - 820)");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
strcpy(errorMessage, "Incomplete multisample buffer. (GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT)(FBO - 820)");
break;
default:
//Programming error; will fail on all hardware
strcpy(errorMessage, "Some video driver error or programming error occured. Framebuffer object status is invalid. (FBO - 823)");
break;
}
common->Error( errorMessage );
}
// Unbind our FBO
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return images[ 0 ];
}
The same thing happens with multisample FBO’s and regular FBO’s.
Here is the actual shadow code as well:
/*
=======================
jmvShadowMap::RunPass
=======================
*/
void jmvShadowMap::RunPass( drawSurf_t *drawSurfs, int entityNum ) {
GL_State(GLS_DEFAULT);
/*
=================================
Tess.isShadowPass is valid when we are rendering the shadows to the forward rendering,
shadow FBO. When it is NOT true we are rendering the depth pass using GL_LUMINANCE,
technically this should be done via a GLSL program, but for now it's not.
For proper VSM were going to need to fix this....
FIXME!!! Ugly code.
=================================
*/
if( tess.isShadowPass == qfalse ) {
// Setup our light matrix.
SetupLightMatrix();
// FIXME: This is ugly, but we are using fixed function to render the depth map.
for( int i = 8; i >= 0; i-- ) {
GL_SelectTexture( i );
qglDisable( GL_TEXTURE_2D );
}
GL_SelectTexture( 0 );
qglEnable( GL_TEXTURE_2D );
GL_Bind( tr.whiteImage );
// Fixme!
qglUseProgramObjectARB( 0 );
qglEnable(GL_CULL_FACE);
qglCullFace(GL_BACK);
qglDisable( GL_BLEND );
qglEnable( GL_DEPTH_TEST );
qglDepthFunc(GL_LEQUAL);
qglDepthMask( true );
qglColorMask( true, true, true, true);
RB_RenderSurfaceVBO();
qglMatrixMode( GL_MODELVIEW );
qglPopMatrix();
}
else {
jmvCgProgram *shadowProgram = &interactionManager.programs[ shadowProgHandle ];
qglUseProgramObjectARB(shadowProgram->linkedProgram);
qglUniform1iARB(qglGetUniformLocationARB(shadowProgram->linkedProgram, "depthLookup"), 0); // depth-maps
qglUniform1iARB(qglGetUniformLocationARB(shadowProgram->linkedProgram, "shadowTexture"), 1);
qglUniform4fARB(qglGetUniformLocationARB(shadowProgram->linkedProgram, "eyeXyz"), backEnd.or.viewOrigin[ 0 ], backEnd.or.viewOrigin[ 1 ], backEnd.or.viewOrigin[ 2 ], 0.0 );
qglUniform4fARB( qglGetUniformLocationARB(shadowProgram->linkedProgram, "entityXyz"), backEnd.currentEntity->e.origin[ 0 ], backEnd.currentEntity->e.origin[ 1 ], backEnd.currentEntity->e.origin[ 2 ], 0.0 );
int shadowLightNum = 0;
for( int c = 0; c < tr.refdef.num_dlights; c++ ) {
if(tr.refdef.dlights[ c ].castsShadow) {
float lightRadiusParem = 1.0f / tr.refdef.dlights[ c ].radius;
tess.lightXyzRadius[ shadowLightNum ][ 0 ] = tr.refdef.dlights[ c ].transformed[ 0 ];
tess.lightXyzRadius[ shadowLightNum ][ 1 ] = tr.refdef.dlights[ c ].transformed[ 1 ];
tess.lightXyzRadius[ shadowLightNum ][ 2 ] = tr.refdef.dlights[ c ].transformed[ 2 ];
tess.lightXyzRadius[ shadowLightNum ][ 3 ] = lightRadiusParem;
shadowLightNum++;
}
}
qglUniform4fv(qglGetUniformLocationARB(shadowProgram->linkedProgram, "lightXyz"), shadowLightNum, &tess.lightXyzRadius[ 0 ][ 0 ] );
GL_SelectTexture( 0 );
qglEnable( GL_TEXTURE_CUBE_MAP );
qglBindTexture( GL_TEXTURE_CUBE_MAP, shadowFBO[ 1 ]->texnum );
// Texture 1 is the shadow depth texture.
GL_SelectTexture( 1 );
qglBindTexture( GL_TEXTURE_2D_ARRAY_EXT, shadowFBO[ 0 ]->texnum );
qglEnable(GL_CULL_FACE);
qglCullFace(GL_FRONT);
qglDisable( GL_BLEND );
qglEnable( GL_DEPTH_TEST );
qglDepthFunc(GL_LEQUAL);
qglDepthMask( true );
qglColorMask(true, true, true, true);
RB_RenderSurfaceVBO();
qglUseProgramObjectARB( 0 );
}
}