0
\$\begingroup\$

I am currently trying to do a shadow map.

Here is the depth map when drawn on a quad (Which looks good to me):

enter image description here

And here is the final result when i try to cast the shadow in my fragment shader:

enter image description here

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);

}

\$\endgroup\$
0
\$\begingroup\$

I had the exact same problem with the exact same fractal-like black spots all over my scene. I figured it out though!

I also used a box with a crate-like texture in my scene and it turned out that my fragment shader did NOT use my shadow map to do the shadow calculations, but the diffuse texture of my box.

What you see is probably the diffuse texture of your box being projected into the scene as shadow. I figured this out when I somehow managed to tile that texture and voilà, I looked at 4 black- and nothing versions of the side texture of my box. You could test this by assigning for example some plain text to your boxe's texture.

I solved this by assigning every sampler manually to the corresponding slot for each render iteration. In my shader, I assigned a uniform location for each texture, e.g. the diffuse texture:

private static int location_diffuseTextureSampler;
location_diffuseTextureState = super.getUniformLocation("material.hasDiffuseTexture");

For each entity that I render, I load its textures by calling:

textureLightShader.loadMaterial(entity.getModel().getMaterial());

...doing this:

 loadDiffuseTexture(0);
 loadSpecularTexture(1);
 loadEmissiveTexture(2);
 loadBumpTexture(3);
 loadNormalTexture(4);   

Those in turn do this:

public void loadDiffuseTexture(int slot){
    super.loadInteger(location_diffuseTextureSampler, slot);
}

I basically now do the same thing for my shadow map texture! From my shader:

private static int location_shadowMapSampler;
location_shadowMapSampler = super.getUniformLocation("shadowMap");

From my render function:

textureLightShader.loadShadowMap(5);

From my fragment shader:

uniform sampler2D shadowMap;

That way, my fragment shader actually used the shadow map instead of my box texture.

Still I do not have shadow maps working correctly. So if you have further issues getting it to work I would like to ask you to contact me. Maybe I have the same problems, maybe I have solutions and maybe you have solutions for me :)

\$\endgroup\$
  • \$\begingroup\$ Thanks for your reply, ill let you know if i manage to make it work \$\endgroup\$ – Dominic Sep 14 '16 at 22:54
  • \$\begingroup\$ If it did, Dominic, could you set my answer as a correct answer please? \$\endgroup\$ – Djindjidj Sep 27 '16 at 6:47
  • \$\begingroup\$ It solved the problem! Thansk a lot! \$\endgroup\$ – Dominic Sep 30 '16 at 0:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.