Skip to main content

Integration parameters

Various aspects of the physics simulation can be tuned by modifying the fields of the IntegrationParameters. Most of these parameters are somewhat advanced and should not be modified unless you know their meaning and effect. Several of them are about balancing efficiency and accuracy. They are given default values that work well in the context of video-games or animations. For more realistic simulations you may want to change those parameters to favor accuracy over performance.

info

Several parameters are expressed in a normalized form, i.e., their value is implicitly multiplied by length_unit before being used. Therefore they don't need to be adjusted when the world is not measured in meters.

Setting the integration parameters​

The integration parameters of a physics context are stored in the RapierContextSimulation::integration_parameters field of its RapierContextSimulation component. The integration parameters of the default physics context can be given to the RapierPhysicsPlugin directly, together with its configuration and the optimization strategy of its broad-phase, by initializing it with RapierContextInitialization::InitializeDefaultRapierContext. The IntegrationParameters structure (as well as the FrictionModel enum in 3D) is part of the prelude of bevy_rapier:

.add_plugins(
RapierPhysicsPlugin::<NoUserData>::default().with_custom_initialization(
RapierContextInitialization::InitializeDefaultRapierContext {
integration_parameters: IntegrationParameters {
// 100 pixels make one meter.
length_unit: 100.0,
num_solver_iterations: 8,
..default()
},
rapier_configuration: RapierConfiguration {
gravity: Vec2::new(0.0, -372.0),
..RapierConfiguration::new(100.0)
},
broad_phase_optimization_strategy:
BroadPhaseOptimizationStrategy::SubtreeOptimizer,
},
),
)

The broad_phase_optimization_strategy selects how the BVH of the broad-phase is kept efficient while the colliders move: BroadPhaseOptimizationStrategy::SubtreeOptimizer (the default) optimizes different sub-trees at each timestep, whereas BroadPhaseOptimizationStrategy::None disables this incremental optimization (which is only useful for debugging). It can only be selected when the physics context is created, e.g., with RapierContextSimulation::with_broad_phase_optimization_strategy for a context you spawn yourself.

The integration parameters can then be modified at any time through the RapierContextSimulation component:

fn modify_integration_parameters(
mut contexts: Query<&mut RapierContextSimulation, With<DefaultRapierContext>>,
) -> Result {
let mut simulation = contexts.single_mut()?;
simulation.integration_parameters.num_solver_iterations = 12;
simulation.integration_parameters.warmstart_joints = true;
Ok(())
}

Time-stepping​

dt​

The timestep length used for each update of the physics engine. This is the time by which the physics simulation will be advanced. The default is 1/601 / 60 seconds. This typically corresponds to a refresh rate of 60Hz. Smaller timesteps yield better accuracy. Large timesteps increase the negative effect of some approximations (linearization of various parts of the equations of motion) and may result in missed collisions (because of collisions that may occur in-between timesteps for fast-moving objects).

The dt parameter is overwritten by the plugin before each update of the physics according to the TimestepMode resource, which also selects the number of timesteps executed by each run of the physics systems:

  • TimestepMode::Variable { max_dt, time_scale, substeps } (the default, with max_dt =1/60= 1 / 60, time_scale =1= 1, and substeps =1= 1) advances the simulation by the time elapsed since the last frame multiplied by time_scale, without exceeding max_dt. This timestep is subdivided into substeps timesteps of equal length. No timestep is executed if the elapsed time is zero (e.g. on the first frame).
  • TimestepMode::Fixed { dt, substeps } advances the simulation by dt, in substeps timesteps of equal length, each time the physics systems run. This is the recommended mode when the physics runs in the FixedUpdate schedule.
  • TimestepMode::Interpolated { dt, time_scale, substeps } executes as many updates of length dt as needed for the simulated time to keep up with the real time (possibly none), each of them advancing the simulation by dt multiplied by time_scale in substeps timesteps. The rigid-bodies with a TransformInterpolation component have their Transform interpolated between the last two timesteps so their motion looks smooth whatever the frame rate.
// Advance the simulation by exactly 1/60 seconds (in two substeps of 1/120 seconds) at
// each update of the schedule running the physics.
.insert_resource(TimestepMode::Fixed {
dt: 1.0 / 60.0,
substeps: 2,
})
warning

The TimestepMode::Variable mode depends on the frame rate of your application, therefore it will not give the same simulation results twice. Use TimestepMode::Fixed (or TimestepMode::Interpolated) if you need determinism.

length_unit​

The number of your own length units that make one meter. The default is 1.01.0, i.e., the simulation is measured in meters. Rapier is tuned for human-scale objects measured in meters, therefore a simulation measured in centimeters should set this to 100.0100.0, and a 2D game where a typical object is 100 pixels tall should set it to 100.0100.0 as well. This scales the normalized parameters as well as various internal tolerances, and is the recommended alternative to re-tuning every threshold by hand. Learn more about this in the common mistakes page.

