Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debug Draw #1625

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ bevy_winit = ["bevy_internal/bevy_winit"]
trace_chrome = ["bevy_internal/trace_chrome"]
trace = ["bevy_internal/trace"]
wgpu_trace = ["bevy_internal/wgpu_trace"]
debug_draw = ["bevy_internal/debug_draw"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
debug_draw = ["bevy_internal/debug_draw"]
debug_draw = ["bevy_internal/bevy_debug_draw"]

I think it must be named this, to succesfully compile.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to help. The other crates do not require a bevy_ prefix either.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is neccesary here, as you added it to bevy_internal this way:

bevy_debug_draw = { path = "../bevy_debug_draw", optional = true, version = "0.4.0" }

See the bevy_ prefix?
Those that don't need it, also don't have the prefix:

wgpu_trace = ["bevy_wgpu/trace"]
trace = [ "bevy_app/trace", "bevy_ecs/trace" ]
trace_chrome = [ "bevy_log/tracing-chrome" ]

For me applying that change allows cargo to compile, though there are still several compile errors:

  • The With<> I suggested below still needs to be imported.
  • The trait functions in the gizmo file, do not need a pub

But at least it's progress.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After fixing up the example, it also compiles successfully.
(Though I don't know why no Lines are drawn)
debug_lines

Copy link
Contributor

@MinerSebas MinerSebas Mar 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have sent you a PR on your Fork, with all the fixes. The5-1#1

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @MinerSebas .
I merged the PR on my fork and have the same behavior.
Will try and find the bug.


# Image format support for texture loading (PNG and HDR are enabled by default)
hdr = ["bevy_internal/hdr"]
Expand Down Expand Up @@ -119,6 +120,11 @@ path = "examples/2d/texture_atlas.rs"
name = "3d_scene"
path = "examples/3d/3d_scene.rs"

[[example]]
name = "debug_draw_3d"
path = "examples/3d/debug_draw_3d.rs"
required-features = ["debug_draw"]

[[example]]
name = "load_gltf"
path = "examples/3d/load_gltf.rs"
Expand Down
28 changes: 28 additions & 0 deletions crates/bevy_debug_draw/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "bevy_debug_draw"
version = "0.4.0"
edition = "2018"
authors = [
"Bevy Contributors <[email protected]>",
"Fabian Krauser <[email protected]>",
]
description = "Provides immediate mode debug drawing for the Bevy Engine"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT"
keywords = ["bevy"]


[dependencies]
# bevy
bevy_render = { path = "../bevy_render", version = "0.4.0" }
bevy_app = { path = "../bevy_app", version = "0.4.0" }
bevy_asset = { path = "../bevy_asset", version = "0.4.0" }
bevy_core = { path = "../bevy_core", version = "0.4.0" }
bevy_log = { path = "../bevy_log", version = "0.4.0" }
bevy_derive = { path = "../bevy_derive", version = "0.4.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.4.0" }
bevy_math = { path = "../bevy_math", version = "0.4.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.4.0", features = ["bevy"] }
bevy_transform = { path = "../bevy_transform", version = "0.4.0" }
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
192 changes: 192 additions & 0 deletions crates/bevy_debug_draw/src/debug_draw_3d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
use bevy_app::{AppBuilder, CoreStage, Plugin};
use bevy_asset::{AddAsset, Assets, Handle};
use bevy_ecs::{
prelude::{Commands, Query, ResMut},
schedule::*,
system::*,
};
use bevy_log::info;
use bevy_math::*;
use bevy_reflect::TypeUuid;
use bevy_render::{
mesh::*,
pipeline::{CullMode, PipelineDescriptor, PrimitiveTopology},
prelude::{Color, MeshBundle},
render_graph::{base, AssetRenderResourcesNode, RenderGraph},
renderer::RenderResources,
shader::{Shader, ShaderStage, ShaderStages},
};
use bevy_transform::{components::GlobalTransform, TransformSystem};
/// Bevy immediate mode debug drawing:
/// This crate introduces a DebugDraw3D resource which provides functions such as `draw_line(start, end, color)`
/// Whenever such a draw_line function is called, a set of vertices is added to the DebugDraw3D objects data.
/// At the end of the frame the internal data is copied into a mesh entity for drawing and then cleared from the DebugDraw3D object.
/// With this, no persistent line drawing is possible and lines have to be added every frame (hence immediate mode).
/// For convenience a system called `debug_draw_all_gizmos` is provided that draws a coordinate gizmo for any `GlobalTransform`.
///
/// ToDo:
/// * Add more convenience functions such as `draw_arrow(start, end, head_size, color)`, `draw_circle(origin, radius, axis, color)`, `draw_aabb(min,max,color)`.
/// * Modify the shader and access the depth buffer and perform hidden-line rendering rather than a binary depth test for better line visualization.
/// * Add the `debug_draw_all_gizmos` system to the plugin, using a parameter to turn it on or off.
/// * Add transparent triangle drawing (useful to visually project a line down on a plane) and matching utility functions.
/// * Add timed or persistent drawing: This requires storing `Line` structs containing a lifetime rather than directly pushing to an array.
/// * Even though this is a debug feature, there current approach may likely not be the most performant solution and optimizations/refactoring should be applied.

pub struct DebugDrawPlugin;
impl Plugin for DebugDrawPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_asset::<DebugDraw3DMaterial>()
.init_resource::<DebugDraw3D>()
.add_startup_system(setup_debug_draw_3d.system())
.add_system_to_stage(
CoreStage::PostUpdate,
update_debug_draw_3d
.system()
.after(TransformSystem::TransformPropagate),
);
}
}

