From 865ce8a8e5301b23ca474adaaffe8b43e725803e Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 11:55:33 +0200 Subject: Collider shape: use a trait-object instead of an enum. --- src/geometry/narrow_phase.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index ebe0a79..e95709c 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -197,7 +197,8 @@ impl NarrowPhase { if self.proximity_graph.graph.find_edge(gid1, gid2).is_none() { let dispatcher = DefaultProximityDispatcher; - let generator = dispatcher.dispatch(co1.shape(), co2.shape()); + let generator = dispatcher + .dispatch(co1.shape().shape_type(), co2.shape().shape_type()); let interaction = ProximityPair::new(*pair, generator.0, generator.1); let _ = self.proximity_graph.add_edge( @@ -226,7 +227,8 @@ impl NarrowPhase { if self.contact_graph.graph.find_edge(gid1, gid2).is_none() { let dispatcher = DefaultContactDispatcher; - let generator = dispatcher.dispatch(co1.shape(), co2.shape()); + let generator = dispatcher + .dispatch(co1.shape().shape_type(), co2.shape().shape_type()); let interaction = ContactPair::new(*pair, generator.0, generator.1); let _ = self.contact_graph.add_edge( co1.contact_graph_index, @@ -308,7 +310,8 @@ impl NarrowPhase { if pair.detector.is_none() { // We need a redispatch for this detector. // This can happen, e.g., after restoring a snapshot of the narrow-phase. - let (detector, workspace) = dispatcher.dispatch(co1.shape(), co2.shape()); + let (detector, workspace) = + dispatcher.dispatch(co1.shape().shape_type(), co2.shape().shape_type()); pair.detector = Some(detector); pair.detector_workspace = workspace; } @@ -418,7 +421,8 @@ impl NarrowPhase { if pair.generator.is_none() { // We need a redispatch for this generator. // This can happen, e.g., after restoring a snapshot of the narrow-phase. - let (generator, workspace) = dispatcher.dispatch(co1.shape(), co2.shape()); + let (generator, workspace) = + dispatcher.dispatch(co1.shape().shape_type(), co2.shape().shape_type()); pair.generator = Some(generator); pair.generator_workspace = workspace; } -- cgit From 3def91d62eba6ca2486fdaa386f78d82923c705a Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 12:08:46 +0100 Subject: Add collision groups to filter collision pairs. --- src/geometry/narrow_phase.rs | 136 ++++--------------------------------------- 1 file changed, 10 insertions(+), 126 deletions(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index e95709c..5bcdcdb 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -306,6 +306,11 @@ impl NarrowPhase { return; } + if !co1.collision_groups.test(co2.collision_groups) { + // The collision is not allowed. + return; + } + let dispatcher = DefaultProximityDispatcher; if pair.detector.is_none() { // We need a redispatch for this detector. @@ -329,69 +334,6 @@ impl NarrowPhase { .unwrap() .detect_proximity(context, events); }); - - /* - // First, group pairs. - // NOTE: the transmutes here are OK because the Vec are all cleared - // before we leave this method. - // We do this in order to avoid reallocating those vecs each time - // we compute the contacts. Unsafe is necessary because we can't just - // store a Vec<&mut ProximityPair> into the NarrowPhase struct without - // polluting the World with lifetimes. - let ball_ball_prox: &mut Vec<&mut ProximityPair> = - unsafe { std::mem::transmute(&mut self.ball_ball_prox) }; - let shape_shape_prox: &mut Vec<&mut ProximityPair> = - unsafe { std::mem::transmute(&mut self.shape_shape_prox) }; - - let bodies = &bodies.bodies; - - // FIXME: don't iterate through all the interactions. - for pair in &mut self.proximity_graph.interactions { - let co1 = &colliders[pair.pair.collider1]; - let co2 = &colliders[pair.pair.collider2]; - - // FIXME: avoid lookup into bodies. - let rb1 = &bodies[co1.parent]; - let rb2 = &bodies[co2.parent]; - - if (rb1.is_sleeping() || !rb1.is_dynamic()) && (rb2.is_sleeping() || !rb2.is_dynamic()) - { - // No need to update this proximity because nothing moved. - continue; - } - - match (co1.shape(), co2.shape()) { - (Shape::Ball(_), Shape::Ball(_)) => ball_ball_prox.push(pair), - _ => shape_shape_prox.push(pair), - } - } - - par_chunks_mut!(ball_ball_prox, SIMD_WIDTH).for_each(|pairs| { - let context = ProximityDetectionContextSimd { - dispatcher: &DefaultProximityDispatcher, - prediction_distance, - colliders, - pairs, - }; - context.pairs[0] - .detector - .detect_proximity_simd(context, events); - }); - - par_iter_mut!(shape_shape_prox).for_each(|pair| { - let context = ProximityDetectionContext { - dispatcher: &DefaultProximityDispatcher, - prediction_distance, - colliders, - pair, - }; - - context.pair.detector.detect_proximity(context, events); - }); - - ball_ball_prox.clear(); - shape_shape_prox.clear(); - */ } pub(crate) fn compute_contacts( @@ -417,6 +359,11 @@ impl NarrowPhase { return; } + if !co1.collision_groups.test(co2.collision_groups) { + // The collision is not allowed. + return; + } + let dispatcher = DefaultContactDispatcher; if pair.generator.is_none() { // We need a redispatch for this generator. @@ -440,69 +387,6 @@ impl NarrowPhase { .unwrap() .generate_contacts(context, events); }); - - /* - // First, group pairs. - // NOTE: the transmutes here are OK because the Vec are all cleared - // before we leave this method. - // We do this in order to avoid reallocating those vecs each time - // we compute the contacts. Unsafe is necessary because we can't just - // store a Vec<&mut ContactPair> into the NarrowPhase struct without - // polluting the World with lifetimes. - let ball_ball: &mut Vec<&mut ContactPair> = - unsafe { std::mem::transmute(&mut self.ball_ball) }; - let shape_shape: &mut Vec<&mut ContactPair> = - unsafe { std::mem::transmute(&mut self.shape_shape) }; - - let bodies = &bodies.bodies; - - // FIXME: don't iterate through all the interactions. - for pair in &mut self.contact_graph.interactions { - let co1 = &colliders[pair.pair.collider1]; - let co2 = &colliders[pair.pair.collider2]; - - // FIXME: avoid lookup into bodies. - let rb1 = &bodies[co1.parent]; - let rb2 = &bodies[co2.parent]; - - if (rb1.is_sleeping() || !rb1.is_dynamic()) && (rb2.is_sleeping() || !rb2.is_dynamic()) - { - // No need to update this contact because nothing moved. - continue; - } - - match (co1.shape(), co2.shape()) { - (Shape::Ball(_), Shape::Ball(_)) => ball_ball.push(pair), - _ => shape_shape.push(pair), - } - } - - par_chunks_mut!(ball_ball, SIMD_WIDTH).for_each(|pairs| { - let context = ContactGenerationContextSimd { - dispatcher: &DefaultContactDispatcher, - prediction_distance, - colliders, - pairs, - }; - context.pairs[0] - .generator - .generate_contacts_simd(context, events); - }); - - par_iter_mut!(shape_shape).for_each(|pair| { - let context = ContactGenerationContext { - dispatcher: &DefaultContactDispatcher, - prediction_distance, - colliders, - pair, - }; - - context.pair.generator.generate_contacts(context, events); - }); - - ball_ball.clear(); - shape_shape.clear(); - */ } /// Retrieve all the interactions with at least one contact point, happening between two active bodies. -- cgit From cb6a7ff9468347735ef63db9a9e38faeb476981b Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 13:36:53 +0100 Subject: Add solver flags for controlling whether or not some contacts should be taken into account by the constraints solver. --- src/geometry/narrow_phase.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 5bcdcdb..290d55f 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -15,7 +15,7 @@ use crate::geometry::proximity_detector::{ //}; use crate::geometry::{ BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactEvent, ProximityEvent, - ProximityPair, RemovedCollider, + ProximityPair, RemovedCollider, SolverFlags, }; use crate::geometry::{ColliderSet, ContactManifold, ContactPair, InteractionGraph}; //#[cfg(feature = "simd-is-enabled")] @@ -374,11 +374,18 @@ impl NarrowPhase { pair.generator_workspace = workspace; } + let solver_flags = if co1.solver_groups.test(co2.solver_groups) { + SolverFlags::COMPUTE_FORCES + } else { + SolverFlags::empty() + }; + let context = ContactGenerationContext { dispatcher: &dispatcher, prediction_distance, colliders, pair, + solver_flags, }; context -- cgit From 5a5ba9cf5992a71f8bbdf594d17f0385bf7f86ba Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 14:25:19 +0100 Subject: Take the solver flags into account when collecting contact manifolds to solve. --- src/geometry/narrow_phase.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 290d55f..f5517ba 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -413,7 +413,8 @@ impl NarrowPhase { for manifold in &mut inter.weight.manifolds { let rb1 = &bodies[manifold.body_pair.body1]; let rb2 = &bodies[manifold.body_pair.body2]; - if manifold.num_active_contacts() != 0 + if manifold.solver_flags.contains(SolverFlags::COMPUTE_FORCES) + && manifold.num_active_contacts() != 0 && (!rb1.is_dynamic() || !rb1.is_sleeping()) && (!rb2.is_dynamic() || !rb2.is_sleeping()) { -- cgit From cc44b65094766aab40561f22431a95877ed5ff11 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 16:11:20 +0100 Subject: Added user-implementable traits for collision/proximity pair filtering. --- src/geometry/narrow_phase.rs | 70 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 14 deletions(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index f5517ba..fb5da99 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -14,8 +14,9 @@ use crate::geometry::proximity_detector::{ // proximity_detector::ProximityDetectionContextSimd, WBall, //}; use crate::geometry::{ - BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactEvent, ProximityEvent, - ProximityPair, RemovedCollider, SolverFlags, + BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactEvent, ContactPairFilter, + PairFilterContext, ProximityEvent, ProximityPair, ProximityPairFilter, RemovedCollider, + SolverFlags, }; use crate::geometry::{ColliderSet, ContactManifold, ContactPair, InteractionGraph}; //#[cfg(feature = "simd-is-enabled")] @@ -290,6 +291,7 @@ impl NarrowPhase { prediction_distance: f32, bodies: &RigidBodySet, colliders: &ColliderSet, + pair_filter: Option<&dyn ProximityPairFilter>, events: &dyn EventHandler, ) { par_iter_mut!(&mut self.proximity_graph.graph.edges).for_each(|edge| { @@ -301,16 +303,35 @@ impl NarrowPhase { let rb1 = &bodies[co1.parent]; let rb2 = &bodies[co2.parent]; - if (rb1.is_sleeping() || rb1.is_static()) && (rb2.is_sleeping() || rb2.is_static()) { - // No need to update this contact because nothing moved. + if (rb1.is_sleeping() && rb2.is_static()) || (rb2.is_sleeping() && rb1.is_static()) { + // No need to update this proximity because nothing moved. return; } if !co1.collision_groups.test(co2.collision_groups) { - // The collision is not allowed. + // The proximity is not allowed. + return; + } + + if pair_filter.is_none() && !rb1.is_dynamic() && !rb2.is_dynamic() { + // Default filtering rule: no proximity between two non-dynamic bodies. return; } + if let Some(filter) = pair_filter { + let context = PairFilterContext { + collider1: co1, + collider2: co2, + rigid_body1: rb1, + rigid_body2: rb2, + }; + + if !filter.filter_proximity_pair(&context) { + // No proximity allowed. + return; + } + } + let dispatcher = DefaultProximityDispatcher; if pair.detector.is_none() { // We need a redispatch for this detector. @@ -341,6 +362,7 @@ impl NarrowPhase { prediction_distance: f32, bodies: &RigidBodySet, colliders: &ColliderSet, + pair_filter: Option<&dyn ContactPairFilter>, events: &dyn EventHandler, ) { par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| { @@ -352,9 +374,7 @@ impl NarrowPhase { let rb1 = &bodies[co1.parent]; let rb2 = &bodies[co2.parent]; - if ((rb1.is_sleeping() || rb1.is_static()) && (rb2.is_sleeping() || rb2.is_static())) - || (!rb1.is_dynamic() && !rb2.is_dynamic()) - { + if (rb1.is_sleeping() && rb2.is_static()) || (rb2.is_sleeping() && rb1.is_static()) { // No need to update this contact because nothing moved. return; } @@ -364,6 +384,33 @@ impl NarrowPhase { return; } + if pair_filter.is_none() && !rb1.is_dynamic() && !rb2.is_dynamic() { + // Default filtering rule: no contact between two non-dynamic bodies. + return; + } + + let solver_flags = if let Some(filter) = pair_filter { + let context = PairFilterContext { + collider1: co1, + collider2: co2, + rigid_body1: rb1, + rigid_body2: rb2, + }; + + if let Some(solver_flags) = filter.filter_contact_pair(&context) { + solver_flags + } else { + // No contact allowed. + return; + } + } else { + if co1.solver_groups.test(co2.solver_groups) { + SolverFlags::COMPUTE_FORCES + } else { + SolverFlags::empty() + } + }; + let dispatcher = DefaultContactDispatcher; if pair.generator.is_none() { // We need a redispatch for this generator. @@ -374,12 +421,6 @@ impl NarrowPhase { pair.generator_workspace = workspace; } - let solver_flags = if co1.solver_groups.test(co2.solver_groups) { - SolverFlags::COMPUTE_FORCES - } else { - SolverFlags::empty() - }; - let context = ContactGenerationContext { dispatcher: &dispatcher, prediction_distance, @@ -415,6 +456,7 @@ impl NarrowPhase { let rb2 = &bodies[manifold.body_pair.body2]; if manifold.solver_flags.contains(SolverFlags::COMPUTE_FORCES) && manifold.num_active_contacts() != 0 + && (rb1.is_dynamic() || rb2.is_dynamic()) && (!rb1.is_dynamic() || !rb1.is_sleeping()) && (!rb2.is_dynamic() || !rb2.is_sleeping()) { -- cgit From 24bd97636e890195c8a72f8e265809bbae44ab13 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 16:21:33 +0100 Subject: Rename SolverFlags::COMPUTE_FORCES to SolverFlags::COMPUTE_IMPULSES. This is closer to what the solver actually does. --- src/geometry/narrow_phase.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index fb5da99..fd2652d 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -405,7 +405,7 @@ impl NarrowPhase { } } else { if co1.solver_groups.test(co2.solver_groups) { - SolverFlags::COMPUTE_FORCES + SolverFlags::COMPUTE_IMPULSES } else { SolverFlags::empty() } @@ -454,7 +454,9 @@ impl NarrowPhase { for manifold in &mut inter.weight.manifolds { let rb1 = &bodies[manifold.body_pair.body1]; let rb2 = &bodies[manifold.body_pair.body2]; - if manifold.solver_flags.contains(SolverFlags::COMPUTE_FORCES) + if manifold + .solver_flags + .contains(SolverFlags::COMPUTE_IMPULSES) && manifold.num_active_contacts() != 0 && (rb1.is_dynamic() || rb2.is_dynamic()) && (!rb1.is_dynamic() || !rb1.is_sleeping()) -- cgit From 3bfa4079999f6c886e692de256abf51e4506a2b1 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 16:48:05 +0100 Subject: ContactPairFilter: don't overwrite the effect of the solver groups. This is more consistent with the fact that the effect of collision groups is not overwritten either. --- src/geometry/narrow_phase.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index fd2652d..69678cd 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -320,10 +320,10 @@ impl NarrowPhase { if let Some(filter) = pair_filter { let context = PairFilterContext { - collider1: co1, - collider2: co2, rigid_body1: rb1, rigid_body2: rb2, + collider1: co1, + collider2: co2, }; if !filter.filter_proximity_pair(&context) { @@ -389,12 +389,12 @@ impl NarrowPhase { return; } - let solver_flags = if let Some(filter) = pair_filter { + let mut solver_flags = if let Some(filter) = pair_filter { let context = PairFilterContext { - collider1: co1, - collider2: co2, rigid_body1: rb1, rigid_body2: rb2, + collider1: co1, + collider2: co2, }; if let Some(solver_flags) = filter.filter_contact_pair(&context) { @@ -404,13 +404,13 @@ impl NarrowPhase { return; } } else { - if co1.solver_groups.test(co2.solver_groups) { - SolverFlags::COMPUTE_IMPULSES - } else { - SolverFlags::empty() - } + SolverFlags::COMPUTE_IMPULSES }; + if !co1.solver_groups.test(co2.solver_groups) { + solver_flags.remove(SolverFlags::COMPUTE_IMPULSES); + } + let dispatcher = DefaultContactDispatcher; if pair.generator.is_none() { // We need a redispatch for this generator. -- cgit From 74f0297221607e1929db75e79089d7cb75558dfe Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 17:14:13 +0100 Subject: Fix performance regression due to sleeping objects pairs no longer being ignored by the narrow-phase. --- src/geometry/narrow_phase.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/geometry/narrow_phase.rs') diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 69678cd..c1bd411 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -303,7 +303,10 @@ impl NarrowPhase { let rb1 = &bodies[co1.parent]; let rb2 = &bodies[co2.parent]; - if (rb1.is_sleeping() && rb2.is_static()) || (rb2.is_sleeping() && rb1.is_static()) { + if (rb1.is_sleeping() && rb2.is_static()) + || (rb2.is_sleeping() && rb1.is_static()) + || (rb1.is_sleeping() && rb2.is_sleeping()) + { // No need to update this proximity because nothing moved. return; } @@ -374,7 +377,10 @@ impl NarrowPhase { let rb1 = &bodies[co1.parent]; let rb2 = &bodies[co2.parent]; - if (rb1.is_sleeping() && rb2.is_static()) || (rb2.is_sleeping() && rb1.is_static()) { + if (rb1.is_sleeping() && rb2.is_static()) + || (rb2.is_sleeping() && rb1.is_static()) + || (rb1.is_sleeping() && rb2.is_sleeping()) + { // No need to update this contact because nothing moved. return; } -- cgit