Skip to content

Fix rolling balls sinking into the ground - #1071

Open
paulrobello wants to merge 1 commit into
dimforge:masterfrom
paulrobello:fix/rolling-ball-sink
Open

paulrobello wants to merge 1 commit into
dimforge:masterfrom
paulrobello:fix/rolling-ball-sink

Conversation

@paulrobello

Copy link
Copy Markdown

Fixes #1070.

Contacts are found once per step, and each substep re-measures the separation from a body-fixed anchor. For a ball, the true contact point stays at centre + r·n while the ball spins. The body-fixed anchor rotates away and lifts by r·(1 − cos θ). The solver reads that lift as separation, so rolling balls sink until the bias cancels it.

Change

  • Adds ContactManifoldData::centered_ball: [bool; 2] (crate-private, serde(default)). It is set in pair_update.rs when a side's collider is a ball centred on its body's CoM.
  • For such a side, the twist and Coulomb kernels track the normal separation by translation from the body centre. This covers build time, substep update and update_rhs_wo_bias.
  • Friction drift keeps the body-fixed anchor.
  • Non-ball shapes, off-centre balls, capsules and the generic (multibody) constraint path are unchanged.
  • Cost: a few lane selects per contact point.

Results

Measured on a 16 mm ball at 240 Hz on a flat trimesh. A frictionless sliding ball sits at the soft-contact equilibrium, 0.069 mm, both before and after.

Speed Penetration before (mean) Penetration after Max end-of-tick |vy| before Max end-of-tick |vy| after
0.3 m/s 0.091 mm 0.069 mm 6.52 mm/s 0.00 mm/s
1.17 m/s 0.641 mm 0.069 mm 20.44 mm/s 0.00 mm/s
2.0 m/s 0.736 mm 0.069 mm 20.44 mm/s 0.00 mm/s

Tests

  • New test: pipeline::physics_pipeline::test::rolling_ball_does_not_sink_into_the_ground. It covers both friction models and both collider orders. On v0.36.1 it fails for the Simplified model with the ball first: rolling penetration is 0.00245 against 0.00160 sliding.

  • Goldens re-minted, because contact behaviour changes for every rolling ball:

    Test Old New
    parallel_path_parity 0xcc9e_c93f_2c15_65cc 0x0332_9d78_889b_bd8c
    simd_backend_determinism 0xe488_2a11_2d57_d212 0x9943_2aa0_b8ca_3abe
    3D snapshot_portability (488_334, 0x3f5e_ac53_ad07_5243) (490_354, 0x504c_043a_1997_c125)
    2D snapshot_portability (90_574, 0x3019_f8f0_67c5_e643) (90_960, 0x85b4_446d_161e_81d5)

    The snapshot sizes grow because centered_ball is serialized, so a restored world keeps the flag for recycled steps.

  • run-ci-checks.sh passes locally.

  • CHANGELOG.md has an Unreleased/Fixed entry.

Contacts are found once per step and each substep re-measures the
separation from a body-fixed anchor. For a ball the true contact point
stays at centre + r*n while the ball spins, but the body-fixed anchor
rotates away and lifts by r*(1 - cos(theta)), which the solver read as
separation, so rolling balls sank until the bias cancelled it.

ContactManifoldData::centered_ball marks a side whose collider is a ball
centred on its body's CoM. For such a side the twist and Coulomb kernels
track the normal separation from the body centre. Friction keeps the
body-fixed anchor. Other shapes and the generic constraint path are
unchanged.

Goldens re-minted for the changed contact behaviour:
- parallel_path_parity 0xcc9e_c93f_2c15_65cc -> 0x0332_9d78_889b_bd8c
- simd_backend_determinism 0xe488_2a11_2d57_d212 -> 0x9943_2aa0_b8ca_3abe
- 3D snapshot_portability (488_334, 0x3f5e_ac53_ad07_5243) -> (490_354, 0x504c_043a_1997_c125)
- 2D snapshot_portability (90_574, 0x3019_f8f0_67c5_e643) -> (90_960, 0x85b4_446d_161e_81d5)
The snapshot sizes grow because centered_ball is serialized (serde default),
so a restored world keeps it for recycled steps.

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.

Rolling balls sink into the ground: per-substep separation is measured from a body-fixed anchor that rotates with the ball

1 participant