openglglsllighting

GLSL Lighting for multiple light not working?


I'm trying to render multiple directional and multiple point lights but it only renders the last directional and last point light in the light arrays. I checked that all the data for lighting is properly sent to the glsl fragment shader but it doesn't seem to work. NUM_DIR_LIGHTS-1 and NUM_POINT_LIGHTS-1 are dynamically inserted into the fragment shader and also have the right values.

Calculation of the fragment color output:

vec4 ambient = vec4(0.0);
vec4 diffuse = vec4(0.0);
vec4 specular = vec4(0.0);
                    
vec4 diffuseTexel = texture(u_Material.DiffuseMap, v_TexCoord);
vec4 specularTexel = texture(u_Material.SpecularMap, v_TexCoord);
vec4 normalTexel = texture(u_Material.NormalMap, v_TexCoord);

vec3 viewDir = normalize(u_CameraPosition - v_Position);
                    
float dirShadow = 0.0;

// calculate material for all directional lights
vec3 normalFromMap = normalize(transpose(inverse(v_ModelRotation)) * normalTexel.xyz);
vec3 normalizedNormal = normalize(v_Normal);
for (int i = 0; i < NUM_DIR_LIGHTS-1; i++)
{
    vec3 lightDir = normalize(-u_DirectionalLights[i].Direction);

    // if material is mapped then apply lighting with lighting maps
    if (u_Material.IsMapped)
    {
        // ambient lighting
        ambient += vec4(u_DirectionalLights[i].Color * u_DirectionalLights[i].Intensity * diffuseTexel.rgb, 1.0);

        // diffuse lighting
        float diff = max(dot(normalFromMap, lightDir), 0.0);
        diffuse += vec4(u_DirectionalLights[i].Color * diff * diffuseTexel.rgb, 1.0);

        // specular lighting
        vec3 reflectDir = reflect(-lightDir, normalFromMap);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Material.Shininess);
        specular += vec4(u_DirectionalLights[i].Color * spec * specularTexel.rgb, 1.0);

        dirShadow += calcDirLightShadow(i, lightDir, normalTexel.xyz);
    }
    else
    {
        // ambient lighting for material
        ambient += vec4(u_DirectionalLights[i].Color * (u_Material.Ambient + u_DirectionalLights[i].Intensity * u_Material.Diffuse), 1.0);

        // diffuse lighting for material
        float diff = max(dot(normalizedNormal, lightDir), 0.0);
        diffuse += vec4(u_DirectionalLights[i].Color * u_DirectionalLights[i].Intensity * diff * u_Material.Diffuse, 1.0);

        // specular lighting for material
        vec3 reflectDir = reflect(-lightDir, normalizedNormal);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Material.Shininess);
        specular += vec4(u_DirectionalLights[i].Color * u_DirectionalLights[i].Intensity * spec * u_Material.Specular, 1.0);
                        
        dirShadow += calcDirLightShadow(i, lightDir, v_Normal);
      }
}
                    
