Debugging

This section of the book explains how to debug various aspects of scenes.

Debug Drawing

Sometimes you may need to visualize some objects, that are normally invisible. The engine has built-in debug drawing context exactly for this purpose. For example, to visualize a point use the following code:

#![allow(unused)]
fn main() {
#[derive(Visit, Default, Reflect, Debug, Clone, ComponentProvider, TypeUuidProvider)]
#[type_uuid(id = "efc71c98-ecf1-4ec3-a08d-116e1656611b")]
struct MyScript {}

impl ScriptTrait for MyScript {
    fn on_update(&mut self, ctx: &mut ScriptContext) {
        let self_position = ctx.scene.graph[ctx.handle].global_position();

        ctx.scene
            .drawing_context
            .draw_sphere(self_position, 16, 16, 0.1, Color::GREEN);
    }
}
}

This code will draw a wireframe sphere at the position of an object, to which the script is attached to. Keep in mind, that all drawing is performed in world-space coordinates. It is important to note, that the code above will just add the wireframe sphere line-by-line to internal list of lines, which you must clear at least once per frame. This is not done automatically, because having a "ghosting" effect could be useful for debugging to see trajectories and to trace short events. To clear the buffer call the clear_lines method somewhere in your plugin's update method:

#![allow(unused)]
fn main() {
#[derive(Visit, Reflect, Debug)]
struct Game {
    scene: Handle<Scene>,
}

impl Plugin for Game {
    fn update(&mut self, context: &mut PluginContext) {
        context.scenes[self.scene].drawing_context.clear_lines();
    }
}
}

Drawing context provides a wide variety of helper methods to draw various shapes, starting from lines and ending by cones, cylinders, etc. The full list of methods is provided below:

  • draw_frustum - draws a frustum, which could be obtained, for instance, from a Camera node.
  • draw_aabb - draws an axis-aligned bounding box.
  • draw_oob - draws an object-oriented bounding box.
  • draw_transform - draws three basis vectors of an arbitrary transformation 4x4 matrix.
  • draw_triangle - draws a triangle by 3 vertices.
  • draw_pyramid - draws a pyramid, using vertices for its top, and four vertices for the base.
  • draw_wire_sphere - draws a wireframe sphere.
  • draw_circle - draws a circle.
  • draw_circle_segment - draws a circle segment using angles range.
  • draw_rectangle - draws a rectangle.
  • draw_sphere - draws a sphere.
  • draw_sphere_section - draws a sphere section.
  • draw_cone - draws a cone.
  • draw_cylinder - draws a cylinder.
  • draw_flat_capsule - draws a flat capsule (axial slice).
  • draw_capsule - draws a volumetric capsule.
  • draw_segment_flat_capsule - draws a segment of a flat capsule
  • draw_segment_capsule - draws a segment of volumetric capsule.
  • draw_arrow - draws an arrow.
  • add_line - draws a single line from point to point.

Nodes

Scene nodes could draw their own debug info to the scene drawing context by overriding debug_draw method provided by NodeTrait. For example, navigational meshes are normally invisible and only used to calculate paths, however it could be very useful to actually see them when debugging game's AI:

img.png

You can debug draw either all scene nodes at once:

#![allow(unused)]
fn main() {
#[derive(Visit, Reflect, Debug)]
struct Game {
    scene: Handle<Scene>,
}

impl Plugin for Game {
    fn update(&mut self, context: &mut PluginContext) {
        let scene = &mut context.scenes[self.scene];
        for node in scene.graph.linear_iter() {
            node.debug_draw(&mut scene.drawing_context);
        }
    }
}
}

Or filter out only specific ones:

#![allow(unused)]
fn main() {
#[derive(Visit, Reflect, Debug)]
struct Game {
    scene: Handle<Scene>,
}

impl Plugin for Game {
    fn update(&mut self, context: &mut PluginContext) {
        let scene = &mut context.scenes[self.scene];
        for node in scene.graph.linear_iter() {
            if let Some(navmesh) = node.component_ref::<NavigationalMesh>() {
                navmesh.debug_draw(&mut scene.drawing_context);
            }
        }
    }
}
}

Physics

You can enable debug visualization of physics using built-in drawing methods. All that is needed is to call the draw() method of a physics world (2D or 3D) like so:

#![allow(unused)]
fn main() {
#[derive(Visit, Reflect, Debug)]
struct Game {
    scene: Handle<Scene>,
}

impl Plugin for Game {
    fn update(&mut self, context: &mut PluginContext) {
        let scene = &mut context.scenes[self.scene];
        scene.graph.physics.draw(&mut scene.drawing_context);
    }
}
}

2D physics can be drawn the same way, just replace .physics with .physics2d. The result should look like this:

physics debug draw