1mod camera_3d;
2mod main_opaque_pass_3d_node;
3mod main_transmissive_pass_3d_node;
4mod main_transparent_pass_3d_node;
5
6pub mod graph {
7 use bevy_render::render_graph::{RenderLabel, RenderSubGraph};
8
9 #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderSubGraph)]
10 pub struct Core3d;
11
12 pub mod input {
13 pub const VIEW_ENTITY: &str = "view_entity";
14 }
15
16 #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
17 pub enum Node3d {
18 MsaaWriteback,
19 EarlyPrepass,
20 EarlyDownsampleDepth,
21 LatePrepass,
22 EarlyDeferredPrepass,
23 LateDeferredPrepass,
24 CopyDeferredLightingId,
25 EndPrepasses,
26 StartMainPass,
27 MainOpaquePass,
28 MainTransmissivePass,
29 MainTransparentPass,
30 EndMainPass,
31 Wireframe,
32 LateDownsampleDepth,
33 Taa,
34 MotionBlur,
35 Bloom,
36 AutoExposure,
37 DepthOfField,
38 PostProcessing,
39 Tonemapping,
40 Fxaa,
41 Smaa,
42 Upscaling,
43 ContrastAdaptiveSharpening,
44 EndMainPassPostProcessing,
45 }
46}
47
48pub const CORE_3D_DEPTH_FORMAT: TextureFormat = TextureFormat::Depth32Float;
50
51#[cfg(not(any(feature = "webgpu", not(target_arch = "wasm32"))))]
59pub const DEPTH_TEXTURE_SAMPLING_SUPPORTED: bool = false;
60
61#[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))]
69pub const DEPTH_TEXTURE_SAMPLING_SUPPORTED: bool = true;
70
71use core::ops::Range;
72
73use bevy_render::{
74 batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport},
75 experimental::occlusion_culling::OcclusionCulling,
76 mesh::allocator::SlabId,
77 render_phase::PhaseItemBatchSetKey,
78 view::{prepare_view_targets, NoIndirectDrawing, RetainedViewEntity},
79};
80pub use camera_3d::*;
81pub use main_opaque_pass_3d_node::*;
82pub use main_transparent_pass_3d_node::*;
83
84use bevy_app::{App, Plugin, PostUpdate};
85use bevy_asset::UntypedAssetId;
86use bevy_color::LinearRgba;
87use bevy_ecs::prelude::*;
88use bevy_image::BevyDefault;
89use bevy_math::FloatOrd;
90use bevy_platform::collections::{HashMap, HashSet};
91use bevy_render::{
92 camera::{Camera, ExtractedCamera},
93 extract_component::ExtractComponentPlugin,
94 prelude::Msaa,
95 render_graph::{EmptyNode, RenderGraphApp, ViewNodeRunner},
96 render_phase::{
97 sort_phase_system, BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId,
98 DrawFunctions, PhaseItem, PhaseItemExtraIndex, SortedPhaseItem, ViewBinnedRenderPhases,
99 ViewSortedRenderPhases,
100 },
101 render_resource::{
102 CachedRenderPipelineId, Extent3d, FilterMode, Sampler, SamplerDescriptor, Texture,
103 TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, TextureView,
104 },
105 renderer::RenderDevice,
106 sync_world::{MainEntity, RenderEntity},
107 texture::{ColorAttachment, TextureCache},
108 view::{ExtractedView, ViewDepthTexture, ViewTarget},
109 Extract, ExtractSchedule, Render, RenderApp, RenderSet,
110};
111use nonmax::NonMaxU32;
112use tracing::warn;
113
114use crate::{
115 core_3d::main_transmissive_pass_3d_node::MainTransmissivePass3dNode,
116 deferred::{
117 copy_lighting_id::CopyDeferredLightingIdNode,
118 node::{EarlyDeferredGBufferPrepassNode, LateDeferredGBufferPrepassNode},
119 AlphaMask3dDeferred, Opaque3dDeferred, DEFERRED_LIGHTING_PASS_ID_FORMAT,
120 DEFERRED_PREPASS_FORMAT,
121 },
122 dof::DepthOfFieldNode,
123 prepass::{
124 node::{EarlyPrepassNode, LatePrepassNode},
125 AlphaMask3dPrepass, DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass,
126 Opaque3dPrepass, OpaqueNoLightmap3dBatchSetKey, OpaqueNoLightmap3dBinKey,
127 ViewPrepassTextures, MOTION_VECTOR_PREPASS_FORMAT, NORMAL_PREPASS_FORMAT,
128 },
129 skybox::SkyboxPlugin,
130 tonemapping::TonemappingNode,
131 upscaling::UpscalingNode,
132};
133
134use self::graph::{Core3d, Node3d};
135
136pub struct Core3dPlugin;
137
138impl Plugin for Core3dPlugin {
139 fn build(&self, app: &mut App) {
140 app.register_type::<Camera3d>()
141 .register_type::<ScreenSpaceTransmissionQuality>()
142 .add_plugins((SkyboxPlugin, ExtractComponentPlugin::<Camera3d>::default()))
143 .add_systems(PostUpdate, check_msaa);
144
145 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
146 return;
147 };
148 render_app
149 .init_resource::<DrawFunctions<Opaque3d>>()
150 .init_resource::<DrawFunctions<AlphaMask3d>>()
151 .init_resource::<DrawFunctions<Transmissive3d>>()
152 .init_resource::<DrawFunctions<Transparent3d>>()
153 .init_resource::<DrawFunctions<Opaque3dPrepass>>()
154 .init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
155 .init_resource::<DrawFunctions<Opaque3dDeferred>>()
156 .init_resource::<DrawFunctions<AlphaMask3dDeferred>>()
157 .init_resource::<ViewBinnedRenderPhases<Opaque3d>>()
158 .init_resource::<ViewBinnedRenderPhases<AlphaMask3d>>()
159 .init_resource::<ViewBinnedRenderPhases<Opaque3dPrepass>>()
160 .init_resource::<ViewBinnedRenderPhases<AlphaMask3dPrepass>>()
161 .init_resource::<ViewBinnedRenderPhases<Opaque3dDeferred>>()
162 .init_resource::<ViewBinnedRenderPhases<AlphaMask3dDeferred>>()
163 .init_resource::<ViewSortedRenderPhases<Transmissive3d>>()
164 .init_resource::<ViewSortedRenderPhases<Transparent3d>>()
165 .add_systems(ExtractSchedule, extract_core_3d_camera_phases)
166 .add_systems(ExtractSchedule, extract_camera_prepass_phase)
167 .add_systems(
168 Render,
169 (
170 sort_phase_system::<Transmissive3d>.in_set(RenderSet::PhaseSort),
171 sort_phase_system::<Transparent3d>.in_set(RenderSet::PhaseSort),
172 configure_occlusion_culling_view_targets
173 .after(prepare_view_targets)
174 .in_set(RenderSet::ManageViews),
175 prepare_core_3d_depth_textures.in_set(RenderSet::PrepareResources),
176 prepare_core_3d_transmission_textures.in_set(RenderSet::PrepareResources),
177 prepare_prepass_textures.in_set(RenderSet::PrepareResources),
178 ),
179 );
180
181 render_app
182 .add_render_sub_graph(Core3d)
183 .add_render_graph_node::<ViewNodeRunner<EarlyPrepassNode>>(Core3d, Node3d::EarlyPrepass)
184 .add_render_graph_node::<ViewNodeRunner<LatePrepassNode>>(Core3d, Node3d::LatePrepass)
185 .add_render_graph_node::<ViewNodeRunner<EarlyDeferredGBufferPrepassNode>>(
186 Core3d,
187 Node3d::EarlyDeferredPrepass,
188 )
189 .add_render_graph_node::<ViewNodeRunner<LateDeferredGBufferPrepassNode>>(
190 Core3d,
191 Node3d::LateDeferredPrepass,
192 )
193 .add_render_graph_node::<ViewNodeRunner<CopyDeferredLightingIdNode>>(
194 Core3d,
195 Node3d::CopyDeferredLightingId,
196 )
197 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::EndPrepasses)
198 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::StartMainPass)
199 .add_render_graph_node::<ViewNodeRunner<MainOpaquePass3dNode>>(
200 Core3d,
201 Node3d::MainOpaquePass,
202 )
203 .add_render_graph_node::<ViewNodeRunner<MainTransmissivePass3dNode>>(
204 Core3d,
205 Node3d::MainTransmissivePass,
206 )
207 .add_render_graph_node::<ViewNodeRunner<MainTransparentPass3dNode>>(
208 Core3d,
209 Node3d::MainTransparentPass,
210 )
211 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::EndMainPass)
212 .add_render_graph_node::<ViewNodeRunner<DepthOfFieldNode>>(Core3d, Node3d::DepthOfField)
213 .add_render_graph_node::<ViewNodeRunner<TonemappingNode>>(Core3d, Node3d::Tonemapping)
214 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::EndMainPassPostProcessing)
215 .add_render_graph_node::<ViewNodeRunner<UpscalingNode>>(Core3d, Node3d::Upscaling)
216 .add_render_graph_edges(
217 Core3d,
218 (
219 Node3d::EarlyPrepass,
220 Node3d::EarlyDeferredPrepass,
221 Node3d::LatePrepass,
222 Node3d::LateDeferredPrepass,
223 Node3d::CopyDeferredLightingId,
224 Node3d::EndPrepasses,
225 Node3d::StartMainPass,
226 Node3d::MainOpaquePass,
227 Node3d::MainTransmissivePass,
228 Node3d::MainTransparentPass,
229 Node3d::EndMainPass,
230 Node3d::Tonemapping,
231 Node3d::EndMainPassPostProcessing,
232 Node3d::Upscaling,
233 ),
234 );
235 }
236}
237
238pub struct Opaque3d {
240 pub batch_set_key: Opaque3dBatchSetKey,
245 pub bin_key: Opaque3dBinKey,
247 pub representative_entity: (Entity, MainEntity),
250 pub batch_range: Range<u32>,
252 pub extra_index: PhaseItemExtraIndex,
255}
256
257#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
263pub struct Opaque3dBatchSetKey {
264 pub pipeline: CachedRenderPipelineId,
266
267 pub draw_function: DrawFunctionId,
269
270 pub material_bind_group_index: Option<u32>,
274
275 pub vertex_slab: SlabId,
280
281 pub index_slab: Option<SlabId>,
285
286 pub lightmap_slab: Option<NonMaxU32>,
289}
290
291impl PhaseItemBatchSetKey for Opaque3dBatchSetKey {
292 fn indexed(&self) -> bool {
293 self.index_slab.is_some()
294 }
295}
296
297#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
301pub struct Opaque3dBinKey {
302 pub asset_id: UntypedAssetId,
307}
308
309impl PhaseItem for Opaque3d {
310 #[inline]
311 fn entity(&self) -> Entity {
312 self.representative_entity.0
313 }
314
315 #[inline]
316 fn main_entity(&self) -> MainEntity {
317 self.representative_entity.1
318 }
319
320 #[inline]
321 fn draw_function(&self) -> DrawFunctionId {
322 self.batch_set_key.draw_function
323 }
324
325 #[inline]
326 fn batch_range(&self) -> &Range<u32> {
327 &self.batch_range
328 }
329
330 #[inline]
331 fn batch_range_mut(&mut self) -> &mut Range<u32> {
332 &mut self.batch_range
333 }
334
335 fn extra_index(&self) -> PhaseItemExtraIndex {
336 self.extra_index.clone()
337 }
338
339 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
340 (&mut self.batch_range, &mut self.extra_index)
341 }
342}
343
344impl BinnedPhaseItem for Opaque3d {
345 type BatchSetKey = Opaque3dBatchSetKey;
346 type BinKey = Opaque3dBinKey;
347
348 #[inline]
349 fn new(
350 batch_set_key: Self::BatchSetKey,
351 bin_key: Self::BinKey,
352 representative_entity: (Entity, MainEntity),
353 batch_range: Range<u32>,
354 extra_index: PhaseItemExtraIndex,
355 ) -> Self {
356 Opaque3d {
357 batch_set_key,
358 bin_key,
359 representative_entity,
360 batch_range,
361 extra_index,
362 }
363 }
364}
365
366impl CachedRenderPipelinePhaseItem for Opaque3d {
367 #[inline]
368 fn cached_pipeline(&self) -> CachedRenderPipelineId {
369 self.batch_set_key.pipeline
370 }
371}
372
373pub struct AlphaMask3d {
374 pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
379 pub bin_key: OpaqueNoLightmap3dBinKey,
381 pub representative_entity: (Entity, MainEntity),
382 pub batch_range: Range<u32>,
383 pub extra_index: PhaseItemExtraIndex,
384}
385
386impl PhaseItem for AlphaMask3d {
387 #[inline]
388 fn entity(&self) -> Entity {
389 self.representative_entity.0
390 }
391
392 fn main_entity(&self) -> MainEntity {
393 self.representative_entity.1
394 }
395
396 #[inline]
397 fn draw_function(&self) -> DrawFunctionId {
398 self.batch_set_key.draw_function
399 }
400
401 #[inline]
402 fn batch_range(&self) -> &Range<u32> {
403 &self.batch_range
404 }
405
406 #[inline]
407 fn batch_range_mut(&mut self) -> &mut Range<u32> {
408 &mut self.batch_range
409 }
410
411 #[inline]
412 fn extra_index(&self) -> PhaseItemExtraIndex {
413 self.extra_index.clone()
414 }
415
416 #[inline]
417 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
418 (&mut self.batch_range, &mut self.extra_index)
419 }
420}
421
422impl BinnedPhaseItem for AlphaMask3d {
423 type BinKey = OpaqueNoLightmap3dBinKey;
424 type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
425
426 #[inline]
427 fn new(
428 batch_set_key: Self::BatchSetKey,
429 bin_key: Self::BinKey,
430 representative_entity: (Entity, MainEntity),
431 batch_range: Range<u32>,
432 extra_index: PhaseItemExtraIndex,
433 ) -> Self {
434 Self {
435 batch_set_key,
436 bin_key,
437 representative_entity,
438 batch_range,
439 extra_index,
440 }
441 }
442}
443
444impl CachedRenderPipelinePhaseItem for AlphaMask3d {
445 #[inline]
446 fn cached_pipeline(&self) -> CachedRenderPipelineId {
447 self.batch_set_key.pipeline
448 }
449}
450
451pub struct Transmissive3d {
452 pub distance: f32,
453 pub pipeline: CachedRenderPipelineId,
454 pub entity: (Entity, MainEntity),
455 pub draw_function: DrawFunctionId,
456 pub batch_range: Range<u32>,
457 pub extra_index: PhaseItemExtraIndex,
458 pub indexed: bool,
461}
462
463impl PhaseItem for Transmissive3d {
464 const AUTOMATIC_BATCHING: bool = false;
474
475 #[inline]
476 fn entity(&self) -> Entity {
477 self.entity.0
478 }
479
480 #[inline]
481 fn main_entity(&self) -> MainEntity {
482 self.entity.1
483 }
484
485 #[inline]
486 fn draw_function(&self) -> DrawFunctionId {
487 self.draw_function
488 }
489
490 #[inline]
491 fn batch_range(&self) -> &Range<u32> {
492 &self.batch_range
493 }
494
495 #[inline]
496 fn batch_range_mut(&mut self) -> &mut Range<u32> {
497 &mut self.batch_range
498 }
499
500 #[inline]
501 fn extra_index(&self) -> PhaseItemExtraIndex {
502 self.extra_index.clone()
503 }
504
505 #[inline]
506 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
507 (&mut self.batch_range, &mut self.extra_index)
508 }
509}
510
511impl SortedPhaseItem for Transmissive3d {
512 type SortKey = FloatOrd;
514
515 #[inline]
516 fn sort_key(&self) -> Self::SortKey {
517 FloatOrd(self.distance)
518 }
519
520 #[inline]
521 fn sort(items: &mut [Self]) {
522 radsort::sort_by_key(items, |item| item.distance);
523 }
524
525 #[inline]
526 fn indexed(&self) -> bool {
527 self.indexed
528 }
529}
530
531impl CachedRenderPipelinePhaseItem for Transmissive3d {
532 #[inline]
533 fn cached_pipeline(&self) -> CachedRenderPipelineId {
534 self.pipeline
535 }
536}
537
538pub struct Transparent3d {
539 pub distance: f32,
540 pub pipeline: CachedRenderPipelineId,
541 pub entity: (Entity, MainEntity),
542 pub draw_function: DrawFunctionId,
543 pub batch_range: Range<u32>,
544 pub extra_index: PhaseItemExtraIndex,
545 pub indexed: bool,
548}
549
550impl PhaseItem for Transparent3d {
551 #[inline]
552 fn entity(&self) -> Entity {
553 self.entity.0
554 }
555
556 fn main_entity(&self) -> MainEntity {
557 self.entity.1
558 }
559
560 #[inline]
561 fn draw_function(&self) -> DrawFunctionId {
562 self.draw_function
563 }
564
565 #[inline]
566 fn batch_range(&self) -> &Range<u32> {
567 &self.batch_range
568 }
569
570 #[inline]
571 fn batch_range_mut(&mut self) -> &mut Range<u32> {
572 &mut self.batch_range
573 }
574
575 #[inline]
576 fn extra_index(&self) -> PhaseItemExtraIndex {
577 self.extra_index.clone()
578 }
579
580 #[inline]
581 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
582 (&mut self.batch_range, &mut self.extra_index)
583 }
584}
585
586impl SortedPhaseItem for Transparent3d {
587 type SortKey = FloatOrd;
589
590 #[inline]
591 fn sort_key(&self) -> Self::SortKey {
592 FloatOrd(self.distance)
593 }
594
595 #[inline]
596 fn sort(items: &mut [Self]) {
597 radsort::sort_by_key(items, |item| item.distance);
598 }
599
600 #[inline]
601 fn indexed(&self) -> bool {
602 self.indexed
603 }
604}
605
606impl CachedRenderPipelinePhaseItem for Transparent3d {
607 #[inline]
608 fn cached_pipeline(&self) -> CachedRenderPipelineId {
609 self.pipeline
610 }
611}
612
613pub fn extract_core_3d_camera_phases(
614 mut opaque_3d_phases: ResMut<ViewBinnedRenderPhases<Opaque3d>>,
615 mut alpha_mask_3d_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3d>>,
616 mut transmissive_3d_phases: ResMut<ViewSortedRenderPhases<Transmissive3d>>,
617 mut transparent_3d_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
618 cameras_3d: Extract<Query<(Entity, &Camera, Has<NoIndirectDrawing>), With<Camera3d>>>,
619 mut live_entities: Local<HashSet<RetainedViewEntity>>,
620 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
621) {
622 live_entities.clear();
623
624 for (main_entity, camera, no_indirect_drawing) in &cameras_3d {
625 if !camera.is_active {
626 continue;
627 }
628
629 let gpu_preprocessing_mode = gpu_preprocessing_support.min(if !no_indirect_drawing {
632 GpuPreprocessingMode::Culling
633 } else {
634 GpuPreprocessingMode::PreprocessingOnly
635 });
636
637 let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
639
640 opaque_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
641 alpha_mask_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
642 transmissive_3d_phases.insert_or_clear(retained_view_entity);
643 transparent_3d_phases.insert_or_clear(retained_view_entity);
644
645 live_entities.insert(retained_view_entity);
646 }
647
648 opaque_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
649 alpha_mask_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
650 transmissive_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
651 transparent_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
652}
653
654pub fn extract_camera_prepass_phase(
657 mut commands: Commands,
658 mut opaque_3d_prepass_phases: ResMut<ViewBinnedRenderPhases<Opaque3dPrepass>>,
659 mut alpha_mask_3d_prepass_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
660 mut opaque_3d_deferred_phases: ResMut<ViewBinnedRenderPhases<Opaque3dDeferred>>,
661 mut alpha_mask_3d_deferred_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
662 cameras_3d: Extract<
663 Query<
664 (
665 Entity,
666 RenderEntity,
667 &Camera,
668 Has<NoIndirectDrawing>,
669 Has<DepthPrepass>,
670 Has<NormalPrepass>,
671 Has<MotionVectorPrepass>,
672 Has<DeferredPrepass>,
673 ),
674 With<Camera3d>,
675 >,
676 >,
677 mut live_entities: Local<HashSet<RetainedViewEntity>>,
678 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
679) {
680 live_entities.clear();
681
682 for (
683 main_entity,
684 entity,
685 camera,
686 no_indirect_drawing,
687 depth_prepass,
688 normal_prepass,
689 motion_vector_prepass,
690 deferred_prepass,
691 ) in cameras_3d.iter()
692 {
693 if !camera.is_active {
694 continue;
695 }
696
697 let gpu_preprocessing_mode = gpu_preprocessing_support.min(if !no_indirect_drawing {
700 GpuPreprocessingMode::Culling
701 } else {
702 GpuPreprocessingMode::PreprocessingOnly
703 });
704
705 let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
707
708 if depth_prepass || normal_prepass || motion_vector_prepass {
709 opaque_3d_prepass_phases
710 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
711 alpha_mask_3d_prepass_phases
712 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
713 } else {
714 opaque_3d_prepass_phases.remove(&retained_view_entity);
715 alpha_mask_3d_prepass_phases.remove(&retained_view_entity);
716 }
717
718 if deferred_prepass {
719 opaque_3d_deferred_phases
720 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
721 alpha_mask_3d_deferred_phases
722 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
723 } else {
724 opaque_3d_deferred_phases.remove(&retained_view_entity);
725 alpha_mask_3d_deferred_phases.remove(&retained_view_entity);
726 }
727 live_entities.insert(retained_view_entity);
728
729 let mut camera_commands = commands
732 .get_entity(entity)
733 .expect("Camera entity wasn't synced.");
734
735 if depth_prepass {
736 camera_commands.insert(DepthPrepass);
737 } else {
738 camera_commands.remove::<DepthPrepass>();
739 }
740
741 if normal_prepass {
742 camera_commands.insert(NormalPrepass);
743 } else {
744 camera_commands.remove::<NormalPrepass>();
745 }
746
747 if motion_vector_prepass {
748 camera_commands.insert(MotionVectorPrepass);
749 } else {
750 camera_commands.remove::<MotionVectorPrepass>();
751 }
752
753 if deferred_prepass {
754 camera_commands.insert(DeferredPrepass);
755 } else {
756 camera_commands.remove::<DeferredPrepass>();
757 }
758 }
759
760 opaque_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
761 alpha_mask_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
762 opaque_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
763 alpha_mask_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
764}
765
766pub fn prepare_core_3d_depth_textures(
767 mut commands: Commands,
768 mut texture_cache: ResMut<TextureCache>,
769 render_device: Res<RenderDevice>,
770 opaque_3d_phases: Res<ViewBinnedRenderPhases<Opaque3d>>,
771 alpha_mask_3d_phases: Res<ViewBinnedRenderPhases<AlphaMask3d>>,
772 transmissive_3d_phases: Res<ViewSortedRenderPhases<Transmissive3d>>,
773 transparent_3d_phases: Res<ViewSortedRenderPhases<Transparent3d>>,
774 views_3d: Query<(
775 Entity,
776 &ExtractedCamera,
777 &ExtractedView,
778 Option<&DepthPrepass>,
779 &Camera3d,
780 &Msaa,
781 )>,
782) {
783 let mut render_target_usage = <HashMap<_, _>>::default();
784 for (_, camera, extracted_view, depth_prepass, camera_3d, _msaa) in &views_3d {
785 if !opaque_3d_phases.contains_key(&extracted_view.retained_view_entity)
786 || !alpha_mask_3d_phases.contains_key(&extracted_view.retained_view_entity)
787 || !transmissive_3d_phases.contains_key(&extracted_view.retained_view_entity)
788 || !transparent_3d_phases.contains_key(&extracted_view.retained_view_entity)
789 {
790 continue;
791 };
792
793 let mut usage: TextureUsages = camera_3d.depth_texture_usages.into();
795 if depth_prepass.is_some() {
796 usage |= TextureUsages::COPY_SRC;
798 }
799 render_target_usage
800 .entry(camera.target.clone())
801 .and_modify(|u| *u |= usage)
802 .or_insert_with(|| usage);
803 }
804
805 let mut textures = <HashMap<_, _>>::default();
806 for (entity, camera, _, _, camera_3d, msaa) in &views_3d {
807 let Some(physical_target_size) = camera.physical_target_size else {
808 continue;
809 };
810
811 let cached_texture = textures
812 .entry((camera.target.clone(), msaa))
813 .or_insert_with(|| {
814 let size = Extent3d {
816 depth_or_array_layers: 1,
817 width: physical_target_size.x,
818 height: physical_target_size.y,
819 };
820
821 let usage = *render_target_usage
822 .get(&camera.target.clone())
823 .expect("The depth texture usage should already exist for this target");
824
825 let descriptor = TextureDescriptor {
826 label: Some("view_depth_texture"),
827 size,
828 mip_level_count: 1,
829 sample_count: msaa.samples(),
830 dimension: TextureDimension::D2,
831 format: CORE_3D_DEPTH_FORMAT,
832 usage,
833 view_formats: &[],
834 };
835
836 texture_cache.get(&render_device, descriptor)
837 })
838 .clone();
839
840 commands.entity(entity).insert(ViewDepthTexture::new(
841 cached_texture,
842 match camera_3d.depth_load_op {
843 Camera3dDepthLoadOp::Clear(v) => Some(v),
844 Camera3dDepthLoadOp::Load => None,
845 },
846 ));
847 }
848}
849
850#[derive(Component)]
851pub struct ViewTransmissionTexture {
852 pub texture: Texture,
853 pub view: TextureView,
854 pub sampler: Sampler,
855}
856
857pub fn prepare_core_3d_transmission_textures(
858 mut commands: Commands,
859 mut texture_cache: ResMut<TextureCache>,
860 render_device: Res<RenderDevice>,
861 opaque_3d_phases: Res<ViewBinnedRenderPhases<Opaque3d>>,
862 alpha_mask_3d_phases: Res<ViewBinnedRenderPhases<AlphaMask3d>>,
863 transmissive_3d_phases: Res<ViewSortedRenderPhases<Transmissive3d>>,
864 transparent_3d_phases: Res<ViewSortedRenderPhases<Transparent3d>>,
865 views_3d: Query<(Entity, &ExtractedCamera, &Camera3d, &ExtractedView)>,
866) {
867 let mut textures = <HashMap<_, _>>::default();
868 for (entity, camera, camera_3d, view) in &views_3d {
869 if !opaque_3d_phases.contains_key(&view.retained_view_entity)
870 || !alpha_mask_3d_phases.contains_key(&view.retained_view_entity)
871 || !transparent_3d_phases.contains_key(&view.retained_view_entity)
872 {
873 continue;
874 };
875
876 let Some(transmissive_3d_phase) = transmissive_3d_phases.get(&view.retained_view_entity)
877 else {
878 continue;
879 };
880
881 let Some(physical_target_size) = camera.physical_target_size else {
882 continue;
883 };
884
885 if camera_3d.screen_space_specular_transmission_steps == 0 {
887 continue;
888 }
889
890 if transmissive_3d_phase.items.is_empty() {
892 continue;
893 }
894
895 let cached_texture = textures
896 .entry(camera.target.clone())
897 .or_insert_with(|| {
898 let usage = TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST;
899
900 let size = Extent3d {
902 depth_or_array_layers: 1,
903 width: physical_target_size.x,
904 height: physical_target_size.y,
905 };
906
907 let format = if view.hdr {
908 ViewTarget::TEXTURE_FORMAT_HDR
909 } else {
910 TextureFormat::bevy_default()
911 };
912
913 let descriptor = TextureDescriptor {
914 label: Some("view_transmission_texture"),
915 size,
916 mip_level_count: 1,
917 sample_count: 1, dimension: TextureDimension::D2,
919 format,
920 usage,
921 view_formats: &[],
922 };
923
924 texture_cache.get(&render_device, descriptor)
925 })
926 .clone();
927
928 let sampler = render_device.create_sampler(&SamplerDescriptor {
929 label: Some("view_transmission_sampler"),
930 mag_filter: FilterMode::Linear,
931 min_filter: FilterMode::Linear,
932 ..Default::default()
933 });
934
935 commands.entity(entity).insert(ViewTransmissionTexture {
936 texture: cached_texture.texture,
937 view: cached_texture.default_view,
938 sampler,
939 });
940 }
941}
942
943fn configure_occlusion_culling_view_targets(
948 mut view_targets: Query<
949 &mut Camera3d,
950 (
951 With<OcclusionCulling>,
952 Without<NoIndirectDrawing>,
953 With<DepthPrepass>,
954 ),
955 >,
956) {
957 for mut camera_3d in &mut view_targets {
958 let mut depth_texture_usages = TextureUsages::from(camera_3d.depth_texture_usages);
959 depth_texture_usages |= TextureUsages::TEXTURE_BINDING;
960 camera_3d.depth_texture_usages = depth_texture_usages.into();
961 }
962}
963
964pub fn check_msaa(mut deferred_views: Query<&mut Msaa, (With<Camera>, With<DeferredPrepass>)>) {
966 for mut msaa in deferred_views.iter_mut() {
967 match *msaa {
968 Msaa::Off => (),
969 _ => {
970 warn!("MSAA is incompatible with deferred rendering and has been disabled.");
971 *msaa = Msaa::Off;
972 }
973 };
974 }
975}
976
977pub fn prepare_prepass_textures(
979 mut commands: Commands,
980 mut texture_cache: ResMut<TextureCache>,
981 render_device: Res<RenderDevice>,
982 opaque_3d_prepass_phases: Res<ViewBinnedRenderPhases<Opaque3dPrepass>>,
983 alpha_mask_3d_prepass_phases: Res<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
984 opaque_3d_deferred_phases: Res<ViewBinnedRenderPhases<Opaque3dDeferred>>,
985 alpha_mask_3d_deferred_phases: Res<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
986 views_3d: Query<(
987 Entity,
988 &ExtractedCamera,
989 &ExtractedView,
990 &Msaa,
991 Has<DepthPrepass>,
992 Has<NormalPrepass>,
993 Has<MotionVectorPrepass>,
994 Has<DeferredPrepass>,
995 )>,
996) {
997 let mut depth_textures = <HashMap<_, _>>::default();
998 let mut normal_textures = <HashMap<_, _>>::default();
999 let mut deferred_textures = <HashMap<_, _>>::default();
1000 let mut deferred_lighting_id_textures = <HashMap<_, _>>::default();
1001 let mut motion_vectors_textures = <HashMap<_, _>>::default();
1002 for (
1003 entity,
1004 camera,
1005 view,
1006 msaa,
1007 depth_prepass,
1008 normal_prepass,
1009 motion_vector_prepass,
1010 deferred_prepass,
1011 ) in &views_3d
1012 {
1013 if !opaque_3d_prepass_phases.contains_key(&view.retained_view_entity)
1014 && !alpha_mask_3d_prepass_phases.contains_key(&view.retained_view_entity)
1015 && !opaque_3d_deferred_phases.contains_key(&view.retained_view_entity)
1016 && !alpha_mask_3d_deferred_phases.contains_key(&view.retained_view_entity)
1017 {
1018 commands.entity(entity).remove::<ViewPrepassTextures>();
1019 continue;
1020 };
1021
1022 let Some(physical_target_size) = camera.physical_target_size else {
1023 continue;
1024 };
1025
1026 let size = Extent3d {
1027 depth_or_array_layers: 1,
1028 width: physical_target_size.x,
1029 height: physical_target_size.y,
1030 };
1031
1032 let cached_depth_texture = depth_prepass.then(|| {
1033 depth_textures
1034 .entry(camera.target.clone())
1035 .or_insert_with(|| {
1036 let descriptor = TextureDescriptor {
1037 label: Some("prepass_depth_texture"),
1038 size,
1039 mip_level_count: 1,
1040 sample_count: msaa.samples(),
1041 dimension: TextureDimension::D2,
1042 format: CORE_3D_DEPTH_FORMAT,
1043 usage: TextureUsages::COPY_DST
1044 | TextureUsages::RENDER_ATTACHMENT
1045 | TextureUsages::TEXTURE_BINDING,
1046 view_formats: &[],
1047 };
1048 texture_cache.get(&render_device, descriptor)
1049 })
1050 .clone()
1051 });
1052
1053 let cached_normals_texture = normal_prepass.then(|| {
1054 normal_textures
1055 .entry(camera.target.clone())
1056 .or_insert_with(|| {
1057 texture_cache.get(
1058 &render_device,
1059 TextureDescriptor {
1060 label: Some("prepass_normal_texture"),
1061 size,
1062 mip_level_count: 1,
1063 sample_count: msaa.samples(),
1064 dimension: TextureDimension::D2,
1065 format: NORMAL_PREPASS_FORMAT,
1066 usage: TextureUsages::RENDER_ATTACHMENT
1067 | TextureUsages::TEXTURE_BINDING,
1068 view_formats: &[],
1069 },
1070 )
1071 })
1072 .clone()
1073 });
1074
1075 let cached_motion_vectors_texture = motion_vector_prepass.then(|| {
1076 motion_vectors_textures
1077 .entry(camera.target.clone())
1078 .or_insert_with(|| {
1079 texture_cache.get(
1080 &render_device,
1081 TextureDescriptor {
1082 label: Some("prepass_motion_vectors_textures"),
1083 size,
1084 mip_level_count: 1,
1085 sample_count: msaa.samples(),
1086 dimension: TextureDimension::D2,
1087 format: MOTION_VECTOR_PREPASS_FORMAT,
1088 usage: TextureUsages::RENDER_ATTACHMENT
1089 | TextureUsages::TEXTURE_BINDING,
1090 view_formats: &[],
1091 },
1092 )
1093 })
1094 .clone()
1095 });
1096
1097 let cached_deferred_texture = deferred_prepass.then(|| {
1098 deferred_textures
1099 .entry(camera.target.clone())
1100 .or_insert_with(|| {
1101 texture_cache.get(
1102 &render_device,
1103 TextureDescriptor {
1104 label: Some("prepass_deferred_texture"),
1105 size,
1106 mip_level_count: 1,
1107 sample_count: 1,
1108 dimension: TextureDimension::D2,
1109 format: DEFERRED_PREPASS_FORMAT,
1110 usage: TextureUsages::RENDER_ATTACHMENT
1111 | TextureUsages::TEXTURE_BINDING,
1112 view_formats: &[],
1113 },
1114 )
1115 })
1116 .clone()
1117 });
1118
1119 let cached_deferred_lighting_pass_id_texture = deferred_prepass.then(|| {
1120 deferred_lighting_id_textures
1121 .entry(camera.target.clone())
1122 .or_insert_with(|| {
1123 texture_cache.get(
1124 &render_device,
1125 TextureDescriptor {
1126 label: Some("deferred_lighting_pass_id_texture"),
1127 size,
1128 mip_level_count: 1,
1129 sample_count: 1,
1130 dimension: TextureDimension::D2,
1131 format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
1132 usage: TextureUsages::RENDER_ATTACHMENT
1133 | TextureUsages::TEXTURE_BINDING,
1134 view_formats: &[],
1135 },
1136 )
1137 })
1138 .clone()
1139 });
1140
1141 commands.entity(entity).insert(ViewPrepassTextures {
1142 depth: cached_depth_texture
1143 .map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
1144 normal: cached_normals_texture
1145 .map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
1146 motion_vectors: cached_motion_vectors_texture
1150 .map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
1151 deferred: cached_deferred_texture
1152 .map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
1153 deferred_lighting_pass_id: cached_deferred_lighting_pass_id_texture
1154 .map(|t| ColorAttachment::new(t, None, Some(LinearRgba::BLACK))),
1155 size,
1156 });
1157 }
1158}