Skip to content

fix(multibody): integrate a dynamic root's rotation around its center-of-mass - #1041

Open
Lanfei wants to merge 1 commit into
dimforge:masterfrom
Lanfei:fix-multibody-root-com-integration
Open

Lanfei wants to merge 1 commit into
dimforge:masterfrom
Lanfei:fix-multibody-root-com-integration

Conversation

@Lanfei

@Lanfei Lanfei commented Oct 15, 2026

Copy link
Copy Markdown

Problem

A dynamic multibody root whose local center-of-mass isn't at its origin drifts: a pure torque translates the whole assembly, even with no gravity or contacts.

For example, a root of mass 2 with its local center-of-mass at (0.2, 0, 0), welded with a multibody fixed joint to a link of mass 1, driven by a 1 N·m torque for one second (60 steps) moves the assembly's center-of-mass by ~8.85 cm. The same bodies joined by an impulse joint, or merged into a single rigid-body, don't move (≤ 1e-7).

Cause

The root's generalized linear velocity is the velocity of its center-of-mass (Multibody::update_velocities writes the root joint velocity directly into rb.vels, and children are offset from world_com). But the root's free joint stores the pose of the rigid-body origin, and MultibodyJoint::integrate applies coords += linvel * dt then rotates around that origin. With a non-zero local center-of-mass r, each step moves the center-of-mass by an extra (R_before - R_after) * r, and every link follows the root.

Regular rigid-bodies don't have this problem: RigidBodyVelocity::integrate rotates around the center-of-mass.

Fix

Multibody::integrate now takes the RigidBodySet. For a dynamic root with a free joint, it compensates the root origin translation by R_before * local_com - R_after * local_com, so the rotation is applied around the center-of-mass, consistent with RigidBodyVelocity::integrate. Non-root links and fixed/kinematic roots are unchanged.

Tests

  • New regression test multibody_root_with_offset_center_of_mass_rotates_around_it. It fails without the fix (drift 0.0885 for a root com of (0.2, 0, 0)) and passes with it.
  • cargo test -p rapier2d -p rapier2d-f64 -p rapier3d -p rapier3d-f64, the enhanced-determinism determinism/parity/snapshot tests, cargo fmt --check and cargo clippy pass.
  • I also built the 3D compat JS package from this branch and ran it against a game where articulated vehicles lose parts (which shifts the root center-of-mass by ~18 cm). Before the fix, vehicles got launched into the air (peak speeds of 65 to 1000+ m/s). With it, they behave normally, and joint drift goes from 8e-2 down to 5e-6. The same build without the fix reproduces the problem exactly, so the change comes from this fix alone.

AI assistance (Claude) was used to investigate, write the fix and the regression test, and I reviewed the results.

…-of-mass

The linear velocity of a dynamic multibody root is the velocity of its
center-of-mass, but its free joint stores the pose of the rigid-body origin
and applied the rotation around that origin. A root whose local
center-of-mass isn't at its origin therefore drifted: a pure torque
translated the whole assembly.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant