bevy_pbr/transmission/
phase.rs1use core::ops::Range;
2
3use bevy_camera::{Camera, Camera3d};
4use bevy_core_pipeline::core_3d::TransparentSortingInfo3d;
5use bevy_ecs::{
6 entity::{Entity, EntityHash},
7 query::With,
8 system::{Local, Query, ResMut},
9};
10use bevy_material::{descriptor::CachedRenderPipelineId, labels::DrawFunctionId};
11use bevy_math::FloatOrd;
12use bevy_platform::collections::HashSet;
13use bevy_render::{
14 render_phase::{
15 CachedRenderPipelinePhaseItem, PhaseItem, PhaseItemExtraIndex, SortedPhaseItem,
16 ViewSortedRenderPhases,
17 },
18 sync_world::MainEntity,
19 view::{ExtractedView, RetainedViewEntity},
20 Extract,
21};
22use indexmap::IndexMap;
23
24pub struct Transmissive3d {
25 pub sorting_info: TransparentSortingInfo3d,
26 pub distance: f32,
27 pub pipeline: CachedRenderPipelineId,
28 pub entity: (Entity, MainEntity),
29 pub draw_function: DrawFunctionId,
30 pub batch_range: Range<u32>,
31 pub extra_index: PhaseItemExtraIndex,
32 pub indexed: bool,
35}
36
37impl PhaseItem for Transmissive3d {
38 const AUTOMATIC_BATCHING: bool = false;
48
49 #[inline]
50 fn entity(&self) -> Entity {
51 self.entity.0
52 }
53
54 #[inline]
55 fn main_entity(&self) -> MainEntity {
56 self.entity.1
57 }
58
59 #[inline]
60 fn draw_function(&self) -> DrawFunctionId {
61 self.draw_function
62 }
63
64 #[inline]
65 fn batch_range(&self) -> &Range<u32> {
66 &self.batch_range
67 }
68
69 #[inline]
70 fn batch_range_mut(&mut self) -> &mut Range<u32> {
71 &mut self.batch_range
72 }
73
74 #[inline]
75 fn extra_index(&self) -> PhaseItemExtraIndex {
76 self.extra_index.clone()
77 }
78
79 #[inline]
80 fn batch_range_and_extra_index_mut(&mut self) -> (&mut Range<u32>, &mut PhaseItemExtraIndex) {
81 (&mut self.batch_range, &mut self.extra_index)
82 }
83}
84
85impl SortedPhaseItem for Transmissive3d {
86 type SortKey = FloatOrd;
88
89 #[inline]
90 fn sort_key(&self) -> Self::SortKey {
91 FloatOrd(self.distance)
92 }
93
94 #[inline]
95 fn sort(items: &mut IndexMap<(Entity, MainEntity), Transmissive3d, EntityHash>) {
96 items.sort_by_key(|_, item| item.sort_key());
97 }
98
99 fn recalculate_sort_keys(
100 items: &mut IndexMap<(Entity, MainEntity), Self, EntityHash>,
101 view: &ExtractedView,
102 ) {
103 let rangefinder = view.rangefinder3d();
105 for item in items.values_mut() {
106 item.distance = item.sorting_info.sort_distance(&rangefinder);
107 }
108 }
109
110 #[inline]
111 fn indexed(&self) -> bool {
112 self.indexed
113 }
114}
115
116impl CachedRenderPipelinePhaseItem for Transmissive3d {
117 #[inline]
118 fn cached_pipeline(&self) -> CachedRenderPipelineId {
119 self.pipeline
120 }
121}
122
123pub fn extract_transmissive_camera_phases(
124 mut transmissive_3d_phases: ResMut<ViewSortedRenderPhases<Transmissive3d>>,
125 cameras: Extract<Query<(Entity, &Camera), With<Camera3d>>>,
126 mut live_entities: Local<HashSet<RetainedViewEntity>>,
127) {
128 live_entities.clear();
129
130 for (main_entity, camera) in &cameras {
131 if !camera.is_active {
132 continue;
133 }
134
135 let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
137
138 transmissive_3d_phases.prepare_for_new_frame(retained_view_entity);
139 live_entities.insert(retained_view_entity);
140 }
141
142 transmissive_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
143}