Skip to content

Commit 44f677a

Browse files
Selene-AmanitaSpecificProtagonistalice-i-cecile
authored
Improve documentation relating to Frustum and HalfSpace (#9136)
# Objective This PR's first aim is to fix a mistake in `HalfSpace`'s documentation. When defining a `Frustum` myself in bevy_basic_portals, I realised that the "distance" of the `HalfSpace` is not, as the current doc defines, the "distance from the origin along the normal", but actually the opposite of that. See the example I gave in this PR. This means one of two things: 1. The documentation about `HalfSpace` is wrong (it is either way because of the `n.p + d > 0` formula given later anyway, which is how it behaves, but in that formula `d` is indeed the opposite of the "distance from the origin along the normal", otherwise it should be `n.p > d`) 2. The distance is supposed to be the "distance from the origin along the normal" but when used in a Frustum it's used as the opposite, and it is a mistake 3. Same as 2, but it is somehow intended Since I think `HalfSpace` is only used for `Frustum`, and it's easier to fix documentation than code, I assumed for this PR we're in case number 1. If we're in case number 3, the documentation of `Frustum` needs to change, and in case number 2, the code needs to be fixed. While I was at it, I also : - Tried to improve the documentation for `Frustum`, `Aabb`, and `VisibilitySystems`, among others, since they're all related to `Frustum`. - Fixed documentation about frustum culling not applying to 2d objects, which is not true since #7885 ## Remarks and questions - What about a `HalfSpace` with an infinite distance, is it allowed and does it represents the whole space? If so it should probably be mentioned. - I referenced the `update_frusta` system in `bevy_render::view::visibility` directly instead of referencing its system set, should I reference the system set instead? It's a bit annoying since it's in 3 sets. - `visibility_propagate` is not public for some reason, I think it probably should be, but for now I only documented its system set, should I make it public? I don't think that would count as a breaking change? - Why is `Aabb` inserted by a system, with `NoFrustumCulling` as an opt-out, instead of having it inserted by default in `PbrBundle` for example and then the system calculating it when it's added? Is it because there is still no way to have an optional component inside a bundle? --------- Co-authored-by: SpecificProtagonist <[email protected]> Co-authored-by: Alice Cecile <[email protected]>
1 parent afcb1fe commit 44f677a

File tree

3 files changed

+114
-22
lines changed

3 files changed

+114
-22
lines changed

crates/bevy_render/src/primitives/mod.rs

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,32 @@ use bevy_math::{Affine3A, Mat3A, Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles};
33
use bevy_reflect::Reflect;
44
use bevy_utils::HashMap;
55

6-
/// An axis-aligned bounding box.
6+
/// An axis-aligned bounding box, defined by:
7+
/// - a center,
8+
/// - the distances from the center to each faces along the axis,
9+
/// the faces are orthogonal to the axis.
10+
///
11+
/// It is typically used as a component on an entity to represent the local space
12+
/// occupied by this entity, with faces orthogonal to its local axis.
13+
///
14+
/// This component is notably used during "frustum culling", a process to determine
15+
/// if an entity should be rendered by a [`Camera`] if its bounding box intersects
16+
/// with the camera's [`Frustum`].
17+
///
18+
/// It will be added automatically by the systems in [`CalculateBounds`] to entities that:
19+
/// - could be subject to frustum culling, for example with a [`Handle<Mesh>`]
20+
/// or `Sprite` component,
21+
/// - don't have the [`NoFrustumCulling`] component.
22+
///
23+
/// It won't be updated automatically if the space occupied by the entity changes,
24+
/// for example if the vertex positions of a [`Mesh`] inside a `Handle<Mesh>` are
25+
/// updated.
26+
///
27+
/// [`Camera`]: crate::camera::Camera
28+
/// [`NoFrustumCulling`]: crate::view::visibility::NoFrustumCulling
29+
/// [`CalculateBounds`]: crate::view::visibility::VisibilitySystems::CalculateBounds
30+
/// [`Mesh`]: crate::mesh::Mesh
31+
/// [`Handle<Mesh>`]: crate::mesh::Mesh
732
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
833
#[reflect(Component)]
934
pub struct Aabb {
@@ -76,20 +101,37 @@ impl Sphere {
76101
}
77102
}
78103

79-
/// A bisecting plane that partitions 3D space into two regions.
104+
/// A region of 3D space, specifically an open set whose border is a bisecting 2D plane.
105+
/// This bisecting plane partitions 3D space into two infinite regions,
106+
/// the half-space is one of those regions and excludes the bisecting plane.
107+
///
108+
/// Each instance of this type is characterized by:
109+
/// - the bisecting plane's unit normal, normalized and pointing "inside" the half-space,
110+
/// - the signed distance along the normal from the bisecting plane to the origin of 3D space.
111+
///
112+
/// The distance can also be seen as:
113+
/// - the distance along the inverse of the normal from the origin of 3D space to the bisecting plane,
114+
/// - the opposite of the distance along the normal from the origin of 3D space to the bisecting plane.
115+
///
116+
/// Any point `p` is considered to be within the `HalfSpace` when the length of the projection
117+
/// of p on the normal is greater or equal than the opposite of the distance,
118+
/// meaning: if the equation `normal.dot(p) + distance > 0.` is satisfied.
80119
///
81-
/// Each instance of this type is characterized by the bisecting plane's unit normal and distance from the origin along the normal.
82-
/// Any point `p` is considered to be within the `HalfSpace` when the distance is positive,
83-
/// meaning: if the equation `n.p + d > 0` is satisfied.
120+
/// For example, the half-space containing all the points with a z-coordinate lesser
121+
/// or equal than `8.0` would be defined by: `HalfSpace::new(Vec3::NEG_Z.extend(-8.0))`.
122+
/// It includes all the points from the bisecting plane towards `NEG_Z`, and the distance
123+
/// from the plane to the origin is `-8.0` along `NEG_Z`.
124+
///
125+
/// It is used to define a [`Frustum`], but is also a useful mathematical primitive for rendering tasks such as light computation.
84126
#[derive(Clone, Copy, Debug, Default)]
85127
pub struct HalfSpace {
86128
normal_d: Vec4,
87129
}
88130

89131
impl HalfSpace {
90132
/// Constructs a `HalfSpace` from a 4D vector whose first 3 components
91-
/// represent the bisecting plane's unit normal, and the last component signifies
92-
/// the distance from the origin to the plane along the normal.
133+
/// represent the bisecting plane's unit normal, and the last component is
134+
/// the signed distance along the normal from the plane to the origin.
93135
/// The constructor ensures the normal vector is normalized and the distance is appropriately scaled.
94136
#[inline]
95137
pub fn new(normal_d: Vec4) -> Self {
@@ -104,23 +146,46 @@ impl HalfSpace {
104146
Vec3A::from(self.normal_d)
105147
}
106148

107-
/// Returns the distance from the origin to the bisecting plane along the plane's unit normal vector.
108-
/// This distance helps determine the position of a point `p` on the bisecting plane, as per the equation `n.p + d = 0`.
149+
/// Returns the signed distance from the bisecting plane to the origin along
150+
/// the plane's unit normal vector.
109151
#[inline]
110152
pub fn d(&self) -> f32 {
111153
self.normal_d.w
112154
}
113155

114-
/// Returns the bisecting plane's unit normal vector and the distance from the origin to the plane.
156+
/// Returns the bisecting plane's unit normal vector and the signed distance
157+
/// from the plane to the origin.
115158
#[inline]
116159
pub fn normal_d(&self) -> Vec4 {
117160
self.normal_d
118161
}
119162
}
120163

121-
/// A frustum made up of the 6 defining half spaces.
122-
/// Half spaces are ordered left, right, top, bottom, near, far.
123-
/// The normal vectors of the half spaces point towards the interior of the frustum.
164+
/// A region of 3D space defined by the intersection of 6 [`HalfSpace`]s.
165+
///
166+
/// Frustums are typically an apex-truncated square pyramid (a pyramid without the top) or a cuboid.
167+
///
168+
/// Half spaces are ordered left, right, top, bottom, near, far. The normal vectors
169+
/// of the half-spaces point towards the interior of the frustum.
170+
///
171+
/// A frustum component is used on an entity with a [`Camera`] component to
172+
/// determine which entities will be considered for rendering by this camera.
173+
/// All entities with an [`Aabb`] component that are not contained by (or crossing
174+
/// the boundary of) the frustum will not be rendered, and not be used in rendering computations.
175+
///
176+
/// This process is called frustum culling, and entities can opt out of it using
177+
/// the [`NoFrustumCulling`] component.
178+
///
179+
/// The frustum component is typically added from a bundle, either the `Camera2dBundle`
180+
/// or the `Camera3dBundle`.
181+
/// It is usually updated automatically by [`update_frusta`] from the
182+
/// [`CameraProjection`] component and [`GlobalTransform`] of the camera entity.
183+
///
184+
/// [`Camera`]: crate::camera::Camera
185+
/// [`NoFrustumCulling`]: crate::view::visibility::NoFrustumCulling
186+
/// [`update_frusta`]: crate::view::visibility::update_frusta
187+
/// [`CameraProjection`]: crate::camera::CameraProjection
188+
/// [`GlobalTransform`]: bevy_transform::components::GlobalTransform
124189
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
125190
#[reflect(Component)]
126191
pub struct Frustum {

crates/bevy_render/src/view/visibility/mod.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,23 +153,26 @@ pub struct VisibilityBundle {
153153
pub computed: ComputedVisibility,
154154
}
155155

156-
/// Use this component to opt-out of built-in frustum culling for Mesh entities
156+
/// Use this component to opt-out of built-in frustum culling for entities, see
157+
/// [`Frustum`].
158+
///
159+
/// It can be used for example:
160+
/// - when a [`Mesh`] is updated but its [`Aabb`] is not, which might happen with animations,
161+
/// - when using some light effects, like wanting a [`Mesh`] out of the [`Frustum`]
162+
/// to appear in the reflection of a [`Mesh`] within.
157163
#[derive(Component, Default, Reflect)]
158164
#[reflect(Component, Default)]
159165
pub struct NoFrustumCulling;
160166

161167
/// Collection of entities visible from the current view.
162168
///
163169
/// This component contains all entities which are visible from the currently
164-
/// rendered view. The collection is updated automatically by the [`check_visibility()`]
165-
/// system, and renderers can use it to optimize rendering of a particular view, to
170+
/// rendered view. The collection is updated automatically by the [`VisibilitySystems::CheckVisibility`]
171+
/// system set, and renderers can use it to optimize rendering of a particular view, to
166172
/// prevent drawing items not visible from that view.
167173
///
168174
/// This component is intended to be attached to the same entity as the [`Camera`] and
169175
/// the [`Frustum`] defining the view.
170-
///
171-
/// Currently this component is ignored by the sprite renderer, so sprite rendering
172-
/// is not optimized per view.
173176
#[derive(Clone, Component, Default, Debug, Reflect)]
174177
#[reflect(Component)]
175178
pub struct VisibleEntities {
@@ -193,13 +196,21 @@ impl VisibleEntities {
193196

194197
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
195198
pub enum VisibilitySystems {
199+
/// Label for the [`calculate_bounds`] and `calculate_bounds_2d` systems,
200+
/// calculating and inserting an [`Aabb`] to relevant entities.
196201
CalculateBounds,
202+
/// Label for the [`apply_deferred`] call after [`VisibilitySystems::CalculateBounds`]
197203
CalculateBoundsFlush,
204+
/// Label for the [`update_frusta<OrthographicProjection>`] system.
198205
UpdateOrthographicFrusta,
206+
/// Label for the [`update_frusta<PerspectiveProjection>`] system.
199207
UpdatePerspectiveFrusta,
208+
/// Label for the [`update_frusta<Projection>`] system.
200209
UpdateProjectionFrusta,
210+
/// Label for the system propagating the [`ComputedVisibility`] in a
211+
/// [`hierarchy`](bevy_hierarchy).
201212
VisibilityPropagate,
202-
/// Label for the [`check_visibility()`] system updating each frame the [`ComputedVisibility`]
213+
/// Label for the [`check_visibility`] system updating [`ComputedVisibility`]
203214
/// of each entity and the [`VisibleEntities`] of each view.
204215
CheckVisibility,
205216
}
@@ -253,6 +264,10 @@ impl Plugin for VisibilityPlugin {
253264
}
254265
}
255266

267+
/// Computes and adds an [`Aabb`] component to entities with a
268+
/// [`Handle<Mesh>`](Mesh) component and without a [`NoFrustumCulling`] component.
269+
///
270+
/// This system is used in system set [`VisibilitySystems::CalculateBounds`].
256271
pub fn calculate_bounds(
257272
mut commands: Commands,
258273
meshes: Res<Assets<Mesh>>,
@@ -267,6 +282,11 @@ pub fn calculate_bounds(
267282
}
268283
}
269284

285+
/// Updates [`Frustum`].
286+
///
287+
/// This system is used in system sets [`VisibilitySystems::UpdateProjectionFrusta`],
288+
/// [`VisibilitySystems::UpdatePerspectiveFrusta`], and
289+
/// [`VisibilitySystems::UpdateOrthographicFrusta`].
270290
pub fn update_frusta<T: Component + CameraProjection + Send + Sync + 'static>(
271291
mut views: Query<
272292
(&GlobalTransform, &T, &mut Frustum),
@@ -345,9 +365,9 @@ fn propagate_recursive(
345365
Ok(())
346366
}
347367

348-
/// System updating the visibility of entities each frame.
368+
/// Updates the visibility of entities each frame.
349369
///
350-
/// The system is part of the [`VisibilitySystems::CheckVisibility`] set. Each frame, it updates the
370+
/// This system is part of the [`VisibilitySystems::CheckVisibility`] set. Each frame, it updates the
351371
/// [`ComputedVisibility`] of all entities, and for each view also compute the [`VisibleEntities`]
352372
/// for that view.
353373
pub fn check_visibility(

crates/bevy_sprite/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ impl Plugin for SpritePlugin {
108108
}
109109
}
110110

111+
/// System calculating and inserting an [`Aabb`] component to entities with either:
112+
/// - a `Mesh2dHandle` component,
113+
/// - a `Sprite` and `Handle<Image>` components,
114+
/// - a `TextureAtlasSprite` and `Handle<TextureAtlas>` components,
115+
/// and without a [`NoFrustumCulling`] component.
116+
///
117+
/// Used in system set [`VisibilitySystems::CalculateBounds`].
111118
pub fn calculate_bounds_2d(
112119
mut commands: Commands,
113120
meshes: Res<Assets<Mesh>>,

0 commit comments

Comments
 (0)