bevy_render 0.19.0-rc.1

Provides rendering functionality for Bevy Engine
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
use core::{any::TypeId, mem};

use bevy_ecs::{
    component::Component,
    entity::Entity,
    prelude::ReflectComponent,
    query::{Changed, Or, With},
    system::{
        lifetimeless::{Read, SQuery},
        Local, Query, SystemParam,
    },
};
#[cfg(feature = "trace")]
use bevy_log::info_span;
use bevy_platform::collections::{HashMap, HashSet};
use bevy_reflect::{prelude::ReflectDefault, Reflect};
use bevy_utils::TypeIdMap;

use crate::{
    sync_world::{MainEntity, MainEntityHashMap, RenderEntity},
    view::RetainedViewEntity,
    Extract,
};

mod range;
use bevy_camera::visibility::*;
pub use range::*;

/// Stores a list of all entities that are visible from a single view or
/// subview, as well as the change lists.
///
/// This component is only placed directly on camera entities. Lights instead
/// have a [`RenderShadowMapVisibleEntities`] component that contains one or
/// more [`RenderVisibleEntities`] components, one for each cascade or cubemap
/// side.
///
/// The [`crate::camera::extract_cameras`] and `extract_lights` systems create
/// this object, but they don't populate it. Instead, the
/// [`collect_visible_cpu_culled_entities`] and
/// `collect_gpu_culled_meshes` systems are responsible for
/// updating this component from the lists of entities in
/// [`RenderExtractedVisibleEntities`] and `RenderGpuCulledEntities`,
/// respectively.
#[derive(Clone, Component, Default, Debug)]
pub struct RenderVisibleEntities {
    /// Entities visible from this view or subview, sorted by
    /// [`VisibilityClass`].
    pub classes: TypeIdMap<RenderVisibleEntitiesClass>,
}

/// Collection of entities visible from a single light.
///
/// This component contains one [`RenderVisibleEntities`] object per subview.
/// Directional lights have one subview per cascade, point lights have one
/// subview per cubemap face, and spot lights only have a single subview.
///
/// The `extract_lights` system creates this component, but it doesn't populate
/// it. Instead, the [`collect_visible_cpu_culled_entities`] and
/// `collect_gpu_culled_meshes` systems are responsible for
/// updating this component from the lists of entities in
/// [`RenderExtractedShadowMapVisibleEntities`] and `RenderGpuCulledEntities`,
/// respectively.
#[derive(Clone, Component, Default, Debug, Reflect)]
#[reflect(Component, Default, Debug, Clone)]
pub struct RenderShadowMapVisibleEntities {
    /// A mapping from each subview (cascade or cubemap face) to the entities
    /// visible from it.
    #[reflect(ignore, clone)]
    pub subviews: HashMap<RetainedViewEntity, RenderVisibleEntities>,
}

/// Stores a list of all entities that are visible from a single view for a
/// single [`VisibilityClass`], as well as the change lists.
///
/// Note that all lists in this component are guaranteed to be sorted. Thus you
/// can test for the presence of an entity in these lists via binary search.
///
/// Note also that, for 3D meshes, the render-world [`Entity`] values will
/// always be [`Entity::PLACEHOLDER`]. The render-world entities are kept for
/// legacy systems that still need to process visibility of render-world
/// entities.
///
/// The [`collect_visible_cpu_culled_entities`] and `collect_gpu_culled_meshes`
/// systems populate this object from the corresponding
/// [`RenderExtractedVisibleEntitiesClass`] object and the
/// `RenderGpuCulledEntities` resource, respectively.
#[derive(Clone, Debug, Default, Reflect)]
#[reflect(Debug, Default, Clone)]
pub struct RenderVisibleEntitiesClass {
    /// A sorted list of all entities that don't have [`NoCpuCulling`]
    /// components and are visible from this view.
    #[reflect(ignore, clone)]
    pub entities_cpu_culling: Vec<(Entity, MainEntity)>,

    /// A table of all entities that have [`NoCpuCulling`] components and have
    /// [`bevy_camera::visibility::InheritedVisibility`] set to true.
    ///
    /// The `collect_gpu_culled_meshes` system keeps this up to date.
    pub entities_gpu_culling: MainEntityHashMap<Entity>,

