Add collision groups to filter collision pairs.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet};
|
||||
use crate::geometry::{
|
||||
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Proximity,
|
||||
Segment, Shape, ShapeType, Triangle, Trimesh,
|
||||
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph,
|
||||
InteractionGroups, Proximity, Segment, Shape, ShapeType, Triangle, Trimesh,
|
||||
};
|
||||
#[cfg(feature = "dim3")]
|
||||
use crate::geometry::{Cone, Cylinder, RoundCylinder};
|
||||
@@ -203,6 +203,7 @@ pub struct Collider {
|
||||
pub friction: f32,
|
||||
/// The restitution coefficient of this collider.
|
||||
pub restitution: f32,
|
||||
pub(crate) collision_groups: InteractionGroups,
|
||||
pub(crate) contact_graph_index: ColliderGraphIndex,
|
||||
pub(crate) proximity_graph_index: ColliderGraphIndex,
|
||||
pub(crate) proxy_index: usize,
|
||||
@@ -255,6 +256,11 @@ impl Collider {
|
||||
&self.delta
|
||||
}
|
||||
|
||||
/// The collision groups used by this collider.
|
||||
pub fn collision_groups(&self) -> InteractionGroups {
|
||||
self.collision_groups
|
||||
}
|
||||
|
||||
/// The density of this collider.
|
||||
pub fn density(&self) -> f32 {
|
||||
self.density
|
||||
@@ -300,6 +306,8 @@ pub struct ColliderBuilder {
|
||||
pub is_sensor: bool,
|
||||
/// The user-data of the collider beind built.
|
||||
pub user_data: u128,
|
||||
/// The collision groups for the collider being built.
|
||||
pub collision_groups: InteractionGroups,
|
||||
}
|
||||
|
||||
impl ColliderBuilder {
|
||||
@@ -313,6 +321,7 @@ impl ColliderBuilder {
|
||||
delta: Isometry::identity(),
|
||||
is_sensor: false,
|
||||
user_data: 0,
|
||||
collision_groups: InteractionGroups::all(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,12 +427,21 @@ impl ColliderBuilder {
|
||||
0.5
|
||||
}
|
||||
|
||||
/// An arbitrary user-defined 128-bit integer associated to the colliders built by this builder.
|
||||
/// Sets an arbitrary user-defined 128-bit integer associated to the colliders built by this builder.
|
||||
pub fn user_data(mut self, data: u128) -> Self {
|
||||
self.user_data = data;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the collision groups used by this collider.
|
||||
///
|
||||
/// Two colliders will interact iff. their collision groups are compatible.
|
||||
/// See [InteractionGroups::test] for details.
|
||||
pub fn collision_groups(mut self, groups: InteractionGroups) -> Self {
|
||||
self.collision_groups = groups;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets whether or not the collider built by this builder is a sensor.
|
||||
pub fn sensor(mut self, is_sensor: bool) -> Self {
|
||||
self.is_sensor = is_sensor;
|
||||
|
||||
54
src/geometry/interaction_groups.rs
Normal file
54
src/geometry/interaction_groups.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
/// Pairwise filtering using bit masks.
|
||||
///
|
||||
/// This filtering method is based on two 16-bit values:
|
||||
/// - The interaction groups (the 16 left-most bits of `self.0`).
|
||||
/// - The interaction mask (the 16 right-most bits of `self.0`).
|
||||
///
|
||||
/// An interaction is allowed between two filters `a` and `b` two conditions
|
||||
/// are met simultaneously:
|
||||
/// - The interaction groups of `a` has at least one bit set to `1` in common with the interaction mask of `b`.
|
||||
/// - The interaction groups of `b` has at least one bit set to `1` in common with the interaction mask of `a`.
|
||||
/// In other words, interactions are allowed between two filter iff. the following condition is met:
|
||||
/// ```rust
|
||||
/// ((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0
|
||||
/// ```
|
||||
pub struct InteractionGroups(pub u32);
|
||||
|
||||
impl InteractionGroups {
|
||||
/// Allow interaction with everything.
|
||||
pub fn all() -> Self {
|
||||
Self(u32::MAX)
|
||||
}
|
||||
|
||||
/// Prevent all interactions.
|
||||
pub fn none() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
/// Sets the group this filter is part of.
|
||||
pub fn with_groups(self, groups: u16) -> Self {
|
||||
Self((self.0 & 0x0000ffff) | ((groups as u32) << 16))
|
||||
}
|
||||
|
||||
/// Sets the interaction mask of this filter.
|
||||
pub fn with_mask(self, mask: u16) -> Self {
|
||||
Self((self.0 & 0xffff0000) | (mask as u32))
|
||||
}
|
||||
|
||||
/// Check if interactions should be allowed based on the interaction groups and mask.
|
||||
///
|
||||
/// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common
|
||||
/// with the mask of `rhs`, and vice-versa.
|
||||
pub fn test(self, rhs: Self) -> bool {
|
||||
((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for InteractionGroups {
|
||||
fn default() -> Self {
|
||||
Self::all()
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,7 @@ pub(crate) use self::polyhedron_feature3d::PolyhedronFace;
|
||||
pub(crate) use self::waabb::{WRay, WAABB};
|
||||
pub(crate) use self::wquadtree::WQuadtree;
|
||||
//pub(crate) use self::z_order::z_cmp_floats;
|
||||
pub use self::interaction_groups::InteractionGroups;
|
||||
pub use self::shape::{Shape, ShapeType};
|
||||
|
||||
mod ball;
|
||||
@@ -97,6 +98,7 @@ mod waabb;
|
||||
mod wquadtree;
|
||||
//mod z_order;
|
||||
mod capsule;
|
||||
mod interaction_groups;
|
||||
#[cfg(feature = "dim3")]
|
||||
mod polygonal_feature_map;
|
||||
#[cfg(feature = "dim3")]
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user