avian3d/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::{
38 ColliderTree, ColliderTreeProxy, ColliderTreeProxyFlags, ColliderTreeWorkspace, MovedProxyList,
39};
40pub use update::{MovedProxies, update_moved_collider_aabbs};
41
42use optimization::ColliderTreeOptimizationPlugin;
43use update::ColliderTreeUpdatePlugin;
44
45use core::marker::PhantomData;
46
47use crate::prelude::*;
48use bevy::prelude::*;
49
50/// A plugin that manages [collider trees](crate::collider_tree) for a collider type `C`.
51pub struct ColliderTreePlugin<C: AnyCollider>(PhantomData<C>);
52
53impl<C: AnyCollider> Default for ColliderTreePlugin<C> {
54 fn default() -> Self {
55 Self(PhantomData)
56 }
57}
58
59impl<C: AnyCollider> Plugin for ColliderTreePlugin<C> {
60 fn build(&self, app: &mut App) {
61 // Register required components.
62 let _ = app.try_register_required_components_with::<C, ColliderTreeProxyKey>(|| {
63 // Use a default proxy key. This will be overwritten when the proxy is actually created.
64 ColliderTreeProxyKey::PLACEHOLDER
65 });
66
67 // Add plugin for updating trees as colliders move.
68 app.add_plugins(ColliderTreeUpdatePlugin::<C>::default());
69
70 // Add plugin for optimizing trees tp maintain good query performance.
71 if !app.is_plugin_added::<ColliderTreeOptimizationPlugin>() {
72 app.add_plugins(ColliderTreeOptimizationPlugin);
73 }
74
75 // Initialize resources.
76 app.init_resource::<ColliderTrees>()
77 .init_resource::<MovedProxies>();
78
79 // Configure system sets.
80 app.configure_sets(
81 PhysicsSchedule,
82 ColliderTreeSystems::UpdateAabbs
83 .in_set(PhysicsStepSystems::BroadPhase)
84 .after(BroadPhaseSystems::First)
85 .before(BroadPhaseSystems::CollectCollisions),
86 );
87 app.configure_sets(
88 PhysicsSchedule,
89 ColliderTreeSystems::BeginOptimize.in_set(BroadPhaseSystems::Last),
90 );
91 app.configure_sets(
92 PhysicsSchedule,
93 // TODO: What's the optimal place for this? It needs to be before spatial queries and collision events.
94 ColliderTreeSystems::EndOptimize.in_set(SolverSystems::Finalize),
95 );
96 }
97
98 fn finish(&self, app: &mut App) {
99 // Register timer diagnostics for collider trees.
100 app.register_physics_diagnostics::<ColliderTreeDiagnostics>();
101 }
102}
103
104/// System sets for managing [`ColliderTrees`].
105#[derive(SystemSet, Clone, Copy, Debug, PartialEq, Eq, Hash)]
106pub enum ColliderTreeSystems {
107 /// Updates the AABBs of colliders.
108 UpdateAabbs,
109 /// Begins optimizing acceleration structures to keep their query performance good.
110 ///
111 /// This runs concurrently with the simulation step as an async task.
112 BeginOptimize,
113 /// Completes the optimization of acceleration structures started in [`ColliderTreeSystems::BeginOptimize`].
114 ///
115 /// This runs at the end of the simulation step.
116 EndOptimize,
117}
118
119/// Trees for accelerating queries on a set of colliders.
120///
121/// See the [`collider_tree`](crate::collider_tree) module for more information.
122#[derive(Resource, Default, Clone)]
123pub struct ColliderTrees {
124 /// A tree for the colliders of dynamic bodies.
125 pub dynamic_tree: ColliderTree,
126 /// A tree for the colliders of kinematic bodies.
127 pub kinematic_tree: ColliderTree,
128 /// A tree for the colliders of static bodies.
129 pub static_tree: ColliderTree,
130 /// A tree for standalone colliders with no associated rigid body.
131 pub standalone_tree: ColliderTree,
132}
133
134impl ColliderTrees {
135 /// Returns the tree for the given [`ColliderTreeType`].
136 #[inline]
137 pub const fn tree_for_type(&self, tree_type: ColliderTreeType) -> &ColliderTree {
138 match tree_type {
139 ColliderTreeType::Dynamic => &self.dynamic_tree,
140 ColliderTreeType::Kinematic => &self.kinematic_tree,
141 ColliderTreeType::Static => &self.static_tree,
142 ColliderTreeType::Standalone => &self.standalone_tree,
143 }
144 }
145
146 /// Returns a mutable reference to the tree for the given [`ColliderTreeType`].
147 #[inline]
148 pub const fn tree_for_type_mut(&mut self, tree_type: ColliderTreeType) -> &mut ColliderTree {
149 match tree_type {
150 ColliderTreeType::Dynamic => &mut self.dynamic_tree,
151 ColliderTreeType::Kinematic => &mut self.kinematic_tree,
152 ColliderTreeType::Static => &mut self.static_tree,
153 ColliderTreeType::Standalone => &mut self.standalone_tree,
154 }
155 }
156
157 /// Returns an iterator over all collider trees.
158 #[inline]
159 pub fn iter_trees(&self) -> impl Iterator<Item = &ColliderTree> {
160 [
161 &self.dynamic_tree,
162 &self.kinematic_tree,
163 &self.static_tree,
164 &self.standalone_tree,
165 ]
166 .into_iter()
167 }
168
169 /// Returns a mutable iterator over all collider trees.
170 #[inline]
171 pub fn iter_trees_mut(&mut self) -> impl Iterator<Item = &mut ColliderTree> {
172 [
173 &mut self.dynamic_tree,
174 &mut self.kinematic_tree,
175 &mut self.static_tree,
176 &mut self.standalone_tree,
177 ]
178 .into_iter()
179 }
180
181 /// Returns the proxy with the given [`ColliderTreeProxyKey`], if it exists.
182 #[inline]
183 pub fn get_proxy(&self, key: ColliderTreeProxyKey) -> Option<&ColliderTreeProxy> {
184 self.tree_for_type(key.tree_type())
185 .proxies
186 .get(key.id().index())
187 }
188
189 /// Returns a mutable reference to the proxy with the given [`ColliderTreeProxyKey`], if it exists.
190 #[inline]
191 pub fn get_proxy_mut(&mut self, key: ColliderTreeProxyKey) -> Option<&mut ColliderTreeProxy> {
192 self.tree_for_type_mut(key.tree_type())
193 .proxies
194 .get_mut(key.id().index())
195 }
196}