Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi lights shadow mapping does not work correctly using GLSL

I have implemented the basic shadow mapping algorithm but it works correctly with only one light.

I want to render a scene with two following point lights :

  • Light_1 - position : vec3(-8.0f, 5.0f, 8.0f), direction : vec3(1.3f, -1.0f, -1.0f)
  • Light_2 - position : vec3(8.0f, 5.0f, 8.0f), direction : vec3(1.3f, -1.0f, -1.0f)

If I render separately the two lights I have the following results:

Rendering with Light_1 :

enter image description here

Rendering with Light_2 :

enter image description here

But the two light together it looks like this :

enter image description here

As you can see the first shadow seems to be rendered correctly, but it is below the shadow of the light_2 which is not correct. To sum up the situation I have the texture of my box which is bound to the texture unit 0. The shadow depth texture is bound from the texture unit 1 and if there are more than one depth texture (so at least two ligths, like in this example), there are bound to the texture unit 1 + 1 (GL_TEXTURE1 + 1). Here's the code that represent what I said :

for (int idy = 0; idy < this->m_pScene->getLightList().size(); idy++)

[...]

Light *light = this->m_pScene->getLightList()[idy];
FrameBuffer *frameBuffer = light->getFrameBuffer();

glActiveTexture(GL_TEXTURE1 + idy);
glBindTexture(GL_TEXTURE_2D, frameBuffer->getTexture()->getTextureId()); //To unbind

shaderProgram->setUniform(std::string("ShadowMatrix[").append(Convertor::toString<int>       (idy)).append("]").c_str(), this->m_pScene->getLightList()[idy]->getBiasViewPerspectiveMatrix() * modelMatrix);
                    shaderProgram->setUniform(std::string("ShadowMap[").append(Convertor::toString<int>(idy)).append("]").c_str(), (int)idy + 1);

It corresponds in our case to :

shaderProgram->setUniform("ShadowMatrix[0]", <shadow_matrix_light_1>);
shaderProgram->setUniform("ShadowMap[0]", 1); (GL_TEXTURE1)
shaderProgram->setUniform("ShadowMatrix[1]", <shadow_matrix_light_2>);
shaderProgram->setUniform("ShadowMap[1]", 2); (GL_TEXTURE2)

The vertex shader is the following (available for just 2 lights):

#version 400

#define MAX_SHADOW_MATRIX 10
#define MAX_SHADOW_COORDS 10

layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
layout (location = 2) in vec2 VertexTexture;

uniform mat3 NormalMatrix;
uniform mat4 ModelViewMatrix;
uniform mat4 ShadowMatrix[MAX_SHADOW_MATRIX];
uniform mat4 MVP;

uniform int lightCount;

out vec3 Position;
out vec3 Normal;
out vec2 TexCoords;
out vec4 ShadowCoords[MAX_SHADOW_COORDS];

void main(void)
{
    TexCoords = VertexTexture;
    Normal = normalize(NormalMatrix * VertexNormal);
    Position = vec3(ModelViewMatrix * VertexPosition);
    for (int idx = 0; idx < lightCount; idx++)
        ShadowCoords[idx] = ShadowMatrix[idx] * VertexPosition;
    gl_Position = MVP * VertexPosition;
}

And a piece of code of the fragment shader :

[...]

vec3 evalBasicFragmentShadow(vec3 LightIntensity, int idx)
{
    vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;

    if (ShadowCoords[idx].w > 0.0f)
    {
        vec4 tmp_shadow_coords = ShadowCoords[idx];

        tmp_shadow_coords.z -= SHADOW_OFFSET;

        float shadow = textureProj(ShadowMap[idx], tmp_shadow_coords);

        LightIntensity = LightIntensity * shadow + Ambient;
    }
    else
    {
        LightIntensity = LightIntensity + MaterialInfos.Ka;
    }
    return (LightIntensity);
}

vec3 getLightIntensity(vec3 TexColor)
{
    vec3 LightIntensity = vec3(0.0f);

    for (int idx = 0; idx < lightCount; idx++)
    {
        vec3 tnorm = (gl_FrontFacing ? -normalize(Normal) : normalize(Normal));
        vec3 lightDir = vec3(LightInfos[idx].Position) - Position;
        vec3 lightDirNorm = normalize(lightDir);
        float lightAtt = getLightAttenuation(lightDir, LightInfos[idx]);

        LightIntensity += Point_ADS_Shading(lightAtt, -tnorm, lightDirNorm, TexColor, idx);
        LightIntensity = evalBasicFragmentShadow(LightIntensity, idx);
    }
    return (LightIntensity);
}

[...]

It's look like a texture unit problem because separatly the two shadows have been rendered perfectly and I use glActiveTexture correctly (I think so). Plus, I noticed that if I change the loading order of the lights, the bad shadow is caused by 'the other light' (it's the contrary). So it seems to comes from the texture unit 2, but I don't understand why. Does anyone can help me, please ? Thanks a lot in advance for your help.

like image 711
user1364743 Avatar asked Dec 23 '13 16:12

user1364743


1 Answers

I solved my problem. Actually, I just filled the first depth texture (for the first loaded light). So for the second light, the shadow map was not filled and this is what explains the black area on the third image above.

Here's the final result :

enter image description here

enter image description here

I hope this post will be usefull for someone. Thanks for your attention.

like image 172
user1364743 Avatar answered Oct 03 '22 00:10

user1364743