Skip to content

Commit 1d0db7e

Browse files
committed
Implement interaction groups test mode and cofficient combine rule
update fix docs cargo format fix update feedback update Update CHANGELOG.md
1 parent 76357e3 commit 1d0db7e

7 files changed

Lines changed: 79 additions & 19 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88

99
### Added
1010

11+
- `InteractionTestMode`: Specifies which method should be used to test interactions. Supports `AND` and `OR`.
12+
- `CoefficientCombineRule::Sum` - Adds the two coefficients and does a clamp to have at most 1.
1113
- `RigidBodySet` and `ColliderSet` have a new constructor `with_capacity`.
1214

1315
### Modified
1416

1517
- `InteractionGroups` default value for `memberships` is now `GROUP_1` (#706)
1618
- `ImpulseJointSet::get_mut` has a new parameter `wake_up: bool`, to wake up connected bodies.
19+
- `InteractionGroups` struct now contains `InteractionTestMode`. Continues [rapier/pull/170](https://github.com/dimforge/rapier/pull/170) for [rapier/issues/622](https://github.com/dimforge/rapier/issues/622)
20+
- `InteractionGroups` constructor now requires an `InteractionTestMode` parameter. If you want same behaviour as before, use `InteractionTestMode::AND` (eg. `InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::AND)`)
21+
- `CoefficientCombineRule::Min` - now makes sure it uses a non zero value as result by using `coeff1.min(coeff2).abs()`
1722

1823
## v0.22.0 (20 July 2024)
1924

examples2d/collision_groups2.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ pub fn init_world(testbed: &mut Testbed) {
2424
/*
2525
* Setup groups
2626
*/
27-
const GREEN_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_1, Group::GROUP_1);
28-
const BLUE_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_2, Group::GROUP_2);
27+
const GREEN_GROUP: InteractionGroups =
28+
InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::AND);
29+
const BLUE_GROUP: InteractionGroups =
30+
InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::AND);
2931

3032
/*
3133
* A green floor that will collide with the GREEN group only.

examples3d/collision_groups3.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ pub fn init_world(testbed: &mut Testbed) {
2424
/*
2525
* Setup groups
2626
*/
27-
const GREEN_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_1, Group::GROUP_1);
28-
const BLUE_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_2, Group::GROUP_2);
27+
const GREEN_GROUP: InteractionGroups =
28+
InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::AND);
29+
const BLUE_GROUP: InteractionGroups =
30+
InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::AND);
2931

