Shadow mapping with moving object

Hi community,

I’m trying to implement shadow mapping in a small project. The scenario is as follow:

I have an object which is moving on a ground. My camera is above and behind this object which leads to a bird’s eye perspective. Now i want the object to throw a real-time shadow on the ground-surface.

I created a FBO which should render my shadowmap, call it shadowMapFBO. When i try to render to my shadowMapFBO I have to move my camera to the light’s position. For that I’m trying to use a glm::lookAt matrix (see below).
After that I do my rendering and active my screen FBO (FBO 0). During my debugging I tried many other “boxing configuration” for the depthProjectionMatrix, but I could’t fix it.
Note: As you can see I’m using something like point light, but since actually my object is just moving in 1 direction (minus z-axis) I didn’t implement a shadow cubemap.

renderShadowMap.cc


void renderShadowMap ( void ) {
        // First render pass
        shadowMapFBO->bind();
        shadowMapFBO->clearDepthBuffer();      //glClear(GL_DEPTH_BUFFER_BIT);

        glViewport( 0, 0, shadowMapResolution.x, shadowMapResolution.y );

        createShadowMapShader->use();
        glm::vec3 position = glm::vec3(objectPosition);
        glm::vec3 lightPosition = glm::vec4(0, 5, 0);

        glm::mat4 depthProjectionMatrix = glm::ortho<float>(-10,10,-10,10,-10,100);
        glm::mat4 depthViewMatrix = glm::lookAt( glm::vec3(lightPosition) , objectPosition , glm::vec3(0,1,0) );
        glm::mat4 depthModelMatrix = glm::mat4(1.0);
        glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;

        glm::mat4 scaleBiasMatrix(
                    0.5, 0.0, 0.0, 0.0,
                    0.0, 0.5, 0.0, 0.0,
                    0.0, 0.0, 0.5, 0.0,
                    0.5, 0.5, 0.5, 1.0
                    );
        shadowMatrix = scaleBiasMatrix * depthMVP;


        shadowShader->setUniform( "depthMVP", depthMVP );
        shadowShader->setUniform( "shadowMatrix", shadowMatrix );

        [ ... render objects ... ]
}

Vertex shader for creating the shadow map


#version 330 core
// Input
in vec3 aPosition;

// Matrices
uniform mat4 depthMVP;

void main(){
    gl_Position =  depthMVP * vec4( aPosition, 1.0 );
}

Fragment shader for creating the shadow map


#version 330 core

// Output data
out float depthValues;

void main(){
    // Not really needed, OpenGL does it anyway
    depthValues = gl_FragCoord.z;
}

After that i hand over the shadow map to the shaders. Now here is how I’m trying to use the shadow map in the fragment shader:

Vertex shader when using the shadow map


#version 330
// Matrices
uniform mat4 uModelMatrix;
uniform mat4 shadowMatrix;
uniform mat4 uMVPMatrix;

in vec3 aPosition;

out vec4 objPos;
out vec4 shadowCoord;

void main()
{
    gl_Position  = uMVPMatrix * vec4(aPosition, 1.0);
    objPos       = uModelMatrix * vec4(aPosition, 1.0);
    shadowCoord  = shadowMatrix * vec4(aPosition, 1.0);
}

Fragment shader when using the shadow map


#version 330

// Light Data
uniform vec4 uLightPos[6];
uniform vec4 uLightAmb[6];
uniform vec4 uLightDif[6];
uniform vec4 uLightSpec[6];

// Informations
uniform int shaderLevel;
uniform float portalRadius;
uniform vec3 uEyePos;
uniform vec3 portalPosition;

// Samplers
uniform sampler2D shadowMapTexture;
//uniform sampler2DShadow shadowMapTexture;

in vec4 objPos;
in vec4 shadowCoord;

out vec4 oColor;

