Shadow Mapping and Shadow2DProj

Hey Guys,

I’m currently working with the fixed-function pipeline, but I’ve decided to begin the upgrade to Modern OpenGL.

One of the first areas I’m looking at is GLSL, and more specifically, Shadow Mapping.

In order to do this, I’ve created a test program (in Java, using LWJGL), to try and figure out how to use the Shadow2DProj function.

The following code is what I use to render the depth map, followed by the actual render:

    private void drawShadowScene() {
        GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
        GL11.glViewport(0, 0, 800, 600);
        GL11.glColorMask(false, false, false, false);

        OpenGL.clearScreen();

        lightCamera.lookThrough();

        updateLightingMatrix();

        GL11.glPushMatrix();
        GL11.glColor3f(0.0f, 0.0f, 1.0f);
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glVertex3f(-20.0f, 0.0f, -20.0f);
        GL11.glVertex3f(20.0f, 0.0f, -20.0f);
        GL11.glVertex3f(20.0f, 0.0f, 0.0f);
        GL11.glVertex3f(-20.0f, 0.0f, 0.0f);
        GL11.glEnd();
        GL11.glPopMatrix();

        GL11.glColor3f(1.0f, 0.0f, 0.0f);
        GL11.glPushMatrix();
        drawCube(0.0f, 2.0f, -10.0f, 1.0f, 1.0f, 1.0f, false, false);
        GL11.glPopMatrix();

        GL11.glColorMask(true, true, true, true);
        GL11.glViewport(0, 0, 800, 600);
        GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
    }

    private void drawCombinedScene() {
        OpenGL.clearScreen();

        GL13.glActiveTexture(GL13.GL_TEXTURE0);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTexture);

        shadowMapShader.enable();
        shadowMapShader.setMatrix4Property("lightingMatrix", lightMatrix);
        shadowMapShader.setProperty("depthSampler", 0);

        player.render();

        GL11.glPushMatrix();
        GL11.glColor3f(0.0f, 0.0f, 1.0f);
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glVertex3f(-20.0f, 0.0f, -20.0f);
        GL11.glVertex3f(20.0f, 0.0f, -20.0f);
        GL11.glVertex3f(20.0f, 0.0f, 0.0f);
        GL11.glVertex3f(-20.0f, 0.0f, 0.0f);
        GL11.glEnd();
        GL11.glPopMatrix();

        GL11.glColor3f(1.0f, 0.0f, 0.0f);
        GL11.glPushMatrix();
        drawCube(0.0f, 2.0f, -10.0f, 1.0f, 1.0f, 1.0f, false, false);
        GL11.glPopMatrix();

        shadowMapShader.disable();

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
    }

And here is the code I use to generate the FrameBuffer and Texture, as well as the function I use to create the light matrix:

    private void setupDepthRendering() {
        depthTexture = GL11.glGenTextures();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTexture);
        GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
        GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D,  GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);

        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, 800, 600, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (FloatBuffer)null);

        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL14.GL_COMPARE_R_TO_TEXTURE);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_FUNC, GL11.GL_LEQUAL);

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);

        fbo = GL30.glGenFramebuffers();
        GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
        GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, depthTexture, 0);
        GL11.glDrawBuffer(GL11.GL_NONE);
        GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
    }

and…

    public void updateLightingMatrix() {
        FloatBuffer modelView = BufferUtils.createFloatBuffer(16);
        FloatBuffer projection = BufferUtils.createFloatBuffer(16);

        // Texture bias matrix
        float[] biasValues = {0.5f, 0.0f, 0.0f, 0.0f,
                0.0f, 0.5f, 0.0f, 0.0f,
                0.0f, 0.0f, 0.5f, 0.0f,
                0.5f, 0.5f, 0.5f, 1.0f};
        FloatBuffer biasMatrix = (FloatBuffer)BufferUtils.createFloatBuffer(16).put(biasValues).flip();

        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView);
        GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);

        GL11.glPushMatrix();

        GL11.glLoadIdentity();
        GL11.glLoadMatrix(biasMatrix);

        GL11.glMultMatrix(modelView);
        GL11.glMultMatrix(projection);

        lightMatrix = BufferUtils.createFloatBuffer(16);
        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, lightMatrix);

        GL11.glPopMatrix();
    }

