Skip to content

Prismatic axis rows for rotation-locked pairs; a spring of no stiffness lets go - #100

Merged
nicolas-maman merged 1 commit into
mainfrom
fix/joint-spring-impulses
Oct 4, 2026
Merged

nicolas-maman merged 1 commit into
mainfrom
fix/joint-spring-impulses

Conversation

@nicolas-maman

Copy link
Copy Markdown
Collaborator

Fixes two defects inherited from upstream, found while auditing the joint solvers against Box3D e77352c. The rest of the per-step math matches upstream line for line.

1. Prismatic spring, motor and limits skipped for rotation-locked pairs. These ran only when the pair could turn (fixed_rotation == false). They are linear rows along the axis, and their mass comes from the bodies' masses, so they work whether or not the bodies can rotate. A rotation-locked body on a prismatic joint (an elevator or a piston) got no motor drive and no spring pull, and slid straight through its limits. Only the rotation lock keeps that gate now; the wheel joint's linear rows never had it.

2. A spring set to zero stiffness kept pushing. make_soft(0) gives no mass and no impulse scale, so the solve's delta was zero and the last spring impulse stayed. It was then warm-started every sub-step for as long as the joint lived, so a ragdoll joint that was let go kept pushing. The port already drops such impulses for the distance and motor joints. The prepares now drop them too when the spring is off or has zero stiffness, for:

  • the revolute, prismatic and spherical springs;
  • the wheel's suspension and steering springs;
  • the parallel joint's soft row.

test_physics_world's test_joint_springs_and_locks:

  • a rotation-locked elevator stops at its limit; on main it falls to y = -18.
  • a hinge spinning against a spring set to 0 Hz keeps spinning without being pushed; on main the frozen impulse spins it up from 0.25 to 21.8 rad/s.

All 28 test programs pass locally on aether 0.772.0, with no warnings.

… of no stiffness lets go

Two defects inherited from the reference, found auditing the joint solvers
against Box3D e77352c (otherwise faithful):

- The prismatic joint's spring, motor and limits ran only when the pair
  could turn (fixed_rotation false). They are linear rows along the axis,
  their mass through the bodies' masses, so a rotation-locked body on a
  prismatic joint (an elevator, a piston) was driven by no motor, pulled by
  no spring and slid straight through its limits. Only the rotation lock
  keeps that gate now; the wheel joint's linear rows never had it.
- make_soft(0) gives a spring no mass and no impulse scale, so a spring set
  to no stiffness computed a zero delta and its last impulse stayed,
  warm-started every sub-step for as long as the joint lived: a ragdoll
  joint let go kept pushing. The port already drops such impulses for the
  distance and motor joints; the revolute, prismatic and spherical
  springs, the wheel's suspension and steering springs and the parallel
  joint's soft row now drop theirs in the prepare when the spring is off
  or of no stiffness.

test_physics_world's test_joint_springs_and_locks: a rotation-locked
elevator stops at its limit (on main it falls to y -18), and a hinge spinning
against a spring set to 0 Hz spins on unpushed (on main the frozen impulse
spins it from 0.25 to 21.8 rad/s).
@nicolas-maman
nicolas-maman merged commit 857ab20 into main Oct 4, 2026
1 check passed
@nicolas-maman
nicolas-maman deleted the fix/joint-spring-impulses branch October 6, 2026 23:09
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