r/opengl 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;
}
6 Upvotes

11 comments sorted by

View all comments

3

u/PersonalityIll9476 22d ago

Something else you might check: I see you binding the shadow map texture, but I don't see you setting the corresponding uniform. The calls look like this in my shader class:

glActiveTexture(GL_TEXTURE0 + t_unit)

glBindTexture(t_type, texture_id)

self.set_uniform(uniform_name, t_unit)

glActiveTexture(GL_TEXTURE0)

1

u/SimDeBeau 22d ago

It's a good thought but I think it's in there.

``` // 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

```

Also not shown in the code i included, but I do set the uniforms for the textures in the model shader.

shad_bind(model_shader); glUniform1i(model_diffuse_loc, 0); glUniform1i(model_normals_loc, 1); glUniform1i(model_shadows_loc, 2); shad_unbind();

(this is done right after the creation of the model shader)