Reputation: 3417
I can't get shadow mapping to work in my application. I try to render a quad bike and view its shadow on a floor beneath it. Here's some of my code. Texture creation:
// Create a depth texture
glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);
// Allocate storage for the texture data
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32 ,1600, 900, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
// Set the default filtering modes
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set up wrapping modes
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
// Create FBO to render depth into
glGenFramebuffers(1, &depth_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
// Attach the depth texture to it
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
depth_texture, 0);
// Disable color rendering as there are no color attachments
glDrawBuffer(GL_NONE);
//check fbo status
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(result != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("shadow mapping framebuffer error");
//bind default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
render to depth texture:
progShadow.Use();
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
glClear(GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowProjection = glm::frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 100.0f);
glm::mat4 shadowView = glm::lookAt(light.position, glm::vec3(0,0,0), glm::vec3(0,1,0));
glm::mat4 shadowModel(1);
if(g_rotate)
shadowModel = glm::rotate((float)clock() / (float)CLOCKS_PER_SEC, glm::vec3(0,1,0));
glm::mat4 shadowMVP = shadowProjection * shadowView * shadowModel;
progShadow.SetUniform("MVPMatrix", shadowMVP);
quadBike.Draw();
I also use a "test" shader program that renders my depth texture. Here's what it looks like.
So I guess I'm good until now. Now I render the scene normally.
glBindTexture(GL_TEXTURE_2D, depth_texture);
prog.Use();//main program
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowBias = glm::mat4(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);
glm::mat4 ShadowBiasMVP = shadowBias * shadowMVP;
prog.SetUniform("ShadowBiasMVP", ShadowBiasMVP);
//draw quadBike and floor
...
Relevant parts of my vertex shader:
#version 430
...
out vec4 shadowCoord;
void main()
{
gl_Position = ProjectionMatrix * CameraMatrix * ModelMatrix * vec4(vertex, 1.0);
shadowCoord = ShadowBiasMVP * vec4(vertex, 1.0);
...
}
Relevant parts of my fragment shader:
#version 430
...
uniform sampler2D shadowMap;
in vec4 shadowCoord;
void main()
{
...
float visibility = 1.0;
if ( texture(shadowMap, shadowCoord.xy).z < shadowCoord.z)
visibility = 0.0;
...
}
Now the problem is that I get a scene that is fully dark as if it was all covered by shadow. Only when the light is really close to the quad bike, it renders it normally. (the depth texture is visible on the right side because it's rendered with a different program. I use it for testing)
What am I doing wrong?
Upvotes: 3
Views: 2910
Reputation: 2455
You should read a grayscale depthtexture at the first component.
texture(shadowMap, shadowCoord.xy).r
or
texture(shadowMap, shadowCoord.xy).x
The Shadow Coordinates should be dehomogenized (divided by w) after interpolation.
-> in fragment shader: shadowPos = shadowPos/shadowPos.w;
If no other techniques like polygon offset is used you need to substract a bias from the shadow depth value to prevent self shadowing.
Here is an example function to calculate shadows in fragment shader. Note: It is part of a deferred renderer, that is why matrix multiplication is done in the fragment shader.
float calculateShadow(vec3 position){
vec4 shadowPos = depthBiasMV * vec4(position,1);
shadowPos = shadowPos/shadowPos.w;
float bias = 0.0012;
float visibility = 1.0f;
if ((shadowPos.x < 0 || shadowPos.x > 1 || shadowPos.y < 0 || shadowPos.y > 1 || shadowPos.z < 0 || shadowPos.z > 1)){
visibility = 1.0f;
}else{
float shadowDepth = texture(depthTex, shadowPos.xy).r;
if(shadowDepth<shadowPos.z-bias)
visibility = 0.0f;
}
return visibility;
}
Upvotes: 2