Hello,
I am currently drawing objects with shadow map / single point light and would like to have more lights displayed on views, it works perfectly fine with single light as below, however it doesn’t seemed to work at all when I add more lights.
Following are my codes, can you please point me out what is wrong with?
.
.
.
// Create and bind depth FBO/cube map
for (int i = 0; i < lights.size; i++) {
if (lights.data[i].depthMapFBO == 0)
glGenFramebuffers(1, &lights.data[i].depthMapFBO);
// Create depth cubemap texture
if (lights.data[i].depthCubemap == 0)
glGenTextures(1, &lights.data[i].depthCubemap);
glBindTexture(GL_TEXTURE_CUBE_MAP, lights.data[i].depthCubemap);
for (unsigned int j = 0; j < 6; ++j)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j + (i * lights.size), 0, GL_DEPTH_COMPONENT, lights.data[i].ShadowWidth, lights.data[i].ShadowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// Attach depth texture as FBO's depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, lights.data[i].depthMapFBO);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, lights.data[i].depthCubemap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Clear background
glClearColor(window.bgColor.r, window.bgColor.g, window.bgColor.b, window.bgColor.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Render objects to depth cubemap
for (int i = 0; i < lights.size; i++) {
// Render scene to depth cubemap
glViewport(0, 0, lights.data[i].ShadowWidth, lights.data[i].ShadowHeight);
// Projection
lights.data[i].projection = glm::perspective(glm::radians(90.0f), (float)lights.data[i].ShadowWidth / (float)lights.data[i].ShadowHeight, lights.data[i].near_plane, lights.data[i].far_plane);
std::vector<glm::mat4> shadowMatrices;
// Create depth cubemap
shadowMatrices.push_back(lights.data[i].projection * glm::lookAt(lights.data[i].Position, lights.data[i].Position + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
shadowMatrices.push_back(lights.data[i].projection * glm::lookAt(lights.data[i].Position, lights.data[i].Position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
shadowMatrices.push_back(lights.data[i].projection * glm::lookAt(lights.data[i].Position, lights.data[i].Position + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
shadowMatrices.push_back(lights.data[i].projection * glm::lookAt(lights.data[i].Position, lights.data[i].Position + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)));
shadowMatrices.push_back(lights.data[i].projection * glm::lookAt(lights.data[i].Position, lights.data[i].Position + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
shadowMatrices.push_back(lights.data[i].projection * glm::lookAt(lights.data[i].Position, lights.data[i].Position + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
// Bind depthMap FBO and clear screen
glBindFramebuffer(GL_FRAMEBUFFER, lights.data[i].depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
sShadowDepth.use();
// Transformation matrices
for (unsigned int x = 0; x < 6; ++x)
sShadowDepth.setMat4("shadowMatrices[" + std::to_string(x) + "]", shadowMatrices[x]);
sShadowDepth.setFloat("far_plane", lights.data[i].far_plane);
sShadowDepth.setVec3("lightPosition", lights.data[i].Position);
// Render objects
RenderObjects(window, objects, sShadowDepth, lights, i);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Render objects as normal
glViewport(0, 0, window.width, window.height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
if (window.projection != PROJECTION_PERSPECTIVE) {
window.prjMatrix = glm::ortho(-(float)window.width * window.scale, (float)window.width * window.scale,
-(float)window.height * window.scale, (float)window.height * window.scale, 0.1f, 100.0f);
window.view = glm::lookAt(glm::vec3(window.eye_x, window.eye_y, window.eye_z),
glm::vec3(window.center_x, window.center_y, window.center_z),
glm::vec3(window.up_x, window.up_y, window.up_z));
}
else {
window.prjMatrix = glm::perspective(glm::radians(window.camera.Zoom), (float)window.width / (float)window.height, 0.1f, 100.0f);
window.view = window.camera.GetViewMatrix();
}
shader.use();
shader.setMat4("projection", window.prjMatrix);
shader.setMat4("view", window.view);
// Camera
shader.setVec3("viewPos", window.camera.Position);
for (int i = 0; i < lights.size; i++) {
// Set lighting uniforms
shader.setVec3("lightPosition", lights.data[i].Position);
shader.setVec3("lightColor", lights.data[i].Color);
// Set shadow brightness
shader.setFloat("shadowBrightness", lights.data[i].shadowBrightness);
// Set far plane
shader.setFloat("far_plane", lights.data[i].far_plane);
}
// Enable or disable shadow
shader.setBool("withShadow", window.withShadow);
// Render objects
RenderObjects(window, objects, sShadowDepth, lights, -1);
.
.
.
[Base Vertex Shader]
#version 450 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec2 TexCoords;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform bool reverse_normals;
void main() {
vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
// A slight hack to make sure the outer large cube displays lighting from the 'inside' instead of the default 'outside'
if (reverse_normals)
vs_out.Normal = transpose(inverse(mat3(model))) * (-1.0 * aNormal);
else
vs_out.Normal = transpose(inverse(mat3(model))) * aNormal;
vs_out.TexCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
[Base Fragment Shader]
#version 450 core
out vec4 FragColor;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} fs_in;
uniform sampler2D diffuseTexture;
uniform samplerCube depthMap;
uniform vec3 lightPosition;
uniform vec3 lightColor;
uniform vec3 viewPos;
uniform float far_plane;
uniform bool withShadow;
uniform vec3 customAmbient;
uniform bool withLight;
uniform float shadowBrightness;
// Array of offset direction for sampling
vec3 gridSamplingDisk[20] = vec3[] (
vec3(1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
vec3(1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
vec3(1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
vec3(1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
vec3(0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
);
float ShadowCalculation(vec3 fragPos) {
// Get vector between fragment position and light position
vec3 fragToLight = fragPos - lightPosition;
// Get current linear depth as the length between the fragment and light position
float currentDepth = length(fragToLight);
float shadow = 0.0;
float bias = 0.15;
int samples = 20;
float viewDistance = length(viewPos - fragPos);
float diskRadius = (1.0 + (viewDistance / far_plane)) / 25.0;
for (int i = 0; i < samples; ++i) {
float closestDepth = texture(depthMap, fragToLight + gridSamplingDisk[i] * diskRadius).r;
closestDepth *= far_plane; // Undo mapping [0;1]
if (currentDepth - bias > closestDepth)
shadow += 1.0;
}
shadow /= float(samples);
return shadow;
}
void main() {
vec3 ambient;
vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
vec3 normal = normalize(fs_in.Normal);
// Ambient
if (!withLight)
ambient = customAmbient;
else
ambient = 0.0 * color;
// diffuse
vec3 lightDir = normalize(lightPosition - fs_in.FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * lightColor;
// specular
vec3 viewDir = normalize(viewPos - fs_in.FragPos);
vec3 reflectDir = reflect(-lightDir, normal);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
vec3 specular = spec * lightColor;
// calculate shadow
float shadow = withShadow ? ShadowCalculation(fs_in.FragPos) : 0.0;
vec3 lighting = (ambient + (shadowBrightness - shadow) * (diffuse + specular)) * color;
if (withLight)
FragColor = vec4(lighting, 1.0);
else
FragColor = vec4(vec3(0.015, 0.015, 0.015), 1.0);
}
[Shadow Depth Vertex Shader]
#version 450 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
void main() {
gl_Position = model * vec4(aPos, 1.0);
}
[Shadow Depth Geometry Shader]
#version 450 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 18) out;
uniform mat4 shadowMatrices[6];
// FragPos from GS (output per emitvertex)
out vec4 FragPos;
void main() {
for (int face = 0; face < 6; ++face) {
// Built-in variable that specifies to which face we render
gl_Layer = face;
// For each triangle's vertices
for (int i = 0; i < 3; ++i) {
FragPos = gl_in[i].gl_Position;
gl_Position = shadowMatrices[face] * FragPos;
EmitVertex();
}
EndPrimitive();
}
}
[Shadow Depth Fragment Shader]
#version 450 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
void main() {
gl_Position = model * vec4(aPos, 1.0);
}