    /// A sorted list of all entities that were invisible last frame (including
    /// ones that didn't exist at all last frame) and became visible this frame.
    pub added_entities: Vec<(Entity, MainEntity)>,

    /// A sorted list of all entities that were visible last frame and became
    /// invisible this frame, including those that were despawned this frame.
    pub removed_entities: Vec<(Entity, MainEntity)>,
}

/// The entities that the CPU has determined are visible from a single view or
/// subview.
///
/// This component is only placed directly on camera entities. Lights instead
/// have a [`RenderExtractedShadowMapVisibleEntities`] component that contains
/// one or more [`RenderExtractedVisibleEntities`] components, one for each
/// cascade or cubemap side.
///
/// Mesh entities with [`NoCpuCulling`] aren't present in this table. Instead,
/// `collect_gpu_culled_meshes` fetches them directly from the
/// `RenderGpuCulledEntities` list.
///
/// The [`crate::camera::extract_cameras`] and `extract_lights` systems populate
/// this object, and the [`collect_visible_cpu_culled_entities`] system reads it.
#[derive(Component, Clone, Default, Debug)]
pub struct RenderExtractedVisibleEntities {
    /// Entities that the CPU has determined to be visible from this view or
    /// subview, sorted by [`VisibilityClass`].
    pub classes: TypeIdMap<RenderExtractedVisibleEntitiesClass>,
}

/// The entities that the CPU has determined are visible from a single
/// shadow-casting light.
///
/// This component contains one [`RenderExtractedVisibleEntities`] object per
/// subview.  Directional lights have one subview per cascade, point lights have
/// one subview per cubemap face, and spot lights only have a single subview.
///
/// Mesh entities that have [`NoCpuCulling`] components aren't in this list.
/// Instead, `collect_gpu_culled_meshes` fetches them directly
/// from the `RenderGpuCulledEntities` table.
///
/// The `extract_lights` system populates this component, and the
/// [`collect_visible_cpu_culled_entities`] system reads it.
#[derive(Component, Default)]
pub struct RenderExtractedShadowMapVisibleEntities {
    /// A mapping from the subview to the list of entities that the CPU has
    /// determined are visible from it.
    pub subviews: HashMap<RetainedViewEntity, RenderExtractedVisibleEntities>,
}

/// The entities that the CPU has determined are visible from a single view or
/// subview, for a single [`VisibilityClass`].
///
/// Mesh entities that have [`NoCpuCulling`] components aren't in this list.
/// Instead, `collect_gpu_culled_meshes` fetches them directly
/// from the `RenderGpuCulledEntities` table in order to update the
/// [`RenderVisibleEntitiesClass`].
///
/// The [`crate::camera::extract_cameras`] and `extract_lights` systems populate
/// this object, and the [`collect_visible_cpu_culled_entities`] system reads it.
#[derive(Clone, Default, Debug)]
pub struct RenderExtractedVisibleEntitiesClass {
    /// A sorted list of entities that don't have [`NoCpuCulling`] components
    /// and are visible from this view or subview.
    pub entities: Vec<(Entity, MainEntity)>,
}

impl RenderVisibleEntities {
    /// Returns the [`RenderVisibleEntitiesClass`] corresponding to the given
    /// [`VisibilityClass`].
    pub fn get<QF>(&self) -> Option<&RenderVisibleEntitiesClass>
    where
        QF: 'static,
    {
        self.classes.get(&TypeId::of::<QF>())
    }
}

impl RenderVisibleEntitiesClass {
    /// Clears out the lists of added and removed entities in preparation for a
    /// new frame.
    pub fn prepare_for_new_frame(&mut self) {
        self.added_entities.clear();
        self.removed_entities.clear();
    }