3032
/*
3133
* A green floor that will collide with the GREEN group only.

examples3d/vehicle_joints3.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ pub fn init_world(testbed: &mut Testbed) {
5353

5454
let body_co = ColliderBuilder::cuboid(0.65, 0.3, 0.9)
5555
.density(100.0)
56-
.collision_groups(InteractionGroups::new(CAR_GROUP, !CAR_GROUP));
56+
.collision_groups(InteractionGroups::new(
57+
CAR_GROUP,
58+
!CAR_GROUP,
59+
InteractionTestMode::AND,
60+
));
5761
let body_rb = RigidBodyBuilder::dynamic()
5862
.position(body_position.into())
5963
.build();
@@ -85,7 +89,11 @@ pub fn init_world(testbed: &mut Testbed) {
8589
// is mathematically simpler than a cylinder and cheaper to compute for collision-detection.
8690
let wheel_co = ColliderBuilder::ball(wheel_radius)
8791
.density(100.0)
88-
.collision_groups(InteractionGroups::new(CAR_GROUP, !CAR_GROUP))
92+
.collision_groups(InteractionGroups::new(
93+
CAR_GROUP,
94+
!CAR_GROUP,
95+
InteractionTestMode::AND,
96+
))
8997
.friction(1.0);
9098
let wheel_rb = RigidBodyBuilder::dynamic().position(wheel_center.into());
9199
let wheel_handle = bodies.insert(wheel_rb);

src/dynamics/coefficient_combine_rule.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub enum CoefficientCombineRule {
1919
Multiply,
2020
/// The greatest coefficient is chosen.
2121
Max,
22+
/// The sum of the two coefficients.
23+
Sum,
2224
}
2325

2426
impl CoefficientCombineRule {
@@ -27,8 +29,10 @@ impl CoefficientCombineRule {
2729

2830
match effective_rule {
2931
0 => (coeff1 + coeff2) / 2.0,
30-
1 => coeff1.min(coeff2),
32+
1 => coeff1.min(coeff2).abs(),
3133
2 => coeff1 * coeff2,
34+
4 => (coeff1 + coeff2).clamp(0.0, 1.0),
35+
// 3 is missing as Max is the default one in case of mismatch.
3236
_ => coeff1.max(coeff2),
3337
}
3438
}

src/geometry/interaction_groups.rs

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77
/// - The interaction groups filter.
88
///
99
/// An interaction is allowed between two filters `a` and `b` when two conditions
10-
/// are met simultaneously:
10+
/// are met simultaneously for [`InteractionTestMode::AND`] or individually for [`InteractionTestMode::OR`]::
1111
/// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`.
1212
/// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`.
1313
///
14-
/// In other words, interactions are allowed between two filter iff. the following condition is met:
15-
/// ```ignore
16-
/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0
14+
/// In other words, interactions are allowed between two filter iff. the following condition is met
15+
/// for [`InteractionTestMode::AND`]:
16+
/// ```rust
17+
/// (self.memberships.bits() & rhs.filter.bits()) != 0 && (rhs.memberships.bits() & self.filter.bits()) != 0
18+
/// ```
19+
/// or for [`InteractionTestMode::OR`]:
20+
/// ```rust
21+
/// (self.memberships.bits() & rhs.filter.bits()) != 0 || (rhs.memberships.bits() & self.filter.bits()) != 0
1722
/// ```
1823
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
1924
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -23,25 +28,39 @@ pub struct InteractionGroups {
2328
pub memberships: Group,
2429
/// Groups filter.
2530
pub filter: Group,
31+
/// Interaction test mode
32+
pub test_mode: InteractionTestMode,
33+
}
34+
35+
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
36+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)]
37+
/// Specifies which method should be used to test interactions
38+
pub enum InteractionTestMode {
39+
/// Use [`InteractionGroups::test_and`].
40+
#[default]
41+
AND,
42+
/// Use [`InteractionGroups::test_or`].
43+
OR,
2644
}
2745

2846
impl InteractionGroups {
2947
/// Initializes with the given interaction groups and interaction mask.
30-
pub const fn new(memberships: Group, filter: Group) -> Self {
48+
pub const fn new(memberships: Group, filter: Group, test_mode: InteractionTestMode) -> Self {
3149
Self {
3250
memberships,
3351
filter,
52+
test_mode,
3453
}
3554
}
3655

3756
/// Allow interaction with everything.
3857
pub const fn all() -> Self {
39-
Self::new(Group::ALL, Group::ALL)
58+
Self::new(Group::ALL, Group::ALL, InteractionTestMode::AND)
4059
}
4160

4261
/// Prevent all interactions.
4362
pub const fn none() -> Self {
44-
Self::new(Group::NONE, Group::NONE)
63+
Self::new(Group::NONE, Group::NONE, InteractionTestMode::AND)
4564
}
4665

4766
/// Sets the group this filter is part of.
@@ -59,21 +78,41 @@ impl InteractionGroups {
5978
/// Check if interactions should be allowed based on the interaction memberships and filter.
6079
///
6180
/// An interaction is allowed iff. the memberships of `self` contain at least one bit set to 1 in common
62-
/// with the filter of `rhs`, and vice-versa.
81+
/// with the filter of `rhs`, **and** vice-versa.
6382
#[inline]
64-
pub const fn test(self, rhs: Self) -> bool {
65-
// NOTE: since const ops is not stable, we have to convert `Group` into u32
66-
// to use & operator in const context.
83+
pub const fn test_and(self, rhs: Self) -> bool {
6784
(self.memberships.bits() & rhs.filter.bits()) != 0
6885
&& (rhs.memberships.bits() & self.filter.bits()) != 0
6986
}
87+
88+
/// Check if interactions should be allowed based on the interaction memberships and filter.
89+
///
90+
/// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common
91+
/// with the mask of `rhs`, **or** vice-versa.
92+
#[inline]
93+
pub const fn test_or(self, rhs: Self) -> bool {
94+
(self.memberships.bits() & rhs.filter.bits()) != 0
95+
|| (rhs.memberships.bits() & self.filter.bits()) != 0
96+
}
97+
98+
/// Check if interactions should be allowed based on the interaction memberships and filter.
99+
///
100+
/// See [`InteractionTestMode`] for more info.
101+
#[inline]
102+
pub const fn test(self, rhs: Self) -> bool {
103+
match self.test_mode {
104+
InteractionTestMode::AND => self.test_and(rhs),
105+
InteractionTestMode::OR => self.test_or(rhs),
106+
}
107+
}
70108
}
71109

72110
impl Default for InteractionGroups {
73111
fn default() -> Self {
74112
Self {
75113
memberships: Group::GROUP_1,
76114
filter: Group::ALL,
115+
test_mode: InteractionTestMode::AND,
77116
}
78117
}
79118
}

src/geometry/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub use self::contact_pair::{
1111
pub use self::interaction_graph::{
1212
ColliderGraphIndex, InteractionGraph, RigidBodyGraphIndex, TemporaryInteractionIndex,
1313
};
14-
pub use self::interaction_groups::{Group, InteractionGroups};
14+
pub use self::interaction_groups::{Group, InteractionGroups, InteractionTestMode};
1515
pub use self::mesh_converter::{MeshConverter, MeshConverterError};
1616
pub use self::narrow_phase::NarrowPhase;
1717

0 commit comments

Comments
 (0)