diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index ba235c56b5791..c42ce981b95bd 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -71,6 +71,8 @@ pub struct PointLightBundle { pub cubemap_frusta: CubemapFrusta, pub transform: Transform, pub global_transform: GlobalTransform, + /// Enables or disables the light + pub visibility: Visibility, } /// A component bundle for [`DirectionalLight`] entities. @@ -81,4 +83,6 @@ pub struct DirectionalLightBundle { pub visible_entities: VisibleEntities, pub transform: Transform, pub global_transform: GlobalTransform, + /// Enables or disables the light + pub visibility: Visibility, } diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index 33781bf774e08..4bda70f0ac8dd 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -480,7 +480,7 @@ fn ndc_position_to_cluster( } // Sort point lights with shadows enabled first, then by a stable key so that the index -// can be used to render at most `MAX_POINT_LIGHT_SHADOW_MAPS` point light shadows, and +// can be used to render at most `MAX_POINT_LIGHT_SHADOW_MAPS` point light shadows and // we keep a stable set of lights visible pub(crate) fn point_light_order( (entity_1, shadows_enabled_1): (&Entity, &bool), @@ -506,7 +506,7 @@ pub(crate) fn assign_lights_to_clusters( mut commands: Commands, mut global_lights: ResMut, mut views: Query<(Entity, &GlobalTransform, &Camera, &Frustum, &mut Clusters)>, - lights_query: Query<(Entity, &GlobalTransform, &PointLight)>, + lights_query: Query<(Entity, &GlobalTransform, &PointLight, &Visibility)>, mut lights: Local>, mut max_point_lights_warning_emitted: Local, ) { @@ -514,12 +514,15 @@ pub(crate) fn assign_lights_to_clusters( lights.extend( lights_query .iter() - .map(|(entity, transform, light)| PointLightAssignmentData { - entity, - translation: transform.translation, - shadows_enabled: light.shadows_enabled, - range: light.range, - }), + .filter(|(.., visibility)| visibility.is_visible) + .map( + |(entity, transform, light, _visibility)| PointLightAssignmentData { + entity, + translation: transform.translation, + shadows_enabled: light.shadows_enabled, + range: light.range, + }, + ), ); if lights.len() > MAX_POINT_LIGHTS { @@ -699,13 +702,18 @@ pub(crate) fn assign_lights_to_clusters( } pub fn update_directional_light_frusta( - mut views: Query<(&GlobalTransform, &DirectionalLight, &mut Frustum)>, + mut views: Query<( + &GlobalTransform, + &DirectionalLight, + &mut Frustum, + &Visibility, + )>, ) { - for (transform, directional_light, mut frustum) in views.iter_mut() { + for (transform, directional_light, mut frustum, visibility) in views.iter_mut() { // The frustum is used for culling meshes to the light for shadow mapping // so if shadow mapping is disabled for this light, then the frustum is // not needed. - if !directional_light.shadows_enabled { + if !directional_light.shadows_enabled || !visibility.is_visible { continue; } @@ -781,6 +789,7 @@ pub fn check_light_mesh_visibility( &Frustum, &mut VisibleEntities, Option<&RenderLayers>, + &Visibility, )>, mut visible_entity_query: Query< ( @@ -795,13 +804,13 @@ pub fn check_light_mesh_visibility( >, ) { // Directonal lights - for (directional_light, frustum, mut visible_entities, maybe_view_mask) in + for (directional_light, frustum, mut visible_entities, maybe_view_mask, visibility) in directional_lights.iter_mut() { visible_entities.entities.clear(); // NOTE: If shadow mapping is disabled for the light then it must have no visible entities - if !directional_light.shadows_enabled { + if !directional_light.shadows_enabled || !visibility.is_visible { continue; } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index e5d09ea18d7f2..327b5a64b1131 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -25,7 +25,9 @@ use bevy_render::{ render_resource::{std140::AsStd140, *}, renderer::{RenderContext, RenderDevice, RenderQueue}, texture::*, - view::{ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities}, + view::{ + ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility, VisibleEntities, + }, }; use bevy_transform::components::GlobalTransform; use bevy_utils::{ @@ -337,6 +339,7 @@ pub fn extract_lights( &DirectionalLight, &mut VisibleEntities, &GlobalTransform, + &Visibility, )>, ) { commands.insert_resource(ExtractedAmbientLight { @@ -383,7 +386,13 @@ pub fn extract_lights( } } - for (entity, directional_light, visible_entities, transform) in directional_lights.iter_mut() { + for (entity, directional_light, visible_entities, transform, visibility) in + directional_lights.iter_mut() + { + if !visibility.is_visible { + continue; + } + // Calulate the directional light shadow map texel size using the largest x,y dimension of // the orthographic projection divided by the shadow map resolution // NOTE: When using various PCF kernel sizes, this will need to be adjusted, according to: