From 26d67e36ee349ebf3b91478282300bbbaafce495 Mon Sep 17 00:00:00 2001 From: newDINO Date: Wed, 12 Nov 2025 21:37:25 +0800 Subject: [PATCH 01/11] Don't clear modified_collider at the end --- src/pipeline/physics_pipeline.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs index 972fd0a5a..4ce0aaf7e 100644 --- a/src/pipeline/physics_pipeline.rs +++ b/src/pipeline/physics_pipeline.rs @@ -704,7 +704,8 @@ impl PhysicsPipeline { let aabb = co.compute_broad_phase_aabb(&integration_parameters, bodies); broad_phase.set_aabb(&integration_parameters, *handle, aabb); } - modified_colliders.clear(); + + // modified_colliders.clear(); // self.clear_modified_colliders(colliders, &mut modified_colliders); } } From 693e090ed4bc526c8e16bcc4c397cd76dc1315c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:23:31 +0100 Subject: [PATCH 02/11] feat: add debug-demo for disabling a collider --- examples3d/debug_disabled3.rs | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 examples3d/debug_disabled3.rs diff --git a/examples3d/debug_disabled3.rs b/examples3d/debug_disabled3.rs new file mode 100644 index 000000000..7d0755d2a --- /dev/null +++ b/examples3d/debug_disabled3.rs @@ -0,0 +1,59 @@ +use rapier_testbed3d::Testbed; +use rapier3d::prelude::*; + +pub fn init_world(testbed: &mut Testbed) { + let mut bodies = RigidBodySet::new(); + let mut colliders = ColliderSet::new(); + let impulse_joints = ImpulseJointSet::new(); + let multibody_joints = MultibodyJointSet::new(); + + let rad = 0.5; + + /* + * Ground + */ + let ground_size = 10.1; + let ground_height = 2.1; + + let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); + let handle = bodies.insert(rigid_body); + let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); + colliders.insert_with_parent(collider, handle, &mut bodies); + + /* + * Platform that will be enabled/disabled. + */ + let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, 5.0, 0.0]); + let handle = bodies.insert(rigid_body); + let collider = ColliderBuilder::cuboid(5.0, 1.0, 5.0); + let handle_to_disable = colliders.insert_with_parent(collider, handle, &mut bodies); + + // Callback that will be executed on the main loop to handle proximities. + testbed.add_callback(move |mut graphics, physics, _, run_state| { + if run_state.timestep_id % 250 == 0 { + let co = &mut physics.colliders[handle_to_disable]; + let enabled = co.is_enabled(); + co.set_enabled(!enabled); + println!("Platform is now enabled: {}", co.is_enabled()); + } + + if run_state.timestep_id % 25 == 0 { + let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, 20.0, 0.0]); + let handle = physics.bodies.insert(rigid_body); + let collider = ColliderBuilder::cuboid(rad, rad, rad); + physics + .colliders + .insert_with_parent(collider, handle, &mut physics.bodies); + + if let Some(graphics) = &mut graphics { + graphics.add_body(handle, &physics.bodies, &physics.colliders); + } + } + }); + + /* + * Set up the testbed. + */ + testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); + testbed.look_at(point![-30.0, 4.0, -30.0], point![0.0, 1.0, 0.0]); +} From de524a2adbcca951dae378e226088c5c4edbb7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:23:44 +0100 Subject: [PATCH 03/11] feat: add a simple debug-demo with two cubes --- examples3d/debug_two_cubes3.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples3d/debug_two_cubes3.rs diff --git a/examples3d/debug_two_cubes3.rs b/examples3d/debug_two_cubes3.rs new file mode 100644 index 000000000..783fe24cb --- /dev/null +++ b/examples3d/debug_two_cubes3.rs @@ -0,0 +1,29 @@ +use rapier_testbed3d::Testbed; +use rapier3d::prelude::*; + +pub fn init_world(testbed: &mut Testbed) { + /* + * World + */ + let mut bodies = RigidBodySet::new(); + let mut colliders = ColliderSet::new(); + let impulse_joints = ImpulseJointSet::new(); + let multibody_joints = MultibodyJointSet::new(); + + // Dynamic box rigid body. + let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, 2.0, 0.0]); + let handle = bodies.insert(rigid_body); + let collider = ColliderBuilder::cuboid(0.5, 0.5, 0.5); + colliders.insert_with_parent(collider, handle, &mut bodies); + + let rigid_body = RigidBodyBuilder::fixed(); + let handle = bodies.insert(rigid_body); + let collider = ColliderBuilder::cuboid(0.5, 0.5, 0.5); + colliders.insert_with_parent(collider, handle, &mut bodies); + + /* + * Set up the testbed. + */ + testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); + testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); +} From dfa3d53de3afdaa6a93944023cfbe81c6fdf92fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:24:25 +0100 Subject: [PATCH 04/11] feat: rename RigidBodyChangnes::MODIFIED and ColliderChanges::MODIFIED to ::IN_MODIFIED_SET --- src/dynamics/rigid_body_components.rs | 16 ++++++---------- src/dynamics/rigid_body_set.rs | 4 ++-- src/geometry/collider_components.rs | 4 ++-- src/geometry/collider_set.rs | 4 ++-- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/dynamics/rigid_body_components.rs b/src/dynamics/rigid_body_components.rs index 7501c2523..d8cce7a5e 100644 --- a/src/dynamics/rigid_body_components.rs +++ b/src/dynamics/rigid_body_components.rs @@ -111,8 +111,8 @@ bitflags::bitflags! { #[derive(Copy, Clone, PartialEq, Eq, Debug)] /// Flags describing how the rigid-body has been modified by the user. pub struct RigidBodyChanges: u32 { - /// Flag indicating that any component of this rigid-body has been modified. - const MODIFIED = 1 << 0; + /// Flag indicating that this rigid-body is in the modified rigid-body set. + const IN_MODIFIED_SET = 1 << 0; /// Flag indicating that the `RigidBodyPosition` component of this rigid-body has been modified. const POSITION = 1 << 1; /// Flag indicating that the `RigidBodyActivation` component of this rigid-body has been modified. @@ -1061,10 +1061,7 @@ impl RigidBodyColliders { co_handle: ColliderHandle, ) { if let Some(i) = self.0.iter().position(|e| *e == co_handle) { - rb_changes.set( - RigidBodyChanges::MODIFIED | RigidBodyChanges::COLLIDERS, - true, - ); + rb_changes.set(RigidBodyChanges::COLLIDERS, true); self.0.swap_remove(i); } } @@ -1083,10 +1080,7 @@ impl RigidBodyColliders { co_shape: &ColliderShape, co_mprops: &ColliderMassProps, ) { - rb_changes.set( - RigidBodyChanges::MODIFIED | RigidBodyChanges::COLLIDERS, - true, - ); + rb_changes.set(RigidBodyChanges::COLLIDERS, true); co_pos.0 = rb_pos.position * co_parent.pos_wrt_parent; rb_ccd.ccd_thickness = rb_ccd.ccd_thickness.min(co_shape.ccd_thickness()); @@ -1113,6 +1107,8 @@ impl RigidBodyColliders { ) { for handle in &self.0 { // NOTE: the ColliderParent component must exist if we enter this method. + // NOTE: currently, we are propagating the position even if the collider is disabled. + // Is that the best behavior? let co = colliders.index_mut_internal(*handle); let new_pos = parent_pos * co.parent.as_ref().unwrap().pos_wrt_parent; diff --git a/src/dynamics/rigid_body_set.rs b/src/dynamics/rigid_body_set.rs index 2b54a3b9c..26b399a7b 100644 --- a/src/dynamics/rigid_body_set.rs +++ b/src/dynamics/rigid_body_set.rs @@ -31,12 +31,12 @@ pub(crate) type ModifiedRigidBodies = ModifiedObjects bool { - self.changes.contains(RigidBodyChanges::MODIFIED) + self.changes.contains(RigidBodyChanges::IN_MODIFIED_SET) } #[inline] fn set_modified_flag(&mut self) { - self.changes |= RigidBodyChanges::MODIFIED; + self.changes |= RigidBodyChanges::IN_MODIFIED_SET; } } diff --git a/src/geometry/collider_components.rs b/src/geometry/collider_components.rs index 1ab98881c..ed8d73377 100644 --- a/src/geometry/collider_components.rs +++ b/src/geometry/collider_components.rs @@ -35,8 +35,8 @@ bitflags::bitflags! { #[derive(Copy, Clone, PartialEq, Eq, Debug)] /// Flags describing how the collider has been modified by the user. pub struct ColliderChanges: u32 { - /// Flag indicating that any component of the collider has been modified. - const MODIFIED = 1 << 0; + /// Flag indicating that the collider handle is in the changed collider set. + const IN_MODIFIED_SET = 1 << 0; /// Flag indicating that the density or mass-properties of this collider was changed. const LOCAL_MASS_PROPERTIES = 1 << 1; // => RigidBody local mass-properties update. /// Flag indicating that the `ColliderParent` component of the collider has been modified. diff --git a/src/geometry/collider_set.rs b/src/geometry/collider_set.rs index 3db5b4c58..6a299b583 100644 --- a/src/geometry/collider_set.rs +++ b/src/geometry/collider_set.rs @@ -11,12 +11,12 @@ pub type ModifiedColliders = ModifiedObjects; impl HasModifiedFlag for Collider { #[inline] fn has_modified_flag(&self) -> bool { - self.changes.contains(ColliderChanges::MODIFIED) + self.changes.contains(ColliderChanges::IN_MODIFIED_SET) } #[inline] fn set_modified_flag(&mut self) { - self.changes |= ColliderChanges::MODIFIED; + self.changes |= ColliderChanges::IN_MODIFIED_SET; } } From 28bcd6296f26720b6ee3844876e54fd443cbb59c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:24:54 +0100 Subject: [PATCH 05/11] feat: render debug-colliders with a different color with the debug-renderer --- src/pipeline/debug_render_pipeline/debug_render_pipeline.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs b/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs index 211f8df32..13e493772 100644 --- a/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs +++ b/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs @@ -327,6 +327,8 @@ impl DebugRenderPipeline { c[2] * coeff[2], c[3] * coeff[3], ] + } else if !co.is_enabled() { + self.style.disabled_color_multiplier } else { self.style.collider_parentless_color }; From 97451ac4bd24eb9a17128247488b1afaf3f86b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:25:12 +0100 Subject: [PATCH 06/11] =?UTF-8?q?chore:=E2=80=AFwire=20up=20new=20examples?= =?UTF-8?q?=20to=20the=20testbed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples3d/all_examples3.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples3d/all_examples3.rs b/examples3d/all_examples3.rs index 405434619..3082f59c3 100644 --- a/examples3d/all_examples3.rs +++ b/examples3d/all_examples3.rs @@ -41,10 +41,12 @@ mod joints3; mod character_controller3; mod debug_chain_high_mass_ratio3; mod debug_cube_high_mass_ratio3; +mod debug_disabled3; mod debug_internal_edges3; mod debug_long_chain3; mod debug_multibody_ang_motor_pos3; mod debug_sleeping_kinematic3; +mod debug_two_cubes3; mod gyroscopic3; mod inverse_kinematics3; mod joint_motor_position3; @@ -106,6 +108,8 @@ pub fn main() { ("(Debug) big colliders", debug_big_colliders3::init_world), ("(Debug) boxes", debug_boxes3::init_world), ("(Debug) balls", debug_balls3::init_world), + ("(Debug) disabled", debug_disabled3::init_world), + ("(Debug) two cubes", debug_two_cubes3::init_world), ("(Debug) pop", debug_pop3::init_world), ( "(Debug) dyn. coll. add", From a714d3697bfa43345ea9bee1aca55a77935991d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:26:05 +0100 Subject: [PATCH 07/11] fix colliders user-modification being ignored after the first step --- src/pipeline/physics_pipeline.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs index 972fd0a5a..3989f49dd 100644 --- a/src/pipeline/physics_pipeline.rs +++ b/src/pipeline/physics_pipeline.rs @@ -82,6 +82,12 @@ impl PhysicsPipeline { colliders: &mut ColliderSet, modified_colliders: &mut ModifiedColliders, ) { + // TODO: we can’t just iterate on `modified_colliders` here to clear the + // flags because the last substep will leave some colliders with + // changes flags set after solving, but without the collider being + // part of the `ModifiedColliders` set. This is a bit error-prone but + // is necessary for the modified information to carry on to the + // next frame’s narrow-phase for updating. for co in colliders.colliders.iter_mut() { co.1.changes = ColliderChanges::empty(); } @@ -700,12 +706,30 @@ impl PhysicsPipeline { // If we ran the last substep, just update the broad-phase bvh instead // of a full collision-detection step. for handle in modified_colliders.iter() { - let co = &colliders[*handle]; - let aabb = co.compute_broad_phase_aabb(&integration_parameters, bodies); - broad_phase.set_aabb(&integration_parameters, *handle, aabb); + let co = colliders.index_mut_internal(*handle); + // NOTE: `advance_to_final_positions` might have added disabled colliders to + // `modified_colliders`. This raises the question: do we want + // rigid-body transform propagation to happen on disabled colliders if + // their parent rigid-body is enabled? For now, we are propagating as + // it feels less surprising to the user and makes handling collider + // re-enable less awkward. + let aabb = co.compute_broad_phase_aabb(&integration_parameters, bodies); + broad_phase.set_aabb(&integration_parameters, *handle, aabb); + + // Clear the modified collider set, but keep the other collider changes flags. + // This is needed so that the narrow-phase at the next timestep knows it must + // not skip these colliders for its update. + // TODO: this doesn’t feel very clean, but leaving the collider in the modified + // set would be expensive as this will be traversed by all the user-changes + // functions. An alternative would be to maintain a second modified set, + // one for user changes, and one for changes applied by the solver but that + // feels a bit too much. Let’s keep it simple for now and we’ll see how it + // goes after the persistent island rework. + co.changes.remove(ColliderChanges::IN_MODIFIED_SET); } + + // Empty the modified colliders set. See comment for `co.change.remove(..)` above. modified_colliders.clear(); - // self.clear_modified_colliders(colliders, &mut modified_colliders); } } From 4ca9648a7a7c10e9bedd9699bca28691b401c090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:27:03 +0100 Subject: [PATCH 08/11] fix broad-phase still taking into account disabled colliders with enabled dynamic rigid-bodies --- src/pipeline/physics_pipeline.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs index 3989f49dd..1838893aa 100644 --- a/src/pipeline/physics_pipeline.rs +++ b/src/pipeline/physics_pipeline.rs @@ -713,8 +713,10 @@ impl PhysicsPipeline { // their parent rigid-body is enabled? For now, we are propagating as // it feels less surprising to the user and makes handling collider // re-enable less awkward. + if co.is_enabled() { let aabb = co.compute_broad_phase_aabb(&integration_parameters, bodies); broad_phase.set_aabb(&integration_parameters, *handle, aabb); + } // Clear the modified collider set, but keep the other collider changes flags. // This is needed so that the narrow-phase at the next timestep knows it must From c40b5ed5c1529a81b6e203c917732942acd07fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:30:04 +0100 Subject: [PATCH 09/11] chore: update changelog --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9504e5d7..e671d8d08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,18 @@ ## Unreleased -- `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` 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::ClampedSum` - Adds the two coefficients and does a clamp to have at most 1. +- Rename `ColliderChanges::CHANGED` to `::IN_CHANGED_SET` to make its meaning more precise. +- Rename `RigidBodyChanges::CHANGED` to `::IN_CHANGED_SET` to make its meaning more precise. +- Fix colliders ignoring user-changes after the first simulation step. +- Fix broad-phase incorrectly taking into account disabled colliders attached to an enabled dynamic rigid-body. ## v0.30.1 (17 Oct. 2025) From cd259e8900e74ddfdd9b957806fda0a1e2eac87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 13 Nov 2025 22:36:31 +0100 Subject: [PATCH 10/11] fix cargo doc --- src/geometry/broad_phase_bvh.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/geometry/broad_phase_bvh.rs b/src/geometry/broad_phase_bvh.rs index d88860947..a72d6fff5 100644 --- a/src/geometry/broad_phase_bvh.rs +++ b/src/geometry/broad_phase_bvh.rs @@ -69,10 +69,6 @@ impl BroadPhaseBvh { /// sent previously and no `RemovePair` happened since then). Sending redundant events is allowed /// but can result in a slight computational overhead. /// - /// The `colliders` set is mutable only to provide access to - /// [`collider.set_internal_broad_phase_proxy_index`]. Other properties of the collider should - /// **not** be modified during the broad-phase update. - /// /// # Parameters /// - `params`: the integration parameters governing the simulation. /// - `colliders`: the set of colliders. Change detection with `collider.needs_broad_phase_update()` From c223f3f4e843c0ed8ed585b0bc9c605466fb9026 Mon Sep 17 00:00:00 2001 From: newDINO Date: Fri, 14 Nov 2025 10:17:15 +0800 Subject: [PATCH 11/11] some fix? --- src/pipeline/physics_pipeline.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/pipeline/physics_pipeline.rs b/src/pipeline/physics_pipeline.rs index 666afb309..1838893aa 100644 --- a/src/pipeline/physics_pipeline.rs +++ b/src/pipeline/physics_pipeline.rs @@ -730,13 +730,8 @@ impl PhysicsPipeline { co.changes.remove(ColliderChanges::IN_MODIFIED_SET); } -<<<<<<< HEAD - modified_colliders.clear(); - // self.clear_modified_colliders(colliders, &mut modified_colliders); -======= // Empty the modified colliders set. See comment for `co.change.remove(..)` above. modified_colliders.clear(); ->>>>>>> upstream/fix-disable-and-user-changes } }