mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 22:20:20 +00:00
Lighting Should Only hold Vec<Entity> instead of TypeId<Vec<Entity>> (#14073)
# Objective - After #13894, I noticed the performance of `many_lights `dropped from 120+ to 60+. I reviewed the PR but couldn't identify any mistakes. After profiling, I discovered that `Hashmap::Clone `was very slow when its not empty, causing `extract_light` to increase from 3ms to 8ms. - Lighting only checks visibility for 3D Meshes. We don't need to maintain a TypeIdMap for this, as it not only impacts performance negatively but also reduces ergonomics. ## Solution - use VisibleMeshEntities for lighint visibility checking. ## Performance cargo run --release --example many_lights --features bevy/trace_tracy name="bevy_pbr::light::check_point_light_mesh_visibility"} ![image](https://github.com/bevyengine/bevy/assets/45868716/8bad061a-f936-45a0-9bb9-4fbdaceec08b) system{name="bevy_pbr::render::light::extract_lights"} ![image](https://github.com/bevyengine/bevy/assets/45868716/ca75b46c-b4ad-45d3-8c8d-66442447b753) ## Migration Guide > now `SpotLightBundle` , `CascadesVisibleEntities `and `CubemapVisibleEntities `use VisibleMeshEntities instead of `VisibleEntities` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
e13c72d8a4
commit
36c6f29832
3 changed files with 36 additions and 30 deletions
|
@ -3,13 +3,14 @@ use crate::{
|
|||
StandardMaterial,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_ecs::entity::EntityHashMap;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::entity::{Entity, EntityHashMap};
|
||||
use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent};
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_render::{
|
||||
mesh::Mesh,
|
||||
primitives::{CascadesFrusta, CubemapFrusta, Frustum},
|
||||
view::{InheritedVisibility, ViewVisibility, Visibility, VisibleEntities},
|
||||
view::{InheritedVisibility, ViewVisibility, Visibility},
|
||||
};
|
||||
use bevy_transform::components::{GlobalTransform, Transform};
|
||||
|
||||
|
@ -45,27 +46,37 @@ impl<M: Material> Default for MaterialMeshBundle<M> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Collection of mesh entities visible for 3D lighting.
|
||||
/// This component contains all mesh entities visible from the current light view.
|
||||
/// The collection is updated automatically by [`crate::SimulationLightSystems`].
|
||||
#[derive(Component, Clone, Debug, Default, Reflect, Deref, DerefMut)]
|
||||
#[reflect(Component)]
|
||||
pub struct VisibleMeshEntities {
|
||||
#[reflect(ignore)]
|
||||
pub entities: Vec<Entity>,
|
||||
}
|
||||
|
||||
#[derive(Component, Clone, Debug, Default, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct CubemapVisibleEntities {
|
||||
#[reflect(ignore)]
|
||||
data: [VisibleEntities; 6],
|
||||
data: [VisibleMeshEntities; 6],
|
||||
}
|
||||
|
||||
impl CubemapVisibleEntities {
|
||||
pub fn get(&self, i: usize) -> &VisibleEntities {
|
||||
pub fn get(&self, i: usize) -> &VisibleMeshEntities {
|
||||
&self.data[i]
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, i: usize) -> &mut VisibleEntities {
|
||||
pub fn get_mut(&mut self, i: usize) -> &mut VisibleMeshEntities {
|
||||
&mut self.data[i]
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &VisibleEntities> {
|
||||
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &VisibleMeshEntities> {
|
||||
self.data.iter()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut VisibleEntities> {
|
||||
pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut VisibleMeshEntities> {
|
||||
self.data.iter_mut()
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +86,7 @@ impl CubemapVisibleEntities {
|
|||
pub struct CascadesVisibleEntities {
|
||||
/// Map of view entity to the visible entities for each cascade frustum.
|
||||
#[reflect(ignore)]
|
||||
pub entities: EntityHashMap<Vec<VisibleEntities>>,
|
||||
pub entities: EntityHashMap<Vec<VisibleMeshEntities>>,
|
||||
}
|
||||
|
||||
/// A component bundle for [`PointLight`] entities.
|
||||
|
@ -98,7 +109,7 @@ pub struct PointLightBundle {
|
|||
#[derive(Debug, Bundle, Default, Clone)]
|
||||
pub struct SpotLightBundle {
|
||||
pub spot_light: SpotLight,
|
||||
pub visible_entities: VisibleEntities,
|
||||
pub visible_entities: VisibleMeshEntities,
|
||||
pub frustum: Frustum,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
|
|
|
@ -11,8 +11,7 @@ use bevy_render::{
|
|||
mesh::Mesh,
|
||||
primitives::{Aabb, CascadesFrusta, CubemapFrusta, Frustum, Sphere},
|
||||
view::{
|
||||
InheritedVisibility, RenderLayers, ViewVisibility, VisibilityRange, VisibleEntities,
|
||||
VisibleEntityRanges, WithMesh,
|
||||
InheritedVisibility, RenderLayers, ViewVisibility, VisibilityRange, VisibleEntityRanges,
|
||||
},
|
||||
};
|
||||
use bevy_transform::components::{GlobalTransform, Transform};
|
||||
|
@ -100,7 +99,7 @@ impl Default for PointLightShadowMap {
|
|||
}
|
||||
|
||||
/// A convenient alias for `Or<(With<PointLight>, With<SpotLight>,
|
||||
/// With<DirectionalLight>)>`, for use with [`VisibleEntities`].
|
||||
/// With<DirectionalLight>)>`, for use with [`bevy_render::view::VisibleEntities`].
|
||||
pub type WithLight = Or<(With<PointLight>, With<SpotLight>, With<DirectionalLight>)>;
|
||||
|
||||
/// Controls the resolution of [`DirectionalLight`] shadow maps.
|
||||
|
@ -698,9 +697,7 @@ pub fn check_dir_light_mesh_visibility(
|
|||
match frusta.frusta.get(view) {
|
||||
Some(view_frusta) => {
|
||||
cascade_view_entities.resize(view_frusta.len(), Default::default());
|
||||
cascade_view_entities
|
||||
.iter_mut()
|
||||
.for_each(VisibleEntities::clear::<WithMesh>);
|
||||
cascade_view_entities.iter_mut().for_each(|x| x.clear());
|
||||
}
|
||||
None => views_to_remove.push(*view),
|
||||
};
|
||||
|
@ -709,7 +706,7 @@ pub fn check_dir_light_mesh_visibility(
|
|||
visible_entities
|
||||
.entities
|
||||
.entry(*view)
|
||||
.or_insert_with(|| vec![VisibleEntities::default(); frusta.len()]);
|
||||
.or_insert_with(|| vec![VisibleMeshEntities::default(); frusta.len()]);
|
||||
}
|
||||
|
||||
for v in views_to_remove {
|
||||
|
@ -790,7 +787,6 @@ pub fn check_dir_light_mesh_visibility(
|
|||
.get_mut(view)
|
||||
.unwrap()
|
||||
.iter_mut()
|
||||
.map(VisibleEntities::get_mut::<WithMesh>)
|
||||
.zip(entities.iter_mut())
|
||||
.for_each(|(dst, source)| {
|
||||
dst.append(source);
|
||||
|
@ -801,7 +797,7 @@ pub fn check_dir_light_mesh_visibility(
|
|||
for (_, cascade_view_entities) in &mut visible_entities.entities {
|
||||
cascade_view_entities
|
||||
.iter_mut()
|
||||
.map(VisibleEntities::get_mut::<WithMesh>)
|
||||
.map(DerefMut::deref_mut)
|
||||
.for_each(shrink_entities);
|
||||
}
|
||||
}
|
||||
|
@ -833,7 +829,7 @@ pub fn check_point_light_mesh_visibility(
|
|||
&SpotLight,
|
||||
&GlobalTransform,
|
||||
&Frustum,
|
||||
&mut VisibleEntities,
|
||||
&mut VisibleMeshEntities,
|
||||
Option<&RenderLayers>,
|
||||
)>,
|
||||
mut visible_entity_query: Query<
|
||||
|
@ -869,7 +865,7 @@ pub fn check_point_light_mesh_visibility(
|
|||
)) = point_lights.get_mut(light_entity)
|
||||
{
|
||||
for visible_entities in cubemap_visible_entities.iter_mut() {
|
||||
visible_entities.clear::<WithMesh>();
|
||||
visible_entities.entities.clear();
|
||||
}
|
||||
|
||||
// NOTE: If shadow mapping is disabled for the light then it must have no visible entities
|
||||
|
@ -940,13 +936,12 @@ pub fn check_point_light_mesh_visibility(
|
|||
for entities in cubemap_visible_entities_queue.iter_mut() {
|
||||
cubemap_visible_entities
|
||||
.iter_mut()
|
||||
.map(VisibleEntities::get_mut::<WithMesh>)
|
||||
.zip(entities.iter_mut())
|
||||
.for_each(|(dst, source)| dst.append(source));
|
||||
.for_each(|(dst, source)| dst.entities.append(source));
|
||||
}
|
||||
|
||||
for visible_entities in cubemap_visible_entities.iter_mut() {
|
||||
shrink_entities(visible_entities.get_mut::<WithMesh>());
|
||||
shrink_entities(visible_entities);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -954,7 +949,7 @@ pub fn check_point_light_mesh_visibility(
|
|||
if let Ok((point_light, transform, frustum, mut visible_entities, maybe_view_mask)) =
|
||||
spot_lights.get_mut(light_entity)
|
||||
{
|
||||
visible_entities.clear::<WithMesh>();
|
||||
visible_entities.clear();
|
||||
|
||||
// NOTE: If shadow mapping is disabled for the light then it must have no visible entities
|
||||
if !point_light.shadows_enabled {
|
||||
|
@ -1015,10 +1010,10 @@ pub fn check_point_light_mesh_visibility(
|
|||
);
|
||||
|
||||
for entities in spot_visible_entities_queue.iter_mut() {
|
||||
visible_entities.get_mut::<WithMesh>().append(entities);
|
||||
visible_entities.append(entities);
|
||||
}
|
||||
|
||||
shrink_entities(visible_entities.get_mut::<WithMesh>());
|
||||
shrink_entities(visible_entities.deref_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use bevy_render::{
|
|||
render_resource::*,
|
||||
renderer::{RenderContext, RenderDevice, RenderQueue},
|
||||
texture::*,
|
||||
view::{ExtractedView, RenderLayers, ViewVisibility, VisibleEntities, WithMesh},
|
||||
view::{ExtractedView, RenderLayers, ViewVisibility},
|
||||
Extract,
|
||||
};
|
||||
use bevy_transform::{components::GlobalTransform, prelude::Transform};
|
||||
|
@ -186,7 +186,7 @@ pub fn extract_lights(
|
|||
spot_lights: Extract<
|
||||
Query<(
|
||||
&SpotLight,
|
||||
&VisibleEntities,
|
||||
&VisibleMeshEntities,
|
||||
&GlobalTransform,
|
||||
&ViewVisibility,
|
||||
&Frustum,
|
||||
|
@ -1174,7 +1174,7 @@ pub fn queue_shadows<M: Material>(
|
|||
mut view_light_entities: Query<&LightEntity>,
|
||||
point_light_entities: Query<&CubemapVisibleEntities, With<ExtractedPointLight>>,
|
||||
directional_light_entities: Query<&CascadesVisibleEntities, With<ExtractedDirectionalLight>>,
|
||||
spot_light_entities: Query<&VisibleEntities, With<ExtractedPointLight>>,
|
||||
spot_light_entities: Query<&VisibleMeshEntities, With<ExtractedPointLight>>,
|
||||
) where
|
||||
M::Data: PartialEq + Eq + Hash + Clone,
|
||||
{
|
||||
|
@ -1218,7 +1218,7 @@ pub fn queue_shadows<M: Material>(
|
|||
// NOTE: Lights with shadow mapping disabled will have no visible entities
|
||||
// so no meshes will be queued
|
||||
|
||||
for entity in visible_entities.iter::<WithMesh>().copied() {
|
||||
for entity in visible_entities.iter().copied() {
|
||||
let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(entity)
|
||||
else {
|
||||
continue;
|
||||
|
|
Loading…
Reference in a new issue