1#[cfg(feature = "parallel")]
2use rayon::prelude::*;
3
4use crate::data::Coarena;
5use crate::data::graph::EdgeIndex;
6use crate::dynamics::{
7 CoefficientCombineRule, ImpulseJointSet, IslandManager, RigidBodyDominance, RigidBodySet,
8 RigidBodyType,
9};
10use crate::geometry::{
11 BoundingVolume, BroadPhasePairEvent, ColliderChanges, ColliderGraphIndex, ColliderHandle,
12 ColliderPair, ColliderSet, CollisionEvent, ContactData, ContactManifold, ContactManifoldData,
13 ContactPair, InteractionGraph, IntersectionPair, SolverContact, SolverFlags,
14 TemporaryInteractionIndex,
15};
16use crate::math::{Real, Vector};
17use crate::pipeline::{
18 ActiveEvents, ActiveHooks, ContactModificationContext, EventHandler, PairFilterContext,
19 PhysicsHooks,
20};
21use crate::prelude::{CollisionEventFlags, MultibodyJointSet};
22use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher};
23use parry::utils::IsometryOpt;
24use std::collections::HashMap;
25use std::sync::Arc;
26
27#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
28#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
29struct ColliderGraphIndices {
30 contact_graph_index: ColliderGraphIndex,
31 intersection_graph_index: ColliderGraphIndex,
32}
33
34impl ColliderGraphIndices {
35 fn invalid() -> Self {
36 Self {
37 contact_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
38 intersection_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
39 }
40 }
41}
42
43#[derive(Copy, Clone, PartialEq, Eq)]
44enum PairRemovalMode {
45 FromContactGraph,
46 FromIntersectionGraph,
47 Auto,
48}
49
50#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
52#[derive(Clone)]
53pub struct NarrowPhase {
54 #[cfg_attr(
55 feature = "serde-serialize",
56 serde(skip, default = "crate::geometry::default_persistent_query_dispatcher")
57 )]
58 query_dispatcher: Arc<dyn PersistentQueryDispatcher<ContactManifoldData, ContactData>>,
59 contact_graph: InteractionGraph<ColliderHandle, ContactPair>,
60 intersection_graph: InteractionGraph<ColliderHandle, IntersectionPair>,
61 graph_indices: Coarena<ColliderGraphIndices>,
62}
63
64pub(crate) type ContactManifoldIndex = usize;
65
66impl Default for NarrowPhase {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72impl NarrowPhase {
73 pub fn new() -> Self {
75 Self::with_query_dispatcher(DefaultQueryDispatcher)
76 }
77
78 pub fn with_query_dispatcher<D>(d: D) -> Self
80 where
81 D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
82 {
83 Self {
84 query_dispatcher: Arc::new(d),
85 contact_graph: InteractionGraph::new(),
86 intersection_graph: InteractionGraph::new(),
87 graph_indices: Coarena::new(),
88 }
89 }
90
91 pub fn query_dispatcher(
94 &self,
95 ) -> &dyn PersistentQueryDispatcher<ContactManifoldData, ContactData> {
96 &*self.query_dispatcher
97 }
98
99 pub fn contact_graph(&self) -> &InteractionGraph<ColliderHandle, ContactPair> {
101 &self.contact_graph
102 }
103
104 pub fn intersection_graph(&self) -> &InteractionGraph<ColliderHandle, IntersectionPair> {
106 &self.intersection_graph
107 }
108
109 pub fn contact_pairs_with_unknown_gen(
114 &self,
115 collider: u32,
116 ) -> impl Iterator<Item = &ContactPair> {
117 self.graph_indices
118 .get_unknown_gen(collider)
119 .map(|id| id.contact_graph_index)
120 .into_iter()
121 .flat_map(move |id| self.contact_graph.interactions_with(id))
122 .map(|pair| pair.2)
123 }
124
125 pub fn contact_pairs_with(
131 &self,
132 collider: ColliderHandle,
133 ) -> impl Iterator<Item = &ContactPair> {
134 self.graph_indices
135 .get(collider.0)
136 .map(|id| id.contact_graph_index)
137 .into_iter()
138 .flat_map(move |id| self.contact_graph.interactions_with(id))
139 .map(|pair| pair.2)
140 }
141
142 pub fn intersection_pairs_with_unknown_gen(
147 &self,
148 collider: u32,
149 ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
150 self.graph_indices
151 .get_unknown_gen(collider)
152 .map(|id| id.intersection_graph_index)
153 .into_iter()
154 .flat_map(move |id| {
155 self.intersection_graph
156 .interactions_with(id)
157 .map(|e| (e.0, e.1, e.2.intersecting))
158 })
159 }
160
161 pub fn intersection_pairs_with(
168 &self,
169 collider: ColliderHandle,
170 ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
171 self.graph_indices
172 .get(collider.0)
173 .map(|id| id.intersection_graph_index)
174 .into_iter()
175 .flat_map(move |id| {
176 self.intersection_graph
177 .interactions_with(id)
178 .map(|e| (e.0, e.1, e.2.intersecting))
179 })
180 }
181
182 pub fn contact_pair_at_index(&self, id: TemporaryInteractionIndex) -> &ContactPair {
184 &self.contact_graph.graph.edges[id.index()].weight
185 }
186
187 pub fn contact_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<&ContactPair> {
196 let id1 = self.graph_indices.get_unknown_gen(collider1)?;
197 let id2 = self.graph_indices.get_unknown_gen(collider2)?;
198 self.contact_graph
199 .interaction_pair(id1.contact_graph_index, id2.contact_graph_index)
200 .map(|c| c.2)
201 }
202
203 pub fn contact_pair(
209 &self,
210 collider1: ColliderHandle,
211 collider2: ColliderHandle,
212 ) -> Option<&ContactPair> {
213 let id1 = self.graph_indices.get(collider1.0)?;
214 let id2 = self.graph_indices.get(collider2.0)?;
215 self.contact_graph
216 .interaction_pair(id1.contact_graph_index, id2.contact_graph_index)
217 .map(|c| c.2)
218 }
219
220 pub fn intersection_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<bool> {
228 let id1 = self.graph_indices.get_unknown_gen(collider1)?;
229 let id2 = self.graph_indices.get_unknown_gen(collider2)?;
230 self.intersection_graph
231 .interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index)
232 .map(|c| c.2.intersecting)
233 }
234
235 pub fn intersection_pair(
240 &self,
241 collider1: ColliderHandle,
242 collider2: ColliderHandle,
243 ) -> Option<bool> {
244 let id1 = self.graph_indices.get(collider1.0)?;
245 let id2 = self.graph_indices.get(collider2.0)?;
246 self.intersection_graph
247 .interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index)
248 .map(|c| c.2.intersecting)
249 }
250
251 pub fn contact_pairs(&self) -> impl Iterator<Item = &ContactPair> {
253 self.contact_graph.interactions()
254 }
255
256 pub fn intersection_pairs(
258 &self,
259 ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
260 self.intersection_graph
261 .interactions_with_endpoints()
262 .map(|e| (e.0, e.1, e.2.intersecting))
263 }
264
265 #[profiling::function]
272 pub fn handle_user_changes(
273 &mut self,
274 mut islands: Option<&mut IslandManager>,
275 modified_colliders: &[ColliderHandle],
276 removed_colliders: &[ColliderHandle],
277 colliders: &mut ColliderSet,
278 bodies: &mut RigidBodySet,
279 events: &dyn EventHandler,
280 ) {
281 let mut prox_id_remap = HashMap::new();
285 let mut contact_id_remap = HashMap::new();
286
287 for collider in removed_colliders {
288 if let Some(graph_idx) = self
291 .graph_indices
292 .remove(collider.0, ColliderGraphIndices::invalid())
293 {
294 let intersection_graph_id = prox_id_remap
295 .get(collider)
296 .copied()
297 .unwrap_or(graph_idx.intersection_graph_index);
298 let contact_graph_id = contact_id_remap
299 .get(collider)
300 .copied()
301 .unwrap_or(graph_idx.contact_graph_index);
302
303 self.remove_collider(
304 intersection_graph_id,
305 contact_graph_id,
306 islands.as_deref_mut(),
307 colliders,
308 bodies,
309 &mut prox_id_remap,
310 &mut contact_id_remap,
311 events,
312 );
313 }
314 }
315
316 self.handle_user_changes_on_colliders(
317 islands,
318 modified_colliders,
319 colliders,
320 bodies,
321 events,
322 );
323 }
324
325 #[profiling::function]
326 pub(crate) fn remove_collider(
327 &mut self,
328 intersection_graph_id: ColliderGraphIndex,
329 contact_graph_id: ColliderGraphIndex,
330 islands: Option<&mut IslandManager>,
331 colliders: &mut ColliderSet,
332 bodies: &mut RigidBodySet,
333 prox_id_remap: &mut HashMap<ColliderHandle, ColliderGraphIndex>,
334 contact_id_remap: &mut HashMap<ColliderHandle, ColliderGraphIndex>,
335 events: &dyn EventHandler,
336 ) {
337 if let Some(islands) = islands {
339 for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) {
340 if let Some(parent) = colliders.get(a).and_then(|c| c.parent.as_ref()) {
341 islands.wake_up(bodies, parent.handle, true)
342 }
343
344 if let Some(parent) = colliders.get(b).and_then(|c| c.parent.as_ref()) {
345 islands.wake_up(bodies, parent.handle, true)
346 }
347
348 if pair.start_event_emitted {
349 events.handle_collision_event(
350 bodies,
351 colliders,
352 CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED),
353 Some(pair),
354 );
355 }
356 }
357 } else {
358 for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) {
360 if pair.start_event_emitted {
361 events.handle_collision_event(
362 bodies,
363 colliders,
364 CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED),
365 Some(pair),
366 );
367 }
368 }
369 }
370
371 for (a, b, pair) in self
373 .intersection_graph
374 .interactions_with(intersection_graph_id)
375 {
376 if pair.start_event_emitted {
377 events.handle_collision_event(
378 bodies,
379 colliders,
380 CollisionEvent::Stopped(
381 a,
382 b,
383 CollisionEventFlags::REMOVED | CollisionEventFlags::SENSOR,
384 ),
385 None,
386 );
387 }
388 }
389
390 if let Some(replacement) = self.intersection_graph.remove_node(intersection_graph_id) {
393 if let Some(replacement) = self.graph_indices.get_mut(replacement.0) {
394 replacement.intersection_graph_index = intersection_graph_id;
395 } else {
396 prox_id_remap.insert(replacement, intersection_graph_id);
397 unreachable!();
401 }
402 }
403
404 if let Some(replacement) = self.contact_graph.remove_node(contact_graph_id) {
405 if let Some(replacement) = self.graph_indices.get_mut(replacement.0) {
406 replacement.contact_graph_index = contact_graph_id;
407 } else {
408 contact_id_remap.insert(replacement, contact_graph_id);
409 unreachable!();
413 }
414 }
415 }
416
417 #[profiling::function]
418 pub(crate) fn handle_user_changes_on_colliders(
419 &mut self,
420 mut islands: Option<&mut IslandManager>,
421 modified_colliders: &[ColliderHandle],
422 colliders: &ColliderSet,
423 bodies: &mut RigidBodySet,
424 events: &dyn EventHandler,
425 ) {
426 let mut pairs_to_remove = vec![];
427
428 for handle in modified_colliders {
429 if let Some(co) = colliders.get(*handle) {
432 if !co.changes.needs_narrow_phase_update() {
433 continue;
435 }
436
437 if let Some(gid) = self.graph_indices.get(handle.0) {
438 if let Some(islands) = islands.as_deref_mut() {
443 if let Some(co_parent) = &co.parent {
444 islands.wake_up(bodies, co_parent.handle, true);
445 }
446
447 for inter in self
448 .contact_graph
449 .interactions_with(gid.contact_graph_index)
450 {
451 let other_handle = if *handle == inter.0 { inter.1 } else { inter.0 };
452 let other_parent = colliders
453 .get(other_handle)
454 .and_then(|co| co.parent.as_ref());
455
456 if let Some(other_parent) = other_parent {
457 islands.wake_up(bodies, other_parent.handle, true);
458 }
459 }
460 }
461
462 if co.changes.intersects(ColliderChanges::TYPE) {
467 if co.is_sensor() {
468 for inter in self
471 .contact_graph
472 .interactions_with(gid.contact_graph_index)
473 {
474 pairs_to_remove.push((
475 ColliderPair::new(inter.0, inter.1),
476 PairRemovalMode::FromContactGraph,
477 ));
478 }
479 } else {
480 for inter in self
484 .intersection_graph
485 .interactions_with(gid.intersection_graph_index)
486 .filter(|(h1, h2, _)| {
487 !colliders[*h1].is_sensor() && !colliders[*h2].is_sensor()
488 })
489 {
490 pairs_to_remove.push((
491 ColliderPair::new(inter.0, inter.1),
492 PairRemovalMode::FromIntersectionGraph,
493 ));
494 }
495 }
496 }
497
498 }
504 }
505 }
506
507 for pair in &pairs_to_remove {
509 self.remove_pair(
510 islands.as_deref_mut(),
511 colliders,
512 bodies,
513 &pair.0,
514 events,
515 pair.1,
516 );
517 }
518
519 for pair in pairs_to_remove {
521 self.add_pair(colliders, &pair.0);
522 }
523 }
524
525 #[profiling::function]
526 fn remove_pair(
527 &mut self,
528 islands: Option<&mut IslandManager>,
529 colliders: &ColliderSet,
530 bodies: &mut RigidBodySet,
531 pair: &ColliderPair,
532 events: &dyn EventHandler,
533 mode: PairRemovalMode,
534 ) {
535 if let (Some(co1), Some(co2)) =
536 (colliders.get(pair.collider1), colliders.get(pair.collider2))
537 {
538 if let (Some(gid1), Some(gid2)) = (
541 self.graph_indices.get(pair.collider1.0),
542 self.graph_indices.get(pair.collider2.0),
543 ) {
544 if mode == PairRemovalMode::FromIntersectionGraph
545 || (mode == PairRemovalMode::Auto && (co1.is_sensor() || co2.is_sensor()))
546 {
547 let intersection = self
548 .intersection_graph
549 .remove_edge(gid1.intersection_graph_index, gid2.intersection_graph_index);
550
551 if let Some(mut intersection) = intersection {
553 if intersection.intersecting
554 && (co1.flags.active_events | co2.flags.active_events)
555 .contains(ActiveEvents::COLLISION_EVENTS)
556 {
557 intersection.emit_stop_event(
558 bodies,
559 colliders,
560 pair.collider1,
561 pair.collider2,
562 events,
563 )
564 }
565 }
566 } else {
567 let contact_pair = self
568 .contact_graph
569 .remove_edge(gid1.contact_graph_index, gid2.contact_graph_index);
570
571 if let Some(mut ctct) = contact_pair {
574 if ctct.has_any_active_contact {
575 if let Some(islands) = islands {
576 if let Some(co_parent1) = &co1.parent {
577 islands.wake_up(bodies, co_parent1.handle, true);
578 }
579
580 if let Some(co_parent2) = co2.parent {
581 islands.wake_up(bodies, co_parent2.handle, true);
582 }
583 }
584
585 if (co1.flags.active_events | co2.flags.active_events)
586 .contains(ActiveEvents::COLLISION_EVENTS)
587 {
588 ctct.emit_stop_event(bodies, colliders, events);
589 }
590 }
591 }
592 }
593 }
594 }
595 }
596
597 #[profiling::function]
598 fn add_pair(&mut self, colliders: &ColliderSet, pair: &ColliderPair) {
599 if let (Some(co1), Some(co2)) =
600 (colliders.get(pair.collider1), colliders.get(pair.collider2))
601 {
602 let (gid1, gid2) = self.graph_indices.ensure_pair_exists(
605 pair.collider1.0,
606 pair.collider2.0,
607 ColliderGraphIndices::invalid(),
608 );
609
610 if co1.is_sensor() || co2.is_sensor() {
611 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid1.intersection_graph_index)
614 {
615 gid1.intersection_graph_index =
616 self.intersection_graph.graph.add_node(pair.collider1);
617 }
618
619 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid2.intersection_graph_index)
620 {
621 gid2.intersection_graph_index =
622 self.intersection_graph.graph.add_node(pair.collider2);
623 }
624
625 if self
626 .intersection_graph
627 .graph
628 .find_edge(gid1.intersection_graph_index, gid2.intersection_graph_index)
629 .is_none()
630 {
631 let _ = self.intersection_graph.add_edge(
632 gid1.intersection_graph_index,
633 gid2.intersection_graph_index,
634 IntersectionPair::new(),
635 );
636 }
637 } else {
638 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid1.contact_graph_index) {
644 gid1.contact_graph_index = self.contact_graph.graph.add_node(pair.collider1);
645 }
646
647 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid2.contact_graph_index) {
648 gid2.contact_graph_index = self.contact_graph.graph.add_node(pair.collider2);
649 }
650
651 if self
652 .contact_graph
653 .graph
654 .find_edge(gid1.contact_graph_index, gid2.contact_graph_index)
655 .is_none()
656 {
657 let interaction = ContactPair::new(pair.collider1, pair.collider2);
658 let _ = self.contact_graph.add_edge(
659 gid1.contact_graph_index,
660 gid2.contact_graph_index,
661 interaction,
662 );
663 }
664 }
665 }
666 }
667
668 pub(crate) fn register_pairs(
669 &mut self,
670 mut islands: Option<&mut IslandManager>,
671 colliders: &ColliderSet,
672 bodies: &mut RigidBodySet,
673 broad_phase_events: &[BroadPhasePairEvent],
674 events: &dyn EventHandler,
675 ) {
676 for event in broad_phase_events {
677 match event {
678 BroadPhasePairEvent::AddPair(pair) => {
679 self.add_pair(colliders, pair);
680 }
681 BroadPhasePairEvent::DeletePair(pair) => {
682 self.remove_pair(
683 islands.as_deref_mut(),
684 colliders,
685 bodies,
686 pair,
687 events,
688 PairRemovalMode::Auto,
689 );
690 }
691 }
692 }
693 }
694
695 #[profiling::function]
696 pub(crate) fn compute_intersections(
697 &mut self,
698 bodies: &RigidBodySet,
699 colliders: &ColliderSet,
700 modified_colliders: &[ColliderHandle],
701 hooks: &dyn PhysicsHooks,
702 events: &dyn EventHandler,
703 ) {
704 if modified_colliders.is_empty() {
705 return;
706 }
707
708 let nodes = &self.intersection_graph.graph.nodes;
709 let query_dispatcher = &*self.query_dispatcher;
710
711 par_iter_mut!(&mut self.intersection_graph.graph.edges).for_each(|edge| {
713 let handle1 = nodes[edge.source().index()].weight;
714 let handle2 = nodes[edge.target().index()].weight;
715 let had_intersection = edge.weight.intersecting;
716 let co1 = &colliders[handle1];
717 let co2 = &colliders[handle2];
718
719 'emit_events: {
720 if !co1.changes.needs_narrow_phase_update()
721 && !co2.changes.needs_narrow_phase_update()
722 {
723 return;
725 }
726 if co1.parent.map(|p| p.handle) == co2.parent.map(|p| p.handle)
727 && co1.parent.is_some()
728 {
729 edge.weight.intersecting = false;
731 break 'emit_events;
732 }
733 let mut rb_type1 = RigidBodyType::Fixed;
735 let mut rb_type2 = RigidBodyType::Fixed;
736
737 if let Some(co_parent1) = &co1.parent {
738 rb_type1 = bodies[co_parent1.handle].body_type;
739 }
740
741 if let Some(co_parent2) = &co2.parent {
742 rb_type2 = bodies[co_parent2.handle].body_type;
743 }
744
745 if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
747 && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
748 {
749 edge.weight.intersecting = false;
750 break 'emit_events;
751 }
752
753 if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
755 edge.weight.intersecting = false;
756 break 'emit_events;
757 }
758
759 let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
760
761 if active_hooks.contains(ActiveHooks::FILTER_INTERSECTION_PAIR) {
762 let context = PairFilterContext {
763 bodies,
764 colliders,
765 rigid_body1: co1.parent.map(|p| p.handle),
766 rigid_body2: co2.parent.map(|p| p.handle),
767 collider1: handle1,
768 collider2: handle2,
769 };
770
771 if !hooks.filter_intersection_pair(&context) {
772 edge.weight.intersecting = false;
774 break 'emit_events;
775 }
776 }
777
778 let pos12 = co1.pos.inv_mul(&co2.pos);
779 edge.weight.intersecting = query_dispatcher
780 .intersection_test(&pos12, &*co1.shape, &*co2.shape)
781 .unwrap_or(false);
782 }
783
784 let active_events = co1.flags.active_events | co2.flags.active_events;
785
786 if active_events.contains(ActiveEvents::COLLISION_EVENTS)
787 && had_intersection != edge.weight.intersecting
788 {
789 if edge.weight.intersecting {
790 edge.weight
791 .emit_start_event(bodies, colliders, handle1, handle2, events);
792 } else {
793 edge.weight
794 .emit_stop_event(bodies, colliders, handle1, handle2, events);
795 }
796 }
797 });
798 }
799
800 #[profiling::function]
801 pub(crate) fn compute_contacts(
802 &mut self,
803 prediction_distance: Real,
804 dt: Real,
805 bodies: &RigidBodySet,
806 colliders: &ColliderSet,
807 impulse_joints: &ImpulseJointSet,
808 multibody_joints: &MultibodyJointSet,
809 modified_colliders: &[ColliderHandle],
810 hooks: &dyn PhysicsHooks,
811 events: &dyn EventHandler,
812 ) {
813 if modified_colliders.is_empty() {
814 return;
815 }
816
817 let query_dispatcher = &*self.query_dispatcher;
818
819 par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| {
821 let pair = &mut edge.weight;
822 let had_any_active_contact = pair.has_any_active_contact;
823 let co1 = &colliders[pair.collider1];
824 let co2 = &colliders[pair.collider2];
825
826 'emit_events: {
827 if !co1.changes.needs_narrow_phase_update()
828 && !co2.changes.needs_narrow_phase_update()
829 {
830 return;
832 }
833 if co1.parent.map(|p| p.handle) == co2.parent.map(|p| p.handle) && co1.parent.is_some()
834 {
835 pair.clear();
837 break 'emit_events;
838 }
839
840 let rb1 = co1.parent.map(|co_parent1| &bodies[co_parent1.handle]);
841 let rb2 = co2.parent.map(|co_parent2| &bodies[co_parent2.handle]);
842
843 let rb_type1 = rb1.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
844 let rb_type2 = rb2.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
845
846 if let (Some(co_parent1), Some(co_parent2)) = (&co1.parent, &co2.parent) {
848 for (_, joint) in
849 impulse_joints.joints_between(co_parent1.handle, co_parent2.handle)
850 {
851 if !joint.data.contacts_enabled {
852 pair.clear();
853 break 'emit_events;
854 }
855 }
856
857 let link1 = multibody_joints.rigid_body_link(co_parent1.handle);
858 let link2 = multibody_joints.rigid_body_link(co_parent2.handle);
859
860 if let (Some(link1),Some(link2)) = (link1, link2) {
861 if link1.multibody == link2.multibody {
864 if let Some(mb) = multibody_joints.get_multibody(link1.multibody) {
866 if !mb.self_contacts_enabled() {
867 pair.clear();
868 break 'emit_events;
869 }
870 }
871
872 if let Some((_, _, mb_link)) =
874 multibody_joints.joint_between(co_parent1.handle, co_parent2.handle)
875 {
876 if !mb_link.joint.data.contacts_enabled {
877 pair.clear();
878 break 'emit_events;
879 }
880 }
881 }
882 }
883 }
884
885 if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
887 && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
888 {
889 pair.clear();
890 break 'emit_events;
891 }
892
893 if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
895 pair.clear();
896 break 'emit_events;
897 }
898
899 let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
900
901 let mut solver_flags = if active_hooks.contains(ActiveHooks::FILTER_CONTACT_PAIRS) {
902 let context = PairFilterContext {
903 bodies,
904 colliders,
905 rigid_body1: co1.parent.map(|p| p.handle),
906 rigid_body2: co2.parent.map(|p| p.handle),
907 collider1: pair.collider1,
908 collider2: pair.collider2,
909 };
910
911 if let Some(solver_flags) = hooks.filter_contact_pair(&context) {
912 solver_flags
913 } else {
914 pair.clear();
916 break 'emit_events;
917 }
918 } else {
919 SolverFlags::default()
920 };
921
922 if !co1.flags.solver_groups.test(co2.flags.solver_groups) {
923 solver_flags.remove(SolverFlags::COMPUTE_IMPULSES);
924 }
925
926 if co1.changes.contains(ColliderChanges::SHAPE)
927 || co2.changes.contains(ColliderChanges::SHAPE)
928 {
929 pair.workspace = None;
931 }
932
933 let pos12 = co1.pos.inv_mul(&co2.pos);
934
935 let contact_skin_sum = co1.contact_skin() + co2.contact_skin();
936 let soft_ccd_prediction1 = rb1.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
937 let soft_ccd_prediction2 = rb2.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
938 let effective_prediction_distance = if soft_ccd_prediction1 > 0.0 || soft_ccd_prediction2 > 0.0 {
939 let aabb1 = co1.compute_collision_aabb(0.0);
940 let aabb2 = co2.compute_collision_aabb(0.0);
941 let inv_dt = crate::utils::inv(dt);
942
943 let linvel1 = rb1.map(|rb| rb.linvel()
944 .cap_magnitude(soft_ccd_prediction1 * inv_dt)).unwrap_or_default();
945 let linvel2 = rb2.map(|rb| rb.linvel()
946 .cap_magnitude(soft_ccd_prediction2 * inv_dt)).unwrap_or_default();
947
948 if !aabb1.intersects(&aabb2) && !aabb1.intersects_moving_aabb(&aabb2, linvel2 - linvel1) {
949 pair.clear();
950 break 'emit_events;
951 }
952
953
954 prediction_distance.max(
955 dt * (linvel1 - linvel2).norm()) + contact_skin_sum
956 } else {
957 prediction_distance + contact_skin_sum
958 };
959
960 let _ = query_dispatcher.contact_manifolds(
961 &pos12,
962 &*co1.shape,
963 &*co2.shape,
964 effective_prediction_distance,
965 &mut pair.manifolds,
966 &mut pair.workspace,
967 );
968
969 let friction = CoefficientCombineRule::combine(
970 co1.material.friction,
971 co2.material.friction,
972 co1.material.friction_combine_rule,
973 co2.material.friction_combine_rule,
974 );
975 let restitution = CoefficientCombineRule::combine(
976 co1.material.restitution,
977 co2.material.restitution,
978 co1.material.restitution_combine_rule,
979 co2.material.restitution_combine_rule,
980 );
981
982 let zero = RigidBodyDominance(0); let dominance1 = rb1.map(|rb| rb.dominance).unwrap_or(zero);
984 let dominance2 = rb2.map(|rb| rb.dominance).unwrap_or(zero);
985
986 pair.has_any_active_contact = false;
987
988 for manifold in &mut pair.manifolds {
989 let world_pos1 = manifold.subshape_pos1.prepend_to(&co1.pos);
990 let world_pos2 = manifold.subshape_pos2.prepend_to(&co2.pos);
991 manifold.data.solver_contacts.clear();
992 manifold.data.rigid_body1 = co1.parent.map(|p| p.handle);
993 manifold.data.rigid_body2 = co2.parent.map(|p| p.handle);
994 manifold.data.solver_flags = solver_flags;
995 manifold.data.relative_dominance = dominance1.effective_group(&rb_type1)
996 - dominance2.effective_group(&rb_type2);
997 manifold.data.normal = world_pos1 * manifold.local_n1;
998
999 for (contact_id, contact) in manifold.points.iter().enumerate() {
1001 if contact_id > u8::MAX as usize {
1002 log::warn!("A contact manifold cannot contain more than 255 contacts currently, dropping contact in excess.");
1003 break;
1004 }
1005
1006 let effective_contact_dist = contact.dist - co1.contact_skin() - co2.contact_skin();
1007
1008 let keep_solver_contact = effective_contact_dist < prediction_distance || {
1009 let world_pt1 = world_pos1 * contact.local_p1;
1010 let world_pt2 = world_pos2 * contact.local_p2;
1011 let vel1 = rb1.map(|rb| rb.velocity_at_point(&world_pt1)).unwrap_or_default();
1012 let vel2 = rb2.map(|rb| rb.velocity_at_point(&world_pt2)).unwrap_or_default();
1013 effective_contact_dist + (vel2 - vel1).dot(&manifold.data.normal) * dt < prediction_distance
1014 };
1015
1016 if keep_solver_contact {
1017 let world_pt1 = world_pos1 * contact.local_p1;
1019 let world_pt2 = world_pos2 * contact.local_p2;
1020 let effective_point = na::center(&world_pt1, &world_pt2);
1021
1022 let solver_contact = SolverContact {
1023 contact_id: contact_id as u8,
1024 point: effective_point,
1025 dist: effective_contact_dist,
1026 friction,
1027 restitution,
1028 tangent_velocity: Vector::zeros(),
1029 is_new: contact.data.impulse == 0.0,
1030 warmstart_impulse: contact.data.warmstart_impulse,
1031 warmstart_tangent_impulse: contact.data.warmstart_tangent_impulse,
1032 };
1033
1034 manifold.data.solver_contacts.push(solver_contact);
1035 pair.has_any_active_contact = true;
1036 }
1037 }
1038
1039 if active_hooks.contains(ActiveHooks::MODIFY_SOLVER_CONTACTS) {
1041 let mut modifiable_solver_contacts =
1042 std::mem::take(&mut manifold.data.solver_contacts);
1043 let mut modifiable_user_data = manifold.data.user_data;
1044 let mut modifiable_normal = manifold.data.normal;
1045
1046 let mut context = ContactModificationContext {
1047 bodies,
1048 colliders,
1049 rigid_body1: co1.parent.map(|p| p.handle),
1050 rigid_body2: co2.parent.map(|p| p.handle),
1051 collider1: pair.collider1,
1052 collider2: pair.collider2,
1053 manifold,
1054 solver_contacts: &mut modifiable_solver_contacts,
1055 normal: &mut modifiable_normal,
1056 user_data: &mut modifiable_user_data,
1057 };
1058
1059 hooks.modify_solver_contacts(&mut context);
1060
1061 manifold.data.solver_contacts = modifiable_solver_contacts;
1062 manifold.data.normal = modifiable_normal;
1063 manifold.data.user_data = modifiable_user_data;
1064 }
1065
1066 }
1095 }
1096
1097 let active_events = co1.flags.active_events | co2.flags.active_events;
1098
1099 if pair.has_any_active_contact != had_any_active_contact
1100 && active_events.contains(ActiveEvents::COLLISION_EVENTS)
1101 {
1102 if pair.has_any_active_contact {
1103 pair.emit_start_event(bodies, colliders, events);
1104 } else {
1105 pair.emit_stop_event(bodies, colliders, events);
1106 }
1107 }
1108 });
1109 }
1110
1111 pub(crate) fn select_active_contacts<'a>(
1114 &'a mut self,
1115 islands: &IslandManager,
1116 bodies: &RigidBodySet,
1117 out_contact_pairs: &mut Vec<TemporaryInteractionIndex>,
1118 out_manifolds: &mut Vec<&'a mut ContactManifold>,
1119 out: &mut [Vec<ContactManifoldIndex>],
1120 ) {
1121 for out_island in &mut out[..islands.num_islands()] {
1122 out_island.clear();
1123 }
1124
1125 for (pair_id, inter) in self.contact_graph.graph.edges.iter_mut().enumerate() {
1127 let mut push_pair = false;
1128
1129 for manifold in &mut inter.weight.manifolds {
1130 if manifold
1131 .data
1132 .solver_flags
1133 .contains(SolverFlags::COMPUTE_IMPULSES)
1134 && manifold.data.num_active_contacts() != 0
1135 {
1136 let (active_island_id1, rb_type1, sleeping1) =
1137 if let Some(handle1) = manifold.data.rigid_body1 {
1138 let rb1 = &bodies[handle1];
1139 (
1140 rb1.ids.active_island_id,
1141 rb1.body_type,
1142 rb1.activation.sleeping,
1143 )
1144 } else {
1145 (0, RigidBodyType::Fixed, true)
1146 };
1147
1148 let (active_island_id2, rb_type2, sleeping2) =
1149 if let Some(handle2) = manifold.data.rigid_body2 {
1150 let rb2 = &bodies[handle2];
1151 (
1152 rb2.ids.active_island_id,
1153 rb2.body_type,
1154 rb2.activation.sleeping,
1155 )
1156 } else {
1157 (0, RigidBodyType::Fixed, true)
1158 };
1159
1160 if (rb_type1.is_dynamic() || rb_type2.is_dynamic())
1161 && (!rb_type1.is_dynamic() || !sleeping1)
1162 && (!rb_type2.is_dynamic() || !sleeping2)
1163 {
1164 let island_index = if !rb_type1.is_dynamic() {
1165 active_island_id2
1166 } else {
1167 active_island_id1
1168 };
1169
1170 out[island_index].push(out_manifolds.len());
1171 out_manifolds.push(manifold);
1172 push_pair = true;
1173 }
1174 }
1175 }
1176
1177 if push_pair {
1178 out_contact_pairs.push(EdgeIndex::new(pair_id as u32));
1179 }
1180 }
1181 }
1182}
1183
1184#[cfg(test)]
1185#[cfg(feature = "f32")]
1186#[cfg(feature = "dim3")]
1187mod test {
1188 use na::vector;
1189
1190 use crate::prelude::{
1191 CCDSolver, ColliderBuilder, DefaultBroadPhase, IntegrationParameters, PhysicsPipeline,
1192 RigidBodyBuilder,
1193 };
1194
1195 use super::*;
1196
1197 #[test]
1199 pub fn collider_set_parent_depenetration() {
1200 let mut rigid_body_set = RigidBodySet::new();
1205 let mut collider_set = ColliderSet::new();
1206
1207 let collider = ColliderBuilder::ball(0.5);
1209
1210 let rigid_body_1 = RigidBodyBuilder::dynamic()
1212 .translation(vector![0.0, 0.0, 0.0])
1213 .build();
1214 let body_1_handle = rigid_body_set.insert(rigid_body_1);
1215
1216 let collider_1_handle =
1218 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1219
1220 let collider_2_handle =
1222 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1223
1224 let rigid_body_2 = RigidBodyBuilder::dynamic()
1226 .translation(vector![0.0, 0.0, 0.0])
1227 .build();
1228 let body_2_handle = rigid_body_set.insert(rigid_body_2);
1229
1230 let gravity = vector![0.0, 0.0, 0.0];
1232 let integration_parameters = IntegrationParameters::default();
1233 let mut physics_pipeline = PhysicsPipeline::new();
1234 let mut island_manager = IslandManager::new();
1235 let mut broad_phase = DefaultBroadPhase::new();
1236 let mut narrow_phase = NarrowPhase::new();
1237 let mut impulse_joint_set = ImpulseJointSet::new();
1238 let mut multibody_joint_set = MultibodyJointSet::new();
1239 let mut ccd_solver = CCDSolver::new();
1240 let physics_hooks = ();
1241 let event_handler = ();
1242
1243 physics_pipeline.step(
1244 &gravity,
1245 &integration_parameters,
1246 &mut island_manager,
1247 &mut broad_phase,
1248 &mut narrow_phase,
1249 &mut rigid_body_set,
1250 &mut collider_set,
1251 &mut impulse_joint_set,
1252 &mut multibody_joint_set,
1253 &mut ccd_solver,
1254 &physics_hooks,
1255 &event_handler,
1256 );
1257 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1258 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1259 assert!(
1260 (collider_1_position.translation.vector - collider_2_position.translation.vector)
1261 .magnitude()
1262 < 0.5f32
1263 );
1264
1265 let contact_pair = narrow_phase
1266 .contact_pair(collider_1_handle, collider_2_handle)
1267 .expect("The contact pair should exist.");
1268 assert_eq!(contact_pair.manifolds.len(), 0);
1269 assert!(
1270 narrow_phase
1271 .intersection_pair(collider_1_handle, collider_2_handle)
1272 .is_none(),
1273 "Interaction pair is for sensors"
1274 );
1275 collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1277
1278 physics_pipeline.step(
1279 &gravity,
1280 &integration_parameters,
1281 &mut island_manager,
1282 &mut broad_phase,
1283 &mut narrow_phase,
1284 &mut rigid_body_set,
1285 &mut collider_set,
1286 &mut impulse_joint_set,
1287 &mut multibody_joint_set,
1288 &mut ccd_solver,
1289 &physics_hooks,
1290 &event_handler,
1291 );
1292
1293 let contact_pair = narrow_phase
1294 .contact_pair(collider_1_handle, collider_2_handle)
1295 .expect("The contact pair should exist.");
1296 assert_eq!(contact_pair.manifolds.len(), 1);
1297 assert!(
1298 narrow_phase
1299 .intersection_pair(collider_1_handle, collider_2_handle)
1300 .is_none(),
1301 "Interaction pair is for sensors"
1302 );
1303
1304 for _ in 0..200 {
1306 physics_pipeline.step(
1307 &gravity,
1308 &integration_parameters,
1309 &mut island_manager,
1310 &mut broad_phase,
1311 &mut narrow_phase,
1312 &mut rigid_body_set,
1313 &mut collider_set,
1314 &mut impulse_joint_set,
1315 &mut multibody_joint_set,
1316 &mut ccd_solver,
1317 &physics_hooks,
1318 &event_handler,
1319 );
1320
1321 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1322 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1323 println!("collider 1 position: {}", collider_1_position.translation);
1324 println!("collider 2 position: {}", collider_2_position.translation);
1325 }
1326
1327 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1328 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1329 println!("collider 2 position: {}", collider_2_position.translation);
1330 assert!(
1331 (collider_1_position.translation.vector - collider_2_position.translation.vector)
1332 .magnitude()
1333 >= 0.5f32,
1334 "colliders should no longer be penetrating."
1335 );
1336 }
1337
1338 #[test]
1340 pub fn collider_set_parent_no_self_intersection() {
1341 let mut rigid_body_set = RigidBodySet::new();
1349 let mut collider_set = ColliderSet::new();
1350
1351 let collider = ColliderBuilder::ball(0.5);
1353
1354 let rigid_body_1 = RigidBodyBuilder::dynamic()
1356 .translation(vector![0.0, 0.0, 0.0])
1357 .build();
1358 let body_1_handle = rigid_body_set.insert(rigid_body_1);
1359
1360 let collider_1_handle =
1362 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1363
1364 let rigid_body_2 = RigidBodyBuilder::dynamic()
1366 .translation(vector![0.0, 0.0, 0.0])
1367 .build();
1368 let body_2_handle = rigid_body_set.insert(rigid_body_2);
1369
1370 let collider_2_handle =
1372 collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set);
1373
1374 let gravity = vector![0.0, 0.0, 0.0];
1376 let integration_parameters = IntegrationParameters::default();
1377 let mut physics_pipeline = PhysicsPipeline::new();
1378 let mut island_manager = IslandManager::new();
1379 let mut broad_phase = DefaultBroadPhase::new();
1380 let mut narrow_phase = NarrowPhase::new();
1381 let mut impulse_joint_set = ImpulseJointSet::new();
1382 let mut multibody_joint_set = MultibodyJointSet::new();
1383 let mut ccd_solver = CCDSolver::new();
1384 let physics_hooks = ();
1385 let event_handler = ();
1386
1387 physics_pipeline.step(
1388 &gravity,
1389 &integration_parameters,
1390 &mut island_manager,
1391 &mut broad_phase,
1392 &mut narrow_phase,
1393 &mut rigid_body_set,
1394 &mut collider_set,
1395 &mut impulse_joint_set,
1396 &mut multibody_joint_set,
1397 &mut ccd_solver,
1398 &physics_hooks,
1399 &event_handler,
1400 );
1401
1402 let contact_pair = narrow_phase
1403 .contact_pair(collider_1_handle, collider_2_handle)
1404 .expect("The contact pair should exist.");
1405 assert_eq!(
1406 contact_pair.manifolds.len(),
1407 1,
1408 "There should be a contact manifold."
1409 );
1410
1411 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1412 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1413 assert!(
1414 (collider_1_position.translation.vector - collider_2_position.translation.vector)
1415 .magnitude()
1416 < 0.5f32
1417 );
1418
1419 collider_set.set_parent(collider_2_handle, Some(body_1_handle), &mut rigid_body_set);
1421 physics_pipeline.step(
1422 &gravity,
1423 &integration_parameters,
1424 &mut island_manager,
1425 &mut broad_phase,
1426 &mut narrow_phase,
1427 &mut rigid_body_set,
1428 &mut collider_set,
1429 &mut impulse_joint_set,
1430 &mut multibody_joint_set,
1431 &mut ccd_solver,
1432 &physics_hooks,
1433 &event_handler,
1434 );
1435
1436 let contact_pair = narrow_phase
1437 .contact_pair(collider_1_handle, collider_2_handle)
1438 .expect("The contact pair should no longer exist.");
1439 assert_eq!(
1440 contact_pair.manifolds.len(),
1441 0,
1442 "Colliders with same parent should not be in contact together."
1443 );
1444
1445 collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1447 physics_pipeline.step(
1448 &gravity,
1449 &integration_parameters,
1450 &mut island_manager,
1451 &mut broad_phase,
1452 &mut narrow_phase,
1453 &mut rigid_body_set,
1454 &mut collider_set,
1455 &mut impulse_joint_set,
1456 &mut multibody_joint_set,
1457 &mut ccd_solver,
1458 &physics_hooks,
1459 &event_handler,
1460 );
1461
1462 let contact_pair = narrow_phase
1463 .contact_pair(collider_1_handle, collider_2_handle)
1464 .expect("The contact pair should exist.");
1465 assert_eq!(
1466 contact_pair.manifolds.len(),
1467 1,
1468 "There should be a contact manifold."
1469 );
1470 }
1471}