    /// Processes a list of visible entities for a new frame, computing the set
    /// of newly-added and newly-removed entities as it goes.
    ///
    /// This function only handles entities that are culled on CPU (i.e. don't
    /// have `NoCpuCulling` components). Entities that use only GPU culling are
    /// instead fetched from the main world and added to the
    /// `RenderGpuCulledEntities` table.
    pub fn update_cpu_culled_entities(
        &mut self,
        visible_mesh_entities_cpu_culling: &[(Entity, MainEntity)],
    ) {
        #[cfg(feature = "trace")]
        let _update_from = info_span!("update_from", name = "update_from").entered();

        let old_entities_cpu_culling = mem::take(&mut self.entities_cpu_culling);

        // March over the old and new visible CPU culling entity lists in
        // lockstep, diffing as we go to determine the added and removed
        // entities. The lists must be sorted.
        let mut old_entity_cpu_culling_iter = old_entities_cpu_culling.iter().peekable();
        {
            #[cfg(feature = "trace")]
            let _old_entity_cpu_culling_span =
                info_span!("old_entity_cpu_culling", name = "old_entity_cpu_culling").entered();
            for (render_entity, visible_main_entity) in visible_mesh_entities_cpu_culling {
                // Mark entities as removed until we see the one we're looking at.
                while old_entity_cpu_culling_iter
                    .peek()
                    .is_some_and(|(_, main_entity)| *main_entity < *visible_main_entity)
                {
                    self.removed_entities
                        .push(*old_entity_cpu_culling_iter.next().unwrap());
                }

                // Add the visible entity to the list.
                self.entities_cpu_culling
                    .push((*render_entity, *visible_main_entity));

                // If the next entity in the old list isn't equal to the entity we
                // just marked visible, then our entity is newly visible this frame.
                if old_entity_cpu_culling_iter
                    .peek()
                    .is_some_and(|&&(_, main_entity)| main_entity == *visible_main_entity)
                {
                    old_entity_cpu_culling_iter.next();
                } else {
                    self.added_entities
                        .push((*render_entity, *visible_main_entity));
                }
            }
        }

        // Any entities that do CPU culling and that we didn't see yet are
        // removed, so drain them.
        {
            #[cfg(feature = "trace")]
            let _old_entity_cpu_culling_removal_span = info_span!(
                "old_entity_cpu_culling_removal",
                name = "old_entity_cpu_culling_removal"
            )
            .entered();
            self.removed_entities
                .extend(old_entity_cpu_culling_iter.copied());
        }
    }

    /// Adds a new entity to the [`Self::added_entities`] list.
    ///
    /// After calling this method one or more times, you must call
    /// [`Self::sort_added_entities`] to ensure the [`Self::added_entities`]
    /// list is sorted.
    pub fn add_entity(&mut self, pair: (Entity, MainEntity)) {
        self.added_entities.push(pair);
    }

    /// Returns the list of newly-added entities.
    pub fn added_entities(&self) -> &[(Entity, MainEntity)] {
        &self.added_entities
    }

    /// Returns true if the given entity pair is known to be visible.
    ///
    /// This checks both the CPU culling visible entries table and the
    /// no-CPU-culling visible entries table.
    pub fn entity_pair_is_visible(&self, entity: Entity, main_entity: MainEntity) -> bool {
        self.entities_cpu_culling
            .binary_search(&(entity, main_entity))
            .is_ok()
            || self
                .entities_gpu_culling
                .get(&main_entity)
                .is_some_and(|that_entity| *that_entity == entity)
    }

    /// Iterates over all visible entities.
    ///
    /// This is an expensive operation, so try to avoid doing it unless
    /// necessary (e.g. the view key changed).
    pub fn iter_visible<'a>(&'a self) -> impl Iterator<Item = (&'a Entity, &'a MainEntity)> {
        self.entities_cpu_culling
            .iter()
            .map(|(entity, main_entity)| (entity, main_entity))
            .chain(
                self.entities_gpu_culling
                    .iter()
                    .map(|(main_entity, entity)| (entity, main_entity)),
            )
    }

    /// Sorts the [`Self::added_entities`] list.
    ///
    /// You must call this after adding entities to the list via
    /// [`Self::add_entity`].
    pub fn sort_added_entities(&mut self) {
        self.added_entities
            .sort_unstable_by_key(|(_, main_entity)| *main_entity);
    }
}

/// A system parameter that goes on any render-world system that needs to
/// extract entities into [`RenderVisibleEntities`].
#[derive(SystemParam)]
pub struct VisibilityExtractionSystemParam<'w, 's> {
    /// Maps entities in the main world to entities in the render world.
    pub mapper: Extract<'w, 's, SQuery<Read<RenderEntity>>>,
}

/// The query, part of [`VisibilityExtractionSystemParam`], that searches for
/// entities with [`NoCpuCulling`] that might have changed visibility.
pub type VisibilityExtractionNoCpuCullingChangedQuery = SQuery<
    (Entity, Read<VisibilityClass>, Read<InheritedVisibility>),
    (
        Or<(Changed<NoCpuCulling>, Changed<InheritedVisibility>)>,
        With<NoCpuCulling>,
    ),