The length unit of the default physics context is set with RapierPhysicsPlugin::with_length_unit, or with RapierPhysicsPlugin::pixels_per_meter in 2D. Note that it also scales the default gravity of the physics context and the lengths drawn by the debug-renderer.

max_ccd_substeps​

The maximum number of CCD substeps performed during one timestep. The default is 11. This is also the global switch of CCD: setting it to 00 disables every form of CCD for this world, including the sweeping of the fast dynamic bodies against the fixed colliders.

min_ccd_dt​

When CCD with multiple substeps is enabled, the timestep is subdivided into smaller pieces. This timestep subdivision won't generate timestep lengths smaller than min_ccd_dt. The default is 1/60/1001 / 60 / 100 seconds.

Setting this to a large value will reduce the opportunity to performing CCD substepping. Setting this to a very small value may lead to numerical instabilities.

Constraints solver​

num_solver_iterations​

The number of iterations, aka. substeps, run by the constraints solver. The default is 44. Higher values give more accurate and more stable simulations, at the cost of performance: 88 to 1212 is a reasonable range for demanding scenes (tall stacks, machinery with stiff joints), whereas 11 or 22 may be enough if performance matters more than accuracy. Note that a single rigid-body can be given additional iterations of its own, as described in the rigid-body solver settings section.

num_internal_pgs_iterations​

The number of internal Projected Gauss-Seidel iterations run at each solver iteration. The default is 11.

num_internal_stabilization_iterations​

The number of stabilization iterations run at each solver iteration. The default is 11. These are the iterations solving the constraints without their depenetration forces. This is what prevents the energy introduced by the position correction from remaining in the simulation.

warmstart_coefficient​

Each cached impulse is multiplied by this coefficient in [0,1][0, 1] when it is re-used to initialize the constraints solver. The default is 1.01.0: it allows the convergence of the solver even when the number of iterations is small.

warmstart_joints​

If enabled, the impulse-joint constraints are warm-started like the contacts are, i.e., the impulses accumulated by the previous timestep are re-applied at the beginning of each substep instead of restarting from zero. The default is false. Enabling it noticeably improves the convergence of stiff joint assemblies. Note that the multibody joints are not affected by this parameter.

friction_in_bias_pass​

If enabled, friction is solved during the biased pass of each substep as well as during the unbiased one. The default is false, which is both cheaper and often more stable.

friction_model (3D only)​

The kind of friction constraints solved by the engine. The Simplified model (the default) solves one Coulomb constraint per group of four contacts, plus one purely rotational "twist" constraint eliminating the angular motion in the tangent plane of the manifold. The Coulomb model solves one Coulomb constraint per contact point instead: it is more mechanically correct but more expensive.

Contacts​

contact_softness and static_contact_softness​

The softness of the contact constraints, given as a natural frequency (in Hz) and a damping ratio instead of a stiffness, so it doesn't depend on the masses of the colliding bodies. Softer constraints make the contacts more compliant (meaning that they allow more penetrations when pressed on), whereas harder constraints feel more rigid and correct, but might introduce jitters if too rigid.

normalized_prediction_distance​

The maximal distance separating two objects that will generate predictive (aka. speculative) contacts. The default is 0.020.02, i.e., four times the geometric slop. Generating contacts before the objects actually touch is what allows the solver to stop them exactly at the surface instead of letting them interpenetrate first.

normalized_allowed_linear_error​

The geometric slop distance. The default is 0.0050.005.

normalized_max_corrective_velocity​

The maximum speed at which the solver is allowed to push penetrating objects apart. The default is 3.03.0. Capping this velocity is what keeps a deep penetration from being resolved explosively.

normalized_max_linear_velocity​

The maximum linear velocity a rigid-body may have after each substep. The default is 400.0400.0. This velocity cap helps with stability and CCD effectiveness.

contact_clustering​

If enabled, the contact manifolds of a collider pair that share (nearly) the same normal are merged into a single cluster manifold before the constraints are generated (default: true, 3D only), so at most four contact points are solved per contact plane. This is a large gain on the composite shapes (triangle-meshes, heightfields, compound shapes, voxels) which generate one manifold per sub-shape.

warning

When contact clustering applies, the contacts and impulses seen by the solver must be read from ContactPair::solver_clusters instead of ContactPair::manifolds. See the contact graph section.

contact_recycling and normalized_contact_recycle_distance​

If enabled, a contact pair which relative position moved less than the recycle distance since its last full update keeps its existing contact points instead of recomputing them (default: true, with a recycle distance of 0.050.05).

Soft-bodies​

soft_bodies​

The settings shared by every soft-body of the world. They are detailed in the soft-body settings section. They are modified through the RapierContextSimulation::integration_parameters field like the other integration parameters.