A prototype plugin providing a simple line drawing api for bevy.

Overview

bevy_debug_lines

A prototype plugin providing a simple line drawing api for bevy.

See docs.rs for documentation.

Expect breakage on master.

demo demo_2 Click on the above demo to play it.

About

This plugin uses a shader and sends individual points to the GPU, which then moves geometry to make a line. This is quite fast with a significant number of lines, and there is no added cost to moving lines around.

Usage

Add bevy_prototype_debug_lines to your Cargo.toml:

[dependencies]
bevy_prototype_debug_lines = "0.2.0"

Add the plugin in your App::build() phase:

use bevy::prelude::*;
use bevy_prototype_debug_lines::*;

fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_plugin(DebugLinesPlugin)
        ...
        .run();
}

Draw a line in whatever system you have using the DebugLines resource:

fn some_system(
    ...
    mut lines: ResMut<DebugLines>
) {
    let start = Vec3::splat(-1.0);
    let end = Vec3::splat(1.0);
    let thickness = 0.01;
    lines.line(start, end, thickness);
}

See the examples for more complete usage examples.

Running Examples

You can run the examples like so:

cargo run --example 3d --features="example_deps"

Where 3d is one of the files in the examples

Notes and Missing Stuff

This plugin is incomplete, so there are some things missing and general annoyances:

  • More gracefully handle exceeding max lines (128000).
  • More, I'm sure...

Let me know if you have any requests, improvements, or suggestions on how to make this crate more ergonomic.

