1
votes

I have a scene composed with 2 meshes (plane, cube), a light and a camera. I want to display shadows on my scene using shadow mapping technique with GLSL shaders and OpenGL.

Here's the result I have (for a sake of simplicity, my cube and my plane are both in blue color and the color) :

enter image description here

Here's the FBO and depth texture initialization :

GLfloat border[] = {1.0f, 1.0f, 1.0f, 1.0f};

    glGenTextures(1, &this->m_TextId);
    glBindTexture(GL_TEXTURE_2D, this->m_TextId);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24,
        this->m_Width, this->m_Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);

    glBindTexture(GL_TEXTURE_2D, 0);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, this->m_TextId, 0);

    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);

    GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if( result == GL_FRAMEBUFFER_COMPLETE) {
        printf("Framebuffer is complete.\n");
    } else {
        printf("Framebuffer is not complete.\n");
    }

Here's the content of my vertex shader :

#version 400
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
layout (location = 2) in vec2 VertexTexture;

uniform mat4 MVP;
uniform mat4 ShadowMatrix;

out vec4 ShadowCoords;

void main(void)
{
    ShadowCoords = ShadowMatrix * vec4(VertexPosition, 1.0f);
    gl_Position = MVP * vec4(VertexPosition, 1.0f);
}

And the one of my fragment shader :

#version 400

in vec3 Position;
in vec3 Normal;
in vec2 TexCoords;
in vec4 ShadowCoords;

layout (location = 0) out vec4 FragColor;

uniform sampler2DShadow ShadowMap;

void main(void)
{
    vec4 ModelColor = vec4(0.0f, 0.0f, 1.0f, 1.0f);

    float shadow = textureProj(ShadowMap, ShadowCoords);

    FragColor = ModelColor * shadow;
}

As you can see there are some artifacts on the models and I don't know how to withdraw them. But the shadow seems to be correct so the variables in input in my shaders should be correct too (I think so).

I tried an other technique in the fragment shader like the following one :

#version 400

in vec3 Position;
in vec3 Normal;
in vec2 TexCoords;
in vec4 ShadowCoords;

layout (location = 0) out vec4 FragColor;

uniform sampler2D ShadowMap;

void main(void)
{
    vec4 ModelColor = vec4(0.0f, 0.0f, 1.0f, 1.0f);

    vec4 shadowCoordinateWdivide = ShadowCoords / ShadowCoords.w;

    shadowCoordinateWdivide.z += 0.0005;

    float distanceFromLight = texture2D(ShadowMap,shadowCoordinateWdivide.st).z;

    float shadow = 1.0;
    if (ShadowCoords.w > 0.0)
        shadow = (distanceFromLight < shadowCoordinateWdivide.z) ? 0.5 : 1.0 ;

    FragColor = shadow * ModelColor;
}

You can notice that I don't use a sampler2DShadow but now a sampler2D. But as you can see there's none shadow displayed :

enter image description here

Does anyone can help me?

1

1 Answers

2
votes

Your first image can be explained by floating point problems. When you transform your vertex by your shadow matrix, you obtain a point whose distance from the light is almost equal to the depth in the light's depth buffer (since the point lies on the geometry). For some of those points, the transformation will give a light-space depth a little in front of the geometry and for others the depth will be a little to the back of the geometry. Hence half of them end up being occluded according to some weird pattern.

What you want to do is to perturb your ShadowCoords' Z coordinate a tiny bit towards the light to avoid this problem.