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::{MAX_MANIFOLD_POINTS, Real};
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::PoseOpt;
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 let rb_handle1 = co1.parent.map(|p| p.handle);
725 let rb_handle2 = co2.parent.map(|p| p.handle);
726
727 'emit_events: {
728 if !co1.changes.needs_narrow_phase_update()
729 && !co2.changes.needs_narrow_phase_update()
730 {
731 return;
733 }
734
735 if rb_handle1 == rb_handle2 && co1.parent.is_some() {
736 edge.weight.intersecting = false;
738 break 'emit_events;
739 }
740 let mut rb_type1 = RigidBodyType::Fixed;
742 let mut rb_type2 = RigidBodyType::Fixed;
743
744 if let Some(co_parent1) = &co1.parent {
745 rb_type1 = bodies[co_parent1.handle].body_type;
746 }
747
748 if let Some(co_parent2) = &co2.parent {
749 rb_type2 = bodies[co_parent2.handle].body_type;
750 }
751
752 if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
754 && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
755 {
756 edge.weight.intersecting = false;
757 break 'emit_events;
758 }
759
760 if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
762 edge.weight.intersecting = false;
763 break 'emit_events;
764 }
765
766 let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
767
768 if active_hooks.contains(ActiveHooks::FILTER_INTERSECTION_PAIR) {
769 let context = PairFilterContext {
770 bodies,
771 colliders,
772 rigid_body1: rb_handle1,
773 rigid_body2: rb_handle2,
774 collider1: handle1,
775 collider2: handle2,
776 };
777
778 if !hooks.filter_intersection_pair(&context) {
779 edge.weight.intersecting = false;
781 break 'emit_events;
782 }
783 }
784
785 let pos12 = co1.pos.inv_mul(&co2.pos);
786 edge.weight.intersecting = query_dispatcher
787 .intersection_test(&pos12, &*co1.shape, &*co2.shape)
788 .unwrap_or(false);
789 }
790
791 let active_events = co1.flags.active_events | co2.flags.active_events;
792
793 if active_events.contains(ActiveEvents::COLLISION_EVENTS)
794 && had_intersection != edge.weight.intersecting
795 {
796 if edge.weight.intersecting {
797 edge.weight
798 .emit_start_event(bodies, colliders, handle1, handle2, events);
799 } else {
800 edge.weight
801 .emit_stop_event(bodies, colliders, handle1, handle2, events);
802 }
803 }
804 });
805 }
806
807 #[profiling::function]
808 pub(crate) fn compute_contacts(
809 &mut self,
810 prediction_distance: Real,
811 dt: Real,
812 islands: &mut IslandManager,
813 bodies: &mut RigidBodySet,
814 colliders: &ColliderSet,
815 impulse_joints: &ImpulseJointSet,
816 multibody_joints: &MultibodyJointSet,
817 hooks: &dyn PhysicsHooks,
818 events: &dyn EventHandler,
819 ) {
820 let query_dispatcher = &*self.query_dispatcher;
821 #[cfg(feature = "parallel")]
822 let (snd, rcv) = std::sync::mpsc::channel();
823
824 par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| {
826 let pair = &mut edge.weight;
827 let had_any_active_contact = pair.has_any_active_contact();
828 let co1 = &colliders[pair.collider1];
829 let co2 = &colliders[pair.collider2];
830 let rb_handle1 = co1.parent.map(|p| p.handle);
831 let rb_handle2 = co2.parent.map(|p| p.handle);
832
833 'emit_events: {
834 if !co1.changes.needs_narrow_phase_update()
835 && !co2.changes.needs_narrow_phase_update()
836 {
837 return;
839 }
840
841 if rb_handle1 == rb_handle2 && co1.parent.is_some() {
842 pair.clear();
844 break 'emit_events;
845 }
846
847 let rb1 = co1.parent.map(|co_parent1| &bodies[co_parent1.handle]);
848 let rb2 = co2.parent.map(|co_parent2| &bodies[co_parent2.handle]);
849
850 let rb_type1 = rb1.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
851 let rb_type2 = rb2.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
852
853 if let (Some(co_parent1), Some(co_parent2)) = (&co1.parent, &co2.parent) {
855 for (_, joint) in
856 impulse_joints.joints_between(co_parent1.handle, co_parent2.handle)
857 {
858 if !joint.data.contacts_enabled {
859 pair.clear();
860 break 'emit_events;
861 }
862 }
863
864 let link1 = multibody_joints.rigid_body_link(co_parent1.handle);
865 let link2 = multibody_joints.rigid_body_link(co_parent2.handle);
866
867 if let (Some(link1), Some(link2)) = (link1, link2) {
868 if link1.multibody == link2.multibody {
871 if let Some(mb) = multibody_joints.get_multibody(link1.multibody) {
873 if !mb.self_contacts_enabled() {
874 pair.clear();
875 break 'emit_events;
876 }
877 }
878
879 if let Some((_, _, mb_link)) =
881 multibody_joints.joint_between(co_parent1.handle, co_parent2.handle)
882 {
883 if !mb_link.joint.data.contacts_enabled {
884 pair.clear();
885 break 'emit_events;
886 }
887 }
888 }
889 }
890 }
891
892 if !co1.flags.active_collision_types.test(rb_type1, rb_type2)
894 && !co2.flags.active_collision_types.test(rb_type1, rb_type2)
895 {
896 pair.clear();
897 break 'emit_events;
898 }
899
900 if !co1.flags.collision_groups.test(co2.flags.collision_groups) {
902 pair.clear();
903 break 'emit_events;
904 }
905
906 let active_hooks = co1.flags.active_hooks | co2.flags.active_hooks;
907
908 let mut solver_flags = if active_hooks.contains(ActiveHooks::FILTER_CONTACT_PAIRS) {
909 let context = PairFilterContext {
910 bodies,
911 colliders,
912 rigid_body1: rb_handle1,
913 rigid_body2: rb_handle2,
914 collider1: pair.collider1,
915 collider2: pair.collider2,
916 };
917
918 if let Some(solver_flags) = hooks.filter_contact_pair(&context) {
919 solver_flags
920 } else {
921 pair.clear();
923 break 'emit_events;
924 }
925 } else {
926 SolverFlags::default()
927 };
928
929 if !co1.flags.solver_groups.test(co2.flags.solver_groups) {
930 solver_flags.remove(SolverFlags::COMPUTE_IMPULSES);
931 }
932
933 if co1.changes.contains(ColliderChanges::SHAPE)
934 || co2.changes.contains(ColliderChanges::SHAPE)
935 {
936 pair.workspace = None;
938 }
939
940 let pos12 = co1.pos.inv_mul(&co2.pos);
941
942 let contact_skin_sum = co1.contact_skin() + co2.contact_skin();
943 let soft_ccd_prediction1 = rb1.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
944 let soft_ccd_prediction2 = rb2.map(|rb| rb.soft_ccd_prediction()).unwrap_or(0.0);
945 let effective_prediction_distance = if soft_ccd_prediction1 > 0.0
946 || soft_ccd_prediction2 > 0.0
947 {
948 let aabb1 = co1.compute_collision_aabb(0.0);
949 let aabb2 = co2.compute_collision_aabb(0.0);
950 let inv_dt = crate::utils::inv(dt);
951
952 let linvel1 = rb1
953 .map(|rb| rb.linvel().clamp_length_max(soft_ccd_prediction1 * inv_dt))
954 .unwrap_or_default();
955 let linvel2 = rb2
956 .map(|rb| rb.linvel().clamp_length_max(soft_ccd_prediction2 * inv_dt))
957 .unwrap_or_default();
958
959 if !aabb1.intersects(&aabb2)
960 && !aabb1.intersects_moving_aabb(&aabb2, linvel2 - linvel1)
961 {
962 pair.clear();
963 break 'emit_events;
964 }
965
966 prediction_distance.max(dt * (linvel1 - linvel2).length()) + contact_skin_sum
967 } else {
968 prediction_distance + contact_skin_sum
969 };
970
971 let _ = query_dispatcher.contact_manifolds(
972 &pos12,
973 &*co1.shape,
974 &*co2.shape,
975 effective_prediction_distance,
976 &mut pair.manifolds,
977 &mut pair.workspace,
978 );
979
980 let friction = CoefficientCombineRule::combine(
981 co1.material.friction,
982 co2.material.friction,
983 co1.material.friction_combine_rule,
984 co2.material.friction_combine_rule,
985 );
986 let restitution = CoefficientCombineRule::combine(
987 co1.material.restitution,
988 co2.material.restitution,
989 co1.material.restitution_combine_rule,
990 co2.material.restitution_combine_rule,
991 );
992
993 let zero = RigidBodyDominance(0); let dominance1 = rb1.map(|rb| rb.dominance).unwrap_or(zero);
995 let dominance2 = rb2.map(|rb| rb.dominance).unwrap_or(zero);
996
997 for manifold in &mut pair.manifolds {
998 let world_pos1 = manifold.subshape_pos1.prepend_to(&co1.pos);
999 let world_pos2 = manifold.subshape_pos2.prepend_to(&co2.pos);
1000 manifold.data.solver_contacts.clear();
1001 manifold.data.rigid_body1 = rb_handle1;
1002 manifold.data.rigid_body2 = rb_handle2;
1003 manifold.data.solver_flags = solver_flags;
1004 manifold.data.relative_dominance = dominance1.effective_group(&rb_type1)
1005 - dominance2.effective_group(&rb_type2);
1006 manifold.data.normal = world_pos1.rotation * manifold.local_n1;
1007
1008 #[allow(unused_mut)] let mut selected = [0, 1, 2, 3];
1011 #[allow(unused_mut)] let mut num_selected = MAX_MANIFOLD_POINTS.min(manifold.points.len());
1013
1014 #[cfg(feature = "dim3")]
1015 #[cfg(feature = "dim3")]
1021 super::manifold_reduction::reduce_manifold_naive(
1022 manifold,
1023 &mut selected,
1024 &mut num_selected,
1025 prediction_distance,
1026 );
1027
1028 for contact_id in &selected[..num_selected] {
1029 let contact = &manifold.points[*contact_id];
1031 let effective_contact_dist =
1032 contact.dist - co1.contact_skin() - co2.contact_skin();
1033
1034 let keep_solver_contact = effective_contact_dist < prediction_distance || {
1035 let world_pt1 = world_pos1 * contact.local_p1;
1036 let world_pt2 = world_pos2 * contact.local_p2;
1037 let vel1 = rb1
1038 .map(|rb| rb.velocity_at_point(world_pt1))
1039 .unwrap_or_default();
1040 let vel2 = rb2
1041 .map(|rb| rb.velocity_at_point(world_pt2))
1042 .unwrap_or_default();
1043 effective_contact_dist + (vel2 - vel1).dot(manifold.data.normal) * dt
1044 < prediction_distance
1045 };
1046
1047 if keep_solver_contact {
1048 let world_pt1 = world_pos1 * contact.local_p1;
1050 let world_pt2 = world_pos2 * contact.local_p2;
1051
1052 let effective_point = world_pt1.midpoint(world_pt2);
1053
1054 let solver_contact = SolverContact {
1055 contact_id: [*contact_id as u32],
1056 point: effective_point,
1057 dist: effective_contact_dist,
1058 friction,
1059 restitution,
1060 tangent_velocity: Default::default(),
1061 is_new: (contact.data.impulse == 0.0) as u32 as Real,
1062 warmstart_impulse: contact.data.warmstart_impulse,
1063 warmstart_tangent_impulse: contact.data.warmstart_tangent_impulse,
1064 #[cfg(feature = "dim2")]
1065 warmstart_twist_impulse: na::zero(),
1066 #[cfg(feature = "dim3")]
1067 warmstart_twist_impulse: contact.data.warmstart_twist_impulse,
1068 #[cfg(feature = "dim3")]
1069 padding: Default::default(),
1070 };
1071
1072 manifold.data.solver_contacts.push(solver_contact);
1073 }
1074 }
1075
1076 if active_hooks.contains(ActiveHooks::MODIFY_SOLVER_CONTACTS) {
1078 let mut modifiable_solver_contacts =
1079 std::mem::take(&mut manifold.data.solver_contacts);
1080 let mut modifiable_user_data = manifold.data.user_data;
1081 let mut modifiable_normal = manifold.data.normal;
1082
1083 let mut context = ContactModificationContext {
1084 bodies,
1085 colliders,
1086 rigid_body1: rb_handle1,
1087 rigid_body2: rb_handle2,
1088 collider1: pair.collider1,
1089 collider2: pair.collider2,
1090 manifold,
1091 solver_contacts: &mut modifiable_solver_contacts,
1092 normal: &mut modifiable_normal,
1093 user_data: &mut modifiable_user_data,
1094 };
1095
1096 hooks.modify_solver_contacts(&mut context);
1097
1098 manifold.data.solver_contacts = modifiable_solver_contacts;
1099 manifold.data.normal = modifiable_normal;
1100 manifold.data.user_data = modifiable_user_data;
1101 }
1102 }
1103 }
1104
1105 let has_any_active_contact = pair.has_any_active_contact();
1111 if has_any_active_contact != had_any_active_contact {
1112 let active_events = co1.flags.active_events | co2.flags.active_events;
1113 if active_events.contains(ActiveEvents::COLLISION_EVENTS) {
1114 if has_any_active_contact {
1115 pair.emit_start_event(bodies, colliders, events);
1116 } else {
1117 pair.emit_stop_event(bodies, colliders, events);
1118 }
1119 }
1120
1121 #[cfg(not(feature = "parallel"))]
1122 islands.interaction_started_or_stopped(
1123 bodies,
1124 rb_handle1,
1125 rb_handle2,
1126 has_any_active_contact,
1127 true,
1128 );
1129 #[cfg(feature = "parallel")]
1130 {
1131 let _ = snd.send((rb_handle1, rb_handle2, has_any_active_contact));
1133 }
1134 }
1135 });
1136
1137 #[cfg(feature = "parallel")]
1138 {
1139 drop(snd);
1140 for (parent1, parent2, any_active_contact) in rcv.iter() {
1141 islands.interaction_started_or_stopped(
1142 bodies,
1143 parent1,
1144 parent2,
1145 any_active_contact,
1146 true,
1147 );
1148 }
1149 }
1150 }
1151
1152 pub(crate) fn select_active_contacts<'a>(
1155 &'a mut self,
1156 islands: &IslandManager,
1157 bodies: &RigidBodySet,
1158 out_contact_pairs: &mut Vec<TemporaryInteractionIndex>,
1159 out_manifolds: &mut Vec<&'a mut ContactManifold>,
1160 out: &mut [Vec<ContactManifoldIndex>],
1161 ) {
1162 for out_island in &mut out[..islands.active_islands().len()] {
1163 out_island.clear();
1164 }
1165
1166 for (pair_id, inter) in self.contact_graph.graph.edges.iter_mut().enumerate() {
1168 let mut push_pair = false;
1169
1170 for manifold in &mut inter.weight.manifolds {
1171 if manifold
1172 .data
1173 .solver_flags
1174 .contains(SolverFlags::COMPUTE_IMPULSES)
1175 && manifold.data.num_active_contacts() != 0
1176 {
1177 let (active_island_id1, rb_type1, sleeping1) =
1178 if let Some(handle1) = manifold.data.rigid_body1 {
1179 let rb1 = &bodies[handle1];
1180 (
1181 rb1.ids.active_island_id,
1182 rb1.body_type,
1183 rb1.activation.sleeping,
1184 )
1185 } else {
1186 (0, RigidBodyType::Fixed, true)
1187 };
1188
1189 let (active_island_id2, rb_type2, sleeping2) =
1190 if let Some(handle2) = manifold.data.rigid_body2 {
1191 let rb2 = &bodies[handle2];
1192 (
1193 rb2.ids.active_island_id,
1194 rb2.body_type,
1195 rb2.activation.sleeping,
1196 )
1197 } else {
1198 (0, RigidBodyType::Fixed, true)
1199 };
1200
1201 if (rb_type1.is_dynamic() || rb_type2.is_dynamic())
1202 && (!rb_type1.is_dynamic() || !sleeping1)
1203 && (!rb_type2.is_dynamic() || !sleeping2)
1204 {
1205 let island_awake_index = if !rb_type1.is_dynamic() {
1206 islands.islands[active_island_id2]
1207 .id_in_awake_list()
1208 .expect("Internal error: island should be awake.")
1209 } else {
1210 islands.islands[active_island_id1]
1211 .id_in_awake_list()
1212 .expect("Internal error: island should be awake.")
1213 };
1214
1215 out[island_awake_index].push(out_manifolds.len());
1216 out_manifolds.push(manifold);
1217 push_pair = true;
1218 }
1219 }
1220 }
1221
1222 if push_pair {
1223 out_contact_pairs.push(EdgeIndex::new(pair_id as u32));
1224 }
1225 }
1226 }
1227}
1228
1229#[cfg(test)]
1230#[cfg(feature = "f32")]
1231#[cfg(feature = "dim3")]
1232mod test {
1233 use crate::math::Vector;
1234 use crate::prelude::{
1235 CCDSolver, ColliderBuilder, DefaultBroadPhase, IntegrationParameters, PhysicsPipeline,
1236 RigidBodyBuilder,
1237 };
1238
1239 use super::*;
1240
1241 #[test]
1243 pub fn collider_set_parent_depenetration() {
1244 let mut rigid_body_set = RigidBodySet::new();
1249 let mut collider_set = ColliderSet::new();
1250
1251 let collider = ColliderBuilder::ball(0.5);
1253
1254 let rigid_body_1 = RigidBodyBuilder::dynamic()
1256 .translation(Vector::new(0.0, 0.0, 0.0))
1257 .build();
1258 let body_1_handle = rigid_body_set.insert(rigid_body_1);
1259
1260 let collider_1_handle =
1262 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1263
1264 let collider_2_handle =
1266 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1267
1268 let rigid_body_2 = RigidBodyBuilder::dynamic()
1270 .translation(Vector::new(0.0, 0.0, 0.0))
1271 .build();
1272 let body_2_handle = rigid_body_set.insert(rigid_body_2);
1273
1274 let gravity = Vector::ZERO;
1276 let integration_parameters = IntegrationParameters::default();
1277 let mut physics_pipeline = PhysicsPipeline::new();
1278 let mut island_manager = IslandManager::new();
1279 let mut broad_phase = DefaultBroadPhase::new();
1280 let mut narrow_phase = NarrowPhase::new();
1281 let mut impulse_joint_set = ImpulseJointSet::new();
1282 let mut multibody_joint_set = MultibodyJointSet::new();
1283 let mut ccd_solver = CCDSolver::new();
1284 let physics_hooks = ();
1285 let event_handler = ();
1286
1287 physics_pipeline.step(
1288 gravity,
1289 &integration_parameters,
1290 &mut island_manager,
1291 &mut broad_phase,
1292 &mut narrow_phase,
1293 &mut rigid_body_set,
1294 &mut collider_set,
1295 &mut impulse_joint_set,
1296 &mut multibody_joint_set,
1297 &mut ccd_solver,
1298 &physics_hooks,
1299 &event_handler,
1300 );
1301 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1302 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1303 assert!(
1304 (collider_1_position.translation - collider_2_position.translation).length() < 0.5f32
1305 );
1306
1307 let contact_pair = narrow_phase
1308 .contact_pair(collider_1_handle, collider_2_handle)
1309 .expect("The contact pair should exist.");
1310 assert_eq!(contact_pair.manifolds.len(), 0);
1311 assert!(
1312 narrow_phase
1313 .intersection_pair(collider_1_handle, collider_2_handle)
1314 .is_none(),
1315 "Interaction pair is for sensors"
1316 );
1317 collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1319
1320 physics_pipeline.step(
1321 gravity,
1322 &integration_parameters,
1323 &mut island_manager,
1324 &mut broad_phase,
1325 &mut narrow_phase,
1326 &mut rigid_body_set,
1327 &mut collider_set,
1328 &mut impulse_joint_set,
1329 &mut multibody_joint_set,
1330 &mut ccd_solver,
1331 &physics_hooks,
1332 &event_handler,
1333 );
1334
1335 let contact_pair = narrow_phase
1336 .contact_pair(collider_1_handle, collider_2_handle)
1337 .expect("The contact pair should exist.");
1338 assert_eq!(contact_pair.manifolds.len(), 1);
1339 assert!(
1340 narrow_phase
1341 .intersection_pair(collider_1_handle, collider_2_handle)
1342 .is_none(),
1343 "Interaction pair is for sensors"
1344 );
1345
1346 for _ in 0..200 {
1348 physics_pipeline.step(
1349 gravity,
1350 &integration_parameters,
1351 &mut island_manager,
1352 &mut broad_phase,
1353 &mut narrow_phase,
1354 &mut rigid_body_set,
1355 &mut collider_set,
1356 &mut impulse_joint_set,
1357 &mut multibody_joint_set,
1358 &mut ccd_solver,
1359 &physics_hooks,
1360 &event_handler,
1361 );
1362
1363 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1364 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1365 println!("collider 1 position: {}", collider_1_position.translation);
1366 println!("collider 2 position: {}", collider_2_position.translation);
1367 }
1368
1369 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1370 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1371 println!("collider 2 position: {}", collider_2_position.translation);
1372 assert!(
1373 (collider_1_position.translation - collider_2_position.translation).length() >= 0.5f32,
1374 "colliders should no longer be penetrating."
1375 );
1376 }
1377
1378 #[test]
1380 pub fn collider_set_parent_no_self_intersection() {
1381 let mut rigid_body_set = RigidBodySet::new();
1389 let mut collider_set = ColliderSet::new();
1390
1391 let collider = ColliderBuilder::ball(0.5);
1393
1394 let rigid_body_1 = RigidBodyBuilder::dynamic()
1396 .translation(Vector::new(0.0, 0.0, 0.0))
1397 .build();
1398 let body_1_handle = rigid_body_set.insert(rigid_body_1);
1399
1400 let collider_1_handle =
1402 collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set);
1403
1404 let rigid_body_2 = RigidBodyBuilder::dynamic()
1406 .translation(Vector::new(0.0, 0.0, 0.0))
1407 .build();
1408 let body_2_handle = rigid_body_set.insert(rigid_body_2);
1409
1410 let collider_2_handle =
1412 collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set);
1413
1414 let gravity = Vector::ZERO;
1416 let integration_parameters = IntegrationParameters::default();
1417 let mut physics_pipeline = PhysicsPipeline::new();
1418 let mut island_manager = IslandManager::new();
1419 let mut broad_phase = DefaultBroadPhase::new();
1420 let mut narrow_phase = NarrowPhase::new();
1421 let mut impulse_joint_set = ImpulseJointSet::new();
1422 let mut multibody_joint_set = MultibodyJointSet::new();
1423 let mut ccd_solver = CCDSolver::new();
1424 let physics_hooks = ();
1425 let event_handler = ();
1426
1427 physics_pipeline.step(
1428 gravity,
1429 &integration_parameters,
1430 &mut island_manager,
1431 &mut broad_phase,
1432 &mut narrow_phase,
1433 &mut rigid_body_set,
1434 &mut collider_set,
1435 &mut impulse_joint_set,
1436 &mut multibody_joint_set,
1437 &mut ccd_solver,
1438 &physics_hooks,
1439 &event_handler,
1440 );
1441
1442 let contact_pair = narrow_phase
1443 .contact_pair(collider_1_handle, collider_2_handle)
1444 .expect("The contact pair should exist.");
1445 assert_eq!(
1446 contact_pair.manifolds.len(),
1447 1,
1448 "There should be a contact manifold."
1449 );
1450
1451 let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos;
1452 let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos;
1453 assert!(
1454 (collider_1_position.translation - collider_2_position.translation).length() < 0.5f32
1455 );
1456
1457 collider_set.set_parent(collider_2_handle, Some(body_1_handle), &mut rigid_body_set);
1459 physics_pipeline.step(
1460 gravity,
1461 &integration_parameters,
1462 &mut island_manager,
1463 &mut broad_phase,
1464 &mut narrow_phase,
1465 &mut rigid_body_set,
1466 &mut collider_set,
1467 &mut impulse_joint_set,
1468 &mut multibody_joint_set,
1469 &mut ccd_solver,
1470 &physics_hooks,
1471 &event_handler,
1472 );
1473
1474 let contact_pair = narrow_phase
1475 .contact_pair(collider_1_handle, collider_2_handle)
1476 .expect("The contact pair should no longer exist.");
1477 assert_eq!(
1478 contact_pair.manifolds.len(),
1479 0,
1480 "Colliders with same parent should not be in contact together."
1481 );
1482
1483 collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set);
1485 physics_pipeline.step(
1486 gravity,
1487 &integration_parameters,
1488 &mut island_manager,
1489 &mut broad_phase,
1490 &mut narrow_phase,
1491 &mut rigid_body_set,
1492 &mut collider_set,
1493 &mut impulse_joint_set,
1494 &mut multibody_joint_set,
1495 &mut ccd_solver,
1496 &physics_hooks,
1497 &event_handler,
1498 );
1499
1500 let contact_pair = narrow_phase
1501 .contact_pair(collider_1_handle, collider_2_handle)
1502 .expect("The contact pair should exist.");
1503 assert_eq!(
1504 contact_pair.manifolds.len(),
1505 1,
1506 "There should be a contact manifold."
1507 );
1508 }
1509}