Comments
  • Update to new renderer

    Update to new renderer

    This is a lot of code and hey, feel free to ignore it, I just wanted to hone my understanding of shader programming with the new bevy renderer. If you reject the PR, I really won't mind.

    The code changes

    The most notable changes in the code are:

    • There is no more Line struct. We store the colors and positions as buffer, pretty much the way it's going to be uploaded to GPU
    • We have two of those buffers, one for "immediate" lines (with duration=0.0) and one for "retained" lines (with a duration set), to be fair, I'm not even sure if it improves performance.
    • We use the attribute lists of meshes as buffers to upload to the GPU
    • We use the mesh vertex index to cull expired lines for the retained lines
    • We also maintain a list of index for the expired lines, we use it as a stack of available indices when adding new lines
    • The size limit now depends on the maximum number of vertex per meshes
    • The number of vertices is dynamic, so no massive pre-allocation, it evolves with usage

    User-facing changes

    Changes:

    • Need to use lines: DebugLines rather than lines: ResMut<DebugLines> to add lines
    • User Lines no longer exist
    • Depth check is now configured through the DebugLinesPlugin constructor

    Regressions:

    • Does not work in 2d anymore
    • ~~The depth check option is now always on~~

    Improvements:

    • Does work with the new renderer
    • Slightly more portable, as it uses wgsl

    Possible improvements and depth check

    I wrote TODOs laying out potential improvement paths.

    I tried implementing the depth test using an uniform. I started an attempt but when I got to 100 additional lines of code I kinda gave up. Seems the best starting point is the shader_material example in the bevy repository.

    Edit: I now simply set it through the DebugLinesPlugin constructor.

    opened by nicopap 13
  • Current `main` branch introduces stutter

    Current `main` branch introduces stutter

    I'm experiencing stutter on my best hardware with the current main branch at 7859f9b87583dc175e43f9a54af50d340f92f7a9. I was able to resolve the stutter by removing DebugLinesPlugin.

    diff --git a/src/game.rs b/src/game.rs
    index a910174..2cf7c20 100644
    --- a/src/game.rs
    +++ b/src/game.rs
    @@ -224,7 +224,7 @@ pub fn update_window_dimensions(windows: Res<Windows>, mut engine_state: ResMut<
     #[doc(hidden)]
     pub fn draw_sprite_colliders(
         engine_state: Res<EngineState>,
    -    mut lines: ResMut<DebugLines>,
    +    //mut lines: ResMut<DebugLines>,
         sprite_query: Query<&Sprite>,
     ) {
         if !engine_state.debug_sprite_colliders {
    @@ -239,7 +239,7 @@ pub fn draw_sprite_colliders(
             let mut curr = 0;
             let mut next = 1;
             while curr < length {
    -            lines.line(points[curr].extend(0.0), points[next].extend(0.0), 0.0);
    +            //lines.line(points[curr].extend(0.0), points[next].extend(0.0), 0.0);
                 curr += 1;
                 next = (next + 1) % length;
             }
    @@ -306,7 +306,7 @@ impl<S: Send + Sync + 'static> Game<S> {
                 .add_system(exit_on_esc_system)
                 // External Plugins
                 .add_plugin(AudioPlugin) // kira_bevy_audio
    -            .add_plugin(DebugLinesPlugin::always_in_front()) // bevy_prototype_debug_lines, for displaying sprite colliders
    +            //.add_plugin(DebugLinesPlugin::always_in_front()) // bevy_prototype_debug_lines, for displaying sprite colliders
                 // Rusty Engine Plugins
                 .add_plugin(AudioManagerPlugin)
                 .add_plugin(KeyboardPlugin)
    

    The weirdest part was that the stutter is in an example program which isn't using debug lines (it is literally not calling lines.line(...) from the diff above) because I've got code at the top of the function returning early and skipping the debug line drawing entirely (see code below). So I've got stutter...and the plugin ostensibly isn't even doing anything!

       if !engine_state.debug_sprite_colliders {
            return;
        }
    

    The stutter happens randomly with an interval that feels like it's random between about 0.25s - 5s. The stutter seems to last at least a couple frames and sometimes more like a dozen.

    Here's the specs for my workstation with the problem:

    image
    # I tried Rust 1.57 -- same thing
    $ rustc --version
    rustc 1.58.0 (02072b482 2022-01-11)
    

    I do NOT see the problem on my laptop, which is really weird:

    mbpro-screenshot

    Steps to Reproduce

    $ git clone https://github.com/CleanCut/rusty_engine.git
    $ cd rusty_engine
    $ git checkout choppy
    $ cargo run --release --example road_race
    
    # Use the arrow keys to avoid obstacles - observe periodic stutters on some hardware
    
    $ git checkout smooth
    $ cargo run --release --example road_race
    
    # no stutters now - neither of these will draw any debug lines (`engine_state.debug_sprite_colliders`
      is `false` in this example)
    
    opened by CleanCut 9
  • Shape API

    Shape API

    I found myself implementing drawing different shapes when using this plugin in projects so I decided to add an (in my opinion) nice API for adding shapes as lines.

    I feel like this would make this plugin a lot more flexible for debugging purposes.

    At the moment I only have line, rect, cuboid (box) as shapes but planning on adding more like circle, sphere caspule, cylinder, etc.

    Shapes also have the added benefit of having sensible defaults which can be overridden with a builder-like pattern so you can add color, duration, and other optional settings only when needed.

    For example, cuboid with rotation and color overridden:

    fn some_system(time: Res<Time>, mut shapes: ResMut<DebugShapes>) {
        let seconds = time.elapsed_seconds();
    
        shapes
            .cuboid(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0))
            .rotation(Quat::from_axis_angle(
                Vec3::X,
                seconds * std::f32::consts::FRAC_PI_4,
            ))
            .color(Color::RED);
    }
    

    What do you think about this?

    opened by GarmOfGnipahellir 8
  • Make lines drawn the same frame they are called

    Make lines drawn the same frame they are called

    While working on some updates to Rusty Engine I started using this plugin to draw debug lines representing the colliders on my sprites. Since the sprites were in motion, I noticed that the debug lines were consistently drawn 1 frame later, which was annoying.

    After poking around a bit, I found that if you move the systems from CoreStage::Last to CoreStage::PostUpdate, then they were drawn in the same frame! This is much nicer.

    I have tested this only with the release version of Bevy 0.5.

    opened by CleanCut 8
  • Bevy 0.7

    Bevy 0.7

    This PR contains two changes (separate commits) related to Bevy:

    • Previously used render feature is a group that contains unneeded stuff, like bevy_ui or bevy_text. Specified features in this PR is the required minimum. You can read more about in in this issue: https://github.com/bevyengine/bevy/issues/4202
    • Update to Bevy 0.7. All changes comes from this PR in Bevy, which I used to get information about what changed. But currently it crashes with the following error:
    thread 'main' panicked at 'range end index 176 out of range for slice of length 160', .cargo/registry/src/github.com-1ecc6299db9ec823/bevy_render-0.7.0/src/mesh/mesh/mod.rs:241:17
    

    So the PR is draft.

    opened by Shatur 7
  • Adding a PointLight crashes the app

    Adding a PointLight crashes the app

    When I try to use this plugin with a scene with a point light it crashes.

    For example, if I add a point light in the 3d example of this repo I get this error:

    2022-02-20T18:57:30.397787Z ERROR wgpu::backend::direct: Handling wgpu errors as fatal by default
    thread 'main' panicked at 'wgpu error: Validation Error
    
    Caused by:
        In a RenderPass
          note: encoder = `<CommandBuffer-(0, 2, Vulkan)>`
        In a draw command, indexed:false indirect:false
          note: render pipeline = `shadow_pipeline`
        vertex 6 extends beyond limit 5 imposed by the buffer in slot 0. Did you bind the correct `Vertex` step-rate vertex buffer?
    

    I don't get this error if I don't spawn a point light.

    I tried it with bevy 0.6 and the latest bevy main and the bevy-main branch of this repo. This is on windows 10.

    opened by IceSentry 6
  • Provide a Way to Re-Initialize Debug Lines?

    Provide a Way to Re-Initialize Debug Lines?

    I have a use-case where I want to reset my whole world. I do this by deleting all entities other than the Camera. The issue is that it also deletes the debug lines meshes.

    I could filter out the debug lines meshes from my query for all entities to delete, but DebugLinesMesh is the only defining component, and it's not public.

    Alternatively I could delete all entities and have a way to re-initialize debug lines, but the setup system is private, too.

    opened by zicklag 5
  • 0.5.0 compat

    0.5.0 compat

    I am using this plugin in a project, and attempting to upgrade that project to bevy 0.5.0. It looks like the definition of a plugin has changed. I am happy to spend the time to submit a fix, if that is welcome :)

    opened by szunami 5
  • Update to Bevy 0.8

    Update to Bevy 0.8

    I haven't fully tested this yet, so it's not ready to be merged, but it works enough to compile. I'll add an update when I've tested it.

    Update:

    • [X] 2D updated
    • [x] 3D updated
    opened by thisjaiden 3
  • Bevy 0.6

    Bevy 0.6

    NOT YET IN A WORKING STATE -- I am putting this out there in the hopes of handing this off to someone who knows the rendering code. I'm not familiar with the old rendering code, so figuring out what changed to what and why is going to be a guessing game for me.

    I'd be happy to grant anyone write access to this repo (I've already done it for "maintainers").

    So far, I have:

    • Merged the contents of the bevy-main branch into the master branch
    • Switched to Bevy 0.6 as a dependency it Cargo.toml
    • Updated to Rust 2021 in Cargo.toml
    • Changed App::build() to App::new()
    • Removed unnecessary .system() calls

    Current state: doesn't compile, many errors, I've done all the changes that were obvious to me. Now it's render stuff I don't understand.

    /cc @Toqozz @payload @IceSentry

    opened by CleanCut 3
  • webgl2 compatibility

    webgl2 compatibility

    Unfortunately this doesn't work with bevy_webgl2 because of the shaders' version. There is a panic on startup which is a bit difficult to trace to this library.

    opened by remram44 3
  • Feature request: Toggle rendering

    Feature request: Toggle rendering

    Thanks for the plugin, really useful!

    It would be sweet if there was some way to disable rendering of debug lines, so one could toggle them with a hotkey, e.g.

    fn toggle_debug_lines(mut debug_lines_context: ResMut<DebugLinesContext>, input: Res<Input<KeyCode>>) {
      if input.just_pressed(KeyCode.F1) {
        debug_lines_context.enabled = !debug_linex_context.enabled;
      }
    }
    
    opened by geirsagberg 2
  • Lines are always behind sprites in a 2d scene

    Lines are always behind sprites in a 2d scene

    Given a 2d orthographic camera and some SpriteBundles, debug lines will never appear in front of the sprites no matter what Z value is used for either. I'm not sure if this is intentional but it also happens when with_depth_test is enabled.

    bevy v0.7.0 bevy_debug_lines v0.7.1 rustc v1.59.0

    opened by thisjaiden 21
  • Consider using additive `2d` and `3d` features

    Consider using additive `2d` and `3d` features

    Hi-

    I struggled with the same issue when Bevy changed its renderer, to ensure both 2D and 3D could be used for bevy_hanabi. Initially the code had some 2d and 3d features, but they were mutually exclusive, which is equivalent to what you have now in bevy_debug_lines with a feature and its opposite.

    For bevy_hanabi this caused a number of issues:

    • By default users have to choose, even before they know anything about the crate. This is not nice.
      • If you set a default, like you did here with 3d, then this hinders discoverability; users might miss that feature flag and end up not being able to use the crate in 2D and get confused, and either log an issue or eventually abandon and consider the crate is broken.
    • Obviously, with that setup you cannot use both 2D and 3D. This was already a problem for bevy_hanabi with particles, but for bevy_debug_lines that seems like an even harsher limitation, as games/apps commonly have a mix of 2D and 3D, and you don't want to find yourself having to choose which one you can line-debug and which one you cannot.
    • Having a mandatory feature doesn't play nice with some tooling like cargo test or code coverage. Being able to use --all-features on the other hand, and covering all codepaths that way, is quite handy.
      • Related, but more minor, is the fact the official Rust guideline for features is to be strictly additive. So in theory having some codepath activated by the absence of the 3d feature is breaking that rule. I know many crates break it anyway, and in particular no_std breaks that idiom, but cargo and other tools are working under that assumption of features being strictly additive, and sometimes things break if that's not the case.

    Eventually the solution was to support both 2d and 3d features additively, each plugging into the appropriate renderer (see here for details). I think that's a nicer approach, and it's not that much more complicated to implement.

    Thanks!

    opened by djeedai 1
  • Line thickness parameter breaks when lines are on the same x, y plane

    Line thickness parameter breaks when lines are on the same x, y plane

    This is a little hard to describe and I might be misunderstanding some of it but I've written a little demo to show what I encountered.

    Basically this code spawns a cube at (0.0, 0.0, 0.0) and then tries to draw 9 lines... four lines pointing up the Y axis, one line pointing up the X axis and four lines pointing up the Z axis.

    This is what I get

    Screenshot from 2021-04-13 22-22-11

    with this code

        // vertical lines
        lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 5.0, 0.0),  0.01, Color::RED);
        lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 5.0, 0.0),  0.01, Color::RED);
        lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.0, 5.0, 0.0),  0.01, Color::RED);
        lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.0, 5.0, 0.0),  0.01, Color::RED);
    
        // one line going up the x axis
        lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(5.0, 0.0, 0.0),  0.01, Color::RED);
    
        // four lines starting from different points on the 
        // x axis going from same x value but toward 5.0 z value
        lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 5.0),  0.01, Color::GREEN);
        lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 5.0),  0.01, Color::GREEN);
        lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.1, 0.0, 5.0),  0.01, Color::GREEN);
        lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.1, 0.0, 5.0),  0.01, Color::GREEN);
    
    

    Note: the last two lines I could get to work by doing x values of 2.0 -> 2.1 and 3.0 -> 3.1. If I leave the X value the same (like in the first two green lines) then it doesn't show. And, I don't seem to get this issue with the other lines (the vertical lines and the X-axis line render fine despite only having the difference in one axis between start and end points)

    If I change that part to this

        lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.1, 0.0, 5.0),  0.01, Color::GREEN);
        lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.1, 0.0, 5.0),  0.01, Color::GREEN);
    

    then I get all four green lines

    Screenshot from 2021-04-13 22-27-30

    Here's the full code

    use bevy::prelude::*;
    use bevy_prototype_debug_lines::{ DebugLinesPlugin, DebugLines };
    
    fn main() {
        App::build()
            .insert_resource(Msaa { samples: 4 })
            .add_plugins(DefaultPlugins)
            .add_plugin(DebugLinesPlugin)
            .add_startup_system(setup.system())
            .add_system(demo.system())
            .run();
    }
    
    fn setup(
        mut commands: Commands,
        mut meshes: ResMut<Assets<Mesh>>,
    ) {
        let mut transform = Transform::from_translation(Vec3::new(-2.4399414, 3.9506745, 5.9317107));
        transform.rotate(Quat::from_xyzw(-0.26216018, -0.36458296, -0.10775752, 0.88698345)); 
    
        commands.spawn_bundle(PerspectiveCameraBundle {
            transform,
            ..Default::default()
        });
    
        commands.spawn_bundle(PbrBundle {
            transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
            mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
            ..Default::default()
        });
    }
    
    fn demo(mut lines: ResMut<DebugLines>) {
        // vertical lines
        lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 5.0, 0.0),  0.01, Color::RED);
        lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 5.0, 0.0),  0.01, Color::RED);
        lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.0, 5.0, 0.0),  0.01, Color::RED);
        lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.0, 5.0, 0.0),  0.01, Color::RED);
    
        // one line going up the x axis
        lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(5.0, 0.0, 0.0),  0.01, Color::RED);
    
        // four lines starting from different points on the 
        // x axis going from same x value but toward 5.0 z value
        lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 5.0),  0.01, Color::GREEN);
        lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 5.0),  0.01, Color::GREEN);
        lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.1, 0.0, 5.0),  0.01, Color::GREEN);
        lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.1, 0.0, 5.0),  0.01, Color::GREEN);
    }
    
    
    opened by ramirezmike 10
