1use std;
4#[cfg(feature = "debug_dump")]
5use std::sync::atomic;
6use std::cmp::Reverse;
7use either::Either;
8use derive_more::Into;
9use log;
10use sorted_vec::{SortedSet, ReverseSortedSet};
11use stash::Stash;
12use vec_map::VecMap;
13#[cfg(feature = "derive_serdes")]
14use serde::{Deserialize, Serialize};
15
16use crate::{component, event, geometry, math, object};
17use math::*;
18use geometry::Aabb3;
19
20pub mod contact;
21pub mod proximity;
22pub mod intersection;
23mod broad;
24
25pub use self::contact::Contact;
26pub use self::proximity::Proximity;
27pub use self::intersection::Intersection;
28use self::broad::Broad;
29
30pub const CONTACT_DISTANCE : f64 = 0.005; pub const RESTING_VELOCITY : f64 = (1.0/120.0) * CONTACT_DISTANCE;
45pub const OBJECT_KEY_MAX : object::KeyType = INTERNAL_ID_DYNAMIC_BIT - 1;
48
49pub (crate) const INTERNAL_ID_DYNAMIC_BIT : object::KeyType =
52 1 << (object::KeyType::BITS - 1); #[cfg(feature = "debug_dump")]
55#[cfg_attr(docsrs, doc(cfg(feature="debug_dump")))]
56pub static DEBUG_DUMP : atomic::AtomicBool = atomic::AtomicBool::new (false);
57#[cfg(feature = "debug_dump")]
58#[cfg_attr(docsrs, doc(cfg(feature="debug_dump")))]
59pub const DEBUG_DUMP_DETECT_RESOLVE_MAX_ITERS : u64 = 200;
60
61#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
67#[derive(Clone, Debug, Default)]
68pub struct Collision {
69 broad : Broad,
71 pseudo_velocities : VecMap <Vector3 <f64>>,
76 #[cfg_attr(feature = "derive_serdes", serde(skip))]
82 pipeline : Pipeline,
83 persistent : contact::Manager,
85 #[cfg(debug_assertions)]
87 detect_resolve_max_iter_count : u64,
88 #[cfg(debug_assertions)]
90 narrow_toi_max_iter_count : u64
91}
92
93#[derive(Clone, Debug, Default, PartialEq)]
97struct Pipeline {
98 pub detect_resolve_iter : u64,
101 pub broad_overlap_pairs : Vec <ObjectPair>,
103 pub mid_toi_pairs :
105 ReverseSortedSet <(Normalized <f64>, Normalized <f64>, ObjectPair)>,
106 pub narrow_toi_contacts :
108 ReverseSortedSet <(Normalized <f64>, ObjectPair, contact::Colliding)>,
109 pub resolved_collisions : Vec <event::CollisionResolve>,
110 pub overlaps : Vec <event::Overlap>,
112}
113
114#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
116#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Into)]
117pub (crate) struct ObjectPair (InternalId, InternalId);
118
119#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
122#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
123pub (crate) struct InternalId (object::KeyType);
124
125#[derive(Debug)]
126struct ContactImpulses {
127 pub impulse_normal_a : Vector3 <f64>,
128 pub impulse_normal_b : Vector3 <f64>,
129 pub impulse_tangent_a : Vector3 <f64>,
130 pub impulse_tangent_b : Vector3 <f64>
131}
132
133#[derive(Debug)]
134struct ContactPostImpulses {
135 pub pseudo_impulse_a : Vector3 <f64>,
136 pub pseudo_impulse_b : Vector3 <f64>
137}
138
139pub fn report_sizes() {
144 use std::mem::size_of;
145 println!("collision report sizes...");
146
147 println!(" size of Collision: {}", size_of::<Collision>());
148
149 println!("...collision report sizes");
150}
151
152fn lerp_object <O : object::Temporal> (
154 object : &mut O, pseudovelocity : Vector3 <f64>, t_relative : f64
155) {
156 let component::Position (position) = object.position();
157 object.position_mut().0 = position +
158 t_relative * object.derivatives().velocity + t_relative * pseudovelocity;
159}
160
161fn contact_constrain_velocity (
162 contact : Contact,
163 restitution : Normalized <f64>, mut object_a : Either <&object::Static, &mut object::Dynamic>,
165 object_b : &mut object::Dynamic,
166 pseudovelocity_a : Option <Vector3 <f64>>,
167 pseudovelocity_b : Vector3 <f64>
168) -> Option <ContactImpulses> {
169 let velocity_effective_a = match &object_a {
170 Either::Left (_) => {
171 debug_assert!(pseudovelocity_a.is_none());
172 Vector3::zero()
173 }
174 Either::Right (object_a) => object_a.derivatives.velocity +
175 pseudovelocity_a.unwrap_or (Vector3::zero())
176 };
177 let velocity_effective_b = object_b.derivatives.velocity + pseudovelocity_b;
178 let velocity_effective_relative = velocity_effective_a - velocity_effective_b;
179 let velocity_normal_component =
180 velocity_effective_relative.dot (*contact.constraint.normal());
181 let mut impulses = None;
182 let mut mass_relative_a = 0.0;
183 let mut mass_relative_b = 0.0;
184 if velocity_normal_component < 0.0 {
185 let velocity_normal = velocity_normal_component * *contact.constraint.normal();
186 let impulse_normal = velocity_normal + *restitution * velocity_normal;
188 let impulse_normal_magnitude2 = impulse_normal.magnitude_squared();
189 if impulse_normal_magnitude2 < RESTING_VELOCITY * RESTING_VELOCITY {
190 return None
191 }
192 let (impulse_normal_a, impulse_normal_b) = match &mut object_a {
193 Either::Right (object_a) => {
194 let mass_combined = object_a.mass + object_b.mass;
195 mass_relative_a = object_a.mass.mass() * mass_combined.mass_reciprocal();
196 mass_relative_b = object_b.mass.mass() * mass_combined.mass_reciprocal();
197 let impulse_normal_a = -mass_relative_b * impulse_normal;
198 let impulse_normal_b = mass_relative_a * impulse_normal;
199 object_a.derivatives.velocity += impulse_normal_a;
200 object_b.derivatives.velocity += impulse_normal_b;
201 (impulse_normal_a, impulse_normal_b)
202 }
203 Either::Left (_) => {
204 object_b.derivatives.velocity += impulse_normal;
205 (Vector3::zero(), impulse_normal)
206 }
207 };
208 let (impulse_tangent_a, impulse_tangent_b) = {
210 let velocity_tangent = velocity_effective_relative - velocity_normal;
211 let velocity_tangent_magnitude2 = velocity_tangent.magnitude_squared();
212 if velocity_tangent_magnitude2 > 0.0 {
213 let friction_a = match &object_a {
214 Either::Left (x) => x.material.friction,
215 Either::Right (x) => x.material.friction
216 };
217 let friction_coefficient = friction_a * object_b.material.friction;
218 let impulse_tangent_potential_magnitude2 =
219 *friction_coefficient * impulse_normal_magnitude2;
220 let impulse_tangent = if impulse_tangent_potential_magnitude2 <
221 velocity_tangent_magnitude2
222 {
223 (impulse_tangent_potential_magnitude2.sqrt()
224 / velocity_tangent_magnitude2.sqrt()) * velocity_tangent
225 } else {
226 velocity_tangent
227 };
228 match object_a {
229 Either::Right (object_a) => {
230 let impulse_tangent_a = -mass_relative_b * impulse_tangent;
231 let impulse_tangent_b = mass_relative_a * impulse_tangent;
232 object_a.derivatives.velocity += impulse_tangent_a;
233 object_b.derivatives.velocity += impulse_tangent_b;
234 (impulse_tangent_a, impulse_tangent_b)
235 }
236 Either::Left (_) => {
237 object_b.derivatives.velocity += impulse_tangent;
238 (Vector3::zero(), impulse_tangent)
239 }
240 }
241 } else {
242 (Vector3::zero(), Vector3::zero())
243 }
244 };
245 impulses = Some (ContactImpulses {
246 impulse_normal_a, impulse_normal_b,
247 impulse_tangent_a, impulse_tangent_b
248 });
249 }
250 impulses
251}
252
253fn contact_constrain_position (
254 t_reverse : f64,
255 mut object_a : Either <&object::Static, &mut object::Dynamic>,
256 object_b : &mut object::Dynamic,
257 pseudovelocity_a : Option <&mut Vector3 <f64>>,
258 pseudovelocity_b : &mut Vector3 <f64>
259) -> (Option <ContactPostImpulses>, Proximity) {
260 let t_forward = -t_reverse;
261 let mut impulses = None;
262 let mut proximity = match &object_a {
263 Either::Left (object_a) => Proximity::query (*object_a, object_b),
264 Either::Right (object_a) => Proximity::query (*object_a, object_b)
265 };
266 log::trace!(distance=proximity.distance; "post impulse contact @ T==1.0");
267 if proximity.distance < 0.0 {
268 let (pseudo_impulse_a, pseudo_impulse_b) = match &mut object_a {
269 Either::Left (object_a) => {
270 lerp_object (object_b, *pseudovelocity_b, t_reverse);
271 let pseudo_impulse_b = -(2.0 * proximity.half_axis +
272 0.5 * CONTACT_DISTANCE * *proximity.normal) / t_forward;
273 *pseudovelocity_b += pseudo_impulse_b;
274 lerp_object (object_b, *pseudovelocity_b, t_forward);
275 proximity = Proximity::query (*object_a, object_b);
276 (Vector3::zero(), pseudo_impulse_b)
277 }
278 Either::Right (object_a) => {
279 let pseudovelocity_a = pseudovelocity_a.unwrap();
280 lerp_object (*object_a, *pseudovelocity_a, t_reverse);
281 lerp_object (object_b, *pseudovelocity_b, t_reverse);
282 let mass_combined = object_a.mass + object_b.mass;
283 let mass_relative_a = object_a.mass.mass() * mass_combined.mass_reciprocal();
284 let mass_relative_b = object_b.mass.mass() * mass_combined.mass_reciprocal();
285 let pseudo_impulse = (2.0 * proximity.half_axis +
286 0.5 * CONTACT_DISTANCE * *proximity.normal) / t_forward;
287 let pseudo_impulse_a = mass_relative_b * pseudo_impulse;
288 let pseudo_impulse_b = -mass_relative_a * pseudo_impulse;
289 *pseudovelocity_a += pseudo_impulse_a;
290 *pseudovelocity_b += pseudo_impulse_b;
291 lerp_object (*object_a, *pseudovelocity_a, t_forward);
292 lerp_object (object_b, *pseudovelocity_b, t_forward);
293 proximity = Proximity::query (*object_a, object_b);
294 (pseudo_impulse_a, pseudo_impulse_b)
295 }
296 };
297 log::trace!(distance=proximity.distance; "position corrected distance @ T==1.0");
298 debug_assert!(proximity.distance >= 0.0);
299 if cfg!(debug_assertions) {
300 approx::assert_abs_diff_eq!(
301 proximity.distance, 0.5 * CONTACT_DISTANCE, epsilon=0.000_000_001);
302 }
303 impulses = Some (ContactPostImpulses { pseudo_impulse_a, pseudo_impulse_b });
304 }
305 (impulses, proximity)
306}
307
308impl Collision {
313 pub(super) const fn broad (&self) -> &Broad {
314 &self.broad
315 }
316 pub fn try_add_object_static (&mut self,
323 objects_dynamic : &VecMap <object::Dynamic>,
324 object : &object::Static,
325 key : object::Key
326 ) -> Result <(), Vec <(object::Id, Intersection)>> {
327 let mut intersections = Vec::new();
328 if object.collidable {
329 let aabb_discrete = object.aabb_dilated();
330 let overlaps : Vec <object::Id> = self.broad.overlaps_discrete (aabb_discrete)
331 .into_iter().map (object::Id::from).collect::<Vec <_>>();
332 for object_id in overlaps {
333 let proximity = match object_id.kind {
334 object::Kind::Static => continue, object::Kind::Dynamic => {
336 let object_dynamic = &objects_dynamic[object_id.key.index()];
337 if !object_dynamic.collidable {
338 continue }
340 Proximity::query (object_dynamic, object)
341 }
342 object::Kind::Nodetect => unreachable!()
343 };
344 if let Ok (intersection) = proximity.try_into() {
345 intersections.push ((object_id, intersection));
346 }
347 }
348 }
349 if intersections.is_empty() {
350 self.add_object_static (object, key);
351 Ok (())
352 } else {
353 Err (intersections)
354 }
355 }
356
357 #[inline]
358 pub fn remove_object_static (&mut self, object_key : object::Key) {
359 debug_assert!(self.pipeline.is_empty());
360 let id = InternalId::new_static (object_key);
361 self.broad.remove_object (id);
362 let _ = self.persistent.remove_object (id);
363 }
364
365 pub fn try_add_object_dynamic (&mut self,
372 objects_static : &VecMap <object::Static>,
373 objects_dynamic : &VecMap <object::Dynamic>,
374 object : &object::Dynamic,
375 key : object::Key
376 ) -> Result <(), Vec <(object::Id, Intersection)>> {
377 let mut intersections = Vec::new();
378 if object.collidable {
379 let aabb_discrete = object.aabb_dilated();
380 let overlaps : Vec <object::Id> = self.broad.overlaps_discrete (aabb_discrete)
381 .into_iter().map (object::Id::from).collect::<Vec <_>>();
382 for object_id in overlaps {
383 let proximity = match object_id.kind {
384 object::Kind::Static => {
385 let object_static = &objects_static[object_id.key.index()];
386 if !object_static.collidable {
387 continue }
389 Proximity::query (object_static, object)
390 }
391 object::Kind::Dynamic => {
392 let object_dynamic = &objects_dynamic[object_id.key.index()];
393 if !object_dynamic.collidable {
394 continue }
396 Proximity::query (object_dynamic, object)
397 }
398 object::Kind::Nodetect => unreachable!()
399 };
400 if let Ok (intersection) = proximity.try_into() {
401 intersections.push ((object_id, intersection));
402 }
403 }
404 }
405 if intersections.is_empty() {
406 self.add_object_dynamic (object, key);
407 Ok (())
408 } else {
409 Err (intersections)
410 }
411 }
412
413 #[inline]
414 pub fn remove_object_dynamic (&mut self, key : object::Key) {
415 debug_assert!(self.pipeline.is_empty());
416 let id = InternalId::new_dynamic (key);
417 self.broad.remove_object (id);
418 self.pseudo_velocities.remove (key.index()).unwrap();
419 let _ = self.persistent.remove_object (id);
420 }
421
422 #[inline]
423 pub fn update_object_static (&mut self,
424 object : &object::Static, key : object::Key
425 ) {
426 debug_assert!(self.pipeline.is_empty());
427 self.broad.update_aabb_static (object.aabb_dilated(), key);
428 unimplemented!("TODO: collision detect and resolve any overlaps caused by \
429 updating the static object")
430 }
431
432 #[inline]
433 pub fn update_object_dynamic (&mut self,
434 object : &object::Dynamic, key : object::Key
435 ) {
436 debug_assert!(self.pipeline.is_empty());
437 let aabb = object.aabb_dilated();
438 self.broad.update_aabb_dynamic_discrete (aabb, key);
439 self.broad.update_aabb_dynamic_continuous (aabb, key);
441 log::warn!("TODO: collision detect and resolve any overlaps caused by \
442 updating the dynamic object")
443 }
444
445 pub fn detect_resolve_loop (&mut self,
464 objects_static : &mut VecMap <object::Static>,
465 objects_dynamic : &mut VecMap <object::Dynamic>,
466 step : u64,
467 output : &mut Vec <event::Output>
468 ) {
469 log::trace!(step; "detect/resolve loop");
470
471 debug_assert!(self.pipeline.is_empty());
473 self.pipeline.detect_resolve_iter = 0;
474
475 self.broad.begin_step (objects_dynamic, step);
480
481 loop {
483 log::debug!(iter=self.pipeline.detect_resolve_iter;
484 "detect/resolve loop iteration");
485 self.detect_continuous (objects_static, objects_dynamic);
487 if !self.resolve_collision (objects_static, objects_dynamic) {
490 debug_assert!(self.pipeline.mid_toi_pairs.is_empty());
491 debug_assert!(self.pipeline.narrow_toi_contacts.is_empty());
492 break
493 }
494 self.pipeline.detect_resolve_iter += 1;
495 }
496
497 log::trace!(iters=self.pipeline.detect_resolve_iter+1;
498 "detect/resolve loop complete");
499 #[cfg(debug_assertions)]
500 {
501 if self.detect_resolve_max_iter_count
502 < (self.pipeline.detect_resolve_iter + 1)
503 {
504 #[cfg(feature = "debug_dump")]
505 if self.pipeline.detect_resolve_iter >
506 DEBUG_DUMP_DETECT_RESOLVE_MAX_ITERS
507 {
508 DEBUG_DUMP.store (true, atomic::Ordering::SeqCst);
509 }
510 self.detect_resolve_max_iter_count = self.pipeline.detect_resolve_iter;
511 }
512 log::debug!(max_iter_count=self.detect_resolve_max_iter_count;
513 "detect/resolve loop max iters");
514 }
515
516 for collision_resolve in self.pipeline.resolved_collisions.drain (..) {
518 output.push (collision_resolve.into());
519 }
520 for overlap in self.pipeline.overlaps.drain (..) {
521 output.push (overlap.into());
522 }
523
524 self.persistent.output_contacts (output);
526
527 for (_, pseudovelocity) in self.pseudo_velocities.iter_mut() {
529 *pseudovelocity = Vector3::zero();
530 }
531
532 debug_assert!(self.pipeline.is_empty());
534 }
535
536 pub fn constrain_contact_positions (&mut self,
538 objects_static : &VecMap <object::Static>,
539 objects_dynamic : &mut VecMap <object::Dynamic>
540 ) {
541 let mut remove_groups = vec![];
542 let mut new_groups = vec![];
543 let mut contact_groups = self.persistent.contact_groups.take().unwrap();
544 for (group_index, group) in contact_groups.iter_mut() {
545 log::debug!(group_index, contacts_count=group.contacts.len();
546 "group constrain positions");
547 log::trace!(group_index, contacts:?=group.contacts;
548 "group constrain positions contacts");
549 let mut iter = 0;
550 let mut remove_contacts = vec![];
551 loop {
552 remove_contacts.clear();
553 let mut satisfied = true;
554 for (contact_index, (object_pair, contact)) in
555 group.contacts.iter_mut().enumerate()
556 {
557 let (object_id_a, object_id_b) = (*object_pair).into();
558 let index_a = object_id_a.key().index();
559 let index_b = object_id_b.key().index();
560 let mut object_a = match object_id_a.kind() {
561 object::Kind::Static => Either::Left (objects_static[index_a].clone()),
562 object::Kind::Dynamic => Either::Right (objects_dynamic[index_a].clone()),
563 object::Kind::Nodetect => unreachable!()
564 };
565 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
566 let mut object_b = objects_dynamic[index_b].clone();
567 let mut pseudovelocity_a = match object_a {
568 Either::Left (_) => None,
569 Either::Right (_) => Some (self.pseudo_velocities[index_a])
570 };
571 let mut pseudovelocity_b = self.pseudo_velocities[index_b];
572 let (maybe_impulses, proximity) = contact_constrain_position (
573 -1.0,
574 object_a.as_mut().map_left (|object_static| &*object_static),
575 &mut object_b, pseudovelocity_a.as_mut(), &mut pseudovelocity_b
576 );
577 if maybe_impulses.is_some() {
578 satisfied = false;
579 match object_a {
580 Either::Right (object_a) => {
581 objects_dynamic[index_a] = object_a;
582 self.pseudo_velocities[index_a] = pseudovelocity_a.unwrap();
583 }
584 Either::Left (_) => {}
585 }
586 objects_dynamic[index_b] = object_b;
587 self.pseudo_velocities[index_b] = pseudovelocity_b;
588 }
589 if proximity.distance >= CONTACT_DISTANCE {
593 log::debug!(object_pair:?, contact:?, proximity:?;
594 "removing contact @ T==1.0");
595 remove_contacts.push (contact_index as u32);
596 } else {
597 *contact = proximity.try_into().unwrap();
599 }
600 }
601 iter += 1;
602 if satisfied {
603 log::debug!(group_index, iters=iter;
605 "group position constraint satisfied");
606 if !remove_contacts.is_empty() {
607 self.persistent.remove_contacts (group, remove_contacts.as_slice());
608 if group.contacts.is_empty() {
609 remove_groups.push (group_index as contact::group::KeyType);
610 } else {
611 let partitions = group.partition();
612 if !partitions.is_empty() {
613 remove_groups.push (group_index as contact::group::KeyType);
614 new_groups.extend (partitions);
615 }
616 }
617 }
618 break
619 }
620 }
621 }
622 for group_key in remove_groups {
623 let _ = contact_groups.take (group_key as usize).unwrap();
624 }
625 for new_group in new_groups {
626 let dynamic_ids = new_group.dynamic_ids();
627 let group_key = contact_groups.put (new_group) as contact::group::KeyType;
628 for dynamic_id in dynamic_ids.into_vec() {
629 self.persistent.change_dynamic_group_key (dynamic_id, group_key);
630 }
631 }
632 self.persistent.contact_groups = Some (contact_groups);
633 }
634
635 pub fn constrain_contact_velocities (&self,
637 objects_static : &VecMap <object::Static>,
638 objects_dynamic : &mut VecMap <object::Dynamic>
639 ) {
640 for (group_index, group) in self.contact_groups().iter() {
641 log::debug!(group_index, contacts_count=group.contacts.len();
642 "group constrain velocities");
643 log::trace!(group_index, contacts:?=group.contacts;
644 "group constrain velocities contacts");
645 let mut iter = 0;
646 loop {
647 let mut satisfied = true;
648 for (object_pair, contact) in group.contacts.iter() {
649 let (object_id_a, object_id_b) = (*object_pair).into();
650 let index_a = object_id_a.key().index();
651 let index_b = object_id_b.key().index();
652 let mut object_a = match object_id_a.kind() {
653 object::Kind::Static => Either::Left (objects_static[index_a].clone()),
654 object::Kind::Dynamic => Either::Right (objects_dynamic[index_a].clone()),
655 object::Kind::Nodetect => unreachable!()
656 };
657 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
658 let mut object_b = objects_dynamic[index_b].clone();
659 if contact_constrain_velocity (
661 contact.clone(), Normalized::zero(),
662 object_a.as_mut().map_left (|object_static| &*object_static),
663 &mut object_b, None, Vector3::zero()
664 ).is_some() {
665 match object_a {
666 Either::Right (object_a) => objects_dynamic[index_a] = object_a,
667 Either::Left (_) => {}
668 }
669 objects_dynamic[index_b] = object_b;
670 satisfied = false;
671 }
672 }
673 iter += 1;
674 if satisfied {
675 log::debug!(group_index, iters=iter; "group velocity constraint satisfied");
677 break
678 }
679 }
680 }
681 }
682
683 pub (crate) const fn contact_groups (&self) -> &Stash <contact::Group> {
684 self.persistent.contact_groups.as_ref().unwrap()
685 }
686
687 fn detect_continuous (&mut self,
693 objects_static : &VecMap <object::Static>,
694 objects_dynamic : &VecMap <object::Dynamic>
695 ) {
696 self.broad_overlap_pairs_continuous();
698 self.mid_toi_pairs (objects_dynamic);
700 self.narrow_toi_contacts (objects_static, objects_dynamic);
702 }
703
704 fn resolve_collision (&mut self,
714 objects_static : &VecMap <object::Static>,
715 objects_dynamic : &mut VecMap <object::Dynamic>
716 ) -> bool {
717 if let Some (Reverse ((toi, object_pair, contact))) =
718 self.pipeline.narrow_toi_contacts.pop()
719 {
720 let (object_id_a, object_id_b) = object_pair.into();
723 let kind_a = object_id_a.kind();
724 let kind_b = object_id_b.kind();
725 let index_a = object_id_a.key().index();
726 let index_b = object_id_b.key().index();
727 let collidable = {
729 let collidable_a = match kind_a {
730 object::Kind::Static => objects_static[index_a].collidable,
731 object::Kind::Dynamic => objects_dynamic[index_a].collidable,
732 object::Kind::Nodetect => unreachable!()
733 };
734 debug_assert_eq!(kind_b, object::Kind::Dynamic);
735 let collidable_b = objects_dynamic[index_b].collidable;
736 collidable_a && collidable_b
737 };
738 if !collidable {
739 let overlap = event::Overlap {
740 object_id_a: object_id_a.into(),
741 object_id_b: object_id_b.into()
742 };
743 log::debug!(toi=*toi, overlap:?; "nocollide overlap");
744 self.pipeline.overlaps.push (overlap);
745 return true
746 }
747 log::debug!(toi=*toi, object_pair:?=(object_id_a, object_id_b);
748 "resolve collision");
749 let maybe_group_a = self.persistent.get_group_key (object_id_a);
751 let maybe_group_b = {
752 let maybe_group_b = self.persistent.get_group_key (object_id_b);
753 if maybe_group_a == maybe_group_b {
754 None
756 } else {
757 maybe_group_b
758 }
759 };
760 let collision_resolve = self.resolve (objects_static, objects_dynamic,
762 toi, object_id_a, object_id_b, contact, maybe_group_a,
763 maybe_group_b);
764 log::trace!(collision_resolve:?; "resolved collision");
765 self.pipeline.resolved_collisions.push (collision_resolve);
766 true
767 } else {
768 debug_assert!(self.pipeline.mid_toi_pairs.is_empty());
770 false
771 }
772 }
773
774 #[expect(clippy::too_many_arguments)]
775 fn resolve (
776 &mut self,
777 objects_static : &VecMap <object::Static>,
778 objects_dynamic : &mut VecMap <object::Dynamic>,
779 toi : Normalized <f64>,
780 object_id_a : InternalId,
781 object_id_b : InternalId,
782 contact : contact::Colliding,
783 group_key_a : Option <contact::group::KeyType>,
784 group_key_b : Option <contact::group::KeyType>
785 ) -> event::CollisionResolve {
786 use num::Zero;
793 let mut dynamic_ids = SortedSet::new();
794 if object_id_a.kind() == object::Kind::Dynamic {
795 dynamic_ids.push (object_id_a);
796 }
797 dynamic_ids.push (object_id_b);
798 let group_a = group_key_a
799 .map (|group_key| self.persistent.get_group (group_key).unwrap());
800 let group_b = group_key_b
801 .map (|group_key| self.persistent.get_group (group_key).unwrap());
802 group_a.map (|group| dynamic_ids.extend (group.dynamic_ids().into_vec()));
803 group_b.map (|group| dynamic_ids.extend (group.dynamic_ids().into_vec()));
804 let mut dynamic_modified = SortedSet::new();
807 let lerp_objects =
809 |objects_dynamic : &mut VecMap <object::Dynamic>, time_delta|
810 for id in dynamic_ids.iter() {
811 let index = id.key().index();
812 let object = &mut objects_dynamic[index];
813 let pseudovelocity = self.pseudo_velocities[index];
814 lerp_object (object, pseudovelocity, time_delta);
815 };
816 let (t_reverse, t_forward) = {
817 let toi_f64 : f64 = *toi; (-1.0 + toi_f64, 1.0 - toi_f64)
819 };
820 lerp_objects (objects_dynamic, t_reverse);
821 let toi_aabbs = dynamic_ids.iter().map (|id|{
822 let index = id.key().index();
823 objects_dynamic[index].aabb_dilated()
824 }).collect::<Vec <_>>();
825 let constrain_velocity = |
827 objects_dynamic : &mut VecMap <object::Dynamic>,
828 pseudovelocities : &VecMap <Vector3 <f64>>,
829 contact : Contact,
830 restitution : Normalized <f64>,
831 object_id_a : InternalId,
832 object_id_b : InternalId
833 | {
834 let key_a = object_id_a.key();
835 let key_b = object_id_b.key();
836 let index_a = key_a.index();
837 let index_b = key_b.index();
838 let mut object_a = match object_id_a.kind() {
839 object::Kind::Static => Either::Left (objects_static[index_a].clone()),
840 object::Kind::Dynamic => Either::Right (objects_dynamic[index_a].clone()),
841 object::Kind::Nodetect => unreachable!()
842 };
843 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
844 let mut object_b = objects_dynamic[index_b].clone();
845 let pseudovelocity_a = if object_id_a.kind() == object::Kind::Dynamic {
846 Some (pseudovelocities[index_a])
847 } else {
848 None
849 };
850 let pseudovelocity_b = pseudovelocities[index_b];
851 let maybe_impulses = contact_constrain_velocity (
852 contact, restitution,
853 object_a.as_mut().map_left (|object_static| &*object_static),
854 &mut object_b, pseudovelocity_a, pseudovelocity_b
855 );
856 if maybe_impulses.is_some() {
857 match object_a {
858 Either::Right (object_a) => objects_dynamic[index_a] = object_a,
859 Either::Left (_) => {}
860 }
861 objects_dynamic[index_b] = object_b;
862 }
863 maybe_impulses
864 };
865 let mut impulse_normal_a = Vector3::zero();
866 let mut impulse_normal_b = Vector3::zero();
867 let mut impulse_tangent_a = Vector3::zero();
868 let mut impulse_tangent_b = Vector3::zero();
869 let mut iter = 0;
870 loop {
871 let mut satisfied = true;
872 if let Some (impulses) = constrain_velocity (
873 objects_dynamic, &self.pseudo_velocities, contact.contact.clone(),
874 contact.restitution, object_id_a, object_id_b
875 ) {
876 satisfied = group_a.is_none() && group_b.is_none();
878 impulse_normal_a += impulses.impulse_normal_a;
879 impulse_normal_b += impulses.impulse_normal_b;
880 impulse_tangent_a += impulses.impulse_tangent_a;
881 impulse_tangent_b += impulses.impulse_tangent_b;
882 }
883 let mut constrain_group = |group : &contact::Group|
884 for (object_pair, contact) in group.contacts.iter().cloned() {
885 let (object_id_a, object_id_b) = object_pair.into();
886 if constrain_velocity (
887 objects_dynamic, &self.pseudo_velocities, contact, Normalized::zero(),
888 object_id_a, object_id_b
889 ).is_some() {
890 if object_id_a.kind() == object::Kind::Dynamic {
891 dynamic_modified.push (object_id_a);
892 }
893 dynamic_modified.push (object_id_b);
894 satisfied = false;
895 }
896 };
897 if let Some (group) = group_a {
898 constrain_group (group);
899 }
900 if let Some (group) = group_b {
901 constrain_group (group);
902 }
903 iter += 1;
904 if satisfied {
905 log::debug!(iters=iter; "collision velocity constraint satisfied");
906 break
907 }
908 }
909 lerp_objects (objects_dynamic, t_forward);
911 let constrain_position = |
913 objects_dynamic : &mut VecMap <object::Dynamic>,
914 pseudovelocities : &mut VecMap <Vector3 <f64>>,
915 object_id_a : InternalId,
916 object_id_b : InternalId
917 | {
918 let key_a = object_id_a.key();
919 let key_b = object_id_b.key();
920 let index_a = key_a.index();
921 let index_b = key_b.index();
922 let mut object_a = match object_id_a.kind() {
923 object::Kind::Static => Either::Left (objects_static[index_a].clone()),
924 object::Kind::Dynamic => Either::Right (objects_dynamic[index_a].clone()),
925 object::Kind::Nodetect => unreachable!()
926 };
927 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
928 let mut object_b = objects_dynamic[index_b].clone();
929 let mut pseudovelocity_a = if object_id_a.kind() == object::Kind::Dynamic {
930 Some (pseudovelocities[index_a])
931 } else {
932 None
933 };
934 let mut pseudovelocity_b = pseudovelocities[index_b];
935 let (maybe_impulses, proximity) = contact_constrain_position (
936 t_reverse,
937 object_a.as_mut().map_left (|object_static| &*object_static),
938 &mut object_b, pseudovelocity_a.as_mut(), &mut pseudovelocity_b
939 );
940 if maybe_impulses.is_some() {
941 match object_a {
942 Either::Right (object_a) => {
943 objects_dynamic[index_a] = object_a;
944 pseudovelocities[index_a] = pseudovelocity_a.unwrap();
945 }
946 Either::Left (_) => {}
947 }
948 objects_dynamic[index_b] = object_b;
949 pseudovelocities[index_b] = pseudovelocity_b;
950 }
951 (maybe_impulses, proximity)
952 };
953 let mut final_proximities = vec![
954 Proximity {
955 distance: 0.0,
956 half_axis: Vector3::zero(),
957 midpoint: Point::origin(),
958 normal: Unit3::axis_z()
959 };
960 1 + group_a.map_or (0, |group| group.contacts.len()) +
961 group_b.map_or (0, |group| group.contacts.len())
962 ];
963 let mut pseudo_impulse_a = Vector3::zero();
964 let mut pseudo_impulse_b = Vector3::zero();
965 let mut iter = 0;
966 loop {
967 let mut satisfied = true;
968 let mut contact_index = 0;
969 let (maybe_impulses, proximity) = constrain_position (
970 objects_dynamic, &mut self.pseudo_velocities, object_id_a, object_id_b);
971 final_proximities[contact_index] = proximity;
972 contact_index += 1;
973 if let Some (impulses) = maybe_impulses {
974 satisfied = group_a.is_none() && group_b.is_none();
976 pseudo_impulse_a += impulses.pseudo_impulse_a;
977 pseudo_impulse_b += impulses.pseudo_impulse_b;
978 }
979 let mut constrain_group = |group : &contact::Group|
980 for (object_pair, _) in group.contacts.iter() {
981 let (object_id_a, object_id_b) = (*object_pair).into();
982 let (maybe_impulses, proximity) = constrain_position (
983 objects_dynamic, &mut self.pseudo_velocities,
984 object_id_a, object_id_b
985 );
986 final_proximities[contact_index] = proximity;
987 contact_index += 1;
988 if maybe_impulses.is_some() {
989 if object_id_a.kind() == object::Kind::Dynamic {
990 dynamic_modified.push (object_id_a);
991 }
992 dynamic_modified.push (object_id_b);
993 satisfied = false;
994 }
995 };
996 if let Some (group) = group_a {
997 constrain_group (group);
998 }
999 if let Some (group) = group_b {
1000 constrain_group (group);
1001 }
1002 iter += 1;
1003 if satisfied {
1004 log::debug!(iters=iter; "collision position constraint satisfied");
1005 break
1006 }
1007 }
1008 let object_pair = (object_id_a, object_id_b).into();
1012 if !impulse_normal_b.is_zero() || !impulse_tangent_b.is_zero() ||
1013 !pseudo_impulse_b.is_zero()
1014 {
1015 if object_id_a.kind() == object::Kind::Dynamic {
1016 debug_assert!(!impulse_normal_a.is_zero() ||
1017 !impulse_tangent_a.is_zero() || !pseudo_impulse_a.is_zero());
1018 dynamic_modified.push (object_id_a);
1019 }
1020 dynamic_modified.push (object_id_b);
1021 }
1022 self.broad.add_resolved (object_pair);
1023 let mut final_proximities = final_proximities.into_iter();
1024 let collision_final_proximity = final_proximities.next().unwrap();
1025 let mut update_group = |
1028 final_proximities : &mut std::vec::IntoIter <Proximity>,
1029 group_key : contact::group::KeyType
1030 | {
1031 let mut contact_groups = self.persistent.contact_groups.take().unwrap();
1032 let group = &mut contact_groups[group_key as usize];
1033 let mut remove_contacts = vec![];
1034 for (i, proximity) in
1035 final_proximities.take (group.contacts.len()).enumerate()
1036 {
1037 let contact = &mut group.contacts[i];
1038 self.broad.add_resolved (contact.0);
1039 if let Ok (update_contact) = Contact::try_from (proximity) {
1040 contact.1 = update_contact;
1041 } else {
1042 remove_contacts.push (i as u32);
1043 }
1044 }
1045 if !remove_contacts.is_empty() {
1046 self.persistent.remove_contacts (group, remove_contacts.as_slice());
1047 if group.contacts.is_empty() {
1048 let _ = contact_groups.take (group_key as usize).unwrap();
1049 } else {
1050 let partitions = group.partition();
1051 if !partitions.is_empty() {
1052 let _ = contact_groups.take (group_key as usize).unwrap();
1053 for new_group in partitions {
1054 let dynamic_ids = new_group.dynamic_ids();
1055 let group_key = contact_groups.put (new_group)
1056 as contact::group::KeyType;
1057 for dynamic_id in dynamic_ids.into_vec() {
1058 self.persistent.change_dynamic_group_key (dynamic_id, group_key);
1059 }
1060 }
1061 }
1062 }
1063 }
1064 self.persistent.contact_groups = Some (contact_groups);
1065 };
1066 if let Some (group_key) = group_key_a {
1067 update_group (&mut final_proximities, group_key);
1068 }
1069 if let Some (group_key) = group_key_b {
1070 update_group (&mut final_proximities, group_key);
1071 }
1072 if let Ok (contact) = collision_final_proximity.try_into() {
1073 log::trace!(object_pair:?, contact:?; "creating contact @ T==1.0");
1074 self.persistent.add_contact (object_pair, contact);
1075 }
1076 for id in dynamic_modified.iter() {
1079 let i = dynamic_ids.binary_search_by_key (&id, |x| x).unwrap();
1080 let key = id.key();
1081 let index = key.index();
1082 let object = &objects_dynamic[index];
1083 let aabb_discrete = object.aabb_dilated();
1084 let aabb_continuous = Aabb3::union (toi_aabbs[i], aabb_discrete);
1085 self.broad.update_aabb_dynamic_discrete (aabb_discrete, key);
1086 self.broad.update_aabb_dynamic_continuous (aabb_continuous, key);
1087 }
1088 self.pipeline.remove_resolved_dynamic (&dynamic_modified);
1089 self.broad.set_modified (dynamic_modified);
1091 let object_id_a = object_id_a.into();
1093 let object_id_b = object_id_b.into();
1094 event::CollisionResolve {
1095 toi, contact,
1096 object_id_a, object_id_b,
1097 impulse_normal_a, impulse_normal_b,
1098 impulse_tangent_a, impulse_tangent_b,
1099 pseudo_impulse_a, pseudo_impulse_b
1100 }
1101 }
1102
1103 #[inline]
1108 fn broad_overlap_pairs_continuous (&mut self) {
1109 self.broad.overlap_pairs_continuous (
1110 &mut self.pipeline.broad_overlap_pairs, self.pipeline.detect_resolve_iter);
1111 self.pipeline.broad_overlap_pairs.retain (
1113 |pair|{
1114 let (id_a, id_b) = (*pair).into();
1115 let id_a = object::Id::from (id_a);
1116 let id_b = object::Id::from (id_b);
1117 for event::Overlap { object_id_a, object_id_b } in
1118 self.pipeline.overlaps.iter()
1119 {
1120 if object_id_a == &id_a && object_id_b == &id_b {
1121 return false
1122 }
1123 }
1124 true
1125 }
1126 );
1127 log::trace!(overlap_pairs:?=self.pipeline.broad_overlap_pairs;
1128 "broad overlap pairs");
1129 }
1130
1131 fn mid_toi_pairs (&mut self, objects_dynamic : &VecMap <object::Dynamic>) {
1138 use sorted_vec::FindOrInsert;
1139 let last_toi = self.pipeline.resolved_collisions.last()
1140 .map_or (0.0, |collision_resolve| *collision_resolve.toi);
1141 'outer: for object_pair in self.pipeline.broad_overlap_pairs.drain (..) {
1142 let (object_id_a, object_id_b) = object_pair.into();
1143 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
1144 match object_id_a.kind() {
1145 object::Kind::Static => {
1149 let id_static = object::Id::from (object_id_a);
1150 let id_dynamic = object::Id::from (object_id_b);
1151 let key_static = id_static.key;
1152 let key_dynamic = id_dynamic.key;
1153 let _index_static = key_static.index();
1154 let index_dynamic = key_dynamic.index();
1155 if let (Some (static_contact_count), Some (dynamic_group_key)) = (
1156 self.persistent.get_contact_count (object_id_a),
1157 self.persistent.get_group_key (object_id_b)
1158 ) {
1159 debug_assert!(static_contact_count > 0);
1160 let group = self.persistent.get_group (dynamic_group_key).unwrap();
1161 for (pair, _) in group.contacts.iter() {
1162 if *pair == object_pair {
1163 continue 'outer
1164 }
1165 }
1166 }
1167 let dynamic_object = &objects_dynamic[index_dynamic];
1169 let dynamic_velocity = dynamic_object.derivatives.velocity;
1170 let dynamic_pseudovelocity = self.pseudo_velocities[index_dynamic];
1171 let dynamic_velocity_effective = dynamic_velocity + dynamic_pseudovelocity;
1172 let static_aabb = self.broad.get_aabb_static (key_static);
1173 let dynamic_aabb_current = self.broad
1174 .get_aabb_dynamic_discrete (key_dynamic);
1175 let _dynamic_aabb_swept = self.broad
1176 .get_aabb_dynamic_continuous (key_dynamic);
1177 let dynamic_aabb_previous = Aabb3::with_minmax_unchecked (
1178 dynamic_aabb_current.min() - dynamic_velocity_effective,
1179 dynamic_aabb_current.max() - dynamic_velocity_effective);
1180 let dynamic_velocity_effective_reciprocal = dynamic_velocity_effective.recip();
1182 let t_margin_x =
1184 (0.5 * CONTACT_DISTANCE * dynamic_velocity_effective_reciprocal.x).abs();
1185 let t_margin_y =
1186 (0.5 * CONTACT_DISTANCE * dynamic_velocity_effective_reciprocal.y).abs();
1187 let t_margin_z =
1188 (0.5 * CONTACT_DISTANCE * dynamic_velocity_effective_reciprocal.z).abs();
1189
1190 let (interval_start_x, interval_end_x) = if
1191 dynamic_velocity_effective.x == 0.0
1192 {
1193 debug_assert!(
1194 dynamic_aabb_current.max().0.x > static_aabb.min().0.x &&
1195 static_aabb.max().0.x > dynamic_aabb_current.min().0.x);
1196 debug_assert!(
1197 dynamic_aabb_previous.max().0.x > static_aabb.min().0.x &&
1198 static_aabb.max().0.x > dynamic_aabb_previous.min().0.x);
1199 (f64::NEG_INFINITY, f64::INFINITY)
1200 } else if dynamic_velocity_effective.x > 0.0 {
1201 ( (static_aabb.min().0.x - dynamic_aabb_previous.max().0.x)
1204 .mul_add (dynamic_velocity_effective_reciprocal.x, -t_margin_x),
1205 (static_aabb.max().0.x - dynamic_aabb_previous.min().0.x)
1208 .mul_add (dynamic_velocity_effective_reciprocal.x, t_margin_x)
1209 )
1210 } else {
1211 debug_assert!(dynamic_velocity_effective.x < 0.0);
1212 ( (static_aabb.max().0.x - dynamic_aabb_previous.min().0.x)
1215 .mul_add (dynamic_velocity_effective_reciprocal.x, -t_margin_x),
1216 (static_aabb.min().0.x - dynamic_aabb_previous.max().0.x)
1219 .mul_add (dynamic_velocity_effective_reciprocal.x, t_margin_x)
1220 )
1221 };
1222
1223 let (interval_start_y, interval_end_y) = if
1224 dynamic_velocity_effective.y == 0.0
1225 {
1226 debug_assert!(
1227 dynamic_aabb_current.max().0.y > static_aabb.min().0.y &&
1228 static_aabb.max().0.y > dynamic_aabb_current.min().0.y);
1229 debug_assert!(
1230 dynamic_aabb_previous.max().0.y > static_aabb.min().0.y &&
1231 static_aabb.max().0.y > dynamic_aabb_previous.min().0.y);
1232 (f64::NEG_INFINITY, f64::INFINITY)
1233 } else if dynamic_velocity_effective.y > 0.0 {
1234 ( dynamic_velocity_effective_reciprocal.y.mul_add (
1237 static_aabb.min().0.y - dynamic_aabb_previous.max().0.y, -t_margin_y),
1238 dynamic_velocity_effective_reciprocal.y.mul_add (
1241 static_aabb.max().0.y - dynamic_aabb_previous.min().0.y, t_margin_y)
1242 )
1243 } else {
1244 debug_assert!(dynamic_velocity_effective.y < 0.0);
1245 ( dynamic_velocity_effective_reciprocal.y.mul_add (
1248 static_aabb.max().0.y - dynamic_aabb_previous.min().0.y, -t_margin_y),
1249 dynamic_velocity_effective_reciprocal.y.mul_add (
1252 static_aabb.min().0.y - dynamic_aabb_previous.max().0.y, t_margin_y)
1253 )
1254 };
1255
1256 let (interval_start_z, interval_end_z) = if
1257 dynamic_velocity_effective.z == 0.0
1258 {
1259 debug_assert!(
1260 dynamic_aabb_current.max().0.z > static_aabb.min().0.z &&
1261 static_aabb.max().0.z > dynamic_aabb_current.min().0.z);
1262 debug_assert!(
1263 dynamic_aabb_previous.max().0.z > static_aabb.min().0.z &&
1264 static_aabb.max().0.z > dynamic_aabb_previous.min().0.z);
1265 (f64::NEG_INFINITY, f64::INFINITY)
1266 } else if dynamic_velocity_effective.z > 0.0 {
1267 ( dynamic_velocity_effective_reciprocal.z.mul_add (
1270 static_aabb.min().0.z - dynamic_aabb_previous.max().0.z, -t_margin_z),
1271 dynamic_velocity_effective_reciprocal.z.mul_add (
1274 static_aabb.max().0.z - dynamic_aabb_previous.min().0.z, t_margin_z)
1275 )
1276 } else {
1277 debug_assert!(dynamic_velocity_effective.z < 0.0);
1278 ( dynamic_velocity_effective_reciprocal.z.mul_add (
1281 static_aabb.max().0.z - dynamic_aabb_previous.min().0.z, -t_margin_z),
1282 dynamic_velocity_effective_reciprocal.z.mul_add (
1285 static_aabb.min().0.z - dynamic_aabb_previous.max().0.z, t_margin_z)
1286 )
1287 };
1288
1289 let interval = {
1290 let interval_xy =
1291 if interval_start_x < interval_end_y && interval_start_y < interval_end_x {
1292 Some ((
1293 f64::max (interval_start_x, interval_start_y),
1294 f64::min (interval_end_x, interval_end_y)
1295 ))
1296 } else {
1297 None
1298 };
1299 if let Some ((interval_start_xy, interval_end_xy)) = interval_xy {
1300 if interval_start_xy < interval_end_z &&
1301 interval_start_z < interval_end_xy
1302 {
1303 Some ((
1304 f64::max (interval_start_xy, interval_start_z),
1305 f64::min (interval_end_xy, interval_end_z)
1306 ))
1307 } else {
1308 None
1309 }
1310 } else {
1311 None
1312 }
1313 };
1314
1315 if let Some ((interval_start, interval_end)) = interval &&
1316 interval_start < 1.0 && 0.0 < interval_end
1317 {
1318 let mid_toi_pair = (
1319 Normalized::clamp (f64::max (interval_start, last_toi)),
1320 Normalized::clamp (interval_end),
1321 object_pair
1322 );
1323 match self.pipeline.mid_toi_pairs.find_or_insert (Reverse (mid_toi_pair)) {
1324 FindOrInsert::Inserted (_) => {}
1325 FindOrInsert::Found (_) => unreachable!()
1326 }
1327 }
1328 }
1329 object::Kind::Dynamic => {
1333 let key_a = object_id_a.key();
1334 let key_b = object_id_b.key();
1335 let index_a = key_a.index();
1336 let index_b = key_b.index();
1337 if let (Some (group_key_a), Some (group_key_b)) = (
1338 self.persistent.get_group_key (object_id_a),
1339 self.persistent.get_group_key (object_id_b)
1340 ) && group_key_a == group_key_b {
1341 let group = self.persistent.get_group (group_key_a).unwrap();
1342 for (pair, _) in group.contacts.iter() {
1343 if *pair == object_pair {
1344 continue 'outer
1345 }
1346 }
1347 }
1348 let object_a = &objects_dynamic[index_a];
1351 let object_b = &objects_dynamic[index_b];
1352 let velocity_a = object_a.derivatives.velocity;
1353 let velocity_b = object_b.derivatives.velocity;
1354 let pseudovelocity_a = self.pseudo_velocities[key_a.index()];
1355 let pseudovelocity_b = self.pseudo_velocities[key_b.index()];
1356 let velocity_effective_a = velocity_a + pseudovelocity_a;
1357 let velocity_effective_b = velocity_b + pseudovelocity_b;
1358 let velocity_effective_relative =
1359 velocity_effective_a - velocity_effective_b;
1360 let velocity_effective_relative_reciprocal =
1361 velocity_effective_relative.recip();
1362 let aabb_current_a = self.broad.get_aabb_dynamic_discrete (key_a);
1363 let aabb_current_b = self.broad.get_aabb_dynamic_discrete (key_b);
1364 let _aabb_swept_a = self.broad.get_aabb_dynamic_continuous (key_a);
1365 let _aabb_swept_b = self.broad.get_aabb_dynamic_continuous (key_b);
1366 let aabb_previous_a = Aabb3::with_minmax_unchecked (
1367 aabb_current_a.min() - velocity_effective_a,
1368 aabb_current_a.max() - velocity_effective_a);
1369 let aabb_previous_b = Aabb3::with_minmax_unchecked (
1370 aabb_current_b.min() - velocity_effective_b,
1371 aabb_current_b.max() - velocity_effective_b);
1372
1373 let overlap_interval_axis = |axis : Axis3| {
1375 let axis_index = axis as usize;
1376 let t_margin = (0.5 * CONTACT_DISTANCE *
1379 velocity_effective_relative_reciprocal[axis_index]).abs();
1380 let velocity_relative = velocity_effective_relative[axis_index];
1381 let velocity_relative_reciprocal =
1382 velocity_effective_relative_reciprocal[axis_index];
1383 let prev_a_min = aabb_previous_a.min().0[axis_index];
1384 let prev_a_max = aabb_previous_a.max().0[axis_index];
1385 let prev_b_min = aabb_previous_b.min().0[axis_index];
1386 let prev_b_max = aabb_previous_b.max().0[axis_index];
1387 if velocity_relative == 0.0 {
1388 geometry::Interval::with_minmax_unchecked (
1392 f64::NEG_INFINITY, f64::INFINITY)
1393 } else if velocity_relative > 0.0 {
1394 geometry::Interval::with_minmax_unchecked (
1395 (prev_b_min - prev_a_max)
1397 .mul_add (velocity_relative_reciprocal, -t_margin),
1398 (prev_b_max - prev_a_min)
1400 .mul_add (velocity_relative_reciprocal, t_margin)
1401 )
1402 } else {
1403 debug_assert!(velocity_relative < 0.0);
1404 geometry::Interval::with_minmax_unchecked (
1405 (prev_b_max - prev_a_min)
1407 .mul_add (velocity_relative_reciprocal, -t_margin),
1408 (prev_b_min - prev_a_max)
1410 .mul_add (velocity_relative_reciprocal, t_margin)
1411 )
1412 }
1413 };
1414 let overlap_interval_x = overlap_interval_axis (Axis3::X);
1415 let overlap_interval_y = overlap_interval_axis (Axis3::Y);
1416 let overlap_interval_z = overlap_interval_axis (Axis3::Z);
1417
1418 if let Some (interval) = overlap_interval_x.intersection (overlap_interval_y)
1419 .and_then (|overlap_interval_xy|
1420 overlap_interval_xy.intersection (overlap_interval_z))
1421 && interval.min() < 1.0 && 0.0 < interval.max()
1422 {
1423 let mid_toi_pair = (
1424 Normalized::clamp (f64::max (interval.min(), last_toi)),
1425 Normalized::clamp (interval.max()),
1426 object_pair
1427 );
1428 match self.pipeline.mid_toi_pairs.find_or_insert (Reverse (mid_toi_pair)) {
1429 FindOrInsert::Inserted (_) => {}
1430 FindOrInsert::Found (_) => unreachable!()
1431 }
1432 }
1433 }
1434 object::Kind::Nodetect => unreachable!()
1435 }
1436 }
1437
1438 log::trace!(mid_toi_pairs:?=self.pipeline.mid_toi_pairs; "mid TOI pairs");
1439
1440 self.pipeline.broad_overlap_pairs.clear();
1441 }
1442
1443 fn narrow_toi_contacts (&mut self,
1448 objects_static : &VecMap <object::Static>,
1449 objects_dynamic : &VecMap <object::Dynamic>
1450 ) {
1451 use sorted_vec::FindOrInsert;
1452
1453 let narrow_toi_contacts = &mut self.pipeline.narrow_toi_contacts;
1454 while let Some (mid_toi_pair) = self.pipeline.mid_toi_pairs.last().copied() {
1455 let earliest_toi_contact = if !narrow_toi_contacts.is_empty() {
1456 narrow_toi_contacts[0].0.0
1457 } else {
1458 Normalized::clamp (1.0)
1459 };
1460
1461 if mid_toi_pair.0.0 < earliest_toi_contact {
1462 let (mid_toi_start, _mid_toi_end, object_pair) = mid_toi_pair.0;
1463 let (object_id_a, object_id_b) = object_pair.into();
1464 let kind_a = object_id_a.kind();
1465 let kind_b = object_id_b.kind();
1466 match (kind_a, kind_b) {
1467 (object::Kind::Static, object::Kind::Dynamic) => {
1468 let key_static = object_id_a.key();
1469 let key_dynamic = object_id_b.key();
1470 let index_static = key_static.index();
1471 let index_dynamic = key_dynamic.index();
1472 let mut dynamic_object = objects_dynamic[index_dynamic].clone();
1474 let dynamic_velocity = dynamic_object.derivatives.velocity;
1475 let dynamic_pseudovelocity = self.pseudo_velocities[index_dynamic];
1476 let dynamic_velocity_effective = dynamic_velocity - dynamic_pseudovelocity;
1477 let static_object = objects_static[index_static].clone();
1478 let mut narrow_toi = *mid_toi_start;
1479 lerp_object (&mut dynamic_object, dynamic_pseudovelocity, -1.0 + narrow_toi);
1482 let mut t_remaining = 1.0 - narrow_toi;
1483 #[expect(clippy::used_underscore_binding)]
1484 let mut _iter = 0;
1485 loop {
1486 #[cfg(debug_assertions)]
1487 if self.narrow_toi_max_iter_count < _iter {
1488 self.narrow_toi_max_iter_count = _iter;
1489 }
1490 let proximity = Proximity::query (&static_object, &dynamic_object);
1491 if cfg!(debug_assertions) &&
1492 dynamic_object.collidable && static_object.collidable
1493 {
1494 debug_assert!(proximity.distance >= 0.0,
1495 "objects should not be overlapping, distance: {}", proximity.distance);
1496 }
1497 let dynamic_velocity_effective_normal =
1498 dynamic_velocity_effective.dot (-*proximity.normal);
1499 if dynamic_velocity_effective_normal > 0.0 &&
1500 dynamic_object.collidable && static_object.collidable
1501 {
1502 log::trace!(
1504 t=narrow_toi, velocity=dynamic_velocity_effective_normal;
1505 "collision rejected, separating velocity");
1506 break
1507 } else if proximity.distance < CONTACT_DISTANCE {
1508 debug_assert!(dynamic_velocity_effective_normal <= 0.0 ||
1509 !dynamic_object.collidable || !static_object.collidable);
1510 log::trace!(t=narrow_toi, proximity:?; "collision detected");
1512 let contact = Contact { constraint: proximity.into() };
1513 let restitution = dynamic_object.material.restitution *
1514 static_object.material.restitution;
1515 let collision = contact::Colliding { contact, restitution };
1516 let narrow_toi_contact = Reverse ((
1517 Normalized::noisy (narrow_toi), object_pair, collision
1518 ));
1519 match narrow_toi_contacts.find_or_insert (narrow_toi_contact) {
1520 FindOrInsert::Inserted (_) => {}
1521 FindOrInsert::Found (_) => unreachable!()
1522 }
1523 break
1524 } else if dynamic_velocity_effective_normal == 0.0 {
1525 log::trace!(
1526 t=narrow_toi, velocity=dynamic_velocity_effective_normal;
1527 "collision rejected, zero relative velocity and objects not \
1528 in contact");
1529 break
1530 }
1531 let dynamic_velocity_effective_normal_reciprocal =
1532 1.0 / dynamic_velocity_effective_normal;
1533 let toi_axis =
1534 0.5f64.mul_add (-CONTACT_DISTANCE, proximity.distance)
1538 .mul_add (-dynamic_velocity_effective_normal_reciprocal, narrow_toi);
1539 debug_assert!(toi_axis > narrow_toi ||
1540 !dynamic_object.collidable || !static_object.collidable);
1541 if toi_axis > 1.0 || toi_axis < 0.0 {
1542 log::trace!(t=narrow_toi, proximity:?;
1544 "collision rejected, final proximity");
1545 break
1546 }
1547 let t_advance = toi_axis - narrow_toi;
1548 lerp_object (&mut dynamic_object, dynamic_pseudovelocity, t_advance);
1549 narrow_toi = toi_axis;
1550 t_remaining -= t_advance;
1551 debug_assert!(t_remaining > 0.0);
1552 _iter += 1;
1553 }
1554 }
1555
1556 (object::Kind::Dynamic, object::Kind::Dynamic) => {
1557 let key_a = object_id_a.key();
1558 let key_b = object_id_b.key();
1559 let index_a = key_a.index();
1560 let index_b = key_b.index();
1561 let mut object_a = objects_dynamic[index_a].clone();
1564 let mut object_b = objects_dynamic[index_b].clone();
1565 let pseudovelocity_a = self.pseudo_velocities[index_a];
1566 let pseudovelocity_b = self.pseudo_velocities[index_b];
1567 let velocity_a = object_a.derivatives.velocity;
1568 let velocity_b = object_b.derivatives.velocity;
1569 let velocity_effective_a = velocity_a + pseudovelocity_a;
1570 let velocity_effective_b = velocity_b + pseudovelocity_b;
1571 let velocity_effective_relative =
1572 velocity_effective_a - velocity_effective_b;
1573 let mut narrow_toi = *mid_toi_start;
1574 let mut t_remaining = 1.0 - narrow_toi;
1575 lerp_object (&mut object_a, pseudovelocity_a, -1.0 + narrow_toi);
1576 lerp_object (&mut object_b, pseudovelocity_b, -1.0 + narrow_toi);
1577 loop {
1578 debug_assert!(narrow_toi <= 1.0);
1579 debug_assert!(t_remaining >= 0.0);
1580 let proximity = Proximity::query (&object_a, &object_b);
1581 if cfg!(debug_assertions) && object_a.collidable && object_b.collidable {
1582 debug_assert!(proximity.distance >= 0.0);
1583 }
1584 let velocity_effective_relative_normal =
1585 velocity_effective_relative.dot (*proximity.normal);
1586 if velocity_effective_relative_normal > 0.0 &&
1587 object_a.collidable && object_b.collidable
1588 {
1589 log::trace!(
1591 t=narrow_toi, velocity=velocity_effective_relative_normal;
1592 "collision rejected, separating velocity");
1593 break
1594 } else if proximity.distance < CONTACT_DISTANCE {
1595 debug_assert!(velocity_effective_relative_normal <= 0.0 ||
1596 !object_a.collidable || !object_b.collidable);
1597 log::trace!(t=narrow_toi, proximity:?; "collision detected");
1599 let contact = Contact { constraint: proximity.into() };
1600 let restitution =
1601 object_a.material.restitution * object_b.material.restitution;
1602 let collision = contact::Colliding { contact, restitution };
1603 let narrow_toi_contact = Reverse ((
1604 Normalized::noisy (narrow_toi), object_pair, collision
1605 ));
1606 match narrow_toi_contacts.find_or_insert (narrow_toi_contact) {
1607 FindOrInsert::Inserted (_) => {}
1608 FindOrInsert::Found (_) => unreachable!()
1609 }
1610 break
1611 } else if velocity_effective_relative_normal == 0.0 {
1612 log::trace!(
1613 t=narrow_toi, velocity=velocity_effective_relative_normal;
1614 "collision rejected, zero relative velocity and objects not in \
1615 contact");
1616 break
1617 }
1618 let velocity_effective_relative_normal_reciprocal =
1619 1.0 / velocity_effective_relative_normal;
1620 let toi_axis =
1621 0.5f64.mul_add (-CONTACT_DISTANCE, proximity.distance)
1625 .mul_add (-velocity_effective_relative_normal_reciprocal, narrow_toi);
1626 debug_assert!(toi_axis > narrow_toi ||
1627 !object_a.collidable || !object_b.collidable);
1628 if toi_axis > 1.0 || toi_axis < 0.0 {
1629 log::trace!(t=narrow_toi, proximity:?;
1631 "collision rejected, final proximity");
1632 break
1633 }
1634 let t_advance = toi_axis - narrow_toi;
1635 lerp_object (&mut object_a, pseudovelocity_a, t_advance);
1636 lerp_object (&mut object_b, pseudovelocity_b, t_advance);
1637 narrow_toi = toi_axis;
1638 t_remaining -= t_advance;
1639 }
1640 }
1641 _ => unreachable!()
1642 }
1643 self.pipeline.mid_toi_pairs.pop();
1644 } else { break }
1645 }
1646 #[cfg(debug_assertions)]
1647 log::debug!(max_iter_count=self.narrow_toi_max_iter_count;
1648 "narrow TOI max iters");
1649 log::trace!(contacts:?=narrow_toi_contacts; "narrow TOI contacts");
1650 }
1651
1652 #[inline]
1653 fn add_object_static (&mut self,
1654 object : &object::Static,
1655 object_key : object::Key,
1656 ) {
1657 self.broad.add_object_static (object.aabb_dilated(), object_key);
1658 }
1659
1660 #[inline]
1661 fn add_object_dynamic (&mut self,
1662 object : &object::Dynamic,
1663 object_key : object::Key
1664 ) {
1665 let aabb_discrete = object.aabb_dilated();
1666 let aabb_continuous = Aabb3::with_minmax_unchecked (
1667 aabb_discrete.min() - object.derivatives.velocity,
1668 aabb_discrete.max() - object.derivatives.velocity);
1669 self.broad.add_object_dynamic (aabb_discrete, aabb_continuous, object_key);
1673 assert!(self.pseudo_velocities
1674 .insert (object_key.index(), Vector3::zero()).is_none());
1675 }
1676
1677}
1678
1679impl Pipeline {
1680 #[inline]
1681 fn is_empty (&self) -> bool {
1682 self.broad_overlap_pairs.is_empty() &&
1683 self.mid_toi_pairs.is_empty() &&
1684 self.narrow_toi_contacts.is_empty() &&
1685 self.resolved_collisions.is_empty() &&
1686 self.overlaps.is_empty()
1687 }
1688
1689 #[inline]
1701 fn remove_resolved_dynamic (&mut self, resolved : &SortedSet <InternalId>) {
1702 debug_assert!(self.broad_overlap_pairs.is_empty());
1703
1704 let (mut i, mut len);
1705
1706 i = 0;
1708 len = self.mid_toi_pairs.len();
1709 while i < len {
1710 let (_, _, object_pair) = self.mid_toi_pairs[i].0;
1711 let (id_a, id_b) = object_pair.into();
1712 if id_a.kind() == object::Kind::Dynamic && resolved.binary_search (&id_a).is_ok() {
1713 self.mid_toi_pairs.remove_index (i);
1714 len -= 1;
1715 continue
1716 }
1717 debug_assert_eq!(id_b.kind(), object::Kind::Dynamic);
1718 if resolved.binary_search (&id_b).is_ok() {
1719 self.mid_toi_pairs.remove_index (i);
1720 len -= 1;
1721 continue
1722 }
1723 i += 1;
1724 }
1725
1726 i = 0;
1728 len = self.narrow_toi_contacts.len();
1729 while i < len {
1730 let (_, object_pair, _) = self.narrow_toi_contacts[i].clone().0;
1731 let (id_a, id_b) = object_pair.into();
1732 if id_a.kind() == object::Kind::Dynamic && resolved.binary_search (&id_a).is_ok() {
1733 self.narrow_toi_contacts.remove_index (i);
1734 len -= 1;
1735 continue
1736 }
1737 debug_assert_eq!(id_b.kind(), object::Kind::Dynamic);
1738 if resolved.binary_search (&id_b).is_ok() {
1739 self.narrow_toi_contacts.remove_index (i);
1740 len -= 1;
1741 continue
1742 }
1743 i += 1;
1744 }
1745 }
1746}
1747
1748impl ObjectPair {
1749 fn new (id_a : InternalId, id_b : InternalId) -> Self {
1754 debug_assert!(id_a.kind() == object::Kind::Dynamic ||
1755 id_b.kind() == object::Kind::Dynamic);
1756 if id_a < id_b {
1757 ObjectPair (id_a, id_b)
1758 } else {
1759 debug_assert!(id_a > id_b, "overlap ids should not be identical");
1760 ObjectPair (id_b, id_a)
1761 }
1762 }
1763}
1764
1765impl From <(InternalId, InternalId)> for ObjectPair {
1766 fn from ((id_a, id_b) : (InternalId, InternalId)) -> Self {
1767 ObjectPair::new (id_a, id_b)
1768 }
1769}
1770
1771impl InternalId {
1772 #[inline]
1773 fn new_static (key : object::Key) -> Self {
1774 debug_assert!(key.value() < OBJECT_KEY_MAX);
1775 InternalId (key.value())
1776 }
1777 #[inline]
1778 fn new_dynamic (key : object::Key) -> Self {
1779 debug_assert!(key.value() < OBJECT_KEY_MAX);
1780 InternalId (key.value() | INTERNAL_ID_DYNAMIC_BIT)
1781 }
1782 #[inline]
1783 const fn kind (self) -> object::Kind {
1784 match self.0 & INTERNAL_ID_DYNAMIC_BIT > 0 {
1785 true => object::Kind::Dynamic,
1786 false => object::Kind::Static
1787 }
1788 }
1789 #[inline]
1790 fn key (self) -> object::Key {
1791 object::Key::from (self.0 & !INTERNAL_ID_DYNAMIC_BIT)
1792 }
1793}
1794impl From <InternalId> for object::Id {
1795 fn from (id : InternalId) -> Self {
1796 object::Id {
1797 kind: id.kind(),
1798 key: id.key()
1799 }
1800 }
1801}