Testbed: switch to bevy 0.7
This commit is contained in:
@@ -38,17 +38,17 @@ bincode = "1"
|
|||||||
Inflector = "0.11"
|
Inflector = "0.11"
|
||||||
md5 = "0.7"
|
md5 = "0.7"
|
||||||
|
|
||||||
bevy_egui = "0.10"
|
bevy_egui = "0.13"
|
||||||
bevy_ecs = "0.6"
|
bevy_ecs = "0.7"
|
||||||
bevy_prototype_debug_lines = "0.6"
|
#bevy_prototype_debug_lines = "0.7"
|
||||||
|
|
||||||
# Dependencies for native only.
|
# Dependencies for native only.
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
||||||
|
|
||||||
# Dependencies for WASM only.
|
# Dependencies for WASM only.
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render"]}
|
||||||
#bevy_webgl2 = "0.5"
|
#bevy_webgl2 = "0.5"
|
||||||
|
|
||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
|
|||||||
@@ -38,17 +38,17 @@ bincode = "1"
|
|||||||
Inflector = "0.11"
|
Inflector = "0.11"
|
||||||
md5 = "0.7"
|
md5 = "0.7"
|
||||||
|
|
||||||
bevy_egui = "0.10"
|
bevy_egui = "0.13"
|
||||||
bevy_ecs = "0.6"
|
bevy_ecs = "0.7"
|
||||||
bevy_prototype_debug_lines = "0.6"
|
#bevy_prototype_debug_lines = "0.7"
|
||||||
|
|
||||||
# Dependencies for native only.
|
# Dependencies for native only.
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
||||||
|
|
||||||
# Dependencies for WASM only.
|
# Dependencies for WASM only.
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render"]}
|
||||||
#bevy_webgl2 = "0.5"
|
#bevy_webgl2 = "0.5"
|
||||||
|
|
||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
|
|||||||
@@ -36,17 +36,17 @@ md5 = "0.7"
|
|||||||
Inflector = "0.11"
|
Inflector = "0.11"
|
||||||
serde = { version = "1", features = [ "derive" ] }
|
serde = { version = "1", features = [ "derive" ] }
|
||||||
|
|
||||||
bevy_egui = "0.10"
|
bevy_egui = "0.13"
|
||||||
bevy_ecs = "0.6"
|
bevy_ecs = "0.7"
|
||||||
bevy_prototype_debug_lines = { version = "0.6", features = [ "3d" ] }
|
#bevy_prototype_debug_lines = { version = "0.7", features = [ "3d" ] }
|
||||||
|
|
||||||
# Dependencies for native only.
|
# Dependencies for native only.
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
||||||
|
|
||||||
# Dependencies for WASM only.
|
# Dependencies for WASM only.
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render"]}
|
||||||
#bevy_webgl2 = "0.5"
|
#bevy_webgl2 = "0.5"
|
||||||
|
|
||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
|
|||||||
@@ -40,17 +40,17 @@ md5 = "0.7"
|
|||||||
Inflector = "0.11"
|
Inflector = "0.11"
|
||||||
serde = { version = "1", features = [ "derive" ] }
|
serde = { version = "1", features = [ "derive" ] }
|
||||||
|
|
||||||
bevy_egui = "0.10"
|
bevy_egui = "0.13"
|
||||||
bevy_ecs = "0.6"
|
bevy_ecs = "0.7"
|
||||||
bevy_prototype_debug_lines = { version = "0.6", features = [ "3d" ] }
|
#bevy_prototype_debug_lines = { version = "0.7", features = [ "3d" ] }
|
||||||
|
|
||||||
# Dependencies for native only.
|
# Dependencies for native only.
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render", "x11"]}
|
||||||
|
|
||||||
# Dependencies for WASM only.
|
# Dependencies for WASM only.
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "render"]}
|
bevy = {version = "0.7", default-features = false, features = ["bevy_winit", "render"]}
|
||||||
#bevy_webgl2 = "0.5"
|
#bevy_webgl2 = "0.5"
|
||||||
|
|
||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ impl OrbitCameraPlugin {
|
|||||||
}
|
}
|
||||||
impl Plugin for OrbitCameraPlugin {
|
impl Plugin for OrbitCameraPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_system(Self::mouse_motion_system.system())
|
app.add_system(Self::mouse_motion_system)
|
||||||
.add_system(Self::zoom_system.system())
|
.add_system(Self::zoom_system)
|
||||||
.add_system(Self::update_transform_system.system());
|
.add_system(Self::update_transform_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,8 +113,8 @@ impl OrbitCameraPlugin {
|
|||||||
}
|
}
|
||||||
impl Plugin for OrbitCameraPlugin {
|
impl Plugin for OrbitCameraPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_system(Self::mouse_motion_system.system())
|
app.add_system(Self::mouse_motion_system)
|
||||||
.add_system(Self::zoom_system.system())
|
.add_system(Self::zoom_system)
|
||||||
.add_system(Self::update_transform_system.system());
|
.add_system(Self::update_transform_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::harness::Harness;
|
use crate::harness::Harness;
|
||||||
|
use crate::lines::DebugLines;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_prototype_debug_lines::DebugLines;
|
|
||||||
use rapier::math::{Point, Real, DIM};
|
use rapier::math::{Point, Real, DIM};
|
||||||
use rapier::pipeline::{
|
use rapier::pipeline::{
|
||||||
DebugRenderBackend, DebugRenderMode, DebugRenderObject, DebugRenderPipeline,
|
DebugRenderBackend, DebugRenderMode, DebugRenderObject, DebugRenderPipeline,
|
||||||
@@ -29,9 +29,9 @@ impl RapierDebugRenderPlugin {
|
|||||||
|
|
||||||
impl Plugin for RapierDebugRenderPlugin {
|
impl Plugin for RapierDebugRenderPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_plugin(
|
app.add_plugin(crate::lines::DebugLinesPlugin::with_depth_test(
|
||||||
bevy_prototype_debug_lines::DebugLinesPlugin::with_depth_test(self.depth_test),
|
self.depth_test,
|
||||||
)
|
))
|
||||||
.insert_resource(DebugRenderPipeline::new(
|
.insert_resource(DebugRenderPipeline::new(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
!DebugRenderMode::RIGID_BODY_AXES,
|
!DebugRenderMode::RIGID_BODY_AXES,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ mod camera3d;
|
|||||||
mod debug_render;
|
mod debug_render;
|
||||||
mod graphics;
|
mod graphics;
|
||||||
pub mod harness;
|
pub mod harness;
|
||||||
|
mod lines;
|
||||||
pub mod objects;
|
pub mod objects;
|
||||||
pub mod physics;
|
pub mod physics;
|
||||||
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
||||||
|
|||||||
49
src_testbed/lines/debuglines.wgsl
Normal file
49
src_testbed/lines/debuglines.wgsl
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// This should work, but it's bugged right now so we have to use 2 shaders: https://github.com/bevyengine/bevy/issues/4011
|
||||||
|
#ifdef LINES_3D
|
||||||
|
#import bevy_pbr::mesh_view_bind_group
|
||||||
|
//#import bevy_pbr::mesh_struct
|
||||||
|
#else
|
||||||
|
//#import bevy_sprite::mesh2d_view_bind_group
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
[[location(0)]] pos: vec3<f32>;
|
||||||
|
[[location(1)]] color: u32;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
[[builtin(position)]] clip_position: vec4<f32>;
|
||||||
|
[[location(0)]] color: vec4<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentOutput {
|
||||||
|
[[builtin(frag_depth)]] depth: f32;
|
||||||
|
[[location(0)]] color: vec4<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(vertex)]]
|
||||||
|
fn vertex(vertex: Vertex) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.clip_position = view.view_proj * vec4<f32>(vertex.pos, 1.0);
|
||||||
|
//out.color = vertex.color;
|
||||||
|
// https://github.com/bevyengine/bevy/blob/328c26d02c50de0bc77f0d24a376f43ba89517b1/examples/2d/mesh2d_manual.rs#L234
|
||||||
|
out.color = vec4<f32>((vec4<u32>(vertex.color) >> vec4<u32>(8u, 8u, 16u, 24u)) & vec4<u32>(255u)) / 255.0;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn fragment(in: VertexOutput) -> FragmentOutput {
|
||||||
|
var out: FragmentOutput;
|
||||||
|
|
||||||
|
// This should be #ifdef DEPTH_TEST_ENABLED && LINES_3D, but the
|
||||||
|
// preprocessor doesn't support that yet.
|
||||||
|
// Luckily, DEPTH_TEST_ENABLED isn't set in 2d anyway.
|
||||||
|
#ifdef DEPTH_TEST_ENABLED
|
||||||
|
out.depth = in.clip_position.z;
|
||||||
|
#else
|
||||||
|
out.depth = 1.0;
|
||||||
|
#endif
|
||||||
|
out.color = in.color;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
31
src_testbed/lines/debuglines2d.wgsl
Normal file
31
src_testbed/lines/debuglines2d.wgsl
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#import bevy_sprite::mesh2d_view_bind_group
|
||||||
|
[[group(0), binding(0)]]
|
||||||
|
var<uniform> view: View;
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
//[[location(0)]] color: vec4<f32>;
|
||||||
|
[[location(0)]] place: vec3<f32>;
|
||||||
|
[[location(1)]] color: u32;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
[[builtin(position)]] clip_position: vec4<f32>;
|
||||||
|
[[location(0)]] color: vec4<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[stage(vertex)]]
|
||||||
|
fn vertex(vertex: Vertex) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.clip_position = view.view_proj * vec4<f32>(vertex.place, 1.0);
|
||||||
|
// What is this craziness?
|
||||||
|
out.color = vec4<f32>((vec4<u32>(vertex.color) >> vec4<u32>(0u, 8u, 16u, 24u)) & vec4<u32>(255u)) / 255.0;
|
||||||
|
//out.color = vertex.color;
|
||||||
|
//out.color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
||||||
|
return in.color;
|
||||||
|
}
|
||||||
358
src_testbed/lines/mod.rs
Normal file
358
src_testbed/lines/mod.rs
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
use bevy::{
|
||||||
|
asset::{Assets, HandleUntyped},
|
||||||
|
pbr::{NotShadowCaster, NotShadowReceiver},
|
||||||
|
prelude::*,
|
||||||
|
reflect::TypeUuid,
|
||||||
|
render::{
|
||||||
|
mesh::{/*Indices,*/ Mesh, VertexAttributeValues},
|
||||||
|
render_phase::AddRenderCommand,
|
||||||
|
render_resource::PrimitiveTopology,
|
||||||
|
render_resource::Shader,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod render_dim;
|
||||||
|
|
||||||
|
// This module exists to "isolate" the `#[cfg]` attributes to this part of the
|
||||||
|
// code. Otherwise, we would pollute the code with a lot of feature
|
||||||
|
// gates-specific code.
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
|
mod dim {
|
||||||
|
pub(crate) use crate::lines::render_dim::r3d::{queue, DebugLinePipeline, DrawDebugLines};
|
||||||
|
pub(crate) use bevy::core_pipeline::Opaque3d as Phase;
|
||||||
|
use bevy::{asset::Handle, render::mesh::Mesh};
|
||||||
|
|
||||||
|
pub(crate) type MeshHandle = Handle<Mesh>;
|
||||||
|
pub(crate) fn from_handle(from: &MeshHandle) -> &Handle<Mesh> {
|
||||||
|
from
|
||||||
|
}
|
||||||
|
pub(crate) fn into_handle(from: Handle<Mesh>) -> MeshHandle {
|
||||||
|
from
|
||||||
|
}
|
||||||
|
pub(crate) const SHADER_FILE: &str = include_str!("debuglines.wgsl");
|
||||||
|
pub(crate) const DIMMENSION: &str = "3d";
|
||||||
|
}
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
mod dim {
|
||||||
|
pub(crate) use crate::lines::render_dim::r2d::{queue, DebugLinePipeline, DrawDebugLines};
|
||||||
|
pub(crate) use bevy::core_pipeline::Transparent2d as Phase;
|
||||||
|
use bevy::{asset::Handle, render::mesh::Mesh, sprite::Mesh2dHandle};
|
||||||
|
|
||||||
|
pub(crate) type MeshHandle = Mesh2dHandle;
|
||||||
|
pub(crate) fn from_handle(from: &MeshHandle) -> &Handle<Mesh> {
|
||||||
|
&from.0
|
||||||
|
}
|
||||||
|
pub(crate) fn into_handle(from: Handle<Mesh>) -> MeshHandle {
|
||||||
|
Mesh2dHandle(from)
|
||||||
|
}
|
||||||
|
pub(crate) const SHADER_FILE: &str = include_str!("debuglines2d.wgsl");
|
||||||
|
pub(crate) const DIMMENSION: &str = "2d";
|
||||||
|
}
|
||||||
|
|
||||||
|
// See debuglines.wgsl for explanation on 2 shaders.
|
||||||
|
//pub(crate) const SHADER_FILE: &str = include_str!("debuglines.wgsl");
|
||||||
|
pub(crate) const DEBUG_LINES_SHADER_HANDLE: HandleUntyped =
|
||||||
|
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 17477439189930443325);
|
||||||
|
|
||||||
|
pub(crate) struct DebugLinesConfig {
|
||||||
|
depth_test: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bevy plugin, for initializing stuff.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use bevy::prelude::*;
|
||||||
|
/// use bevy_prototype_debug_lines::*;
|
||||||
|
///
|
||||||
|
/// App::new()
|
||||||
|
/// .add_plugins(DefaultPlugins)
|
||||||
|
/// .add_plugin(DebugLinesPlugin::default())
|
||||||
|
/// .run();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Alternatively, you can initialize the plugin with depth testing, so that
|
||||||
|
/// debug lines cut through geometry. To do this, use [`DebugLinesPlugin::with_depth_test(true)`].
|
||||||
|
/// ```
|
||||||
|
/// use bevy::prelude::*;
|
||||||
|
/// use bevy_prototype_debug_lines::*;
|
||||||
|
///
|
||||||
|
/// App::new()
|
||||||
|
/// .add_plugins(DefaultPlugins)
|
||||||
|
/// .add_plugin(DebugLinesPlugin::with_depth_test(true))
|
||||||
|
/// .run();
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct DebugLinesPlugin {
|
||||||
|
depth_test: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugLinesPlugin {
|
||||||
|
/// Controls whether debug lines should be drawn with depth testing enabled
|
||||||
|
/// or disabled.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `val` - True if lines should intersect with other geometry, or false
|
||||||
|
/// if lines should always draw on top be drawn on top (the default).
|
||||||
|
pub fn with_depth_test(val: bool) -> Self {
|
||||||
|
Self { depth_test: val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for DebugLinesPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
use bevy::render::{render_resource::SpecializedMeshPipelines, RenderApp, RenderStage};
|
||||||
|
let mut shaders = app.world.get_resource_mut::<Assets<Shader>>().unwrap();
|
||||||
|
shaders.set_untracked(
|
||||||
|
DEBUG_LINES_SHADER_HANDLE,
|
||||||
|
Shader::from_wgsl(dim::SHADER_FILE),
|
||||||
|
);
|
||||||
|
app.init_resource::<DebugLines>();
|
||||||
|
app.add_startup_system(setup)
|
||||||
|
.add_system_to_stage(CoreStage::PostUpdate, update.label("draw_lines"));
|
||||||
|
app.sub_app_mut(RenderApp)
|
||||||
|
.add_render_command::<dim::Phase, dim::DrawDebugLines>()
|
||||||
|
.insert_resource(DebugLinesConfig {
|
||||||
|
depth_test: self.depth_test,
|
||||||
|
})
|
||||||
|
.init_resource::<dim::DebugLinePipeline>()
|
||||||
|
.init_resource::<SpecializedMeshPipelines<dim::DebugLinePipeline>>()
|
||||||
|
.add_system_to_stage(RenderStage::Extract, extract)
|
||||||
|
.add_system_to_stage(RenderStage::Queue, dim::queue);
|
||||||
|
|
||||||
|
info!("Loaded {} debug lines plugin.", dim::DIMMENSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of meshes to separate line buffers into.
|
||||||
|
// We don't really do culling currently but this is a gateway to that.
|
||||||
|
const MESH_COUNT: usize = 4;
|
||||||
|
// Maximum number of points for each individual mesh.
|
||||||
|
const MAX_POINTS_PER_MESH: usize = 2_usize.pow(16);
|
||||||
|
const _MAX_LINES_PER_MESH: usize = MAX_POINTS_PER_MESH / 2;
|
||||||
|
/// Maximum number of points.
|
||||||
|
pub const MAX_POINTS: usize = MAX_POINTS_PER_MESH * MESH_COUNT;
|
||||||
|
/// Maximum number of unique lines to draw at once.
|
||||||
|
pub const MAX_LINES: usize = MAX_POINTS / 2;
|
||||||
|
|
||||||
|
fn setup(mut cmds: Commands, mut meshes: ResMut<Assets<Mesh>>) {
|
||||||
|
// Spawn a bunch of meshes to use for lines.
|
||||||
|
for i in 0..MESH_COUNT {
|
||||||
|
// Create a new mesh with the number of vertices we need.
|
||||||
|
let mut mesh = Mesh::new(PrimitiveTopology::LineList);
|
||||||
|
mesh.insert_attribute(
|
||||||
|
Mesh::ATTRIBUTE_POSITION,
|
||||||
|
VertexAttributeValues::Float32x3(Vec::with_capacity(MAX_POINTS_PER_MESH)),
|
||||||
|
);
|
||||||
|
mesh.insert_attribute(
|
||||||
|
Mesh::ATTRIBUTE_COLOR,
|
||||||
|
VertexAttributeValues::Uint32(Vec::with_capacity(MAX_POINTS_PER_MESH)),
|
||||||
|
);
|
||||||
|
// https://github.com/Toqozz/bevy_debug_lines/issues/16
|
||||||
|
//mesh.set_indices(Some(Indices::U16(Vec::with_capacity(MAX_POINTS_PER_MESH))));
|
||||||
|
|
||||||
|
cmds.spawn_bundle((
|
||||||
|
dim::into_handle(meshes.add(mesh)),
|
||||||
|
NotShadowCaster,
|
||||||
|
NotShadowReceiver,
|
||||||
|
Transform::default(),
|
||||||
|
GlobalTransform::default(),
|
||||||
|
Visibility::default(),
|
||||||
|
ComputedVisibility::default(),
|
||||||
|
DebugLinesMesh(i),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(
|
||||||
|
debug_line_meshes: Query<(&dim::MeshHandle, &DebugLinesMesh)>,
|
||||||
|
time: Res<Time>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut lines: ResMut<DebugLines>,
|
||||||
|
) {
|
||||||
|
// For each debug line mesh, fill its buffers with the relevant positions/colors chunks.
|
||||||
|
for (mesh_handle, debug_lines_idx) in debug_line_meshes.iter() {
|
||||||
|
let mesh = meshes.get_mut(dim::from_handle(mesh_handle)).unwrap();
|
||||||
|
use VertexAttributeValues::{Float32x3, Float32x4, Uint32};
|
||||||
|
if let Some(Float32x3(vbuffer)) = mesh.attribute_mut(Mesh::ATTRIBUTE_POSITION) {
|
||||||
|
vbuffer.clear();
|
||||||
|
if let Some(new_content) = lines
|
||||||
|
.positions
|
||||||
|
.chunks(MAX_POINTS_PER_MESH)
|
||||||
|
.nth(debug_lines_idx.0)
|
||||||
|
{
|
||||||
|
vbuffer.extend(new_content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(Uint32(cbuffer)) = mesh.attribute_mut(Mesh::ATTRIBUTE_COLOR) {
|
||||||
|
cbuffer.clear();
|
||||||
|
if let Some(new_content) = lines
|
||||||
|
.colors
|
||||||
|
.chunks(MAX_POINTS_PER_MESH)
|
||||||
|
.nth(debug_lines_idx.0)
|
||||||
|
{
|
||||||
|
cbuffer.extend(new_content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// https://github.com/Toqozz/bevy_debug_lines/issues/16
|
||||||
|
if let Some(Indices::U16(indices)) = mesh.indices_mut() {
|
||||||
|
indices.clear();
|
||||||
|
if let Some(new_content) = lines.durations.chunks(_MAX_LINES_PER_MESH).nth(debug_lines_idx.0) {
|
||||||
|
indices.extend(
|
||||||
|
new_content.iter().enumerate().map(|(i, _)| i as u16).flat_map(|i| [i * 2, i*2 + 1])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processes stuff like getting rid of expired lines and stuff.
|
||||||
|
lines.update(time.delta_seconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move the DebugLinesMesh marker Component to the render context.
|
||||||
|
fn extract(mut commands: Commands, query: Query<Entity, With<DebugLinesMesh>>) {
|
||||||
|
for entity in query.iter() {
|
||||||
|
commands.get_or_spawn(entity).insert(RenderDebugLinesMesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct DebugLinesMesh(usize);
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub(crate) struct RenderDebugLinesMesh;
|
||||||
|
|
||||||
|
/// Bevy resource providing facilities to draw lines.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
/// ```
|
||||||
|
/// use bevy::prelude::*;
|
||||||
|
/// use bevy_prototype_debug_lines::*;
|
||||||
|
///
|
||||||
|
/// // Draws 3 horizontal lines, which disappear after 1 frame.
|
||||||
|
/// fn some_system(mut lines: ResMut<DebugLines>) {
|
||||||
|
/// lines.line(Vec3::new(-1.0, 1.0, 0.0), Vec3::new(1.0, 1.0, 0.0), 0.0);
|
||||||
|
/// lines.line_colored(
|
||||||
|
/// Vec3::new(-1.0, 0.0, 0.0),
|
||||||
|
/// Vec3::new(1.0, 0.0, 0.0),
|
||||||
|
/// 0.0,
|
||||||
|
/// Color::WHITE
|
||||||
|
/// );
|
||||||
|
/// lines.line_gradient(
|
||||||
|
/// Vec3::new(-1.0, -1.0, 0.0),
|
||||||
|
/// Vec3::new(1.0, -1.0, 0.0),
|
||||||
|
/// 0.0,
|
||||||
|
/// Color::WHITE, Color::PINK
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DebugLines {
|
||||||
|
pub positions: Vec<[f32; 3]>,
|
||||||
|
//pub colors: Vec<[f32; 4]>,
|
||||||
|
pub colors: Vec<u32>,
|
||||||
|
pub durations: Vec<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugLines {
|
||||||
|
/// Draw a line in world space, or update an existing line
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `start` - The start of the line in world space
|
||||||
|
/// * `end` - The end of the line in world space
|
||||||
|
/// * `duration` - Duration (in seconds) that the line should show for -- a value of
|
||||||
|
/// zero will show the line for 1 frame.
|
||||||
|
pub fn line(&mut self, start: Vec3, end: Vec3, duration: f32) {
|
||||||
|
self.line_colored(start, end, duration, Color::WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a line in world space with a specified color, or update an existing line
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `start` - The start of the line in world space
|
||||||
|
/// * `end` - The end of the line in world space
|
||||||
|
/// * `duration` - Duration (in seconds) that the line should show for -- a value of
|
||||||
|
/// zero will show the line for 1 frame.
|
||||||
|
/// * `color` - Line color
|
||||||
|
pub fn line_colored(&mut self, start: Vec3, end: Vec3, duration: f32, color: Color) {
|
||||||
|
self.line_gradient(start, end, duration, color, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a line in world space with a specified gradient color, or update an existing line
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `start` - The start of the line in world space
|
||||||
|
/// * `end` - The end of the line in world space
|
||||||
|
/// * `duration` - Duration (in seconds) that the line should show for -- a value of
|
||||||
|
/// zero will show the line for 1 frame.
|
||||||
|
/// * `start_color` - Line color
|
||||||
|
/// * `end_color` - Line color
|
||||||
|
pub fn line_gradient(
|
||||||
|
&mut self,
|
||||||
|
start: Vec3,
|
||||||
|
end: Vec3,
|
||||||
|
duration: f32,
|
||||||
|
start_color: Color,
|
||||||
|
end_color: Color,
|
||||||
|
) {
|
||||||
|
if self.positions.len() >= MAX_POINTS {
|
||||||
|
warn!("Tried to add a new line when existing number of lines was already at maximum, ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.positions.push(start.into());
|
||||||
|
self.positions.push(end.into());
|
||||||
|
//self.colors.push(start_color.into());
|
||||||
|
//self.colors.push(end_color.into());
|
||||||
|
self.colors.push(start_color.as_rgba_u32());
|
||||||
|
self.colors.push(end_color.as_rgba_u32());
|
||||||
|
self.durations.push(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the indices of the start and end positions of the nth line.
|
||||||
|
// The indices can also be used to access color data.
|
||||||
|
fn nth(&self, idx: usize) -> (usize, usize) {
|
||||||
|
let i = idx * 2;
|
||||||
|
(i, i + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare [`ImmediateLinesStorage`] and [`RetainedLinesStorage`] for next
|
||||||
|
// frame.
|
||||||
|
// This clears the immediate mod buffers and tells the retained mode
|
||||||
|
// buffers to recompute expired lines list.
|
||||||
|
fn update(&mut self, dt: f32) {
|
||||||
|
// TODO: an actual line counter wouldn't hurt.
|
||||||
|
let mut i = 0;
|
||||||
|
let mut len = self.durations.len();
|
||||||
|
while i != len {
|
||||||
|
self.durations[i] -= dt;
|
||||||
|
// <= instead of < is fine here because this is always called AFTER sending the
|
||||||
|
// data to the mesh, so we're guaranteed at least a frame here.
|
||||||
|
if self.durations[i] <= 0.0 {
|
||||||
|
let (cur_s, cur_e) = self.nth(i);
|
||||||
|
let (last_s, last_e) = self.nth(len - 1);
|
||||||
|
self.positions.swap(cur_s, last_s);
|
||||||
|
self.positions.swap(cur_e, last_e);
|
||||||
|
self.colors.swap(cur_s, last_s);
|
||||||
|
self.colors.swap(cur_e, last_e);
|
||||||
|
self.durations.swap(i, len - 1);
|
||||||
|
len -= 1;
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.positions.truncate(len * 2);
|
||||||
|
self.colors.truncate(len * 2);
|
||||||
|
self.durations.truncate(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
335
src_testbed/lines/render_dim.rs
Normal file
335
src_testbed/lines/render_dim.rs
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
pub mod r3d {
|
||||||
|
use bevy::{
|
||||||
|
core_pipeline::Opaque3d,
|
||||||
|
pbr::{
|
||||||
|
DrawMesh, MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup,
|
||||||
|
SetMeshViewBindGroup,
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
render::{
|
||||||
|
mesh::MeshVertexBufferLayout,
|
||||||
|
render_asset::RenderAssets,
|
||||||
|
render_phase::{DrawFunctions, RenderPhase, SetItemPipeline},
|
||||||
|
render_resource::{
|
||||||
|
BlendState, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState,
|
||||||
|
DepthStencilState, FragmentState, FrontFace, MultisampleState, PipelineCache,
|
||||||
|
PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipelineDescriptor,
|
||||||
|
SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines,
|
||||||
|
StencilFaceState, StencilState, TextureFormat, VertexAttribute, VertexBufferLayout,
|
||||||
|
VertexFormat, VertexState, VertexStepMode,
|
||||||
|
},
|
||||||
|
texture::BevyDefault,
|
||||||
|
view::{ExtractedView, Msaa},
|
||||||
|
},
|
||||||
|
utils::Hashed,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::lines::{DebugLinesConfig, RenderDebugLinesMesh, DEBUG_LINES_SHADER_HANDLE};
|
||||||
|
|
||||||
|
pub(crate) struct DebugLinePipeline {
|
||||||
|
mesh_pipeline: MeshPipeline,
|
||||||
|
shader: Handle<Shader>,
|
||||||
|
//always_in_front: bool,
|
||||||
|
}
|
||||||
|
impl FromWorld for DebugLinePipeline {
|
||||||
|
fn from_world(render_world: &mut World) -> Self {
|
||||||
|
//let config = render_world.get_resource::<DebugLinesConfig>().unwrap();
|
||||||
|
DebugLinePipeline {
|
||||||
|
mesh_pipeline: render_world.get_resource::<MeshPipeline>().unwrap().clone(),
|
||||||
|
shader: DEBUG_LINES_SHADER_HANDLE.typed(),
|
||||||
|
//always_in_front: config.always_in_front,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecializedMeshPipeline for DebugLinePipeline {
|
||||||
|
type Key = (bool, MeshPipelineKey);
|
||||||
|
|
||||||
|
fn specialize(
|
||||||
|
&self,
|
||||||
|
(depth_test, key): Self::Key,
|
||||||
|
layout: &MeshVertexBufferLayout,
|
||||||
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
|
//use VertexFormat::{Float32x3, Float32x4};
|
||||||
|
|
||||||
|
let mut shader_defs = Vec::new();
|
||||||
|
shader_defs.push("LINES_3D".to_string());
|
||||||
|
if depth_test {
|
||||||
|
shader_defs.push("DEPTH_TEST_ENABLED".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let vertex_buffer_layout = layout.get_layout(&[
|
||||||
|
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
|
||||||
|
Mesh::ATTRIBUTE_COLOR.at_shader_location(1),
|
||||||
|
])?;
|
||||||
|
let (label, blend, depth_write_enabled);
|
||||||
|
if key.contains(MeshPipelineKey::TRANSPARENT_MAIN_PASS) {
|
||||||
|
label = "transparent_mesh_pipeline".into();
|
||||||
|
blend = Some(BlendState::ALPHA_BLENDING);
|
||||||
|
// For the transparent pass, fragments that are closer will be alpha
|
||||||
|
// blended but their depth is not written to the depth buffer.
|
||||||
|
depth_write_enabled = false;
|
||||||
|
} else {
|
||||||
|
label = "opaque_mesh_pipeline".into();
|
||||||
|
blend = Some(BlendState::REPLACE);
|
||||||
|
// For the opaque and alpha mask passes, fragments that are closer
|
||||||
|
// will replace the current fragment value in the output and the depth is
|
||||||
|
// written to the depth buffer.
|
||||||
|
depth_write_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(RenderPipelineDescriptor {
|
||||||
|
vertex: VertexState {
|
||||||
|
shader: self.shader.clone_weak(),
|
||||||
|
entry_point: "vertex".into(),
|
||||||
|
shader_defs: shader_defs.clone(),
|
||||||
|
buffers: vec![vertex_buffer_layout],
|
||||||
|
},
|
||||||
|
fragment: Some(FragmentState {
|
||||||
|
shader: self.shader.clone_weak(),
|
||||||
|
shader_defs,
|
||||||
|
entry_point: "fragment".into(),
|
||||||
|
targets: vec![ColorTargetState {
|
||||||
|
format: TextureFormat::bevy_default(),
|
||||||
|
blend,
|
||||||
|
write_mask: ColorWrites::ALL,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
layout: Some(vec![self.mesh_pipeline.view_layout.clone()]),
|
||||||
|
primitive: PrimitiveState {
|
||||||
|
front_face: FrontFace::Ccw,
|
||||||
|
cull_mode: None,
|
||||||
|
unclipped_depth: false,
|
||||||
|
polygon_mode: PolygonMode::Fill,
|
||||||
|
conservative: false,
|
||||||
|
topology: PrimitiveTopology::LineList,
|
||||||
|
strip_index_format: None,
|
||||||
|
},
|
||||||
|
depth_stencil: Some(DepthStencilState {
|
||||||
|
format: TextureFormat::Depth32Float,
|
||||||
|
depth_write_enabled,
|
||||||
|
depth_compare: CompareFunction::Greater,
|
||||||
|
stencil: StencilState {
|
||||||
|
front: StencilFaceState::IGNORE,
|
||||||
|
back: StencilFaceState::IGNORE,
|
||||||
|
read_mask: 0,
|
||||||
|
write_mask: 0,
|
||||||
|
},
|
||||||
|
bias: DepthBiasState {
|
||||||
|
constant: 0,
|
||||||
|
slope_scale: 0.0,
|
||||||
|
clamp: 0.0,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
multisample: MultisampleState {
|
||||||
|
count: key.msaa_samples(),
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
label: Some(label),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn queue(
|
||||||
|
opaque_3d_draw_functions: Res<DrawFunctions<Opaque3d>>,
|
||||||
|
debug_line_pipeline: Res<DebugLinePipeline>,
|
||||||
|
mut pipelines: ResMut<SpecializedMeshPipelines<DebugLinePipeline>>,
|
||||||
|
mut pipeline_cache: ResMut<PipelineCache>,
|
||||||
|
render_meshes: Res<RenderAssets<Mesh>>,
|
||||||
|
msaa: Res<Msaa>,
|
||||||
|
material_meshes: Query<(Entity, &MeshUniform, &Handle<Mesh>), With<RenderDebugLinesMesh>>,
|
||||||
|
config: Res<DebugLinesConfig>,
|
||||||
|
mut views: Query<(&ExtractedView, &mut RenderPhase<Opaque3d>)>,
|
||||||
|
) {
|
||||||
|
let draw_custom = opaque_3d_draw_functions
|
||||||
|
.read()
|
||||||
|
.get_id::<DrawDebugLines>()
|
||||||
|
.unwrap();
|
||||||
|
let key = MeshPipelineKey::from_msaa_samples(msaa.samples);
|
||||||
|
for (view, mut transparent_phase) in views.iter_mut() {
|
||||||
|
let view_matrix = view.transform.compute_matrix();
|
||||||
|
let view_row_2 = view_matrix.row(2);
|
||||||
|
for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() {
|
||||||
|
if let Some(mesh) = render_meshes.get(mesh_handle) {
|
||||||
|
let pipeline = pipelines
|
||||||
|
.specialize(
|
||||||
|
&mut pipeline_cache,
|
||||||
|
&debug_line_pipeline,
|
||||||
|
(config.depth_test, key),
|
||||||
|
&mesh.layout,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
transparent_phase.add(Opaque3d {
|
||||||
|
entity,
|
||||||
|
pipeline,
|
||||||
|
draw_function: draw_custom,
|
||||||
|
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type DrawDebugLines = (
|
||||||
|
SetItemPipeline,
|
||||||
|
SetMeshViewBindGroup<0>,
|
||||||
|
SetMeshBindGroup<1>,
|
||||||
|
DrawMesh,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod r2d {
|
||||||
|
use bevy::{
|
||||||
|
asset::Handle,
|
||||||
|
core::FloatOrd,
|
||||||
|
core_pipeline::Transparent2d,
|
||||||
|
prelude::*,
|
||||||
|
render::{
|
||||||
|
mesh::MeshVertexBufferLayout,
|
||||||
|
render_asset::RenderAssets,
|
||||||
|
render_phase::{DrawFunctions, RenderPhase, SetItemPipeline},
|
||||||
|
render_resource::{
|
||||||
|
BlendState, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState,
|
||||||
|
DepthStencilState, FragmentState, FrontFace, MultisampleState, PipelineCache,
|
||||||
|
PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipelineDescriptor, Shader,
|
||||||
|
SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines,
|
||||||
|
StencilFaceState, StencilState, TextureFormat, VertexAttribute, VertexBufferLayout,
|
||||||
|
VertexFormat, VertexState, VertexStepMode,
|
||||||
|
},
|
||||||
|
texture::BevyDefault,
|
||||||
|
view::{Msaa, VisibleEntities},
|
||||||
|
},
|
||||||
|
sprite::{
|
||||||
|
DrawMesh2d, Mesh2dHandle, Mesh2dPipeline, Mesh2dPipelineKey, Mesh2dUniform,
|
||||||
|
SetMesh2dBindGroup, SetMesh2dViewBindGroup,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::lines::{RenderDebugLinesMesh, DEBUG_LINES_SHADER_HANDLE};
|
||||||
|
|
||||||
|
pub(crate) struct DebugLinePipeline {
|
||||||
|
mesh_pipeline: Mesh2dPipeline,
|
||||||
|
shader: Handle<Shader>,
|
||||||
|
}
|
||||||
|
impl FromWorld for DebugLinePipeline {
|
||||||
|
fn from_world(render_world: &mut World) -> Self {
|
||||||
|
DebugLinePipeline {
|
||||||
|
mesh_pipeline: render_world
|
||||||
|
.get_resource::<Mesh2dPipeline>()
|
||||||
|
.unwrap()
|
||||||
|
.clone(),
|
||||||
|
shader: DEBUG_LINES_SHADER_HANDLE.typed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecializedMeshPipeline for DebugLinePipeline {
|
||||||
|
type Key = Mesh2dPipelineKey;
|
||||||
|
|
||||||
|
fn specialize(
|
||||||
|
&self,
|
||||||
|
key: Self::Key,
|
||||||
|
layout: &MeshVertexBufferLayout,
|
||||||
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
|
/*
|
||||||
|
let mut shader_defs = Vec::new();
|
||||||
|
shader_defs.push("LINES_3D".to_string());
|
||||||
|
if depth_test {
|
||||||
|
shader_defs.push("DEPTH_TEST_ENABLED".to_string());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
let vertex_buffer_layout = layout.get_layout(&[
|
||||||
|
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
|
||||||
|
Mesh::ATTRIBUTE_COLOR.at_shader_location(1),
|
||||||
|
])?;
|
||||||
|
|
||||||
|
Ok(RenderPipelineDescriptor {
|
||||||
|
vertex: VertexState {
|
||||||
|
shader: self.shader.clone_weak(),
|
||||||
|
entry_point: "vertex".into(),
|
||||||
|
shader_defs: vec![],
|
||||||
|
buffers: vec![vertex_buffer_layout],
|
||||||
|
},
|
||||||
|
fragment: Some(FragmentState {
|
||||||
|
shader: self.shader.clone_weak(),
|
||||||
|
shader_defs: vec![],
|
||||||
|
entry_point: "fragment".into(),
|
||||||
|
targets: vec![ColorTargetState {
|
||||||
|
format: TextureFormat::bevy_default(),
|
||||||
|
blend: Some(BlendState::ALPHA_BLENDING),
|
||||||
|
write_mask: ColorWrites::ALL,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
layout: Some(vec![self.mesh_pipeline.view_layout.clone()]),
|
||||||
|
primitive: PrimitiveState {
|
||||||
|
front_face: FrontFace::Ccw,
|
||||||
|
cull_mode: None,
|
||||||
|
unclipped_depth: false,
|
||||||
|
polygon_mode: PolygonMode::Fill,
|
||||||
|
conservative: false,
|
||||||
|
topology: PrimitiveTopology::LineList,
|
||||||
|
strip_index_format: None,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: MultisampleState {
|
||||||
|
count: key.msaa_samples(),
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
label: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn queue(
|
||||||
|
draw2d_functions: Res<DrawFunctions<Transparent2d>>,
|
||||||
|
debug_line_pipeline: Res<DebugLinePipeline>,
|
||||||
|
mut pipeline_cache: ResMut<PipelineCache>,
|
||||||
|
mut specialized_pipelines: ResMut<SpecializedMeshPipelines<DebugLinePipeline>>,
|
||||||
|
render_meshes: Res<RenderAssets<Mesh>>,
|
||||||
|
msaa: Res<Msaa>,
|
||||||
|
material_meshes: Query<(&Mesh2dUniform, &Mesh2dHandle), With<RenderDebugLinesMesh>>,
|
||||||
|
mut views: Query<(&VisibleEntities, &mut RenderPhase<Transparent2d>)>,
|
||||||
|
) {
|
||||||
|
for (view, mut phase) in views.iter_mut() {
|
||||||
|
let draw_mesh2d = draw2d_functions.read().get_id::<DrawDebugLines>().unwrap();
|
||||||
|
let msaa_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples);
|
||||||
|
|
||||||
|
for visible_entity in &view.entities {
|
||||||
|
if let Ok((uniform, mesh_handle)) = material_meshes.get(*visible_entity) {
|
||||||
|
if let Some(mesh) = render_meshes.get(&mesh_handle.0) {
|
||||||
|
let mesh_key = msaa_key
|
||||||
|
| Mesh2dPipelineKey::from_primitive_topology(
|
||||||
|
PrimitiveTopology::LineList,
|
||||||
|
);
|
||||||
|
let mesh_z = uniform.transform.w_axis.z;
|
||||||
|
let pipeline = specialized_pipelines
|
||||||
|
.specialize(
|
||||||
|
&mut pipeline_cache,
|
||||||
|
&debug_line_pipeline,
|
||||||
|
mesh_key,
|
||||||
|
&mesh.layout,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
phase.add(Transparent2d {
|
||||||
|
entity: *visible_entity,
|
||||||
|
draw_function: draw_mesh2d,
|
||||||
|
pipeline,
|
||||||
|
sort_key: FloatOrd(mesh_z),
|
||||||
|
batch_range: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type DrawDebugLines = (
|
||||||
|
SetItemPipeline,
|
||||||
|
SetMesh2dViewBindGroup<0>,
|
||||||
|
SetMesh2dBindGroup<1>,
|
||||||
|
DrawMesh2d,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -210,7 +210,8 @@ impl EntityWithGraphics {
|
|||||||
// Cuboid mesh
|
// Cuboid mesh
|
||||||
//
|
//
|
||||||
let cuboid = bevy_mesh_from_polyline(Cuboid::new(Vector2::new(1.0, 1.0)).to_polyline());
|
let cuboid = bevy_mesh_from_polyline(Cuboid::new(Vector2::new(1.0, 1.0)).to_polyline());
|
||||||
out.insert(ShapeType::Cuboid, meshes.add(cuboid));
|
out.insert(ShapeType::Cuboid, meshes.add(cuboid.clone()));
|
||||||
|
out.insert(ShapeType::RoundCuboid, meshes.add(cuboid));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ball mesh
|
// Ball mesh
|
||||||
@@ -228,7 +229,8 @@ impl EntityWithGraphics {
|
|||||||
// Cuboid mesh
|
// Cuboid mesh
|
||||||
//
|
//
|
||||||
let cuboid = Mesh::from(shape::Cube { size: 2.0 });
|
let cuboid = Mesh::from(shape::Cube { size: 2.0 });
|
||||||
out.insert(ShapeType::Cuboid, meshes.add(cuboid));
|
out.insert(ShapeType::Cuboid, meshes.add(cuboid.clone()));
|
||||||
|
out.insert(ShapeType::RoundCuboid, meshes.add(cuboid));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ball mesh
|
// Ball mesh
|
||||||
@@ -305,12 +307,12 @@ fn bevy_polyline(buffers: (Vec<Point2<Real>>, Option<Vec<[u32; 2]>>)) -> Mesh {
|
|||||||
|
|
||||||
// Generate the mesh
|
// Generate the mesh
|
||||||
let mut mesh = Mesh::new(PrimitiveTopology::LineStrip);
|
let mut mesh = Mesh::new(PrimitiveTopology::LineStrip);
|
||||||
mesh.set_attribute(
|
mesh.insert_attribute(
|
||||||
Mesh::ATTRIBUTE_POSITION,
|
Mesh::ATTRIBUTE_POSITION,
|
||||||
VertexAttributeValues::from(vertices),
|
VertexAttributeValues::from(vertices),
|
||||||
);
|
);
|
||||||
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, VertexAttributeValues::from(normals));
|
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, VertexAttributeValues::from(normals));
|
||||||
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, VertexAttributeValues::from(uvs));
|
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, VertexAttributeValues::from(uvs));
|
||||||
mesh.set_indices(Some(Indices::U32(indices)));
|
mesh.set_indices(Some(Indices::U32(indices)));
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
@@ -348,12 +350,12 @@ fn bevy_mesh(buffers: (Vec<Point3<Real>>, Vec<[u32; 3]>)) -> Mesh {
|
|||||||
|
|
||||||
// Generate the mesh
|
// Generate the mesh
|
||||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||||
mesh.set_attribute(
|
mesh.insert_attribute(
|
||||||
Mesh::ATTRIBUTE_POSITION,
|
Mesh::ATTRIBUTE_POSITION,
|
||||||
VertexAttributeValues::from(vertices),
|
VertexAttributeValues::from(vertices),
|
||||||
);
|
);
|
||||||
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, VertexAttributeValues::from(normals));
|
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, VertexAttributeValues::from(normals));
|
||||||
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, VertexAttributeValues::from(uvs));
|
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, VertexAttributeValues::from(uvs));
|
||||||
mesh.set_indices(Some(Indices::U32(indices)));
|
mesh.set_indices(Some(Indices::U32(indices)));
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
@@ -365,6 +367,11 @@ fn collider_mesh_scale(co_shape: &dyn Shape) -> Vec3 {
|
|||||||
let c = co_shape.as_cuboid().unwrap();
|
let c = co_shape.as_cuboid().unwrap();
|
||||||
Vec3::new(c.half_extents.x as f32, c.half_extents.y as f32, 1.0)
|
Vec3::new(c.half_extents.x as f32, c.half_extents.y as f32, 1.0)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "dim2")]
|
||||||
|
ShapeType::RoundCuboid => {
|
||||||
|
let c = &co_shape.as_round_cuboid().unwrap().inner_shape;
|
||||||
|
Vec3::new(c.half_extents.x as f32, c.half_extents.y as f32, 1.0)
|
||||||
|
}
|
||||||
ShapeType::Ball => {
|
ShapeType::Ball => {
|
||||||
let b = co_shape.as_ball().unwrap();
|
let b = co_shape.as_ball().unwrap();
|
||||||
Vec3::new(b.radius as f32, b.radius as f32, b.radius as f32)
|
Vec3::new(b.radius as f32, b.radius as f32, b.radius as f32)
|
||||||
@@ -375,13 +382,18 @@ fn collider_mesh_scale(co_shape: &dyn Shape) -> Vec3 {
|
|||||||
Vec3::from_slice(c.half_extents.cast::<f32>().as_slice())
|
Vec3::from_slice(c.half_extents.cast::<f32>().as_slice())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
|
ShapeType::RoundCuboid => {
|
||||||
|
let c = co_shape.as_round_cuboid().unwrap();
|
||||||
|
Vec3::from_slice(c.inner_shape.half_extents.cast::<f32>().as_slice())
|
||||||
|
}
|
||||||
|
#[cfg(feature = "dim3")]
|
||||||
ShapeType::Cylinder => {
|
ShapeType::Cylinder => {
|
||||||
let c = co_shape.as_cylinder().unwrap();
|
let c = co_shape.as_cylinder().unwrap();
|
||||||
Vec3::new(c.radius as f32, c.half_height as f32, c.radius as f32)
|
Vec3::new(c.radius as f32, c.half_height as f32, c.radius as f32)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
ShapeType::RoundCylinder => {
|
ShapeType::RoundCylinder => {
|
||||||
let c = &co_shape.as_round_cylinder().unwrap().base_shape;
|
let c = &co_shape.as_round_cylinder().unwrap().inner_shape;
|
||||||
Vec3::new(c.radius as f32, c.half_height as f32, c.radius as f32)
|
Vec3::new(c.radius as f32, c.half_height as f32, c.radius as f32)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
@@ -391,7 +403,7 @@ fn collider_mesh_scale(co_shape: &dyn Shape) -> Vec3 {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
ShapeType::RoundCone => {
|
ShapeType::RoundCone => {
|
||||||
let c = &co_shape.as_round_cone().unwrap().base_shape;
|
let c = &co_shape.as_round_cone().unwrap().inner_shape;
|
||||||
Vec3::new(c.radius as f32, c.half_height as f32, c.radius as f32)
|
Vec3::new(c.radius as f32, c.half_height as f32, c.radius as f32)
|
||||||
}
|
}
|
||||||
_ => Vec3::ONE,
|
_ => Vec3::ONE,
|
||||||
@@ -439,7 +451,7 @@ fn generate_collider_mesh(co_shape: &dyn Shape) -> Option<Mesh> {
|
|||||||
}
|
}
|
||||||
ShapeType::RoundConvexPolygon => {
|
ShapeType::RoundConvexPolygon => {
|
||||||
let poly = co_shape.as_round_convex_polygon().unwrap();
|
let poly = co_shape.as_round_convex_polygon().unwrap();
|
||||||
bevy_mesh_from_polyline(poly.base_shape.points().to_vec())
|
bevy_mesh_from_polyline(poly.inner_shape.points().to_vec())
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
@@ -472,7 +484,7 @@ fn generate_collider_mesh(co_shape: &dyn Shape) -> Option<Mesh> {
|
|||||||
}
|
}
|
||||||
ShapeType::RoundConvexPolyhedron => {
|
ShapeType::RoundConvexPolyhedron => {
|
||||||
let poly = co_shape.as_round_convex_polyhedron().unwrap();
|
let poly = co_shape.as_round_convex_polyhedron().unwrap();
|
||||||
bevy_mesh(poly.base_shape.to_trimesh())
|
bevy_mesh(poly.inner_shape.to_trimesh())
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -642,7 +642,7 @@ fn physx_collider_from_rapier_collider(
|
|||||||
}
|
}
|
||||||
} else if let Some(convex) = shape
|
} else if let Some(convex) = shape
|
||||||
.as_convex_polyhedron()
|
.as_convex_polyhedron()
|
||||||
.or(shape.as_round_convex_polyhedron().map(|c| &c.base_shape))
|
.or(shape.as_round_convex_polyhedron().map(|c| &c.inner_shape))
|
||||||
{
|
{
|
||||||
let vertices = convex.points();
|
let vertices = convex.points();
|
||||||
let mut convex_desc;
|
let mut convex_desc;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use crate::harness::Harness;
|
|||||||
use crate::physx_backend::PhysxWorld;
|
use crate::physx_backend::PhysxWorld;
|
||||||
use bevy::pbr::wireframe::WireframePlugin;
|
use bevy::pbr::wireframe::WireframePlugin;
|
||||||
use bevy::render::camera::Camera;
|
use bevy::render::camera::Camera;
|
||||||
use bevy::render::options::{WgpuFeatures, WgpuOptions};
|
use bevy::render::render_resource::WgpuFeatures;
|
||||||
use bevy_egui::EguiContext;
|
use bevy_egui::EguiContext;
|
||||||
|
|
||||||
#[cfg(feature = "dim2")]
|
#[cfg(feature = "dim2")]
|
||||||
@@ -363,16 +363,10 @@ impl TestbedApp {
|
|||||||
|
|
||||||
app.insert_resource(WindowDescriptor {
|
app.insert_resource(WindowDescriptor {
|
||||||
title,
|
title,
|
||||||
vsync: true,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.insert_resource(ClearColor(Color::rgb(0.15, 0.15, 0.15)))
|
.insert_resource(ClearColor(Color::rgb(0.15, 0.15, 0.15)))
|
||||||
.insert_resource(Msaa { samples: 4 })
|
.insert_resource(Msaa { samples: 4 })
|
||||||
.insert_resource(WgpuOptions {
|
|
||||||
// Required for wireframes.
|
|
||||||
features: WgpuFeatures::POLYGON_MODE_LINE,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.insert_resource(AmbientLight {
|
.insert_resource(AmbientLight {
|
||||||
brightness: 0.3,
|
brightness: 0.3,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -389,15 +383,15 @@ impl TestbedApp {
|
|||||||
#[cfg(feature = "other-backends")]
|
#[cfg(feature = "other-backends")]
|
||||||
app.insert_non_send_resource(self.other_backends);
|
app.insert_non_send_resource(self.other_backends);
|
||||||
|
|
||||||
app.add_startup_system(setup_graphics_environment.system())
|
app.add_startup_system(setup_graphics_environment)
|
||||||
.insert_non_send_resource(self.graphics)
|
.insert_non_send_resource(self.graphics)
|
||||||
.insert_resource(self.state)
|
.insert_resource(self.state)
|
||||||
.insert_non_send_resource(self.harness)
|
.insert_non_send_resource(self.harness)
|
||||||
.insert_resource(self.builders)
|
.insert_resource(self.builders)
|
||||||
.insert_non_send_resource(self.plugins)
|
.insert_non_send_resource(self.plugins)
|
||||||
.add_stage_before(CoreStage::Update, "physics", SystemStage::single_threaded())
|
.add_stage_before(CoreStage::Update, "physics", SystemStage::single_threaded())
|
||||||
.add_system_to_stage("physics", update_testbed.system())
|
.add_system_to_stage("physics", update_testbed)
|
||||||
.add_system(egui_focus.system());
|
.add_system(egui_focus);
|
||||||
init(&mut app);
|
init(&mut app);
|
||||||
app.run();
|
app.run();
|
||||||
}
|
}
|
||||||
@@ -856,11 +850,14 @@ fn setup_graphics_environment(mut commands: Commands) {
|
|||||||
|
|
||||||
commands
|
commands
|
||||||
.spawn_bundle(PerspectiveCameraBundle {
|
.spawn_bundle(PerspectiveCameraBundle {
|
||||||
transform: Transform::from_matrix(Mat4::face_toward(
|
transform: Transform::from_matrix(
|
||||||
Vec3::new(-30.0, 30.0, 100.0),
|
Mat4::look_at_rh(
|
||||||
Vec3::new(0.0, 10.0, 0.0),
|
Vec3::new(-30.0, 30.0, 100.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 10.0, 0.0),
|
||||||
)),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
)
|
||||||
|
.inverse(),
|
||||||
|
),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.insert(OrbitCamera {
|
.insert(OrbitCamera {
|
||||||
@@ -900,9 +897,9 @@ fn setup_graphics_environment(mut commands: Commands) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn egui_focus(ui_context: Res<EguiContext>, mut cameras: Query<&mut OrbitCamera>) {
|
fn egui_focus(mut ui_context: ResMut<EguiContext>, mut cameras: Query<&mut OrbitCamera>) {
|
||||||
let mut camera_enabled = true;
|
let mut camera_enabled = true;
|
||||||
if ui_context.ctx().wants_pointer_input() {
|
if ui_context.ctx_mut().wants_pointer_input() {
|
||||||
camera_enabled = false;
|
camera_enabled = false;
|
||||||
}
|
}
|
||||||
for mut camera in cameras.iter_mut() {
|
for mut camera in cameras.iter_mut() {
|
||||||
@@ -922,7 +919,7 @@ fn update_testbed(
|
|||||||
mut harness: NonSendMut<Harness>,
|
mut harness: NonSendMut<Harness>,
|
||||||
#[cfg(feature = "other-backends")] mut other_backends: NonSendMut<OtherBackends>,
|
#[cfg(feature = "other-backends")] mut other_backends: NonSendMut<OtherBackends>,
|
||||||
mut plugins: NonSendMut<Plugins>,
|
mut plugins: NonSendMut<Plugins>,
|
||||||
ui_context: Res<EguiContext>,
|
mut ui_context: ResMut<EguiContext>,
|
||||||
mut gfx_components: Query<(&mut Transform,)>,
|
mut gfx_components: Query<(&mut Transform,)>,
|
||||||
mut cameras: Query<(&Camera, &GlobalTransform, &mut OrbitCamera)>,
|
mut cameras: Query<(&Camera, &GlobalTransform, &mut OrbitCamera)>,
|
||||||
keys: Res<Input<KeyCode>>,
|
keys: Res<Input<KeyCode>>,
|
||||||
@@ -957,11 +954,11 @@ fn update_testbed(
|
|||||||
// Update UI
|
// Update UI
|
||||||
{
|
{
|
||||||
let harness = &mut *harness;
|
let harness = &mut *harness;
|
||||||
ui::update_ui(&ui_context, &mut state, harness);
|
ui::update_ui(&mut ui_context, &mut state, harness);
|
||||||
|
|
||||||
for plugin in &mut plugins.0 {
|
for plugin in &mut plugins.0 {
|
||||||
plugin.update_ui(
|
plugin.update_ui(
|
||||||
&ui_context,
|
&mut ui_context,
|
||||||
harness,
|
harness,
|
||||||
&mut graphics,
|
&mut graphics,
|
||||||
&mut commands,
|
&mut commands,
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ use crate::PhysicsState;
|
|||||||
use bevy_egui::egui::Slider;
|
use bevy_egui::egui::Slider;
|
||||||
use bevy_egui::{egui, EguiContext};
|
use bevy_egui::{egui, EguiContext};
|
||||||
|
|
||||||
pub fn update_ui(ui_context: &EguiContext, state: &mut TestbedState, harness: &mut Harness) {
|
pub fn update_ui(ui_context: &mut EguiContext, state: &mut TestbedState, harness: &mut Harness) {
|
||||||
egui::Window::new("Parameters").show(ui_context.ctx(), |ui| {
|
egui::Window::new("Parameters").show(ui_context.ctx_mut(), |ui| {
|
||||||
if state.backend_names.len() > 1 && !state.example_names.is_empty() {
|
if state.backend_names.len() > 1 && !state.example_names.is_empty() {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
egui::ComboBox::from_label("backend")
|
egui::ComboBox::from_label("backend")
|
||||||
|
|||||||
Reference in New Issue
Block a user