bevy_vector_shapes/render/
render_3d.rs

1use bevy::{
2    core_pipeline::core_3d::*,
3    ecs::entity::hash_map::EntityHashMap,
4    platform::collections::HashMap,
5    prelude::*,
6    render::{
7        render_phase::DrawFunctions,
8        render_resource::*,
9        sync_world::{MainEntity, RenderEntity, TemporaryRenderEntity},
10        view::ExtractedView,
11        Extract,
12    },
13};
14
15use crate::{painter::ShapeStorage, render::*, shapes::Shape3d};
16
17#[derive(Resource, Deref, DerefMut)]
18pub struct Shape3dInstances<T: ShapeData>(EntityHashMap<ShapeInstance<T>>);
19
20impl<T: ShapeData> Default for Shape3dInstances<T> {
21    fn default() -> Self {
22        Self(Default::default())
23    }
24}
25
26#[derive(Resource, Deref, DerefMut)]
27pub struct Shape3dMaterials<T: ShapeData>(
28    #[deref] HashMap<ShapePipelineMaterial, Vec<Entity>>,
29    PhantomData<T>,
30);
31
32impl<T: ShapeData> Default for Shape3dMaterials<T> {
33    fn default() -> Self {
34        Self(Default::default(), Default::default())
35    }
36}
37
38pub fn extract_shapes_3d<T: ShapeData>(
39    mut commands: Commands,
40    entities: Extract<
41        Query<
42            (
43                Entity,
44                &T::Component,
45                &ShapeFill,
46                &GlobalTransform,
47                &InheritedVisibility,
48                Option<&ShapeMaterial>,
49                Option<&RenderLayers>,
50                Option<&ShapeOrigin>,
51            ),
52            With<Shape3d>,
53        >,
54    >,
55    storage: Extract<Res<ShapeStorage>>,
56    mut instance_data: ResMut<Shape3dInstances<T>>,
57    mut materials: ResMut<Shape3dMaterials<T>>,
58    render_entities: Extract<Query<&RenderEntity>>,
59    mut canvases: Local<EntityHashMap<Entity>>,
60) {
61    instance_data.clear();
62    materials.clear();
63    canvases.clear();
64
65    entities
66        .iter()
67        .filter_map(|(e, cp, fill, tf, vis, flags, rl, or)| {
68            if vis.get() {
69                // find global origin of shape
70                let local_origin = or.map(|or| or.0).unwrap_or(Vec3::ZERO);
71                let origin = tf.transform_point(local_origin);
72
73                Some((
74                    e,
75                    ShapeInstance {
76                        material: ShapePipelineMaterial::new(flags, rl),
77                        origin,
78                        data: cp.get_data(tf, fill),
79                    },
80                ))
81            } else {
82                None
83            }
84        })
85        .for_each(|(entity, instance)| {
86            materials
87                .entry(instance.material.clone())
88                .or_default()
89                .push(entity);
90            instance_data.insert(entity, instance);
91        });
92
93    if let Some(iter) = storage.get::<T>(ShapePipelineType::Shape3d) {
94        iter.cloned().for_each(|mut instance| {
95            let entity = commands.spawn(TemporaryRenderEntity).id();
96            if let Some(canvas) = &mut instance.material.canvas {
97                *canvas = *canvases.entry(*canvas).or_insert_with(|| {
98                    render_entities
99                        .get(*canvas)
100                        .map(|e| e.id())
101                        .unwrap_or(Entity::PLACEHOLDER)
102                });
103            }
104            materials
105                .entry(instance.material.clone())
106                .or_default()
107                .push(entity);
108            instance_data.insert(entity, instance);
109        });
110    }
111}
112
113#[allow(clippy::too_many_arguments)]
114pub fn queue_shapes_3d<T: ShapeData>(
115    // opaque_draw_functions: Res<DrawFunctions<Opaque3d>>,
116    // alpha_mask_draw_functions: Res<DrawFunctions<AlphaMask3d>>,
117    transparent_draw_functions: Res<DrawFunctions<Transparent3d>>,
118    pipeline: Res<Shape3dPipeline<T>>,
119    pipeline_cache: Res<PipelineCache>,
120    materials: Res<Shape3dMaterials<T>>,
121    instance_data: Res<Shape3dInstances<T>>,
122    mut shape_pipelines: ResMut<ShapePipelines>,
123    // mut opaque_phases: ResMut<ViewBinnedRenderPhases<Opaque3d>>,
124    // mut alpha_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3d>>,
125    mut trans_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
126    mut views: Query<(&ExtractedView, &Msaa, Option<&RenderLayers>)>,
127) {
128    // let draw_opaque = opaque_draw_functions.read().id::<DrawShape3dCommand<T>>();
129    // let draw_alpha_mask = alpha_mask_draw_functions
130    //     .read()
131    //     .id::<DrawShape3dCommand<T>>();
132    let draw_transparent = transparent_draw_functions
133        .read()
134        .id::<DrawShape3dCommand<T>>();
135    let view_count = views.iter().count();
136
137    for (material, entities) in materials.iter() {
138        let mut key = ShapePipelineKey::from_material(material);
139        if !material.disable_laa {
140            key |= ShapePipelineKey::LOCAL_AA;
141        }
142
143        let mut visible_views = Vec::with_capacity(view_count);
144        if let Some(canvas) = material.canvas {
145            if let Ok(view) = views.get_mut(canvas) {
146                visible_views.push(view);
147            }
148        } else {
149            views
150                .iter_mut()
151                .filter(|(_, _, layers)| {
152                    let render_layers = layers.cloned().unwrap_or_default();
153                    render_layers.intersects(&material.render_layers.0)
154                })
155                .for_each(|view| visible_views.push(view))
156        };
157
158        for (view, msaa, _) in visible_views.into_iter() {
159            // let (Some(opaque_phase), Some(alpha_mask_phase), Some(transparent_phase)) = (
160            //     opaque_phases.get_mut(&view_entity),
161            //     alpha_phases.get_mut(&view_entity),
162            //     trans_phases.get_mut(&view_entity),
163            // ) else {
164            //     continue;
165            // };
166            let Some(transparent_phase) = trans_phases.get_mut(&view.retained_view_entity) else {
167                continue;
168            };
169            let mut view_key = key;
170            view_key |= ShapePipelineKey::from_msaa_samples(msaa.samples());
171            view_key |= ShapePipelineKey::from_hdr(view.hdr);
172            let pipeline = shape_pipelines.specialize(&pipeline_cache, pipeline.as_ref(), view_key);
173
174            // let default_id = AssetId::Uuid {
175            //     uuid: AssetId::<Mesh>::DEFAULT_UUID,
176            // };
177            let rangefinder = view.rangefinder3d();
178            for &entity in entities {
179                // SAFETY: we insert this alongside inserting into the vector we are currently iterating
180                let instance = unsafe { instance_data.get(&entity).unwrap_unchecked() };
181                let distance = rangefinder.distance_translation(&instance.origin);
182                transparent_phase.add(Transparent3d {
183                    entity: (entity, MainEntity::from(Entity::PLACEHOLDER)),
184                    draw_function: draw_transparent,
185                    pipeline,
186                    distance,
187                    batch_range: 0..1,
188                    extra_index: PhaseItemExtraIndex::None,
189                    indexed: false,
190                });
191            }
192        }
193    }
194}
195
196#[derive(Resource)]
197pub struct Shape3dBindGroup<T: ShapeData> {
198    pub value: BindGroup,
199    _marker: PhantomData<T>,
200}
201
202pub fn prepare_shape_3d_bind_group<T: ShapeData + 'static>(
203    mut commands: Commands,
204    pipeline: Res<Shape3dPipeline<T>>,
205    render_device: Res<RenderDevice>,
206    shape_buffer: Res<BatchedInstanceBuffer<T>>,
207) {
208    if let Some(binding) = shape_buffer.binding() {
209        commands.insert_resource(Shape3dBindGroup {
210            value: render_device.create_bind_group(
211                "shape_bind_group",
212                &pipeline.layout,
213                &BindGroupEntries::single(binding),
214            ),
215            _marker: PhantomData::<T>,
216        });
217    }
218}