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().clone();
157 object.position_mut().0 = position +
158 t_relative * object.derivatives().velocity + t_relative * pseudovelocity;
159}
160
161fn contact_constrain_velocity (
162 contact : contact::Contact,
163 restitution : 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 =
178 object_b.derivatives.velocity + pseudovelocity_b;
179 let velocity_effective_relative =
180 velocity_effective_a - velocity_effective_b;
181 let velocity_normal_component =
182 velocity_effective_relative.dot (*contact.constraint.normal());
183 let mut impulses = None;
184 let mut mass_relative_a = 0.0;
185 let mut mass_relative_b = 0.0;
186 if velocity_normal_component < 0.0 {
187 let velocity_normal =
188 velocity_normal_component * *contact.constraint.normal();
189 let impulse_normal = velocity_normal + restitution * velocity_normal;
191 let impulse_normal_magnitude2 = impulse_normal.magnitude_squared();
192 if impulse_normal_magnitude2 < RESTING_VELOCITY * RESTING_VELOCITY {
193 return None
194 }
195 let (impulse_normal_a, impulse_normal_b) = match &mut object_a {
196 Either::Right (object_a) => {
197 let mass_combined = object_a.mass.clone() + object_b.mass.clone();
198 mass_relative_a =
199 object_a.mass.mass() * mass_combined.mass_reciprocal();
200 mass_relative_b =
201 object_b.mass.mass() * mass_combined.mass_reciprocal();
202 let impulse_normal_a = -mass_relative_b * impulse_normal;
203 let impulse_normal_b = mass_relative_a * impulse_normal;
204 object_a.derivatives.velocity += impulse_normal_a;
205 object_b.derivatives.velocity += impulse_normal_b;
206 (impulse_normal_a, impulse_normal_b)
207 }
208 Either::Left (_) => {
209 object_b.derivatives.velocity += impulse_normal;
210 (Vector3::zero(), impulse_normal)
211 }
212 };
213 let (impulse_tangent_a, impulse_tangent_b) = {
215 let velocity_tangent = velocity_effective_relative - velocity_normal;
216 let velocity_tangent_magnitude2 = velocity_tangent.magnitude_squared();
217 if velocity_tangent_magnitude2 > 0.0 {
218 let friction_a = match &object_a {
219 Either::Left (x) => x.material.friction,
220 Either::Right (x) => x.material.friction
221 };
222 let friction_coefficient = friction_a * object_b.material.friction;
223 let impulse_tangent_potential_magnitude2 =
224 friction_coefficient * impulse_normal_magnitude2;
225 let impulse_tangent = if impulse_tangent_potential_magnitude2 <
226 velocity_tangent_magnitude2
227 {
228 (impulse_tangent_potential_magnitude2.sqrt()
229 / velocity_tangent_magnitude2.sqrt()) * velocity_tangent
230 } else {
231 velocity_tangent
232 };
233 match object_a {
234 Either::Right (object_a) => {
235 let impulse_tangent_a = -mass_relative_b * impulse_tangent;
236 let impulse_tangent_b = mass_relative_a * impulse_tangent;
237 object_a.derivatives.velocity += impulse_tangent_a;
238 object_b.derivatives.velocity += impulse_tangent_b;
239 (impulse_tangent_a, impulse_tangent_b)
240 }
241 Either::Left (_) => {
242 object_b.derivatives.velocity += impulse_tangent;
243 (Vector3::zero(), impulse_tangent)
244 }
245 }
246 } else {
247 (Vector3::zero(), Vector3::zero())
248 }
249 };
250 impulses = Some (ContactImpulses {
251 impulse_normal_a, impulse_normal_b,
252 impulse_tangent_a, impulse_tangent_b
253 });
254 }
255 impulses
256}
257
258fn contact_constrain_position (
259 t_reverse : f64,
260 mut object_a : Either <&object::Static, &mut object::Dynamic>,
261 object_b : &mut object::Dynamic,
262 pseudovelocity_a : Option <&mut Vector3 <f64>>,
263 pseudovelocity_b : &mut Vector3 <f64>
264) -> (Option <ContactPostImpulses>, Proximity) {
265 let t_forward = -t_reverse;
266 let mut impulses = None;
267 let mut proximity = match &object_a {
268 Either::Left (object_a) => Proximity::query (*object_a, object_b),
269 Either::Right (object_a) => Proximity::query (*object_a, object_b)
270 };
271 log::trace!(distance=proximity.distance; "post impulse contact @ T==1.0");
272 if proximity.distance < 0.0 {
273 let (pseudo_impulse_a, pseudo_impulse_b) = match &mut object_a {
274 Either::Left (object_a) => {
275 lerp_object (object_b, *pseudovelocity_b, t_reverse);
276 let pseudo_impulse_b = -(2.0 * proximity.half_axis +
277 0.5 * CONTACT_DISTANCE * *proximity.normal) / t_forward;
278 *pseudovelocity_b += pseudo_impulse_b;
279 lerp_object (object_b, *pseudovelocity_b, t_forward);
280 proximity = Proximity::query (*object_a, object_b);
281 (Vector3::zero(), pseudo_impulse_b)
282 }
283 Either::Right (object_a) => {
284 let pseudovelocity_a = pseudovelocity_a.unwrap();
285 lerp_object (*object_a, *pseudovelocity_a, t_reverse);
286 lerp_object (object_b, *pseudovelocity_b, t_reverse);
287 let mass_combined = object_a.mass.clone() + object_b.mass.clone();
288 let mass_relative_a =
289 object_a.mass.mass() * mass_combined.mass_reciprocal();
290 let mass_relative_b =
291 object_b.mass.mass() * mass_combined.mass_reciprocal();
292 let pseudo_impulse = (2.0 * proximity.half_axis +
293 0.5 * CONTACT_DISTANCE * *proximity.normal) / t_forward;
294 let pseudo_impulse_a = mass_relative_b * pseudo_impulse;
295 let pseudo_impulse_b = -mass_relative_a * pseudo_impulse;
296 *pseudovelocity_a += pseudo_impulse_a;
297 *pseudovelocity_b += pseudo_impulse_b;
298 lerp_object (*object_a, *pseudovelocity_a, t_forward);
299 lerp_object (object_b, *pseudovelocity_b, t_forward);
300 proximity = Proximity::query (*object_a, object_b);
301 (pseudo_impulse_a, pseudo_impulse_b)
302 }
303 };
304 log::trace!(distance=proximity.distance;
305 "position corrected distance @ T==1.0");
306 debug_assert!(proximity.distance >= 0.0);
307 if cfg!(debug_assertions) {
308 math::approx::assert_abs_diff_eq!(
309 proximity.distance, 0.5 * CONTACT_DISTANCE, epsilon=0.000000001);
310 }
311 impulses = Some (ContactPostImpulses { pseudo_impulse_a, pseudo_impulse_b });
312 }
313 (impulses, proximity)
314}
315
316impl Collision {
321 pub (crate) fn broad (&self) -> &Broad {
322 &self.broad
323 }
324 pub fn try_add_object_static (&mut self,
331 objects_dynamic : &VecMap <object::Dynamic>,
332 object : &object::Static,
333 key : object::Key
334 ) -> Result <(), Vec <(object::Id, Intersection)>> {
335 let mut intersections = Vec::new();
336 if object.collidable {
337 let aabb_discrete = object.aabb_dilated();
338 let overlaps : Vec <object::Id> = self.broad
339 .overlaps_discrete (aabb_discrete).into_iter().map (|id| id.into())
340 .collect::<Vec <_>>();
341 for object_id in overlaps {
342 let proximity = match object_id.kind {
343 object::Kind::Static => continue, object::Kind::Dynamic => {
345 let object_dynamic = &objects_dynamic[object_id.key.index()];
346 if !object_dynamic.collidable {
347 continue }
349 Proximity::query (object_dynamic, object)
350 }
351 _ => unreachable!()
352 };
353 if let Ok (intersection) = proximity.try_into() {
354 intersections.push ((object_id, intersection));
355 }
356 }
357 }
358 if intersections.is_empty() {
359 self.add_object_static (object, key);
360 Ok (())
361 } else {
362 Err (intersections)
363 }
364 }
365
366 #[inline]
367 pub fn remove_object_static (&mut self, object_key : object::Key) {
368 debug_assert!(self.pipeline.is_empty());
369 let id = InternalId::new_static (object_key);
370 self.broad.remove_object (id);
371 let _ = self.persistent.remove_object (id);
372 }
373
374 pub fn try_add_object_dynamic (&mut self,
382 objects_static : &VecMap <object::Static>,
383 objects_dynamic : &VecMap <object::Dynamic>,
384 object : &object::Dynamic,
385 key : object::Key
386 ) -> Result <(), Vec <(object::Id, Intersection)>> {
387 let mut intersections = Vec::new();
388 if object.collidable {
389 let aabb_discrete = object.aabb_dilated();
390 let overlaps : Vec <object::Id> = self.broad
391 .overlaps_discrete (aabb_discrete).into_iter().map (|id| id.into())
392 .collect::<Vec <_>>();
393 for object_id in overlaps {
394 let proximity = match object_id.kind {
395 object::Kind::Static => {
396 let object_static = &objects_static[object_id.key.index()];
397 if !object_static.collidable {
398 continue }
400 Proximity::query (object_static, object)
401 }
402 object::Kind::Dynamic => {
403 let object_dynamic = &objects_dynamic[object_id.key.index()];
404 if !object_dynamic.collidable {
405 continue }
407 Proximity::query (object_dynamic, object)
408 }
409 _ => unreachable!()
410 };
411 if let Ok (intersection) = proximity.try_into() {
412 intersections.push ((object_id, intersection));
413 }
414 }
415 }
416 if intersections.is_empty() {
417 self.add_object_dynamic (object, key);
418 Ok (())
419 } else {
420 Err (intersections)
421 }
422 }
423
424 #[inline]
425 pub fn remove_object_dynamic (&mut self, key : object::Key) {
426 debug_assert!(self.pipeline.is_empty());
427 let id = InternalId::new_dynamic (key);
428 self.broad.remove_object (id);
429 self.pseudo_velocities.remove (key.index()).unwrap();
430 let _ = self.persistent.remove_object (id);
431 }
432
433 #[inline]
434 pub fn update_object_static (&mut self,
435 object : &object::Static, key : object::Key
436 ) {
437 debug_assert!(self.pipeline.is_empty());
438 self.broad.update_aabb_static (object.aabb_dilated(), key);
439 unimplemented!("TODO: collision detect and resolve any overlaps caused by \
440 updating the static object")
441 }
442
443 #[inline]
444 pub fn update_object_dynamic (&mut self,
445 object : &object::Dynamic, key : object::Key
446 ) {
447 debug_assert!(self.pipeline.is_empty());
448 let aabb = object.aabb_dilated();
449 self.broad.update_aabb_dynamic_discrete (aabb, key);
450 self.broad.update_aabb_dynamic_continuous (aabb, key);
452 log::warn!("TODO: collision detect and resolve any overlaps caused by \
453 updating the dynamic object")
454 }
455
456 pub fn detect_resolve_loop (&mut self,
475 objects_static : &mut VecMap <object::Static>,
476 objects_dynamic : &mut VecMap <object::Dynamic>,
477 step : u64,
478 output : &mut Vec <event::Output>
479 ) {
480 log::trace!(step; "detect/resolve loop");
481
482 debug_assert!(self.pipeline.is_empty());
484 self.pipeline.detect_resolve_iter = 0;
485
486 self.broad.begin_step (objects_dynamic, step);
491
492 loop {
494 log::debug!(iter=self.pipeline.detect_resolve_iter;
495 "detect/resolve loop iteration");
496 self.detect_continuous (objects_static, objects_dynamic);
498 if !self.resolve_collision (objects_static, objects_dynamic) {
501 debug_assert!(self.pipeline.mid_toi_pairs.is_empty());
502 debug_assert!(self.pipeline.narrow_toi_contacts.is_empty());
503 break
504 }
505 self.pipeline.detect_resolve_iter += 1;
506 }
507
508 log::trace!(iters=self.pipeline.detect_resolve_iter+1;
509 "detect/resolve loop complete");
510 #[cfg(debug_assertions)]
511 {
512 if self.detect_resolve_max_iter_count
513 < (self.pipeline.detect_resolve_iter + 1)
514 {
515 #[cfg(feature = "debug_dump")]
516 if self.pipeline.detect_resolve_iter >
517 DEBUG_DUMP_DETECT_RESOLVE_MAX_ITERS
518 {
519 DEBUG_DUMP.store (true, atomic::Ordering::SeqCst);
520 }
521 self.detect_resolve_max_iter_count = self.pipeline.detect_resolve_iter;
522 }
523 log::debug!(max_iter_count=self.detect_resolve_max_iter_count;
524 "detect/resolve loop max iters");
525 }
526
527 for collision_resolve in self.pipeline.resolved_collisions.drain (..) {
529 output.push (collision_resolve.into());
530 }
531 for overlap in self.pipeline.overlaps.drain (..) {
532 output.push (overlap.into());
533 }
534
535 self.persistent.output_contacts (output);
537
538 for (_, pseudovelocity) in self.pseudo_velocities.iter_mut() {
540 *pseudovelocity = Vector3::zero();
541 }
542
543 debug_assert!(self.pipeline.is_empty());
545 }
546
547 pub fn constrain_contact_positions (&mut self,
549 objects_static : &VecMap <object::Static>,
550 objects_dynamic : &mut VecMap <object::Dynamic>
551 ) {
552 let mut remove_groups = vec![];
553 let mut new_groups = vec![];
554 let mut contact_groups = self.persistent.contact_groups.take().unwrap();
555 for (group_index, group) in contact_groups.iter_mut() {
556 log::debug!(group_index, contacts_count=group.contacts.len();
557 "group constrain positions");
558 log::trace!(group_index, contacts:?=group.contacts;
559 "group constrain positions contacts");
560 let mut iter = 0;
561 let mut remove_contacts = vec![];
562 loop {
563 remove_contacts.clear();
564 let mut satisfied = true;
565 for (contact_index, (object_pair, contact)) in
566 group.contacts.iter_mut().enumerate()
567 {
568 let (object_id_a, object_id_b) = (*object_pair).into();
569 let index_a = object_id_a.key().index();
570 let index_b = object_id_b.key().index();
571 let mut object_a = match object_id_a.kind() {
572 object::Kind::Static =>
573 Either::Left (objects_static[index_a].clone()),
574 object::Kind::Dynamic =>
575 Either::Right (objects_dynamic[index_a].clone()),
576 _ => unreachable!()
577 };
578 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
579 let mut object_b = objects_dynamic[index_b].clone();
580 let mut pseudovelocity_a = match object_a {
581 Either::Left (_) => None,
582 Either::Right (_) => Some (self.pseudo_velocities[index_a])
583 };
584 let mut pseudovelocity_b = self.pseudo_velocities[index_b];
585 let (maybe_impulses, proximity) = contact_constrain_position (
586 -1.0,
587 object_a.as_mut().map_left (|object_static| &*object_static),
588 &mut object_b, pseudovelocity_a.as_mut(), &mut pseudovelocity_b
589 );
590 if maybe_impulses.is_some() {
591 satisfied = false;
592 match object_a {
593 Either::Right (object_a) => {
594 objects_dynamic[index_a] = object_a;
595 self.pseudo_velocities[index_a] = pseudovelocity_a.unwrap();
596 }
597 Either::Left (_) => {}
598 }
599 objects_dynamic[index_b] = object_b;
600 self.pseudo_velocities[index_b] = pseudovelocity_b;
601 }
602 if proximity.distance >= CONTACT_DISTANCE {
606 log::debug!(object_pair:?, contact:?, proximity:?;
607 "removing contact @ T==1.0");
608 remove_contacts.push (contact_index as u32);
609 } else {
610 *contact = proximity.try_into().unwrap();
612 }
613 }
614 iter += 1;
615 if satisfied {
616 log::debug!(group_index, iters=iter;
618 "group position constraint satisfied");
619 if !remove_contacts.is_empty() {
620 self.persistent.remove_contacts (group, remove_contacts.as_slice());
621 if group.contacts.is_empty() {
622 remove_groups.push (group_index as contact::group::KeyType);
623 } else {
624 let partitions = group.partition();
625 if !partitions.is_empty() {
626 remove_groups.push (group_index as contact::group::KeyType);
627 new_groups.extend (partitions);
628 }
629 }
630 }
631 break
632 }
633 }
634 }
635 for group_key in remove_groups {
636 let _ = contact_groups.take (group_key as usize).unwrap();
637 }
638 for new_group in new_groups {
639 let dynamic_ids = new_group.dynamic_ids();
640 let group_key = contact_groups.put (new_group) as contact::group::KeyType;
641 for dynamic_id in dynamic_ids.into_vec() {
642 self.persistent.change_dynamic_group_key (dynamic_id, group_key);
643 }
644 }
645 self.persistent.contact_groups = Some (contact_groups);
646 }
647
648 pub fn constrain_contact_velocities (&self,
650 objects_static : &VecMap <object::Static>,
651 objects_dynamic : &mut VecMap <object::Dynamic>
652 ) {
653 for (group_index, group) in self.contact_groups().iter() {
654 log::debug!(group_index, contacts_count=group.contacts.len();
655 "group constrain velocities");
656 log::trace!(group_index, contacts:?=group.contacts;
657 "group constrain velocities contacts");
658 let mut iter = 0;
659 loop {
660 let mut satisfied = true;
661 for (object_pair, contact) in group.contacts.iter() {
662 let (object_id_a, object_id_b) = (*object_pair).into();
663 let index_a = object_id_a.key().index();
664 let index_b = object_id_b.key().index();
665 let mut object_a = match object_id_a.kind() {
666 object::Kind::Static =>
667 Either::Left (objects_static[index_a].clone()),
668 object::Kind::Dynamic =>
669 Either::Right (objects_dynamic[index_a].clone()),
670 _ => unreachable!()
671 };
672 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
673 let mut object_b = objects_dynamic[index_b].clone();
674 if contact_constrain_velocity (
676 contact.clone(), 0.0,
677 object_a.as_mut().map_left (|object_static| &*object_static),
678 &mut object_b, None, Vector3::zero()
679 ).is_some() {
680 match object_a {
681 Either::Right (object_a) => objects_dynamic[index_a] = object_a,
682 Either::Left (_) => {}
683 }
684 objects_dynamic[index_b] = object_b;
685 satisfied = false;
686 }
687 }
688 iter += 1;
689 if satisfied {
690 log::debug!(group_index, iters=iter;
692 "group velocity constraint satisfied");
693 break
694 }
695 }
696 }
697 }
698
699 pub (crate) fn contact_groups (&self) -> &Stash <contact::Group> {
700 self.persistent.contact_groups.as_ref().unwrap()
701 }
702
703 fn detect_continuous (&mut self,
709 objects_static : &VecMap <object::Static>,
710 objects_dynamic : &VecMap <object::Dynamic>
711 ) {
712 self.broad_overlap_pairs_continuous();
714 self.mid_toi_pairs (objects_dynamic);
716 self.narrow_toi_contacts (objects_static, objects_dynamic);
718 }
719
720 fn resolve_collision (&mut self,
730 objects_static : &VecMap <object::Static>,
731 objects_dynamic : &mut VecMap <object::Dynamic>
732 ) -> bool {
733 if let Some (Reverse ((toi, object_pair, contact))) =
734 self.pipeline.narrow_toi_contacts.pop()
735 {
736 let (object_id_a, object_id_b) = object_pair.into();
739 let kind_a = object_id_a.kind();
740 let kind_b = object_id_b.kind();
741 let index_a = object_id_a.key().index();
742 let index_b = object_id_b.key().index();
743 let collidable = {
745 let collidable_a = match kind_a {
746 object::Kind::Static => objects_static[index_a].collidable,
747 object::Kind::Dynamic => objects_dynamic[index_a].collidable,
748 _ => unreachable!()
749 };
750 debug_assert_eq!(kind_b, object::Kind::Dynamic);
751 let collidable_b = objects_dynamic[index_b].collidable;
752 collidable_a && collidable_b
753 };
754 if !collidable {
755 let overlap = event::Overlap {
756 object_id_a: object_id_a.into(),
757 object_id_b: object_id_b.into()
758 };
759 log::debug!(toi=*toi, overlap:?; "nocollide overlap");
760 self.pipeline.overlaps.push (overlap);
761 return true
762 }
763 log::debug!(toi=*toi, object_pair:?=(object_id_a, object_id_b);
764 "resolve collision");
765 let maybe_group_a = self.persistent.get_group_key (object_id_a);
767 let maybe_group_b = {
768 let maybe_group_b = self.persistent.get_group_key (object_id_b);
769 if maybe_group_a == maybe_group_b {
770 None
772 } else {
773 maybe_group_b
774 }
775 };
776 let collision_resolve = self.resolve (objects_static, objects_dynamic,
778 toi, object_id_a, object_id_b, contact.clone(), maybe_group_a,
779 maybe_group_b);
780 log::trace!(collision_resolve:?; "resolved collision");
781 self.pipeline.resolved_collisions.push (collision_resolve);
782 true
783 } else {
784 debug_assert!(self.pipeline.mid_toi_pairs.is_empty());
786 false
787 }
788 }
789
790 #[allow(clippy::too_many_arguments)]
791 fn resolve (
792 &mut self,
793 objects_static : &VecMap <object::Static>,
794 objects_dynamic : &mut VecMap <object::Dynamic>,
795 toi : Normalized <f64>,
796 object_id_a : InternalId,
797 object_id_b : InternalId,
798 contact : contact::Colliding,
799 group_key_a : Option <contact::group::KeyType>,
800 group_key_b : Option <contact::group::KeyType>
801 ) -> event::CollisionResolve {
802 use math::num_traits::Zero;
809 let mut dynamic_ids = SortedSet::new();
810 if object_id_a.kind() == object::Kind::Dynamic {
811 dynamic_ids.push (object_id_a);
812 };
813 dynamic_ids.push (object_id_b);
814 let group_a = group_key_a
815 .map (|group_key| self.persistent.get_group (group_key).unwrap());
816 let group_b = group_key_b
817 .map (|group_key| self.persistent.get_group (group_key).unwrap());
818 group_a.map (|group| dynamic_ids.extend (group.dynamic_ids().into_vec()));
819 group_b.map (|group| dynamic_ids.extend (group.dynamic_ids().into_vec()));
820 let mut dynamic_modified = SortedSet::new();
824 let lerp_objects =
826 |objects_dynamic : &mut VecMap <object::Dynamic>, time_delta|
827 for id in dynamic_ids.iter() {
828 let index = id.key().index();
829 let object = &mut objects_dynamic[index];
830 let pseudovelocity = self.pseudo_velocities[index];
831 lerp_object (object, pseudovelocity, time_delta);
832 };
833 let (t_reverse, t_forward) = {
834 let toi_f64 : f64 = *toi; (-1.0 + toi_f64, 1.0 - toi_f64)
836 };
837 lerp_objects (objects_dynamic, t_reverse);
838 let toi_aabbs = dynamic_ids.iter().map (|id|{
839 let index = id.key().index();
840 objects_dynamic[index].aabb_dilated()
841 }).collect::<Vec <_>>();
842 let constrain_velocity = |
844 objects_dynamic : &mut VecMap <object::Dynamic>,
845 pseudovelocities : &VecMap <Vector3 <f64>>,
846 contact : Contact,
847 restitution : f64,
848 object_id_a : InternalId,
849 object_id_b : InternalId
850 | {
851 let key_a = object_id_a.key();
852 let key_b = object_id_b.key();
853 let index_a = key_a.index();
854 let index_b = key_b.index();
855 let mut object_a = match object_id_a.kind() {
856 object::Kind::Static => Either::Left (objects_static[index_a].clone()),
857 object::Kind::Dynamic => Either::Right (objects_dynamic[index_a].clone()),
858 _ => unreachable!()
859 };
860 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
861 let mut object_b = objects_dynamic[index_b].clone();
862 let pseudovelocity_a = if object_id_a.kind() == object::Kind::Dynamic {
863 Some (pseudovelocities[index_a])
864 } else {
865 None
866 };
867 let pseudovelocity_b = pseudovelocities[index_b];
868 let maybe_impulses = contact_constrain_velocity (
869 contact, restitution,
870 object_a.as_mut().map_left (|object_static| &*object_static),
871 &mut object_b, pseudovelocity_a, pseudovelocity_b
872 );
873 if maybe_impulses.is_some() {
874 match object_a {
875 Either::Right (object_a) => objects_dynamic[index_a] = object_a,
876 Either::Left (_) => {}
877 }
878 objects_dynamic[index_b] = object_b;
879 }
880 maybe_impulses
881 };
882 let mut impulse_normal_a = Vector3::zero();
883 let mut impulse_normal_b = Vector3::zero();
884 let mut impulse_tangent_a = Vector3::zero();
885 let mut impulse_tangent_b = Vector3::zero();
886 let mut iter = 0;
887 loop {
888 let mut satisfied = true;
889 if let Some (impulses) = constrain_velocity (
890 objects_dynamic, &self.pseudo_velocities, contact.contact.clone(),
891 contact.restitution, object_id_a, object_id_b
892 ) {
893 satisfied = group_a.is_none() && group_b.is_none();
895 impulse_normal_a += impulses.impulse_normal_a;
896 impulse_normal_b += impulses.impulse_normal_b;
897 impulse_tangent_a += impulses.impulse_tangent_a;
898 impulse_tangent_b += impulses.impulse_tangent_b;
899 }
900 let mut constrain_group = |group : &contact::Group|
901 for (object_pair, contact) in group.contacts.iter().cloned() {
902 let (object_id_a, object_id_b) = object_pair.into();
903 if constrain_velocity (
904 objects_dynamic, &self.pseudo_velocities, contact, 0.0,
905 object_id_a, object_id_b
906 ).is_some() {
907 if object_id_a.kind() == object::Kind::Dynamic {
908 dynamic_modified.push (object_id_a);
909 }
910 dynamic_modified.push (object_id_b);
911 satisfied = false;
912 }
913 };
914 if let Some (group) = group_a {
915 constrain_group (group);
916 }
917 if let Some (group) = group_b {
918 constrain_group (group);
919 }
920 iter += 1;
921 if satisfied {
922 log::debug!(iters=iter; "collision velocity constraint satisfied");
923 break
924 }
925 }
926 lerp_objects (objects_dynamic, t_forward);
928 let constrain_position = |
930 objects_dynamic : &mut VecMap <object::Dynamic>,
931 pseudovelocities : &mut VecMap <Vector3 <f64>>,
932 object_id_a : InternalId,
933 object_id_b : InternalId
934 | {
935 let key_a = object_id_a.key();
936 let key_b = object_id_b.key();
937 let index_a = key_a.index();
938 let index_b = key_b.index();
939 let mut object_a = match object_id_a.kind() {
940 object::Kind::Static => Either::Left (objects_static[index_a].clone()),
941 object::Kind::Dynamic => Either::Right (objects_dynamic[index_a].clone()),
942 _ => unreachable!()
943 };
944 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
945 let mut object_b = objects_dynamic[index_b].clone();
946 let mut pseudovelocity_a = if object_id_a.kind() == object::Kind::Dynamic {
947 Some (pseudovelocities[index_a])
948 } else {
949 None
950 };
951 let mut pseudovelocity_b = pseudovelocities[index_b];
952 let (maybe_impulses, proximity) = contact_constrain_position (
953 t_reverse,
954 object_a.as_mut().map_left (|object_static| &*object_static),
955 &mut object_b, pseudovelocity_a.as_mut(), &mut pseudovelocity_b
956 );
957 if maybe_impulses.is_some() {
958 match object_a {
959 Either::Right (object_a) => {
960 objects_dynamic[index_a] = object_a;
961 pseudovelocities[index_a] = pseudovelocity_a.unwrap();
962 }
963 Either::Left (_) => {}
964 }
965 objects_dynamic[index_b] = object_b;
966 pseudovelocities[index_b] = pseudovelocity_b;
967 }
968 (maybe_impulses, proximity)
969 };
970 let mut final_proximities = vec![
971 Proximity {
972 distance: 0.0,
973 half_axis: Vector3::zero(),
974 midpoint: Point::origin(),
975 normal: Unit3::axis_z()
976 };
977 1 + group_a.map (|group| group.contacts.len()).unwrap_or (0) +
978 group_b.map (|group| group.contacts.len()).unwrap_or (0)
979 ];
980 let mut pseudo_impulse_a = Vector3::zero();
981 let mut pseudo_impulse_b = Vector3::zero();
982 let mut iter = 0;
983 loop {
984 let mut satisfied = true;
985 let mut contact_index = 0;
986 let (maybe_impulses, proximity) = constrain_position (
987 objects_dynamic, &mut self.pseudo_velocities, object_id_a, object_id_b
988 );
989 final_proximities[contact_index] = proximity;
990 contact_index += 1;
991 if let Some (impulses) = maybe_impulses {
992 satisfied = group_a.is_none() && group_b.is_none();
994 pseudo_impulse_a += impulses.pseudo_impulse_a;
995 pseudo_impulse_b += impulses.pseudo_impulse_b;
996 }
997 let mut constrain_group = |group : &contact::Group|
998 for (object_pair, _) in group.contacts.iter() {
999 let (object_id_a, object_id_b) = (*object_pair).into();
1000 let (maybe_impulses, proximity) = constrain_position (
1001 objects_dynamic, &mut self.pseudo_velocities,
1002 object_id_a, object_id_b
1003 );
1004 final_proximities[contact_index] = proximity;
1005 contact_index += 1;
1006 if maybe_impulses.is_some() {
1007 if object_id_a.kind() == object::Kind::Dynamic {
1008 dynamic_modified.push (object_id_a);
1009 }
1010 dynamic_modified.push (object_id_b);
1011 satisfied = false;
1012 }
1013 };
1014 if let Some (group) = group_a {
1015 constrain_group (group);
1016 }
1017 if let Some (group) = group_b {
1018 constrain_group (group);
1019 }
1020 iter += 1;
1021 if satisfied {
1022 log::debug!(iters=iter; "collision position constraint satisfied");
1023 break
1024 }
1025 }
1026 let object_pair = (object_id_a, object_id_b).into();
1030 if !impulse_normal_b.is_zero() || !impulse_tangent_b.is_zero() ||
1031 !pseudo_impulse_b.is_zero()
1032 {
1033 if object_id_a.kind() == object::Kind::Dynamic {
1034 debug_assert!(!impulse_normal_a.is_zero() ||
1035 !impulse_tangent_a.is_zero() || !pseudo_impulse_a.is_zero());
1036 dynamic_modified.push (object_id_a);
1037 }
1038 dynamic_modified.push (object_id_b);
1039 }
1040 self.broad.add_resolved (object_pair);
1041 let mut final_proximities = final_proximities.into_iter();
1042 let collision_final_proximity = final_proximities.next().unwrap();
1043 let mut update_group = |
1046 final_proximities : &mut std::vec::IntoIter <Proximity>,
1047 group_key : contact::group::KeyType
1048 | {
1049 let mut contact_groups = self.persistent.contact_groups.take().unwrap();
1050 let group = &mut contact_groups[group_key as usize];
1051 let mut remove_contacts = vec![];
1052 for (i, proximity) in
1053 final_proximities.take (group.contacts.len()).enumerate()
1054 {
1055 let contact = &mut group.contacts[i];
1056 self.broad.add_resolved (contact.0);
1057 if let Ok (update_contact) = Contact::try_from (proximity) {
1058 contact.1 = update_contact;
1059 } else {
1060 remove_contacts.push (i as u32);
1061 }
1062 }
1063 if !remove_contacts.is_empty() {
1064 self.persistent.remove_contacts (group, remove_contacts.as_slice());
1065 if group.contacts.is_empty() {
1066 let _ = contact_groups.take (group_key as usize).unwrap();
1067 } else {
1068 let partitions = group.partition();
1069 if !partitions.is_empty() {
1070 let _ = contact_groups.take (group_key as usize).unwrap();
1071 for new_group in partitions {
1072 let dynamic_ids = new_group.dynamic_ids();
1073 let group_key = contact_groups.put (new_group)
1074 as contact::group::KeyType;
1075 for dynamic_id in dynamic_ids.into_vec() {
1076 self.persistent.change_dynamic_group_key (dynamic_id, group_key);
1077 }
1078 }
1079 }
1080 }
1081 }
1082 self.persistent.contact_groups = Some (contact_groups);
1083 };
1084 if let Some (group_key) = group_key_a {
1085 update_group (&mut final_proximities, group_key);
1086 }
1087 if let Some (group_key) = group_key_b {
1088 update_group (&mut final_proximities, group_key);
1089 }
1090 if let Ok (contact) = collision_final_proximity.try_into() {
1091 log::trace!(object_pair:?, contact:?; "creating contact @ T==1.0");
1092 self.persistent.add_contact (object_pair, contact);
1093 }
1094 for id in dynamic_modified.iter() {
1097 let i = dynamic_ids.binary_search_by_key (&id, |x| x).unwrap();
1098 let key = id.key();
1099 let index = key.index();
1100 let object = &objects_dynamic[index];
1101 let aabb_discrete = object.aabb_dilated();
1102 let aabb_continuous = Aabb3::union (&toi_aabbs[i], &aabb_discrete);
1103 self.broad.update_aabb_dynamic_discrete (aabb_discrete, key);
1104 self.broad.update_aabb_dynamic_continuous (aabb_continuous, key);
1105 }
1106 self.pipeline.remove_resolved_dynamic (&dynamic_modified);
1107 self.broad.set_modified (dynamic_modified);
1109 let object_id_a = object_id_a.into();
1111 let object_id_b = object_id_b.into();
1112 event::CollisionResolve {
1113 toi, contact,
1114 object_id_a, object_id_b,
1115 impulse_normal_a, impulse_normal_b,
1116 impulse_tangent_a, impulse_tangent_b,
1117 pseudo_impulse_a, pseudo_impulse_b
1118 }
1119 }
1120
1121 #[inline]
1126 fn broad_overlap_pairs_continuous (&mut self) {
1127 self.broad.overlap_pairs_continuous (
1128 &mut self.pipeline.broad_overlap_pairs, self.pipeline.detect_resolve_iter);
1129 self.pipeline.broad_overlap_pairs.retain (
1131 |pair|{
1132 let (id_a, id_b) = (*pair).into();
1133 let id_a = object::Id::from (id_a);
1134 let id_b = object::Id::from (id_b);
1135 for event::Overlap { object_id_a, object_id_b } in
1136 self.pipeline.overlaps.iter()
1137 {
1138 if object_id_a == &id_a && object_id_b == &id_b {
1139 return false
1140 }
1141 }
1142 true
1143 }
1144 );
1145 log::trace!(overlap_pairs:?=self.pipeline.broad_overlap_pairs;
1146 "broad overlap pairs");
1147 }
1148
1149 fn mid_toi_pairs (&mut self, objects_dynamic : &VecMap <object::Dynamic>) {
1156 use sorted_vec::FindOrInsert;
1157 let last_toi = self.pipeline.resolved_collisions.last()
1158 .map_or (0.0, |collision_resolve| *collision_resolve.toi);
1159 'outer: for object_pair in self.pipeline.broad_overlap_pairs.drain (..) {
1160 let (object_id_a, object_id_b) = object_pair.into();
1161 debug_assert_eq!(object_id_b.kind(), object::Kind::Dynamic);
1162 match object_id_a.kind() {
1163 object::Kind::Static => {
1167 let id_static = object::Id::from (object_id_a);
1168 let id_dynamic = object::Id::from (object_id_b);
1169 let key_static = id_static.key;
1170 let key_dynamic = id_dynamic.key;
1171 let _index_static = key_static.index();
1172 let index_dynamic = key_dynamic.index();
1173 if let (Some (static_contact_count), Some (dynamic_group_key)) = (
1174 self.persistent.get_contact_count (object_id_a),
1175 self.persistent.get_group_key (object_id_b)
1176 ) {
1177 debug_assert!(static_contact_count > 0);
1178 let group = self.persistent.get_group (dynamic_group_key).unwrap();
1179 for (pair, _) in group.contacts.iter() {
1180 if *pair == object_pair {
1181 continue 'outer
1182 }
1183 }
1184 }
1185 let dynamic_object = &objects_dynamic[index_dynamic];
1187 let dynamic_velocity = dynamic_object.derivatives.velocity;
1188 let dynamic_pseudovelocity = self.pseudo_velocities[index_dynamic];
1189 let dynamic_velocity_effective = dynamic_velocity + dynamic_pseudovelocity;
1190 let static_aabb = self.broad.get_aabb_static (key_static);
1191 let dynamic_aabb_current = self.broad
1192 .get_aabb_dynamic_discrete (key_dynamic);
1193 let _dynamic_aabb_swept = self.broad
1194 .get_aabb_dynamic_continuous (key_dynamic);
1195 let dynamic_aabb_previous = Aabb3::with_minmax (
1196 dynamic_aabb_current.min() - dynamic_velocity_effective,
1197 dynamic_aabb_current.max() - dynamic_velocity_effective);
1198 let dynamic_velocity_effective_reciprocal =
1200 dynamic_velocity_effective.recip();
1201 let t_margin_x =
1203 (0.5 * CONTACT_DISTANCE * dynamic_velocity_effective_reciprocal.x)
1204 .abs();
1205 let t_margin_y =
1206 (0.5 * CONTACT_DISTANCE * dynamic_velocity_effective_reciprocal.y)
1207 .abs();
1208 let t_margin_z =
1209 (0.5 * CONTACT_DISTANCE * dynamic_velocity_effective_reciprocal.z)
1210 .abs();
1211
1212 let (interval_start_x, interval_end_x) = if
1213 dynamic_velocity_effective.x == 0.0
1214 {
1215 debug_assert!(
1216 dynamic_aabb_current.max().0.x > static_aabb.min().0.x &&
1217 static_aabb.max().0.x > dynamic_aabb_current.min().0.x);
1218 debug_assert!(
1219 dynamic_aabb_previous.max().0.x > static_aabb.min().0.x &&
1220 static_aabb.max().0.x > dynamic_aabb_previous.min().0.x);
1221 (f64::NEG_INFINITY, f64::INFINITY)
1222 } else if dynamic_velocity_effective.x > 0.0 {
1223 ( (static_aabb.min().0.x - dynamic_aabb_previous.max().0.x) *
1224 dynamic_velocity_effective_reciprocal.x - t_margin_x,
1225 (static_aabb.max().0.x - dynamic_aabb_previous.min().0.x) *
1226 dynamic_velocity_effective_reciprocal.x + t_margin_x
1227 )
1228 } else {
1229 debug_assert!(dynamic_velocity_effective.x < 0.0);
1230 ( (static_aabb.max().0.x - dynamic_aabb_previous.min().0.x) *
1231 dynamic_velocity_effective_reciprocal.x - t_margin_x,
1232 (static_aabb.min().0.x - dynamic_aabb_previous.max().0.x) *
1233 dynamic_velocity_effective_reciprocal.x + t_margin_x
1234 )
1235 };
1236
1237 let (interval_start_y, interval_end_y) = if
1238 dynamic_velocity_effective.y == 0.0
1239 {
1240 debug_assert!(
1241 dynamic_aabb_current.max().0.y > static_aabb.min().0.y &&
1242 static_aabb.max().0.y > dynamic_aabb_current.min().0.y);
1243 debug_assert!(
1244 dynamic_aabb_previous.max().0.y > static_aabb.min().0.y &&
1245 static_aabb.max().0.y > dynamic_aabb_previous.min().0.y);
1246 (f64::NEG_INFINITY, f64::INFINITY)
1247 } else if dynamic_velocity_effective.y > 0.0 {
1248 ( dynamic_velocity_effective_reciprocal.y *
1249 (static_aabb.min().0.y - dynamic_aabb_previous.max().0.y)
1250 - t_margin_y,
1251 dynamic_velocity_effective_reciprocal.y *
1252 (static_aabb.max().0.y - dynamic_aabb_previous.min().0.y)
1253 + t_margin_y
1254 )
1255 } else {
1256 debug_assert!(dynamic_velocity_effective.y < 0.0);
1257 ( dynamic_velocity_effective_reciprocal.y *
1258 (static_aabb.max().0.y - dynamic_aabb_previous.min().0.y)
1259 - t_margin_y,
1260 dynamic_velocity_effective_reciprocal.y *
1261 (static_aabb.min().0.y - dynamic_aabb_previous.max().0.y)
1262 + t_margin_y
1263 )
1264 };
1265
1266 let (interval_start_z, interval_end_z) = if
1267 dynamic_velocity_effective.z == 0.0
1268 {
1269 debug_assert!(
1270 dynamic_aabb_current.max().0.z > static_aabb.min().0.z &&
1271 static_aabb.max().0.z > dynamic_aabb_current.min().0.z);
1272 debug_assert!(
1273 dynamic_aabb_previous.max().0.z > static_aabb.min().0.z &&
1274 static_aabb.max().0.z > dynamic_aabb_previous.min().0.z);
1275 (f64::NEG_INFINITY, f64::INFINITY)
1276 } else if dynamic_velocity_effective.z > 0.0 {
1277 ( dynamic_velocity_effective_reciprocal.z *
1278 (static_aabb.min().0.z - dynamic_aabb_previous.max().0.z)
1279 - t_margin_z,
1280 dynamic_velocity_effective_reciprocal.z *
1281 (static_aabb.max().0.z - dynamic_aabb_previous.min().0.z)
1282 + t_margin_z
1283 )
1284 } else {
1285 debug_assert!(dynamic_velocity_effective.z < 0.0);
1286 ( dynamic_velocity_effective_reciprocal.z *
1287 (static_aabb.max().0.z - dynamic_aabb_previous.min().0.z)
1288 - t_margin_z,
1289 dynamic_velocity_effective_reciprocal.z *
1290 (static_aabb.min().0.z - dynamic_aabb_previous.max().0.z)
1291 + t_margin_z
1292 )
1293 };
1294
1295 #[allow(clippy::collapsible_if)]
1297 if let Some ((interval_start, interval_end)) =
1298 if let Some ((interval_start_xy, interval_end_xy)) =
1299 if interval_start_x < interval_end_y &&
1300 interval_start_y < interval_end_x
1301 {
1302 Some ((
1303 f64::max (interval_start_x, interval_start_y),
1304 f64::min (interval_end_x, interval_end_y)
1305 ))
1306 } else {
1307 None
1308 }
1309 {
1310 if interval_start_xy < interval_end_z &&
1311 interval_start_z < interval_end_xy
1312 {
1313 Some ((
1314 f64::max (interval_start_xy, interval_start_z),
1315 f64::min (interval_end_xy, interval_end_z)
1316 ))
1317 } else {
1318 None
1319 }
1320 } else {
1321 None
1322 }
1323 {
1324 if interval_start < 1.0 && 0.0 < interval_end {
1325 let mid_toi_pair = (
1326 Normalized::clamp (f64::max (interval_start, last_toi)),
1327 Normalized::clamp (interval_end),
1328 object_pair
1329 );
1330 match self.pipeline.mid_toi_pairs
1331 .find_or_insert (Reverse (mid_toi_pair))
1332 {
1333 FindOrInsert::Inserted (_) => {}
1334 FindOrInsert::Found (_) => unreachable!()
1335 }
1336 }
1337 }
1338 }
1339 object::Kind::Dynamic => {
1343 let key_a = object_id_a.key();
1344 let key_b = object_id_b.key();
1345 let index_a = key_a.index();
1346 let index_b = key_b.index();
1347 if let (Some (group_key_a), Some (group_key_b)) = (
1348 self.persistent.get_group_key (object_id_a),
1349 self.persistent.get_group_key (object_id_b)
1350 ) && group_key_a == group_key_b {
1351 let group = self.persistent.get_group (group_key_a).unwrap();
1352 for (pair, _) in group.contacts.iter() {
1353 if *pair == object_pair {
1354 continue 'outer
1355 }
1356 }
1357 }
1358 let object_a = &objects_dynamic[index_a];
1361 let object_b = &objects_dynamic[index_b];
1362 let velocity_a = object_a.derivatives.velocity;
1363 let velocity_b = object_b.derivatives.velocity;
1364 let pseudovelocity_a = self.pseudo_velocities[key_a.index()];
1365 let pseudovelocity_b = self.pseudo_velocities[key_b.index()];
1366 let velocity_effective_a = velocity_a + pseudovelocity_a;
1367 let velocity_effective_b = velocity_b + pseudovelocity_b;
1368 let velocity_effective_relative =
1369 velocity_effective_a - velocity_effective_b;
1370 let velocity_effective_relative_reciprocal =
1371 velocity_effective_relative.recip();
1372 let aabb_current_a = self.broad.get_aabb_dynamic_discrete (key_a);
1373 let aabb_current_b = self.broad.get_aabb_dynamic_discrete (key_b);
1374 let _aabb_swept_a = self.broad.get_aabb_dynamic_continuous (key_a);
1375 let _aabb_swept_b = self.broad.get_aabb_dynamic_continuous (key_b);
1376 let aabb_previous_a = Aabb3::with_minmax (
1377 aabb_current_a.min() - velocity_effective_a,
1378 aabb_current_a.max() - velocity_effective_a);
1379 let aabb_previous_b = Aabb3::with_minmax (
1380 aabb_current_b.min() - velocity_effective_b,
1381 aabb_current_b.max() - velocity_effective_b);
1382
1383 let overlap_interval_axis = |axis : Axis3| {
1385 let axis_index = axis as usize;
1386 let t_margin = (0.5 * CONTACT_DISTANCE *
1389 velocity_effective_relative_reciprocal[axis_index]).abs();
1390 let velocity_relative = velocity_effective_relative[axis_index];
1391 let velocity_relative_reciprocal =
1392 velocity_effective_relative_reciprocal[axis_index];
1393 let prev_a_min = aabb_previous_a.min().0[axis_index];
1394 let prev_a_max = aabb_previous_a.max().0[axis_index];
1395 let prev_b_min = aabb_previous_b.min().0[axis_index];
1396 let prev_b_max = aabb_previous_b.max().0[axis_index];
1397 if velocity_relative == 0.0 {
1398 geometry::Interval::with_minmax (f64::NEG_INFINITY, f64::INFINITY)
1402 } else if velocity_relative > 0.0 {
1403 geometry::Interval::with_minmax (
1404 (prev_b_min - prev_a_max) * velocity_relative_reciprocal -
1405 t_margin,
1406 (prev_b_max - prev_a_min) * velocity_relative_reciprocal +
1407 t_margin
1408 )
1409 } else {
1410 debug_assert!(velocity_relative < 0.0);
1411 geometry::Interval::with_minmax (
1412 (prev_b_max - prev_a_min) * velocity_relative_reciprocal -
1413 t_margin,
1414 (prev_b_min - prev_a_max) * velocity_relative_reciprocal +
1415 t_margin
1416 )
1417 }
1418 };
1419 let overlap_interval_x = overlap_interval_axis (Axis3::X);
1420 let overlap_interval_y = overlap_interval_axis (Axis3::Y);
1421 let overlap_interval_z = overlap_interval_axis (Axis3::Z);
1422
1423 if let Some (interval) = overlap_interval_x
1424 .intersection (overlap_interval_y).and_then (|overlap_interval_xy|
1425 overlap_interval_xy.intersection (overlap_interval_z))
1426 && interval.min() < 1.0 && 0.0 < interval.max()
1427 {
1428 let mid_toi_pair = (
1429 Normalized::clamp (f64::max (interval.min(), last_toi)),
1430 Normalized::clamp (interval.max()),
1431 object_pair
1432 );
1433 match self.pipeline.mid_toi_pairs .find_or_insert (Reverse (mid_toi_pair)) {
1434 FindOrInsert::Inserted (_) => {}
1435 FindOrInsert::Found (_) => unreachable!()
1436 }
1437 }
1438 }
1439 _ => unreachable!()
1440 }
1441 }
1442
1443 log::trace!(mid_toi_pairs:?=self.pipeline.mid_toi_pairs; "mid TOI pairs");
1444
1445 self.pipeline.broad_overlap_pairs.clear();
1446 }
1447
1448 fn narrow_toi_contacts (&mut self,
1453 objects_static : &VecMap <object::Static>,
1454 objects_dynamic : &VecMap <object::Dynamic>
1455 ) {
1456 use sorted_vec::FindOrInsert;
1457
1458 let narrow_toi_contacts = &mut self.pipeline.narrow_toi_contacts;
1459 while let Some (mid_toi_pair) = self.pipeline.mid_toi_pairs.last().cloned() {
1460 let earliest_toi_contact = if !narrow_toi_contacts.is_empty() {
1461 narrow_toi_contacts[0].0.0
1462 } else {
1463 Normalized::clamp (1.0)
1464 };
1465
1466 if mid_toi_pair.0.0 < earliest_toi_contact {
1467 let (mid_toi_start, _mid_toi_end, object_pair) =
1468 mid_toi_pair.0;
1469 let (object_id_a, object_id_b) = object_pair.into();
1470 let kind_a = object_id_a.kind();
1471 let kind_b = object_id_b.kind();
1472 match (kind_a, kind_b) {
1473 (object::Kind::Static, object::Kind::Dynamic) => {
1474 let key_static = object_id_a.key();
1475 let key_dynamic = object_id_b.key();
1476 let index_static = key_static.index();
1477 let index_dynamic = key_dynamic.index();
1478 let mut dynamic_object = objects_dynamic[index_dynamic].clone();
1480 let dynamic_velocity = dynamic_object.derivatives.velocity;
1481 let dynamic_pseudovelocity = self.pseudo_velocities[index_dynamic];
1482 let dynamic_velocity_effective =
1483 dynamic_velocity - dynamic_pseudovelocity;
1484 let static_object = objects_static[index_static].clone();
1485 let mut narrow_toi = *mid_toi_start;
1486 lerp_object (&mut dynamic_object, dynamic_pseudovelocity,
1489 -1.0 + narrow_toi);
1490 let mut t_remaining = 1.0 - narrow_toi;
1491 #[allow(unused_variables)]
1492 let mut iter = 0;
1493 loop {
1494 #[cfg(debug_assertions)]
1495 if self.narrow_toi_max_iter_count < iter {
1496 self.narrow_toi_max_iter_count = iter;
1497 }
1498 let proximity = Proximity::query (&static_object, &dynamic_object);
1499 if cfg!(debug_assertions) &&
1500 dynamic_object.collidable && static_object.collidable
1501 {
1502 debug_assert!(proximity.distance >= 0.0);
1503 }
1504 let dynamic_velocity_effective_normal =
1505 dynamic_velocity_effective.dot (-*proximity.normal);
1506 if dynamic_velocity_effective_normal > 0.0 &&
1507 dynamic_object.collidable && static_object.collidable
1508 {
1509 log::trace!(
1511 t=narrow_toi, velocity=dynamic_velocity_effective_normal;
1512 "collision rejected, separating velocity");
1513 break
1514 } else if proximity.distance < CONTACT_DISTANCE {
1515 debug_assert!(dynamic_velocity_effective_normal <= 0.0 ||
1516 !dynamic_object.collidable || !static_object.collidable);
1517 log::trace!(t=narrow_toi, proximity:?; "collision detected");
1519 let contact = Contact { constraint: proximity.into() };
1520 let restitution = dynamic_object.material.restitution *
1521 static_object.material.restitution;
1522 let collision = contact::Colliding { contact, restitution };
1523 let narrow_toi_contact = Reverse ((
1524 Normalized::noisy (narrow_toi), object_pair, collision
1525 ));
1526 match narrow_toi_contacts.find_or_insert (narrow_toi_contact) {
1527 FindOrInsert::Inserted (_) => {}
1528 FindOrInsert::Found (_) => unreachable!()
1529 }
1530 break
1531 } else if dynamic_velocity_effective_normal == 0.0 {
1532 log::trace!(
1533 t=narrow_toi, velocity=dynamic_velocity_effective_normal;
1534 "collision rejected, zero relative velocity and objects not \
1535 in contact");
1536 break
1537 }
1538 let dynamic_velocity_effective_normal_reciprocal =
1539 1.0 / dynamic_velocity_effective_normal;
1540 let toi_axis = narrow_toi +
1541 (proximity.distance - 0.5 * CONTACT_DISTANCE) *
1542 (-dynamic_velocity_effective_normal_reciprocal);
1543 debug_assert!(toi_axis > narrow_toi ||
1544 !dynamic_object.collidable || !static_object.collidable);
1545 if toi_axis > 1.0 || toi_axis < 0.0 {
1546 log::trace!(t=narrow_toi, proximity:?;
1548 "collision rejected, final proximity");
1549 break
1550 }
1551 let t_advance = toi_axis - narrow_toi;
1552 lerp_object (&mut dynamic_object, dynamic_pseudovelocity, t_advance);
1553 narrow_toi = toi_axis;
1554 t_remaining -= t_advance;
1555 debug_assert!(t_remaining > 0.0);
1556 iter += 1;
1557 }
1558 }
1559
1560 (object::Kind::Dynamic, object::Kind::Dynamic) => {
1561 let key_a = object_id_a.key();
1562 let key_b = object_id_b.key();
1563 let index_a = key_a.index();
1564 let index_b = key_b.index();
1565 let mut object_a = objects_dynamic[index_a].clone();
1568 let mut object_b = objects_dynamic[index_b].clone();
1569 let pseudovelocity_a = self.pseudo_velocities[index_a];
1570 let pseudovelocity_b = self.pseudo_velocities[index_b];
1571 let velocity_a = object_a.derivatives.velocity;
1572 let velocity_b = object_b.derivatives.velocity;
1573 let velocity_effective_a = velocity_a + pseudovelocity_a;
1574 let velocity_effective_b = velocity_b + pseudovelocity_b;
1575 let velocity_effective_relative =
1576 velocity_effective_a - velocity_effective_b;
1577 let mut narrow_toi = *mid_toi_start;
1578 let mut t_remaining = 1.0 - narrow_toi;
1579 lerp_object (&mut object_a, pseudovelocity_a, -1.0 + narrow_toi);
1580 lerp_object (&mut object_b, pseudovelocity_b, -1.0 + narrow_toi);
1581 loop {
1582 debug_assert!(narrow_toi <= 1.0);
1583 debug_assert!(t_remaining >= 0.0);
1584 let proximity = Proximity::query (&object_a, &object_b);
1585 if cfg!(debug_assertions) && object_a.collidable && object_b.collidable {
1586 debug_assert!(proximity.distance >= 0.0);
1587 }
1588 let velocity_effective_relative_normal =
1589 velocity_effective_relative.dot (*proximity.normal);
1590 if velocity_effective_relative_normal > 0.0 &&
1591 object_a.collidable && object_b.collidable
1592 {
1593 log::trace!(
1595 t=narrow_toi, velocity=velocity_effective_relative_normal;
1596 "collision rejected, separating velocity");
1597 break
1598 } else if proximity.distance < CONTACT_DISTANCE {
1599 debug_assert!(velocity_effective_relative_normal <= 0.0 ||
1600 !object_a.collidable || !object_b.collidable);
1601 log::trace!(t=narrow_toi, proximity:?; "collision detected");
1603 let contact = Contact { constraint: proximity.into() };
1604 let restitution =
1605 object_a.material.restitution * object_b.material.restitution;
1606 let collision = contact::Colliding { contact, restitution };
1607 let narrow_toi_contact = Reverse ((
1608 Normalized::noisy (narrow_toi), object_pair, collision
1609 ));
1610 match narrow_toi_contacts.find_or_insert (narrow_toi_contact) {
1611 FindOrInsert::Inserted (_) => {}
1612 FindOrInsert::Found (_) => unreachable!()
1613 }
1614 break
1615 } else if velocity_effective_relative_normal == 0.0 {
1616 log::trace!(
1617 t=narrow_toi, velocity=velocity_effective_relative_normal;
1618 "collision rejected, zero relative velocity and objects not \
1619 in contact");
1620 break
1621 }
1622 let velocity_effective_relative_normal_reciprocal =
1623 1.0 / velocity_effective_relative_normal;
1624 let toi_axis = narrow_toi +
1625 (proximity.distance - 0.5 * CONTACT_DISTANCE) *
1626 (-velocity_effective_relative_normal_reciprocal);
1627 debug_assert!(toi_axis > narrow_toi ||
1628 !object_a.collidable || !object_b.collidable);
1629 if toi_axis > 1.0 || toi_axis < 0.0 {
1630 log::trace!(t=narrow_toi, proximity:?;
1632 "collision rejected, final proximity");
1633 break
1634 }
1635 let t_advance = toi_axis - narrow_toi;
1636 lerp_object (&mut object_a, pseudovelocity_a, t_advance);
1637 lerp_object (&mut object_b, pseudovelocity_b, t_advance);
1638 narrow_toi = toi_axis;
1639 t_remaining -= t_advance;
1640 }
1641 }
1642 _ => unreachable!()
1643 }
1644 self.pipeline.mid_toi_pairs.pop();
1645 } else { break }
1646 }
1647 #[cfg(debug_assertions)]
1648 log::debug!(max_iter_count=self.narrow_toi_max_iter_count;
1649 "narrow TOI max iters");
1650 log::trace!(contacts:?=narrow_toi_contacts; "narrow TOI contacts");
1651 }
1652
1653 #[inline]
1654 fn add_object_static (&mut self,
1655 object : &object::Static,
1656 object_key : object::Key,
1657 ) {
1658 self.broad.add_object_static (object.aabb_dilated(), object_key);
1659 }
1660
1661 #[inline]
1662 fn add_object_dynamic (&mut self,
1663 object : &object::Dynamic,
1664 object_key : object::Key
1665 ) {
1666 let aabb_discrete = object.aabb_dilated();
1667 let aabb_continuous = Aabb3::with_minmax (
1668 aabb_discrete.min() - object.derivatives.velocity,
1669 aabb_discrete.max() - object.derivatives.velocity);
1670 self.broad.add_object_dynamic (aabb_discrete, aabb_continuous, object_key);
1674 assert!(self.pseudo_velocities
1675 .insert (object_key.index(), Vector3::zero()).is_none());
1676 }
1677
1678}
1679
1680impl Pipeline {
1681 #[inline]
1682 pub fn is_empty (&self) -> bool {
1683 self.broad_overlap_pairs.is_empty() &&
1684 self.mid_toi_pairs.is_empty() &&
1685 self.narrow_toi_contacts.is_empty() &&
1686 self.resolved_collisions.is_empty() &&
1687 self.overlaps.is_empty()
1688 }
1689
1690 #[inline]
1702 pub fn remove_resolved_dynamic (&mut self, resolved : &SortedSet <InternalId>) {
1703 debug_assert!(self.broad_overlap_pairs.is_empty());
1704
1705 let (mut i, mut len);
1706
1707 i = 0;
1709 len = self.mid_toi_pairs.len();
1710 while i < len {
1711 let (_, _, object_pair) = self.mid_toi_pairs[i].0;
1712 let (id_a, id_b) = object_pair.into();
1713 if id_a.kind() == object::Kind::Dynamic && resolved.binary_search (&id_a).is_ok() {
1714 self.mid_toi_pairs.remove_index (i);
1715 len -= 1;
1716 continue
1717 }
1718 debug_assert_eq!(id_b.kind(), object::Kind::Dynamic);
1719 if resolved.binary_search (&id_b).is_ok() {
1720 self.mid_toi_pairs.remove_index (i);
1721 len -= 1;
1722 continue
1723 }
1724 i += 1;
1725 }
1726
1727 i = 0;
1729 len = self.narrow_toi_contacts.len();
1730 while i < len {
1731 let (_, object_pair, _) = self.narrow_toi_contacts[i].clone().0;
1732 let (id_a, id_b) = object_pair.into();
1733 if id_a.kind() == object::Kind::Dynamic && resolved.binary_search (&id_a).is_ok() {
1734 self.narrow_toi_contacts.remove_index (i);
1735 len -= 1;
1736 continue
1737 }
1738 debug_assert_eq!(id_b.kind(), object::Kind::Dynamic);
1739 if resolved.binary_search (&id_b).is_ok() {
1740 self.narrow_toi_contacts.remove_index (i);
1741 len -= 1;
1742 continue
1743 }
1744 i += 1;
1745 }
1746 }
1747}
1748
1749impl ObjectPair {
1750 pub fn new (id_a : InternalId, id_b : InternalId) -> Self {
1755 debug_assert!(id_a.kind() == object::Kind::Dynamic ||
1756 id_b.kind() == object::Kind::Dynamic);
1757 if id_a < id_b {
1758 ObjectPair (id_a, id_b)
1759 } else {
1760 debug_assert!(id_a > id_b, "overlap ids should not be identical");
1761 ObjectPair (id_b, id_a)
1762 }
1763 }
1764}
1765
1766impl From <(InternalId, InternalId)> for ObjectPair {
1767 fn from ((id_a, id_b) : (InternalId, InternalId)) -> Self {
1768 ObjectPair::new (id_a, id_b)
1769 }
1770}
1771
1772impl InternalId {
1773 #[inline]
1774 pub fn new_static (key : object::Key) -> Self {
1775 debug_assert!(key.value() < OBJECT_KEY_MAX);
1776 InternalId (key.value())
1777 }
1778 #[inline]
1779 pub fn new_dynamic (key : object::Key) -> Self {
1780 debug_assert!(key.value() < OBJECT_KEY_MAX);
1781 InternalId (key.value() | INTERNAL_ID_DYNAMIC_BIT)
1782 }
1783 #[inline]
1784 pub fn kind (&self) -> object::Kind {
1785 match self.0 & INTERNAL_ID_DYNAMIC_BIT > 0 {
1786 true => object::Kind::Dynamic,
1787 false => object::Kind::Static
1788 }
1789 }
1790 #[inline]
1791 pub fn key (&self) -> object::Key {
1792 object::Key::from (self.0 & !INTERNAL_ID_DYNAMIC_BIT)
1793 }
1794}
1795impl From <InternalId> for object::Id {
1796 fn from (id : InternalId) -> Self {
1797 object::Id {
1798 kind: id.kind(),
1799 key: id.key()
1800 }
1801 }
1802}