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_diagnostic::FrameCount;
77use bevy_render::{
78 batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport},
79 camera::CameraRenderGraph,
80 experimental::occlusion_culling::OcclusionCulling,
81 mesh::allocator::SlabId,
82 render_phase::PhaseItemBatchSetKey,
83 texture::CachedTexture,
84 view::{prepare_view_targets, NoIndirectDrawing, RetainedViewEntity},
85};
86pub use main_opaque_pass_3d_node::*;
87pub use main_transparent_pass_3d_node::*;
88
89use bevy_app::{App, Plugin, PostUpdate};
90use bevy_asset::UntypedAssetId;
91use bevy_color::LinearRgba;
92use bevy_ecs::prelude::*;
93use bevy_image::{BevyDefault, ToExtents};
94use bevy_math::FloatOrd;
95use bevy_platform::collections::{HashMap, HashSet};
96use bevy_render::{
97 camera::ExtractedCamera,
98 extract_component::ExtractComponentPlugin,
99 prelude::Msaa,
100 render_graph::{EmptyNode, RenderGraphExt, ViewNodeRunner},
101 render_phase::{
102 sort_phase_system, BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId,
103 DrawFunctions, PhaseItem, PhaseItemExtraIndex, SortedPhaseItem, ViewBinnedRenderPhases,
104 ViewSortedRenderPhases,
105 },
106 render_resource::{
107 CachedRenderPipelineId, FilterMode, Sampler, SamplerDescriptor, Texture, TextureDescriptor,
108 TextureDimension, TextureFormat, TextureUsages, TextureView,
109 },
110 renderer::RenderDevice,
111 sync_world::{MainEntity, RenderEntity},
112 texture::{ColorAttachment, TextureCache},
113 view::{ExtractedView, ViewDepthTexture, ViewTarget},
114 Extract, ExtractSchedule, Render, RenderApp, RenderSystems,
115};
116use nonmax::NonMaxU32;
117use tracing::warn;
118
119use crate::{
120 core_3d::main_transmissive_pass_3d_node::MainTransmissivePass3dNode,
121 deferred::{
122 copy_lighting_id::CopyDeferredLightingIdNode,
123 node::{EarlyDeferredGBufferPrepassNode, LateDeferredGBufferPrepassNode},
124 AlphaMask3dDeferred, Opaque3dDeferred, DEFERRED_LIGHTING_PASS_ID_FORMAT,
125 DEFERRED_PREPASS_FORMAT,
126 },
127 prepass::{
128 node::{EarlyPrepassNode, LatePrepassNode},
129 AlphaMask3dPrepass, DeferredPrepass, DeferredPrepassDoubleBuffer, DepthPrepass,
130 DepthPrepassDoubleBuffer, MotionVectorPrepass, NormalPrepass, Opaque3dPrepass,
131 OpaqueNoLightmap3dBatchSetKey, OpaqueNoLightmap3dBinKey, ViewPrepassTextures,
132 MOTION_VECTOR_PREPASS_FORMAT, NORMAL_PREPASS_FORMAT,
133 },
134 skybox::SkyboxPlugin,
135 tonemapping::{DebandDither, Tonemapping, TonemappingNode},
136 upscaling::UpscalingNode,
137};
138
139use self::graph::{Core3d, Node3d};
140
141pub struct Core3dPlugin;
142
143impl Plugin for Core3dPlugin {
144 fn build(&self, app: &mut App) {
145 app.register_required_components_with::<Camera3d, DebandDither>(|| DebandDither::Enabled)
146 .register_required_components_with::<Camera3d, CameraRenderGraph>(|| {
147 CameraRenderGraph::new(Core3d)
148 })
149 .register_required_components::<Camera3d, Tonemapping>()
150 .add_plugins((SkyboxPlugin, ExtractComponentPlugin::<Camera3d>::default()))
151 .add_systems(PostUpdate, check_msaa);
152
153 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
154 return;
155 };
156 render_app
157 .init_resource::<DrawFunctions<Opaque3d>>()
158 .init_resource::<DrawFunctions<AlphaMask3d>>()
159 .init_resource::<DrawFunctions<Transmissive3d>>()
160 .init_resource::<DrawFunctions<Transparent3d>>()
161 .init_resource::<DrawFunctions<Opaque3dPrepass>>()
162 .init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
163 .init_resource::<DrawFunctions<Opaque3dDeferred>>()
164 .init_resource::<DrawFunctions<AlphaMask3dDeferred>>()
165 .init_resource::<ViewBinnedRenderPhases<Opaque3d>>()
166 .init_resource::<ViewBinnedRenderPhases<AlphaMask3d>>()
167 .init_resource::<ViewBinnedRenderPhases<Opaque3dPrepass>>()
168 .init_resource::<ViewBinnedRenderPhases<AlphaMask3dPrepass>>()
169 .init_resource::<ViewBinnedRenderPhases<Opaque3dDeferred>>()
170 .init_resource::<ViewBinnedRenderPhases<AlphaMask3dDeferred>>()
171 .init_resource::<ViewSortedRenderPhases<Transmissive3d>>()
172 .init_resource::<ViewSortedRenderPhases<Transparent3d>>()
173 .add_systems(ExtractSchedule, extract_core_3d_camera_phases)
174 .add_systems(ExtractSchedule, extract_camera_prepass_phase)
175 .add_systems(
176 Render,
177 (
178 sort_phase_system::<Transmissive3d>.in_set(RenderSystems::PhaseSort),
179 sort_phase_system::<Transparent3d>.in_set(RenderSystems::PhaseSort),
180 configure_occlusion_culling_view_targets
181 .after(prepare_view_targets)
182 .in_set(RenderSystems::ManageViews),
183 prepare_core_3d_depth_textures.in_set(RenderSystems::PrepareResources),
184 prepare_core_3d_transmission_textures.in_set(RenderSystems::PrepareResources),
185 prepare_prepass_textures.in_set(RenderSystems::PrepareResources),
186 ),
187 );
188
189 render_app
190 .add_render_sub_graph(Core3d)
191 .add_render_graph_node::<ViewNodeRunner<EarlyPrepassNode>>(Core3d, Node3d::EarlyPrepass)
192 .add_render_graph_node::<ViewNodeRunner<LatePrepassNode>>(Core3d, Node3d::LatePrepass)
193 .add_render_graph_node::<ViewNodeRunner<EarlyDeferredGBufferPrepassNode>>(
194 Core3d,
195 Node3d::EarlyDeferredPrepass,
196 )
197 .add_render_graph_node::<ViewNodeRunner<LateDeferredGBufferPrepassNode>>(
198 Core3d,
199 Node3d::LateDeferredPrepass,
200 )
201 .add_render_graph_node::<ViewNodeRunner<CopyDeferredLightingIdNode>>(
202 Core3d,
203 Node3d::CopyDeferredLightingId,
204 )
205 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::EndPrepasses)
206 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::StartMainPass)
207 .add_render_graph_node::<ViewNodeRunner<MainOpaquePass3dNode>>(
208 Core3d,
209 Node3d::MainOpaquePass,
210 )
211 .add_render_graph_node::<ViewNodeRunner<MainTransmissivePass3dNode>>(
212 Core3d,
213 Node3d::MainTransmissivePass,
214 )
215 .add_render_graph_node::<ViewNodeRunner<MainTransparentPass3dNode>>(
216 Core3d,
217 Node3d::MainTransparentPass,
218 )
219 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::EndMainPass)
220 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::StartMainPassPostProcessing)
221 .add_render_graph_node::<ViewNodeRunner<TonemappingNode>>(Core3d, Node3d::Tonemapping)
222 .add_render_graph_node::<EmptyNode>(Core3d, Node3d::EndMainPassPostProcessing)
223 .add_render_graph_node::<ViewNodeRunner<UpscalingNode>>(Core3d, Node3d::Upscaling)
224 .add_render_graph_edges(
225 Core3d,
226 (
227 Node3d::EarlyPrepass,
228 Node3d::EarlyDeferredPrepass,
229 Node3d::LatePrepass,
230 Node3d::LateDeferredPrepass,
231 Node3d::CopyDeferredLightingId,
232 Node3d::EndPrepasses,
233 Node3d::StartMainPass,
234 Node3d::MainOpaquePass,
235 Node3d::MainTransmissivePass,
236 Node3d::MainTransparentPass,
237 Node3d::EndMainPass,
238 Node3d::StartMainPassPostProcessing,
239 Node3d::Tonemapping,
240 Node3d::EndMainPassPostProcessing,
241 Node3d::Upscaling,
242 ),
243 );
244 }
245}
246
247pub struct Opaque3d {
249 pub batch_set_key: Opaque3dBatchSetKey,
254 pub bin_key: Opaque3dBinKey,
256 pub representative_entity: (Entity, MainEntity),
259 pub batch_range: Range<u32>,
261 pub extra_index: PhaseItemExtraIndex,
264}
265
266#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
272pub struct Opaque3dBatchSetKey {
273 pub pipeline: CachedRenderPipelineId,
275
276 pub draw_function: DrawFunctionId,
278
279 pub material_bind_group_index: Option<u32>,
283
284 pub vertex_slab: SlabId,
289
290 pub index_slab: Option<SlabId>,
294
295 pub lightmap_slab: Option<NonMaxU32>,
298}
299
300impl PhaseItemBatchSetKey for Opaque3dBatchSetKey {
301 fn indexed(&self) -> bool {
302 self.index_slab.is_some()
303 }
304}
305
306#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
310pub struct Opaque3dBinKey {
311 pub asset_id: UntypedAssetId,
316}
317
318impl PhaseItem for Opaque3d {
319 #[inline]
320 fn entity(&self) -> Entity {
321 self.representative_entity.0
322 }
323
324 #[inline]
325 fn main_entity(&self) -> MainEntity {
326 self.representative_entity.1
327 }
328
329 #[inline]
330 fn draw_function(&self) -> DrawFunctionId {
331 self.batch_set_key.draw_function
332 }
333
334 #[inline]
335 fn batch_range(&self) -> &Range<u32> {
336 &self.batch_range
337 }
338
339 #[inline]
340 fn batch_range_mut(&mut self) -> &mut Range<u32> {
341 &mut self.batch_range
342 }
343
344 fn extra_index(&self) -> PhaseItemExtraIndex {
345 self.extra_index.clone()
346 }
347
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 Opaque3d {
354 type BatchSetKey = Opaque3dBatchSetKey;
355 type BinKey = Opaque3dBinKey;
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 Opaque3d {
366 batch_set_key,
367 bin_key,
368 representative_entity,
369 batch_range,
370 extra_index,
371 }
372 }
373}
374
375impl CachedRenderPipelinePhaseItem for Opaque3d {
376 #[inline]
377 fn cached_pipeline(&self) -> CachedRenderPipelineId {
378 self.batch_set_key.pipeline
379 }
380}
381
382pub struct AlphaMask3d {
383 pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
388 pub bin_key: OpaqueNoLightmap3dBinKey,
390 pub representative_entity: (Entity, MainEntity),
391 pub batch_range: Range<u32>,
392 pub extra_index: PhaseItemExtraIndex,
393}
394
395impl PhaseItem for AlphaMask3d {
396 #[inline]
397 fn entity(&self) -> Entity {
398 self.representative_entity.0
399 }
400
401 fn main_entity(&self) -> MainEntity {
402 self.representative_entity.1
403 }
404
405 #[inline]
406 fn draw_function(&self) -> DrawFunctionId {
407 self.batch_set_key.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 BinnedPhaseItem for AlphaMask3d {
432 type BinKey = OpaqueNoLightmap3dBinKey;
433 type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
434
435 #[inline]
436 fn new(
437 batch_set_key: Self::BatchSetKey,
438 bin_key: Self::BinKey,
439 representative_entity: (Entity, MainEntity),
440 batch_range: Range<u32>,
441 extra_index: PhaseItemExtraIndex,
442 ) -> Self {
443 Self {
444 batch_set_key,
445 bin_key,
446 representative_entity,
447 batch_range,
448 extra_index,
449 }
450 }
451}
452
453impl CachedRenderPipelinePhaseItem for AlphaMask3d {
454 #[inline]
455 fn cached_pipeline(&self) -> CachedRenderPipelineId {
456 self.batch_set_key.pipeline
457 }
458}
459
460pub struct Transmissive3d {
461 pub distance: f32,
462 pub pipeline: CachedRenderPipelineId,
463 pub entity: (Entity, MainEntity),
464 pub draw_function: DrawFunctionId,
465 pub batch_range: Range<u32>,
466 pub extra_index: PhaseItemExtraIndex,
467 pub indexed: bool,
470}
471
472impl PhaseItem for Transmissive3d {
473 const AUTOMATIC_BATCHING: bool = false;
483
484 #[inline]
485 fn entity(&self) -> Entity {
486 self.entity.0
487 }
488
489 #[inline]
490 fn main_entity(&self) -> MainEntity {
491 self.entity.1
492 }
493
494 #[inline]
495 fn draw_function(&self) -> DrawFunctionId {
496 self.draw_function
497 }
498
499 #[inline]
500 fn batch_range(&self) -> &Range<u32> {
501 &self.batch_range
502 }
503
504 #[inline]
505 fn batch_range_mut(&mut self) -> &mut Range<u32> {
506 &mut self.batch_range
507 }
508
509 #[inline]
510 fn extra_index(&self) -> PhaseItemExtraIndex {
511 self.extra_index.clone()
512 }
513
514 #[inline]
515 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
516 (&mut self.batch_range, &mut self.extra_index)
517 }
518}
519
520impl SortedPhaseItem for Transmissive3d {
521 type SortKey = FloatOrd;
523
524 #[inline]
525 fn sort_key(&self) -> Self::SortKey {
526 FloatOrd(self.distance)
527 }
528
529 #[inline]
530 fn sort(items: &mut [Self]) {
531 radsort::sort_by_key(items, |item| item.distance);
532 }
533
534 #[inline]
535 fn indexed(&self) -> bool {
536 self.indexed
537 }
538}
539
540impl CachedRenderPipelinePhaseItem for Transmissive3d {
541 #[inline]
542 fn cached_pipeline(&self) -> CachedRenderPipelineId {
543 self.pipeline
544 }
545}
546
547pub struct Transparent3d {
548 pub distance: f32,
549 pub pipeline: CachedRenderPipelineId,
550 pub entity: (Entity, MainEntity),
551 pub draw_function: DrawFunctionId,
552 pub batch_range: Range<u32>,
553 pub extra_index: PhaseItemExtraIndex,
554 pub indexed: bool,
557}
558
559impl PhaseItem for Transparent3d {
560 #[inline]
561 fn entity(&self) -> Entity {
562 self.entity.0
563 }
564
565 fn main_entity(&self) -> MainEntity {
566 self.entity.1
567 }
568
569 #[inline]
570 fn draw_function(&self) -> DrawFunctionId {
571 self.draw_function
572 }
573
574 #[inline]
575 fn batch_range(&self) -> &Range<u32> {
576 &self.batch_range
577 }
578
579 #[inline]
580 fn batch_range_mut(&mut self) -> &mut Range<u32> {
581 &mut self.batch_range
582 }
583
584 #[inline]
585 fn extra_index(&self) -> PhaseItemExtraIndex {
586 self.extra_index.clone()
587 }
588
589 #[inline]
590 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
591 (&mut self.batch_range, &mut self.extra_index)
592 }
593}
594
595impl SortedPhaseItem for Transparent3d {
596 type SortKey = FloatOrd;
598
599 #[inline]
600 fn sort_key(&self) -> Self::SortKey {
601 FloatOrd(self.distance)
602 }
603
604 #[inline]
605 fn sort(items: &mut [Self]) {
606 radsort::sort_by_key(items, |item| item.distance);
607 }
608
609 #[inline]
610 fn indexed(&self) -> bool {
611 self.indexed
612 }
613}
614
615impl CachedRenderPipelinePhaseItem for Transparent3d {
616 #[inline]
617 fn cached_pipeline(&self) -> CachedRenderPipelineId {
618 self.pipeline
619 }
620}
621
622pub fn extract_core_3d_camera_phases(
623 mut opaque_3d_phases: ResMut<ViewBinnedRenderPhases<Opaque3d>>,
624 mut alpha_mask_3d_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3d>>,
625 mut transmissive_3d_phases: ResMut<ViewSortedRenderPhases<Transmissive3d>>,
626 mut transparent_3d_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
627 cameras_3d: Extract<Query<(Entity, &Camera, Has<NoIndirectDrawing>), With<Camera3d>>>,
628 mut live_entities: Local<HashSet<RetainedViewEntity>>,
629 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
630) {
631 live_entities.clear();
632
633 for (main_entity, camera, no_indirect_drawing) in &cameras_3d {
634 if !camera.is_active {
635 continue;
636 }
637
638 let gpu_preprocessing_mode = gpu_preprocessing_support.min(if !no_indirect_drawing {
641 GpuPreprocessingMode::Culling
642 } else {
643 GpuPreprocessingMode::PreprocessingOnly
644 });
645
646 let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
648
649 opaque_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
650 alpha_mask_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
651 transmissive_3d_phases.insert_or_clear(retained_view_entity);
652 transparent_3d_phases.insert_or_clear(retained_view_entity);
653
654 live_entities.insert(retained_view_entity);
655 }
656
657 opaque_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
658 alpha_mask_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
659 transmissive_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
660 transparent_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
661}
662
663pub fn extract_camera_prepass_phase(
666 mut commands: Commands,
667 mut opaque_3d_prepass_phases: ResMut<ViewBinnedRenderPhases<Opaque3dPrepass>>,
668 mut alpha_mask_3d_prepass_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
669 mut opaque_3d_deferred_phases: ResMut<ViewBinnedRenderPhases<Opaque3dDeferred>>,
670 mut alpha_mask_3d_deferred_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
671 cameras_3d: Extract<
672 Query<
673 (
674 Entity,
675 RenderEntity,
676 &Camera,
677 Has<NoIndirectDrawing>,
678 Has<DepthPrepass>,
679 Has<NormalPrepass>,
680 Has<MotionVectorPrepass>,
681 Has<DeferredPrepass>,
682 Has<DepthPrepassDoubleBuffer>,
683 Has<DeferredPrepassDoubleBuffer>,
684 ),
685 With<Camera3d>,
686 >,
687 >,
688 mut live_entities: Local<HashSet<RetainedViewEntity>>,
689 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
690) {
691 live_entities.clear();
692
693 for (
694 main_entity,
695 entity,
696 camera,
697 no_indirect_drawing,
698 depth_prepass,
699 normal_prepass,
700 motion_vector_prepass,
701 deferred_prepass,
702 depth_prepass_double_buffer,
703 deferred_prepass_double_buffer,
704 ) in cameras_3d.iter()
705 {
706 if !camera.is_active {
707 continue;
708 }
709
710 let gpu_preprocessing_mode = gpu_preprocessing_support.min(if !no_indirect_drawing {
713 GpuPreprocessingMode::Culling
714 } else {
715 GpuPreprocessingMode::PreprocessingOnly
716 });
717
718 let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
720
721 if depth_prepass || normal_prepass || motion_vector_prepass {
722 opaque_3d_prepass_phases
723 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
724 alpha_mask_3d_prepass_phases
725 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
726 } else {
727 opaque_3d_prepass_phases.remove(&retained_view_entity);
728 alpha_mask_3d_prepass_phases.remove(&retained_view_entity);
729 }
730
731 if deferred_prepass {
732 opaque_3d_deferred_phases
733 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
734 alpha_mask_3d_deferred_phases
735 .prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
736 } else {
737 opaque_3d_deferred_phases.remove(&retained_view_entity);
738 alpha_mask_3d_deferred_phases.remove(&retained_view_entity);
739 }
740 live_entities.insert(retained_view_entity);
741
742 let mut camera_commands = commands
745 .get_entity(entity)
746 .expect("Camera entity wasn't synced.");
747
748 if depth_prepass {
749 camera_commands.insert(DepthPrepass);
750 } else {
751 camera_commands.remove::<DepthPrepass>();
752 }
753
754 if normal_prepass {
755 camera_commands.insert(NormalPrepass);
756 } else {
757 camera_commands.remove::<NormalPrepass>();
758 }
759
760 if motion_vector_prepass {
761 camera_commands.insert(MotionVectorPrepass);
762 } else {
763 camera_commands.remove::<MotionVectorPrepass>();
764 }
765
766 if deferred_prepass {
767 camera_commands.insert(DeferredPrepass);
768 } else {
769 camera_commands.remove::<DeferredPrepass>();
770 }
771
772 if depth_prepass_double_buffer {
773 camera_commands.insert(DepthPrepassDoubleBuffer);
774 } else {
775 camera_commands.remove::<DepthPrepassDoubleBuffer>();
776 }
777
778 if deferred_prepass_double_buffer {
779 camera_commands.insert(DeferredPrepassDoubleBuffer);
780 } else {
781 camera_commands.remove::<DeferredPrepassDoubleBuffer>();
782 }
783 }
784
785 opaque_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
786 alpha_mask_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
787 opaque_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
788 alpha_mask_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
789}
790
791pub fn prepare_core_3d_depth_textures(
792 mut commands: Commands,
793 mut texture_cache: ResMut<TextureCache>,
794 render_device: Res<RenderDevice>,
795 opaque_3d_phases: Res<ViewBinnedRenderPhases<Opaque3d>>,
796 alpha_mask_3d_phases: Res<ViewBinnedRenderPhases<AlphaMask3d>>,
797 transmissive_3d_phases: Res<ViewSortedRenderPhases<Transmissive3d>>,
798 transparent_3d_phases: Res<ViewSortedRenderPhases<Transparent3d>>,
799 views_3d: Query<(
800 Entity,
801 &ExtractedCamera,
802 &ExtractedView,
803 Option<&DepthPrepass>,
804 &Camera3d,
805 &Msaa,
806 )>,
807) {
808 let mut render_target_usage = <HashMap<_, _>>::default();
809 for (_, camera, extracted_view, depth_prepass, camera_3d, _msaa) in &views_3d {
810 if !opaque_3d_phases.contains_key(&extracted_view.retained_view_entity)
811 || !alpha_mask_3d_phases.contains_key(&extracted_view.retained_view_entity)
812 || !transmissive_3d_phases.contains_key(&extracted_view.retained_view_entity)
813 || !transparent_3d_phases.contains_key(&extracted_view.retained_view_entity)
814 {
815 continue;
816 };
817
818 let mut usage: TextureUsages = camera_3d.depth_texture_usages.into();
820 if depth_prepass.is_some() {
821 usage |= TextureUsages::COPY_SRC;
823 }
824 render_target_usage
825 .entry(camera.target.clone())
826 .and_modify(|u| *u |= usage)
827 .or_insert_with(|| usage);
828 }
829
830 let mut textures = <HashMap<_, _>>::default();
831 for (entity, camera, _, _, camera_3d, msaa) in &views_3d {
832 let Some(physical_target_size) = camera.physical_target_size else {
833 continue;
834 };
835
836 let cached_texture = textures
837 .entry((camera.target.clone(), msaa))
838 .or_insert_with(|| {
839 let usage = *render_target_usage
840 .get(&camera.target.clone())
841 .expect("The depth texture usage should already exist for this target");
842
843 let descriptor = TextureDescriptor {
844 label: Some("view_depth_texture"),
845 size: physical_target_size.to_extents(),
847 mip_level_count: 1,
848 sample_count: msaa.samples(),
849 dimension: TextureDimension::D2,
850 format: CORE_3D_DEPTH_FORMAT,
851 usage,
852 view_formats: &[],
853 };
854
855 texture_cache.get(&render_device, descriptor)
856 })
857 .clone();
858
859 commands.entity(entity).insert(ViewDepthTexture::new(
860 cached_texture,
861 match camera_3d.depth_load_op {
862 Camera3dDepthLoadOp::Clear(v) => Some(v),
863 Camera3dDepthLoadOp::Load => None,
864 },
865 ));
866 }
867}
868
869#[derive(Component)]
870pub struct ViewTransmissionTexture {
871 pub texture: Texture,
872 pub view: TextureView,
873 pub sampler: Sampler,
874}
875
876pub fn prepare_core_3d_transmission_textures(
877 mut commands: Commands,
878 mut texture_cache: ResMut<TextureCache>,
879 render_device: Res<RenderDevice>,
880 opaque_3d_phases: Res<ViewBinnedRenderPhases<Opaque3d>>,
881 alpha_mask_3d_phases: Res<ViewBinnedRenderPhases<AlphaMask3d>>,
882 transmissive_3d_phases: Res<ViewSortedRenderPhases<Transmissive3d>>,
883 transparent_3d_phases: Res<ViewSortedRenderPhases<Transparent3d>>,
884 views_3d: Query<(Entity, &ExtractedCamera, &Camera3d, &ExtractedView)>,
885) {
886 let mut textures = <HashMap<_, _>>::default();
887 for (entity, camera, camera_3d, view) in &views_3d {
888 if !opaque_3d_phases.contains_key(&view.retained_view_entity)
889 || !alpha_mask_3d_phases.contains_key(&view.retained_view_entity)
890 || !transparent_3d_phases.contains_key(&view.retained_view_entity)
891 {
892 continue;
893 };
894
895 let Some(transmissive_3d_phase) = transmissive_3d_phases.get(&view.retained_view_entity)
896 else {
897 continue;
898 };
899
900 let Some(physical_target_size) = camera.physical_target_size else {
901 continue;
902 };
903
904 if camera_3d.screen_space_specular_transmission_steps == 0 {
906 continue;
907 }
908
909 if transmissive_3d_phase.items.is_empty() {
911 continue;
912 }
913
914 let cached_texture = textures
915 .entry(camera.target.clone())
916 .or_insert_with(|| {
917 let usage = TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST;
918
919 let format = if view.hdr {
920 ViewTarget::TEXTURE_FORMAT_HDR
921 } else {
922 TextureFormat::bevy_default()
923 };
924
925 let descriptor = TextureDescriptor {
926 label: Some("view_transmission_texture"),
927 size: physical_target_size.to_extents(),
929 mip_level_count: 1,
930 sample_count: 1, dimension: TextureDimension::D2,
932 format,
933 usage,
934 view_formats: &[],
935 };
936
937 texture_cache.get(&render_device, descriptor)
938 })
939 .clone();
940
941 let sampler = render_device.create_sampler(&SamplerDescriptor {
942 label: Some("view_transmission_sampler"),
943 mag_filter: FilterMode::Linear,
944 min_filter: FilterMode::Linear,
945 ..Default::default()
946 });
947
948 commands.entity(entity).insert(ViewTransmissionTexture {
949 texture: cached_texture.texture,
950 view: cached_texture.default_view,
951 sampler,
952 });
953 }
954}
955
956fn configure_occlusion_culling_view_targets(
961 mut view_targets: Query<
962 &mut Camera3d,
963 (
964 With<OcclusionCulling>,
965 Without<NoIndirectDrawing>,
966 With<DepthPrepass>,
967 ),
968 >,
969) {
970 for mut camera_3d in &mut view_targets {
971 let mut depth_texture_usages = TextureUsages::from(camera_3d.depth_texture_usages);
972 depth_texture_usages |= TextureUsages::TEXTURE_BINDING;
973 camera_3d.depth_texture_usages = depth_texture_usages.into();
974 }
975}
976
977pub fn check_msaa(mut deferred_views: Query<&mut Msaa, (With<Camera>, With<DeferredPrepass>)>) {
979 for mut msaa in deferred_views.iter_mut() {
980 match *msaa {
981 Msaa::Off => (),
982 _ => {
983 warn!("MSAA is incompatible with deferred rendering and has been disabled.");
984 *msaa = Msaa::Off;
985 }
986 };
987 }
988}
989
990pub fn prepare_prepass_textures(
992 mut commands: Commands,
993 mut texture_cache: ResMut<TextureCache>,
994 render_device: Res<RenderDevice>,
995 frame_count: Res<FrameCount>,
996 opaque_3d_prepass_phases: Res<ViewBinnedRenderPhases<Opaque3dPrepass>>,
997 alpha_mask_3d_prepass_phases: Res<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
998 opaque_3d_deferred_phases: Res<ViewBinnedRenderPhases<Opaque3dDeferred>>,
999 alpha_mask_3d_deferred_phases: Res<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
1000 views_3d: Query<(
1001 Entity,
1002 &ExtractedCamera,
1003 &ExtractedView,
1004 &Msaa,
1005 Has<DepthPrepass>,
1006 Has<NormalPrepass>,
1007 Has<MotionVectorPrepass>,
1008 Has<DeferredPrepass>,
1009 Has<DepthPrepassDoubleBuffer>,
1010 Has<DeferredPrepassDoubleBuffer>,
1011 )>,
1012) {
1013 let mut depth_textures1 = <HashMap<_, _>>::default();
1014 let mut depth_textures2 = <HashMap<_, _>>::default();
1015 let mut normal_textures = <HashMap<_, _>>::default();
1016 let mut deferred_textures1: HashMap<_, _> = <HashMap<_, _>>::default();
1017 let mut deferred_textures2: HashMap<_, _> = <HashMap<_, _>>::default();
1018 let mut deferred_lighting_id_textures = <HashMap<_, _>>::default();
1019 let mut motion_vectors_textures = <HashMap<_, _>>::default();
1020 for (
1021 entity,
1022 camera,
1023 view,
1024 msaa,
1025 depth_prepass,
1026 normal_prepass,
1027 motion_vector_prepass,
1028 deferred_prepass,
1029 depth_prepass_double_buffer,
1030 deferred_prepass_double_buffer,
1031 ) in &views_3d
1032 {
1033 if !opaque_3d_prepass_phases.contains_key(&view.retained_view_entity)
1034 && !alpha_mask_3d_prepass_phases.contains_key(&view.retained_view_entity)
1035 && !opaque_3d_deferred_phases.contains_key(&view.retained_view_entity)
1036 && !alpha_mask_3d_deferred_phases.contains_key(&view.retained_view_entity)
1037 {
1038 commands.entity(entity).remove::<ViewPrepassTextures>();
1039 continue;
1040 };
1041
1042 let Some(physical_target_size) = camera.physical_target_size else {
1043 continue;
1044 };
1045
1046 let size = physical_target_size.to_extents();
1047
1048 let cached_depth_texture1 = depth_prepass.then(|| {
1049 depth_textures1
1050 .entry(camera.target.clone())
1051 .or_insert_with(|| {
1052 let descriptor = TextureDescriptor {
1053 label: Some("prepass_depth_texture_1"),
1054 size,
1055 mip_level_count: 1,
1056 sample_count: msaa.samples(),
1057 dimension: TextureDimension::D2,
1058 format: CORE_3D_DEPTH_FORMAT,
1059 usage: TextureUsages::COPY_DST
1060 | TextureUsages::RENDER_ATTACHMENT
1061 | TextureUsages::TEXTURE_BINDING,
1062 view_formats: &[],
1063 };
1064 texture_cache.get(&render_device, descriptor)
1065 })
1066 .clone()
1067 });
1068
1069 let cached_depth_texture2 = depth_prepass_double_buffer.then(|| {
1070 depth_textures2
1071 .entry(camera.target.clone())
1072 .or_insert_with(|| {
1073 let descriptor = TextureDescriptor {
1074 label: Some("prepass_depth_texture_2"),
1075 size,
1076 mip_level_count: 1,
1077 sample_count: msaa.samples(),
1078 dimension: TextureDimension::D2,
1079 format: CORE_3D_DEPTH_FORMAT,
1080 usage: TextureUsages::COPY_DST
1081 | TextureUsages::RENDER_ATTACHMENT
1082 | TextureUsages::TEXTURE_BINDING,
1083 view_formats: &[],
1084 };
1085 texture_cache.get(&render_device, descriptor)
1086 })
1087 .clone()
1088 });
1089
1090 let cached_normals_texture = normal_prepass.then(|| {
1091 normal_textures
1092 .entry(camera.target.clone())
1093 .or_insert_with(|| {
1094 texture_cache.get(
1095 &render_device,
1096 TextureDescriptor {
1097 label: Some("prepass_normal_texture"),
1098 size,
1099 mip_level_count: 1,
1100 sample_count: msaa.samples(),
1101 dimension: TextureDimension::D2,
1102 format: NORMAL_PREPASS_FORMAT,
1103 usage: TextureUsages::RENDER_ATTACHMENT
1104 | TextureUsages::TEXTURE_BINDING,
1105 view_formats: &[],
1106 },
1107 )
1108 })
1109 .clone()
1110 });
1111
1112 let cached_motion_vectors_texture = motion_vector_prepass.then(|| {
1113 motion_vectors_textures
1114 .entry(camera.target.clone())
1115 .or_insert_with(|| {
1116 texture_cache.get(
1117 &render_device,
1118 TextureDescriptor {
1119 label: Some("prepass_motion_vectors_textures"),
1120 size,
1121 mip_level_count: 1,
1122 sample_count: msaa.samples(),
1123 dimension: TextureDimension::D2,
1124 format: MOTION_VECTOR_PREPASS_FORMAT,
1125 usage: TextureUsages::RENDER_ATTACHMENT
1126 | TextureUsages::TEXTURE_BINDING,
1127 view_formats: &[],
1128 },
1129 )
1130 })
1131 .clone()
1132 });
1133
1134 let cached_deferred_texture1 = deferred_prepass.then(|| {
1135 deferred_textures1
1136 .entry(camera.target.clone())
1137 .or_insert_with(|| {
1138 texture_cache.get(
1139 &render_device,
1140 TextureDescriptor {
1141 label: Some("prepass_deferred_texture_1"),
1142 size,
1143 mip_level_count: 1,
1144 sample_count: 1,
1145 dimension: TextureDimension::D2,
1146 format: DEFERRED_PREPASS_FORMAT,
1147 usage: TextureUsages::RENDER_ATTACHMENT
1148 | TextureUsages::TEXTURE_BINDING,
1149 view_formats: &[],
1150 },
1151 )
1152 })
1153 .clone()
1154 });
1155
1156 let cached_deferred_texture2 = deferred_prepass_double_buffer.then(|| {
1157 deferred_textures2
1158 .entry(camera.target.clone())
1159 .or_insert_with(|| {
1160 texture_cache.get(
1161 &render_device,
1162 TextureDescriptor {
1163 label: Some("prepass_deferred_texture_2"),
1164 size,
1165 mip_level_count: 1,
1166 sample_count: 1,
1167 dimension: TextureDimension::D2,
1168 format: DEFERRED_PREPASS_FORMAT,
1169 usage: TextureUsages::RENDER_ATTACHMENT
1170 | TextureUsages::TEXTURE_BINDING,
1171 view_formats: &[],
1172 },
1173 )
1174 })
1175 .clone()
1176 });
1177
1178 let cached_deferred_lighting_pass_id_texture = deferred_prepass.then(|| {
1179 deferred_lighting_id_textures
1180 .entry(camera.target.clone())
1181 .or_insert_with(|| {
1182 texture_cache.get(
1183 &render_device,
1184 TextureDescriptor {
1185 label: Some("deferred_lighting_pass_id_texture"),
1186 size,
1187 mip_level_count: 1,
1188 sample_count: 1,
1189 dimension: TextureDimension::D2,
1190 format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
1191 usage: TextureUsages::RENDER_ATTACHMENT
1192 | TextureUsages::TEXTURE_BINDING,
1193 view_formats: &[],
1194 },
1195 )
1196 })
1197 .clone()
1198 });
1199
1200 commands.entity(entity).insert(ViewPrepassTextures {
1201 depth: package_double_buffered_texture(
1202 cached_depth_texture1,
1203 cached_depth_texture2,
1204 frame_count.0,
1205 ),
1206 normal: cached_normals_texture
1207 .map(|t| ColorAttachment::new(t, None, None, Some(LinearRgba::BLACK))),
1208 motion_vectors: cached_motion_vectors_texture
1212 .map(|t| ColorAttachment::new(t, None, None, Some(LinearRgba::BLACK))),
1213 deferred: package_double_buffered_texture(
1214 cached_deferred_texture1,
1215 cached_deferred_texture2,
1216 frame_count.0,
1217 ),
1218 deferred_lighting_pass_id: cached_deferred_lighting_pass_id_texture
1219 .map(|t| ColorAttachment::new(t, None, None, Some(LinearRgba::BLACK))),
1220 size,
1221 });
1222 }
1223}
1224
1225fn package_double_buffered_texture(
1226 texture1: Option<CachedTexture>,
1227 texture2: Option<CachedTexture>,
1228 frame_count: u32,
1229) -> Option<ColorAttachment> {
1230 match (texture1, texture2) {
1231 (Some(t1), None) => Some(ColorAttachment::new(
1232 t1,
1233 None,
1234 None,
1235 Some(LinearRgba::BLACK),
1236 )),
1237 (Some(t1), Some(t2)) if frame_count.is_multiple_of(2) => Some(ColorAttachment::new(
1238 t1,
1239 None,
1240 Some(t2),
1241 Some(LinearRgba::BLACK),
1242 )),
1243 (Some(t1), Some(t2)) => Some(ColorAttachment::new(
1244 t2,
1245 None,
1246 Some(t1),
1247 Some(LinearRgba::BLACK),
1248 )),
1249 _ => None,
1250 }
1251}