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 :
Rendering with Light_2 :
But the two light together it looks like this :
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.
vec4(VertexPosition, 1.0f)
, just declare VertexPosition asvec4
to begin with. GLSL automatically fills in 1.0 forW
if yourglVertexAttribPointer (...)
call only gives enough data for XYZ. Also this whole complicated thing you are doing where you convertidy
to a character and build a string (e.g. "ShadowCoords[" idy "]") from it is unnecessary - you can get the uniform location forShadowCoords
and then addidy
to that value because each element in a uniform array is guaranteed to be allocated a sequential location. – Precedency