Skip to main content

Debug-renderer

Rapier is a physics engine, it doesn't render anything. What is displayed by your application comes from your own renderer, and game assets generally don’t match the shapes seen by the physics engine exactly. Therefore a collider given the wrong size, a joint attached at the wrong place, or a rigid-body that is not where its sprite is, can be difficult to debug (and easy to misinterpret as physics-engine-bugs).

To help with debugging physics, Rapier’s debug-renderer exists to convert the content of the physics scene into a set of colored lines that your application to obtain a wireframe view of what Rapier actually sees.

info

The debug-renderer is behind the debug-render cargo feature, which is disabled by default.

Despite its name, the debug-render doesn’t actually contains any windowing/rasterization/shader code. Instead, it provides to a backend implementing DebugRenderBackend the set of lines that needs to be displayed by your own graphics engine. This makes it possible to integrate the debug-rendering to any graphics stack your application might use. From the DebugRenderBackend, only the draw_line method must be implemented and everything else has a default implementation expressed in terms of individual lines.

Note that the colors are given in the HSLA format, therefore a backend expecting RGBA colors is expected to convert them:

// The backend receives the lines to be drawn. A real one would push them to the renderer of the
// application instead of collecting them.
struct LineCollector {
lines: Vec<(Vector, Vector, DebugColor)>,
}

impl DebugRenderBackend for LineCollector {
fn draw_line(&mut self, _object: DebugRenderObject, a: Vector, b: Vector, color: DebugColor) {
self.lines.push((a, b, color));
}
}

The DebugRenderPipeline is then given the sets of the scene once per rendered frame. Its DebugRenderStyle specifies the colors and various length properties, whereas its DebugRenderMode selects what is drawn so you can select only the element types you are interested in debugging.

// The style gives the colors and sizes, the mode selects what is drawn.
let mut debug_render = DebugRenderPipeline::new(
DebugRenderStyle::default(),
DebugRenderMode::COLLIDER_SHAPES | DebugRenderMode::CONTACTS,
);
let mut backend = LineCollector { lines: vec![] };

for _ in 0..10 {
world.step();

// The debug-rendering is done after the step, once per frame to be drawn.
backend.lines.clear();
debug_render.render(
&mut backend,
&world.bodies,
&world.colliders,
&world.impulse_joints,
&world.multibody_joints,
&world.narrow_phase,
&world.soft_bodies,
);
}

println!("{} lines to draw", backend.lines.len());
warning

The debug-rendering is not free: it walks every collider of the scene and converts its shape into lines at each frame. Therefore it is meant to be enabled only when debugging rather than a player-facing representation of the game objects.