Owner
Michael Palmos
Michael Palmos
Minecraft-esque voxel engine prototype made with the bevy game engine. Pending bevy 0.6 release to undergo a full rewrite.

vx_bevy A voxel engine prototype made using the Bevy game engine. Goals and features Very basic worldgen Animated chunk loading (ala cube world) Optim

Lucas Arriesse 125 Dec 31, 2022
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Sélène Amanita 11 May 28, 2023
Bevy plugin for a simple single-line text input widget.

bevy_simple_text_input An unambitious single-line text input widget for bevy_ui. Usage See examples/basic.rs. Alternatives If you need more features,

Rob Parrett 9 Oct 3, 2023
Victorem - easy UDP game server and client framework for creating simple 2D and 3D online game prototype in Rust.

Victorem Easy UDP game server and client framework for creating simple 2D and 3D online game prototype in Rust. Example Cargo.toml [dependencies] vict

Victor Winbringer 27 Jan 7, 2023
A canvas on which you can draw anything with ease before drawing the pixels on your small hardware display.

embedded-canvas    canvas - a piece of cloth backed or framed as a surface for a painting NOTE: This crate is still in development and may have breaki

Lechev.space 13 Aug 31, 2022
A simple extension for `bevy-editor-pls` to support tilemap editing right inside the bevy app.