// calculate material for all point lights
vec3 pointAmbient = vec3(0.0);
vec3 pointDiffuse = vec3(0.0);
vec3 pointSpecular = vec3(0.0);
for (int i = 0; i < NUM_POINT_LIGHTS-1; i++)
{
    // if material is mapped then apply lighting with lighting maps
    if (u_Material.IsMapped)
    {
        // ambient lighting
        pointAmbient += u_PointLights[i].Color * u_PointLights[i].Intensity * diffuseTexel.rgb;

        // diffuse lighting
        vec3 lightDir = normalize(u_PointLights[i].Position - v_Position);
        float diff = max(dot(normalFromMap, lightDir), 0.0);
        pointDiffuse += u_PointLights[i].Color * diff * diffuseTexel.rgb;

        // specular lighting
        vec3 reflectDir = reflect(-lightDir, normalFromMap);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Material.Shininess);
        pointSpecular += u_PointLights[i].Color * spec * specularTexel.rgb;
    }
    else
    {
        // ambient lighting for material
        pointAmbient += u_PointLights[i].Color * (u_Material.Ambient + u_PointLights[i].Intensity * u_Material.Diffuse);

        // diffuse lighting for material
        vec3 lightDir = normalize(u_PointLights[i].Position - v_Position);
        float diff = max(dot(normalizedNormal, lightDir), 0.0);
        pointDiffuse += u_PointLights[i].Color * u_PointLights[i].Intensity * diff * u_Material.Diffuse;

        // specular lighting for material
        vec3 reflectDir = reflect(-lightDir, normalizedNormal);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Material.Shininess);
        pointSpecular += u_PointLights[i].Color * u_PointLights[i].Intensity * spec * u_Material.Specular;
     }

    // calculate attenuation
    float distance = length(u_PointLights[i].Position - v_Position);
    float attenuation = 1.0f / (u_PointLights[i].Constant + u_PointLights[i].Linear * 
    distance + u_PointLights[i].Quadratic * (distance * distance));

    // include attenuation in lighting
    pointAmbient *= attenuation;
    pointDiffuse *= attenuation;
    pointSpecular *= attenuation;
}

// calculate directional lighting with shadow
vec3 lighting = vec3(ambient + (1.0 - dirShadow) * (diffuse + specular));

return vec4(lighting + pointAmbient + pointDiffuse + pointSpecular, 1.0);

I hope someone can understand why it isn't rendering all lights.


Solution

  • The problem is

    for (int i = 0; i < NUM_POINT_LIGHTS-1; i++)
    {
        // [...]
    
        pointAmbient *= attenuation;
        pointDiffuse *= attenuation; 
        pointSpecular *= attenuation;
    }
    

    Here the sum of the light sources is multiplied by the attenuation within the loop that iterates through the light sources. This means that light sources that have already been added are multiplied by the attenuation of later light sources. The light from the light sources that have already been added will become weaker and weaker with each new light source that is added.

    Possible solution:

    vec3 pointAmbient = vec3(0.0);
    vec3 pointDiffuse = vec3(0.0);
    vec3 pointSpecular = vec3(0.0);
    for (int i = 0; i < NUM_POINT_LIGHTS-1; i++)
    {
        // calculate attenuation
        float distance = length(u_PointLights[i].Position - v_Position);
        float attenuation = 1.0f / (u_PointLights[i].Constant + u_PointLights[i].Linear * 
            distance + u_PointLights[i].Quadratic * (distance * distance));
    
        // if material is mapped then apply lighting with lighting maps
        if (u_Material.IsMapped)
        {
            // ambient lighting
            pointAmbient += attenuation * u_PointLights[i].Color * u_PointLights[i].Intensity * diffuseTexel.rgb;
    
            // diffuse lighting
            vec3 lightDir = normalize(u_PointLights[i].Position - v_Position);
            float diff = max(dot(normalFromMap, lightDir), 0.0);
            pointDiffuse += attenuation * u_PointLights[i].Color * diff * diffuseTexel.rgb;
    
            // specular lighting
            vec3 reflectDir = reflect(-lightDir, normalFromMap);
            float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Material.Shininess);
            pointSpecular += attenuation * u_PointLights[i].Color * spec * specularTexel.rgb;
        }
        else
        {
            // ambient lighting for material
            pointAmbient += attenuation * u_PointLights[i].Color * (u_Material.Ambient + u_PointLights[i].Intensity * u_Material.Diffuse);
    
            // diffuse lighting for material
            vec3 lightDir = normalize(u_PointLights[i].Position - v_Position);
            float diff = max(dot(normalizedNormal, lightDir), 0.0);
            pointDiffuse += attenuation * u_PointLights[i].Color * u_PointLights[i].Intensity * diff * u_Material.Diffuse;
    
            // specular lighting for material
            vec3 reflectDir = reflect(-lightDir, normalizedNormal);
            float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Material.Shininess);
            pointSpecular += attenuation * u_PointLights[i].Color * u_PointLights[i].Intensity * spec * u_Material.Specular;
         }
    }