Skip to content

Release v0.35.0 - #982

Merged
sebcrozet merged 1 commit into
masterfrom
release-0.35.0
Aug 8, 2026
Merged

Release v0.35.0#982
sebcrozet merged 1 commit into
masterfrom
release-0.35.0

Conversation

@sebcrozet

@sebcrozet sebcrozet commented Aug 8, 2026

Copy link
Copy Markdown
Member

v0.35.0 (08 August 2026)

Added

  • ContactForceEvent::first_tick: true on the step a pair's total contact force first
    exceeds its contact_force_event_threshold (coming from below it, or from separation),
    false while it stays above on consecutive steps — the analogue of PhysX's
    "threshold force found" vs "persists" report. The status resets when the force drops
    back below the threshold or the colliders separate.

  • CoefficientCombineRule::GeometricMean: combines friction/restitution as
    sqrt(c1 * c2), the convention used by several other engines. It has the highest
    rule priority, and clamps negative coefficients to zero before the square root.

  • DebugRenderStyle::sleep_eligible_color_multiplier: the debug-renderer now draws bodies that
    are eligible for sleep but still awake in a distinct color, making it easy to spot what is
    keeping a pile awake.

Fixed

  • Wheel::rotation now accumulates from the wheel's own rolling direction on the
    contact plane (contact normal × axle, the same forward direction used by the
    friction update) instead of the chassis' index_forward_axis, so wheels visually
    spin whenever the vehicle actually rolls (adapted from PR Fix issue 925 v2 #950 by @tomo0613).
  • DynamicRayCastVehicleController no longer has unlimited braking friction when a
    wheel's side impulse is exactly zero (e.g. braking in a straight line): the skid
    clamp now applies to the forward impulse as well, so braking strength is bounded by
    friction_slip (adapted from PR fix wheel impulse scaling #947 by @tomo0613).
  • Angular joint limits are no longer restricted to (-π, π): the limit rows now measure the
    wrapped joint angle from the middle of the allowed range (with the joint axis as the row's
    jacobian, like the angular motor rows), so a range may sit anywhere on the circle
    ([0, 3π/2] stops the joint at 3π/2 instead of π/2, and ranges crossing the ±π seam like
    [3π/4, 5π/4] work at all). A range wider than a full turn is indistinguishable from "no
    limit" for an angle read off a relative rotation, so it now leaves the axis free instead of
    clamping it at some folded-back angle.
  • Joint limit rows (linear and angular) now cap their position-correction bias by
    IntegrationParameters::max_corrective_velocity, like contacts always did: a deep limit
    violation recovers over a few steps instead of catapulting the bodies.
  • Python: DynamicRayCastVehicleController.update_vehicle now excludes the chassis body from
    the suspension raycasts by default (their origins sit on its own collider).
  • The character controller's snap-to-ground now triggers on any movement that isn't upwards,
    including movements exactly orthogonal to the up vector, instead of requiring a downward
    motion larger than an arbitrary epsilon. Purely lateral movement along the ground no longer
    flickers the grounded flag when snap-to-ground is enabled (PR should allow grounding with no movement counter to the up direction #481 by @ChrisJanssens).
  • Restitution is now applied as an end-of-step pass instead of during the velocity solve, so
    contacts detected speculatively (within the prediction distance) bounce with the requested
    coefficient instead of being damped away by the prediction distance (issue Restitution has almost no effect in 0.35.0-beta.0 (regression from 0.34.0) #974).
  • SIMD joint constraints now build their local frames relative to the body's center of mass,
    fixing joints on bodies whose center of mass isn't at their origin (PR Fix SIMD joint constraints #953 by @Kyzzsa).
  • The broad phase now filters candidate pairs by collision groups, so colliders that can never
    interact don't reach the narrow phase at all (issue Performance Problem when using a lot of intersecting colliders #288).
  • ContactForceEvent sums the pair's solver manifolds, so contact clustering no longer
    makes the reported force and contact point disagree with what the solver applied.
  • Generic (multibody) contact constraints now rebuild their anchors in the same frames the
    substep update uses, fixing multibodies welded to rigid-bodies never settling (issue MultibodyJoints dont handle collisions correctly #968).
  • RigidBodyBuilder::additional_mass on a body whose colliders are all massless (zero density)
    now derives the angular inertia from the collider shapes instead of leaving it null, so such
    bodies rotate (issue Friction impulse not applied at contact point with additional_mass #666).
  • Joints specified through a subset of their axes now complete the missing frame axes with a
    twist-consistent minimal rotation, so a prismatic joint whose axis isn't x no longer picks
    an arbitrarily rolled frame (issue Very simple PrismaticJoint numerically explodes for certain angles #746).
  • RigidBody::sleep() is now honored immediately, even when the body was repositioned during
    the same frame (issue Stop a rigid body #448).
  • ImpulseJointSet::joints_between now yields every joint between the two bodies instead of
    only the first (issue contacts_enabled behaves incorrectly when there's more than 1 joint between 2 rigid bodies #866).
  • CollisionPipeline::step now clears the rigid-bodies' modified flags, so a collision-only
    pipeline no longer accumulates stale change tracking (issue CollisionPipeline ergonomics feedback and a bug #662).
  • Contact impulses are stored with canonicalized signed zeros, removing a source of
    cross-platform divergence with enhanced-determinism.
  • The debug-renderer now draws the border radius of 2D round triangles (issue Collider::round_triangle doesn't have round edges no matter the border_radius #634).
  • Testbed: objects no longer flash visible for one frame when the surface rendering is
    disabled (issue surface render disabled has 1 visible frame #843).

Modified

  • The broad phase no longer creates pairs between colliders attached to the same
    rigid-body (they can never collide). A single awake body carrying thousands of
    mutually-overlapping colliders previously flooded the pair map and contact graph with
    pairs the narrow phase re-discarded every step; the issue Multiple colliders attached to a single body cause significant performance degradation #970 scene (2,210 convex
    colliders on one always-awake body) steps ~90x faster while stationary and ~18x
    faster while moving. Note that NarrowPhase::contact_pair now returns None for
    same-parent colliders instead of a manifold-less pair.
  • Sleep eligibility is now judged on the actual per-step pose displacement (measured at the
    body’s farthest point) instead of the velocities: a body held in place by contacts can sleep
    even with residual solver velocities, while a body creeping through solver position
    corrections cannot.
  • With the block-solver feature, manifolds whose 2x2 constraint matrix is almost singular
    (e.g. redundant contact points) are now solved with the sequential solver instead of a
    degraded one-point solve, removing residual jiggle in piles. The block solver also uses the
    same lexicographic manifold point ordering as the sequential solver.
  • Improved 3D solver performance by caching the constraints angular jacobians instead of
    recomputing them at each solver iteration.

@sebcrozet
sebcrozet merged commit 5de07a4 into master Aug 8, 2026
35 checks passed
@sebcrozet
sebcrozet deleted the release-0.35.0 branch August 8, 2026 17:37
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