1mod main_opaque_pass_3d_node;
2mod main_transparent_pass_3d_node;
3
4pub const CORE_3D_DEPTH_FORMAT: TextureFormat = TextureFormat::Depth32Float;
6
7#[cfg(not(any(feature = "webgpu", not(target_arch = "wasm32"))))]
18pub const DEPTH_PREPASS_TEXTURE_SUPPORTED: bool = false;
19
20#[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))]
31pub const DEPTH_PREPASS_TEXTURE_SUPPORTED: bool = true;
32
33use core::ops::Range;
34
35use bevy_camera::{Camera, Camera3d, Camera3dDepthLoadOp};
36use bevy_diagnostic::FrameCount;
37use bevy_render::{
38 batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport},
39 camera::CameraRenderGraph,
40 mesh::allocator::MeshSlabs,
41 occlusion_culling::OcclusionCulling,
42 render_phase::{PhaseItemBatchSetKey, ViewRangefinder3d},
43 texture::{CachedTexture, DepthStencilAttachment},
44 view::{prepare_view_targets, NoIndirectDrawing, RetainedViewEntity},
45};
46use indexmap::IndexMap;
47pub use main_opaque_pass_3d_node::*;
48pub use main_transparent_pass_3d_node::*;
49
50use bevy_app::{App, Plugin, PostUpdate};
51use bevy_asset::UntypedAssetId;
52use bevy_color::LinearRgba;
53use bevy_ecs::{entity::EntityHash, prelude::*};
54use bevy_image::ToExtents;
55use bevy_log::warn;
56use bevy_math::{FloatOrd, Vec3};
57use bevy_platform::collections::{HashMap, HashSet};
58use bevy_render::{
59 camera::ExtractedCamera,
60 extract_component::ExtractComponentPlugin,
61 prelude::Msaa,
62 render_phase::{
63 sort_phase_system, BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId,
64 DrawFunctions, PhaseItem, PhaseItemExtraIndex, SortedPhaseItem, ViewBinnedRenderPhases,
65 ViewSortedRenderPhases,
66 },
67 render_resource::{
68 CachedRenderPipelineId, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
69 },
70 renderer::{RenderAdapter, RenderDevice},
71 sync_world::{MainEntity, RenderEntity},
72 texture::{ColorAttachment, TextureCache},
73 view::{ExtractedView, ViewDepthStencilTexture},
74 Extract, ExtractSchedule, Render, RenderApp, RenderSystems,
75};
76use nonmax::NonMaxU32;
77
78use crate::deferred::copy_lighting_id::copy_deferred_lighting_id;
79use crate::deferred::node::{early_deferred_prepass, late_deferred_prepass};
80use crate::prepass::node::{early_prepass, late_prepass};
81use crate::tonemapping::tonemapping;
82use crate::upscaling::upscaling;
83use crate::{
84 deferred::{
85 AlphaMask3dDeferred, Opaque3dDeferred, DEFERRED_LIGHTING_PASS_ID_FORMAT,
86 DEFERRED_PREPASS_FORMAT,
87 },
88 prepass::{
89 AlphaMask3dPrepass, DeferredPrepass, DeferredPrepassDoubleBuffer, DepthPrepass,
90 DepthPrepassDoubleBuffer, MotionVectorPrepass, NormalPrepass, Opaque3dPrepass,
91 OpaqueNoLightmap3dBatchSetKey, OpaqueNoLightmap3dBinKey, ViewPrepassTextures,
92 MOTION_VECTOR_PREPASS_FORMAT, NORMAL_PREPASS_FORMAT,
93 },
94 schedule::Core3d,
95 skybox::SkyboxPlugin,
96 tonemapping::{DebandDither, Tonemapping},
97 Core3dSystems,
98};
99
100pub struct Core3dPlugin;
101
102impl Plugin for Core3dPlugin {
103 fn build(&self, app: &mut App) {
104 app.register_required_components_with::<Camera3d, DebandDither>(|| DebandDither::Enabled)
105 .register_required_components_with::<Camera3d, CameraRenderGraph>(|| {
106 CameraRenderGraph::new(Core3d)
107 })
108 .register_required_components::<Camera3d, Tonemapping>()
109 .add_plugins((SkyboxPlugin, ExtractComponentPlugin::<Camera3d>::default()))
110 .add_systems(PostUpdate, check_msaa);
111
112 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
113 return;
114 };
115 render_app
116 .init_resource::<DrawFunctions<Opaque3d>>()
117 .init_resource::<DrawFunctions<AlphaMask3d>>()
118 .init_resource::<DrawFunctions<Transparent3d>>()
119 .init_resource::<DrawFunctions<Opaque3dPrepass>>()
120 .init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
121 .init_resource::<DrawFunctions<Opaque3dDeferred>>()
122 .init_resource::<DrawFunctions<AlphaMask3dDeferred>>()
123 .init_resource::<ViewBinnedRenderPhases<Opaque3d>>()
124 .init_resource::<ViewBinnedRenderPhases<AlphaMask3d>>()
125 .init_resource::<ViewBinnedRenderPhases<Opaque3dPrepass>>()
126 .init_resource::<ViewBinnedRenderPhases<AlphaMask3dPrepass>>()
127 .init_resource::<ViewBinnedRenderPhases<Opaque3dDeferred>>()
128 .init_resource::<ViewBinnedRenderPhases<AlphaMask3dDeferred>>()
129 .init_resource::<ViewSortedRenderPhases<Transparent3d>>()
130 .add_systems(ExtractSchedule, extract_core_3d_camera_phases)
131 .add_systems(ExtractSchedule, extract_camera_prepass_phase)
132 .add_systems(
133 Render,
134 (
135 sort_phase_system::<Transparent3d>.in_set(RenderSystems::PhaseSort),
136 configure_occlusion_culling_view_targets
137 .after(prepare_view_targets)
138 .in_set(RenderSystems::PrepareViews)
139 .ambiguous_with(RenderSystems::PrepareViews),
140 prepare_core_3d_depth_textures.in_set(RenderSystems::PrepareResources),
141 prepare_prepass_textures.in_set(RenderSystems::PrepareResources),
142 ),
143 )
144 .add_schedule(Core3d::base_schedule())
145 .add_systems(
146 Core3d,
147 (
148 (
149 early_prepass,
150 early_deferred_prepass,
151 late_prepass,
152 late_deferred_prepass,
153 )
154 .chain()
155 .in_set(Core3dSystems::Prepass),
156 copy_deferred_lighting_id
160 .after(Core3dSystems::Prepass)
161 .before(Core3dSystems::MainPass),
162 (main_opaque_pass_3d, main_transparent_pass_3d)
163 .chain()
164 .in_set(Core3dSystems::MainPass),
165 tonemapping.in_set(Core3dSystems::PostProcess),
166 upscaling.after(Core3dSystems::PostProcess),
167 ),
168 );
169 }
170}
171
172pub struct Opaque3d {
174 pub batch_set_key: Opaque3dBatchSetKey,
179 pub bin_key: Opaque3dBinKey,
181 pub representative_entity: (Entity, MainEntity),
184 pub batch_range: Range<u32>,
186 pub extra_index: PhaseItemExtraIndex,
189}
190
191#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
197pub struct Opaque3dBatchSetKey {
198 pub pipeline: CachedRenderPipelineId,
200
201 pub draw_function: DrawFunctionId,
203
204 pub material_bind_group_index: Option<u32>,
208
209 pub slabs: MeshSlabs,
216
217 pub lightmap_slab: Option<NonMaxU32>,
220}
221
222impl PhaseItemBatchSetKey for Opaque3dBatchSetKey {
223 fn indexed(&self) -> bool {
224 self.slabs.index_slab_id.is_some()
225 }
226}
227
228#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
232pub struct Opaque3dBinKey {
233 pub asset_id: UntypedAssetId,
238}
239
240impl PhaseItem for Opaque3d {
241 #[inline]
242 fn entity(&self) -> Entity {
243 self.representative_entity.0
244 }
245
246 #[inline]
247 fn main_entity(&self) -> MainEntity {
248 self.representative_entity.1
249 }
250
251 #[inline]
252 fn draw_function(&self) -> DrawFunctionId {
253 self.batch_set_key.draw_function
254 }
255
256 #[inline]
257 fn batch_range(&self) -> &Range<u32> {
258 &self.batch_range
259 }
260
261 #[inline]
262 fn batch_range_mut(&mut self) -> &mut Range<u32> {
263 &mut self.batch_range
264 }
265
266 fn extra_index(&self) -> PhaseItemExtraIndex {
267 self.extra_index.clone()
268 }
269
270 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
271 (&mut self.batch_range, &mut self.extra_index)
272 }
273}
274
275impl BinnedPhaseItem for Opaque3d {
276 type BatchSetKey = Opaque3dBatchSetKey;
277 type BinKey = Opaque3dBinKey;
278
279 #[inline]
280 fn new(
281 batch_set_key: Self::BatchSetKey,
282 bin_key: Self::BinKey,
283 representative_entity: (Entity, MainEntity),
284 batch_range: Range<u32>,
285 extra_index: PhaseItemExtraIndex,
286 ) -> Self {
287 Opaque3d {
288 batch_set_key,
289 bin_key,
290 representative_entity,
291 batch_range,
292 extra_index,
293 }
294 }
295}
296
297impl CachedRenderPipelinePhaseItem for Opaque3d {
298 #[inline]
299 fn cached_pipeline(&self) -> CachedRenderPipelineId {
300 self.batch_set_key.pipeline
301 }
302}
303
304pub struct AlphaMask3d {
305 pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
310 pub bin_key: OpaqueNoLightmap3dBinKey,
312 pub representative_entity: (Entity, MainEntity),
313 pub batch_range: Range<u32>,
314 pub extra_index: PhaseItemExtraIndex,
315}
316
317impl PhaseItem for AlphaMask3d {
318 #[inline]
319 fn entity(&self) -> Entity {
320 self.representative_entity.0
321 }
322
323 fn main_entity(&self) -> MainEntity {
324 self.representative_entity.1
325 }
326
327 #[inline]
328 fn draw_function(&self) -> DrawFunctionId {
329 self.batch_set_key.draw_function
330 }
331
332 #[inline]
333 fn batch_range(&self) -> &Range<u32> {
334 &self.batch_range
335 }
336
337 #[inline]
338 fn batch_range_mut(&mut self) -> &mut Range<u32> {
339 &mut self.batch_range
340 }
341
342 #[inline]
343 fn extra_index(&self) -> PhaseItemExtraIndex {
344 self.extra_index.clone()
345 }
346
347 #[inline]
348 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
349 (&mut self.batch_range, &mut self.extra_index)
350 }
351}
352
353impl BinnedPhaseItem for AlphaMask3d {
354 type BinKey = OpaqueNoLightmap3dBinKey;
355 type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
356
357 #[inline]
358 fn new(
359 batch_set_key: Self::BatchSetKey,
360 bin_key: Self::BinKey,
361 representative_entity: (Entity, MainEntity),
362 batch_range: Range<u32>,
363 extra_index: PhaseItemExtraIndex,
364 ) -> Self {
365 Self {
366 batch_set_key,
367 bin_key,
368 representative_entity,
369 batch_range,
370 extra_index,
371 }
372 }
373}
374
375impl CachedRenderPipelinePhaseItem for AlphaMask3d {
376 #[inline]
377 fn cached_pipeline(&self) -> CachedRenderPipelineId {
378 self.batch_set_key.pipeline
379 }
380}
381
382pub struct Transparent3d {
383 pub sorting_info: TransparentSortingInfo3d,
384 pub distance: f32,
385 pub pipeline: CachedRenderPipelineId,
386 pub entity: (Entity, MainEntity),
387 pub draw_function: DrawFunctionId,
388 pub batch_range: Range<u32>,
389 pub extra_index: PhaseItemExtraIndex,
390 pub indexed: bool,
393}
394
395impl PhaseItem for Transparent3d {
396 #[inline]
397 fn entity(&self) -> Entity {
398 self.entity.0
399 }
400
401 fn main_entity(&self) -> MainEntity {
402 self.entity.1
403 }
404
405 #[inline]
406 fn draw_function(&self) -> DrawFunctionId {
407 self.draw_function
408 }
409
410 #[inline]
411 fn batch_range(&self) -> &Range<u32> {
412 &self.batch_range
413 }
414
415 #[inline]
416 fn batch_range_mut(&mut self) -> &mut Range<u32> {
417 &mut self.batch_range
418 }
419
420 #[inline]
421 fn extra_index(&self) -> PhaseItemExtraIndex {
422 self.extra_index.clone()
423 }
424
425 #[inline]
426 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
427 (&mut self.batch_range, &mut self.extra_index)
428 }
429}
430
431impl SortedPhaseItem for Transparent3d {
432 type SortKey = FloatOrd;
434
435 #[inline]
436 fn sort_key(&self) -> Self::SortKey {
437 FloatOrd(self.distance)
438 }
439
440 #[inline]
441 fn sort(items: &mut IndexMap<(Entity, MainEntity), Transparent3d, EntityHash>) {
442 items.sort_by_key(|_, item| item.sort_key());
443 }
444
445 fn recalculate_sort_keys(
446 items: &mut IndexMap<(Entity, MainEntity), Self, EntityHash>,
447 view: &ExtractedView,
448 ) {
449 let rangefinder = view.rangefinder3d();
451 for item in items.values_mut() {
452 item.distance = item.sorting_info.sort_distance(&rangefinder);
453 }
454 }
455
456 #[inline]
457 fn indexed(&self) -> bool {
458 self.indexed
459 }
460}
461
462impl CachedRenderPipelinePhaseItem for Transparent3d {
463 #[inline]
464 fn cached_pipeline(&self) -> CachedRenderPipelineId {
465 self.pipeline
466 }
467}
468
469#[derive(Clone, Copy)]
471pub enum TransparentSortingInfo3d {
472 AlwaysOnTop,
475 Sorted {
477 mesh_center: Vec3,
481 depth_bias: f32,
484 },
485}
486
487impl TransparentSortingInfo3d {
488 pub fn sort_distance(&self, rangefinder: &ViewRangefinder3d) -> f32 {
491 match *self {
492 TransparentSortingInfo3d::AlwaysOnTop => f32::NEG_INFINITY,
493 TransparentSortingInfo3d::Sorted {
494 mesh_center,
495 depth_bias,
496 } => rangefinder.distance(&mesh_center) + depth_bias,
497 }
498 }
499}
500
501pub fn extract_core_3d_camera_phases(
502 mut opaque_3d_phases: ResMut<ViewBinnedRenderPhases<Opaque3d>>,
503 mut alpha_mask_3d_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3d>>,
504 mut transparent_3d_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
505 cameras_3d: Extract<Query<(Entity, &Camera, Has<NoIndirectDrawing>), With<Camera3d>>>,
506 mut live_entities: Local<HashSet<RetainedViewEntity>>,
507 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
508) {
509 live_entities.clear();
510
511 for (main_entity, camera, no_indirect_drawing) in &cameras_3d {
512 if !camera.is_active {
513 continue;
514 }
515
516 let gpu_preprocessing_mode = gpu_preprocessing_support.min(if !no_indirect_drawing {
519 GpuPreprocessingMode::Culling
520 } else {
521 GpuPreprocessingMode::PreprocessingOnly
522 });
523
524 let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
526
527 opaque_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
528 alpha_mask_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
529 transparent_3d_phases.prepare_for_new_frame(retained_view_entity);
530
531 live_entities.insert(retained_view_entity);
532 }
533
534 opaque_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
535 alpha_mask_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
536 transparent_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
537}
538
539pub fn extract_camera_prepass_phase(
542 mut commands: Commands,
543 mut opaque_3d_prepass_phases: ResMut<ViewBinnedRenderPhases<Opaque3dPrepass>>,
544 mut alpha_mask_3d_prepass_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
545 mut opaque_3d_deferred_phases: ResMut<ViewBinnedRenderPhases<Opaque3dDeferred>>,
546 mut alpha_mask_3d_deferred_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
547 cameras_3d: Extract<
548 Query<
549 (
550 Entity,
551 RenderEntity,
552 &Camera,
553 Has<NoIndirectDrawing>,
554 Has<DepthPrepass>,
555 Has<NormalPrepass>,
556 Has<MotionVectorPrepass>,
557 Has<DeferredPrepass>,
558 Has<DepthPrepassDoubleBuffer>,
559 Has<DeferredPrepassDoubleBuffer>,
560 ),
561 With<Camera3d>,
562 >,
563 >,
564 mut live_entities: Local<HashSet<RetainedViewEntity>>,
565 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
566) {
567 live_entities.clear();
568
569 for (
570 main_entity,
571 entity,
572 camera,
573 no_indirect_drawing,
574 depth_prepass,
575 normal_prepass,
576 motion_vector_prepass,
577 deferred_prepass,
578 depth_prepass_double_buffer,
579 deferred_prepass_double_buffer,
580 ) in cameras_3d.iter()
581 {
582 if !camera.is_active {
583 continue;
584 }
585
586 let gpu_preprocessing_mode = gpu_preprocessing_support.min(if !no_indirect_drawing {
589 GpuPreprocessingMode::Culling
590 } else {
591 GpuPreprocessingMode::PreprocessingOnly
592 });
593
594 let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
596
597 if depth_prepass || normal_prepass || motion_vector_prepass {
598 opaque_3d_prepass_phases
599 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
600 alpha_mask_3d_prepass_phases
601 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
602 } else {
603 opaque_3d_prepass_phases.remove(&retained_view_entity);
604 alpha_mask_3d_prepass_phases.remove(&retained_view_entity);
605 }
606
607 if deferred_prepass {
608 opaque_3d_deferred_phases
609 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
610 alpha_mask_3d_deferred_phases
611 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
612 } else {
613 opaque_3d_deferred_phases.remove(&retained_view_entity);
614 alpha_mask_3d_deferred_phases.remove(&retained_view_entity);
615 }
616 live_entities.insert(retained_view_entity);
617
618 let mut camera_commands = commands
621 .get_entity(entity)
622 .expect("Camera entity wasn't synced.");
623
624 if depth_prepass {
625 camera_commands.insert(DepthPrepass);
626 } else {
627 camera_commands.remove::<DepthPrepass>();
628 }
629
630 if normal_prepass {
631 camera_commands.insert(NormalPrepass);
632 } else {
633 camera_commands.remove::<NormalPrepass>();
634 }
635
636 if motion_vector_prepass {
637 camera_commands.insert(MotionVectorPrepass);
638 } else {
639 camera_commands.remove::<MotionVectorPrepass>();
640 }
641
642 if deferred_prepass {
643 camera_commands.insert(DeferredPrepass);
644 } else {
645 camera_commands.remove::<DeferredPrepass>();
646 }
647
648 if depth_prepass_double_buffer {
649 camera_commands.insert(DepthPrepassDoubleBuffer);
650 } else {
651 camera_commands.remove::<DepthPrepassDoubleBuffer>();
652 }
653
654 if deferred_prepass_double_buffer {
655 camera_commands.insert(DeferredPrepassDoubleBuffer);
656 } else {
657 camera_commands.remove::<DeferredPrepassDoubleBuffer>();
658 }
659 }
660
661 opaque_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
662 alpha_mask_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
663 opaque_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
664 alpha_mask_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
665}
666
667pub fn prepare_core_3d_depth_textures(
668 mut commands: Commands,
669 mut texture_cache: ResMut<TextureCache>,
670 render_device: Res<RenderDevice>,
671 views_3d: Query<(
672 Entity,
673 &ExtractedCamera,
674 Option<&DepthPrepass>,
675 &Camera3d,
676 &Msaa,
677 )>,
678) {
679 let mut render_target_usage = <HashMap<_, _>>::default();
680 for (_, camera, depth_prepass, camera_3d, _msaa) in &views_3d {
681 let mut usage: TextureUsages = camera_3d.depth_texture_usages.into();
683 if depth_prepass.is_some() {
684 usage |= TextureUsages::COPY_SRC;
686 }
687 render_target_usage
688 .entry(camera.target.clone())
689 .and_modify(|u| *u |= usage)
690 .or_insert_with(|| usage);
691 }
692
693 let mut textures = <HashMap<_, _>>::default();
694 for (entity, camera, _, camera_3d, msaa) in &views_3d {
695 let Some(physical_target_size) = camera.physical_target_size else {
696 continue;
697 };
698
699 let cached_texture = textures
700 .entry((camera.target.clone(), msaa))
701 .or_insert_with(|| {
702 let usage = *render_target_usage
703 .get(&camera.target.clone())
704 .expect("The depth texture usage should already exist for this target");
705
706 let descriptor = TextureDescriptor {
707 label: Some("view_depth_texture"),
708 size: physical_target_size.to_extents(),
710 mip_level_count: 1,
711 sample_count: msaa.samples(),
712 dimension: TextureDimension::D2,
713 format: CORE_3D_DEPTH_FORMAT,
714 usage,
715 view_formats: &[],
716 };
717
718 texture_cache.get(&render_device, descriptor)
719 })
720 .clone();
721
722 commands.entity(entity).insert(ViewDepthStencilTexture::new(
723 cached_texture,
724 match camera_3d.depth_load_op {
725 Camera3dDepthLoadOp::Clear(v) => Some(v),
726 Camera3dDepthLoadOp::Load => None,
727 },
728 None,
729 ));
730 }
731}
732
733fn configure_occlusion_culling_view_targets(
738 mut view_targets: Query<
739 &mut Camera3d,
740 (
741 With<OcclusionCulling>,
742 Without<NoIndirectDrawing>,
743 With<DepthPrepass>,
744 ),
745 >,
746) {
747 for mut camera_3d in &mut view_targets {
748 let mut depth_texture_usages = TextureUsages::from(camera_3d.depth_texture_usages);
749 depth_texture_usages |= TextureUsages::TEXTURE_BINDING;
750 camera_3d.depth_texture_usages = depth_texture_usages.into();
751 }
752}
753
754pub fn check_msaa(mut deferred_views: Query<&mut Msaa, (With<Camera>, With<DeferredPrepass>)>) {
756 for mut msaa in deferred_views.iter_mut() {
757 match *msaa {
758 Msaa::Off => (),
759 _ => {
760 warn!("MSAA is incompatible with deferred rendering and has been disabled.");
761 *msaa = Msaa::Off;
762 }
763 };
764 }
765}
766
767pub fn prepare_prepass_textures(
769 mut commands: Commands,
770 mut texture_cache: ResMut<TextureCache>,
771 render_device: Res<RenderDevice>,
772 render_adapter: Res<RenderAdapter>,
773 frame_count: Res<FrameCount>,
774 opaque_3d_prepass_phases: Res<ViewBinnedRenderPhases<Opaque3dPrepass>>,
775 alpha_mask_3d_prepass_phases: Res<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
776 opaque_3d_deferred_phases: Res<ViewBinnedRenderPhases<Opaque3dDeferred>>,
777 alpha_mask_3d_deferred_phases: Res<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
778 views_3d: Query<(
779 Entity,
780 &ExtractedCamera,
781 &ExtractedView,
782 &Msaa,
783 Has<DepthPrepass>,
784 Has<NormalPrepass>,
785 Has<MotionVectorPrepass>,
786 Has<DeferredPrepass>,
787 Has<DepthPrepassDoubleBuffer>,
788 Has<DeferredPrepassDoubleBuffer>,
789 )>,
790) {
791 let motion_vector_storage_binding = render_adapter
792 .get_texture_format_features(MOTION_VECTOR_PREPASS_FORMAT)
793 .allowed_usages
794 .contains(TextureUsages::STORAGE_BINDING);
795
796 let mut depth_textures1 = <HashMap<_, _>>::default();
797 let mut depth_textures2 = <HashMap<_, _>>::default();
798 let mut normal_textures = <HashMap<_, _>>::default();
799 let mut deferred_textures1: HashMap<_, _> = <HashMap<_, _>>::default();
800 let mut deferred_textures2: HashMap<_, _> = <HashMap<_, _>>::default();
801 let mut deferred_lighting_id_textures = <HashMap<_, _>>::default();
802 let mut motion_vectors_textures = <HashMap<_, _>>::default();
803 for (
804 entity,
805 camera,
806 view,
807 msaa,
808 depth_prepass,
809 normal_prepass,
810 motion_vector_prepass,
811 deferred_prepass,
812 depth_prepass_double_buffer,
813 deferred_prepass_double_buffer,
814 ) in &views_3d
815 {
816 if !opaque_3d_prepass_phases.contains_key(&view.retained_view_entity)
817 && !alpha_mask_3d_prepass_phases.contains_key(&view.retained_view_entity)
818 && !opaque_3d_deferred_phases.contains_key(&view.retained_view_entity)
819 && !alpha_mask_3d_deferred_phases.contains_key(&view.retained_view_entity)
820 {
821 commands.entity(entity).remove::<ViewPrepassTextures>();
822 continue;
823 };
824
825 let Some(physical_target_size) = camera.physical_target_size else {
826 continue;
827 };
828
829 let size = physical_target_size.to_extents();
830
831 let cached_depth_texture1 = depth_prepass.then(|| {
832 depth_textures1
833 .entry(camera.target.clone())
834 .or_insert_with(|| {
835 let descriptor = TextureDescriptor {
836 label: Some("prepass_depth_texture_1"),
837 size,
838 mip_level_count: 1,
839 sample_count: msaa.samples(),
840 dimension: TextureDimension::D2,
841 format: CORE_3D_DEPTH_FORMAT,
842 usage: TextureUsages::COPY_DST
843 | TextureUsages::RENDER_ATTACHMENT
844 | TextureUsages::TEXTURE_BINDING,
845 view_formats: &[],
846 };
847 texture_cache.get(&render_device, descriptor)
848 })
849 .clone()
850 });
851
852 let cached_depth_texture2 = depth_prepass_double_buffer.then(|| {
853 depth_textures2
854 .entry(camera.target.clone())
855 .or_insert_with(|| {
856 let descriptor = TextureDescriptor {
857 label: Some("prepass_depth_texture_2"),
858 size,
859 mip_level_count: 1,
860 sample_count: msaa.samples(),
861 dimension: TextureDimension::D2,
862 format: CORE_3D_DEPTH_FORMAT,
863 usage: TextureUsages::COPY_DST
864 | TextureUsages::RENDER_ATTACHMENT
865 | TextureUsages::TEXTURE_BINDING,
866 view_formats: &[],
867 };
868 texture_cache.get(&render_device, descriptor)
869 })
870 .clone()
871 });
872
873 let cached_normals_texture = normal_prepass.then(|| {
874 normal_textures
875 .entry(camera.target.clone())
876 .or_insert_with(|| {
877 texture_cache.get(
878 &render_device,
879 TextureDescriptor {
880 label: Some("prepass_normal_texture"),
881 size,
882 mip_level_count: 1,
883 sample_count: msaa.samples(),
884 dimension: TextureDimension::D2,
885 format: NORMAL_PREPASS_FORMAT,
886 usage: TextureUsages::RENDER_ATTACHMENT
887 | TextureUsages::TEXTURE_BINDING,
888 view_formats: &[],
889 },
890 )
891 })
892 .clone()
893 });
894
895 let cached_motion_vectors_texture = motion_vector_prepass.then(|| {
896 motion_vectors_textures
897 .entry(camera.target.clone())
898 .or_insert_with(|| {
899 texture_cache.get(
900 &render_device,
901 TextureDescriptor {
902 label: Some("prepass_motion_vectors_textures"),
903 size,
904 mip_level_count: 1,
905 sample_count: msaa.samples(),
906 dimension: TextureDimension::D2,
907 format: MOTION_VECTOR_PREPASS_FORMAT,
908 usage: if motion_vector_storage_binding && msaa.samples() == 1 {
909 TextureUsages::RENDER_ATTACHMENT
910 | TextureUsages::TEXTURE_BINDING
911 | TextureUsages::STORAGE_BINDING
912 } else {
913 TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING
914 },
915 view_formats: &[],
916 },
917 )
918 })
919 .clone()
920 });
921
922 let cached_deferred_texture1 = deferred_prepass.then(|| {
923 deferred_textures1
924 .entry(camera.target.clone())
925 .or_insert_with(|| {
926 texture_cache.get(
927 &render_device,
928 TextureDescriptor {
929 label: Some("prepass_deferred_texture_1"),
930 size,
931 mip_level_count: 1,
932 sample_count: 1,
933 dimension: TextureDimension::D2,
934 format: DEFERRED_PREPASS_FORMAT,
935 usage: TextureUsages::RENDER_ATTACHMENT
936 | TextureUsages::TEXTURE_BINDING,
937 view_formats: &[],
938 },
939 )
940 })
941 .clone()
942 });
943
944 let cached_deferred_texture2 = deferred_prepass_double_buffer.then(|| {
945 deferred_textures2
946 .entry(camera.target.clone())
947 .or_insert_with(|| {
948 texture_cache.get(
949 &render_device,
950 TextureDescriptor {
951 label: Some("prepass_deferred_texture_2"),
952 size,
953 mip_level_count: 1,
954 sample_count: 1,
955 dimension: TextureDimension::D2,
956 format: DEFERRED_PREPASS_FORMAT,
957 usage: TextureUsages::RENDER_ATTACHMENT
958 | TextureUsages::TEXTURE_BINDING,
959 view_formats: &[],
960 },
961 )
962 })
963 .clone()
964 });
965
966 let cached_deferred_lighting_pass_id_texture = deferred_prepass.then(|| {
967 deferred_lighting_id_textures
968 .entry(camera.target.clone())
969 .or_insert_with(|| {
970 texture_cache.get(
971 &render_device,
972 TextureDescriptor {
973 label: Some("deferred_lighting_pass_id_texture"),
974 size,
975 mip_level_count: 1,
976 sample_count: 1,
977 dimension: TextureDimension::D2,
978 format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
979 usage: TextureUsages::RENDER_ATTACHMENT
980 | TextureUsages::TEXTURE_BINDING,
981 view_formats: &[],
982 },
983 )
984 })
985 .clone()
986 });
987
988 commands.entity(entity).insert(ViewPrepassTextures {
989 depth: package_double_buffered_depth_texture(
990 cached_depth_texture1,
991 cached_depth_texture2,
992 frame_count.0,
993 ),
994 normal: cached_normals_texture
995 .map(|t| ColorAttachment::new(t, None, None, Some(LinearRgba::BLACK.into()))),
996 motion_vectors: cached_motion_vectors_texture
1000 .map(|t| ColorAttachment::new(t, None, None, Some(LinearRgba::BLACK.into()))),
1001 deferred: package_double_buffered_texture(
1002 cached_deferred_texture1,
1003 cached_deferred_texture2,
1004 frame_count.0,
1005 ),
1006 deferred_lighting_pass_id: cached_deferred_lighting_pass_id_texture
1007 .map(|t| ColorAttachment::new(t, None, None, Some(LinearRgba::BLACK.into()))),
1008 size,
1009 });
1010 }
1011}
1012
1013fn package_double_buffered_texture(
1014 texture1: Option<CachedTexture>,
1015 texture2: Option<CachedTexture>,
1016 frame_count: u32,
1017) -> Option<ColorAttachment> {
1018 match (texture1, texture2) {
1019 (Some(t1), None) => Some(ColorAttachment::new(
1020 t1,
1021 None,
1022 None,
1023 Some(LinearRgba::BLACK.into()),
1024 )),
1025 (Some(t1), Some(t2)) if frame_count.is_multiple_of(2) => Some(ColorAttachment::new(
1026 t1,
1027 None,
1028 Some(t2),
1029 Some(LinearRgba::BLACK.into()),
1030 )),
1031 (Some(t1), Some(t2)) => Some(ColorAttachment::new(
1032 t2,
1033 None,
1034 Some(t1),
1035 Some(LinearRgba::BLACK.into()),
1036 )),
1037 _ => None,
1038 }
1039}
1040
1041fn package_double_buffered_depth_texture(
1042 texture1: Option<CachedTexture>,
1043 texture2: Option<CachedTexture>,
1044 frame_count: u32,
1045) -> Option<DepthStencilAttachment> {
1046 match (texture1, texture2) {
1047 (Some(t1), None) => Some(DepthStencilAttachment::new(t1, None, Some(0.0), None)),
1048 (Some(t1), Some(t2)) if frame_count.is_multiple_of(2) => {
1049 Some(DepthStencilAttachment::new(t1, Some(t2), Some(0.0), None))
1050 }
1051 (Some(t1), Some(t2)) => Some(DepthStencilAttachment::new(t2, Some(t1), Some(0.0), None)),
1052 _ => None,
1053 }
1054}