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

[Merged by Bors] - Take DirectionalLight's GlobalTransform into account when calculating shadow map volume (not just direction) #6384

Closed
wants to merge 10 commits into from
17 changes: 8 additions & 9 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use bevy_ecs::{
prelude::*,
system::{lifetimeless::*, SystemParamItem},
};
use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles};
use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles};
use bevy_render::{
camera::{Camera, CameraProjection},
color::Color,
Expand Down Expand Up @@ -66,7 +66,7 @@ pub struct ExtractedPointLight {
pub struct ExtractedDirectionalLight {
color: Color,
illuminance: f32,
direction: Vec3,
transform: GlobalTransform,
projection: Mat4,
shadows_enabled: bool,
shadow_depth_bias: f32,
Expand Down Expand Up @@ -560,15 +560,15 @@ pub fn extract_lights(
directional_light.shadow_projection.top
- directional_light.shadow_projection.bottom,
);
let directional_light_texel_size =
largest_dimension / directional_light_shadow_map.size as f32;
let directional_light_texel_size = transform.radius_vec3a(Vec3A::ONE) * largest_dimension
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the largest dimension be calculated after the transform?

let directional_light_texel_size = transform.radius_vec3a(Vec3A::new(
  directional_light.shadow_projection.right - directional_light.shadow_projection.left,
  directional_light.shadow_projection.top - directional_light.shadow_projection.bottom,
  0.
)).abs().max_element() / directional_light_shadow_map.size as f32;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch. Updated to use this approach, should give more accurate results.

/ directional_light_shadow_map.size as f32;
// TODO: As above
let render_visible_entities = visible_entities.clone();
commands.get_or_spawn(entity).insert((
ExtractedDirectionalLight {
color: directional_light.color,
illuminance: directional_light.illuminance,
direction: transform.forward(),
transform: *transform,
projection: directional_light.shadow_projection.get_projection_matrix(),
shadows_enabled: directional_light.shadows_enabled,
shadow_depth_bias: directional_light.shadow_depth_bias,
Expand Down Expand Up @@ -1103,7 +1103,7 @@ pub fn prepare_lights(
.take(MAX_DIRECTIONAL_LIGHTS)
{
// direction is negated to be ready for N.L
let dir_to_light = -light.direction;
let dir_to_light = -light.transform.forward();

// convert from illuminance (lux) to candelas
//
Expand All @@ -1118,9 +1118,8 @@ pub fn prepare_lights(
let exposure = 1.0 / (f32::powf(2.0, ev100) * 1.2);
let intensity = light.illuminance * exposure;

// NOTE: A directional light seems to have to have an eye position on the line along the direction of the light
// through the world origin. I (Rob Swain) do not yet understand why it cannot be translated away from this.
let view = Mat4::look_at_rh(Vec3::ZERO, light.direction, Vec3::Y);
// NOTE: For the purpose of rendering shadow maps, we apply the directional light's transform to an orthographic camera
let view = light.transform.compute_matrix().inverse();
// NOTE: This orthographic projection defines the volume within which shadows from a directional light can be cast
let projection = light.projection;

Expand Down