1
\$\begingroup\$

I have looked far and wide for this and have not found any issue like this, so far. Basically, when my light is at a certain angle my shadows seem to be correctly positioned and scaled, yet if I rotate the light about itself, both of these things change.

It should be about that size and position but it is rotated incorrectly here.

Seemingly correct shadow on teapot

Completely incorrect

In this image, it is completely incorrect.

Now for my code.

1st, the code run on the CPU concerning the shadow map:

In the load, I create my shadow map based on the width and height of the screen.

shadow = shadow_map(renderer::get_screen_width(), renderer::get_screen_height());

And I set up my shaders, no need to show it, that bit's working. In the update method I give my shadow map the properties of the light used to create the shadow like so:

shadow.light_dir = normalize(spot.get_direction());
shadow.light_position = spot.get_position();

Then in my render method I do this:

renderer::set_render_target(shadow);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
renderer::bind(shadow_eff);
for (auto &e : meshes)
{
        auto m = e.second;
        auto M = m.get_transform().get_transform_matrix();
        auto V = shadow.get_view();
        //glm::lookAt(light_position, light_position + light_dir, glm::vec3(0.0f, 1.0f, 0.0f));
        auto P = cam.get_projection();
        auto MVP = biasMatrix * (P * V * M);
  glUniformMatrix4fv(shadow_eff.get_uniform_location("MVP"),1,GL_FALSE,value_ptr(MVP));
renderer::render(m);
}

glCullFace(GL_BACK);
//set render target back to screen
renderer::set_render_target();

//...

auto lM = m.get_transform().get_transform_matrix();
        auto lV = shadow.get_view();
        auto lP = cam.get_projection();
        auto lMVP = (lP * lV * lM);

        glUniformMatrix4fv(main_eff.get_uniform_location("lightMVP"), 1, GL_FALSE, value_ptr(lMVP));

//bind the shadow map texture
renderer::bind(shadow.buffer->get_depth(), 1);
        glUniform1i(main_eff.get_uniform_location("shadow_map"), 1);

It is worth noting that my bias matrix looks like this:

0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0

Now onto the shader code:

void main()
{
    // **********************
    // Calculate shade factor
    // **********************
    float shade = calculate_shadow(shadow_map, light_space_pos);
    // ************************
    // Calculate view direction
    // ************************
    vec3 view_dir = normalize(eye_pos - position);
    // **************
    // Sample texture
    // **************
    vec4 tex_colour = texture(tex, tex_coord);
    // ********************
    // Calculate spot light
    // ********************
    colour = calculate_spot(spot, mat, position, normal, view_dir, tex_colour);
    // *********************
    // Scale colour by shade
    // *********************
    colour *= vec4(shade, shade, shade, 1.0);

    colour.a = 1.0;
}

Where calculate_shadow(...) looks like this:

float calculate_shadow(in sampler2D shadow_map, in vec4 light_space_pos)
{
    vec3 light_dir = normalize(spot.position - position);

    vec3 proj_coords = light_space_pos.xyz / light_space_pos.w;

    proj_coords = proj_coords * 0.5 + 0.5;

    float closest_depth = texture(shadow_map, proj_coords.xy).r;
    float current_depth = proj_coords.z;

    float bias = max(0.05 * (1.0 - dot(normal, light_dir)), 0.005);

    float shadow = current_depth - bias > closest_depth ? 0.0 : 1.0;
    return shadow;
}

and the most important part of the shadow vertex shader is:

vertex_light = (lightMVP * vec4(vertex_position, 1.0));

I've been thinking about this on and off for weeks, any help is appreciated. In my experience it's usually something small that I've got wrong. Thanks in advance.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.