avian2d/collider_tree/
mod.rs

1//! Tree acceleration structures for spatial queries on [colliders](crate::collision::collider::Collider).
2//!
3//! To speed up [broad phase](crate::collision::broad_phase) collision detection and [spatial queries](crate::spatial_query),
4//! Avian maintains a [`ColliderTree`] structure for all colliders in the physics world. This is implemented as
5//! a [Bounding Volume Hierarchy (BVH)][BVH], which accelerates querying for [AABB](crate::collision::collider::ColliderAabb)
6//! overlaps, ray intersections, and more.
7//!
8//! Colliders of dynamic, kinematic, and static bodies are all stored in a separate [`ColliderTree`]
9//! to allow efficiently querying for specific subsets of colliders and to optimize tree updates based on body type.
10//! Trees for dynamic and kinematic bodies are rebuilt every physics step, while the static tree is incrementally updated
11//! when static colliders are added, removed, or modified. The trees are stored in the [`ColliderTrees`] resource.
12//!
13//! [BVH]: https://en.wikipedia.org/wiki/Bounding_volume_hierarchy
14//!
15//! # Usage
16//!
17//! The collider trees are fairly low-level, and not intended to be used directly.
18//! For spatial queries, consider using the higher-level [`SpatialQuery`] API instead,
19//! and for broad phase collision detection, consider using the [`BvhBroadPhasePlugin`].
20//!
21//! [`SpatialQuery`]: crate::spatial_query::SpatialQuery
22//! [`BvhBroadPhasePlugin`]: crate::collision::broad_phase::BvhBroadPhasePlugin
23
24mod diagnostics;
25mod obvhs_ext;
26mod optimization;
27mod proxy_key;
28mod traverse;
29mod tree;
30mod update;
31
32pub use diagnostics::ColliderTreeDiagnostics;
33pub use obvhs_ext::Bvh2Ext;
34pub(crate) use obvhs_ext::obvhs_ray;
35pub use optimization::{ColliderTreeOptimization, TreeOptimizationMode};
36pub use proxy_key::{ColliderTreeProxyKey, ColliderTreeType, ProxyId};
37pub use tree::{ColliderTree, ColliderTreeProxy, ColliderTreeProxyFlags, ColliderTreeWorkspace};
38pub use update::{MovedProxies, update_moved_collider_aabbs};
39
40use optimization::ColliderTreeOptimizationPlugin;
41use update::ColliderTreeUpdatePlugin;
42
43use core::marker::PhantomData;
44
45use crate::prelude::*;
46use bevy::prelude::*;
47
48/// A plugin that manages [collider trees](crate::collider_tree) for a collider type `C`.
49pub struct ColliderTreePlugin<C: AnyCollider>(PhantomData<C>);
50
51impl<C: AnyCollider> Default for ColliderTreePlugin<C> {
52    fn default() -> Self {
53        Self(PhantomData)
54    }
55}
56
57impl<C: AnyCollider> Plugin for ColliderTreePlugin<C> {
58    fn build(&self, app: &mut App) {
59        // Register required components.
60        let _ = app.try_register_required_components_with::<C, ColliderTreeProxyKey>(|| {
61            // Use a default proxy key. This will be overwritten when the proxy is actually created.
62            ColliderTreeProxyKey::PLACEHOLDER
63        });
64
65        // Add plugin for updating trees as colliders move.
66        app.add_plugins(ColliderTreeUpdatePlugin::<C>::default());
67
68        // Add plugin for optimizing trees tp maintain good query performance.
69        if !app.is_plugin_added::<ColliderTreeOptimizationPlugin>() {
70            app.add_plugins(ColliderTreeOptimizationPlugin);
71        }
72
73        // Initialize resources.
74        app.init_resource::<ColliderTrees>()
75            .init_resource::<MovedProxies>();
76
77        // Configure system sets.
78        app.configure_sets(
79            PhysicsSchedule,
80            ColliderTreeSystems::UpdateAabbs
81                .in_set(PhysicsStepSystems::BroadPhase)
82                .after(BroadPhaseSystems::First)
83                .before(BroadPhaseSystems::CollectCollisions),
84        );
85        app.configure_sets(
86            PhysicsSchedule,
87            ColliderTreeSystems::BeginOptimize.in_set(BroadPhaseSystems::Last),
88        );
89        app.configure_sets(
90            PhysicsSchedule,
91            // TODO: What's the optimal place for this? It needs to be before spatial queries and collision events.
92            ColliderTreeSystems::EndOptimize.in_set(SolverSystems::Finalize),
93        );
94    }
95
96    fn finish(&self, app: &mut App) {
97        // Register timer diagnostics for collider trees.
98        app.register_physics_diagnostics::<ColliderTreeDiagnostics>();
99    }
100}
101
102/// System sets for managing [`ColliderTrees`].
103#[derive(SystemSet, Clone, Copy, Debug, PartialEq, Eq, Hash)]
104pub enum ColliderTreeSystems {
105    /// Updates the AABBs of colliders.
106    UpdateAabbs,
107    /// Begins optimizing acceleration structures to keep their query performance good.
108    ///
109    /// This runs concurrently with the simulation step as an async task.
110    BeginOptimize,
111    /// Completes the optimization of acceleration structures started in [`ColliderTreeSystems::BeginOptimize`].
112    ///
113    /// This runs at the end of the simulation step.
114    EndOptimize,
115}
116
117/// Trees for accelerating queries on a set of colliders.
118///
119/// See the [`collider_tree`](crate::collider_tree) module for more information.
120#[derive(Resource, Default)]
121pub struct ColliderTrees {
122    /// A tree for the colliders of dynamic bodies.
123    pub dynamic_tree: ColliderTree,
124    /// A tree for the colliders of kinematic bodies.
125    pub kinematic_tree: ColliderTree,
126    /// A tree for the colliders of static bodies.
127    pub static_tree: ColliderTree,
128    /// A tree for standalone colliders with no associated rigid body.
129    pub standalone_tree: ColliderTree,
130}
131
132impl ColliderTrees {
133    /// Returns the tree for the given [`ColliderTreeType`].
134    #[inline]
135    pub const fn tree_for_type(&self, tree_type: ColliderTreeType) -> &ColliderTree {
136        match tree_type {
137            ColliderTreeType::Dynamic => &self.dynamic_tree,
138            ColliderTreeType::Kinematic => &self.kinematic_tree,
139            ColliderTreeType::Static => &self.static_tree,
140            ColliderTreeType::Standalone => &self.standalone_tree,
141        }
142    }
143
144    /// Returns a mutable reference to the tree for the given [`ColliderTreeType`].
145    #[inline]
146    pub const fn tree_for_type_mut(&mut self, tree_type: ColliderTreeType) -> &mut ColliderTree {
147        match tree_type {
148            ColliderTreeType::Dynamic => &mut self.dynamic_tree,
149            ColliderTreeType::Kinematic => &mut self.kinematic_tree,
150            ColliderTreeType::Static => &mut self.static_tree,
151            ColliderTreeType::Standalone => &mut self.standalone_tree,
152        }
153    }
154
155    /// Returns an iterator over all collider trees.
156    #[inline]
157    pub fn iter_trees(&self) -> impl Iterator<Item = &ColliderTree> {
158        [
159            &self.dynamic_tree,
160            &self.kinematic_tree,
161            &self.static_tree,
162            &self.standalone_tree,
163        ]
164        .into_iter()
165    }
166
167    /// Returns a mutable iterator over all collider trees.
168    #[inline]
169    pub fn iter_trees_mut(&mut self) -> impl Iterator<Item = &mut ColliderTree> {
170        [
171            &mut self.dynamic_tree,
172            &mut self.kinematic_tree,
173            &mut self.static_tree,
174            &mut self.standalone_tree,
175        ]
176        .into_iter()
177    }
178
179    /// Returns the proxy with the given [`ColliderTreeProxyKey`], if it exists.
180    #[inline]
181    pub fn get_proxy(&self, key: ColliderTreeProxyKey) -> Option<&ColliderTreeProxy> {
182        self.tree_for_type(key.tree_type())
183            .proxies
184            .get(key.id().index())
185    }
186
187    /// Returns a mutable reference to the proxy with the given [`ColliderTreeProxyKey`], if it exists.
188    #[inline]
189    pub fn get_proxy_mut(&mut self, key: ColliderTreeProxyKey) -> Option<&mut ColliderTreeProxy> {
190        self.tree_for_type_mut(key.tree_type())
191            .proxies
192            .get_mut(key.id().index())
193    }
194}