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