I’m experiencing some issues trying to render my scene and display it on a fullscreen quad.
I first render depth to a shadowMap for all shadow-casters in my scene. I then render the scene where all shadow-receivers get the shadowMap in the fragment shader.
This works just fine when I render directly to the backbuffer, but if I try to render to an FBO color0 attachment, and then send that texture to a fullscreen quad for final backbuffer rendering, the shadows gets all wrong.
I would think it’s got to do with how I set up my FBO with depth and color texture attachements. If someone could give me some help on thisone I’d be very happy!
some code:
void GenericManager::initFBO()
{
glGenFramebuffers(1, &fbo);
}
void GenericManager::initShadows()
{
glGenTextures(1, &depthShadowMap);
glBindTexture(GL_TEXTURE_2D, depthShadowMap);
{
// GL_LINEAR does not make sense for depth texture. However, next tutorial shows usage of GL_LINEAR and PCF
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Remove artefact on the edges of the shadowmap
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
depthShadowMapSize = 1024;
// No need to force GL_DEPTH_COMPONENT24, drivers usually give you the max precision if available
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, depthShadowMapSize, depthShadowMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
} glBindTexture(GL_TEXTURE_2D, 0); //Done setting up the texture
}
void GenericManager::initFinal()
{
glGenTextures(1, &finalMap);
glBindTexture(GL_TEXTURE_2D, finalMap);
{
// GL_LINEAR does not make sense for depth texture. However, next tutorial shows usage of GL_LINEAR and PCF
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Remove artefact on the edges of the shadowmap
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
finalMapSize = 1024;
// No need to force GL_DEPTH_COMPONENT24, drivers usually give you the max precision if available
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, finalMapSize, finalMapSize, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
} glBindTexture(GL_TEXTURE_2D, 0); //Done setting up the texture
//Create a the final fullscreen quad to render the scene's final framebuffer texture to
finalNode = factory->create(Scene::NODE_PLANE);
finalNode->setShader(cl_format("%1/%2", basePath, "Resources/Shaders/final"));
finalNode->GetProperty<siut::simd::Vec3f>("Size") = siut::simd::Vec3f(10.0f, 10.0f, 0.0f);
finalNode->setTexId8(finalMap);
finalNode->add(finalCamera);
finalCamera->translate(0.0f, 0.0f, 13.0f);
finalCamera->lookAt(finalCamera->getGlobalPos(), finalNode->getGlobalPos(), siut::simd::Vec3f(0.0f, 1.0f, 0.0f));
}
void GenericManager::postInitFBO()
{
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
{
GLenum fboStatus;
// Instruct openGL that we won't bind a color texture with the currently binded FBO
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
// attach the texture to FBO depth attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthShadowMap, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_NONE);
// attach the texture to FBO color0 attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, finalMap, 0);
// check FBO status
fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(fboStatus != GL_FRAMEBUFFER_COMPLETE)
printf("GL_FRAMEBUFFER_COMPLETE failed, CANNOT use FBO
");
} glBindFramebuffer(GL_FRAMEBUFFER, 0); // switch back to window-system-provided framebuffer
}
I call these at initialization of my scene manager:
lightCamera = static_cast<Core::PerspectiveCamera*>(factory->create(Scene::NODE_PERSPECTIVE_CAMERA));
lightCamera->perspective(40.0f, 1.0f, 1.0f, 10000.0f);
finalCamera = static_cast<Core::PerspectiveCamera*>(factory->create(Scene::NODE_PERSPECTIVE_CAMERA));
finalCamera->perspective(40.0f, 1.0f, 1.0f, 10000.0f);
initFBO();
{
initShadows();
initFinal();
} postInitFBO();
The next two snippets show how I render the scene using the FBO
void GenericManager::display()
{
siut::simd::Mat4f lightView;
siut::simd::Vec3f lightDir;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); //Rendering offscreen
{
//////////////////////////////
// PASS 1
// DRAW DEPTH FOR SHADOW
//////////////////////////////
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
);
glClear(GL_DEPTH_BUFFER_BIT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //Disable color rendering, we only want to write to the Z-Buffer
// Cull switching, rendering only backface, this is done to avoid self-shadowing
glCullFace(GL_FRONT);
if(lightCamera)
{
siut::simd::Vec3f lightPos = siut::simd::Vec3f(580.0f, 280.0f, 680.0f);
siut::simd::Vec3f lightTarget = siut::simd::Vec3f(64.0f*8.0f, 100.0f, 64.0f*8.0f);
lightDir = lightPos - lightTarget;
lightCamera->lookAt(lightPos,
lightTarget,
siut::simd::Vec3f(0.0f, 1.0f, 0.0f));
lightView = lightCamera->getViewMatrix();
coreManager->setActiveCamera(lightCamera);
}
displayScene(false, true, lightView, lightDir);
//////////////////////////////
// PASS 2
// DRAW COLOR ATTACHMENT
//////////////////////////////
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCullFace(GL_BACK);
if(coreManager->getStateManager()->getCurrentState()->getPerspectiveCamera())
coreManager->setActiveCamera(coreManager->getStateManager()->getCurrentState()->getPerspectiveCamera());
displayScene(true, false, lightView, lightDir);
} glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
displayFinal();
}
void GenericManager::displayFinal()
{
IRenderInfo *info = finalNode->getRenderInfo();
if(info == NULL || finalNode->isHidden())
return;
coreManager->setActiveCamera(finalCamera);
renderer->displayInfo(info, finalNode, 0, siut::simd::identityMatrixf(), siut::simd::Vec3f());
}
This results in the following render:
If I change my display function, so that it becomes this instead:
void GenericManager::display()
{
siut::simd::Mat4f lightView;
siut::simd::Vec3f lightDir;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); //Rendering offscreen
{
//////////////////////////////
// PASS 1
// DRAW DEPTH FOR SHADOW
//////////////////////////////
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glClear(GL_DEPTH_BUFFER_BIT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //Disable color rendering, we only want to write to the Z-Buffer
// Cull switching, rendering only backface, this is done to avoid self-shadowing
glCullFace(GL_FRONT);
if(lightCamera)
{
siut::simd::Vec3f lightPos = siut::simd::Vec3f(580.0f, 280.0f, 680.0f);
siut::simd::Vec3f lightTarget = siut::simd::Vec3f(64.0f*8.0f, 100.0f, 64.0f*8.0f);
lightDir = lightPos - lightTarget;
lightCamera->lookAt(lightPos,
lightTarget,
siut::simd::Vec3f(0.0f, 1.0f, 0.0f));
lightView = lightCamera->getViewMatrix();
coreManager->setActiveCamera(lightCamera);
}
displayScene(false, true, lightView, lightDir);
} glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCullFace(GL_BACK);
if(coreManager->getStateManager()->getCurrentState()->getPerspectiveCamera())
coreManager->setActiveCamera(coreManager->getStateManager()->getCurrentState()->getPerspectiveCamera());
displayScene(true, false, lightView, lightDir);
}
then it renders the shadows just fine:
Anyone spot some immediate mistakes? I’m not sure, but I have a feeling that renderbuffers is something I might have to use to get this right… any advice that can make me smarter would be highly appreciated though!