From 0db7c72c3e8e1525d6a5c95966058d38c8131dce Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Sun, 22 Sep 2024 23:23:57 +0200 Subject: [PATCH 01/14] Implement interaction groups test mode and cofficient combine rule update fix docs cargo format fix update feedback update Update CHANGELOG.md ignore line for error docs fix update --- CHANGELOG.md | 5 ++ examples2d/collision_groups2.rs | 6 ++- examples3d/collision_groups3.rs | 6 ++- examples3d/vehicle_joints3.rs | 12 ++++- src/dynamics/coefficient_combine_rule.rs | 6 ++- src/geometry/interaction_groups.rs | 59 ++++++++++++++++++++---- src/geometry/mod.rs | 2 +- 7 files changed, 78 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88bef4883..eb272d390 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,17 @@ ### Added +- `InteractionTestMode`: Specifies which method should be used to test interactions. Supports `AND` and `OR`. +- `CoefficientCombineRule::Sum` - Adds the two coefficients and does a clamp to have at most 1. - `RigidBodySet` and `ColliderSet` have a new constructor `with_capacity`. ### Modified - `InteractionGroups` default value for `memberships` is now `GROUP_1` (#706) - `ImpulseJointSet::get_mut` has a new parameter `wake_up: bool`, to wake up connected bodies. +- `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) +- `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)`) +- `CoefficientCombineRule::Min` - now makes sure it uses a non zero value as result by using `coeff1.min(coeff2).abs()` ## v0.22.0 (20 July 2024) diff --git a/examples2d/collision_groups2.rs b/examples2d/collision_groups2.rs index f84f139ab..2784c9200 100644 --- a/examples2d/collision_groups2.rs +++ b/examples2d/collision_groups2.rs @@ -24,8 +24,10 @@ pub fn init_world(testbed: &mut Testbed) { /* * Setup groups */ - const GREEN_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_1, Group::GROUP_1); - const BLUE_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_2, Group::GROUP_2); + const GREEN_GROUP: InteractionGroups = + InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::AND); + const BLUE_GROUP: InteractionGroups = + InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::AND); /* * A green floor that will collide with the GREEN group only. diff --git a/examples3d/collision_groups3.rs b/examples3d/collision_groups3.rs index b9eea7920..7c8f35774 100644 --- a/examples3d/collision_groups3.rs +++ b/examples3d/collision_groups3.rs @@ -24,8 +24,10 @@ pub fn init_world(testbed: &mut Testbed) { /* * Setup groups */ - const GREEN_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_1, Group::GROUP_1); - const BLUE_GROUP: InteractionGroups = InteractionGroups::new(Group::GROUP_2, Group::GROUP_2); + const GREEN_GROUP: InteractionGroups = + InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::AND); + const BLUE_GROUP: InteractionGroups = + InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::AND); /* * A green floor that will collide with the GREEN group only. diff --git a/examples3d/vehicle_joints3.rs b/examples3d/vehicle_joints3.rs index 517bd9cb9..fd2633fad 100644 --- a/examples3d/vehicle_joints3.rs +++ b/examples3d/vehicle_joints3.rs @@ -53,7 +53,11 @@ pub fn init_world(testbed: &mut Testbed) { let body_co = ColliderBuilder::cuboid(0.65, 0.3, 0.9) .density(100.0) - .collision_groups(InteractionGroups::new(CAR_GROUP, !CAR_GROUP)); + .collision_groups(InteractionGroups::new( + CAR_GROUP, + !CAR_GROUP, + InteractionTestMode::AND, + )); let body_rb = RigidBodyBuilder::dynamic() .position(body_position.into()) .build(); @@ -85,7 +89,11 @@ pub fn init_world(testbed: &mut Testbed) { // is mathematically simpler than a cylinder and cheaper to compute for collision-detection. let wheel_co = ColliderBuilder::ball(wheel_radius) .density(100.0) - .collision_groups(InteractionGroups::new(CAR_GROUP, !CAR_GROUP)) + .collision_groups(InteractionGroups::new( + CAR_GROUP, + !CAR_GROUP, + InteractionTestMode::AND, + )) .friction(1.0); let wheel_rb = RigidBodyBuilder::dynamic().position(wheel_center.into()); let wheel_handle = bodies.insert(wheel_rb); diff --git a/src/dynamics/coefficient_combine_rule.rs b/src/dynamics/coefficient_combine_rule.rs index 9f99b7daf..6d4a6a1fa 100644 --- a/src/dynamics/coefficient_combine_rule.rs +++ b/src/dynamics/coefficient_combine_rule.rs @@ -19,6 +19,8 @@ pub enum CoefficientCombineRule { Multiply, /// The greatest coefficient is chosen. Max, + /// The sum of the two coefficients. + Sum, } impl CoefficientCombineRule { @@ -27,8 +29,10 @@ impl CoefficientCombineRule { match effective_rule { 0 => (coeff1 + coeff2) / 2.0, - 1 => coeff1.min(coeff2), + 1 => coeff1.min(coeff2).abs(), 2 => coeff1 * coeff2, + 4 => (coeff1 + coeff2).clamp(0.0, 1.0), + // 3 is missing as Max is the default one in case of mismatch. _ => coeff1.max(coeff2), } } diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index d8941f752..83b341b55 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -7,13 +7,18 @@ /// - The interaction groups filter. /// /// An interaction is allowed between two filters `a` and `b` when two conditions -/// are met simultaneously: +/// are met simultaneously for [`InteractionTestMode::AND`] or individually for [`InteractionTestMode::OR`]:: /// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`. /// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`. /// -/// In other words, interactions are allowed between two filter iff. the following condition is met: +/// In other words, interactions are allowed between two filter iff. the following condition is met +/// for [`InteractionTestMode::AND`]: /// ```ignore -/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0 +/// (self.memberships.bits() & rhs.filter.bits()) != 0 && (rhs.memberships.bits() & self.filter.bits()) != 0 +/// ``` +/// or for [`InteractionTestMode::OR`]: +/// ```ignore +/// (self.memberships.bits() & rhs.filter.bits()) != 0 || (rhs.memberships.bits() & self.filter.bits()) != 0 /// ``` #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -23,25 +28,39 @@ pub struct InteractionGroups { pub memberships: Group, /// Groups filter. pub filter: Group, + /// Interaction test mode + pub test_mode: InteractionTestMode, +} + +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)] +/// Specifies which method should be used to test interactions +pub enum InteractionTestMode { + /// Use [`InteractionGroups::test_and`]. + #[default] + AND, + /// Use [`InteractionGroups::test_or`]. + OR, } impl InteractionGroups { /// Initializes with the given interaction groups and interaction mask. - pub const fn new(memberships: Group, filter: Group) -> Self { + pub const fn new(memberships: Group, filter: Group, test_mode: InteractionTestMode) -> Self { Self { memberships, filter, + test_mode, } } /// Allow interaction with everything. pub const fn all() -> Self { - Self::new(Group::ALL, Group::ALL) + Self::new(Group::ALL, Group::ALL, InteractionTestMode::AND) } /// Prevent all interactions. pub const fn none() -> Self { - Self::new(Group::NONE, Group::NONE) + Self::new(Group::NONE, Group::NONE, InteractionTestMode::AND) } /// Sets the group this filter is part of. @@ -59,14 +78,33 @@ impl InteractionGroups { /// Check if interactions should be allowed based on the interaction memberships and filter. /// /// An interaction is allowed iff. the memberships of `self` contain at least one bit set to 1 in common - /// with the filter of `rhs`, and vice-versa. + /// with the filter of `rhs`, **and** vice-versa. #[inline] - pub const fn test(self, rhs: Self) -> bool { - // NOTE: since const ops is not stable, we have to convert `Group` into u32 - // to use & operator in const context. + pub const fn test_and(self, rhs: Self) -> bool { (self.memberships.bits() & rhs.filter.bits()) != 0 && (rhs.memberships.bits() & self.filter.bits()) != 0 } + + /// Check if interactions should be allowed based on the interaction memberships and filter. + /// + /// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common + /// with the mask of `rhs`, **or** vice-versa. + #[inline] + pub const fn test_or(self, rhs: Self) -> bool { + (self.memberships.bits() & rhs.filter.bits()) != 0 + || (rhs.memberships.bits() & self.filter.bits()) != 0 + } + + /// Check if interactions should be allowed based on the interaction memberships and filter. + /// + /// See [`InteractionTestMode`] for more info. + #[inline] + pub const fn test(self, rhs: Self) -> bool { + match self.test_mode { + InteractionTestMode::AND => self.test_and(rhs), + InteractionTestMode::OR => self.test_or(rhs), + } + } } impl Default for InteractionGroups { @@ -74,6 +112,7 @@ impl Default for InteractionGroups { Self { memberships: Group::GROUP_1, filter: Group::ALL, + test_mode: InteractionTestMode::AND, } } } diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index ea0c7fbdd..d0d5e9959 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -11,7 +11,7 @@ pub use self::contact_pair::{ pub use self::interaction_graph::{ ColliderGraphIndex, InteractionGraph, RigidBodyGraphIndex, TemporaryInteractionIndex, }; -pub use self::interaction_groups::{Group, InteractionGroups}; +pub use self::interaction_groups::{Group, InteractionGroups, InteractionTestMode}; pub use self::mesh_converter::{MeshConverter, MeshConverterError}; pub use self::narrow_phase::NarrowPhase; From db3c009cb554c1769aa7d74248a172ab97642828 Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Thu, 28 Nov 2024 16:39:39 +0100 Subject: [PATCH 02/14] Update src/geometry/interaction_groups.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Crozet --- src/geometry/interaction_groups.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 83b341b55..7180e5db7 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -100,11 +100,11 @@ impl InteractionGroups { /// See [`InteractionTestMode`] for more info. #[inline] pub const fn test(self, rhs: Self) -> bool { - match self.test_mode { - InteractionTestMode::AND => self.test_and(rhs), - InteractionTestMode::OR => self.test_or(rhs), + if self.test_mode == InteractionTestMode::And || rhs.test_mode == InteractionTestMode::And { + self.test_and(rhs) + } else { + self.test_or(rhs) } - } } impl Default for InteractionGroups { From 9edf3ec3363418a489628d5be4535990db38dee5 Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Thu, 28 Nov 2024 16:39:48 +0100 Subject: [PATCH 03/14] Update src/geometry/interaction_groups.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Crozet --- src/geometry/interaction_groups.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 7180e5db7..c7502f9de 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -38,9 +38,9 @@ pub struct InteractionGroups { pub enum InteractionTestMode { /// Use [`InteractionGroups::test_and`]. #[default] - AND, + And, /// Use [`InteractionGroups::test_or`]. - OR, + Or, } impl InteractionGroups { From d3a741c0dfc578c1de53903d4da9813f0adc6928 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 6 Jan 2025 17:37:38 +0100 Subject: [PATCH 04/14] Add some clarifying comments --- src/dynamics/coefficient_combine_rule.rs | 7 ++++++- src/geometry/interaction_groups.rs | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/dynamics/coefficient_combine_rule.rs b/src/dynamics/coefficient_combine_rule.rs index 6d4a6a1fa..7d0119d93 100644 --- a/src/dynamics/coefficient_combine_rule.rs +++ b/src/dynamics/coefficient_combine_rule.rs @@ -29,7 +29,12 @@ impl CoefficientCombineRule { match effective_rule { 0 => (coeff1 + coeff2) / 2.0, - 1 => coeff1.min(coeff2).abs(), + 1 => { + // Even though coeffs are meant to be positive, godot use-case has negative values. + // We're following their logic here. + // Context: https://github.com/dimforge/rapier/pull/741#discussion_r1862402948 + coeff1.min(coeff2).abs() + } 2 => coeff1 * coeff2, 4 => (coeff1 + coeff2).clamp(0.0, 1.0), // 3 is missing as Max is the default one in case of mismatch. diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index c7502f9de..a28dc821c 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -29,17 +29,23 @@ pub struct InteractionGroups { /// Groups filter. pub filter: Group, /// Interaction test mode + /// + /// In case of different test modes between two [`InteractionGroups`], [`InteractionTestMode::And`] is given priority. pub test_mode: InteractionTestMode, } #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)] -/// Specifies which method should be used to test interactions +/// Specifies which method should be used to test interactions. +/// +/// In case of different test modes between two [`InteractionGroups`], [`InteractionTestMode::And`] is given priority. pub enum InteractionTestMode { /// Use [`InteractionGroups::test_and`]. #[default] And, - /// Use [`InteractionGroups::test_or`]. + /// Use [`InteractionGroups::test_or`], iff. the `rhs` is also [`InteractionTestMode::Or`]. + /// + /// If the `rhs` is not [`InteractionTestMode::Or`], use [`InteractionGroups::test_and`]. Or, } From d59e3c35e52ff56e3fc3f5aba33c744750385b11 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 9 Jan 2025 17:24:06 +0100 Subject: [PATCH 05/14] fix compilation --- src/geometry/interaction_groups.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index a28dc821c..4443c831d 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -105,12 +105,15 @@ impl InteractionGroups { /// /// See [`InteractionTestMode`] for more info. #[inline] - pub const fn test(self, rhs: Self) -> bool { - if self.test_mode == InteractionTestMode::And || rhs.test_mode == InteractionTestMode::And { + pub fn test(self, rhs: Self) -> bool { + if self.test_mode == InteractionTestMode::And { + self.test_and(rhs) + } else if rhs.test_mode == InteractionTestMode::Or { self.test_and(rhs) } else { self.test_or(rhs) } + } } impl Default for InteractionGroups { From a29d80c0594b80ffa168d89ecbc3243147bd8b60 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 13 Jan 2025 09:33:31 +0100 Subject: [PATCH 06/14] better readability for test logic (also fixes it) --- src/geometry/interaction_groups.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 4443c831d..15a14fd55 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -106,12 +106,10 @@ impl InteractionGroups { /// See [`InteractionTestMode`] for more info. #[inline] pub fn test(self, rhs: Self) -> bool { - if self.test_mode == InteractionTestMode::And { - self.test_and(rhs) - } else if rhs.test_mode == InteractionTestMode::Or { - self.test_and(rhs) - } else { - self.test_or(rhs) + match (self.test_mode, rhs.test_mode) { + (InteractionTestMode::And, _) => self.test_and(rhs), + (InteractionTestMode::Or, InteractionTestMode::And) => self.test_and(rhs), + (InteractionTestMode::Or, InteractionTestMode::Or) => self.test_or(rhs), } } } @@ -121,7 +119,7 @@ impl Default for InteractionGroups { Self { memberships: Group::GROUP_1, filter: Group::ALL, - test_mode: InteractionTestMode::AND, + test_mode: InteractionTestMode::And, } } } From 5224669fc202574a94e4d1613b674b5e879168b2 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 13 Jan 2025 09:35:36 +0100 Subject: [PATCH 07/14] fix capitalization of InteractionTestMode --- CHANGELOG.md | 2 +- examples2d/collision_groups2.rs | 4 ++-- examples3d/collision_groups3.rs | 4 ++-- examples3d/vehicle_joints3.rs | 4 ++-- src/geometry/interaction_groups.rs | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 490538366..2eb81eec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ - `ImpulseJointSet::get_mut` has a new parameter `wake_up: bool`, to wake up connected bodies. - Removed unmaintained `instant` in favor of `web-time`. This effectively removes the `wasm-bindgen` transitive dependency as it's no longer needed. - `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) -- `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)`) +- `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)`) - `CoefficientCombineRule::Min` - now makes sure it uses a non zero value as result by using `coeff1.min(coeff2).abs()` ## v0.22.0 (20 July 2024) diff --git a/examples2d/collision_groups2.rs b/examples2d/collision_groups2.rs index 2784c9200..5fea3a24a 100644 --- a/examples2d/collision_groups2.rs +++ b/examples2d/collision_groups2.rs @@ -25,9 +25,9 @@ pub fn init_world(testbed: &mut Testbed) { * Setup groups */ const GREEN_GROUP: InteractionGroups = - InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::AND); + InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::And); const BLUE_GROUP: InteractionGroups = - InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::AND); + InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::And); /* * A green floor that will collide with the GREEN group only. diff --git a/examples3d/collision_groups3.rs b/examples3d/collision_groups3.rs index 7c8f35774..17f2c8525 100644 --- a/examples3d/collision_groups3.rs +++ b/examples3d/collision_groups3.rs @@ -25,9 +25,9 @@ pub fn init_world(testbed: &mut Testbed) { * Setup groups */ const GREEN_GROUP: InteractionGroups = - InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::AND); + InteractionGroups::new(Group::GROUP_1, Group::GROUP_1, InteractionTestMode::And); const BLUE_GROUP: InteractionGroups = - InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::AND); + InteractionGroups::new(Group::GROUP_2, Group::GROUP_2, InteractionTestMode::And); /* * A green floor that will collide with the GREEN group only. diff --git a/examples3d/vehicle_joints3.rs b/examples3d/vehicle_joints3.rs index fd2633fad..315132ea8 100644 --- a/examples3d/vehicle_joints3.rs +++ b/examples3d/vehicle_joints3.rs @@ -56,7 +56,7 @@ pub fn init_world(testbed: &mut Testbed) { .collision_groups(InteractionGroups::new( CAR_GROUP, !CAR_GROUP, - InteractionTestMode::AND, + InteractionTestMode::And, )); let body_rb = RigidBodyBuilder::dynamic() .position(body_position.into()) @@ -92,7 +92,7 @@ pub fn init_world(testbed: &mut Testbed) { .collision_groups(InteractionGroups::new( CAR_GROUP, !CAR_GROUP, - InteractionTestMode::AND, + InteractionTestMode::And, )) .friction(1.0); let wheel_rb = RigidBodyBuilder::dynamic().position(wheel_center.into()); diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 15a14fd55..c8122f501 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -7,16 +7,16 @@ /// - The interaction groups filter. /// /// An interaction is allowed between two filters `a` and `b` when two conditions -/// are met simultaneously for [`InteractionTestMode::AND`] or individually for [`InteractionTestMode::OR`]:: +/// are met simultaneously for [`InteractionTestMode::And`] or individually for [`InteractionTestMode::Or`]:: /// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`. /// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`. /// /// In other words, interactions are allowed between two filter iff. the following condition is met -/// for [`InteractionTestMode::AND`]: +/// for [`InteractionTestMode::And`]: /// ```ignore /// (self.memberships.bits() & rhs.filter.bits()) != 0 && (rhs.memberships.bits() & self.filter.bits()) != 0 /// ``` -/// or for [`InteractionTestMode::OR`]: +/// or for [`InteractionTestMode::Or`]: /// ```ignore /// (self.memberships.bits() & rhs.filter.bits()) != 0 || (rhs.memberships.bits() & self.filter.bits()) != 0 /// ``` @@ -61,12 +61,12 @@ impl InteractionGroups { /// Allow interaction with everything. pub const fn all() -> Self { - Self::new(Group::ALL, Group::ALL, InteractionTestMode::AND) + Self::new(Group::ALL, Group::ALL, InteractionTestMode::And) } /// Prevent all interactions. pub const fn none() -> Self { - Self::new(Group::NONE, Group::NONE, InteractionTestMode::AND) + Self::new(Group::NONE, Group::NONE, InteractionTestMode::And) } /// Sets the group this filter is part of. From 636c01bbbd8b4669bd2e5944b75d681065f216ea Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 13 Jan 2025 09:38:32 +0100 Subject: [PATCH 08/14] re-enabled const --- src/geometry/interaction_groups.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index c8122f501..8a98d48a7 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -105,7 +105,7 @@ impl InteractionGroups { /// /// See [`InteractionTestMode`] for more info. #[inline] - pub fn test(self, rhs: Self) -> bool { + pub const fn test(self, rhs: Self) -> bool { match (self.test_mode, rhs.test_mode) { (InteractionTestMode::And, _) => self.test_and(rhs), (InteractionTestMode::Or, InteractionTestMode::And) => self.test_and(rhs), From d1de2812b2d84019874bf2f2194022c21db98bcc Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Wed, 29 Oct 2025 21:33:52 +0100 Subject: [PATCH 09/14] ad missing comment, update changelog --- CHANGELOG.md | 6 ++---- src/geometry/interaction_groups.rs | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b86990986..fa9e5eac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,10 @@ ## Unreleased -### Modified - - `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) - `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)`) - `CoefficientCombineRule::Min` - now makes sure it uses a non zero value as result by using `coeff1.min(coeff2).abs()` +- `InteractionTestMode`: Specifies which method should be used to test interactions. Supports `AND` and `OR`. +- `CoefficientCombineRule::Sum` - Adds the two coefficients and does a clamp to have at most 1. ## v0.30.1 (17 Oct. 2025) @@ -151,8 +151,6 @@ Notable changes include: ### Added -- `InteractionTestMode`: Specifies which method should be used to test interactions. Supports `AND` and `OR`. -- `CoefficientCombineRule::Sum` - Adds the two coefficients and does a clamp to have at most 1. - `RigidBodySet` and `ColliderSet` have a new constructor `with_capacity`. - Use `profiling` crate to provide helpful profiling information in different tools. - The testbeds have been updated to use `puffin_egui` diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 80e09b597..9d5225e8c 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -120,6 +120,8 @@ impl InteractionGroups { /// with the filter of `rhs`, **and** vice-versa. #[inline] pub const fn test_and(self, rhs: Self) -> bool { + // NOTE: since const ops is not stable, we have to convert `Group` into u32 + // to use & operator in const context. (self.memberships.bits() & rhs.filter.bits()) != 0 && (rhs.memberships.bits() & self.filter.bits()) != 0 } @@ -130,6 +132,8 @@ impl InteractionGroups { /// with the mask of `rhs`, **or** vice-versa. #[inline] pub const fn test_or(self, rhs: Self) -> bool { + // NOTE: since const ops is not stable, we have to convert `Group` into u32 + // to use & operator in const context. (self.memberships.bits() & rhs.filter.bits()) != 0 || (rhs.memberships.bits() & self.filter.bits()) != 0 } From 8ec08f53572bdeace39600a5177f398ad9a445b8 Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Wed, 29 Oct 2025 21:34:44 +0100 Subject: [PATCH 10/14] small padding issue --- src/geometry/interaction_groups.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 9d5225e8c..a88cede22 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -40,7 +40,7 @@ /// // Enemy collider: in group 2, collides with group 1 /// let enemy_groups = InteractionGroups::new( /// Group::GROUP_2, // I am in group 2 -/// Group::GROUP_1, // I collide with group 1 +/// Group::GROUP_1, // I collide with group 1 /// InteractionTestMode::And /// ); /// From 270e8c7d85f7015a1c40547284c149a519b88aa7 Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Wed, 29 Oct 2025 21:41:48 +0100 Subject: [PATCH 11/14] fix docs issue --- src/geometry/interaction_groups.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index a88cede22..54a3e0481 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -28,7 +28,7 @@ /// /// # Example /// -/// ``` +/// ```rust /// # use rapier3d::geometry::{InteractionGroups, Group}; /// // Player collider: in group 1, collides with groups 2 and 3 /// let player_groups = InteractionGroups::new( From b730a8cae525db6853fb62fdd6a73c60887d40bd Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Wed, 29 Oct 2025 21:45:07 +0100 Subject: [PATCH 12/14] mark it as code --- src/geometry/interaction_groups.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 54a3e0481..4b9f8134f 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -13,13 +13,13 @@ /// /// In other words, interactions are allowed between two colliders iff. the following condition is met /// for [`InteractionTestMode::And`]: -/// ```ignore +/// ```rust /// (self.memberships.bits() & rhs.filter.bits()) != 0 && (rhs.memberships.bits() & self.filter.bits()) != 0 /// ``` /// or for [`InteractionTestMode::Or`]: -/// ```ignore +/// ```rust /// (self.memberships.bits() & rhs.filter.bits()) != 0 || (rhs.memberships.bits() & self.filter.bits()) != 0 -/// +/// ``` /// # Common use cases /// /// - **Player vs. Enemy bullets**: Players in group 1, enemies in group 2. Player bullets From 1a560730add7a53707a514bca16bcd063cde2486 Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Wed, 29 Oct 2025 22:07:46 +0100 Subject: [PATCH 13/14] use ignore again. --- src/geometry/interaction_groups.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 4b9f8134f..e43637986 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -13,11 +13,11 @@ /// /// In other words, interactions are allowed between two colliders iff. the following condition is met /// for [`InteractionTestMode::And`]: -/// ```rust +/// ```ignore /// (self.memberships.bits() & rhs.filter.bits()) != 0 && (rhs.memberships.bits() & self.filter.bits()) != 0 /// ``` /// or for [`InteractionTestMode::Or`]: -/// ```rust +/// ```ignore /// (self.memberships.bits() & rhs.filter.bits()) != 0 || (rhs.memberships.bits() & self.filter.bits()) != 0 /// ``` /// # Common use cases @@ -28,12 +28,12 @@ /// /// # Example /// -/// ```rust +/// ```ignore /// # use rapier3d::geometry::{InteractionGroups, Group}; /// // Player collider: in group 1, collides with groups 2 and 3 /// let player_groups = InteractionGroups::new( -/// Group::GROUP_1, // I am in group 1 -/// Group::GROUP_2, | Group::GROUP_3 // I collide with groups 2 and 3 +/// Group::GROUP_1, // I am in group 1 +/// Group::GROUP_2, | Group::GROUP_3, // I collide with groups 2 and 3 /// InteractionTestMode::And /// ); /// From 72752c9b016a42f2e5022c2024416c24658e3859 Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Thu, 30 Oct 2025 11:29:32 +0100 Subject: [PATCH 14/14] update Sum to be ClampedSum --- CHANGELOG.md | 2 +- src/dynamics/coefficient_combine_rule.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa9e5eac9..a9504e5d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - `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)`) - `CoefficientCombineRule::Min` - now makes sure it uses a non zero value as result by using `coeff1.min(coeff2).abs()` - `InteractionTestMode`: Specifies which method should be used to test interactions. Supports `AND` and `OR`. -- `CoefficientCombineRule::Sum` - Adds the two coefficients and does a clamp to have at most 1. +- `CoefficientCombineRule::ClampedSum` - Adds the two coefficients and does a clamp to have at most 1. ## v0.30.1 (17 Oct. 2025) diff --git a/src/dynamics/coefficient_combine_rule.rs b/src/dynamics/coefficient_combine_rule.rs index 74c070449..b0286c77c 100644 --- a/src/dynamics/coefficient_combine_rule.rs +++ b/src/dynamics/coefficient_combine_rule.rs @@ -14,7 +14,7 @@ use crate::math::Real; /// - **Min**: `min(friction1, friction2).abs()` - "Slippery wins" (ice on any surface = ice) /// - **Multiply**: `friction1 × friction2` - Both must be high for high friction /// - **Max**: `max(friction1, friction2)` - "Sticky wins" (rubber on any surface = rubber) -/// - **Sum**: `sum(friction1, friction2).clamp(0, 1)` - Sum of both frictions, clamped to range 0, 1. +/// - **ClampedSum**: `sum(friction1, friction2).clamp(0, 1)` - Sum of both frictions, clamped to range 0, 1. /// /// ## Example /// ``` @@ -27,7 +27,7 @@ use crate::math::Real; /// ``` /// /// ## Priority System -/// If colliders disagree on rules, the "higher" one wins: Sum > Max > Multiply > Min > Average +/// If colliders disagree on rules, the "higher" one wins: ClampedSum > Max > Multiply > Min > Average #[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] pub enum CoefficientCombineRule { @@ -40,8 +40,8 @@ pub enum CoefficientCombineRule { Multiply = 2, /// Use the larger value ("sticky/bouncy wins"). Max = 3, - /// The sum of the two coefficients. - Sum = 4, + /// The clamped sum of the two coefficients. + ClampedSum = 4, } impl CoefficientCombineRule { @@ -63,7 +63,7 @@ impl CoefficientCombineRule { } CoefficientCombineRule::Multiply => coeff1 * coeff2, CoefficientCombineRule::Max => coeff1.max(coeff2), - CoefficientCombineRule::Sum => (coeff1 + coeff2).clamp(0.0, 1.0), + CoefficientCombineRule::ClampedSum => (coeff1 + coeff2).clamp(0.0, 1.0), } } }