feat: make narrow-phase filter-out predictive solver contact based on contact velocity

This commit is contained in:
Sébastien Crozet
2024-04-07 22:25:08 +02:00
committed by Sébastien Crozet
parent a44f39a7b6
commit 15c07cfeb3

View File

@@ -789,6 +789,7 @@ impl NarrowPhase {
pub(crate) fn compute_contacts( pub(crate) fn compute_contacts(
&mut self, &mut self,
prediction_distance: Real, prediction_distance: Real,
dt: Real,
bodies: &RigidBodySet, bodies: &RigidBodySet,
colliders: &ColliderSet, colliders: &ColliderSet,
impulse_joints: &ImpulseJointSet, impulse_joints: &ImpulseJointSet,
@@ -819,17 +820,11 @@ impl NarrowPhase {
return; return;
} }
// TODO: avoid lookup into bodies. let rb1 = co1.parent.map(|co_parent1| &bodies[co_parent1.handle]);
let mut rb_type1 = RigidBodyType::Fixed; let rb2 = co2.parent.map(|co_parent2| &bodies[co_parent2.handle]);
let mut rb_type2 = RigidBodyType::Fixed;
if let Some(co_parent1) = &co1.parent { let rb_type1 = rb1.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
rb_type1 = bodies[co_parent1.handle].body_type; let rb_type2 = rb2.map(|rb| rb.body_type).unwrap_or(RigidBodyType::Fixed);
}
if let Some(co_parent2) = &co2.parent {
rb_type2 = bodies[co_parent2.handle].body_type;
}
// Deal with contacts disabled between bodies attached by joints. // Deal with contacts disabled between bodies attached by joints.
if let (Some(co_parent1), Some(co_parent2)) = (&co1.parent, &co2.parent) { if let (Some(co_parent1), Some(co_parent2)) = (&co1.parent, &co2.parent) {
@@ -924,14 +919,8 @@ impl NarrowPhase {
); );
let zero = RigidBodyDominance(0); // The value doesn't matter, it will be MAX because of the effective groups. let zero = RigidBodyDominance(0); // The value doesn't matter, it will be MAX because of the effective groups.
let dominance1 = co1 let dominance1 = rb1.map(|rb| rb.dominance).unwrap_or(zero);
.parent let dominance2 = rb2.map(|rb| rb.dominance).unwrap_or(zero);
.map(|p1| bodies[p1.handle].dominance)
.unwrap_or(zero);
let dominance2 = co2
.parent
.map(|p2| bodies[p2.handle].dominance)
.unwrap_or(zero);
pair.has_any_active_contact = false; pair.has_any_active_contact = false;
@@ -948,12 +937,20 @@ impl NarrowPhase {
// Generate solver contacts. // Generate solver contacts.
for (contact_id, contact) in manifold.points.iter().enumerate() { for (contact_id, contact) in manifold.points.iter().enumerate() {
assert!( if contact_id > u8::MAX as usize {
contact_id <= u8::MAX as usize, log::warn!("A contact manifold cannot contain more than 255 contacts currently, dropping contact in excess.");
"A contact manifold cannot contain more than 255 contacts currently." break;
); }
if contact.dist < prediction_distance { let keep_solver_contact = contact.dist < prediction_distance || {
let world_pt1 = world_pos1 * contact.local_p1;
let world_pt2 = world_pos2 * contact.local_p2;
let vel1 = rb1.map(|rb| rb.velocity_at_point(&world_pt1)).unwrap_or_default();
let vel2 = rb2.map(|rb| rb.velocity_at_point(&world_pt2)).unwrap_or_default();
contact.dist + (vel2 - vel1).dot(&manifold.data.normal) * dt < prediction_distance
};
if keep_solver_contact {
// Generate the solver contact. // Generate the solver contact.
let world_pt1 = world_pos1 * contact.local_p1; let world_pt1 = world_pos1 * contact.local_p1;
let world_pt2 = world_pos2 * contact.local_p2; let world_pt2 = world_pos2 * contact.local_p2;