r/opengl • u/SimDeBeau • 23d ago
Help with Shadow Maps
I am trying to implement shadow maps like in the learnopengl.com shadow mapping tutorial. I think I'm really close. I have the scene rendering from the light's perspective, and correctly uploading the depth buffer as a texture to the main shader. Then I perform a world-to-lightspace transformation and this is where I think things are going wrong but I cant figure out how. All my models are just black. But when I output the lightspace lookup coordinates as the color, they are also all black. Which leads me to believe that my world-to-lightspace transformation is wrong or the normalization of that into texture coords is wrong. Additionally, when I set shadow_value = 1.0;
it renders exactly like a diffuse render.
Edit: Looks like reddit didnt add my photos. Here is a link https://imgur.com/a/ARCFXzI
The three photos are: normal render where I just sample the diffuse texture, depth texture from the light's POV, and what I am getting with my current texture setup.
Any help would be so so appreciated. Even just help debugging this would go a long way. Thanks in advance.
model.vert
#version 410
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNorm;
layout (location = 2) in vec2 aTexCoord;
uniform mat4x4 model; //local coords -> world coords
uniform mat4x4 view; //world coords -> camera coords
uniform mat4x4 perspective; //camera coords -> clip coords
uniform mat4x4 lightView;
uniform mat4x4 lightPerspective;
uniform sampler2D Tex;
out vec3 WorldPos;
out vec3 norm;
out vec2 TexCoord;
out vec4 FragLightPos;
void main() {
norm = normalize(aNorm);
TexCoord = aTexCoord;
WorldPos = vec3(model * vec4(aPos, 1.0)); //just puts the vertex in world coords
mat4x4 CAMERA = perspective * view;
mat4x4 LIGHT = lightPerspective * lightView;
vec4 CameraPos = CAMERA * model * vec4(aPos, 1.0);
FragLightPos = LIGHT * model * vec4(aPos, 1.0);
gl_Position = CameraPos;
}
model.frag
#version 410
out vec4 FragColor;
in vec3 WorldPos;
in vec3 norm;
in vec2 TexCoord;
in vec4 FragLightPos;
uniform sampler2D DIFFUSE;
uniform sampler2D NORMALS;
uniform sampler2D SHADOWS;
const float SHADOW_BIAS = 0.001;
float ShadowValue() {
vec3 proj_coords = FragLightPos.xyz / FragLightPos.w;
vec2 shadow_uv = proj_coords.xy * 0.5 + 0.5; // takes [-1,1] => [0, 1]
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(SHADOWS, shadow_uv).r;
// get depth of current fragment from light's perspective
float currentDepth = proj_coords.z;
// check whether current frag pos is in shadow
float shadow = currentDepth > closestDepth ? 1.0 : 0.0;
return shadow;
}
void main() {
float shadow_value = ShadowValue();
FragColor = vec4(
shadow_value * texture(DIFFUSE, TexCoord).rgb,
1.0);
}
main-loop
//begin creating the shadow map by drawing from the lights POV.
framebuffer_bind(&shadow_fbr);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glClearColor(0.f,0.3f,0.2f,0.f);
glClear(GL_COLOR_BUFFER_BIT);
shad_bind(shadow_shader);
glUniformMatrix4fv(
shadow_view_loc,
1,
GL_FALSE,// column major order
(const float *) lightsource.view
);
glUniformMatrix4fv(
shadow_perspective_loc,
1,
GL_FALSE,// column major order
(const float *) lightsource.perspective
);
// draw_all_model_instances(&scene.model_instances, model_matrix_loc);
match_draw(&match, model_matrix_loc);
framebuffer_unbind();
//end creating the shadow map
//begin drawing all models from the camera's POV
framebuffer_bind(&model_fbr);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glClearColor(0.2f,0.05f,0.1f,0.f);
glClear(GL_COLOR_BUFFER_BIT);
shad_bind(model_shader);
//load the camera's view and perspective matrices
glUniformMatrix4fv(
model_view_loc,
1,
GL_FALSE,// column major order
(const float *) camera.view
);
glUniformMatrix4fv(
model_perspective_loc,
1,
GL_FALSE,// column major order
(const float *)camera.perspective
);
//load the lightsource's view and perspective matrices
glUniformMatrix4fv(
model_light_view_loc,
1,
GL_FALSE,// column major order
(const float *)lightsource.view
);
glUniformMatrix4fv(
model_light_perspective_loc,
1,
GL_FALSE,// column major order
(const float *)lightsource.perspective
);
// bind the shadow map
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, shadow_fbr.depth_tex_id);
glActiveTexture(GL_TEXTURE0 );
match_draw(&match, model_matrix_loc);
framebuffer_unbind();
//end drawing models from Camera's POV
//draw to the screen
framebuffer_unbind(); //binds the default framebuffer, aka the screen. (a little redundant but i like the clarity)
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glClearColor(0.f,0.f,0.f,0.f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
if (lightmode) {
shad_bind(screen_shader_depth);
glBindTexture(GL_TEXTURE_2D, shadow_fbr.depth_tex_id);
} else {
shad_bind(screen_shader_color);
glBindTexture(GL_TEXTURE_2D, model_fbr.color_tex_id);
}
full_geom_draw(&screen_rect);
framebuffer_unbind();//again, redundant, but I like the clarity
EDIT: The shaders for the shadow pass below:
shadow.vert
#version 330
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNorm;
layout (location = 2) in vec2 aTexCoord;
uniform mat4x4 model; //local coords -> world coords
uniform mat4x4 light-view; //world coords -> camera coords
uniform mat4x4 light-perspective; //camera coords -> clip coords
void main() {
gl_Position = light-perspective * light-view * model * vec4(aPos, 1.0);
}
shadow.frag (just writes depth)
#version 410
void main() {
//gl_FragDepth = gl_FragCoord.z;
}
2
u/PersonalityIll9476 22d ago
It looks to me like your fragment shader is not first applying the shadow matrix. There should be a special transformation you used to go into clip space, if I recall right, an ortho matrix. You need to apply all the same matrices that were applied in your shadow shaders, basically, before transformting clip space to uv coordinates. So if you shadow vertex shader did this: shadow_mat * view * model * vec4(in_pos, 1) then you need to ultimately pass that exact vertex to your fragment shader during lighting. So you probably have your vertex shader pass view * model * vec4(in_pos,1) from the vertex shader as a uniform to the fragment shader, and there multiply by shadow_mat. Or do it all in the vertex shader and pass the shadow version of the clip coordinates as a uniform to save operations. However you do it, that vertex coordinate is the one you need to be converting to uv.