PDA

View Full Version : Shadow mapping with moving object



Man2hell
07-06-2013, 04:08 PM
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

Alphaomega86
07-12-2013, 02:53 AM
As i can see, your problem is really simple!

You have to uniform your depth mvp before every single object rendering pass, because the right position of the rendered object
is in the model matrix. So you must calculate the right mvp before rendering the object to get the right mvo matrix.



Matrix mode MODELVIEW
Push matrix
Translate and Rotate... (And do simple matrix calculations...)

Calculate the new MVP matrix //Very important!
Uniform the mvp matrix as depthMVP in your case //Very important!

Render the object

Pop matrix


I used the same tutorial for shadow mapping as you and had exactly the same problem ^^


-- Daniel