diff options
Diffstat (limited to 'src/geometry/narrow_phase.rs')
| -rw-r--r-- | src/geometry/narrow_phase.rs | 91 |
1 files changed, 61 insertions, 30 deletions
diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 640ce12..d05b19a 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -5,13 +5,14 @@ use crate::data::pubsub::Subscription; use crate::data::Coarena; use crate::dynamics::{BodyPair, CoefficientCombineRule, RigidBodySet}; use crate::geometry::{ - BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactData, ContactEvent, - ContactManifoldData, ContactPairFilter, IntersectionEvent, IntersectionPairFilter, - PairFilterContext, RemovedCollider, SolverContact, SolverFlags, + BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ColliderSet, ContactData, + ContactEvent, ContactManifold, ContactManifoldData, ContactPair, InteractionGraph, + IntersectionEvent, RemovedCollider, SolverContact, SolverFlags, }; -use crate::geometry::{ColliderSet, ContactManifold, ContactPair, InteractionGraph}; use crate::math::{Real, Vector}; -use crate::pipeline::EventHandler; +use crate::pipeline::{ + ContactModificationContext, EventHandler, PairFilterContext, PhysicsHooks, PhysicsHooksFlags, +}; use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher}; use parry::utils::IsometryOpt; use std::collections::HashMap; @@ -387,11 +388,13 @@ impl NarrowPhase { &mut self, bodies: &RigidBodySet, colliders: &ColliderSet, - pair_filter: Option<&dyn IntersectionPairFilter>, + hooks: &dyn PhysicsHooks, events: &dyn EventHandler, ) { let nodes = &self.intersection_graph.graph.nodes; let query_dispatcher = &*self.query_dispatcher; + let active_hooks = hooks.active_hooks(); + par_iter_mut!(&mut self.intersection_graph.graph.edges).for_each(|edge| { let handle1 = nodes[edge.source().index()].weight; let handle2 = nodes[edge.target().index()].weight; @@ -415,12 +418,15 @@ impl NarrowPhase { return; } - if pair_filter.is_none() && !rb1.is_dynamic() && !rb2.is_dynamic() { + if !active_hooks.contains(PhysicsHooksFlags::FILTER_INTERSECTION_PAIR) + && !rb1.is_dynamic() + && !rb2.is_dynamic() + { // Default filtering rule: no intersection between two non-dynamic bodies. return; } - if let Some(filter) = pair_filter { + if active_hooks.contains(PhysicsHooksFlags::FILTER_INTERSECTION_PAIR) { let context = PairFilterContext { rigid_body1: rb1, rigid_body2: rb2, @@ -430,7 +436,7 @@ impl NarrowPhase { collider2: co2, }; - if !filter.filter_intersection_pair(&context) { + if !hooks.filter_intersection_pair(&context) { // No intersection allowed. return; } @@ -458,10 +464,11 @@ impl NarrowPhase { prediction_distance: Real, bodies: &RigidBodySet, colliders: &ColliderSet, - pair_filter: Option<&dyn ContactPairFilter>, + hooks: &dyn PhysicsHooks, events: &dyn EventHandler, ) { let query_dispatcher = &*self.query_dispatcher; + let active_hooks = hooks.active_hooks(); par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| { let pair = &mut edge.weight; @@ -485,12 +492,16 @@ impl NarrowPhase { return; } - if pair_filter.is_none() && !rb1.is_dynamic() && !rb2.is_dynamic() { + if !active_hooks.contains(PhysicsHooksFlags::FILTER_CONTACT_PAIR) + && !rb1.is_dynamic() + && !rb2.is_dynamic() + { // Default filtering rule: no contact between two non-dynamic bodies. return; } - let mut solver_flags = if let Some(filter) = pair_filter { + let mut solver_flags = if active_hooks.contains(PhysicsHooksFlags::FILTER_CONTACT_PAIR) + { let context = PairFilterContext { rigid_body1: rb1, rigid_body2: rb2, @@ -500,14 +511,14 @@ impl NarrowPhase { collider2: co2, }; - if let Some(solver_flags) = filter.filter_contact_pair(&context) { + if let Some(solver_flags) = hooks.filter_contact_pair(&context) { solver_flags } else { // No contact allowed. return; } } else { - SolverFlags::COMPUTE_IMPULSES + co1.solver_flags | co2.solver_flags }; if !co1.solver_groups.test(co2.solver_groups) { @@ -546,38 +557,58 @@ impl NarrowPhase { manifold.data.solver_flags = solver_flags; manifold.data.normal = world_pos1 * manifold.local_n1; - // Sort contacts to keep only these with distances bellow - // the prediction, and generate solver contacts. - let mut first_inactive_index = manifold.points.len(); + // Generate solver contacts. + for (contact_id, contact) in manifold.points.iter().enumerate() { + assert!( + contact_id <= u8::MAX as usize, + "A contact manifold cannot contain more than 255 contacts currently." + ); - while manifold.data.num_active_contacts() != first_inactive_index { - let contact = &manifold.points[manifold.data.num_active_contacts()]; if contact.dist < prediction_distance { // Generate the solver contact. let solver_contact = SolverContact { + contact_id: contact_id as u8, point: world_pos1 * contact.local_p1 + manifold.data.normal * contact.dist / 2.0, dist: contact.dist, friction, restitution, - surface_velocity: Vector::zeros(), + tangent_velocity: Vector::zeros(), data: contact.data, }; - // TODO: apply the user-defined contact modification/removal, if needed. - manifold.data.solver_contacts.push(solver_contact); has_any_active_contact = true; - continue; } + } - // If we reach this code, then the contact must be ignored by the constraints solver. - // Swap with the last contact. - manifold.points.swap( - manifold.data.num_active_contacts(), - first_inactive_index - 1, - ); - first_inactive_index -= 1; + // Apply the user-defined contact modification. + if active_hooks.contains(PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS) + && manifold + .data + .solver_flags + .contains(SolverFlags::MODIFY_SOLVER_CONTACTS) + { + let mut modifiable_solver_contacts = + std::mem::replace(&mut manifold.data.solver_contacts, Vec::new()); + let mut modifiable_user_data = manifold.data.user_data; + + let mut context = ContactModificationContext { + rigid_body1: rb1, + rigid_body2: rb2, + collider_handle1: pair.pair.collider1, + collider_handle2: pair.pair.collider2, + collider1: co1, + collider2: co2, + manifold, + solver_contacts: &mut modifiable_solver_contacts, + user_data: &mut modifiable_user_data, + }; + + hooks.modify_solver_contacts(&mut context); + + manifold.data.solver_contacts = modifiable_solver_contacts; + manifold.data.user_data = modifiable_user_data; } } |
