Following the learnopengl tutorial (https://learnopengl.com/Advanced-Lighting/Deferred-Shading) the author leaves fixed the amount of light (32 lights) as shown by the GLSL:
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedoSpec;
struct Light {
vec3 Position;
color;
};
const int NR_LIGHTS = 32;
uniform Light lights [NR_LIGHTS];
uniform vec3 viewPos;
void main ()
{
// retrieve data from G-buffer
vec3 FragPos = texture (gPosition, TexCoords) .rgb;
vec3 Normal = texture (gNormal, TexCoords) .rgb;
vec3 Albedo = texture (gAlbedoSpec, TexCoords) .rgb;
float Specular = texture (gAlbedoSpec, TexCoords) .a;
// then calculate lighting as usual
vec3 lighting = Albedo * 0.1; // hard-coded ambient component
vec3 viewDir = normalize (viewPos - FragPos);
for (int i = 0; i <NR_LIGHTS; ++ i)
{
// diffuse
vec3 lightDir = normalize (lights [i] .Position - FragPos);
vec3 diffuse = max (dot (Normal, lightDir), 0.0) * Albedo * lights [i] .Color;
lighting + = diffuse;
}
FragColor = vec4 (lighting, 1.0);
}
And when it comes to applying the lights:
glBindFramebuffer (GL_FRAMEBUFFER, 0);
// 2. lighting pass: calculate lighting by iterating over screen filled quad pixel-by-pixel using the gbuffer's content.
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shaderLightingPass.use ();
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, gPosition);
glActiveTexture (GL_TEXTURE1);
glBindTexture (GL_TEXTURE_2D, gNormal);
glActiveTexture (GL_TEXTURE2);
glBindTexture (GL_TEXTURE_2D, gAlbedoSpec);
// send light relevant uniforms
for (unsigned int i = 0; i <lightPositions.size (); i ++)
{
shaderLightingPass.setVec3 ("lights [" + std :: to_string (i) + "] .Position", lightPositions [i]);
shaderLightingPass.setVec3 ("lights [" + std :: to_string (i) + "] .Color", lightColors [i]);
// update attenuation parameters and calculate radius
const float constant = 1.0; // note that we do not send this to the shader, we assume it is always 1.0 (in our case)
const float linear = 0.7;
const float quadratic = 1.8;
shaderLightingPass.setFloat ("lights [" + std :: to_string (i) + "] .Linear", linear);
shaderLightingPass.setFloat ("lights [" + std :: to_string (i) + "] .Quadratic", quadratic);
}
shaderLightingPass.setVec3 ("viewPos", camera.Position);
// finally render quad
renderQuad ();
but I would like to be able to add as many lights as I want, because my project will have countless lights (laser guns, bonfire, blast), so I made some changes:
GLSL:
uniform Light light;
uniform vec3 viewPos;
void main()
{
// retrieve data from gbuffer
vec3 FragPos = texture(gPosition, TexCoords).rgb;
vec3 Normal = texture(gNormal, TexCoords).rgb;
vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb;
float Specular = texture(gAlbedoSpec, TexCoords).a;
// then calculate lighting as usual
vec3 lighting = Diffuse * 0.1; // hard-coded ambient component
vec3 viewDir = normalize(viewPos - FragPos);
// diffuse
vec3 lightDir = normalize(light.Position - FragPos);
vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * light.Color;
// specular
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0);
vec3 specular = light.Color * spec * Specular;
// attenuation
float distance = length(light.Position - FragPos);
float attenuation = 1.0 / (1.0 + light.Linear * distance + light.Quadratic * distance * distance);
diffuse *= attenuation;
specular *= attenuation;
lighting += diffuse + specular;
FragColor = vec4(lighting, 1.0);
}
And then I passed the values one by one and rendered a quad:
for (unsigned int i = 0; i < lightPositions.size(); i++)
{
shaderLightingPass.use();
shaderLightingPass.setInt("gPosition", 0);
shaderLightingPass.setInt("gNormal", 1);
shaderLightingPass.setInt("gAlbedoSpec", 2);
shaderLightingPass.setVec3("light.Position", lightPositions[i]);
shaderLightingPass.setVec3("light.Color", lightColors[i]);
const float constant = 1.0; // note that we don't send this to the shader, we assume it is always 1.0 (in our case)
const float linear = 0.7;
const float quadratic = 0.08;
shaderLightingPass.setFloat("light.Linear", linear);
shaderLightingPass.setFloat("light.Quadratic", quadratic);
shaderLightingPass.setVec3("viewPos", camera.Position);
renderQuad();
glUseProgram(-1);
}
and also added a new shader to render the framebuffer on the screen:
screenShader.use();
renderQuad();
but my code renders only the first light: Result could anyone tell me what I am doing wrong and how to add the lights in the end result?
Please include code like below
And
And your draw function should look like
For complete implementation refer following
https://github.com/PixelClear/Deferred-renderer
I have above code where we store light information in SSBO so this demo has 32 lights but can easily extended to many.