Hi community,
I’m trying to implement shadow mapping in a small project. The scenario is as follow:
I have an object which is moving on a ground. My camera is above and behind this object which leads to a bird’s eye perspective. Now i want the object to throw a real-time shadow on the ground-surface.
I created a FBO which should render my shadowmap, call it shadowMapFBO. When i try to render to my shadowMapFBO I have to move my camera to the light’s position. For that I’m trying to use a glm::lookAt matrix (see below).
After that I do my rendering and active my screen FBO (FBO 0). During my debugging I tried many other “boxing configuration” for the depthProjectionMatrix, but I could’t fix it.
Note: As you can see I’m using something like point light, but since actually my object is just moving in 1 direction (minus z-axis) I didn’t implement a shadow cubemap.
renderShadowMap.cc
void renderShadowMap ( void ) {
// First render pass
shadowMapFBO->bind();
shadowMapFBO->clearDepthBuffer(); //glClear(GL_DEPTH_BUFFER_BIT);
glViewport( 0, 0, shadowMapResolution.x, shadowMapResolution.y );
createShadowMapShader->use();
glm::vec3 position = glm::vec3(objectPosition);
glm::vec3 lightPosition = glm::vec4(0, 5, 0);
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-10,10,-10,10,-10,100);
glm::mat4 depthViewMatrix = glm::lookAt( glm::vec3(lightPosition) , objectPosition , glm::vec3(0,1,0) );
glm::mat4 depthModelMatrix = glm::mat4(1.0);
glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;
glm::mat4 scaleBiasMatrix(
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
);
shadowMatrix = scaleBiasMatrix * depthMVP;
shadowShader->setUniform( "depthMVP", depthMVP );
shadowShader->setUniform( "shadowMatrix", shadowMatrix );
[ ... render objects ... ]
}
Vertex shader for creating the shadow map
#version 330 core
// Input
in vec3 aPosition;
// Matrices
uniform mat4 depthMVP;
void main(){
gl_Position = depthMVP * vec4( aPosition, 1.0 );
}
Fragment shader for creating the shadow map
#version 330 core
// Output data
out float depthValues;
void main(){
// Not really needed, OpenGL does it anyway
depthValues = gl_FragCoord.z;
}
After that i hand over the shadow map to the shaders. Now here is how I’m trying to use the shadow map in the fragment shader:
Vertex shader when using the shadow map
#version 330
// Matrices
uniform mat4 uModelMatrix;
uniform mat4 shadowMatrix;
uniform mat4 uMVPMatrix;
in vec3 aPosition;
out vec4 objPos;
out vec4 shadowCoord;
void main()
{
gl_Position = uMVPMatrix * vec4(aPosition, 1.0);
objPos = uModelMatrix * vec4(aPosition, 1.0);
shadowCoord = shadowMatrix * vec4(aPosition, 1.0);
}
Fragment shader when using the shadow map
#version 330
// Light Data
uniform vec4 uLightPos[6];
uniform vec4 uLightAmb[6];
uniform vec4 uLightDif[6];
uniform vec4 uLightSpec[6];
// Informations
uniform int shaderLevel;
uniform float portalRadius;
uniform vec3 uEyePos;
uniform vec3 portalPosition;
// Samplers
uniform sampler2D shadowMapTexture;
//uniform sampler2DShadow shadowMapTexture;
in vec4 objPos;
in vec4 shadowCoord;
out vec4 oColor;
vec3 shadowMapping(){
float attenuation = computeAttenuation(objPos, (uLightPos[0]), 1.0, 0.0, 0.0);
vec3 ambientLight = computeAmbience(uLightAmb[0]);
vec3 fNormal = computeNormals(true);
vec3 fLightD = computeLightDirection();
vec3 diffuseLight = computeDiffuseLight(fNormal, fLightD);
vec3 specularLight = computeSpecularLight(fNormal, fLightD);
float bias = 0.005;
float visibility = 1.0;
//visibility = textureProj(shadowMapTexture, shadowCoord);
/*
if ( textureProj( shadowMapTexture, shadowCoord.xy ).z < shadowCoord.z-bias) { // < (shadowCoord.z-bias)/shadowCoord.w
visibility = 0.5;
}
float visibility = texture( shadowMapTexture, shadowCoord.xy ).z;
visibility = texture( shadowMapTexture, vec3(shadowCoord.xy, (shadowCoord.z)/shadowCoord.w) );
//*/
if ( texture( shadowMapTexture, shadowCoord.xy ).z < shadowCoord.z){
visibility = 0.5;
}
return ((ambientLight + visibility*(diffuseLight + specularLight)) * attenuation);
}
void main(){
oColor = vec4(shadowMapping(), 1.0);
}
Actually I’m completely lost on the debugging. I tried to visualize the shadow map using 2 triangles, but it does not work as expected (I commented the texture compare mode and func out). The code for that lookis like this:
//Initialisation
// The quad's FBO. Used only for visualizing the shadowmap.
glGenVertexArrays(1, &quad_VertexArrayID);
glBindVertexArray(quad_VertexArrayID);
static const GLfloat g_quad_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
//Rendering pass
glEnableVertexAttribArray(12);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glVertexAttribPointer(
12, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
// You have to disable GL_COMPARE_R_TO_TEXTURE above in order to see anything !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
glDisableVertexAttribArray(12);
//Vertex shader
#version 330 core
// Input
in vec3 aPosition;
uniform mat4 uModelMatrix;
// Output
out vec2 uv;
void main(){
gl_Position = vec4(aPosition , 1.0);
uv = ( aPosition.xy + vec2(1.0 , 1.0) ) / 2.0;
}
//Fragment shader
#version 330 core
// Ouput
out vec4 oColor;
uniform sampler2D shadowMapTexture;
in vec2 uv;
void main(){
oColor = texture2D(shadowMapTexture, uv);
//oColor = vec4(1.0,0,0,1.0);
}
For the sake of completeness: I created my FBO as follow :
//Create unset depth texture from where we render shadow depth into FBO
glGenTextures(1, &shadowMapTexture);
glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
//Alloc storage for texture data -> later filled with depth values
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, shadowMapResolution.x, shadowMapResolution.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
//Choose filtering mode
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//Choose wrapping mode
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Choose depth comparison mode in order to leverage shadow textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
//Create FBO and RBO for depth rendering
glGenFramebuffers(1, &shadowMapFBO);
glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO);
//Attach depth texture to it
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowMapTexture, 0);
//Disable color rendering <- no colors to attach
glDrawBuffer(GL_NONE);
HOPEFULLY there is someone who can help us with our problem and tell us what we did wrong!
Thank you in anticipation!
Sincerely M2h