I am facing a really frustrating problem. After looking at a lot of tutorials (probably all existing on net, not kidding), i tried to do the point light shadow mapping using a cube texture.
The problem is: when i try to visualize my cube map, EVERYTHING is white.
I have no clue what is causing this.
Here is what it looks like when i try to visualize my cube map:
(NOTE THAT MY MODELS ARE at (-1,0,0) and (1,0,0) respectively and my light is at (0,2,0) )
And here what it should looks like (Not my project, but just for the colors)
Here is my cubeTexture class:
Shadow::Shadow(e_LightType* light) {
m_type = light;
[.... non-usefull code before ....]
else if (*m_type == e_PointLight) {
glGenFramebuffers(1, &m_depthMapFBO); //Create frame buffer
m_shadowWidth = 1024; //Set shadow map size
m_shadowHeight = 1024;
glGenTextures(1, &m_depthMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_depthMap);
for (GLuint i = 0; i < 6; i++) { //MAYBE ERROR WITH ++I
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT32F, m_shadowWidth, m_shadowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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);
glBindFramebuffer(GL_FRAMEBUFFER, m_depthMapFBO);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Framebuffer not complete!" << "\n";
glBindFramebuffer(GL_FRAMEBUFFER, 0);
m_aspect = (GLfloat)m_shadowWidth / (GLfloat)m_shadowHeight;
m_near = 1.0f;
m_far = 25.0f;
SetShadowProjection();
}
}
void Shadow::SetShadowProjection() { //Private
m_shadowProjection = glm::perspective(90.0f, m_aspect, m_near, m_far);
}
void Shadow::SetShadowTransformMatrixs(glm::vec4& position) {
glm::vec3 lightPos = glm::vec3(position.x, position.y, position.z);
m_shadowTransformMatrixs.clear();
SetShadowProjection();
for (int i = 0; i < 6; ++i) {
glm::mat4 m(1);
glm::mat4 r;
switch (i) {
case 0:
r = glm::mat4(glm::vec4(0, 0, -1, 0), glm::vec4(0, -1, 0, 0), glm::vec4(-1, 0, 0, 0), glm::vec4(0, 0, 0, 1));
break;
case 1:
r = glm::mat4(glm::vec4(0, 0, 1, 0), glm::vec4(0, -1, 0, 0), glm::vec4(1, 0, 0, 0), glm::vec4(0, 0, 0, 1));
break;
case 2:
r = glm::mat4(glm::vec4(1, 0, 0, 0), glm::vec4(0, 0, 1, 0), glm::vec4(0, -1, 0, 0), glm::vec4(0, 0, 0, 1));
break;
case 3:
r = glm::mat4(glm::vec4(1, 0, 0, 0), glm::vec4(0, 0, -1, 0), glm::vec4(0, 1, 0, 0), glm::vec4(0, 0, 0, 1));
break;
case 4:
r = glm::mat4(glm::vec4(1, 0, 0, 0), glm::vec4(0, -1, 0, 0), glm::vec4(0, 0, -1, 0), glm::vec4(0, 0, 0, 1));
break;
case 5:
r = glm::mat4(glm::vec4(-1, 0, 0, 0), glm::vec4(0, -1, 0, 0), glm::vec4(0, 0, 1, 0), glm::vec4(0, 0, 0, 1));
break;
}
m = glm::translate(m, lightPos);
m = r * m;
m_shadowTransformMatrixs.push_back(m_shadowProjection * m);
}
/*m_shadowTransformMatrixs.push_back(m_shadowProjection * glm::lookAt(lightPos, lightPos + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));
m_shadowTransformMatrixs.push_back(m_shadowProjection * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));
m_shadowTransformMatrixs.push_back(m_shadowProjection * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0)));
m_shadowTransformMatrixs.push_back(m_shadowProjection * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0)));
m_shadowTransformMatrixs.push_back(m_shadowProjection * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
m_shadowTransformMatrixs.push_back(m_shadowProjection * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0)));*/
}
void Shadow::RenderToDepthMap() {
switch (*m_type) {
case e_DirectionnalLight:
case e_Spotlight:
glViewport(0, 0, m_shadowWidth, m_shadowHeight);
glBindFramebuffer(GL_FRAMEBUFFER, m_depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
break;
case e_PointLight:
glBindFramebuffer(GL_FRAMEBUFFER, m_depthMapFBO);
glViewport(0, 0, m_shadowWidth, m_shadowHeight);
glClear(GL_DEPTH_BUFFER_BIT);
break;
}
}
I create a new light that incorporate a shadow of type point light.
Here is my render function (With both rendering pass)
void Render() {
//--------------- SHADOW ------------------
glCullFace(GL_FRONT);
GLuint texLoc;
m_Shaders[e_CubeShadowMap]->Bind();
m_lights[0]->GetShadow()->RenderToDepthMap();
m_lights[0]->GetShadow()->SetShadowTransformMatrixs(m_lights[0]->GetPosition());
for (int i = 0; i < 6; i++) { //i++ maybe error since i did ++i in shadow class
GLuint location = glGetUniformLocation(*m_Shaders[e_CubeShadowMap]->GetProgram(), "shadowMatrices");
glUniformMatrix4fv(location + i, 1, GL_FALSE, glm::value_ptr(m_lights[0]->GetShadow()->GetShadowTransformMatrixs()->at(i)));
}
m_Shaders[e_CubeShadowMap]->SetUniform("lightPos", m_lights[0]->GetPosition());
m_Shaders[e_CubeShadowMap]->SetUniform("far_plane", m_lights[0]->GetShadow()->GetFar());
if (m_objectPool.size() > 0) {
for (Model* m : m_objectPool) {
m->Render(m_Shaders[e_CubeShadowMap]->GetProgram());
}
}
m_lights[0]->GetShadow()->Unbind();
//--------------- Normal rendering with shadow ------------------
glCullFace(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Set black as clear color - Set him the depth
glViewport(0, 0, glutGet(GLUT_SCREEN_WIDTH), glutGet(GLUT_SCREEN_HEIGHT));
m_Shaders[e_Shadow]->Bind();
m_Shaders[e_Shadow]->SetUniform("lightPos", m_lights[0]->GetPosition());
m_Shaders[e_Shadow]->SetUniform("viewPos", m_camera->position());
m_Shaders[e_Shadow]->SetUniform("far_plane", m_lights[0]->GetShadow()->GetFar());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, *m_lights[0]->GetShadow()->GetDepthMap());
if (m_objectPool.size() > 0) {
for (Model* m : m_objectPool) {
m_Shaders[e_Shadow]->Bind();
texLoc = glGetUniformLocation(*m_Shaders[e_Shadow]->GetProgram(), "diffuseTexture");
glUniform1i(texLoc, 0);
texLoc = glGetUniformLocation(*m_Shaders[e_Shadow]->GetProgram(), "depthMap");
glUniform1i(texLoc, 1);
m->GetMaterial()->GetDiffuseTexture()->UseTexture(GL_TEXTURE0); //Use diffuse
m->Render(m_Shaders[e_Shadow]->GetProgram());
}
}
glFlush();
}
And finally here are all 5 shaders used for doing all this
(first pass : vertex, geometry, fragment)
PASS 1 - VERTEX #version 330 core in vec3 position; in vec2 texture; in vec3 normal;
uniform mat4 model;
void main(){
gl_Position = model * vec4(position,1.0);
}
PASS 1 - GEOMETRY
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;
uniform mat4 shadowMatrices[6];
out vec4 FragPos; // FragPos from GS (output per emitvertex)
void main()
{
//iterate over the 6 cubemap faces
for(gl_Layer=0; gl_Layer<6; ++gl_Layer) {
for(int tri_vert=0; tri_vert<3; ++tri_vert) {
FragPos = gl_in[tri_vert].gl_Position;
gl_Position = shadowMatrices[gl_Layer] * FragPos;
EmitVertex();
}
EndPrimitive();
}
}
PASS 1 : FRAGMENT
#version 330
in vec4 FragPos;
uniform vec4 lightPos;
uniform float far_plane;
out float color;
void main()
{
// get distance between fragment and light source
float lightDistance = distance(FragPos,lightPos);
// map to [0;1] range by dividing by far_plane
lightDistance = lightDistance / far_plane;
// Write this as modified depth
gl_FragDepth = lightDistance;
}
(second pass: vertex, fragment)
PASS 2 : VERTEX
#version 430
in vec3 position;
in vec2 texture;
in vec3 normal;
#define MAX_SHADOW_MATRIX 10
out VS_OUT {
vec4 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position,1.0f);
vs_out.FragPos = model * vec4(position,1.0f);
vs_out.Normal = transpose(inverse(mat3(model))) * normal;
vs_out.TexCoords = texture;
}
PASS 2 : FRAGMENT
#version 430
out vec4 FragColor;
in VS_OUT {
vec4 FragPos;
vec3 Normal;
vec2 TexCoords;
vec4 FragPosLightSpace;
} fs_in;
uniform sampler2D diffuseTexture;
uniform samplerCube depthMap;
uniform vec4 lightPos;
uniform vec3 viewPos;
void main()
{
// Get vector between fragment position and light position
vec3 fragToLight = fs_in.FragPos.xyz - lightPos.xyz;
// Use the fragment to light vector to sample from the depth map
float closestDepth = texture(depthMap, fragToLight).r;
FragColor = vec4(vec3(closestDepth * 255) , 1.0);
}
To be honest, im pretty sure its about the first pass (cube texture aint filling anything in) but i dont know why.
Here are the main sources i used: