1use crate::dynamics::{ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet};
4use crate::geometry::{
5 BroadPhaseBvh, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
6 ModifiedColliders, NarrowPhase,
7};
8use crate::math::Real;
9use crate::pipeline::{EventHandler, PhysicsHooks};
10use crate::{dynamics::RigidBodySet, geometry::ColliderSet};
11
12pub struct CollisionPipeline {
28 broadphase_collider_pairs: Vec<ColliderPair>,
29 broad_phase_events: Vec<BroadPhasePairEvent>,
30}
31
32#[allow(dead_code)]
33fn check_pipeline_send_sync() {
34 fn do_test<T: Sync>() {}
35 do_test::<CollisionPipeline>();
36}
37
38impl Default for CollisionPipeline {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl CollisionPipeline {
45 pub fn new() -> CollisionPipeline {
47 CollisionPipeline {
48 broadphase_collider_pairs: Vec::new(),
49 broad_phase_events: Vec::new(),
50 }
51 }
52
53 fn detect_collisions(
54 &mut self,
55 prediction_distance: Real,
56 islands: &mut IslandManager,
57 broad_phase: &mut BroadPhaseBvh,
58 narrow_phase: &mut NarrowPhase,
59 bodies: &mut RigidBodySet,
60 colliders: &mut ColliderSet,
61 modified_colliders: &[ColliderHandle],
62 removed_colliders: &[ColliderHandle],
63 hooks: &dyn PhysicsHooks,
64 events: &dyn EventHandler,
65 handle_user_changes: bool,
66 ) {
67 self.broad_phase_events.clear();
69 self.broadphase_collider_pairs.clear();
70
71 let params = IntegrationParameters {
72 normalized_prediction_distance: prediction_distance,
73 dt: 0.0,
74 ..Default::default()
75 };
76
77 broad_phase.update(
78 ¶ms,
79 colliders,
80 bodies,
81 modified_colliders,
82 removed_colliders,
83 &mut self.broad_phase_events,
84 );
85
86 if handle_user_changes {
88 narrow_phase.handle_user_changes(
89 None,
90 modified_colliders,
91 removed_colliders,
92 colliders,
93 bodies,
94 events,
95 );
96 }
97
98 narrow_phase.register_pairs(None, colliders, bodies, &self.broad_phase_events, events);
99 narrow_phase.compute_contacts(
100 prediction_distance,
101 0.0,
102 islands,
103 bodies,
104 colliders,
105 &ImpulseJointSet::new(),
106 &MultibodyJointSet::new(),
107 hooks,
108 events,
109 );
110 narrow_phase.compute_intersections(bodies, colliders, hooks, events);
111 }
112
113 fn clear_modified_colliders(
114 &mut self,
115 colliders: &mut ColliderSet,
116 modified_colliders: &mut ModifiedColliders,
117 ) {
118 for handle in modified_colliders.iter() {
119 if let Some(co) = colliders.get_mut_internal(*handle) {
120 co.changes = ColliderChanges::empty();
121 }
122 }
123
124 modified_colliders.clear();
125 }
126
127 pub fn step(
129 &mut self,
130 prediction_distance: Real,
131 islands: &mut IslandManager,
132 broad_phase: &mut BroadPhaseBvh,
133 narrow_phase: &mut NarrowPhase,
134 bodies: &mut RigidBodySet,
135 colliders: &mut ColliderSet,
136 hooks: &dyn PhysicsHooks,
137 events: &dyn EventHandler,
138 ) {
139 let modified_bodies = bodies.take_modified();
140 let mut modified_colliders = colliders.take_modified();
141 let mut removed_colliders = colliders.take_removed();
142
143 super::user_changes::handle_user_changes_to_colliders(
144 bodies,
145 colliders,
146 &modified_colliders[..],
147 );
148 super::user_changes::handle_user_changes_to_rigid_bodies(
149 None,
150 bodies,
151 colliders,
152 &mut ImpulseJointSet::new(),
153 &mut MultibodyJointSet::new(),
154 &modified_bodies,
155 &mut modified_colliders,
156 );
157
158 removed_colliders.extend(
160 modified_colliders
161 .iter()
162 .copied()
163 .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
164 );
165
166 self.detect_collisions(
167 prediction_distance,
168 islands,
169 broad_phase,
170 narrow_phase,
171 bodies,
172 colliders,
173 &modified_colliders[..],
174 &removed_colliders,
175 hooks,
176 events,
177 true,
178 );
179
180 self.clear_modified_colliders(colliders, &mut modified_colliders);
181 removed_colliders.clear();
182 }
183}
184
185#[cfg(test)]
186mod tests {
187
188 #[test]
189 #[cfg(feature = "dim3")]
190 pub fn test_no_rigid_bodies() {
191 use crate::prelude::*;
192 let mut rigid_body_set = RigidBodySet::new();
193 let mut collider_set = ColliderSet::new();
194
195 let collider_a = ColliderBuilder::cuboid(1.0, 1.0, 1.0)
197 .active_collision_types(ActiveCollisionTypes::all())
198 .sensor(true)
199 .active_events(ActiveEvents::COLLISION_EVENTS)
200 .build();
201
202 let a_handle = collider_set.insert(collider_a);
203
204 let collider_b = ColliderBuilder::cuboid(1.0, 1.0, 1.0)
205 .active_collision_types(ActiveCollisionTypes::all())
206 .sensor(true)
207 .active_events(ActiveEvents::COLLISION_EVENTS)
208 .build();
209
210 let _ = collider_set.insert(collider_b);
211
212 let integration_parameters = IntegrationParameters::default();
213 let mut islands = IslandManager::new();
214 let mut broad_phase = BroadPhaseBvh::new();
215 let mut narrow_phase = NarrowPhase::new();
216 let mut collision_pipeline = CollisionPipeline::new();
217 let physics_hooks = ();
218
219 collision_pipeline.step(
220 integration_parameters.prediction_distance(),
221 &mut islands,
222 &mut broad_phase,
223 &mut narrow_phase,
224 &mut rigid_body_set,
225 &mut collider_set,
226 &physics_hooks,
227 &(),
228 );
229
230 let mut hit = false;
231
232 for (_, _, intersecting) in narrow_phase.intersection_pairs_with(a_handle) {
233 if intersecting {
234 hit = true;
235 }
236 }
237
238 assert!(hit, "No hit found");
239 }
240
241 #[test]
242 #[cfg(feature = "dim2")]
243 pub fn test_no_rigid_bodies() {
244 use crate::prelude::*;
245 let mut rigid_body_set = RigidBodySet::new();
246 let mut collider_set = ColliderSet::new();
247
248 let collider_a = ColliderBuilder::cuboid(1.0, 1.0)
250 .active_collision_types(ActiveCollisionTypes::all())
251 .sensor(true)
252 .active_events(ActiveEvents::COLLISION_EVENTS)
253 .build();
254
255 let a_handle = collider_set.insert(collider_a);
256
257 let collider_b = ColliderBuilder::cuboid(1.0, 1.0)
258 .active_collision_types(ActiveCollisionTypes::all())
259 .sensor(true)
260 .active_events(ActiveEvents::COLLISION_EVENTS)
261 .build();
262
263 let _ = collider_set.insert(collider_b);
264
265 let integration_parameters = IntegrationParameters::default();
266 let mut islands = IslandManager::new();
267 let mut broad_phase = BroadPhaseBvh::new();
268 let mut narrow_phase = NarrowPhase::new();
269 let mut collision_pipeline = CollisionPipeline::new();
270 let physics_hooks = ();
271
272 collision_pipeline.step(
273 integration_parameters.prediction_distance(),
274 &mut islands,
275 &mut broad_phase,
276 &mut narrow_phase,
277 &mut rigid_body_set,
278 &mut collider_set,
279 &physics_hooks,
280 &(),
281 );
282
283 let mut hit = false;
284
285 for (_, _, intersecting) in narrow_phase.intersection_pairs_with(a_handle) {
286 if intersecting {
287 hit = true;
288 }
289 }
290
291 assert!(hit, "No hit found");
292 }
293}