diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index c2a61d16e08e2..54e49dfe45825 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -15,6 +15,7 @@ use bevy_render::{ batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport}, camera::SortedCameras, mesh::allocator::MeshAllocator, + view::GpuCulling, }; use bevy_render::{ diagnostic::RecordDiagnostics, @@ -689,6 +690,7 @@ pub fn prepare_lights( &ExtractedView, &ExtractedClusterConfig, Option<&RenderLayers>, + Has, ), With, >, @@ -1097,7 +1099,7 @@ pub fn prepare_lights( let mut live_views = EntityHashSet::with_capacity_and_hasher(views_count, EntityHash); // set up light data for each view - for (entity, extracted_view, clusters, maybe_layers) in sorted_cameras + for (entity, extracted_view, clusters, maybe_layers, has_gpu_culling) in sorted_cameras .0 .iter() .filter_map(|sorted_camera| views.get(sorted_camera.entity).ok()) @@ -1105,6 +1107,12 @@ pub fn prepare_lights( live_views.insert(entity); let mut view_lights = Vec::new(); + let gpu_preprocessing_mode = gpu_preprocessing_support.min(if has_gpu_culling { + GpuPreprocessingMode::Culling + } else { + GpuPreprocessingMode::PreprocessingOnly + }); + let is_orthographic = extracted_view.clip_from_view.w_axis.w == 1.0; let cluster_factors_zw = calculate_cluster_factors( clusters.near, @@ -1232,15 +1240,15 @@ pub fn prepare_lights( }, )); + if matches!(gpu_preprocessing_mode, GpuPreprocessingMode::Culling) { + commands.entity(view_light_entity).insert(GpuCulling); + } + view_lights.push(view_light_entity); if first { // Subsequent views with the same light entity will reuse the same shadow map - // TODO: Implement GPU culling for shadow passes. - shadow_render_phases.insert_or_clear( - view_light_entity, - gpu_preprocessing_support.min(GpuPreprocessingMode::PreprocessingOnly), - ); + shadow_render_phases.insert_or_clear(view_light_entity, gpu_preprocessing_mode); live_shadow_mapping_lights.insert(view_light_entity); } } @@ -1324,14 +1332,15 @@ pub fn prepare_lights( LightEntity::Spot { light_entity }, )); + if matches!(gpu_preprocessing_mode, GpuPreprocessingMode::Culling) { + commands.entity(view_light_entity).insert(GpuCulling); + } + view_lights.push(view_light_entity); if first { // Subsequent views with the same light entity will reuse the same shadow map - shadow_render_phases.insert_or_clear( - view_light_entity, - gpu_preprocessing_support.min(GpuPreprocessingMode::PreprocessingOnly), - ); + shadow_render_phases.insert_or_clear(view_light_entity, gpu_preprocessing_mode); live_shadow_mapping_lights.insert(view_light_entity); } } @@ -1457,15 +1466,17 @@ pub fn prepare_lights( cascade_index, }, )); + + if matches!(gpu_preprocessing_mode, GpuPreprocessingMode::Culling) { + commands.entity(view_light_entity).insert(GpuCulling); + } + view_lights.push(view_light_entity); // Subsequent views with the same light entity will **NOT** reuse the same shadow map // (Because the cascades are unique to each view) // TODO: Implement GPU culling for shadow passes. - shadow_render_phases.insert_or_clear( - view_light_entity, - gpu_preprocessing_support.min(GpuPreprocessingMode::PreprocessingOnly), - ); + shadow_render_phases.insert_or_clear(view_light_entity, gpu_preprocessing_mode); live_shadow_mapping_lights.insert(view_light_entity); } }