>;

/// Updates the [`RenderVisibleEntities`] and [`RenderShadowMapVisibleEntities`]
/// components with the contents of the [`RenderExtractedVisibleEntities`] and
/// the [`RenderExtractedShadowMapVisibleEntities`] components respectively.
///
/// This system only handles CPU-culled entities (i.e. those without
/// [`NoCpuCulling`] components). The `collect_gpu_culled_meshes` system in
/// `bevy_pbr` handles GPU-culled entities.
pub fn collect_visible_cpu_culled_entities(
    mut cameras: Query<(
        &mut RenderVisibleEntities,
        Option<&mut RenderExtractedVisibleEntities>,
    )>,
    mut lights: Query<(
        &mut RenderShadowMapVisibleEntities,
        Option<&mut RenderExtractedShadowMapVisibleEntities>,
    )>,
    mut visibility_classes: Local<HashSet<TypeId>>,
) {
    // Collect cameras.
    for (mut render_visible_entities, mut maybe_render_visible_entities_cpu_culling) in
        cameras.iter_mut()
    {
        let mut maybe_render_subview_visible_entities_cpu_culling =
            maybe_render_visible_entities_cpu_culling.as_deref_mut();
        collect_visible_cpu_culled_entities_for_subview(
            &mut render_visible_entities,
            &mut maybe_render_subview_visible_entities_cpu_culling,
            &mut visibility_classes,
        );
    }

    // Collect shadow maps.
    for (
        mut render_shadow_map_visible_entities,
        mut maybe_render_shadow_map_visible_entities_cpu_culling,
    ) in lights.iter_mut()
    {
        for (subview, render_visible_entities) in
            render_shadow_map_visible_entities.subviews.iter_mut()
        {
            let mut maybe_render_subview_visible_entities_cpu_culling =
                maybe_render_shadow_map_visible_entities_cpu_culling
                    .as_mut()
                    .and_then(|render_subview_visible_entities_cpu_culling| {
                        render_subview_visible_entities_cpu_culling
                            .subviews
                            .get_mut(subview)
                    });
            collect_visible_cpu_culled_entities_for_subview(
                render_visible_entities,
                &mut maybe_render_subview_visible_entities_cpu_culling,
                &mut visibility_classes,
            );
        }
    }
}

/// Updates the [`RenderVisibleEntities`] list for a single subview from the
/// applicable [`RenderExtractedVisibleEntities`].
///
/// This only handles CPU-culled entities. The corresponding function for
/// GPU-called entities is `collect_gpu_culled_meshes_for_subview` in
/// `bevy_pbr`.
fn collect_visible_cpu_culled_entities_for_subview(
    render_visible_entities: &mut RenderVisibleEntities,
    maybe_render_subview_visible_entities: &mut Option<&mut RenderExtractedVisibleEntities>,
    visibility_classes: &mut HashSet<TypeId>,
) {
    // Gather up all visibility classes. We need to make sure that the
    // `RenderVisibleEntities` has an entry for each one.
    visibility_classes.clear();
    visibility_classes.extend(render_visible_entities.classes.keys().copied());
    if let Some(ref mut render_subview_visible_entities) = *maybe_render_subview_visible_entities {
        visibility_classes.extend(render_subview_visible_entities.classes.keys().copied());
    }

    // Update the tables of each visibility class.
    for visibility_class in visibility_classes.iter() {
        let entities = render_visible_entities
            .classes
            .entry(*visibility_class)
            .or_default();

        entities.prepare_for_new_frame();

        // Fetch the visibility class's entity table.
        let Some(ref mut render_subview_visible_entities) = *maybe_render_subview_visible_entities
        else {
            continue;
        };
        let Some(render_view_entities) = render_subview_visible_entities
            .classes
            .get_mut(visibility_class)
        else {
            continue;
        };

        // Make sure the entity list is sorted, as this is a requirement for
        // [`RenderVisibleEntitiesClass::update_from_cpu`].
        render_view_entities
            .entities
            .sort_unstable_by_key(|(_, main_entity)| *main_entity);

        entities.update_cpu_culled_entities(&render_view_entities.entities);
    }
}