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