4
\$\begingroup\$

I've been playing around with rendering shadow maps using FBOs in OpenGL. I set up a simple directional light in my engine and managed to get a shadow map rendered. My Scene is a big castle and the shadow was cast over most of the other objects in the scene. Out of curiosity I removed the castle and just added a simple floor and my shadow map no longer renders properly. It seems that only one object at a time is making it through my render pass and onto the shadow map.

Here's an overview of the way the render is structured:

void RenderingManager::RenderGL()
{
    PreRenderGL();

    ShadowPassGL();

    //Other user defined render passes here?

    ScenePassGL();

    //Cleanup
    directionalLights.clear();
    pointLights.clear();
    renderables.clear();
}

The ShadowPassGL() call is fairly simple

void RenderingManager::ShadowPassGL()
{
    glViewport(0, 0, 1024, 1024);
    for (unsigned int i = 0; i < directionalLights.size(); i++)
        directionalLights[i]->RenderShadowMap(ShadowShader);
}

The RenderShadowMap(Shader* shadowShader) call is a bit more complicated but it seems the orthographic view is setup properly, the look at view is also correct. I have verified that the matrices that are generated by my math functions work.

void DirectionalLightInternal::RenderShadowMapGL(Shader* shadowShader)
{
    //Bind shadow shader for rendering shadow maps
    shadowShader->bindShader();

    //Send info about the directional light to the shader for shadow mapping
    Vector3 focalPoint = direction * -10;

    //Compute MVP from light's direction
    Matrix4 depthProjection = Matrix4::getOrthographicProjection(-10, 10, -10, 10, -20, 20);
    Matrix4 depthView = Matrix4::getLookAtView(focalPoint, Vector3(0, 0, 0), Vector3(0, 1, 0));

    depthMVP = depthView * depthProjection;

    shadowShader->setGlobalMatrix4("depthMVP", depthMVP);

    //Actually bind framebuffer and render shadow map for texture

    //Bind buffer for drawing
    glBindFramebuffer(GL_FRAMEBUFFER, shadowBuffer);

    glClearDepth(1.0f);
    glClear(GL_DEPTH_BUFFER_BIT);

    //render buffer
    RenderingManager::RenderPass();

    //Clean up
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    shadowShader->freeShader();
}

And the final bit of code that I think is relevant is the RenderPass() method which just loops through all renderable objects and tries to render them with RenderObjectGL(Renderable renderable).

void RenderingManager::RenderObjectGL(Renderable renderable)
{
        Mesh* mesh = renderable.mesh;

        GLint shaderProgram;
        glGetIntegerv(GL_CURRENT_PROGRAM, &shaderProgram);

        GLuint vPosition = glGetAttribLocation(shaderProgram, "vPosition");
        GLuint vNormal = glGetAttribLocation(shaderProgram, "vNormal");
        GLuint vTexCoord = glGetAttribLocation(shaderProgram, "vTexCoord");

        glEnableVertexAttribArray(vPosition);
        glEnableVertexAttribArray(vNormal);
        glEnableVertexAttribArray(vTexCoord);

        int normalOffset = mesh->getPointSize();
        int texCoordOffset = normalOffset + mesh->getNormalSize();

        glBindBuffer(GL_ARRAY_BUFFER, mesh->getVBO());
        glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
        glVertexAttribPointer(vNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(normalOffset));
        glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(texCoordOffset));

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIBO());

        //Draw Shape
        glDrawElements(GL_TRIANGLES, mesh->getNumberOfVerts(), GL_UNSIGNED_SHORT, (void *)0);
}

//Render every object in the scene; assume a bound shader
void RenderingManager::RenderPassGL()
{
    for(unsigned int i = 0; i < renderables.size(); i++)
        RenderObjectGL(renderables[i]);
}

I figured some images to illustrate the problem would be pretty useful.

When I render with the castle it looks like this:

Castle Rendered

And the shadow map from the scene is:

Castle Shadow Map

Interestingly the shadow map is really just of the castle, the other objects aren't in the shadow map.

Now the scene with just the floor:

Floor Rendered

And its shadow map:

enter image description here

Which again seems to be of just the floor, none of the other objects in my scene. Is there some aspect of FBOs that I'm missing here?

\$\endgroup\$
  • \$\begingroup\$ You appear to call glClear on every object in the shadow pass..? \$\endgroup\$ – Jari Komppa Sep 28 '15 at 6:07
  • \$\begingroup\$ Nope. I clear once and the call to RenderPass should render every object in the scene \$\endgroup\$ – Honeybunch Sep 28 '15 at 6:09
4
\$\begingroup\$

After much deliberation and a stroke of insight I figured out what the problem was. It was a problem with my shadow map vertex shader; I wasn't putting the objects into model space. That means that all objects were being rendered at 0, 0, 0 with a scale of 1 and no rotation. OOPS.

Properly applying a model matrix in the shader managed to fix the issue.

EDIT: If you're interested in seeing the exact code that fixed the problem here's a link to the commit on Github: https://github.com/Honeybunch/Brickware-Engine/commit/4908040f3223ae157cdb55244bc6e079f7970327

There was some extra architecture that went into getting the model matrix sent to the shadow shader that might be interesting.

\$\endgroup\$
  • \$\begingroup\$ I always upvote people who fix their own issue through debugging and provide pictures/information. Nicely done. \$\endgroup\$ – Alec Teal Sep 28 '15 at 23:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.