Merge pull request #43 from dimforge/interaction_groups
Add collision filtering based in bit masks
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use rapier_testbed2d::Testbed;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
mod add_remove2;
|
mod add_remove2;
|
||||||
|
mod collision_groups2;
|
||||||
mod debug_box_ball2;
|
mod debug_box_ball2;
|
||||||
mod heightfield2;
|
mod heightfield2;
|
||||||
mod joints2;
|
mod joints2;
|
||||||
@@ -52,6 +53,7 @@ pub fn main() {
|
|||||||
|
|
||||||
let mut builders: Vec<(_, fn(&mut Testbed))> = vec![
|
let mut builders: Vec<(_, fn(&mut Testbed))> = vec![
|
||||||
("Add remove", add_remove2::init_world),
|
("Add remove", add_remove2::init_world),
|
||||||
|
("Collision groups", collision_groups2::init_world),
|
||||||
("Heightfield", heightfield2::init_world),
|
("Heightfield", heightfield2::init_world),
|
||||||
("Joints", joints2::init_world),
|
("Joints", joints2::init_world),
|
||||||
("Platform", platform2::init_world),
|
("Platform", platform2::init_world),
|
||||||
|
|||||||
98
examples2d/collision_groups2.rs
Normal file
98
examples2d/collision_groups2.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use na::{Point2, Point3};
|
||||||
|
use rapier2d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet};
|
||||||
|
use rapier2d::geometry::{ColliderBuilder, ColliderSet, InteractionGroups};
|
||||||
|
use rapier_testbed2d::Testbed;
|
||||||
|
|
||||||
|
pub fn init_world(testbed: &mut Testbed) {
|
||||||
|
/*
|
||||||
|
* World
|
||||||
|
*/
|
||||||
|
let mut bodies = RigidBodySet::new();
|
||||||
|
let mut colliders = ColliderSet::new();
|
||||||
|
let joints = JointSet::new();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ground
|
||||||
|
*/
|
||||||
|
let ground_size = 5.0;
|
||||||
|
let ground_height = 0.1;
|
||||||
|
|
||||||
|
let rigid_body = RigidBodyBuilder::new_static()
|
||||||
|
.translation(0.0, -ground_height)
|
||||||
|
.build();
|
||||||
|
let floor_handle = bodies.insert(rigid_body);
|
||||||
|
let collider = ColliderBuilder::cuboid(ground_size, ground_height).build();
|
||||||
|
colliders.insert(collider, floor_handle, &mut bodies);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup groups
|
||||||
|
*/
|
||||||
|
const GREEN_GROUP: InteractionGroups = InteractionGroups::new(0b01, 0b01);
|
||||||
|
const BLUE_GROUP: InteractionGroups = InteractionGroups::new(0b10, 0b10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A green floor that will collide with the GREEN group only.
|
||||||
|
*/
|
||||||
|
let green_floor = ColliderBuilder::cuboid(1.0, 0.1)
|
||||||
|
.translation(0.0, 1.0)
|
||||||
|
.collision_groups(GREEN_GROUP)
|
||||||
|
.build();
|
||||||
|
let green_collider_handle = colliders.insert(green_floor, floor_handle, &mut bodies);
|
||||||
|
|
||||||
|
testbed.set_collider_initial_color(green_collider_handle, Point3::new(0.0, 1.0, 0.0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A blue floor that will collide with the BLUE group only.
|
||||||
|
*/
|
||||||
|
let blue_floor = ColliderBuilder::cuboid(1.0, 0.1)
|
||||||
|
.translation(0.0, 2.0)
|
||||||
|
.collision_groups(BLUE_GROUP)
|
||||||
|
.build();
|
||||||
|
let blue_collider_handle = colliders.insert(blue_floor, floor_handle, &mut bodies);
|
||||||
|
|
||||||
|
testbed.set_collider_initial_color(blue_collider_handle, Point3::new(0.0, 0.0, 1.0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the cubes
|
||||||
|
*/
|
||||||
|
let num = 8;
|
||||||
|
let rad = 0.1;
|
||||||
|
|
||||||
|
let shift = rad * 2.0;
|
||||||
|
let centerx = shift * (num / 2) as f32;
|
||||||
|
let centery = 2.5;
|
||||||
|
|
||||||
|
for j in 0usize..4 {
|
||||||
|
for i in 0..num {
|
||||||
|
let x = i as f32 * shift - centerx;
|
||||||
|
let y = j as f32 * shift + centery;
|
||||||
|
|
||||||
|
// Alternate between the green and blue groups.
|
||||||
|
let (group, color) = if i % 2 == 0 {
|
||||||
|
(GREEN_GROUP, Point3::new(0.0, 1.0, 0.0))
|
||||||
|
} else {
|
||||||
|
(BLUE_GROUP, Point3::new(0.0, 0.0, 1.0))
|
||||||
|
};
|
||||||
|
|
||||||
|
let rigid_body = RigidBodyBuilder::new_dynamic().translation(x, y).build();
|
||||||
|
let handle = bodies.insert(rigid_body);
|
||||||
|
let collider = ColliderBuilder::cuboid(rad, rad)
|
||||||
|
.collision_groups(group)
|
||||||
|
.build();
|
||||||
|
colliders.insert(collider, handle, &mut bodies);
|
||||||
|
|
||||||
|
testbed.set_body_color(handle, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the testbed.
|
||||||
|
*/
|
||||||
|
testbed.set_world(bodies, colliders, joints);
|
||||||
|
testbed.look_at(Point2::new(0.0, 1.0), 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let testbed = Testbed::from_builders(0, vec![("Boxes", init_world)]);
|
||||||
|
testbed.run()
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use rapier_testbed3d::Testbed;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
mod add_remove3;
|
mod add_remove3;
|
||||||
|
mod collision_groups3;
|
||||||
mod compound3;
|
mod compound3;
|
||||||
mod debug_boxes3;
|
mod debug_boxes3;
|
||||||
mod debug_cylinder3;
|
mod debug_cylinder3;
|
||||||
@@ -65,6 +66,7 @@ pub fn main() {
|
|||||||
let mut builders: Vec<(_, fn(&mut Testbed))> = vec![
|
let mut builders: Vec<(_, fn(&mut Testbed))> = vec![
|
||||||
("Add remove", add_remove3::init_world),
|
("Add remove", add_remove3::init_world),
|
||||||
("Primitives", primitives3::init_world),
|
("Primitives", primitives3::init_world),
|
||||||
|
("Collision groups", collision_groups3::init_world),
|
||||||
("Compound", compound3::init_world),
|
("Compound", compound3::init_world),
|
||||||
("Domino", domino3::init_world),
|
("Domino", domino3::init_world),
|
||||||
("Heightfield", heightfield3::init_world),
|
("Heightfield", heightfield3::init_world),
|
||||||
|
|||||||
102
examples3d/collision_groups3.rs
Normal file
102
examples3d/collision_groups3.rs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
use na::Point3;
|
||||||
|
use rapier3d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet};
|
||||||
|
use rapier3d::geometry::{ColliderBuilder, ColliderSet, InteractionGroups};
|
||||||
|
use rapier_testbed3d::Testbed;
|
||||||
|
|
||||||
|
pub fn init_world(testbed: &mut Testbed) {
|
||||||
|
/*
|
||||||
|
* World
|
||||||
|
*/
|
||||||
|
let mut bodies = RigidBodySet::new();
|
||||||
|
let mut colliders = ColliderSet::new();
|
||||||
|
let joints = JointSet::new();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ground
|
||||||
|
*/
|
||||||
|
let ground_size = 5.0;
|
||||||
|
let ground_height = 0.1;
|
||||||
|
|
||||||
|
let rigid_body = RigidBodyBuilder::new_static()
|
||||||
|
.translation(0.0, -ground_height, 0.0)
|
||||||
|
.build();
|
||||||
|
let floor_handle = bodies.insert(rigid_body);
|
||||||
|
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size).build();
|
||||||
|
colliders.insert(collider, floor_handle, &mut bodies);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup groups
|
||||||
|
*/
|
||||||
|
const GREEN_GROUP: InteractionGroups = InteractionGroups::new(0b01, 0b01);
|
||||||
|
const BLUE_GROUP: InteractionGroups = InteractionGroups::new(0b10, 0b10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A green floor that will collide with the GREEN group only.
|
||||||
|
*/
|
||||||
|
let green_floor = ColliderBuilder::cuboid(1.0, 0.1, 1.0)
|
||||||
|
.translation(0.0, 1.0, 0.0)
|
||||||
|
.collision_groups(GREEN_GROUP)
|
||||||
|
.build();
|
||||||
|
let green_collider_handle = colliders.insert(green_floor, floor_handle, &mut bodies);
|
||||||
|
|
||||||
|
testbed.set_collider_initial_color(green_collider_handle, Point3::new(0.0, 1.0, 0.0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A blue floor that will collide with the BLUE group only.
|
||||||
|
*/
|
||||||
|
let blue_floor = ColliderBuilder::cuboid(1.0, 0.1, 1.0)
|
||||||
|
.translation(0.0, 2.0, 0.0)
|
||||||
|
.collision_groups(BLUE_GROUP)
|
||||||
|
.build();
|
||||||
|
let blue_collider_handle = colliders.insert(blue_floor, floor_handle, &mut bodies);
|
||||||
|
|
||||||
|
testbed.set_collider_initial_color(blue_collider_handle, Point3::new(0.0, 0.0, 1.0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the cubes
|
||||||
|
*/
|
||||||
|
let num = 8;
|
||||||
|
let rad = 0.1;
|
||||||
|
|
||||||
|
let shift = rad * 2.0;
|
||||||
|
let centerx = shift * (num / 2) as f32;
|
||||||
|
let centery = 2.5;
|
||||||
|
let centerz = shift * (num / 2) as f32;
|
||||||
|
|
||||||
|
for j in 0usize..4 {
|
||||||
|
for i in 0..num {
|
||||||
|
for k in 0usize..num {
|
||||||
|
let x = i as f32 * shift - centerx;
|
||||||
|
let y = j as f32 * shift + centery;
|
||||||
|
let z = k as f32 * shift - centerz;
|
||||||
|
|
||||||
|
// Alternate between the green and blue groups.
|
||||||
|
let (group, color) = if k % 2 == 0 {
|
||||||
|
(GREEN_GROUP, Point3::new(0.0, 1.0, 0.0))
|
||||||
|
} else {
|
||||||
|
(BLUE_GROUP, Point3::new(0.0, 0.0, 1.0))
|
||||||
|
};
|
||||||
|
|
||||||
|
let rigid_body = RigidBodyBuilder::new_dynamic().translation(x, y, z).build();
|
||||||
|
let handle = bodies.insert(rigid_body);
|
||||||
|
let collider = ColliderBuilder::cuboid(rad, rad, rad)
|
||||||
|
.collision_groups(group)
|
||||||
|
.build();
|
||||||
|
colliders.insert(collider, handle, &mut bodies);
|
||||||
|
|
||||||
|
testbed.set_body_color(handle, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the testbed.
|
||||||
|
*/
|
||||||
|
testbed.set_world(bodies, colliders, joints);
|
||||||
|
testbed.look_at(Point3::new(10.0, 10.0, 10.0), Point3::origin());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let testbed = Testbed::from_builders(0, vec![("Boxes", init_world)]);
|
||||||
|
testbed.run()
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet};
|
use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet};
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Proximity,
|
Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph,
|
||||||
Segment, Shape, ShapeType, Triangle, Trimesh,
|
InteractionGroups, Proximity, Segment, Shape, ShapeType, Triangle, Trimesh,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
use crate::geometry::{Cone, Cylinder, RoundCylinder};
|
use crate::geometry::{Cone, Cylinder, RoundCylinder};
|
||||||
@@ -203,6 +203,8 @@ pub struct Collider {
|
|||||||
pub friction: f32,
|
pub friction: f32,
|
||||||
/// 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) 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,
|
||||||
@@ -255,6 +257,16 @@ impl Collider {
|
|||||||
&self.delta
|
&self.delta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The collision groups used by this collider.
|
||||||
|
pub fn collision_groups(&self) -> InteractionGroups {
|
||||||
|
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
|
||||||
@@ -298,8 +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.
|
||||||
|
pub collision_groups: InteractionGroups,
|
||||||
|
/// The solver groups for the collider being built.
|
||||||
|
pub solver_groups: InteractionGroups,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColliderBuilder {
|
impl ColliderBuilder {
|
||||||
@@ -313,6 +329,8 @@ impl ColliderBuilder {
|
|||||||
delta: Isometry::identity(),
|
delta: Isometry::identity(),
|
||||||
is_sensor: false,
|
is_sensor: false,
|
||||||
user_data: 0,
|
user_data: 0,
|
||||||
|
collision_groups: InteractionGroups::all(),
|
||||||
|
solver_groups: InteractionGroups::all(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,12 +436,30 @@ impl ColliderBuilder {
|
|||||||
0.5
|
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 {
|
pub fn user_data(mut self, data: u128) -> Self {
|
||||||
self.user_data = data;
|
self.user_data = data;
|
||||||
self
|
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 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;
|
||||||
@@ -505,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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
60
src/geometry/interaction_groups.rs
Normal file
60
src/geometry/interaction_groups.rs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#[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:
|
||||||
|
/// ```ignore
|
||||||
|
/// ((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0
|
||||||
|
/// ```
|
||||||
|
pub struct InteractionGroups(pub u32);
|
||||||
|
|
||||||
|
impl InteractionGroups {
|
||||||
|
/// Initializes with the given interaction groups and interaction mask.
|
||||||
|
pub const fn new(groups: u16, masks: u16) -> Self {
|
||||||
|
Self::none().with_groups(groups).with_mask(masks)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allow interaction with everything.
|
||||||
|
pub const fn all() -> Self {
|
||||||
|
Self(u32::MAX)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prevent all interactions.
|
||||||
|
pub const fn none() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the group this filter is part of.
|
||||||
|
pub const fn with_groups(self, groups: u16) -> Self {
|
||||||
|
Self((self.0 & 0x0000ffff) | ((groups as u32) << 16))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the interaction mask of this filter.
|
||||||
|
pub const 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.
|
||||||
|
#[inline]
|
||||||
|
pub const 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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")]
|
||||||
@@ -70,6 +70,7 @@ pub(crate) use self::polyhedron_feature3d::PolyhedronFace;
|
|||||||
pub(crate) use self::waabb::{WRay, WAABB};
|
pub(crate) use self::waabb::{WRay, WAABB};
|
||||||
pub(crate) use self::wquadtree::WQuadtree;
|
pub(crate) use self::wquadtree::WQuadtree;
|
||||||
//pub(crate) use self::z_order::z_cmp_floats;
|
//pub(crate) use self::z_order::z_cmp_floats;
|
||||||
|
pub use self::interaction_groups::InteractionGroups;
|
||||||
pub use self::shape::{Shape, ShapeType};
|
pub use self::shape::{Shape, ShapeType};
|
||||||
|
|
||||||
mod ball;
|
mod ball;
|
||||||
@@ -97,6 +98,7 @@ mod waabb;
|
|||||||
mod wquadtree;
|
mod wquadtree;
|
||||||
//mod z_order;
|
//mod z_order;
|
||||||
mod capsule;
|
mod capsule;
|
||||||
|
mod interaction_groups;
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
mod polygonal_feature_map;
|
mod polygonal_feature_map;
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
|
|||||||
@@ -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")]
|
||||||
@@ -306,6 +306,11 @@ impl NarrowPhase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !co1.collision_groups.test(co2.collision_groups) {
|
||||||
|
// The collision is not allowed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let dispatcher = DefaultProximityDispatcher;
|
let dispatcher = DefaultProximityDispatcher;
|
||||||
if pair.detector.is_none() {
|
if pair.detector.is_none() {
|
||||||
// We need a redispatch for this detector.
|
// We need a redispatch for this detector.
|
||||||
@@ -329,69 +334,6 @@ impl NarrowPhase {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.detect_proximity(context, events);
|
.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(
|
pub(crate) fn compute_contacts(
|
||||||
@@ -417,6 +359,11 @@ impl NarrowPhase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !co1.collision_groups.test(co2.collision_groups) {
|
||||||
|
// The collision is not allowed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let dispatcher = DefaultContactDispatcher;
|
let dispatcher = DefaultContactDispatcher;
|
||||||
if pair.generator.is_none() {
|
if pair.generator.is_none() {
|
||||||
// We need a redispatch for this generator.
|
// We need a redispatch for this generator.
|
||||||
@@ -427,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
|
||||||
@@ -440,69 +394,6 @@ impl NarrowPhase {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.generate_contacts(context, events);
|
.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.
|
/// Retrieve all the interactions with at least one contact point, happening between two active bodies.
|
||||||
@@ -522,7 +413,8 @@ impl NarrowPhase {
|
|||||||
for manifold in &mut inter.weight.manifolds {
|
for manifold in &mut inter.weight.manifolds {
|
||||||
let rb1 = &bodies[manifold.body_pair.body1];
|
let rb1 = &bodies[manifold.body_pair.body1];
|
||||||
let rb2 = &bodies[manifold.body_pair.body2];
|
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())
|
&& (!rb1.is_dynamic() || !rb1.is_sleeping())
|
||||||
&& (!rb2.is_dynamic() || !rb2.is_sleeping())
|
&& (!rb2.is_dynamic() || !rb2.is_sleeping())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::dynamics::RigidBodySet;
|
use crate::dynamics::RigidBodySet;
|
||||||
use crate::geometry::{Collider, ColliderHandle, ColliderSet, Ray, RayIntersection, WQuadtree};
|
use crate::geometry::{
|
||||||
|
Collider, ColliderHandle, ColliderSet, InteractionGroups, Ray, RayIntersection, WQuadtree,
|
||||||
|
};
|
||||||
|
|
||||||
/// A pipeline for performing queries on all the colliders of a scene.
|
/// A pipeline for performing queries on all the colliders of a scene.
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
@@ -59,6 +61,7 @@ impl QueryPipeline {
|
|||||||
colliders: &'a ColliderSet,
|
colliders: &'a ColliderSet,
|
||||||
ray: &Ray,
|
ray: &Ray,
|
||||||
max_toi: f32,
|
max_toi: f32,
|
||||||
|
groups: InteractionGroups,
|
||||||
) -> Option<(ColliderHandle, &'a Collider, RayIntersection)> {
|
) -> Option<(ColliderHandle, &'a Collider, RayIntersection)> {
|
||||||
// TODO: avoid allocation?
|
// TODO: avoid allocation?
|
||||||
let mut inter = Vec::new();
|
let mut inter = Vec::new();
|
||||||
@@ -69,14 +72,17 @@ impl QueryPipeline {
|
|||||||
|
|
||||||
for handle in inter {
|
for handle in inter {
|
||||||
let collider = &colliders[handle];
|
let collider = &colliders[handle];
|
||||||
if let Some(inter) =
|
if collider.collision_groups.test(groups) {
|
||||||
collider
|
if let Some(inter) = collider.shape().toi_and_normal_with_ray(
|
||||||
.shape()
|
collider.position(),
|
||||||
.toi_and_normal_with_ray(collider.position(), ray, max_toi, true)
|
ray,
|
||||||
{
|
max_toi,
|
||||||
if inter.toi < best {
|
true,
|
||||||
best = inter.toi;
|
) {
|
||||||
result = Some((handle, collider, inter));
|
if inter.toi < best {
|
||||||
|
best = inter.toi;
|
||||||
|
result = Some((handle, collider, inter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,6 +105,7 @@ impl QueryPipeline {
|
|||||||
colliders: &'a ColliderSet,
|
colliders: &'a ColliderSet,
|
||||||
ray: &Ray,
|
ray: &Ray,
|
||||||
max_toi: f32,
|
max_toi: f32,
|
||||||
|
groups: InteractionGroups,
|
||||||
mut callback: impl FnMut(ColliderHandle, &'a Collider, RayIntersection) -> bool,
|
mut callback: impl FnMut(ColliderHandle, &'a Collider, RayIntersection) -> bool,
|
||||||
) {
|
) {
|
||||||
// TODO: avoid allocation?
|
// TODO: avoid allocation?
|
||||||
@@ -107,13 +114,17 @@ impl QueryPipeline {
|
|||||||
|
|
||||||
for handle in inter {
|
for handle in inter {
|
||||||
let collider = &colliders[handle];
|
let collider = &colliders[handle];
|
||||||
if let Some(inter) =
|
|
||||||
collider
|
if collider.collision_groups.test(groups) {
|
||||||
.shape()
|
if let Some(inter) = collider.shape().toi_and_normal_with_ray(
|
||||||
.toi_and_normal_with_ray(collider.position(), ray, max_toi, true)
|
collider.position(),
|
||||||
{
|
ray,
|
||||||
if !callback(handle, collider, inter) {
|
max_toi,
|
||||||
return;
|
true,
|
||||||
|
) {
|
||||||
|
if !callback(handle, collider, inter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ pub struct GraphicsManager {
|
|||||||
#[cfg(feature = "fluids")]
|
#[cfg(feature = "fluids")]
|
||||||
boundary2sn: HashMap<BoundaryHandle, FluidNode>,
|
boundary2sn: HashMap<BoundaryHandle, FluidNode>,
|
||||||
b2color: HashMap<RigidBodyHandle, Point3<f32>>,
|
b2color: HashMap<RigidBodyHandle, Point3<f32>>,
|
||||||
|
c2color: HashMap<ColliderHandle, Point3<f32>>,
|
||||||
b2wireframe: HashMap<RigidBodyHandle, bool>,
|
b2wireframe: HashMap<RigidBodyHandle, bool>,
|
||||||
#[cfg(feature = "fluids")]
|
#[cfg(feature = "fluids")]
|
||||||
f2color: HashMap<FluidHandle, Point3<f32>>,
|
f2color: HashMap<FluidHandle, Point3<f32>>,
|
||||||
@@ -100,6 +101,7 @@ impl GraphicsManager {
|
|||||||
#[cfg(feature = "fluids")]
|
#[cfg(feature = "fluids")]
|
||||||
boundary2sn: HashMap::new(),
|
boundary2sn: HashMap::new(),
|
||||||
b2color: HashMap::new(),
|
b2color: HashMap::new(),
|
||||||
|
c2color: HashMap::new(),
|
||||||
#[cfg(feature = "fluids")]
|
#[cfg(feature = "fluids")]
|
||||||
f2color: HashMap::new(),
|
f2color: HashMap::new(),
|
||||||
ground_color: Point3::new(0.5, 0.5, 0.5),
|
ground_color: Point3::new(0.5, 0.5, 0.5),
|
||||||
@@ -186,6 +188,10 @@ impl GraphicsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_collider_initial_color(&mut self, c: ColliderHandle, color: Point3<f32>) {
|
||||||
|
self.c2color.insert(c, color);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_body_wireframe(&mut self, b: RigidBodyHandle, enabled: bool) {
|
pub fn set_body_wireframe(&mut self, b: RigidBodyHandle, enabled: bool) {
|
||||||
self.b2wireframe.insert(b, enabled);
|
self.b2wireframe.insert(b, enabled);
|
||||||
|
|
||||||
@@ -324,6 +330,7 @@ impl GraphicsManager {
|
|||||||
let mut new_nodes = Vec::new();
|
let mut new_nodes = Vec::new();
|
||||||
|
|
||||||
for collider_handle in bodies[handle].colliders() {
|
for collider_handle in bodies[handle].colliders() {
|
||||||
|
let color = self.c2color.get(collider_handle).copied().unwrap_or(color);
|
||||||
let collider = &colliders[*collider_handle];
|
let collider = &colliders[*collider_handle];
|
||||||
self.add_collider(window, *collider_handle, collider, color, &mut new_nodes);
|
self.add_collider(window, *collider_handle, collider, color, &mut new_nodes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ use rapier::dynamics::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
use rapier::geometry::Ray;
|
use rapier::geometry::Ray;
|
||||||
use rapier::geometry::{BroadPhase, ColliderSet, ContactEvent, NarrowPhase, ProximityEvent};
|
use rapier::geometry::{
|
||||||
|
BroadPhase, ColliderHandle, ColliderSet, ContactEvent, InteractionGroups, NarrowPhase,
|
||||||
|
ProximityEvent,
|
||||||
|
};
|
||||||
use rapier::math::Vector;
|
use rapier::math::Vector;
|
||||||
use rapier::pipeline::{ChannelEventCollector, PhysicsPipeline, QueryPipeline};
|
use rapier::pipeline::{ChannelEventCollector, PhysicsPipeline, QueryPipeline};
|
||||||
#[cfg(feature = "fluids")]
|
#[cfg(feature = "fluids")]
|
||||||
@@ -497,6 +500,10 @@ impl Testbed {
|
|||||||
self.graphics.set_body_color(body, color);
|
self.graphics.set_body_color(body, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_collider_initial_color(&mut self, collider: ColliderHandle, color: Point3<f32>) {
|
||||||
|
self.graphics.set_collider_initial_color(collider, color);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "fluids")]
|
#[cfg(feature = "fluids")]
|
||||||
pub fn set_fluid_color(&mut self, fluid: FluidHandle, color: Point3<f32>) {
|
pub fn set_fluid_color(&mut self, fluid: FluidHandle, color: Point3<f32>) {
|
||||||
self.graphics.set_fluid_color(fluid, color);
|
self.graphics.set_fluid_color(fluid, color);
|
||||||
@@ -1182,10 +1189,12 @@ impl Testbed {
|
|||||||
.camera()
|
.camera()
|
||||||
.unproject(&self.cursor_pos, &na::convert(size));
|
.unproject(&self.cursor_pos, &na::convert(size));
|
||||||
let ray = Ray::new(pos, dir);
|
let ray = Ray::new(pos, dir);
|
||||||
let hit = self
|
let hit = self.physics.query_pipeline.cast_ray(
|
||||||
.physics
|
&self.physics.colliders,
|
||||||
.query_pipeline
|
&ray,
|
||||||
.cast_ray(&self.physics.colliders, &ray, f32::MAX);
|
f32::MAX,
|
||||||
|
InteractionGroups::all(),
|
||||||
|
);
|
||||||
|
|
||||||
if let Some((_, collider, _)) = hit {
|
if let Some((_, collider, _)) = hit {
|
||||||
if self.physics.bodies[collider.parent()].is_dynamic() {
|
if self.physics.bodies[collider.parent()].is_dynamic() {
|
||||||
|
|||||||
Reference in New Issue
Block a user