I am currently trying to do a shadow map.
Here is the depth map when drawn on a quad (Which looks good to me):
And here is the final result when i try to cast the shadow in my fragment shader:
As you can see, there is no shadow being cast where it should be but instead, there is a lot of weird shadow looking spots all over the ground plane.
Any idea what is causing this ?
Code that i am using:
My shadow class
#pragma region Constructor - Destructor
Shadow::Shadow() {
glGenFramebuffers(1, &m_depthMapFBO); //Create frame buffer
m_shadowWidth = 1024; //Set shadow map size
m_shadowHeight = 1024;
glGenTextures(1, &m_depthMap);
glBindTexture(GL_TEXTURE_2D, m_depthMap);
//Generate the texture with gl_depth_component settings
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_shadowWidth, m_shadowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
//Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindFramebuffer(GL_FRAMEBUFFER, m_depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Shadow::Shadow(GLuint shadowWidth, GLuint shadowHeight) {
glGenFramebuffers(1, &m_depthMapFBO); //Create frame buffer
m_shadowWidth = shadowWidth; //Set shadow map size
m_shadowHeight = shadowHeight;
glGenTextures(1, &m_depthMap);
glBindTexture(GL_TEXTURE_2D, m_depthMap);
//Generate the texture with gl_depth_component settings
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_shadowWidth, m_shadowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
//Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindFramebuffer(GL_FRAMEBUFFER, m_depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Shadow::~Shadow() {
}
#pragma endregion
#pragma region Get
const GLuint* Shadow::GetDepthMapFBO() const { return &m_depthMapFBO; } ;
const GLuint* Shadow::GetDepthMap() const { return &m_depthMap; } ;
const GLuint Shadow::GetShadowWidth() const { return m_shadowWidth; };
const GLuint Shadow::GetShadowHeight() const { return m_shadowHeight; };
#pragma endregion
#pragma region Prototypes definition
void Shadow::ConfigureShaderAndMatrices() {
}
void Shadow::RenderToDepthMap() {
glViewport(0, 0, m_shadowWidth, m_shadowHeight);
glBindFramebuffer(GL_FRAMEBUFFER, m_depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
}
void Shadow::Unbind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
#pragma endregion
My render function :
void Render() {
//--------------- SHADOW ------------------
m_shadow->RenderToDepthMap(); //Set the scene for rendering from light position
GLfloat near_plane = 1.0f, far_plane = 7.5f;
glm::mat4 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
glm::vec3 lightPos = glm::vec3(m_lights[0]->GetPosition().x, m_lights[0]->GetPosition().y, m_lights[0]->GetPosition().z);
//lightPos *= 2.5f;
glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 lightSpaceMatrix = lightProjection * lightView;
if (m_objectPool.size() > 0) {
for (Model* m : m_objectPool) {
m->RenderForShadow(m_Shaders[e_normal]->GetProgram(), &lightSpaceMatrix);
}
}
m_shadow->Unbind(); //Unbind the frame buffer
//--------------- Normal rendering with shadow ------------------
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));
//Update the lights for the texture shader
m_Shaders[e_texture]->Bind();
m_Shaders[e_texture]->SetUniform("numLights", (int)m_lights.size()); //Set the ammount of lights
//Set value for each light
for (int i = 0; i < m_lights.size(); i++) {
m_Shaders[e_texture]->SetUniform("lights[" + std::to_string(i) + "].position", m_lights[i]->GetPosition());
m_Shaders[e_texture]->SetUniform("lights[" + std::to_string(i) + "].intensities", m_lights[i]->GetIntensities());
m_Shaders[e_texture]->SetUniform("lights[" + std::to_string(i) + "].ambientCoefficient", m_lights[i]->GetAmbientCoefficient());
m_Shaders[e_texture]->SetUniform("lights[" + std::to_string(i) + "].attenuation", m_lights[i]->GetAttenuation());
m_Shaders[e_texture]->SetUniform("lights[" + std::to_string(i) + "].coneAngle", m_lights[i]->GetConeAngle());
m_Shaders[e_texture]->SetUniform("lights[" + std::to_string(i) + "].coneDirection", m_lights[i]->GetConeDirection());
}
m_Shaders[e_texture]->SetUniform("cameraPosition", m_camera->position());
//Render tools
/*if (m_grid)
m_grid->Render();
if (m_axis)
m_axis->Render();
if (m_skybox)
m_skybox->Render();*/
//Add the shadow map to the shader and the light matrix
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, *m_shadow->GetDepthMap());
GLuint lightMatrixLocation = glGetUniformLocation(*m_Shaders[e_texture]->GetProgram(), "lightSpaceMatrix");
//Give the info to the shader
glUniformMatrix4fv(lightMatrixLocation, 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
if (m_objectPool.size() > 0) {
for (Model* m : m_objectPool) {
m->Render();
}
}
/*
m_Shaders[e_quad]->Bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, *m_shadow->GetDepthMap());
RenderQuad();*/
//m_terrain->Render(); //Render the terrain
glFlush();
}
My vertex shader
#version 430
in vec4 position;
in vec2 texture;
in vec3 normal;
in vec3 tangent;
out vec2 fragTexcord;
out vec3 fragNormal;
out vec3 fragVert;
out mat4 f_modelView;
out vec4 FragPosLightSpace;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 modelView;
uniform mat4 lightSpaceMatrix;
void main(){
fragVert = vec3(position);
gl_Position = projection * view * model * position;
fragTexcord = texture;
fragNormal = normal;
f_modelView = modelView;
vec4 pos = model * position;
FragPosLightSpace = lightSpaceMatrix * pos;
}
My fragment shader
#version 430
#define MAX_LIGHTS 15
uniform int numLights;
uniform struct Light{
vec4 position;
vec3 intensities;
float ambientCoefficient;
float attenuation;
float coneAngle;
vec3 coneDirection;
} lights[MAX_LIGHTS];
uniform float materialShininess;
uniform vec3 materialSpecularColor;
uniform vec3 cameraPosition;
uniform mat4 model;
uniform bool specularMapping;
uniform bool normalMapping;
uniform bool glossMapping;
uniform bool ambientOcclusionMapping;
uniform sampler2D diffuseTexture;
uniform sampler2D specularTexture;
uniform sampler2D normalTexture;
uniform sampler2D glossTexture;
uniform sampler2D aoTexture;
uniform sampler2D shadowMap;
in mat4 f_modelView;
in vec2 fragTexcord;
in vec3 fragNormal;
in vec3 fragVert;
in vec4 FragPosLightSpace;
out vec4 color;
float ShadowCalculation(vec4 fragPosLightSpace)
{
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// Transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(shadowMap, projCoords.xy).r;
// Get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
// Check whether current frag pos is in shadow
float shadow = currentDepth > closestDepth ? 1.0 : 0.0;
return shadow;
}
vec3 ApplyLight(Light light, vec3 diffuseColor, vec3 normal, vec3 fragPosition, vec3 surfaceToCamera, vec4 specularColor, float shininess){
vec3 surfaceToLight;
float attenuation = 1.0;
float pointAttenuation = 1.0f;
if(light.position.w == 0.0) {
//directional light
surfaceToLight = normalize(light.position.xyz);
attenuation = 1.0; //no attenuation for directional lights
} else {
//point light
surfaceToLight = normalize((light.position.xyz - fragPosition));
float distanceToLight = length(light.position.xyz - fragPosition);
attenuation = 1.0 / (1.0 + light.attenuation * pow(distanceToLight, 2));
//cone restrictions (affects attenuation)
float lightToSurfaceAngle = degrees(acos(dot(-surfaceToLight, normalize(light.coneDirection))));
if(lightToSurfaceAngle > light.coneAngle){
if(lightToSurfaceAngle - light.coneAngle < 2.5f){ //Smooth around the spotlight by 2.5 degree
pointAttenuation = 1 / lightToSurfaceAngle;
pointAttenuation = clamp(pointAttenuation, 0, 1);
}else{
attenuation = 0.0;
}
}else{
pointAttenuation = (1 + 15) / lightToSurfaceAngle; //Smooth color from center
pointAttenuation = clamp(pointAttenuation, 0, 1);
}
}
//Ambient
vec3 ambient = diffuseColor.rgb * light.ambientCoefficient * light.intensities * pointAttenuation;
//Diffuse
float brightness = max(0,dot(normal, surfaceToLight));
vec3 diffuse = brightness * light.intensities * diffuseColor.rgb;
//specular
float specularCoefficient = 0.0f;
float cosAngle;
cosAngle = dot(surfaceToCamera, reflect(-surfaceToLight, normal));
if(shininess < 255){
if(brightness > 0.0){
cosAngle = clamp(cosAngle, 0,1);
specularCoefficient = pow(cosAngle, shininess);
}
}
vec3 specular = specularCoefficient * materialSpecularColor * light.intensities * specularColor.rgb;
//Attenuation relative to distance
float distanceToLight = length(vec3(light.position.xyz) - fragPosition);
float shadow = ShadowCalculation(FragPosLightSpace);
return ambient + ((1.0 - shadow) * (diffuse + specular));
//return ambient + attenuation * (diffuse + specular);
}
void main(){
float shininess = materialShininess;
vec4 diffuseColor = vec4(1);
vec4 specularColor = vec4(1);
vec4 normalColor = vec4(1);
diffuseColor = texture(diffuseTexture,fragTexcord); //Color on the diffuse texture
if(ambientOcclusionMapping)
diffuseColor *= texture(aoTexture, fragTexcord) * 1.2;
if(specularMapping)
specularColor = texture(specularTexture,fragTexcord); //Color on the specular texture
if(glossMapping)
shininess = texture(glossTexture, fragTexcord).r;
vec3 fragPosition = vec3((model * vec4(fragVert,1)).xyz);
mat3 normalMatrix = transpose(inverse(mat3(model)));
vec3 normal = normalize(normalMatrix * fragNormal);
vec3 surfaceToCamera = normalize(cameraPosition - fragPosition);
if(normalMapping){
normal = normalize(normalMatrix * fragNormal);
}
//Calculate all the lights
vec3 finalColor = vec3(0);
for(int i = 0; i < numLights; i++){
finalColor += ApplyLight(lights[i], diffuseColor.rgb, normal, fragPosition, surfaceToCamera,specularColor,shininess);
}
//HDR (high dynamic range)
finalColor = vec3(1.0) - exp(-finalColor * 0.8);
//Gamma correction
vec3 gamma = vec3(1.0/2.2);
//Final color calculation
//Gamma calculation : color = vec4(pow(linearColor,gamma),diffuseColor.a);
color = vec4(finalColor,diffuseColor.a);
float shadow = ShadowCalculation(FragPosLightSpace);
//color = diffuseColor * (1 - shadow);
}