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 parry::utils::hashmap::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))]
63#[derive(Clone)]
64pub struct NarrowPhase {
65 #[cfg_attr(
66 feature = "serde-serialize",
67 serde(skip, default = "crate::geometry::default_persistent_query_dispatcher")
68 )]
69 query_dispatcher: Arc<dyn PersistentQueryDispatcher<ContactManifoldData, ContactData>>,
70 contact_graph: InteractionGraph<ColliderHandle, ContactPair>,
71 intersection_graph: InteractionGraph<ColliderHandle, IntersectionPair>,
72 graph_indices: Coarena<ColliderGraphIndices>,
73}
74
75pub(crate) type ContactManifoldIndex = usize;
76
77impl Default for NarrowPhase {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl NarrowPhase {
84 pub fn new() -> Self {
86 Self::with_query_dispatcher(DefaultQueryDispatcher)
87 }
88
89 pub fn with_query_dispatcher<D>(d: D) -> Self
91 where
92 D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
93 {
94 Self {
95 query_dispatcher: Arc::new(d),
96 contact_graph: InteractionGraph::new(),
97 intersection_graph: InteractionGraph::new(),
98 graph_indices: Coarena::new(),
99 }
100 }
101
102 pub fn query_dispatcher(
105 &self,
106 ) -> &dyn PersistentQueryDispatcher<ContactManifoldData, ContactData> {
107 &*self.query_dispatcher
108 }
109
110 pub fn contact_graph(&self) -> &InteractionGraph<ColliderHandle, ContactPair> {
112 &self.contact_graph
113 }
114
115 pub fn intersection_graph(&self) -> &InteractionGraph<ColliderHandle, IntersectionPair> {
117 &self.intersection_graph
118 }
119
120 pub fn contact_pairs_with_unknown_gen(
125 &self,
126 collider: u32,
127 ) -> impl Iterator<Item = &ContactPair> {
128 self.graph_indices
129 .get_unknown_gen(collider)
130 .map(|id| id.contact_graph_index)
131 .into_iter()
132 .flat_map(move |id| self.contact_graph.interactions_with(id))
133 .map(|pair| pair.2)
134 }
135
136 pub fn contact_pairs_with(
142 &self,
143 collider: ColliderHandle,
144 ) -> impl Iterator<Item = &ContactPair> {
145 self.graph_indices
146 .get(collider.0)
147 .map(|id| id.contact_graph_index)
148 .into_iter()
149 .flat_map(move |id| self.contact_graph.interactions_with(id))
150 .map(|pair| pair.2)
151 }
152
153 pub fn intersection_pairs_with_unknown_gen(
158 &self,
159 collider: u32,
160 ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
161 self.graph_indices
162 .get_unknown_gen(collider)
163 .map(|id| id.intersection_graph_index)
164 .into_iter()
165 .flat_map(move |id| {
166 self.intersection_graph
167 .interactions_with(id)
168 .map(|e| (e.0, e.1, e.2.intersecting))
169 })
170 }
171
172 pub fn intersection_pairs_with(
179 &self,
180 collider: ColliderHandle,
181 ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
182 self.graph_indices
183 .get(collider.0)
184 .map(|id| id.intersection_graph_index)
185 .into_iter()
186 .flat_map(move |id| {
187 self.intersection_graph
188 .interactions_with(id)
189 .map(|e| (e.0, e.1, e.2.intersecting))
190 })
191 }
192
193 pub fn contact_pair_at_index(&self, id: TemporaryInteractionIndex) -> &ContactPair {
195 &self.contact_graph.graph.edges[id.index()].weight
196 }
197
198 pub fn contact_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<&ContactPair> {
207 let id1 = self.graph_indices.get_unknown_gen(collider1)?;
208 let id2 = self.graph_indices.get_unknown_gen(collider2)?;
209 self.contact_graph
210 .interaction_pair(id1.contact_graph_index, id2.contact_graph_index)
211 .map(|c| c.2)
212 }
213
214 pub fn contact_pair(
220 &self,
221 collider1: ColliderHandle,
222 collider2: ColliderHandle,
223 ) -> Option<&ContactPair> {
224 let id1 = self.graph_indices.get(collider1.0)?;
225 let id2 = self.graph_indices.get(collider2.0)?;
226 self.contact_graph
227 .interaction_pair(id1.contact_graph_index, id2.contact_graph_index)
228 .map(|c| c.2)
229 }
230
231 pub fn intersection_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<bool> {
239 let id1 = self.graph_indices.get_unknown_gen(collider1)?;
240 let id2 = self.graph_indices.get_unknown_gen(collider2)?;
241 self.intersection_graph
242 .interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index)
243 .map(|c| c.2.intersecting)
244 }
245
246 pub fn intersection_pair(
251 &self,
252 collider1: ColliderHandle,
253 collider2: ColliderHandle,
254 ) -> Option<bool> {
255 let id1 = self.graph_indices.get(collider1.0)?;
256 let id2 = self.graph_indices.get(collider2.0)?;
257 self.intersection_graph
258 .interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index)
259 .map(|c| c.2.intersecting)
260 }
261
262 pub fn contact_pairs(&self) -> impl Iterator<Item = &ContactPair> {
264 self.contact_graph.interactions()
265 }
266
267 pub fn intersection_pairs(
269 &self,
270 ) -> impl Iterator<Item = (ColliderHandle, ColliderHandle, bool)> + '_ {
271 self.intersection_graph
272 .interactions_with_endpoints()
273 .map(|e| (e.0, e.1, e.2.intersecting))
274 }
275
276 #[profiling::function]
283 pub fn handle_user_changes(
284 &mut self,
285 mut islands: Option<&mut IslandManager>,
286 modified_colliders: &[ColliderHandle],
287 removed_colliders: &[ColliderHandle],
288 colliders: &mut ColliderSet,
289 bodies: &mut RigidBodySet,
290 events: &dyn EventHandler,
291 ) {
292 let mut prox_id_remap = HashMap::default();
296 let mut contact_id_remap = HashMap::default();
297
298 for collider in removed_colliders {
299 if let Some(graph_idx) = self
302 .graph_indices
303 .remove(collider.0, ColliderGraphIndices::invalid())
304 {
305 let intersection_graph_id = prox_id_remap
306 .get(collider)
307 .copied()
308 .unwrap_or(graph_idx.intersection_graph_index);
309 let contact_graph_id = contact_id_remap
310 .get(collider)
311 .copied()
312 .unwrap_or(graph_idx.contact_graph_index);
313
314 self.remove_collider(
315 intersection_graph_id,
316 contact_graph_id,
317 islands.as_deref_mut(),
318 colliders,
319 bodies,
320 &mut prox_id_remap,
321 &mut contact_id_remap,
322 events,
323 );
324 }
325 }
326
327 self.handle_user_changes_on_colliders(
328 islands,
329 modified_colliders,
330 colliders,
331 bodies,
332 events,
333 );
334 }
335
336 #[profiling::function]
337 pub(crate) fn remove_collider(
338 &mut self,
339 intersection_graph_id: ColliderGraphIndex,
340 contact_graph_id: ColliderGraphIndex,
341 islands: Option<&mut IslandManager>,
342 colliders: &mut ColliderSet,
343 bodies: &mut RigidBodySet,
344 prox_id_remap: &mut HashMap<ColliderHandle, ColliderGraphIndex>,
345 contact_id_remap: &mut HashMap<ColliderHandle, ColliderGraphIndex>,
346 events: &dyn EventHandler,
347 ) {
348 if let Some(islands) = islands {
350 for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) {
351 if let Some(parent) = colliders.get(a).and_then(|c| c.parent.as_ref()) {
352 islands.wake_up(bodies, parent.handle, true)
353 }
354
355 if let Some(parent) = colliders.get(b).and_then(|c| c.parent.as_ref()) {
356 islands.wake_up(bodies, parent.handle, true)
357 }
358
359 if pair.start_event_emitted {
360 events.handle_collision_event(
361 bodies,
362 colliders,
363 CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED),
364 Some(pair),
365 );
366 }
367 }
368 } else {
369 for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) {
371 if pair.start_event_emitted {
372 events.handle_collision_event(
373 bodies,
374 colliders,
375 CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED),
376 Some(pair),
377 );
378 }
379 }
380 }
381
382 for (a, b, pair) in self
384 .intersection_graph
385 .interactions_with(intersection_graph_id)
386 {
387 if pair.start_event_emitted {
388 events.handle_collision_event(
389 bodies,
390 colliders,
391 CollisionEvent::Stopped(
392 a,
393 b,
394 CollisionEventFlags::REMOVED | CollisionEventFlags::SENSOR,
395 ),
396 None,
397 );
398 }
399 }
400
401 if let Some(replacement) = self.intersection_graph.remove_node(intersection_graph_id) {
404 if let Some(replacement) = self.graph_indices.get_mut(replacement.0) {
405 replacement.intersection_graph_index = intersection_graph_id;
406 } else {
407 prox_id_remap.insert(replacement, intersection_graph_id);
408 unreachable!();
412 }
413 }
414
415 if let Some(replacement) = self.contact_graph.remove_node(contact_graph_id) {
416 if let Some(replacement) = self.graph_indices.get_mut(replacement.0) {
417 replacement.contact_graph_index = contact_graph_id;
418 } else {
419 contact_id_remap.insert(replacement, contact_graph_id);
420 unreachable!();
424 }
425 }
426 }
427
428 #[profiling::function]
429 pub(crate) fn handle_user_changes_on_colliders(
430 &mut self,
431 mut islands: Option<&mut IslandManager>,
432 modified_colliders: &[ColliderHandle],
433 colliders: &ColliderSet,
434 bodies: &mut RigidBodySet,
435 events: &dyn EventHandler,
436 ) {
437 let mut pairs_to_remove = vec![];
438
439 for handle in modified_colliders {
440 if let Some(co) = colliders.get(*handle) {
443 if !co.changes.needs_narrow_phase_update() {
444 continue;
446 }
447
448 if let Some(gid) = self.graph_indices.get(handle.0) {
449 if let Some(islands) = islands.as_deref_mut() {
454 if let Some(co_parent) = &co.parent {
455 islands.wake_up(bodies, co_parent.handle, true);
456 }
457
458 for inter in self
459 .contact_graph
460 .interactions_with(gid.contact_graph_index)
461 {
462 let other_handle = if *handle == inter.0 { inter.1 } else { inter.0 };
463 let other_parent = colliders
464 .get(other_handle)
465 .and_then(|co| co.parent.as_ref());
466
467 if let Some(other_parent) = other_parent {
468 islands.wake_up(bodies, other_parent.handle, true);
469 }
470 }
471 }
472
473 if co.changes.intersects(ColliderChanges::TYPE) {
478 if co.is_sensor() {
479 for inter in self
482 .contact_graph
483 .interactions_with(gid.contact_graph_index)
484 {
485 pairs_to_remove.push((
486 ColliderPair::new(inter.0, inter.1),
487 PairRemovalMode::FromContactGraph,
488 ));
489 }
490 } else {
491 for inter in self
495 .intersection_graph
496 .interactions_with(gid.intersection_graph_index)
497 .filter(|(h1, h2, _)| {
498 !colliders[*h1].is_sensor() && !colliders[*h2].is_sensor()
499 })
500 {
501 pairs_to_remove.push((
502 ColliderPair::new(inter.0, inter.1),
503 PairRemovalMode::FromIntersectionGraph,
504 ));
505 }
506 }
507 }
508
509 }
515 }
516 }
517
518 for pair in &pairs_to_remove {
520 self.remove_pair(
521 islands.as_deref_mut(),
522 colliders,
523 bodies,
524 &pair.0,
525 events,
526 pair.1,
527 );
528 }
529
530 for pair in pairs_to_remove {
532 self.add_pair(colliders, &pair.0);
533 }
534 }
535
536 #[profiling::function]
537 fn remove_pair(
538 &mut self,
539 islands: Option<&mut IslandManager>,
540 colliders: &ColliderSet,
541 bodies: &mut RigidBodySet,
542 pair: &ColliderPair,
543 events: &dyn EventHandler,
544 mode: PairRemovalMode,
545 ) {
546 if let (Some(co1), Some(co2)) =
547 (colliders.get(pair.collider1), colliders.get(pair.collider2))
548 {
549 if let (Some(gid1), Some(gid2)) = (
552 self.graph_indices.get(pair.collider1.0),
553 self.graph_indices.get(pair.collider2.0),
554 ) {
555 if mode == PairRemovalMode::FromIntersectionGraph
556 || (mode == PairRemovalMode::Auto && (co1.is_sensor() || co2.is_sensor()))
557 {
558 let intersection = self
559 .intersection_graph
560 .remove_edge(gid1.intersection_graph_index, gid2.intersection_graph_index);
561
562 if let Some(mut intersection) = intersection {
564 if intersection.intersecting
565 && (co1.flags.active_events | co2.flags.active_events)
566 .contains(ActiveEvents::COLLISION_EVENTS)
567 {
568 intersection.emit_stop_event(
569 bodies,
570 colliders,
571 pair.collider1,
572 pair.collider2,
573 events,
574 )
575 }
576 }
577 } else {
578 let contact_pair = self
579 .contact_graph
580 .remove_edge(gid1.contact_graph_index, gid2.contact_graph_index);
581
582 if let Some(mut ctct) = contact_pair {
585 if ctct.has_any_active_contact {
586 if let Some(islands) = islands {
587 if let Some(co_parent1) = &co1.parent {
588 islands.wake_up(bodies, co_parent1.handle, true);
589 }
590
591 if let Some(co_parent2) = co2.parent {
592 islands.wake_up(bodies, co_parent2.handle, true);
593 }
594 }
595
596 if (co1.flags.active_events | co2.flags.active_events)
597 .contains(ActiveEvents::COLLISION_EVENTS)
598 {
599 ctct.emit_stop_event(bodies, colliders, events);
600 }
601 }
602 }
603 }
604 }
605 }
606 }
607
608 #[profiling::function]
609 fn add_pair(&mut self, colliders: &ColliderSet, pair: &ColliderPair) {
610 if let (Some(co1), Some(co2)) =
611 (colliders.get(pair.collider1), colliders.get(pair.collider2))
612 {
613 let (gid1, gid2) = self.graph_indices.ensure_pair_exists(
616 pair.collider1.0,
617 pair.collider2.0,
618 ColliderGraphIndices::invalid(),
619 );
620
621 if co1.is_sensor() || co2.is_sensor() {
622 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid1.intersection_graph_index)
625 {
626 gid1.intersection_graph_index =
627 self.intersection_graph.graph.add_node(pair.collider1);
628 }
629
630 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid2.intersection_graph_index)
631 {
632 gid2.intersection_graph_index =
633 self.intersection_graph.graph.add_node(pair.collider2);
634 }
635
636 if self
637 .intersection_graph
638 .graph
639 .find_edge(gid1.intersection_graph_index, gid2.intersection_graph_index)
640 .is_none()
641 {
642 let _ = self.intersection_graph.add_edge(
643 gid1.intersection_graph_index,
644 gid2.intersection_graph_index,
645 IntersectionPair::new(),
646 );
647 }
648 } else {
649 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid1.contact_graph_index) {
655 gid1.contact_graph_index = self.contact_graph.graph.add_node(pair.collider1);
656 }
657
658 if !InteractionGraph::<(), ()>::is_graph_index_valid(gid2.contact_graph_index) {
659 gid2.contact_graph_index = self.contact_graph.graph.add_node(pair.collider2);
660 }
661
662 if self
663 .contact_graph
664 .graph
665 .find_edge(gid1.contact_graph_index, gid2.contact_graph_index)
666 .is_none()
667 {
668 let interaction = ContactPair::new(pair.collider1, pair.collider2);
669 let _ = self.contact_graph.add_edge(
670 gid1.contact_graph_index,
671 gid2.contact_graph_index,
672 interaction,
673 );
674 }
675 }
676 }
677 }
678
679 pub(crate) fn register_pairs(
680 &mut self,
681 mut islands: Option<&mut IslandManager>,
682 colliders: &ColliderSet,
683 bodies: &mut RigidBodySet,
684 broad_phase_events: &[BroadPhasePairEvent],
685 events: &dyn EventHandler,
686 ) {
687 for event in broad_phase_events {
688 match event {
689 BroadPhasePairEvent::AddPair(pair) => {
690 self.add_pair(colliders, pair);
691 }
692 BroadPhasePairEvent::DeletePair(pair) => {
693 self.remove_pair(
694 islands.as_deref_mut(),
695 colliders,
696 bodies,
697 pair,
698 events,
699 PairRemovalMode::Auto,
700 );
701 }
702 }
703 }
704 }
705
706 #[profiling::function]
707 pub(crate) fn compute_intersections(
708 &mut self,
709 bodies: &RigidBodySet,
710 colliders: &ColliderSet,
711 hooks: &dyn PhysicsHooks,
712 events: &dyn EventHandler,
713 ) {
714 let nodes = &self.intersection_graph.graph.nodes;
715 let query_dispatcher = &*self.query_dispatcher;
716
717 par_iter_mut!(&mut self.intersection_graph.graph.edges).for_each(|edge| {
719 let handle1 = nodes[edge.source().index()].weight;
720 let handle2 = nodes[edge.target().index()].weight;
721 let had_intersection = edge.weight.intersecting;
722 let co1 = &colliders[handle1];
723 let co2 = &colliders[handle2];
724
725 'emit_events: {
726 if !co1.changes.needs_narrow_phase_update()
727 && !co2.changes.needs_narrow_phase_update()
728 {
729 return;
731 }
732 if co1.parent.map(|p| p.handle) == co2.parent.map(|p| p.handle)
733 && co1.parent.is_some()
734 {
735 edge.weight.intersecting = false;
737 break 'emit_events;
738 }
739 let mut rb_type1 = RigidBodyType::Fixed;
741 let mut rb_type2 = RigidBodyType::Fixed;
742
743 if let Some(co_parent1) = &co1.parent {
744 rb_type1 = bodies[co_parent1.handle].body_type;
745 }
746
747 if let Some(co_parent2) = &co2.parent {
748 rb_type2 = bodies[co_parent2.handle].body_type;
749 }
750
751 if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
753 && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
754 {
755 edge.weight.intersecting = false;
756 break 'emit_events;
757 }
758
759 if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
761 edge.weight.intersecting = false;
762 break 'emit_events;
763 }
764
765 let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
766
767 if active_hooks.contains(ActiveHooks::FILTER_INTERSECTION_PAIR) {
768 let context = PairFilterContext {
769 bodies,
770 colliders,
771 rigid_body1: co1.parent.map(|p| p.handle),
772 rigid_body2: co2.parent.map(|p| p.handle),
773 collider1: handle1,
774 collider2: handle2,
775 };
776
777 if !hooks.filter_intersection_pair(&context) {
778 edge.weight.intersecting = false;
780 break 'emit_events;
781 }
782 }
783
784 let pos12 = co1.pos.inv_mul(&co2.pos);
785 edge.weight.intersecting = query_dispatcher
786 .intersection_test(&pos12, &*co1.shape, &*co2.shape)
787 .unwrap_or(false);
788 }
789
790 let active_events = co1.flags.active_events | co2.flags.active_events;
791
792 if active_events.contains(ActiveEvents::COLLISION_EVENTS)
793 && had_intersection != edge.weight.intersecting
794 {
795 if edge.weight.intersecting {
796 edge.weight
797 .emit_start_event(bodies, colliders, handle1, handle2, events);
798 } else {
799 edge.weight
800 .emit_stop_event(bodies, colliders, handle1, handle2, events);
801 }
802 }
803 });
804 }
805
806 #[profiling::function]
807 pub(crate) fn compute_contacts(
808 &mut self,
809 prediction_distance: Real,
810 dt: Real,
811 bodies: &RigidBodySet,
812 colliders: &ColliderSet,
813 impulse_joints: &ImpulseJointSet,
814 multibody_joints: &MultibodyJointSet,
815 hooks: &dyn PhysicsHooks,
816 events: &dyn EventHandler,
817 ) {
818 let query_dispatcher = &*self.query_dispatcher;
819
820 par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| {
822 let pair = &mut edge.weight;
823 let had_any_active_contact = pair.has_any_active_contact;
824 let co1 = &colliders[pair.collider1];
825 let co2 = &colliders[pair.collider2];
826
827 'emit_events: {
828 if !co1.changes.needs_narrow_phase_update()
829 && !co2.changes.needs_narrow_phase_update()
830 {
831 return;
833 }
834 if co1.parent.map(|p| p.handle) == co2.parent.map(|p| p.handle) && co1.parent.is_some()
835 {
836 pair.clear();
838 break 'emit_events;
839 }
840
841 let rb1 = co1.parent.map(|co_parent1| &bodies[co_parent1.handle]);
842 let rb2 = co2.parent.map(|co_parent2| &bodies[co_parent2.handle]);
843
844 let rb_type1 = rb1.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
845 let rb_type2 = rb2.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
846
847 if let (Some(co_parent1), Some(co_parent2)) = (&co1.parent, &co2.parent) {
849 for (_, joint) in
850 impulse_joints.joints_between(co_parent1.handle, co_parent2.handle)
851 {
852 if !joint.data.contacts_enabled {
853 pair.clear();
854 break 'emit_events;
855 }
856 }
857
858 let link1 = multibody_joints.rigid_body_link(co_parent1.handle);
859 let link2 = multibody_joints.rigid_body_link(co_parent2.handle);
860
861 if let (Some(link1),Some(link2)) = (link1, link2) {
862 if link1.multibody == link2.multibody {
865 if let Some(mb) = multibody_joints.get_multibody(link1.multibody) {
867 if !mb.self_contacts_enabled() {
868 pair.clear();
869 break 'emit_events;
870 }
871 }
872
873 if let Some((_, _, mb_link)) =
875 multibody_joints.joint_between(co_parent1.handle, co_parent2.handle)
876 {
877 if !mb_link.joint.data.contacts_enabled {
878 pair.clear();
879 break 'emit_events;
880 }
881 }
882 }
883 }
884 }
885
886 if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
888 && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
889 {
890 pair.clear();
891 break 'emit_events;
892 }
893
894 if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
896 pair.clear();
897 break 'emit_events;
898 }
899
900 let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
901
902 let mut solver_flags = if active_hooks.contains(ActiveHooks::FILTER_CONTACT_PAIRS) {
903 let context = PairFilterContext {
904 bodies,
905 colliders,
906 rigid_body1: co1.parent.map(|p| p.handle),
907 rigid_body2: co2.parent.map(|p| p.handle),
908 collider1: pair.collider1,
909 collider2: pair.collider2,
910 };
911
912 if let Some(solver_flags) = hooks.filter_contact_pair(&context) {
913 solver_flags
914 } else {
915 pair.clear();
917 break 'emit_events;
918 }
919 } else {
920 SolverFlags::default()
921 };
922
923 if !co1.flags.solver_groups.test(co2.flags.solver_groups) {
924 solver_flags.remove(SolverFlags::COMPUTE_IMPULSES);
925 }
926
927 if co1.changes.contains(ColliderChanges::SHAPE)
928 || co2.changes.contains(ColliderChanges::SHAPE)
929 {
930 pair.workspace = None;
932 }
933
934 let pos12 = co1.pos.inv_mul(&co2.pos);
935
936 let contact_skin_sum = co1.contact_skin() + co2.contact_skin();
937 let soft_ccd_prediction1 = rb1.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
938 let soft_ccd_prediction2 = rb2.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
939 let effective_prediction_distance = if soft_ccd_prediction1 > 0.0 || soft_ccd_prediction2 > 0.0 {
940 let aabb1 = co1.compute_collision_aabb(0.0);
941 let aabb2 = co2.compute_collision_aabb(0.0);
942 let inv_dt = crate::utils::inv(dt);
943
944 let linvel1 = rb1.map(|rb| rb.linvel()
945 .cap_magnitude(soft_ccd_prediction1 * inv_dt)).unwrap_or_default();
946 let linvel2 = rb2.map(|rb| rb.linvel()
947 .cap_magnitude(soft_ccd_prediction2 * inv_dt)).unwrap_or_default();
948
949 if !aabb1.intersects(&aabb2) && !aabb1.intersects_moving_aabb(&aabb2, linvel2 - linvel1) {
950 pair.clear();
951 break 'emit_events;
952 }
953
954
955 prediction_distance.max(
956 dt * (linvel1 - linvel2).norm()) + contact_skin_sum
957 } else {
958 prediction_distance + contact_skin_sum
959 };
960
961 let _ = query_dispatcher.contact_manifolds(
962 &pos12,
963 &*co1.shape,
964 &*co2.shape,
965 effective_prediction_distance,
966 &mut pair.manifolds,
967 &mut pair.workspace,
968 );
969
970 let friction = CoefficientCombineRule::combine(
971 co1.material.friction,
972 co2.material.friction,
973 co1.material.friction_combine_rule,
974 co2.material.friction_combine_rule,
975 );
976 let restitution = CoefficientCombineRule::combine(
977 co1.material.restitution,
978 co2.material.restitution,
979 co1.material.restitution_combine_rule,
980 co2.material.restitution_combine_rule,
981 );
982
983 let zero = RigidBodyDominance(0); let dominance1 = rb1.map(|rb| rb.dominance).unwrap_or(zero);
985 let dominance2 = rb2.map(|rb| rb.dominance).unwrap_or(zero);
986
987 pair.has_any_active_contact = false;
988
989 for manifold in &mut pair.manifolds {
990 let world_pos1 = manifold.subshape_pos1.prepend_to(&co1.pos);
991 let world_pos2 = manifold.subshape_pos2.prepend_to(&co2.pos);
992 manifold.data.solver_contacts.clear();
993 manifold.data.rigid_body1 = co1.parent.map(|p| p.handle);
994 manifold.data.rigid_body2 = co2.parent.map(|p| p.handle);
995 manifold.data.solver_flags = solver_flags;
996 manifold.data.relative_dominance = dominance1.effective_group(&rb_type1)
997 - dominance2.effective_group(&rb_type2);
998 manifold.data.normal = world_pos1 * manifold.local_n1;
999
1000 for (contact_id, contact) in manifold.points.iter().enumerate() {
1002 if contact_id > u8::MAX as usize {
1003 log::warn!("A contact manifold cannot contain more than 255 contacts currently, dropping contact in excess.");
1004 break;
1005 }
1006
1007 let effective_contact_dist = contact.dist - co1.contact_skin() - co2.contact_skin();
1008
1009 let keep_solver_contact = effective_contact_dist < prediction_distance || {
1010 let world_pt1 = world_pos1 * contact.local_p1;
1011 let world_pt2 = world_pos2 * contact.local_p2;
1012 let vel1 = rb1.map(|rb| rb.velocity_at_point(&world_pt1)).unwrap_or_default();
1013 let vel2 = rb2.map(|rb| rb.velocity_at_point(&world_pt2)).unwrap_or_default();
1014 effective_contact_dist + (vel2 - vel1).dot(&manifold.data.normal) * dt < prediction_distance
1015 };
1016
1017 if keep_solver_contact {
1018 let world_pt1 = world_pos1 * contact.local_p1;
1020 let world_pt2 = world_pos2 * contact.local_p2;
1021 let effective_point = na::center(&world_pt1, &world_pt2);
1022
1023 let solver_contact = SolverContact {
1024 contact_id: [contact_id as u32],
1025 point: effective_point,
1026 dist: effective_contact_dist,
1027 friction,
1028 restitution,
1029 tangent_velocity: Vector::zeros(),
1030 is_new: (contact.data.impulse == 0.0) as u32 as Real,
1031 warmstart_impulse: contact.data.warmstart_impulse,
1032 warmstart_tangent_impulse: contact.data.warmstart_tangent_impulse,
1033 #[cfg(feature = "dim2")]
1034 warmstart_twist_impulse: na::zero(),
1035 #[cfg(feature = "dim3")]
1036 warmstart_twist_impulse: contact.data.warmstart_twist_impulse,
1037 #[cfg(feature = "dim3")]
1038 padding: Default::default(),
1039 };
1040
1041 manifold.data.solver_contacts.push(solver_contact);
1042 pair.has_any_active_contact = true;
1043 }
1044 }
1045
1046 if active_hooks.contains(ActiveHooks::MODIFY_SOLVER_CONTACTS) {
1048 let mut modifiable_solver_contacts =
1049 std::mem::take(&mut manifold.data.solver_contacts);
1050 let mut modifiable_user_data = manifold.data.user_data;
1051 let mut modifiable_normal = manifold.data.normal;
1052
1053 let mut context = ContactModificationContext {
1054 bodies,
1055 colliders,
1056 rigid_body1: co1.parent.map(|p| p.handle),
1057 rigid_body2: co2.parent.map(|p| p.handle),
1058 collider1: pair.collider1,
1059 collider2: pair.collider2,
1060 manifold,
1061 solver_contacts: &mut modifiable_solver_contacts,
1062 normal: &mut modifiable_normal,
1063 user_data: &mut modifiable_user_data,
1064 };
1065
1066 hooks.modify_solver_contacts(&mut context);
1067
1068 manifold.data.solver_contacts = modifiable_solver_contacts;
1069 manifold.data.normal = modifiable_normal;
1070 manifold.data.user_data = modifiable_user_data;
1071 }
1072
1073 }
1102 }
1103
1104 let active_events = co1.flags.active_events | co2.flags.active_events;
1105
1106 if pair.has_any_active_contact != had_any_active_contact
1107 && active_events.contains(ActiveEvents::COLLISION_EVENTS)
1108 {
1109 if pair.has_any_active_contact {
1110 pair.emit_start_event(bodies, colliders, events);
1111 } else {
1112 pair.emit_stop_event(bodies, colliders, events);
1113 }
1114 }
1115 });
1116 }
1117
1118 pub(crate) fn select_active_contacts<'a>(
1121 &'a mut self,
1122 islands: &IslandManager,
1123 bodies: &RigidBodySet,
1124 out_contact_pairs: &mut Vec<TemporaryInteractionIndex>,
1125 out_manifolds: &mut Vec<&'a mut ContactManifold>,
1126 out: &mut [Vec<ContactManifoldIndex>],
1127 ) {
1128 for out_island in &mut out[..islands.num_islands()] {
1129 out_island.clear();
1130 }
1131
1132 for (pair_id, inter) in self.contact_graph.graph.edges.iter_mut().enumerate() {
1134 let mut push_pair = false;
1135
1136 for manifold in &mut inter.weight.manifolds {
1137 if manifold
1138 .data
1139 .solver_flags
1140 .contains(SolverFlags::COMPUTE_IMPULSES)
1141 && manifold.data.num_active_contacts() != 0
1142 {
1143 let (active_island_id1, rb_type1, sleeping1) =
1144 if let Some(handle1) = manifold.data.rigid_body1 {
1145 let rb1 = &bodies[handle1];
1146 (
1147 rb1.ids.active_island_id,
1148 rb1.body_type,
1149 rb1.activation.sleeping,
1150 )
1151 } else {
1152 (0, RigidBodyType::Fixed, true)
1153 };
1154
1155 let (active_island_id2, rb_type2, sleeping2) =
1156 if let Some(handle2) = manifold.data.rigid_body2 {
1157 let rb2 = &bodies[handle2];
1158 (
1159 rb2.ids.active_island_id,
1160 rb2.body_type,
1161 rb2.activation.sleeping,
1162 )
1163 } else {
1164 (0, RigidBodyType::Fixed, true)
1165 };
1166
1167 if (rb_type1.is_dynamic() || rb_type2.is_dynamic())
1168 && (!rb_type1.is_dynamic() || !sleeping1)
1169 && (!rb_type2.is_dynamic() || !sleeping2)
1170 {
1171 let island_index = if !rb_type1.is_dynamic() {
1172 active_island_id2
1173 } else {
1174 active_island_id1
1175 };
1176
1177 out[island_index].push(out_manifolds.len());
1178 out_manifolds.push(manifold);
1179 push_pair = true;
1180 }
1181 }
1182 }
1183
1184 if push_pair {
1185 out_contact_pairs.push(EdgeIndex::new(pair_id as u32));
1186 }
1187 }
1188 }
1189}
1190
1191#[cfg(test)]
1192#[cfg(feature = "f32")]
1193#[cfg(feature = "dim3")]
1194mod test {
1195 use na::vector;
1196
1197 use crate::prelude::{
1198 CCDSolver, ColliderBuilder, DefaultBroadPhase, IntegrationParameters, PhysicsPipeline,
1199 RigidBodyBuilder,
1200 };
1201
1202 use super::*;
1203
1204 #[test]
1206 pub fn collider_set_parent_depenetration() {
1207 let mut rigid_body_set = RigidBodySet::new();
1212 let mut collider_set = ColliderSet::new();
1213
1214 let collider = ColliderBuilder::ball(0.5);
1216
1217 let rigid_body_1 = RigidBodyBuilder::dynamic()
1219 .translation(vector![0.0, 0.0, 0.0])
1220 .build();
1221 let body_1_handle = rigid_body_set.insert(rigid_body_1);
1222
1223 let collider_1_handle =
1225 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1226
1227 let collider_2_handle =
1229 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1230
1231 let rigid_body_2 = RigidBodyBuilder::dynamic()
1233 .translation(vector![0.0, 0.0, 0.0])
1234 .build();
1235 let body_2_handle = rigid_body_set.insert(rigid_body_2);
1236
1237 let gravity = vector![0.0, 0.0, 0.0];
1239 let integration_parameters = IntegrationParameters::default();
1240 let mut physics_pipeline = PhysicsPipeline::new();
1241 let mut island_manager = IslandManager::new();
1242 let mut broad_phase = DefaultBroadPhase::new();
1243 let mut narrow_phase = NarrowPhase::new();
1244 let mut impulse_joint_set = ImpulseJointSet::new();
1245 let mut multibody_joint_set = MultibodyJointSet::new();
1246 let mut ccd_solver = CCDSolver::new();
1247 let physics_hooks = ();
1248 let event_handler = ();
1249
1250 physics_pipeline.step(
1251 &gravity,
1252 &integration_parameters,
1253 &mut island_manager,
1254 &mut broad_phase,
1255 &mut narrow_phase,
1256 &mut rigid_body_set,
1257 &mut collider_set,
1258 &mut impulse_joint_set,
1259 &mut multibody_joint_set,
1260 &mut ccd_solver,
1261 &physics_hooks,
1262 &event_handler,
1263 );
1264 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1265 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1266 assert!(
1267 (collider_1_position.translation.vector - collider_2_position.translation.vector)
1268 .magnitude()
1269 < 0.5f32
1270 );
1271
1272 let contact_pair = narrow_phase
1273 .contact_pair(collider_1_handle, collider_2_handle)
1274 .expect("The contact pair should exist.");
1275 assert_eq!(contact_pair.manifolds.len(), 0);
1276 assert!(
1277 narrow_phase
1278 .intersection_pair(collider_1_handle, collider_2_handle)
1279 .is_none(),
1280 "Interaction pair is for sensors"
1281 );
1282 collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1284
1285 physics_pipeline.step(
1286 &gravity,
1287 &integration_parameters,
1288 &mut island_manager,
1289 &mut broad_phase,
1290 &mut narrow_phase,
1291 &mut rigid_body_set,
1292 &mut collider_set,
1293 &mut impulse_joint_set,
1294 &mut multibody_joint_set,
1295 &mut ccd_solver,
1296 &physics_hooks,
1297 &event_handler,
1298 );
1299
1300 let contact_pair = narrow_phase
1301 .contact_pair(collider_1_handle, collider_2_handle)
1302 .expect("The contact pair should exist.");
1303 assert_eq!(contact_pair.manifolds.len(), 1);
1304 assert!(
1305 narrow_phase
1306 .intersection_pair(collider_1_handle, collider_2_handle)
1307 .is_none(),
1308 "Interaction pair is for sensors"
1309 );
1310
1311 for _ in 0..200 {
1313 physics_pipeline.step(
1314 &gravity,
1315 &integration_parameters,
1316 &mut island_manager,
1317 &mut broad_phase,
1318 &mut narrow_phase,
1319 &mut rigid_body_set,
1320 &mut collider_set,
1321 &mut impulse_joint_set,
1322 &mut multibody_joint_set,
1323 &mut ccd_solver,
1324 &physics_hooks,
1325 &event_handler,
1326 );
1327
1328 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1329 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1330 println!("collider 1 position: {}", collider_1_position.translation);
1331 println!("collider 2 position: {}", collider_2_position.translation);
1332 }
1333
1334 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1335 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1336 println!("collider 2 position: {}", collider_2_position.translation);
1337 assert!(
1338 (collider_1_position.translation.vector - collider_2_position.translation.vector)
1339 .magnitude()
1340 >= 0.5f32,
1341 "colliders should no longer be penetrating."
1342 );
1343 }
1344
1345 #[test]
1347 pub fn collider_set_parent_no_self_intersection() {
1348 let mut rigid_body_set = RigidBodySet::new();
1356 let mut collider_set = ColliderSet::new();
1357
1358 let collider = ColliderBuilder::ball(0.5);
1360
1361 let rigid_body_1 = RigidBodyBuilder::dynamic()
1363 .translation(vector![0.0, 0.0, 0.0])
1364 .build();
1365 let body_1_handle = rigid_body_set.insert(rigid_body_1);
1366
1367 let collider_1_handle =
1369 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1370
1371 let rigid_body_2 = RigidBodyBuilder::dynamic()
1373 .translation(vector![0.0, 0.0, 0.0])
1374 .build();
1375 let body_2_handle = rigid_body_set.insert(rigid_body_2);
1376
1377 let collider_2_handle =
1379 collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set);
1380
1381 let gravity = vector![0.0, 0.0, 0.0];
1383 let integration_parameters = IntegrationParameters::default();
1384 let mut physics_pipeline = PhysicsPipeline::new();
1385 let mut island_manager = IslandManager::new();
1386 let mut broad_phase = DefaultBroadPhase::new();
1387 let mut narrow_phase = NarrowPhase::new();
1388 let mut impulse_joint_set = ImpulseJointSet::new();
1389 let mut multibody_joint_set = MultibodyJointSet::new();
1390 let mut ccd_solver = CCDSolver::new();
1391 let physics_hooks = ();
1392 let event_handler = ();
1393
1394 physics_pipeline.step(
1395 &gravity,
1396 &integration_parameters,
1397 &mut island_manager,
1398 &mut broad_phase,
1399 &mut narrow_phase,
1400 &mut rigid_body_set,
1401 &mut collider_set,
1402 &mut impulse_joint_set,
1403 &mut multibody_joint_set,
1404 &mut ccd_solver,
1405 &physics_hooks,
1406 &event_handler,
1407 );
1408
1409 let contact_pair = narrow_phase
1410 .contact_pair(collider_1_handle, collider_2_handle)
1411 .expect("The contact pair should exist.");
1412 assert_eq!(
1413 contact_pair.manifolds.len(),
1414 1,
1415 "There should be a contact manifold."
1416 );
1417
1418 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1419 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1420 assert!(
1421 (collider_1_position.translation.vector - collider_2_position.translation.vector)
1422 .magnitude()
1423 < 0.5f32
1424 );
1425
1426 collider_set.set_parent(collider_2_handle, Some(body_1_handle), &mut rigid_body_set);
1428 physics_pipeline.step(
1429 &gravity,
1430 &integration_parameters,
1431 &mut island_manager,
1432 &mut broad_phase,
1433 &mut narrow_phase,
1434 &mut rigid_body_set,
1435 &mut collider_set,
1436 &mut impulse_joint_set,
1437 &mut multibody_joint_set,
1438 &mut ccd_solver,
1439 &physics_hooks,
1440 &event_handler,
1441 );
1442
1443 let contact_pair = narrow_phase
1444 .contact_pair(collider_1_handle, collider_2_handle)
1445 .expect("The contact pair should no longer exist.");
1446 assert_eq!(
1447 contact_pair.manifolds.len(),
1448 0,
1449 "Colliders with same parent should not be in contact together."
1450 );
1451
1452 collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1454 physics_pipeline.step(
1455 &gravity,
1456 &integration_parameters,
1457 &mut island_manager,
1458 &mut broad_phase,
1459 &mut narrow_phase,
1460 &mut rigid_body_set,
1461 &mut collider_set,
1462 &mut impulse_joint_set,
1463 &mut multibody_joint_set,
1464 &mut ccd_solver,
1465 &physics_hooks,
1466 &event_handler,
1467 );
1468
1469 let contact_pair = narrow_phase
1470 .contact_pair(collider_1_handle, collider_2_handle)
1471 .expect("The contact pair should exist.");
1472 assert_eq!(
1473 contact_pair.manifolds.len(),
1474 1,
1475 "There should be a contact manifold."
1476 );
1477 }
1478}