From ad5c10672e36f47fbdb0667bccd79c59ff3a97cc Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Mon, 22 Feb 2021 17:51:40 +0100 Subject: Use contact ids instead of contact reordering in order to identify the impulse writeback location. --- src/geometry/contact_pair.rs | 8 ++++++++ src/geometry/narrow_phase.rs | 20 +++++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/contact_pair.rs b/src/geometry/contact_pair.rs index 462d3ef..c94a2cf 100644 --- a/src/geometry/contact_pair.rs +++ b/src/geometry/contact_pair.rs @@ -110,6 +110,8 @@ pub struct ContactManifoldData { #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] pub struct SolverContact { + /// The index of the manifold contact used to generate this solver contact. + pub contact_id: u8, /// The world-space contact point. pub point: Point, /// The distance between the two original contacts points along the contact normal. @@ -203,3 +205,9 @@ impl ContactManifoldData { // manifold.data.warmstart_multiplier = Self::min_warmstart_multiplier() // } } + +/// A contact manifold that can be modified by the user. +pub struct ModifiableContactManifold<'a> { + manifold: &'a super::ContactManifold, + solver_contacts: &'a mut Vec, +} diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 640ce12..9513fef 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -546,15 +546,17 @@ 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, @@ -570,14 +572,6 @@ impl NarrowPhase { 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; } } -- cgit From 00706e8b360e132cb88a7b393dcedadf35403379 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 23 Feb 2021 11:24:54 +0100 Subject: Introduce the PhysicsHook trait used for both contact filtering and contact modification. --- src/geometry/contact_pair.rs | 14 +++--- src/geometry/mod.rs | 2 +- src/geometry/narrow_phase.rs | 63 ++++++++++++++++++++------ src/geometry/pair_filter.rs | 103 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 148 insertions(+), 34 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/contact_pair.rs b/src/geometry/contact_pair.rs index c94a2cf..11e0188 100644 --- a/src/geometry/contact_pair.rs +++ b/src/geometry/contact_pair.rs @@ -9,7 +9,10 @@ bitflags::bitflags! { pub struct SolverFlags: u32 { /// The constraint solver will take this contact manifold into /// account for force computation. - const COMPUTE_IMPULSES = 0b01; + const COMPUTE_IMPULSES = 0b001; + /// The user-defined physics hooks will be used to + /// modify the solver contacts of this contact manifold. + const MODIFY_SOLVER_CONTACTS = 0b010; } } @@ -104,6 +107,8 @@ pub struct ContactManifoldData { /// The contacts that will be seen by the constraints solver for computing forces. #[cfg_attr(feature = "serde-serialize", serde(skip))] pub solver_contacts: Vec, + /// A user-defined piece of data. + pub user_data: u32, } /// A contact seen by the constraints solver for computing forces. @@ -165,6 +170,7 @@ impl ContactManifoldData { solver_flags, normal: Vector::zeros(), solver_contacts: Vec::new(), + user_data: 0, } } @@ -205,9 +211,3 @@ impl ContactManifoldData { // manifold.data.warmstart_multiplier = Self::min_warmstart_multiplier() // } } - -/// A contact manifold that can be modified by the user. -pub struct ModifiableContactManifold<'a> { - manifold: &'a super::ContactManifold, - solver_contacts: &'a mut Vec, -} diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 861763e..2997e24 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -10,7 +10,7 @@ pub use self::interaction_graph::{ }; pub use self::interaction_groups::InteractionGroups; pub use self::narrow_phase::NarrowPhase; -pub use self::pair_filter::{ContactPairFilter, IntersectionPairFilter, PairFilterContext}; +pub use self::pair_filter::{PairFilterContext, PhysicsHooks}; pub use parry::query::TrackedContact; diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 9513fef..e929e0f 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -4,10 +4,11 @@ use rayon::prelude::*; use crate::data::pubsub::Subscription; use crate::data::Coarena; use crate::dynamics::{BodyPair, CoefficientCombineRule, RigidBodySet}; +use crate::geometry::pair_filter::{ContactModificationContext, PhysicsHooksFlags}; use crate::geometry::{ BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactData, ContactEvent, - ContactManifoldData, ContactPairFilter, IntersectionEvent, IntersectionPairFilter, - PairFilterContext, RemovedCollider, SolverContact, SolverFlags, + ContactManifoldData, IntersectionEvent, PairFilterContext, PhysicsHooks, RemovedCollider, + SolverContact, SolverFlags, }; use crate::geometry::{ColliderSet, ContactManifold, ContactPair, InteractionGraph}; use crate::math::{Real, Vector}; @@ -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,7 +511,7 @@ 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. @@ -566,13 +577,39 @@ impl NarrowPhase { 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; } } + + // 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; + } } if has_any_active_contact != pair.has_any_active_contact { diff --git a/src/geometry/pair_filter.rs b/src/geometry/pair_filter.rs index 25f300f..a30145e 100644 --- a/src/geometry/pair_filter.rs +++ b/src/geometry/pair_filter.rs @@ -1,5 +1,5 @@ use crate::dynamics::RigidBody; -use crate::geometry::{Collider, ColliderHandle, SolverFlags}; +use crate::geometry::{Collider, ColliderHandle, ContactManifold, SolverContact, SolverFlags}; /// Context given to custom collision filters to filter-out collisions. pub struct PairFilterContext<'a> { @@ -17,14 +17,54 @@ pub struct PairFilterContext<'a> { pub collider2: &'a Collider, } -/// User-defined filter for potential contact pairs detected by the broad-phase. -/// -/// This can be used to apply custom logic in order to decide whether two colliders -/// should have their contact computed by the narrow-phase, and if these contact -/// should be solved by the constraints solver -pub trait ContactPairFilter: Send + Sync { +pub struct ContactModificationContext<'a> { + /// The first collider involved in the potential collision. + pub rigid_body1: &'a RigidBody, + /// The first collider involved in the potential collision. + pub rigid_body2: &'a RigidBody, + /// The first collider involved in the potential collision. + pub collider_handle1: ColliderHandle, + /// The first collider involved in the potential collision. + pub collider_handle2: ColliderHandle, + /// The first collider involved in the potential collision. + pub collider1: &'a Collider, + /// The first collider involved in the potential collision. + pub collider2: &'a Collider, + /// The contact manifold. + pub manifold: &'a ContactManifold, + /// The solver contacts that can be modified. + pub solver_contacts: &'a mut Vec, + /// User-defined data attached to the manifold. + // NOTE: we keep this a &'a mut u32 to emphasize the + // fact that this can be modified. + pub user_data: &'a mut u32, +} + +bitflags::bitflags! { + #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] + /// Flags affecting the behavior of the constraints solver for a given contact manifold. + pub struct PhysicsHooksFlags: u32 { + /// If set, Rapier will call `PhysicsHooks::filter_contact_pair` whenever relevant. + const FILTER_CONTACT_PAIR = 0b0001; + /// If set, Rapier will call `PhysicsHooks::filter_intersection_pair` whenever relevant. + const FILTER_INTERSECTION_PAIR = 0b0010; + /// If set, Rapier will call `PhysicsHooks::modify_solver_contact` whenever relevant. + const MODIFY_SOLVER_CONTACTS = 0b0100; + } +} + +/// User-defined functions called by the physics engines during one timestep in order to customize its behavior. +pub trait PhysicsHooks: Send + Sync { + /// The sets of hooks that must be taken into account. + fn active_hooks(&self) -> PhysicsHooksFlags; + /// Applies the contact pair filter. /// + /// User-defined filter for potential contact pairs detected by the broad-phase. + /// This can be used to apply custom logic in order to decide whether two colliders + /// should have their contact computed by the narrow-phase, and if these contact + /// should be solved by the constraints solver + /// /// Note that using a contact pair filter will replace the default contact filtering /// which consists of preventing contact computation between two non-dynamic bodies. /// @@ -39,15 +79,14 @@ pub trait ContactPairFilter: Send + Sync { /// `Some(SolverFlags::empty())` then the constraints solver will ignore these /// contacts. fn filter_contact_pair(&self, context: &PairFilterContext) -> Option; -} -/// User-defined filter for potential intersection pairs detected by the broad-phase. -/// -/// This can be used to apply custom logic in order to decide whether two colliders -/// should have their intersection computed by the narrow-phase. -pub trait IntersectionPairFilter: Send + Sync { /// Applies the intersection pair filter. /// + /// User-defined filter for potential intersection pairs detected by the broad-phase. + /// + /// This can be used to apply custom logic in order to decide whether two colliders + /// should have their intersection computed by the narrow-phase. + /// /// Note that using an intersection pair filter will replace the default intersection filtering /// which consists of preventing intersection computation between two non-dynamic bodies. /// @@ -58,4 +97,42 @@ pub trait IntersectionPairFilter: Send + Sync { /// If this return `true` then the narrow-phase will compute intersection /// information for this pair. fn filter_intersection_pair(&self, context: &PairFilterContext) -> bool; + + /// Modifies the set of contacts seen by the constraints solver. + /// + /// By default, the content of `solver_contacts` is computed from `manifold.points`. + /// This method will be called on each contact manifold which have the flag `SolverFlags::MODIFY_CONTACTS` set. + /// This method can be used to modify the set of solver contacts seen by the constraints solver: contacts + /// can be removed and modified. + /// + /// Note that if all the contacts have to be ignored by the constraint solver, you may simply + /// do `context.solver_contacts.clear()`. + /// + /// Modifying the solver contacts allow you to achieve various effects, including: + /// - Simulating conveyor belts by setting the `surface_velocity` of a solver contact. + /// - Simulating shapes with multiply materials by modifying the friction and restitution + /// coefficient depending of the features in contacts. + /// - Simulating one-way platforms depending on the contact normal. + /// + /// Each contact manifold is given a `u32` user-defined data that is persistent between + /// timesteps (as long as the contact manifold exists). This user-defined data is initialized + /// as 0 and can be modified in `context.user_data`. + fn modify_solver_contacts(&self, context: &mut ContactModificationContext); +} + +impl PhysicsHooks for () { + /// The sets of hooks that must be taken into account. + fn active_hooks(&self) -> PhysicsHooksFlags { + PhysicsHooksFlags::empty() + } + + fn filter_contact_pair(&self, _: &PairFilterContext) -> Option { + None + } + + fn filter_intersection_pair(&self, _: &PairFilterContext) -> bool { + false + } + + fn modify_solver_contacts(&self, _: &mut ContactModificationContext) {} } -- cgit From 4ca32a9546beca788104041134f0afbe96c5e871 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 23 Feb 2021 15:43:43 +0100 Subject: Add one-way platform + conveyor belt demos. --- src/geometry/pair_filter.rs | 138 -------------------------------------------- 1 file changed, 138 deletions(-) delete mode 100644 src/geometry/pair_filter.rs (limited to 'src/geometry') diff --git a/src/geometry/pair_filter.rs b/src/geometry/pair_filter.rs deleted file mode 100644 index a30145e..0000000 --- a/src/geometry/pair_filter.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::dynamics::RigidBody; -use crate::geometry::{Collider, ColliderHandle, ContactManifold, SolverContact, SolverFlags}; - -/// Context given to custom collision filters to filter-out collisions. -pub struct PairFilterContext<'a> { - /// The first collider involved in the potential collision. - pub rigid_body1: &'a RigidBody, - /// The first collider involved in the potential collision. - pub rigid_body2: &'a RigidBody, - /// The first collider involved in the potential collision. - pub collider_handle1: ColliderHandle, - /// The first collider involved in the potential collision. - pub collider_handle2: ColliderHandle, - /// The first collider involved in the potential collision. - pub collider1: &'a Collider, - /// The first collider involved in the potential collision. - pub collider2: &'a Collider, -} - -pub struct ContactModificationContext<'a> { - /// The first collider involved in the potential collision. - pub rigid_body1: &'a RigidBody, - /// The first collider involved in the potential collision. - pub rigid_body2: &'a RigidBody, - /// The first collider involved in the potential collision. - pub collider_handle1: ColliderHandle, - /// The first collider involved in the potential collision. - pub collider_handle2: ColliderHandle, - /// The first collider involved in the potential collision. - pub collider1: &'a Collider, - /// The first collider involved in the potential collision. - pub collider2: &'a Collider, - /// The contact manifold. - pub manifold: &'a ContactManifold, - /// The solver contacts that can be modified. - pub solver_contacts: &'a mut Vec, - /// User-defined data attached to the manifold. - // NOTE: we keep this a &'a mut u32 to emphasize the - // fact that this can be modified. - pub user_data: &'a mut u32, -} - -bitflags::bitflags! { - #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] - /// Flags affecting the behavior of the constraints solver for a given contact manifold. - pub struct PhysicsHooksFlags: u32 { - /// If set, Rapier will call `PhysicsHooks::filter_contact_pair` whenever relevant. - const FILTER_CONTACT_PAIR = 0b0001; - /// If set, Rapier will call `PhysicsHooks::filter_intersection_pair` whenever relevant. - const FILTER_INTERSECTION_PAIR = 0b0010; - /// If set, Rapier will call `PhysicsHooks::modify_solver_contact` whenever relevant. - const MODIFY_SOLVER_CONTACTS = 0b0100; - } -} - -/// User-defined functions called by the physics engines during one timestep in order to customize its behavior. -pub trait PhysicsHooks: Send + Sync { - /// The sets of hooks that must be taken into account. - fn active_hooks(&self) -> PhysicsHooksFlags; - - /// Applies the contact pair filter. - /// - /// User-defined filter for potential contact pairs detected by the broad-phase. - /// This can be used to apply custom logic in order to decide whether two colliders - /// should have their contact computed by the narrow-phase, and if these contact - /// should be solved by the constraints solver - /// - /// Note that using a contact pair filter will replace the default contact filtering - /// which consists of preventing contact computation between two non-dynamic bodies. - /// - /// This filtering method is called after taking into account the colliders collision groups. - /// - /// If this returns `None`, then the narrow-phase will ignore this contact pair and - /// not compute any contact manifolds for it. - /// If this returns `Some`, then the narrow-phase will compute contact manifolds for - /// this pair of colliders, and configure them with the returned solver flags. For - /// example, if this returns `Some(SolverFlags::COMPUTE_IMPULSES)` then the contacts - /// will be taken into account by the constraints solver. If this returns - /// `Some(SolverFlags::empty())` then the constraints solver will ignore these - /// contacts. - fn filter_contact_pair(&self, context: &PairFilterContext) -> Option; - - /// Applies the intersection pair filter. - /// - /// User-defined filter for potential intersection pairs detected by the broad-phase. - /// - /// This can be used to apply custom logic in order to decide whether two colliders - /// should have their intersection computed by the narrow-phase. - /// - /// Note that using an intersection pair filter will replace the default intersection filtering - /// which consists of preventing intersection computation between two non-dynamic bodies. - /// - /// This filtering method is called after taking into account the colliders collision groups. - /// - /// If this returns `false`, then the narrow-phase will ignore this pair and - /// not compute any intersection information for it. - /// If this return `true` then the narrow-phase will compute intersection - /// information for this pair. - fn filter_intersection_pair(&self, context: &PairFilterContext) -> bool; - - /// Modifies the set of contacts seen by the constraints solver. - /// - /// By default, the content of `solver_contacts` is computed from `manifold.points`. - /// This method will be called on each contact manifold which have the flag `SolverFlags::MODIFY_CONTACTS` set. - /// This method can be used to modify the set of solver contacts seen by the constraints solver: contacts - /// can be removed and modified. - /// - /// Note that if all the contacts have to be ignored by the constraint solver, you may simply - /// do `context.solver_contacts.clear()`. - /// - /// Modifying the solver contacts allow you to achieve various effects, including: - /// - Simulating conveyor belts by setting the `surface_velocity` of a solver contact. - /// - Simulating shapes with multiply materials by modifying the friction and restitution - /// coefficient depending of the features in contacts. - /// - Simulating one-way platforms depending on the contact normal. - /// - /// Each contact manifold is given a `u32` user-defined data that is persistent between - /// timesteps (as long as the contact manifold exists). This user-defined data is initialized - /// as 0 and can be modified in `context.user_data`. - fn modify_solver_contacts(&self, context: &mut ContactModificationContext); -} - -impl PhysicsHooks for () { - /// The sets of hooks that must be taken into account. - fn active_hooks(&self) -> PhysicsHooksFlags { - PhysicsHooksFlags::empty() - } - - fn filter_contact_pair(&self, _: &PairFilterContext) -> Option { - None - } - - fn filter_intersection_pair(&self, _: &PairFilterContext) -> bool { - false - } - - fn modify_solver_contacts(&self, _: &mut ContactModificationContext) {} -} -- cgit From babcab0bed23fadd23181ccc58aae34fb80d01d8 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 23 Feb 2021 15:49:23 +0100 Subject: Update the testbed to use PhysicsHooks. --- src/geometry/collider.rs | 17 ++++++++++++++++- src/geometry/contact_pair.rs | 11 +++++++++-- src/geometry/mod.rs | 2 -- src/geometry/narrow_phase.rs | 16 ++++++++-------- 4 files changed, 33 insertions(+), 13 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index ce263f8..4be6d29 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,5 +1,5 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle}; -use crate::geometry::{InteractionGroups, SharedShape}; +use crate::geometry::{InteractionGroups, SharedShape, SolverFlags}; use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM}; use crate::parry::transformation::vhacd::VHACDParameters; use parry::bounding_volume::AABB; @@ -50,6 +50,7 @@ pub struct Collider { shape: SharedShape, density: Real, pub(crate) flags: ColliderFlags, + pub(crate) solver_flags: SolverFlags, pub(crate) parent: RigidBodyHandle, pub(crate) delta: Isometry, pub(crate) position: Isometry, @@ -159,6 +160,9 @@ pub struct ColliderBuilder { pub delta: Isometry, /// Is this collider a sensor? pub is_sensor: bool, + /// Do we have to always call the contact modifier + /// on this collider? + pub modify_contacts: bool, /// The user-data of the collider being built. pub user_data: u128, /// The collision groups for the collider being built. @@ -182,6 +186,7 @@ impl ColliderBuilder { solver_groups: InteractionGroups::all(), friction_combine_rule: CoefficientCombineRule::Average, restitution_combine_rule: CoefficientCombineRule::Average, + modify_contacts: false, } } @@ -456,6 +461,13 @@ impl ColliderBuilder { self } + /// If set to `true` then the physics hooks will always run to modify + /// contacts involving this collider. + pub fn modify_contacts(mut self, modify_contacts: bool) -> Self { + self.modify_contacts = modify_contacts; + self + } + /// Sets the friction coefficient of the collider this builder will build. pub fn friction(mut self, friction: Real) -> Self { self.friction = friction; @@ -534,6 +546,8 @@ impl ColliderBuilder { flags = flags .with_friction_combine_rule(self.friction_combine_rule) .with_restitution_combine_rule(self.restitution_combine_rule); + let mut solver_flags = SolverFlags::default(); + solver_flags.set(SolverFlags::MODIFY_SOLVER_CONTACTS, self.modify_contacts); Collider { shape: self.shape.clone(), @@ -542,6 +556,7 @@ impl ColliderBuilder { restitution: self.restitution, delta: self.delta, flags, + solver_flags, parent: RigidBodyHandle::invalid(), position: Isometry::identity(), predicted_position: Isometry::identity(), diff --git a/src/geometry/contact_pair.rs b/src/geometry/contact_pair.rs index 11e0188..50094ca 100644 --- a/src/geometry/contact_pair.rs +++ b/src/geometry/contact_pair.rs @@ -16,6 +16,12 @@ bitflags::bitflags! { } } +impl Default for SolverFlags { + fn default() -> Self { + SolverFlags::COMPUTE_IMPULSES + } +} + #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] /// A single contact between two collider. @@ -126,10 +132,11 @@ pub struct SolverContact { pub friction: Real, /// The effective restitution coefficient at this contact point. pub restitution: Real, - /// The artificially add relative velocity at the contact point. + /// The desired tangent relative velocity at the contact point. + /// /// This is set to zero by default. Set to a non-zero value to /// simulate, e.g., conveyor belts. - pub surface_velocity: Vector, + pub tangent_velocity: Vector, /// Associated contact data used to warm-start the constraints /// solver. pub data: ContactData, diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 2997e24..ab04b25 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -10,7 +10,6 @@ pub use self::interaction_graph::{ }; pub use self::interaction_groups::InteractionGroups; pub use self::narrow_phase::NarrowPhase; -pub use self::pair_filter::{PairFilterContext, PhysicsHooks}; pub use parry::query::TrackedContact; @@ -109,4 +108,3 @@ mod contact_pair; mod interaction_graph; mod interaction_groups; mod narrow_phase; -mod pair_filter; diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index e929e0f..d05b19a 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -4,15 +4,15 @@ use rayon::prelude::*; use crate::data::pubsub::Subscription; use crate::data::Coarena; use crate::dynamics::{BodyPair, CoefficientCombineRule, RigidBodySet}; -use crate::geometry::pair_filter::{ContactModificationContext, PhysicsHooksFlags}; use crate::geometry::{ - BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactData, ContactEvent, - ContactManifoldData, IntersectionEvent, PairFilterContext, PhysicsHooks, 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; @@ -518,7 +518,7 @@ impl NarrowPhase { return; } } else { - SolverFlags::COMPUTE_IMPULSES + co1.solver_flags | co2.solver_flags }; if !co1.solver_groups.test(co2.solver_groups) { @@ -573,7 +573,7 @@ impl NarrowPhase { dist: contact.dist, friction, restitution, - surface_velocity: Vector::zeros(), + tangent_velocity: Vector::zeros(), data: contact.data, }; -- cgit From 0f0f2c344fd78c3d1ca9ec07d3523c5d0ea10c82 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 23 Feb 2021 16:02:19 +0100 Subject: Rename modify_contacts -> modify_solver_contacts. --- src/geometry/collider.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 4be6d29..b006f9e 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -162,7 +162,7 @@ pub struct ColliderBuilder { pub is_sensor: bool, /// Do we have to always call the contact modifier /// on this collider? - pub modify_contacts: bool, + pub modify_solver_contacts: bool, /// The user-data of the collider being built. pub user_data: u128, /// The collision groups for the collider being built. @@ -186,7 +186,7 @@ impl ColliderBuilder { solver_groups: InteractionGroups::all(), friction_combine_rule: CoefficientCombineRule::Average, restitution_combine_rule: CoefficientCombineRule::Average, - modify_contacts: false, + modify_solver_contacts: false, } } @@ -463,8 +463,8 @@ impl ColliderBuilder { /// If set to `true` then the physics hooks will always run to modify /// contacts involving this collider. - pub fn modify_contacts(mut self, modify_contacts: bool) -> Self { - self.modify_contacts = modify_contacts; + pub fn modify_solver_contacts(mut self, modify_solver_contacts: bool) -> Self { + self.modify_solver_contacts = modify_solver_contacts; self } @@ -547,7 +547,10 @@ impl ColliderBuilder { .with_friction_combine_rule(self.friction_combine_rule) .with_restitution_combine_rule(self.restitution_combine_rule); let mut solver_flags = SolverFlags::default(); - solver_flags.set(SolverFlags::MODIFY_SOLVER_CONTACTS, self.modify_contacts); + solver_flags.set( + SolverFlags::MODIFY_SOLVER_CONTACTS, + self.modify_solver_contacts, + ); Collider { shape: self.shape.clone(), -- cgit