What is this This is a simple tilemap editor plugin, that hooks right into bevy_editor_pls to work with bevy_ecs_tilemap. It works completely within i

null 3 May 8, 2023
a prototype crate for creating modular and performant 3D CPU particle systems, inspired by Unity's Shuriken Particle System.

bevy_prototype_particles This is a prototype crate for creating modular and performant 3D CPU particle systems, inspired by Unity's Shuriken Particle

James Liu 28 Sep 12, 2022
A Bevy plugin for loading the LDtk 2D tile map format.

bevy_ldtk ( Tileset from "Cavernas" by Adam Saltsman ) A Bevy plugin for loading LDtk tile maps. Usage use bevy::prelude::*; use bevy_ldtk::*; fn mai

Katharos Technology 23 Jul 4, 2022
Inspector plugin for the bevy game engine

bevy-inspector-egui This crate provides the ability to annotate structs with a #[derive(Inspectable)], which opens a debug interface using egui where

Jakob Hellermann 517 Dec 31, 2022
A plugin for Egui integration into Bevy

bevy_egui This crate provides a Egui integration for the Bevy game engine. Features: Desktop and web (bevy_webgl2) platforms support Clipboard (web su

Vladyslav Batyrenko 453 Jan 3, 2023
Crossterm plugin for the bevy game engine

What is bevy_crossterm? bevy_crossterm is a Bevy plugin that uses crossterm as a renderer. It provides custom components and events which allow users

null 79 Nov 2, 2022
A Bevy plugin to use Kira for game audio

Bevy Kira audio This bevy plugin is intended to try integrating Kira into Bevy. The end goal would be to replace or update bevy_audio, if Kira turns o

Niklas Eicker 172 Jan 5, 2023
Bevy plugin helping with asset loading and organisation

Bevy asset loader This Bevy plugin reduces boilerplate when loading game assets. The crate offers the AssetCollection trait and can automatically load

Niklas Eicker 205 Jan 2, 2023
A sprite-sheet animation plugin for bevy

Benimator A sprite sheet animation plugin for bevy Features A SpriteSheetAnimation component to automatically update the indices of the TextureAtlasSp

Jonathan Cornaz 140 Dec 27, 2022
A Bevy Engine plugin for making 2D paths, smooth animations with Bezier curves

bevy_pen_tool A Bevy Engine plugin for making 2D paths and smooth animations with Bezier curves TODO: Mesh-making functionality for building 2D shapes

Eli 36 Dec 22, 2022
A procedural sky plugin for bevy

bevy_atmosphere A procedural sky plugin for bevy Example use bevy::prelude::*; use bevy_atmosphere::*; fn main() { App::build() .insert_re

Jonah Henriksson 137 Dec 23, 2022
Generic cellular automaton plugin for bevy.

Bevy Cellular Automaton bevy_life is a generic plugin for cellular automaton. From the classic 2D Conway's game of life to WireWorld and 3D rules, the

Félix Lescaudey de Maneville 34 Nov 23, 2022
Verlet physics plugin for bevy.

bevy_verlet Simple Verlet points and sticks implementation for bevy. Features You can simply add a VerletPoint component on any entity with a Transfor

Félix Lescaudey de Maneville 34 Dec 9, 2022
Bevy plugin for an AssetServer that can load embedded resources, or use other AssetServers based on the path.

Bevy-Embasset Embed your asset folder inside your binary. bevy-embasset adds support for loading assets embedded into the binary. Furthermore, it can

Johnny Tidemand Vestergaard 9 Aug 4, 2022