Skip to main content

Common mistakes

My local build of Rapier is slower than the online demos​

Make sure you are building your project (or just the Rapier dependency) in release mode, e.g., cargo build --release. Rapier can be 100 times slower without optimizations enabled. Keep in mind that it is possible to compile your project without optimizations while keeping optimizations enabled for Rapier itself:

# Add this to your Cargo.toml
[profile.dev.package.bevy_rapier3d]
opt-level = 3

[profile.dev.package.rapier3d]
opt-level = 3

See the cargo book about profile overrides for details about this technique.

info

Also note that setting the number codegen units to 1 will further improve performances in a noticeable way, even for a release build (though the build itself will take longer to complete):

# Add this to your Cargo.toml
[profile.release]
codegen-units = 1

Rigid-body isn't affected by gravity​

If you expect your rigid-body to fall because of gravity but it doesn't, please make sure to double-check the following:

  • Your gravity vector is non-zero.
  • Your rigid-body is a dynamic rigid-body.
  • You didn't lock the translations of the rigid-body.
  • The rigid-body has a non-zero mass.

Note that a collider not attached to a dynamic rigid-body will never fall because it won't be affected by forces.

note

If the rigid-body has no collider attached to it, its mass will be zero unless you gave it a mass (or mass properties) explicitly. If the rigid-body has colliders attached to it and you didn't give the rigid-body a mass explicitly, make sure that at least one of the colliders has a non-zero density (or non-zero mass if you set it explicitly on the collider).

warning

The shapes that don't enclose any volume, i.e., the polylines, the half-spaces, the segments, and the triangles in 3D, have a zero mass whatever their density. So if a rigid-body only has colliders with such shapes attached to it, you need to set its mass/angular inertia manually. Note that a triangle-mesh isn't one of them: its mass properties are computed from the volume enclosed by its faces, which assumes that the mesh is closed and that its triangles are consistently oriented.

Applying a force to a rigid-body doesn't work​

If applying a force or an impulse to a rigid-body doesn't work, please make sure to double-check the following:

  • The rigid-body is a dynamic rigid-body.
  • The rigid-body has a non-zero mass (or non-zero angular inertia for torques).
  • The force or impulse must be strong enough to actually push the rigid-body. You may for example try with a very high force/impulse value (say, with a magnitude of 100_000.0) and see if this stronger force works.
note

If the rigid-body has no collider attached to it, its mass will be zero unless you gave it a mass (or mass properties) explicitly. If the rigid-body has colliders attached to it and you didn't give the rigid-body a mass explicitly, make sure that at least one of the colliders has a non-zero density (or non-zero mass if you set it explicitly on the collider).

A rigid-body suddenly stops being simulated​

It may happen that a rigid-body disappears from the simulation, i.e., it stops moving and stops generating contacts, without being removed by your own code. This generally means that non-finite values (NaN or infinites) appeared in its position or in its velocity for one reason or another (could be the simulation diverged, incorrect values provided, etc.)

Rather than panicking or letting these values propagate and corrupt the whole simulation, Rapier detects them at the beginning and at the end of each timestep, and puts the affected rigid-body, collider, or soft-body in quarantine: it is reset to its last valid position when one is known, its velocities are zeroed, and it is disabled.

A warning is logged and a PhysicsQuarantineEvent message is sent after each simulation step that quarantined something. It gives the entity of the physics context, and the entities of the quarantined rigid-bodies, colliders, and soft-bodies (the bodies, colliders, and soft_bodies fields). The plugin also inserts the RigidBodyDisabled (resp. ColliderDisabled, SoftBodyDisabled) component on each quarantined entity. Once the cause is fixed (e.g. by writing a finite Velocity or Transform, or by moving the non-finite particles of a soft-body back), a quarantined object is brought back into the simulation by removing that component:

fn handle_quarantine(
mut commands: Commands,
mut quarantine_events: MessageReader<PhysicsQuarantineEvent>,
mut velocities: Query<&mut Velocity>,
) {
for event in quarantine_events.read() {
for entity in &event.bodies {
println!("The rigid-body {entity} went non-finite and was disabled.");
// Fix the cause, e.g., a non-finite velocity set by our own code.
if let Ok(mut velocity) = velocities.get_mut(*entity) {
*velocity = Velocity::zero();
}
// Then bring the rigid-body back into the simulation.
commands.entity(*entity).remove::<RigidBodyDisabled>();
}
// The quarantined colliders and soft-bodies are re-enabled the same way.
for entity in &event.colliders {
commands.entity(*entity).remove::<ColliderDisabled>();
}
for entity in &event.soft_bodies {
commands.entity(*entity).remove::<SoftBodyDisabled>();
}
}
}

The most common configuration that leads to non-finite values is two dynamic rigid-bodies with a zero mass starting to be in contact. Therefore, make sure that your dynamic rigid-bodies have a non-zero mass. Note that the values given to the physics engine are checked too: a position or a velocity set to NaN by your own code (e.g. after a division by a zero-length vector) is caught at the beginning of the next timestep.

note

If the rigid-body has no collider attached to it, its mass will be zero unless you gave it a mass (or mass properties) explicitly. If the rigid-body has colliders attached to it and you didn't give the rigid-body a mass explicitly, make sure that at least one of the colliders has a non-zero density (or non-zero mass if you set it explicitly on the collider).

Why is everything moving in slow-motion?​

A common mistake, especially in 2D, is to use pixels as the length unit in the physics world. Let's say that in 2D you have a 100x100 pixels sprite for your player. It may be tempting to use a 100x100 cuboid collider for this sprite: Collider::cuboid(50.0, 50.0) (we set 50.0 because this is the half-width of the cuboid). Doing this will make it look like the simulation runs in slow-motion because the cuboid will be huge compared to the magnitude of the default gravity (-9.81).

The recommended way of using Rapier is to use SI units (meters, seconds, kilograms, etc.) If the player sprite is a 100x100 cuboid, then it is as if your player is 100 meters tall and 100 meters wide, which is huge. Therefore it is recommended to have a scaling factor between the graphics and the physics. For example we can say that 1 physics meter is equal to 50 pixels. This means that we can initialize our player collider as a 2x2 cuboid while still using a 100x100 pixels sprite.

In this example, we could set RapierPhysicsPlugin::pixels_per_meter(50.0): all the transforms, collider sizes, velocities, etc. remain expressed in pixels on your end, but this sets the length unit of the simulation to 50, which scales the default gravity and the internal tolerances of Rapier accordingly. The simulation then behaves as if the player was measured in meters.