Make light extraction retained, and clean up lights that became newly invisible.#22857
Merged
superdump merged 7 commits intobevyengine:mainfrom Feb 9, 2026
Merged
Make light extraction retained, and clean up lights that became newly invisible.#22857superdump merged 7 commits intobevyengine:mainfrom
superdump merged 7 commits intobevyengine:mainfrom
Conversation
invisible. The lighting code is designed such that lights that aren't visible in any view shouldn't exist in the render world. Unfortunately, when the render world was made retained, the light extraction code was never fully updated to clean up components corresponding to lights that became invisible. So Bevy is currently not enforcing that invariant. This causes `many_lights` to become slower over time as more lights enter the view and are extracted to the render world, while lights outside the view aren't removed. This PR fixes the issue in two ways: 1. Light extraction now properly accounts for the retained render world, following the patterns that other objects like meshes use. Lights that haven't changed from the previous frame aren't re-extracted and are retained from frame to frame. 2. Visibility of lights and other clustered objects is now determined by the same system that determines visibility of meshes. The `GlobalVisibleClusterableObjects` side table is gone. To do this, I made the existing `Sphere` type into a component that can be added in lieu of `Aabb` to entities that are culled using spheres instead of AABBs. This was surprisingly straightforward to add to the visibility code, as it was already using spheres for quick rejection. In addition to being a simplification, this PR increases the FPS of `many_lights` from around 30 FPS to around 100 FPS on my Ryzen 9 8945HS, moving it from CPU bound to strongly GPU bound. The profile was dominated by `extract_lights` and `prepare_lights` before. Retained mode drops `extract_lights` time from 8.9 ms plus 8.0 ms of commands processing time to 0.4 ms, and `prepare_lights` time drops to approximately 1.2 ms per frame (which further drops to 0.9 ms with my extra PR bevyengine#22846 applied).
IceSentry
reviewed
Feb 8, 2026
IceSentry
approved these changes
Feb 8, 2026
Contributor
IceSentry
left a comment
There was a problem hiding this comment.
I started a full example run just to be safe but LGTM
IceSentry
reviewed
Feb 8, 2026
| let mut update_from_object_intersections = | ||
| |visible_clusterable_objects: &mut VisibleClusterableObjects| { | ||
| for clusterable_object in &clusterable_objects { | ||
| for clusterable_object in &mut clusterable_objects { |
Contributor
There was a problem hiding this comment.
Is the mut here needed? I'm not seeing where it actually gets mutated.
atlv24
reviewed
Feb 9, 2026
| } else if let Some(model_sphere) = maybe_model_sphere | ||
| && !frustum.intersects_sphere(model_sphere, false) | ||
| { | ||
| // Do sphere-based frustum culling in this case |
Contributor
There was a problem hiding this comment.
maybe this comment should live up above the conditional like the rest of them? feels weird that doing "sphere based frustum culling in this case" is just an empty return
atlv24
reviewed
Feb 9, 2026
| Changed<OcclusionCulling>, | ||
| Changed<SunDisk>, | ||
| )>, | ||
| ), |
Contributor
There was a problem hiding this comment.
these queries are getting comically long lol
atlv24
approved these changes
Feb 9, 2026
Co-authored-by: atlv <email@atlasdostal.com>
superdump
approved these changes
Feb 9, 2026
Member
|
This PR caused a spam of error log when running the |
Member
|
I could not cleanly cherrypick this; it has been removed from 0.18.1. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The lighting code is designed such that lights that aren't visible in any view shouldn't exist in the render world. Unfortunately, when the render world was made retained, the light extraction code was never fully updated to clean up components corresponding to lights that became invisible. So Bevy is currently not enforcing that invariant. This causes
many_lightsto become slower over time as more lights enter the view and are extracted to the render world, while lights outside the view aren't removed.This PR fixes the issue in two ways:
Light extraction now properly accounts for the retained render world, following the patterns that other objects like meshes use. Lights that haven't changed from the previous frame aren't re-extracted and are retained from frame to frame.
Visibility of lights and other clustered objects is now determined by the same system that determines visibility of meshes. The
GlobalVisibleClusterableObjectsside table is gone. To do this, I made the existingSpheretype into a component that can be added in lieu ofAabbto entities that are culled using spheres instead of AABBs. This was surprisingly straightforward to add to the visibility code, as it was already using spheres for quick rejection.In addition to being a simplification, this PR increases the FPS of
many_lightsfrom around 30 FPS to around 100 FPS on my Ryzen 9 8945HS, moving it from CPU bound to strongly GPU bound. The profile was dominated byextract_lightsandprepare_lightsbefore. Retained mode dropsextract_lightstime from 8.9 ms plus 8.0 ms of commands processing time to 0.4 ms, andprepare_lightstime drops to approximately 1.2 ms per frame (which further drops to 0.9 ms with my extra PR #22846 applied).many_lightsonmain:many_lightsin this PR:Comparison of

prepare_lightsbetweenmainand this PR formany_lights:Comparison of

extract_lightsbetweenmainand this PR formany_lights: