From da0c5944899f8253fe5a4a5e89dd8dfedc93138e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9l=C3=A8ne=20Amanita?= Date: Fri, 21 Jul 2023 14:57:27 +0100 Subject: [PATCH 1/2] Make DirectionalLight cascade computation generic over CameraProjection --- crates/bevy_pbr/src/lib.rs | 8 ++- crates/bevy_pbr/src/light.rs | 61 +++++---------------- crates/bevy_render/src/camera/projection.rs | 43 ++++++++++++++- 3 files changed, 63 insertions(+), 49 deletions(-) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 2460a0e0f67df..b10208af65107 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -58,7 +58,7 @@ use bevy_reflect::TypeUuid; use bevy_render::{ camera::CameraUpdateSystem, extract_resource::ExtractResourcePlugin, - prelude::Color, + prelude::{Color, Projection}, render_graph::RenderGraph, render_phase::sort_phase_system, render_resource::Shader, @@ -216,7 +216,11 @@ impl Plugin for PbrPlugin { .after(TransformSystem::TransformPropagate) .after(VisibilitySystems::CheckVisibility) .after(CameraUpdateSystem), - update_directional_light_cascades + ( + clear_directional_light_cascades, + build_directional_light_cascades::, + ) + .chain() .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) .after(TransformSystem::TransformPropagate) .after(CameraUpdateSystem), diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index 3e8c0d45177e6..ba0ace800ca86 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -1,13 +1,12 @@ use std::collections::HashSet; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, Rect, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_math::{Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_reflect::prelude::*; use bevy_render::{ - camera::Camera, + camera::{Camera, CameraProjection}, color::Color, extract_resource::ExtractResource, - prelude::Projection, primitives::{Aabb, CascadesFrusta, CubemapFrusta, Frustum, HalfSpace, Sphere}, render_resource::BufferBindingType, renderer::RenderDevice, @@ -401,9 +400,18 @@ pub struct Cascade { pub(crate) texel_size: f32, } -pub fn update_directional_light_cascades( +pub fn clear_directional_light_cascades(mut lights: Query<(&DirectionalLight, &mut Cascades)>) { + for (directional_light, mut cascades) in lights.iter_mut() { + if !directional_light.shadows_enabled { + continue; + } + cascades.cascades.clear(); + } +} + +pub fn build_directional_light_cascades( directional_light_shadow_map: Res, - views: Query<(Entity, &GlobalTransform, &Projection, &Camera)>, + views: Query<(Entity, &GlobalTransform, &P, &Camera)>, mut lights: Query<( &GlobalTransform, &DirectionalLight, @@ -453,17 +461,8 @@ pub fn update_directional_light_cascades( }; let z_far = -far_bound; - let corners = match projection { - Projection::Perspective(projection) => frustum_corners( - projection.aspect_ratio, - (projection.fov / 2.).tan(), - z_near, - z_far, - ), - Projection::Orthographic(projection) => { - frustum_corners_ortho(projection.area, z_near, z_far) - } - }; + let corners = projection.get_frustum_corners(z_near, z_far); + calculate_cascade( corners, directional_light_shadow_map.size as f32, @@ -477,36 +476,6 @@ pub fn update_directional_light_cascades( } } -fn frustum_corners_ortho(area: Rect, z_near: f32, z_far: f32) -> [Vec3A; 8] { - // NOTE: These vertices are in the specific order required by [`calculate_cascade`]. - [ - Vec3A::new(area.max.x, area.min.y, z_near), // bottom right - Vec3A::new(area.max.x, area.max.y, z_near), // top right - Vec3A::new(area.min.x, area.max.y, z_near), // top left - Vec3A::new(area.min.x, area.min.y, z_near), // bottom left - Vec3A::new(area.max.x, area.min.y, z_far), // bottom right - Vec3A::new(area.max.x, area.max.y, z_far), // top right - Vec3A::new(area.min.x, area.max.y, z_far), // top left - Vec3A::new(area.min.x, area.min.y, z_far), // bottom left - ] -} - -fn frustum_corners(aspect_ratio: f32, tan_half_fov: f32, z_near: f32, z_far: f32) -> [Vec3A; 8] { - let a = z_near.abs() * tan_half_fov; - let b = z_far.abs() * tan_half_fov; - // NOTE: These vertices are in the specific order required by [`calculate_cascade`]. - [ - Vec3A::new(a * aspect_ratio, -a, z_near), // bottom right - Vec3A::new(a * aspect_ratio, a, z_near), // top right - Vec3A::new(-a * aspect_ratio, a, z_near), // top left - Vec3A::new(-a * aspect_ratio, -a, z_near), // bottom left - Vec3A::new(b * aspect_ratio, -b, z_far), // bottom right - Vec3A::new(b * aspect_ratio, b, z_far), // top right - Vec3A::new(-b * aspect_ratio, b, z_far), // top left - Vec3A::new(-b * aspect_ratio, -b, z_far), // bottom left - ] -} - /// Returns a [`Cascade`] for the frustum defined by `frustum_corners`. /// The corner vertices should be specified in the following order: /// first the bottom right, top right, top left, bottom left for the near plane, then similar for the far plane. diff --git a/crates/bevy_render/src/camera/projection.rs b/crates/bevy_render/src/camera/projection.rs index 73e3d6a431f65..d857831b8a390 100644 --- a/crates/bevy_render/src/camera/projection.rs +++ b/crates/bevy_render/src/camera/projection.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use bevy_app::{App, Plugin, PostStartup, PostUpdate}; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; -use bevy_math::{Mat4, Rect, Vec2}; +use bevy_math::{Mat4, Rect, Vec2, Vec3A}; use bevy_reflect::{ std_traits::ReflectDefault, GetTypeRegistration, Reflect, ReflectDeserialize, ReflectSerialize, }; @@ -58,6 +58,7 @@ pub trait CameraProjection { fn get_projection_matrix(&self) -> Mat4; fn update(&mut self, width: f32, height: f32); fn far(&self) -> f32; + fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8]; } /// A configurable [`CameraProjection`] that can select its projection type at runtime. @@ -101,6 +102,13 @@ impl CameraProjection for Projection { Projection::Orthographic(projection) => projection.far(), } } + + fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8] { + match self { + Projection::Perspective(projection) => projection.get_frustum_corners(z_near, z_far), + Projection::Orthographic(projection) => projection.get_frustum_corners(z_near, z_far), + } + } } impl Default for Projection { @@ -153,6 +161,24 @@ impl CameraProjection for PerspectiveProjection { fn far(&self) -> f32 { self.far } + + fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8] { + let tan_half_fov = (self.fov / 2.).tan(); + let a = z_near.abs() * tan_half_fov; + let b = z_far.abs() * tan_half_fov; + let aspect_ratio = self.aspect_ratio; + // NOTE: These vertices are in the specific order required by [`calculate_cascade`]. + [ + Vec3A::new(a * aspect_ratio, -a, z_near), // bottom right + Vec3A::new(a * aspect_ratio, a, z_near), // top right + Vec3A::new(-a * aspect_ratio, a, z_near), // top left + Vec3A::new(-a * aspect_ratio, -a, z_near), // bottom left + Vec3A::new(b * aspect_ratio, -b, z_far), // bottom right + Vec3A::new(b * aspect_ratio, b, z_far), // top right + Vec3A::new(-b * aspect_ratio, b, z_far), // top left + Vec3A::new(-b * aspect_ratio, -b, z_far), // bottom left + ] + } } impl Default for PerspectiveProjection { @@ -309,6 +335,21 @@ impl CameraProjection for OrthographicProjection { fn far(&self) -> f32 { self.far } + + fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8] { + let area = self.area; + // NOTE: These vertices are in the specific order required by [`calculate_cascade`]. + [ + Vec3A::new(area.max.x, area.min.y, z_near), // bottom right + Vec3A::new(area.max.x, area.max.y, z_near), // top right + Vec3A::new(area.min.x, area.max.y, z_near), // top left + Vec3A::new(area.min.x, area.min.y, z_near), // bottom left + Vec3A::new(area.max.x, area.min.y, z_far), // bottom right + Vec3A::new(area.max.x, area.max.y, z_far), // top right + Vec3A::new(area.min.x, area.max.y, z_far), // top left + Vec3A::new(area.min.x, area.min.y, z_far), // bottom left + ] + } } impl Default for OrthographicProjection { From 433358f958f4167d2bc11164a65559995302d043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9l=C3=A8ne=20Amanita?= Date: Fri, 21 Jul 2023 15:15:38 +0100 Subject: [PATCH 2/2] Forgot to remove the clear in build --- crates/bevy_pbr/src/light.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index ba0ace800ca86..da046d83663e8 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -444,7 +444,6 @@ pub fn build_directional_light_cascades( let light_to_world = Mat4::from_quat(transform.compute_transform().rotation); let light_to_world_inverse = light_to_world.inverse(); - cascades.cascades.clear(); for (view_entity, projection, view_to_world) in views.iter().copied() { let camera_to_light_view = light_to_world_inverse * view_to_world; let view_cascades = cascades_config