Finally, here is my vertex and fragment shader:

varying vec4 shadowCoordinate;

uniform sampler2DShadow depthSampler;

void main() {
    float shadow = 1.0f;
    shadow = shadow2DProj(depthSampler, shadowCoordinate);

    gl_FragColor = shadow;
}

and…

varying vec4 shadowCoordinate;

uniform mat4 lightingMatrix;

void main() {
    shadowCoordinate = lightingMatrix * gl_Vertex;
    gl_FrontColor = gl_Color;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

However, none of this seems to have any impact. All I see on the screen is a white plane below a white cube, with no ‘shadowing’ at all.

Am I setting any render states that I shouldn’t be? I’m pretty sure the depth map is rendering correctly, as when I previously rendered it to a quad, I could clearly make out the cube/plane.

Thanks for the help,
Matt.

FloatBuffer biasMatrix = (FloatBuffer)BufferUtils.createFloatBuffer(16).put(biasValues).flip();

Does flip() transpose the matrix returned by put() again? If so, you transpose the correct matrix which would yield false results when computing the light’s projection MVPB matrix.

Furthermore, the projection matrix is not computed correctly:


GL11.glLoadMatrix(biasMatrix);
GL11.glMultMatrix(modelView);
GL11.glMultMatrix(projection);

What will this compute? It will compute the matrix M[SUB]Bias[/SUB]* M[SUB]Model[/SUB] * M[SUB]View[/SUB] * M[SUB]Projection[/SUB].

This is incorrect. The projector matrix is computed just as any other MVP matrix - incorporating the light sources properties of course. The bias matrix is needed to map values from [-w, w] at the end of the transformation to [0,1]. Minding how the matrix stack works, your order of operations needs to be:


GL11.glLoadIdentity();
GL11.glLoadMatrix(biasMatrix);
GL11.glMultMatrix(projection);
GL11.glMultMatrix(modelView);

Shaders look correct. However, I didn’t see any call to glUniformMatrix4fv() anywhere in your code. Do you actually ass the matrix to the vertex shader’s constant memory?

Thanks for the reply!

Does flip() transpose the matrix returned by put() again? If so, you transpose the correct matrix which would yield false results when computing the light’s projection MVPB matrix.

Actually, I’m using LWJGL (Java bindings to OpenGL), and the only way to actually communicate with OpenGL is through the use of FloatBuffers (effectively native areas of memory), the flip function just sets the position back to 0 so it can be read.

I didn’t see any call to glUniformMatrix4fv() anywhere in your code. Do you actually ass the matrix to the vertex shader’s constant memory?

I actually use that in the shader.setMatrixProperty function, or at least I think I do, I’m not at my development PC at the moment, so I’ll have to check later!

Thanks again, I’ll post later with the results!

Hi!
So, I altered the updateLightMatrix function to match your suggestion.

It seems to have had some effect, as instead of simple white shapes, I am now getting the following:

I still think there is something wrong with the way I am calculating the light matrix, or perhaps the shadow coordinates, as the black line on the back of the cube looks very similar to what should be it’s shadow. Any suggestions?

Thanks for the help!
Matt.

Can you absolutely verfiy that the depth texture still works?

It actually turns out that the problem above was being caused by the camera being too far away from the cube/plane!

It’s working now, however, I’m getting the following image:

It seems that, aside from the moire pattern on the floor, that when the cube is high enough, the black line appears on the back of the cube? Is there any way to remove this?

Thanks for your help, I can’t believe it’s finally working!
Matt.