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