/// DebugDraw3D Resource providing functions for immediate mode drawing
pub struct DebugDraw3D {
// The mesh data is held as plain arrays here
// If we wish to extend to more than just lines we may need multiple pairs that will later be ass, e.g. vertices_line and vertices_triangle
vertices: Vec<[f32; 3]>,
colors: Vec<[f32; 4]>,
dirty: bool,
clear: bool,
}

impl Default for DebugDraw3D {
fn default() -> Self {
DebugDraw3D {
vertices: Default::default(),
colors: Default::default(),
dirty: true,
clear: true,
}
}
}

impl DebugDraw3D {
pub fn draw_line(&mut self, start: Vec3, end: Vec3, color: Color) {
self.vertices.push(start.into());
self.vertices.push(end.into());
self.colors.push(color.into());
self.colors.push(color.into());
self.set_dirty();
}

pub fn set_dirty(&mut self) {
self.dirty = true;
}

pub fn reset(&mut self) {
if self.clear {
self.vertices.clear();
self.colors.clear();
}
self.dirty = false;
}

pub fn set_clear(&mut self, clear: bool) {
self.clear = clear;
}
}
/// This component marks the internal entity that does the mesh drawing.
#[derive(Default)]
struct DebugDraw3DComponent;

/// The Material holding the shader for debug drawing
#[derive(RenderResources, Default, TypeUuid)]
#[uuid = "188f0f97-60b2-476a-a749-7a0103adeeba"]
pub struct DebugDraw3DMaterial;

///This system sets up the entity holding the actual mesh for drawing as well as the render pipeline step for the shader.
fn setup_debug_draw_3d(
mut commands: Commands,
mut shaders: ResMut<Assets<Shader>>,
mut materials: ResMut<Assets<DebugDraw3DMaterial>>,
mut render_graph: ResMut<RenderGraph>,
) {
// Crate a shader Pipeline
let mut p = PipelineDescriptor::default_config(ShaderStages {
vertex: shaders.add(Shader::from_glsl(
ShaderStage::Vertex,
include_str!("shaders/debugDrawLine.vert"),
)),
fragment: Some(shaders.add(Shader::from_glsl(
ShaderStage::Fragment,
include_str!("shaders/debugDrawLine.frag"),
))),
});
p.primitive.topology = PrimitiveTopology::LineList;
p.primitive.cull_mode = CullMode::None;

// add the material to the pipeline
render_graph.add_system_node(
"debug_draw_3d",
AssetRenderResourcesNode::<DebugDraw3DMaterial>::new(false),
);
// connect that node stage the MAIN_PASS node
render_graph
.add_node_edge("debug_draw_3d", base::node::MAIN_PASS)
.unwrap();

let material_instance = materials.add(DebugDraw3DMaterial {});

// Spawn a entity that will do the debug drawing with its mesh
commands
.spawn(MeshBundle::default())
.with(material_instance)
.with(DebugDraw3DComponent::default())
.current_entity()
.unwrap();
The5-1 marked this conversation as resolved.
Show resolved Hide resolved

info!("Loaded debug lines plugin.");
}

/// This system updates the debug draw Entity with the data from
fn update_debug_draw_3d(
mut debug_draw: ResMut<DebugDraw3D>,
mut meshes: ResMut<Assets<Mesh>>,
query: Query<(&DebugDraw3DComponent, &Handle<Mesh>)>,
) {
if !debug_draw.dirty {
return;
} else {
for (_, mesh) in query.iter() {
The5-1 marked this conversation as resolved.
Show resolved Hide resolved
if let Some(mesh) = meshes.get_mut(mesh) {
mesh.set_attribute(
Mesh::ATTRIBUTE_POSITION,
VertexAttributeValues::Float3(debug_draw.vertices.clone()),
);
mesh.set_attribute(
"Vertex_Color",
VertexAttributeValues::Float4(debug_draw.colors.clone()),
);
}
}
}
debug_draw.reset();
}

