Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug?] SpotLight::generate_shadow_map() doesn't cast shadows? #503

Closed
javalsai opened this issue Oct 27, 2024 · 4 comments
Closed

[bug?] SpotLight::generate_shadow_map() doesn't cast shadows? #503

javalsai opened this issue Oct 27, 2024 · 4 comments

Comments

@javalsai
Copy link

To be fair I'm not really familiar with the library, but to my understanding, the Light objects that implement the function generate_shadow_map should cast shadows on things when provided with the appropriate Meshs of the scene. And this is what happens at least with DirectionalLight, but doesn't work at all with SpotLight.

I was able to make this relatively simple demo for the issue:

image

demo code
use three_d::*;

fn main() {
    let window = Window::new(WindowSettings {
        title: "bug".to_string(),
        max_size: Some((1200, 700)),
        ..Default::default()
    })
    .unwrap();
    let ctx = window.gl();

    let mut camera = Camera::new_perspective(
        window.viewport(),
        vec3(5.0, 2.0, 2.5),
        vec3(0.0, 0.0, -0.5),
        vec3(0.0, 1.0, 0.0),
        degrees(45.0),
        0.1,
        1000.0,
    );
    let mut oc = OrbitControl::new(*camera.target(), 1.0, 10000.0);

    let s1_mesh = CpuMesh::sphere(16);
    let s2_mesh = CpuMesh::sphere(16);

    let mut gm1 = Gm::new(
        Mesh::new(&ctx, &s1_mesh),
        PhysicalMaterial::new_opaque(
            &ctx,
            &CpuMaterial {
                albedo: Srgba::RED,
                ..Default::default()
            }
        ),
    );
    gm1.set_transformation(Mat4::from_translation(vec3(2.0, 0.0, 0.0)));

    let mut gm2 = Gm::new(
        Mesh::new(&ctx, &s2_mesh),
        PhysicalMaterial::new_opaque(
            &ctx,
            &CpuMaterial {
                albedo: Srgba::RED,
                ..Default::default()
            }
        ),
    );
    gm2.set_transformation(Mat4::from_translation(vec3(4.0, 0.0, 0.0)));

    let mut light = SpotLight::new(
        &ctx,
        10.0,
        Srgba::WHITE,
        &Vector3::zero(),
        &vec3(1.0, 0.0, 0.0),
        degrees(179.9999),
        Attenuation::default(),
    );
    light.generate_shadow_map(1024, &[&gm1.geometry, &gm2.geometry]);

    let mut dlight = DirectionalLight::new(
        &ctx,
        1.0,
        Srgba::WHITE,
        &vec3(-1.0, 0.0, 0.0)
    );
    dlight.generate_shadow_map(1024, &[&gm1.geometry, &gm2.geometry]);

    window.render_loop(move |mut frame_input| {
        camera.set_viewport(frame_input.viewport);
        oc.handle_events(&mut camera, &mut frame_input.events);

        frame_input
            .screen()
            .clear(ClearState::color_and_depth(42.0 / 255.0, 42.0 / 255.0, 42.0 / 255.0, 1.0, 1.0))
            .render(&camera, gm1.into_iter().chain(&gm2), &[&light, &dlight]);

        FrameOutput::default()
    });
}

I would expect the spotlight to cast a shadow on the right element as it's covered by the left sphere, just like what happens with the directional light from the other side.


Also unrelated, but a few quick thoughts on the shadows thing. They should have a common trait, or implement it in the Light trait, but I don't expect lights like ambient light to have the shadow method. And PointLight should implement shadows too, imo it's just like a spotlight but with a full coverage angle, so there's less variables to mind in the calculation.

@javalsai
Copy link
Author

#461 could be related to this?

@asny
Copy link
Owner

asny commented Nov 22, 2024

degrees(179.9999),

You defined a spotlight with a cutoff at almost 180 degrees, that means the shadow map needs to cover an enormous area and therefore no pixel in the shadow map will actually hit the relatively small sphere. If you change the angle to something more realistic (a spotlight is usually something like a flashlight), then it's working as expected.

Also unrelated, but a few quick thoughts on the shadows thing. They should have a common trait, or implement it in the Light trait, but I don't expect lights like ambient light to have the shadow method.

What is the exact reason why it should be part of a trait? 🤔

And PointLight should implement shadows too, imo it's just like a spotlight but with a full coverage angle, so there's less variables to mind in the calculation.

It's already an issue: #74. However, it's quite expensive for point lights since it requires a shadow map in all directions (a cube map instead of a 2D texture). So it's not used a lot in practice in my experience.

In general, shadow maps are really nice but definitely have their limitations due to performance. Therefore, it's not just plug-and-play, you need to understand the technique before being able to use it effectively.

@asny asny closed this as completed Nov 22, 2024
@javalsai
Copy link
Author

You defined a spotlight with a cutoff at almost 180 degrees, that means the shadow map needs to cover an enormous area and therefore no pixel in the shadow map will actually hit the relatively small sphere. If you change the angle to something more realistic (a spotlight is usually something like a flashlight), then it's working as expected.

Well yes, playing around found the cutoff to be somewhere around 179.72-179.73, high enough for any normal use, I was using such angles to try to get a pointlight kind of light but with shadows, guess I wont.

What is the exact reason why it should be part of a trait?

Its just some shared behavior, I simply ran into an issue in my project where I had to take a generic light that implements shadows, so I ended up making my custom trait for it and implementing it for each light element. I just think it makes sense to make it a trait in the library directly.

In general, shadow maps are really nice but definitely have their limitations due to performance. Therefore, it's not just plug-and-play, you need to understand the technique before being able to use it effectively.

Tbh idk much about shadow maps, I just get the basic idea of how they work and using them to make my project look a little nicer, nothing performance critical. But I think they are a little too complex for me, might look into it to optimize things at some point, but it's definitely not important for what I'm doing.

Thanks for the assistance though!

@asny
Copy link
Owner

asny commented Nov 25, 2024

Well yes, playing around found the cutoff to be somewhere around 179.72-179.73, high enough for any normal use, I was using such angles to try to get a pointlight kind of light but with shadows, guess I wont.

Well you might be able to if you use 6 spot lights with an angle of 90 degrees. That's basically the point light shadow map setup.

Its just some shared behavior, I simply ran into an issue in my project where I had to take a generic light that implements shadows, so I ended up making my custom trait for it and implementing it for each light element. I just think it makes sense to make it a trait in the library directly.

I'll consider it 👍

Thanks for the assistance though!

No problem 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants