Add solver flags for controlling whether or not some contacts should be taken into account by the constraints solver.

This commit is contained in:
Crozet Sébastien
2020-10-27 13:36:53 +01:00
parent 3def91d62e
commit cb6a7ff946
9 changed files with 78 additions and 13 deletions

View File

@@ -49,6 +49,7 @@ erased-serde = { version = "0.3", optional = true }
indexmap = { version = "1", features = [ "serde-1" ], optional = true } indexmap = { version = "1", features = [ "serde-1" ], optional = true }
downcast-rs = "1.2" downcast-rs = "1.2"
num-derive = "0.3" num-derive = "0.3"
bitflags = "1"
[dev-dependencies] [dev-dependencies]
bincode = "1" bincode = "1"

View File

@@ -49,7 +49,7 @@ erased-serde = { version = "0.3", optional = true }
indexmap = { version = "1", features = [ "serde-1" ], optional = true } indexmap = { version = "1", features = [ "serde-1" ], optional = true }
downcast-rs = "1.2" downcast-rs = "1.2"
num-derive = "0.3" num-derive = "0.3"
bitflags = "1"
[dev-dependencies] [dev-dependencies]
bincode = "1" bincode = "1"

View File

@@ -204,6 +204,7 @@ pub struct Collider {
/// The restitution coefficient of this collider. /// The restitution coefficient of this collider.
pub restitution: f32, pub restitution: f32,
pub(crate) collision_groups: InteractionGroups, pub(crate) collision_groups: InteractionGroups,
pub(crate) solver_groups: InteractionGroups,
pub(crate) contact_graph_index: ColliderGraphIndex, pub(crate) contact_graph_index: ColliderGraphIndex,
pub(crate) proximity_graph_index: ColliderGraphIndex, pub(crate) proximity_graph_index: ColliderGraphIndex,
pub(crate) proxy_index: usize, pub(crate) proxy_index: usize,
@@ -261,6 +262,11 @@ impl Collider {
self.collision_groups self.collision_groups
} }
/// The solver groups used by this collider.
pub fn solver_groups(&self) -> InteractionGroups {
self.solver_groups
}
/// The density of this collider. /// The density of this collider.
pub fn density(&self) -> f32 { pub fn density(&self) -> f32 {
self.density self.density
@@ -304,10 +310,12 @@ pub struct ColliderBuilder {
pub delta: Isometry<f32>, pub delta: Isometry<f32>,
/// Is this collider a sensor? /// Is this collider a sensor?
pub is_sensor: bool, pub is_sensor: bool,
/// The user-data of the collider beind built. /// The user-data of the collider being built.
pub user_data: u128, pub user_data: u128,
/// The collision groups for the collider being built. /// The collision groups for the collider being built.
pub collision_groups: InteractionGroups, pub collision_groups: InteractionGroups,
/// The solver groups for the collider being built.
pub solver_groups: InteractionGroups,
} }
impl ColliderBuilder { impl ColliderBuilder {
@@ -322,6 +330,7 @@ impl ColliderBuilder {
is_sensor: false, is_sensor: false,
user_data: 0, user_data: 0,
collision_groups: InteractionGroups::all(), collision_groups: InteractionGroups::all(),
solver_groups: InteractionGroups::all(),
} }
} }
@@ -442,6 +451,15 @@ impl ColliderBuilder {
self self
} }
/// Sets the solver groups used by this collider.
///
/// Forces between two colliders in contact will be computed iff their solver groups are
/// compatible. See [InteractionGroups::test] for details.
pub fn solver_groups(mut self, groups: InteractionGroups) -> Self {
self.solver_groups = groups;
self
}
/// Sets whether or not the collider built by this builder is a sensor. /// Sets whether or not the collider built by this builder is a sensor.
pub fn sensor(mut self, is_sensor: bool) -> Self { pub fn sensor(mut self, is_sensor: bool) -> Self {
self.is_sensor = is_sensor; self.is_sensor = is_sensor;
@@ -523,6 +541,8 @@ impl ColliderBuilder {
contact_graph_index: InteractionGraph::<Contact>::invalid_graph_index(), contact_graph_index: InteractionGraph::<Contact>::invalid_graph_index(),
proximity_graph_index: InteractionGraph::<Proximity>::invalid_graph_index(), proximity_graph_index: InteractionGraph::<Proximity>::invalid_graph_index(),
proxy_index: crate::INVALID_USIZE, proxy_index: crate::INVALID_USIZE,
collision_groups: self.collision_groups,
solver_groups: self.solver_groups,
user_data: self.user_data, user_data: self.user_data,
} }
} }

View File