pub fn debug_draw_all_gizmos(mut debug_draw: ResMut<DebugDraw3D>, query: Query<&GlobalTransform>) {
for transform in query.iter() {
debug_draw.draw_line(
transform.translation,
transform.translation + transform.local_x(),
Color::RED,
);
debug_draw.draw_line(
transform.translation,
transform.translation + transform.local_y(),
Color::GREEN,
);
debug_draw.draw_line(
transform.translation,
transform.translation + transform.local_z(),
Color::BLUE,
);
}
}
45 changes: 45 additions & 0 deletions crates/bevy_debug_draw/src/gizmo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use bevy_render::{mesh::*, pipeline::PrimitiveTopology};

pub struct CoordinateGizmo {
pub size: f32,
}

impl CoordinateGizmo {
pub fn new(size: f32) -> CoordinateGizmo {
CoordinateGizmo { size }
}
}

impl Default for CoordinateGizmo {
pub fn default() -> Self {
CoordinateGizmo { size: 1.0 }
}
}

impl From<CoordinateGizmo> for Mesh {
pub fn from(shape: CoordinateGizmo) -> Self {
let mut mesh = Mesh::new(PrimitiveTopology::LineList);
let vertices = vec![
[0.0, 0.0, 0.0],
[shape.size, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, shape.size, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, shape.size],
];
mesh.set_attribute(
Mesh::ATTRIBUTE_POSITION,
VertexAttributeValues::Float3(vertices),
);
let colors = vec![
[1.0, 0.0, 0.0, 1.0],
[1.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 0.0, 1.0],
[0.0, 1.0, 0.0, 1.0],
[0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0],
];
mesh.set_attribute("Vertex_Color", VertexAttributeValues::Float4(colors));
mesh
}
}
2 changes: 2 additions & 0 deletions crates/bevy_debug_draw/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod debug_draw_3d;
pub mod gizmo;
6 changes: 6 additions & 0 deletions crates/bevy_debug_draw/src/shaders/debugDrawLine.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#version 450
layout(location = 0) in vec4 vColor;
layout(location = 0) out vec4 o_Target;
void main() {
o_Target = vColor;
}
15 changes: 15 additions & 0 deletions crates/bevy_debug_draw/src/shaders/debugDrawLine.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#version 450
layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec4 Vertex_Color;
layout(location = 0) out vec4 vColor;

layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Transform {
mat4 Model;
};
void main() {
vColor = Vertex_Color;
gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
}
1 change: 1 addition & 0 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ bevy_audio = { path = "../bevy_audio", optional = true, version = "0.4.0" }
bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.4.0" }
bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.4.0" }
bevy_render = { path = "../bevy_render", optional = true, version = "0.4.0" }
bevy_debug_draw = { path = "../bevy_debug_draw", optional = true, version = "0.4.0" }
bevy_dynamic_plugin = { path = "../bevy_dynamic_plugin", optional = true, version = "0.4.0" }
bevy_sprite = { path = "../bevy_sprite", optional = true, version = "0.4.0" }
bevy_text = { path = "../bevy_text", optional = true, version = "0.4.0" }
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_internal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ pub mod render {
pub use bevy_render::*;
}

#[cfg(feature = "bevy_debug_draw")]
pub mod debug_draw {
//! Immediate mode debug drawing, like a visual println.
pub use bevy_debug_draw::*;
}

#[cfg(feature = "bevy_sprite")]
pub mod sprite {
//! Items for sprites, rects, texture atlases, etc.
Expand Down
44 changes: 44 additions & 0 deletions examples/3d/debug_draw_3d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use bevy::prelude::*;
use bevy::debug_draw::*;

fn main() {
App::build()
.insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(debug_draw_all_gizmos.system()) //add the system to draw a coordinate gizmo for all Objects
.run();
}

/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// add entities to the world
commands
// plane
.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
..Default::default()
})
// cube
.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(0.0, 0.5, 0.0),
..Default::default()
})
// light
.spawn(LightBundle {
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..Default::default()
})
// camera
.spawn(PerspectiveCameraBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::default(), Vec3::Y),
..Default::default()
});
}
1 change: 1 addition & 0 deletions tools/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ crates=(
bevy_transform
bevy_window
bevy_render
bevy_debug_draw
bevy_input
bevy_gilrs
bevy_pbr
Expand Down