vec3 shadowMapping(){

    float attenuation   = computeAttenuation(objPos, (uLightPos[0]), 1.0, 0.0, 0.0);
    vec3 ambientLight   = computeAmbience(uLightAmb[0]);

    vec3 fNormal        = computeNormals(true);
    vec3 fLightD        = computeLightDirection();

    vec3 diffuseLight   = computeDiffuseLight(fNormal, fLightD);
    vec3 specularLight  = computeSpecularLight(fNormal, fLightD);

    float bias = 0.005;
    float visibility = 1.0;

    //visibility = textureProj(shadowMapTexture, shadowCoord);

    /*
    if ( textureProj( shadowMapTexture, shadowCoord.xy ).z  <  shadowCoord.z-bias) {  // < (shadowCoord.z-bias)/shadowCoord.w
        visibility = 0.5;
    }
    float visibility = texture( shadowMapTexture, shadowCoord.xy ).z;
    visibility = texture( shadowMapTexture, vec3(shadowCoord.xy, (shadowCoord.z)/shadowCoord.w) );
    //*/

    if ( texture( shadowMapTexture, shadowCoord.xy ).z  <  shadowCoord.z){
        visibility = 0.5;
    }

    return ((ambientLight + visibility*(diffuseLight + specularLight)) * attenuation);
}

void main(){
        oColor = vec4(shadowMapping(), 1.0);
}

Actually I’m completely lost on the debugging. I tried to visualize the shadow map using 2 triangles, but it does not work as expected (I commented the texture compare mode and func out). The code for that lookis like this:


            //Initialisation
        // The quad's FBO. Used only for visualizing the shadowmap.
        glGenVertexArrays(1, &quad_VertexArrayID);
        glBindVertexArray(quad_VertexArrayID);

        static const GLfloat g_quad_vertex_buffer_data[] = {
            -1.0f, -1.0f, 0.0f,
             1.0f, -1.0f, 0.0f,
            -1.0f,  1.0f, 0.0f,
            -1.0f,  1.0f, 0.0f,
             1.0f, -1.0f, 0.0f,
             1.0f,  1.0f, 0.0f,
        };

        glGenBuffers(1, &quad_vertexbuffer);
        glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);


            //Rendering pass
            glEnableVertexAttribArray(12);

            glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
            glVertexAttribPointer(
                12,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
                3,                  // size
                GL_FLOAT,           // type
                GL_FALSE,           // normalized?
                0,                  // stride
                (void*)0            // array buffer offset
            );

            // Draw the triangle !
            // You have to disable GL_COMPARE_R_TO_TEXTURE above in order to see anything !
            glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
            glDisableVertexAttribArray(12);


//Vertex shader
#version 330 core

// Input
in vec3 aPosition;

uniform mat4 uModelMatrix;

// Output
out vec2 uv;

void main(){
        gl_Position =  vec4(aPosition , 1.0);
        uv = ( aPosition.xy + vec2(1.0 , 1.0) ) / 2.0;
}


//Fragment shader
#version 330 core

// Ouput
out vec4 oColor;

uniform sampler2D shadowMapTexture;

in vec2 uv;

void main(){
    oColor = texture2D(shadowMapTexture, uv);
    //oColor = vec4(1.0,0,0,1.0);
}

For the sake of completeness: I created my FBO as follow :


    //Create unset depth texture from where we render shadow depth into FBO
    glGenTextures(1, &shadowMapTexture);
    glBindTexture(GL_TEXTURE_2D, shadowMapTexture);

    //Alloc storage for texture data -> later filled with depth values
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, shadowMapResolution.x, shadowMapResolution.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);

    //Choose filtering mode
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    //Choose wrapping mode
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    //Choose depth comparison mode in order to leverage shadow textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

    //Create FBO and RBO for depth rendering
    glGenFramebuffers(1, &shadowMapFBO);

    glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO);

    //Attach depth texture to it
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowMapTexture, 0);

    //Disable color rendering <- no colors to attach
    glDrawBuffer(GL_NONE);

HOPEFULLY there is someone who can help us with our problem and tell us what we did wrong!

Thank you in anticipation!

Sincerely M2h

As i can see, your problem is really simple!

You have to uniform your depth mvp before every single object rendering pass, because the right position of the rendered object
is in the model matrix. So you must calculate the right mvp before rendering the object to get the right mvo matrix.


Matrix mode MODELVIEW
Push matrix
Translate and Rotate... (And do simple matrix calculations...)

Calculate the new MVP matrix                                  //Very important!
Uniform the mvp matrix as depthMVP in your case       //Very important!

Render the object

Pop matrix

I used the same tutorial for shadow mapping as you and had exactly the same problem ^^

– Daniel