@@ -9,6 +9,16 @@ use {
simba::simd::SimdValue, simba::simd::SimdValue,
}; };
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 SolverFlags: u32 {
/// The constraint solver will take this contact manifold into
/// account for force computation.
const COMPUTE_FORCES = 0b01;
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// The type local linear approximation of the neighborhood of a pair contact points on two shapes /// The type local linear approximation of the neighborhood of a pair contact points on two shapes
@@ -206,6 +216,7 @@ impl ContactPair {
pub(crate) fn single_manifold<'a, 'b>( pub(crate) fn single_manifold<'a, 'b>(
&'a mut self, &'a mut self,
colliders: &'b ColliderSet, colliders: &'b ColliderSet,
flags: SolverFlags,
) -> ( ) -> (
&'b Collider, &'b Collider,
&'b Collider, &'b Collider,
@@ -216,7 +227,7 @@ impl ContactPair {
let coll2 = &colliders[self.pair.collider2]; let coll2 = &colliders[self.pair.collider2];
if self.manifolds.len() == 0 { if self.manifolds.len() == 0 {
let manifold = ContactManifold::from_colliders(self.pair, coll1, coll2); let manifold = ContactManifold::from_colliders(self.pair, coll1, coll2, flags);
self.manifolds.push(manifold); self.manifolds.push(manifold);
} }
@@ -288,6 +299,8 @@ pub struct ContactManifold {
/// The relative position between the second collider and its parent at the time the /// The relative position between the second collider and its parent at the time the
/// contact points were generated. /// contact points were generated.
pub delta2: Isometry<f32>, pub delta2: Isometry<f32>,
/// Flags used to control some aspects of the constraints solver for this contact manifold.
pub solver_flags: SolverFlags,
} }
impl ContactManifold { impl ContactManifold {
@@ -299,6 +312,7 @@ impl ContactManifold {
delta2: Isometry<f32>, delta2: Isometry<f32>,
friction: f32, friction: f32,
restitution: f32, restitution: f32,
solver_flags: SolverFlags,
) -> ContactManifold { ) -> ContactManifold {
Self { Self {
#[cfg(feature = "dim2")] #[cfg(feature = "dim2")]
@@ -319,6 +333,7 @@ impl ContactManifold {
delta2, delta2,
constraint_index: 0, constraint_index: 0,
position_constraint_index: 0, position_constraint_index: 0,
solver_flags,
} }
} }
@@ -342,11 +357,17 @@ impl ContactManifold {
delta2: self.delta2, delta2: self.delta2,
constraint_index: self.constraint_index, constraint_index: self.constraint_index,
position_constraint_index: self.position_constraint_index, position_constraint_index: self.position_constraint_index,
solver_flags: self.solver_flags,
} }
} }
pub(crate) fn from_colliders(pair: ColliderPair, coll1: &Collider, coll2: &Collider) -> Self { pub(crate) fn from_colliders(
Self::with_subshape_indices(pair, coll1, coll2, 0, 0) pair: ColliderPair,
coll1: &Collider,
coll2: &Collider,
flags: SolverFlags,
) -> Self {
Self::with_subshape_indices(pair, coll1, coll2, 0, 0, flags)
} }
pub(crate) fn with_subshape_indices( pub(crate) fn with_subshape_indices(
@@ -355,6 +376,7 @@ impl ContactManifold {
coll2: &Collider, coll2: &Collider,
subshape1: usize, subshape1: usize,
subshape2: usize, subshape2: usize,
solver_flags: SolverFlags,
) -> Self { ) -> Self {
Self::new( Self::new(
pair, pair,
@@ -364,6 +386,7 @@ impl ContactManifold {
*coll2.position_wrt_parent(), *coll2.position_wrt_parent(),
(coll1.friction + coll2.friction) * 0.5, (coll1.friction + coll2.friction) * 0.5,
(coll1.restitution + coll2.restitution) * 0.5, (coll1.restitution + coll2.restitution) * 0.5,
solver_flags,
) )
} }

View File

@@ -1,5 +1,6 @@
use crate::geometry::{ use crate::geometry::{
Collider, ColliderSet, ContactDispatcher, ContactEvent, ContactManifold, ContactPair, Shape, Collider, ColliderSet, ContactDispatcher, ContactEvent, ContactManifold, ContactPair, Shape,
SolverFlags,
}; };
use crate::math::Isometry; use crate::math::Isometry;
#[cfg(feature = "simd-is-enabled")] #[cfg(feature = "simd-is-enabled")]
@@ -26,8 +27,9 @@ impl ContactPhase {
Self::NearPhase(gen) => (gen.generate_contacts)(&mut context), Self::NearPhase(gen) => (gen.generate_contacts)(&mut context),
Self::ExactPhase(gen) => { Self::ExactPhase(gen) => {
// Build the primitive context from the non-primitive context and dispatch. // Build the primitive context from the non-primitive context and dispatch.
let (collider1, collider2, manifold, workspace) = let (collider1, collider2, manifold, workspace) = context
context.pair.single_manifold(context.colliders); .pair
.single_manifold(context.colliders, context.solver_flags);
let mut context2 = PrimitiveContactGenerationContext { let mut context2 = PrimitiveContactGenerationContext {
prediction_distance: context.prediction_distance, prediction_distance: context.prediction_distance,
collider1, collider1,
@@ -85,9 +87,11 @@ impl ContactPhase {
[Option<&mut (dyn Any + Send + Sync)>; SIMD_WIDTH], [Option<&mut (dyn Any + Send + Sync)>; SIMD_WIDTH],
> = ArrayVec::new(); > = ArrayVec::new();
for pair in context.pairs.iter_mut() { for (pair, solver_flags) in
context.pairs.iter_mut().zip(context.solver_flags.iter())
{
let (collider1, collider2, manifold, workspace) = let (collider1, collider2, manifold, workspace) =
pair.single_manifold(context.colliders); pair.single_manifold(context.colliders, *solver_flags);
colliders_arr.push((collider1, collider2)); colliders_arr.push((collider1, collider2));
manifold_arr.push(manifold); manifold_arr.push(manifold);
workspace_arr.push(workspace); workspace_arr.push(workspace);
@@ -188,6 +192,7 @@ pub struct ContactGenerationContext<'a> {
pub prediction_distance: f32, pub prediction_distance: f32,
pub colliders: &'a ColliderSet, pub colliders: &'a ColliderSet,
pub pair: &'a mut ContactPair, pub pair: &'a mut ContactPair,
pub solver_flags: SolverFlags,
} }
#[cfg(feature = "simd-is-enabled")] #[cfg(feature = "simd-is-enabled")]
@@ -196,6 +201,7 @@ pub struct ContactGenerationContextSimd<'a, 'b> {
pub prediction_distance: f32, pub prediction_distance: f32,
pub colliders: &'a ColliderSet, pub colliders: &'a ColliderSet,
pub pairs: &'a mut [&'b mut ContactPair], pub pairs: &'a mut [&'b mut ContactPair],
pub solver_flags: &'a [SolverFlags],
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]

View File

@@ -104,6 +104,7 @@ fn do_generate_contacts(
let manifolds = &mut ctxt.pair.manifolds; let manifolds = &mut ctxt.pair.manifolds;
let prediction_distance = ctxt.prediction_distance; let prediction_distance = ctxt.prediction_distance;
let dispatcher = ctxt.dispatcher; let dispatcher = ctxt.dispatcher;
let solver_flags = ctxt.solver_flags;
let shape_type2 = collider2.shape().shape_type(); let shape_type2 = collider2.shape().shape_type();
heightfield1.map_elements_in_local_aabb(&ls_aabb2, &mut |i, part1, _| { heightfield1.map_elements_in_local_aabb(&ls_aabb2, &mut |i, part1, _| {
@@ -131,8 +132,14 @@ fn do_generate_contacts(
timestamp: new_timestamp, timestamp: new_timestamp,
workspace: workspace2, workspace: workspace2,
}; };
let manifold = let manifold = ContactManifold::with_subshape_indices(
ContactManifold::with_subshape_indices(coll_pair, collider1, collider2, i, 0); coll_pair,
collider1,
collider2,
i,
0,
solver_flags,
);
manifolds.push(manifold); manifolds.push(manifold);
entry.insert(sub_detector) entry.insert(sub_detector)

View File

@@ -149,6 +149,7 @@ fn do_generate_contacts(
collider2, collider2,
*triangle_id, *triangle_id,
0, 0,
ctxt.solver_flags,
) )
} else { } else {
// We already have a manifold for this triangle. // We already have a manifold for this triangle.

View File

@@ -5,7 +5,7 @@ pub use self::capsule::Capsule;
pub use self::collider::{Collider, ColliderBuilder, ColliderShape}; pub use self::collider::{Collider, ColliderBuilder, ColliderShape};
pub use self::collider_set::{ColliderHandle, ColliderSet}; pub use self::collider_set::{ColliderHandle, ColliderSet};
pub use self::contact::{ pub use self::contact::{
Contact, ContactKinematics, ContactManifold, ContactPair, KinematicsCategory, Contact, ContactKinematics, ContactManifold, ContactPair, KinematicsCategory, SolverFlags,
}; };
pub use self::contact_generator::{ContactDispatcher, DefaultContactDispatcher}; pub use self::contact_generator::{ContactDispatcher, DefaultContactDispatcher};
#[cfg(feature = "dim2")] #[cfg(feature = "dim2")]

View File

@@ -15,7 +15,7 @@ use crate::geometry::proximity_detector::{
//}; //};
use crate::geometry::{ use crate::geometry::{
BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactEvent, ProximityEvent, BroadPhasePairEvent, ColliderGraphIndex, ColliderHandle, ContactEvent, ProximityEvent,
ProximityPair, RemovedCollider, ProximityPair, RemovedCollider, SolverFlags,
}; };
use crate::geometry::{ColliderSet, ContactManifold, ContactPair, InteractionGraph}; use crate::geometry::{ColliderSet, ContactManifold, ContactPair, InteractionGraph};
//#[cfg(feature = "simd-is-enabled")] //#[cfg(feature = "simd-is-enabled")]
@@ -374,11 +374,18 @@ impl NarrowPhase {
pair.generator_workspace = workspace; pair.generator_workspace = workspace;
} }
let solver_flags = if co1.solver_groups.test(co2.solver_groups) {
SolverFlags::COMPUTE_FORCES
} else {
SolverFlags::empty()
};
let context = ContactGenerationContext { let context = ContactGenerationContext {
dispatcher: &dispatcher, dispatcher: &dispatcher,
prediction_distance, prediction_distance,
colliders, colliders,
pair, pair,
solver_flags,
}; };
context context