Skip to content

Commit 623e7a6

Browse files
corehmockersf
andcommitted
Do not re-check visibility or re-render shadow maps for point and spot lights for each view (#15156)
# Objective _If I understand it correctly_, we were checking mesh visibility, as well as re-rendering point and spot light shadow maps for each view. This makes it so that M views and N lights produce M x N complexity. This PR aims to fix that, as well as introduce a stress test for this specific scenario. ## Solution - Keep track of what lights have already had mesh visibility calculated and do not calculate it again; - Reuse shadow depth textures and attachments across all views, and only render shadow maps for the _first_ time a light is encountered on a view; - Directional lights remain unaltered, since their shadow map cascades are view-dependent; - Add a new `many_cameras_lights` stress test example to verify the solution ## Showcase 110% speed up on the stress test 83% reduction of memory usage in stress test ### Before (5.35 FPS on stress test) <img width="1392" alt="Screenshot 2024-09-11 at 12 25 57" src="https://github.com/user-attachments/assets/136b0785-e9a4-44df-9a22-f99cc465e126"> ### After (11.34 FPS on stress test) <img width="1392" alt="Screenshot 2024-09-11 at 12 24 35" src="https://github.com/user-attachments/assets/b8dd858f-5e19-467f-8344-2b46ca039630"> ## Testing - Did you test these changes? If so, how? - On my game project where I have two cameras, and many shadow casting lights I managed to get pretty much double the FPS. - Also included a stress test, see the comparison above - Are there any parts that need more testing? - Yes, I would like help verifying that this fix is indeed correct, and that we were really re-rendering the shadow maps by mistake and it's indeed okay to not do that - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Run the `many_cameras_lights` example - On the `main` branch, cherry pick the commit with the example (`git cherry-pick --no-commit 1ed4ace`) and run it - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - macOS --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
1 parent 7284d14 commit 623e7a6

File tree

6 files changed

+297
-131
lines changed

6 files changed

+297
-131
lines changed

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2708,6 +2708,17 @@ description = "Test rendering of many UI elements"
27082708
category = "Stress Tests"
27092709
wasm = true
27102710

2711+
[[example]]
2712+
name = "many_cameras_lights"
2713+
path = "examples/stress_tests/many_cameras_lights.rs"
2714+
doc-scrape-examples = true
2715+
2716+
[package.metadata.example.many_cameras_lights]
2717+
name = "Many Cameras & Lights"
2718+
description = "Test rendering of many cameras and lights"
2719+
category = "Stress Tests"
2720+
wasm = true
2721+
27112722
[[example]]
27122723
name = "many_cubes"
27132724
path = "examples/stress_tests/many_cubes.rs"

crates/bevy_pbr/src/light/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use core::ops::DerefMut;
22

3-
use bevy_ecs::{entity::EntityHashMap, prelude::*};
3+
use bevy_ecs::{
4+
entity::{EntityHashMap, EntityHashSet},
5+
prelude::*,
6+
};
47
use bevy_math::{ops, Mat4, Vec3A, Vec4};
58
use bevy_reflect::prelude::*;
69
use bevy_render::{
@@ -836,6 +839,7 @@ pub fn check_dir_light_mesh_visibility(
836839
});
837840
}
838841

842+
#[allow(clippy::too_many_arguments)]
839843
pub fn check_point_light_mesh_visibility(
840844
visible_point_lights: Query<&VisibleClusterableObjects>,
841845
mut point_lights: Query<(
@@ -872,10 +876,17 @@ pub fn check_point_light_mesh_visibility(
872876
visible_entity_ranges: Option<Res<VisibleEntityRanges>>,
873877
mut cubemap_visible_entities_queue: Local<Parallel<[Vec<Entity>; 6]>>,
874878
mut spot_visible_entities_queue: Local<Parallel<Vec<Entity>>>,
879+
mut checked_lights: Local<EntityHashSet>,
875880
) {
881+
checked_lights.clear();
882+
876883
let visible_entity_ranges = visible_entity_ranges.as_deref();
877884
for visible_lights in &visible_point_lights {
878885
for light_entity in visible_lights.entities.iter().copied() {
886+
if !checked_lights.insert(light_entity) {
887+
continue;
888+
}
889+
879890
// Point lights
880891
if let Ok((
881892
point_light,

0 commit comments

Comments
 (0)