newton.solvers.SolverXPBD#

class newton.solvers.SolverXPBD(model, iterations=2, soft_body_relaxation=0.9, soft_contact_relaxation=0.9, joint_linear_relaxation=0.7, joint_angular_relaxation=0.4, joint_linear_compliance=0.0, joint_angular_compliance=0.0, rigid_contact_relaxation=0.8, rigid_contact_con_weighting=True, angular_damping=0.0, enable_restitution=False)[source]#

Bases: SolverBase

An implicit integrator using eXtended Position-Based Dynamics (XPBD) for rigid and soft body simulation.

References

  • Miles Macklin, Matthias Müller, and Nuttapong Chentanez. 2016. XPBD: position-based simulation of compliant constrained dynamics. In Proceedings of the 9th International Conference on Motion in Games (MIG ‘16). Association for Computing Machinery, New York, NY, USA, 49-54. https://doi.org/10.1145/2994258.2994272

  • Matthias Müller, Miles Macklin, Nuttapong Chentanez, Stefan Jeschke, and Tae-Yong Kim. 2020. Detailed rigid body simulation with extended position based dynamics. In Proceedings of the ACM SIGGRAPH/Eurographics Symposium on Computer Animation (SCA ‘20). Eurographics Association, Goslar, DEU, Article 10, 1-12. https://doi.org/10.1111/cgf.14105

After constructing Model, State, and Control (optional) objects, this time-integrator may be used to advance the simulation state forward in time.

Limitations:

Momentum conservation – When rigid_contact_con_weighting is enabled (the default), each body’s positional correction is divided by its number of active contacts. This improves convergence for stacking scenarios but means the solver does not conserve momentum at contacts. Reported per-contact forces (see update_contacts()) are approximate: for contacts between two dynamic bodies the force is computed using the harmonic mean of the two bodies’ contact counts, which is symmetric but not exact.

Reported parent-joint forces (see body_parent_f, populated when the extended state attribute is requested) are also approximate. XPBD applies relaxation factors (joint_linear_relaxation, joint_angular_relaxation) to each joint constraint correction, and with a finite iterations count residual constraint error remains at end-of-step, so the reported wrench is the applied constraint reaction rather than the exact wrench needed to enforce the joint perfectly. The convention matches SolverMuJoCo: it is the spatial wrench transmitted from the parent through the inbound joint, in world frame at the child body’s COM. In equilibrium this reaction counters all applied forces (gravity, contacts, State.body_f, and the net effect of joint_f) by Newton’s third law.

Joint limitations:

See Joint Feature Support for the full comparison across solvers.

Example

solver = newton.solvers.SolverXPBD(model)

# simulation loop
for i in range(100):
    solver.step(state_in, state_out, control, contacts, dt)
    state_in, state_out = state_out, state_in
__init__(model, iterations=2, soft_body_relaxation=0.9, soft_contact_relaxation=0.9, joint_linear_relaxation=0.7, joint_angular_relaxation=0.4, joint_linear_compliance=0.0, joint_angular_compliance=0.0, rigid_contact_relaxation=0.8, rigid_contact_con_weighting=True, angular_damping=0.0, enable_restitution=False)#
notify_model_changed(flags)#
step(state_in, state_out, control, contacts, dt)#
update_contacts(contacts, state=None)#

Populate contacts.force from XPBD contact impulses accumulated during the last step().

Both force [N] and torque [N·m] components are written. The torque includes torsional and rolling friction contributions that cannot be reconstructed from the linear force alone.

When rigid_contact_con_weighting is enabled, the raw per-contact impulse is scaled to reflect the 1/N correction that apply_body_deltas applies. For contacts between a dynamic and a kinematic body, N is the dynamic body’s contact count. For contacts between two dynamic bodies, the harmonic mean 2/(N_a + N_b) is used so that the reported force is symmetric with respect to body ordering. This is an approximation – the solver applies 1/N_a and 1/N_b independently to each side, so no single scalar can exactly represent both.

Parameters:
  • contacts (Contacts) – Contacts object whose force buffer will be written. Must have been created with "force" in its requested attributes and must match the Contacts instance (same rigid_contact_max) passed to the preceding step().

  • state (State | None) – Unused (accepted for API compatibility with SolverBase).

Raises:

ValueError – If contacts.force is None (not requested), if no step has been run yet, or if the contacts capacity does not match the one used in the last step().