-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Fix: Send CurrentView/ PointAndSpotLightShadowPrimaryCamera ’s world position via Immediates for gpu vis range culling
#24197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8ea52c8
37fac2e
f3b3681
147ba07
7f7d031
2f8e21a
31dc456
edc1df0
c6f162b
f1fc851
ac87f8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,7 @@ use bevy_core_pipeline::{ | |
| DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass, PreviousViewData, | ||
| PreviousViewUniformOffset, PreviousViewUniforms, | ||
| }, | ||
| schedule::{Core3d, Core3dSystems}, | ||
| schedule::{Core3d, Core3dSystems, RootNonCameraView}, | ||
| }; | ||
| use bevy_derive::{Deref, DerefMut}; | ||
| use bevy_ecs::{ | ||
|
|
@@ -45,6 +45,7 @@ use bevy_render::{ | |
| PreprocessWorkItemBuffers, UntypedPhaseBatchedInstanceBuffers, | ||
| UntypedPhaseIndirectParametersBuffers, | ||
| }, | ||
| camera::ExtractedCamera, | ||
| diagnostic::RecordDiagnostics as _, | ||
| occlusion_culling::OcclusionCulling, | ||
| render_phase::GpuRenderBinnedMeshInstance, | ||
|
|
@@ -61,14 +62,15 @@ use bevy_render::{ | |
| renderer::{RenderContext, RenderDevice, RenderQueue, ViewQuery}, | ||
| settings::WgpuFeatures, | ||
| view::{ | ||
| ExtractedView, NoIndirectDrawing, RenderVisibilityRanges, RetainedViewEntity, ViewUniform, | ||
| ViewUniformOffset, ViewUniforms, | ||
| ExtractedView, NoIndirectDrawing, PointAndSpotLightShadowPrimaryCamera, | ||
| RenderVisibilityRanges, RetainedViewEntity, ViewUniform, ViewUniformOffset, ViewUniforms, | ||
| }, | ||
| GpuResourceAppExt, Render, RenderApp, RenderSystems, | ||
| }; | ||
| use bevy_shader::Shader; | ||
| use bevy_utils::{default, TypeIdMap}; | ||
| use bitflags::bitflags; | ||
| use bytemuck::{Pod, Zeroable}; | ||
| use smallvec::{smallvec, SmallVec}; | ||
| use tracing::warn; | ||
|
|
||
|
|
@@ -291,7 +293,7 @@ pub enum PhasePreprocessBindGroups { | |
| }, | ||
|
|
||
| /// The bind groups used for the compute shader when indirect drawing is | ||
| /// being used, but occlusion culling isn't being used. | ||
| /// being used and occlusion culling is being used. | ||
| /// | ||
| /// Because indirect drawing requires splitting the meshes into indexed and | ||
| /// non-indexed meshes, and because occlusion culling requires splitting | ||
|
|
@@ -313,6 +315,13 @@ pub enum PhasePreprocessBindGroups { | |
| }, | ||
| } | ||
|
|
||
| #[derive(Clone, Copy, Pod, Zeroable)] | ||
| #[repr(C)] | ||
| struct PreprocessImmediates { | ||
| cur_view_world_position: [f32; 3], | ||
| late_preprocess_work_item_indirect_offset: u32, | ||
| } | ||
|
|
||
| /// The bind groups for the compute shaders that reset indirect draw counts and | ||
| /// build indirect parameters. | ||
| /// | ||
|
|
@@ -600,7 +609,21 @@ pub fn unpack_bins( | |
| } | ||
|
|
||
| pub fn early_gpu_preprocess( | ||
| current_view: ViewQuery<Option<&ViewLightEntities>, Without<SkipGpuPreprocess>>, | ||
| current_view: ViewQuery< | ||
| ( | ||
| Option<&ViewLightEntities>, | ||
| &ExtractedView, | ||
| Has<RootNonCameraView>, | ||
| ), | ||
| Without<SkipGpuPreprocess>, | ||
| >, | ||
| point_and_spot_light_shadow_primary_camera: Query< | ||
| &ExtractedView, | ||
| ( | ||
| With<ExtractedCamera>, | ||
| With<PointAndSpotLightShadowPrimaryCamera>, | ||
| ), | ||
| >, | ||
| view_query: Query< | ||
| ( | ||
| &ExtractedView, | ||
|
|
@@ -630,9 +653,11 @@ pub fn early_gpu_preprocess( | |
| let pass_span = diagnostics.pass_span(&mut compute_pass, "early_mesh_preprocessing"); | ||
|
|
||
| let view_entity = current_view.entity(); | ||
| let shadow_cascade_views = current_view.into_inner(); | ||
| let (shadow_cascade_views, extracted_view, has_non_root_view) = current_view.into_inner(); | ||
| let all_views = | ||
| gather_shadow_cascades_for_view(view_entity, shadow_cascade_views, &light_query); | ||
| let point_and_spot_light_shadow_camera_view = | ||
| point_and_spot_light_shadow_primary_camera.single(); | ||
|
|
||
| // Run the compute passes. | ||
| for view_entity in all_views { | ||
|
|
@@ -641,6 +666,26 @@ pub fn early_gpu_preprocess( | |
| else { | ||
| continue; | ||
| }; | ||
| // Set the camera position that will be used for visibility range culling. | ||
| let cur_view_world_position = if !has_non_root_view { | ||
| // Directional light shadows are made via cascaded shadow maps. | ||
| // These cascades are unique to each camera view (see RetainedViewEntity). | ||
| // For directional light shadows, the world position of the associated camera | ||
| // should be used for visibility range culling, not the world position of the shadow camera. | ||
| // The `CurrentView`'s `ExtractedView` contains the associated camera's world position. | ||
| extracted_view.world_from_view.translation().to_array() | ||
| } else { | ||
| // PointLight and SpotLight shadow views are handled in this else block. | ||
| // We could handle this case better if we can specify certain point and spot light shadow | ||
| // views to different cameras. Right now, it is all centralized to one user specified camera. | ||
| if let Ok(camera_view) = point_and_spot_light_shadow_camera_view { | ||
| camera_view.world_from_view.translation().to_array() | ||
| } else { | ||
| // There is no single designated primary camera to use for vis range culling of the shadows. | ||
| // Do not render them. | ||
| continue; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this continue skip the entire preprocess dispatch for the view?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the PointLight/SpotLight shadow view, yes But I would consider that a user configuration error at this point, so the shadows just wouldn’t be rendered. (However we do not need to continue this conversation because I will close this PR! It seems the consensus is converging on reverting the offending PR) |
||
| } | ||
| }; | ||
|
|
||
| let Some(bind_groups) = bind_groups else { | ||
| continue; | ||
|
|
@@ -746,10 +791,15 @@ pub fn early_gpu_preprocess( | |
| .. | ||
| } = *work_item_buffers | ||
| { | ||
| compute_pass.set_immediates( | ||
| 0, | ||
| bytemuck::bytes_of(&late_indirect_parameters_indexed_offset), | ||
| ); | ||
| let immediates = PreprocessImmediates { | ||
| cur_view_world_position, | ||
| late_preprocess_work_item_indirect_offset: | ||
| late_indirect_parameters_indexed_offset, | ||
| }; | ||
| compute_pass.set_immediates(0, bytemuck::bytes_of(&immediates)); | ||
| } else { | ||
| compute_pass | ||
| .set_immediates(0, bytemuck::bytes_of(&cur_view_world_position)); | ||
| } | ||
|
|
||
| compute_pass.set_bind_group(0, indexed_bind_group, &dynamic_offsets); | ||
|
|
@@ -770,10 +820,15 @@ pub fn early_gpu_preprocess( | |
| .. | ||
| } = *work_item_buffers | ||
| { | ||
| compute_pass.set_immediates( | ||
| 0, | ||
| bytemuck::bytes_of(&late_indirect_parameters_non_indexed_offset), | ||
| ); | ||
| let immediates = PreprocessImmediates { | ||
| cur_view_world_position, | ||
| late_preprocess_work_item_indirect_offset: | ||
| late_indirect_parameters_non_indexed_offset, | ||
| }; | ||
| compute_pass.set_immediates(0, bytemuck::bytes_of(&immediates)); | ||
| } else { | ||
| compute_pass | ||
| .set_immediates(0, bytemuck::bytes_of(&cur_view_world_position)); | ||
| } | ||
|
|
||
| compute_pass.set_bind_group(0, non_indexed_bind_group, &dynamic_offsets); | ||
|
|
@@ -1247,7 +1302,9 @@ impl SpecializedComputePipeline for PreprocessPipeline { | |
| ), | ||
| layout: vec![self.bind_group_layout.clone()], | ||
| immediate_size: if key.contains(PreprocessPipelineKey::OCCLUSION_CULLING) { | ||
| 4 | ||
| 16 | ||
| } else if key.contains(PreprocessPipelineKey::FRUSTUM_CULLING) { | ||
| 12 | ||
| } else { | ||
| 0 | ||
| }, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.