aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2022-04-22 15:45:53 +0200
committerSébastien Crozet <developer@crozet.re>2022-04-22 16:11:23 +0200
commitbc2ae4b512b8bc7a2b61dd24d9685289453681c5 (patch)
tree576d950ee18b0a3a2e69a48db5fd2ba14f7bcd39
parent21a31bc1026d17d30b3a5ac35e6bb716dc66be6e (diff)
downloadrapier-bc2ae4b512b8bc7a2b61dd24d9685289453681c5.tar.gz
rapier-bc2ae4b512b8bc7a2b61dd24d9685289453681c5.tar.bz2
rapier-bc2ae4b512b8bc7a2b61dd24d9685289453681c5.zip
Add a basic lines-based debug-renderer
-rw-r--r--crates/rapier2d-f64/Cargo.toml1
-rw-r--r--crates/rapier2d/Cargo.toml3
-rw-r--r--crates/rapier3d-f64/Cargo.toml1
-rw-r--r--crates/rapier3d/Cargo.toml1
-rw-r--r--crates/rapier_testbed2d-f64/Cargo.toml3
-rw-r--r--crates/rapier_testbed2d/Cargo.toml3
-rw-r--r--crates/rapier_testbed3d-f64/Cargo.toml3
-rw-r--r--crates/rapier_testbed3d/Cargo.toml3
-rw-r--r--examples3d/joints3.rs156
-rw-r--r--src/pipeline/debug_render_pipeline/debug_render_backend.rs66
-rw-r--r--src/pipeline/debug_render_pipeline/debug_render_pipeline.rs450
-rw-r--r--src/pipeline/debug_render_pipeline/debug_render_style.rs37
-rw-r--r--src/pipeline/debug_render_pipeline/mod.rs8
-rw-r--r--src/pipeline/debug_render_pipeline/outlines.rs36
-rw-r--r--src/pipeline/mod.rs9
-rw-r--r--src/pipeline/physics_pipeline.rs11
-rw-r--r--src_testbed/debug_render.rs81
-rw-r--r--src_testbed/lib.rs1
-rw-r--r--src_testbed/testbed.rs7
19 files changed, 795 insertions, 85 deletions
diff --git a/crates/rapier2d-f64/Cargo.toml b/crates/rapier2d-f64/Cargo.toml
index 44a86bd..f0a85d9 100644
--- a/crates/rapier2d-f64/Cargo.toml
+++ b/crates/rapier2d-f64/Cargo.toml
@@ -28,6 +28,7 @@ simd-is-enabled = [ "vec_map" ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
serde-serialize = [ "nalgebra/serde-serialize", "parry2d-f64/serde-serialize", "serde", "bit-vec/serde", "arrayvec/serde" ]
enhanced-determinism = [ "simba/libm_force", "parry2d-f64/enhanced-determinism", "indexmap" ]
+debug-render = [ ]
# Feature used for debugging only.
debug-disable-legitimate-fe-exceptions = [ ]
diff --git a/crates/rapier2d/Cargo.toml b/crates/rapier2d/Cargo.toml
index ad79f12..8ae4fd4 100644
--- a/crates/rapier2d/Cargo.toml
+++ b/crates/rapier2d/Cargo.toml
@@ -28,6 +28,7 @@ simd-is-enabled = [ "vec_map" ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
serde-serialize = [ "nalgebra/serde-serialize", "parry2d/serde-serialize", "serde", "bit-vec/serde", "arrayvec/serde" ]
enhanced-determinism = [ "simba/libm_force", "parry2d/enhanced-determinism", "indexmap" ]
+debug-render = [ "oorandom" ]
# Feature used for debugging only.
debug-disable-legitimate-fe-exceptions = [ ]
@@ -61,6 +62,8 @@ downcast-rs = "1.2"
num-derive = "0.3"
bitflags = "1"
+oorandom = { version = "11", optional = true }
+
[dev-dependencies]
bincode = "1"
serde = { version = "1", features = [ "derive" ] }
diff --git a/crates/rapier3d-f64/Cargo.toml b/crates/rapier3d-f64/Cargo.toml
index 1b8c1dc..6cdf20f 100644
--- a/crates/rapier3d-f64/Cargo.toml
+++ b/crates/rapier3d-f64/Cargo.toml
@@ -28,6 +28,7 @@ simd-is-enabled = [ "vec_map" ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
serde-serialize = [ "nalgebra/serde-serialize", "parry3d-f64/serde-serialize", "serde", "bit-vec/serde" ]
enhanced-determinism = [ "simba/libm_force", "parry3d-f64/enhanced-determinism" ]
+debug-render = []
# Feature used for debugging only.
debug-disable-legitimate-fe-exceptions = [ ]
diff --git a/crates/rapier3d/Cargo.toml b/crates/rapier3d/Cargo.toml
index 4aae73a..7f4896d 100644
--- a/crates/rapier3d/Cargo.toml
+++ b/crates/rapier3d/Cargo.toml
@@ -28,6 +28,7 @@ simd-is-enabled = [ "vec_map" ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
serde-serialize = [ "nalgebra/serde-serialize", "parry3d/serde-serialize", "serde", "bit-vec/serde" ]
enhanced-determinism = [ "simba/libm_force", "parry3d/enhanced-determinism" ]
+debug-render = [ ]
# Feature used for debugging only.
debug-disable-legitimate-fe-exceptions = [ ]
diff --git a/crates/rapier_testbed2d-f64/Cargo.toml b/crates/rapier_testbed2d-f64/Cargo.toml
index cfa0f42..495ccd9 100644
--- a/crates/rapier_testbed2d-f64/Cargo.toml
+++ b/crates/rapier_testbed2d-f64/Cargo.toml
@@ -40,6 +40,7 @@ md5 = "0.7"
bevy_egui = "0.10"
bevy_ecs = "0.6"
+bevy_prototype_debug_lines = "0.6"
# Dependencies for native only.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@@ -54,4 +55,4 @@ bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "re
package = "rapier2d-f64"
path = "../rapier2d-f64"
version = "0.12.0-alpha.1"
-features = [ "serde-serialize" ]
+features = [ "serde-serialize", "debug-render" ]
diff --git a/crates/rapier_testbed2d/Cargo.toml b/crates/rapier_testbed2d/Cargo.toml
index 6b0430a..a985fdd 100644
--- a/crates/rapier_testbed2d/Cargo.toml
+++ b/crates/rapier_testbed2d/Cargo.toml
@@ -40,6 +40,7 @@ md5 = "0.7"
bevy_egui = "0.10"
bevy_ecs = "0.6"
+bevy_prototype_debug_lines = "0.6"
# Dependencies for native only.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@@ -54,4 +55,4 @@ bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "re
package = "rapier2d"
path = "../rapier2d"
version = "0.12.0-alpha.1"
-features = [ "serde-serialize" ]
+features = [ "serde-serialize", "debug-render" ]
diff --git a/crates/rapier_testbed3d-f64/Cargo.toml b/crates/rapier_testbed3d-f64/Cargo.toml
index dfd0fbd..b77635f 100644
--- a/crates/rapier_testbed3d-f64/Cargo.toml
+++ b/crates/rapier_testbed3d-f64/Cargo.toml
@@ -38,6 +38,7 @@ serde = { version = "1", features = [ "derive" ] }
bevy_egui = "0.10"
bevy_ecs = "0.6"
+bevy_prototype_debug_lines = { version = "0.6", features = [ "3d" ] }
# Dependencies for native only.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@@ -52,4 +53,4 @@ bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "re
package = "rapier3d-f64"
path = "../rapier3d-f64"
version = "0.12.0-alpha.1"
-features = [ "serde-serialize" ] \ No newline at end of file
+features = [ "serde-serialize", "debug-render" ] \ No newline at end of file
diff --git a/crates/rapier_testbed3d/Cargo.toml b/crates/rapier_testbed3d/Cargo.toml
index 89a050f..5f3e6cb 100644
--- a/crates/rapier_testbed3d/Cargo.toml
+++ b/crates/rapier_testbed3d/Cargo.toml
@@ -42,6 +42,7 @@ serde = { version = "1", features = [ "derive" ] }
bevy_egui = "0.10"
bevy_ecs = "0.6"
+bevy_prototype_debug_lines = { version = "0.6", features = [ "3d" ] }
# Dependencies for native only.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@@ -56,4 +57,4 @@ bevy = {version = "0.6", default-features = false, features = ["bevy_winit", "re
package = "rapier3d"
path = "../rapier3d"
version = "0.12.0-alpha.1"
-features = [ "serde-serialize" ] \ No newline at end of file
+features = [ "serde-serialize", "debug-render" ] \ No newline at end of file
diff --git a/examples3d/joints3.rs b/examples3d/joints3.rs
index b5dc984..f7c6cb3 100644
--- a/examples3d/joints3.rs
+++ b/examples3d/joints3.rs
@@ -578,33 +578,33 @@ fn do_init_world(testbed: &mut Testbed, use_articulations: bool) {
let mut impulse_joints = ImpulseJointSet::new();
let mut multibody_joints = MultibodyJointSet::new();
- // create_prismatic_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![20.0, 5.0, 0.0],
- // 4,
- // use_articulations,
- // );
- // create_actuated_prismatic_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![25.0, 5.0, 0.0],
- // 4,
- // use_articulations,
- // );
- // create_revolute_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![20.0, 0.0, 0.0],
- // 3,
- // use_articulations,
- // );
+ create_prismatic_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![20.0, 5.0, 0.0],
+ 4,
+ use_articulations,
+ );
+ create_actuated_prismatic_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![25.0, 5.0, 0.0],
+ 4,
+ use_articulations,
+ );
+ create_revolute_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![20.0, 0.0, 0.0],
+ 3,
+ use_articulations,
+ );
create_revolute_joints_with_limits(
&mut bodies,
&mut colliders,
@@ -613,57 +613,57 @@ fn do_init_world(testbed: &mut Testbed, use_articulations: bool) {
point![34.0, 0.0, 0.0],
use_articulations,
);
- // create_fixed_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![0.0, 10.0, 0.0],
- // 10,
- // use_articulations,
- // );
- // create_actuated_revolute_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![20.0, 10.0, 0.0],
- // 6,
- // use_articulations,
- // );
- // create_actuated_spherical_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![13.0, 10.0, 0.0],
- // 3,
- // use_articulations,
- // );
- // create_spherical_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // 15,
- // use_articulations,
- // );
- // create_spherical_joints_with_limits(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![-5.0, 0.0, 0.0],
- // use_articulations,
- // );
- // create_coupled_joints(
- // &mut bodies,
- // &mut colliders,
- // &mut impulse_joints,
- // &mut multibody_joints,
- // point![0.0, 20.0, 0.0],
- // use_articulations,
- // );
+ create_fixed_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![0.0, 10.0, 0.0],
+ 10,
+ use_articulations,
+ );
+ create_actuated_revolute_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![20.0, 10.0, 0.0],
+ 6,
+ use_articulations,
+ );
+ create_actuated_spherical_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![13.0, 10.0, 0.0],
+ 3,
+ use_articulations,
+ );
+ create_spherical_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ 15,
+ use_articulations,
+ );
+ create_spherical_joints_with_limits(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![-5.0, 0.0, 0.0],
+ use_articulations,
+ );
+ create_coupled_joints(
+ &mut bodies,
+ &mut colliders,
+ &mut impulse_joints,
+ &mut multibody_joints,
+ point![0.0, 20.0, 0.0],
+ use_articulations,
+ );
/*
* Set up the testbed.
diff --git a/src/pipeline/debug_render_pipeline/debug_render_backend.rs b/src/pipeline/debug_render_pipeline/debug_render_backend.rs
new file mode 100644
index 0000000..27a67e4
--- /dev/null
+++ b/src/pipeline/debug_render_pipeline/debug_render_backend.rs
@@ -0,0 +1,66 @@
+use crate::dynamics::{
+ ImpulseJoint, ImpulseJointHandle, Multibody, MultibodyLink, RigidBody, RigidBodyHandle,
+};
+use crate::geometry::Collider;
+use crate::math::{Isometry, Point, Real, Vector};
+use crate::prelude::{ColliderHandle, MultibodyJointHandle};
+use na::Scale;
+
+#[derive(Copy, Clone)]
+pub enum DebugRenderObject<'a> {
+ RigidBody(RigidBodyHandle, &'a RigidBody),
+ Collider(ColliderHandle, &'a Collider),
+ ImpulseJoint(ImpulseJointHandle, &'a ImpulseJoint),
+ MultibodyJoint(MultibodyJointHandle, &'a Multibody, &'a MultibodyLink),
+ Other,
+}
+
+pub trait DebugRenderBackend {
+ fn draw_line(
+ &mut self,
+ object: DebugRenderObject,
+ a: Point<Real>,
+ b: Point<Real>,
+ color: [f32; 4],
+ );
+
+ fn draw_polyline(
+ &mut self,
+ object: DebugRenderObject,
+ vertices: &[Point<Real>],
+ indices: &[[u32; 2]],
+ transform: &Isometry<Real>,
+ scale: &Vector<Real>,
+ color: [f32; 4],
+ ) {
+ for idx in indices {
+ let a = transform * (Scale::from(*scale) * vertices[idx[0] as usize]);
+ let b = transform * (Scale::from(*scale) * vertices[idx[1] as usize]);
+ self.draw_line(object, a, b, color);
+ }
+ }
+
+ fn draw_line_strip(
+ &mut self,
+ object: DebugRenderObject,
+ vertices: &[Point<Real>],
+ transform: &Isometry<Real>,
+ scale: &Vector<Real>,
+ color: [f32; 4],
+ closed: bool,
+ ) {
+ for vtx in vertices.windows(2) {
+ let a = transform * (Scale::from(*scale) * vtx[0]);
+ let b = transform * (Scale::from(*scale) * vtx[1]);
+ self.draw_line(object, a, b, color);
+ }
+
+ if closed {
+ if vertices.len() > 2 {
+ let a = transform * (Scale::from(*scale) * vertices[0]);
+ let b = transform * (Scale::from(*scale) * vertices.last().unwrap());
+ self.draw_line(object, a, b, color);
+ }
+ }
+ }
+}
diff --git a/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs b/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs
new file mode 100644
index 0000000..36593ce
--- /dev/null
+++ b/src/pipeline/debug_render_pipeline/debug_render_pipeline.rs
@@ -0,0 +1,450 @@
+use super::{outlines, DebugRenderBackend};
+use crate::dynamics::{
+ GenericJoint, ImpulseJointSet, MultibodyJointSet, RigidBodySet, RigidBodyType,
+};
+use crate::geometry::{Ball, ColliderSet, Cuboid, Shape, TypedShape};
+#[cfg(feature = "dim3")]
+use crate::geometry::{Cone, Cylinder};
+use crate::math::{Isometry, Point, Real, Vector, DIM};
+use crate::pipeline::debug_render_pipeline::debug_render_backend::DebugRenderObject;
+use crate::pipeline::debug_render_pipeline::DebugRenderStyle;
+use crate::utils::WBasis;
+use std::any::TypeId;
+use std::collections::HashMap;
+
+bitflags::bitflags! {
+ pub struct DebugRenderMode: u32 {
+ const COLLIDER_SHAPES = 1 << 0;
+ const RIGID_BODY_AXES = 1 << 1;
+ const MULTIBODY_JOINTS = 1 << 2;
+ const IMPULSE_JOINTS = 1 << 3;
+ }
+}
+
+pub struct DebugRenderPipeline {
+ #[cfg(feature = "dim2")]
+ instances: HashMap<TypeId, Vec<Point<Real>>>,
+ #[cfg(feature = "dim3")]
+ instances: HashMap<TypeId, (Vec<Point<Real>>, Vec<[u32; 2]>)>,
+ pub style: DebugRenderStyle,
+ pub mode: DebugRenderMode,
+}
+
+impl Default for DebugRenderPipeline {
+ fn default() -> Self {
+ Self::render_all(DebugRenderStyle::default())
+ }
+}
+
+impl DebugRenderPipeline {
+ pub fn new(style: DebugRenderStyle, mode: DebugRenderMode) -> Self {
+ Self {
+ instances: outlines::instances(style.subdivisions),
+ style,
+ mode,
+ }
+ }
+
+ pub fn render_all(style: DebugRenderStyle) -> Self {
+ Self::new(style, DebugRenderMode::all())
+ }
+
+ pub fn render(
+ &mut self,
+ backend: &mut impl DebugRenderBackend,
+ bodies: &RigidBodySet,
+ colliders: &ColliderSet,
+ impulse_joints: &ImpulseJointSet,
+ multibody_joints: &MultibodyJointSet,
+ ) {
+ self.render_bodies(backend, bodies);
+ self.render_colliders(backend, bodies, colliders);
+ self.render_joints(backend, bodies, impulse_joints, multibody_joints);
+ }
+
+ pub fn render_joints(
+ &mut self,
+ backend: &mut impl DebugRenderBackend,
+ bodies: &RigidBodySet,
+ impulse_joints: &ImpulseJointSet,
+ multibody_joints: &MultibodyJointSet,
+ ) {
+ let mut render_joint = |body1,
+ body2,
+ data: &GenericJoint,
+ mut anchor_color: [f32; 4],
+ mut separation_color: [f32; 4],
+ object| {
+ if let (Some(rb1), Some(rb2)) = (bodies.get(body1), bodies.get(body2)) {
+ let coeff = if (rb1.is_fixed() || rb1.is_sleeping())
+ && (rb2.is_fixed() || rb2.is_sleeping())
+ {
+ self.style.sleep_color_multiplier
+ } else {
+ [1.0; 4]
+ };
+
+ let frame1 = rb1.position() * data.local_frame1;
+ let frame2 = rb2.position() * data.local_frame2;
+
+ let a = *rb1.translation();
+ let b = frame1.translation.vector;
+ let c = frame2.translation.vector;
+ let d = *rb2.translation();
+
+ for k in 0..4 {
+ anchor_color[k] *= coeff[k];
+ separation_color[k] *= coeff[k];
+ }
+
+ backend.draw_line(object, a.into(), b.into(), anchor_color);
+ backend.draw_line(object, b.into(), c.into(), separation_color);
+ backend.draw_line(object, c.into(), d.into(), anchor_color);
+ }
+ };
+
+ if self.mode.contains(DebugRenderMode::IMPULSE_JOINTS) {
+ for (handle, joint) in impulse_joints.iter() {
+ let anc_color = self.style.impulse_joint_anchor_color;
+ let sep_color = self.style.impulse_joint_separation_color;
+ let object = DebugRenderObject::ImpulseJoint(handle, joint);
+ render_joint(
+ joint.body1,
+ joint.body2,
+ &joint.data,
+ anc_color,
+ sep_color,
+ object,
+ );
+ }
+ }
+
+ if self.mode.contains(DebugRenderMode::MULTIBODY_JOINTS) {
+ for (handle, multibody, link) in multibody_joints.iter() {
+ let anc_color = self.style.multibody_joint_anchor_color;
+ let sep_color = self.style.multibody_joint_separation_color;
+ let parent = multibody.link(link.parent_id().unwrap()).unwrap();
+ let object = DebugRenderObject::MultibodyJoint(handle, multibody, link);
+ render_joint(
+ parent.rigid_body_handle(),
+ link.rigid_body_handle(),
+ &link.joint.data,
+ anc_color,
+ sep_color,
+ object,
+ );
+ }
+ }
+ }
+
+ pub fn render_bodies(&mut self, backend: &mut impl DebugRenderBackend, bodies: &RigidBodySet) {
+ for (handle, rb) in bodies.iter() {
+ let object = DebugRenderObject::RigidBody(handle, rb);
+
+ if self.style.rigid_body_axes_length != 0.0
+ && self.mode.contains(DebugRenderMode::RIGID_BODY_AXES)
+ {
+ let basis = rb.rotation().to_rotation_matrix().into_inner();
+ let coeff = if rb.is_sleeping() {
+ self.style.sleep_color_multiplier
+ } else {
+ [1.0; 4]
+ };
+ let colors = [
+ [0.0 * coeff[0], 1.0 * coeff[1], 0.25 * coeff[2], coeff[3]],
+ [120.0 * coeff[0], 1.0 * coeff[1], 0.1 * coeff[2], coeff[3]],
+ [240.0 * coeff[0], 1.0 * coeff[1], 0.2 * coeff[2], coeff[3]],
+ ];
+ let com = rb.mprops.world_com;
+
+ for k in 0..DIM {
+ let axis = basis.column(k) * self.style.rigid_body_axes_length;
+ backend.draw_line(object, com, com + axis, colors[k]);
+ }
+ }
+ }
+ }
+
+ pub fn render_colliders(
+ &mut self,
+ backend: &mut impl DebugRenderBackend,
+ bodies: &RigidBodySet,
+ colliders: &ColliderSet,
+ ) {
+ if self.mode.contains(DebugRenderMode::COLLIDER_SHAPES) {
+ for (h, co) in colliders.iter() {
+ let object = DebugRenderObject::Collider(h, co);
+ let color = if let Some(parent) = co.parent().and_then(|p| bodies.get(p)) {
+ let coeff = if parent.is_sleeping() {
+ self.style.sleep_color_multiplier
+ } else {
+ [1.0; 4]
+ };
+ let c = match parent.body_type {
+ RigidBodyType::Fixed => self.style.collider_fixed_color,
+ RigidBodyType::Dynamic => self.style.collider_dynamic_color,
+ RigidBodyType::KinematicPositionBased
+ | RigidBodyType::KinematicVelocityBased => {
+ self.style.collider_kinematic_color
+ }
+ };
+
+ [
+ c[0] * coeff[0],
+ c[1] * coeff[1],
+ c[2] * coeff[2],
+ c[3] * coeff[3],
+ ]
+ } else {
+ self.style.collider_parentless_color
+ };
+
+ self.render_shape(object, backend, co.shape(), co.position(), color)
+ }
+ }
+ }
+
+ #[cfg(feature = "dim2")]
+ fn render_shape(
+ &mut self,
+ object: DebugRenderObject,
+ backend: &mut impl DebugRenderBackend,
+ shape: &dyn Shape,
+ pos: &Isometry<Real>,
+ color: [f32; 4],
+ ) {
+ match shape.as_typed_shape() {
+ TypedShape::Ball(s) => {
+ let vtx = &self.instances[&TypeId::of::<Ball>()];
+ backend.draw_line_strip(
+ object,
+ vtx,
+ pos,
+ &Vector::repeat(s.radius * 2.0),
+ color,
+ true,
+ )
+ }
+ TypedShape::Cuboid(s) => {
+ let vtx = &self.instances[&TypeId::of::<Cuboid>()];
+ backend.draw_line_strip(object, vtx, pos, &(s.half_extents * 2.0), color, true)
+ }
+ TypedShape::Capsule(s) => {
+ let vtx = s.to_polyline(self.style.subdivisions);
+ backend.draw_line_strip(object, &vtx, pos, &Vector::repeat(1.0), color, true)
+ }
+ TypedShape::Segment(s) => backend.draw_line_strip(
+ object,
+ &[s.a, s.b],
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ false,
+ ),
+ TypedShape::Triangle(s) => backend.draw_line_strip(
+ object,
+ &[s.a, s.b, s.c],
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ true,
+ ),
+ TypedShape::TriMesh(s) => {
+ for tri in s.triangles() {
+ self.render_shape(object, backend, &tri, pos, color)
+ }
+ }
+ TypedShape::Polyline(s) => backend.draw_polyline(
+ object,
+ s.vertices(),
+ s.indices(),
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ ),
+ TypedShape::HalfSpace(s) => {
+ let basis = s.normal.orthonormal_basis()[0];
+ let a = Point::from(basis) * 10_000.0;
+ let b = Point::from(basis) * -10_000.0;
+ backend.draw_line_strip(object, &[a, b], pos, &Vector::repeat(1.0), color, false)
+ }
+ TypedShape::HeightField(s) => {
+ for seg in s.segments() {
+ self.render_shape(object, backend, &seg, pos, color)
+ }
+ }
+ TypedShape::Compound(s) => {
+ for (sub_pos, shape) in s.shapes() {
+ self.render_shape(object, backend, &**shape, &(pos * sub_pos), color)
+ }
+ }
+ TypedShape::ConvexPolygon(s) => {
+ backend.draw_line_strip(object, s.points(), pos, &Vector::repeat(1.0), color, true)
+ }
+ /*
+ * Round shapes.
+ */
+ TypedShape::RoundCuboid(s) => {
+ self.render_shape(object, backend, &s.base_shape, pos, color)
+ }
+ TypedShape::RoundTriangle(s) => {
+ self.render_shape(object, backend, &s.base_shape, pos, color)
+ }
+ // TypedShape::RoundTriMesh(s) => self.render_shape(backend, &s.base_shape, pos, color),
+ // TypedShape::RoundHeightField(s) => {
+ // self.render_shape(backend, &s.base_shape, pos, color)
+ // }
+ TypedShape::RoundConvexPolygon(s) => {
+ self.render_shape(object, backend, &s.base_shape, pos, color)
+ }
+ TypedShape::Custom(_) => {}
+ }
+ }
+
+ #[cfg(feature = "dim3")]
+ fn render_shape(
+ &mut self,
+ object: DebugRenderObject,
+ backend: &mut impl DebugRenderBackend,
+ shape: &dyn Shape,
+ pos: &Isometry<Real>,
+ color: [f32; 4],
+ ) {
+ match shape.as_typed_shape() {
+ TypedShape::Ball(s) => {
+ let (vtx, idx) = &self.instances[&TypeId::of::<Ball>()];
+ backend.draw_polyline(
+ object,
+ vtx,
+ idx,
+ pos,
+ &Vector::repeat(s.radius * 2.0),
+ color,
+ )
+ }
+ TypedShape::Cuboid(s) => {
+ let (vtx, idx) = &self.instances[&TypeId::of::<Cuboid>()];
+ backend.draw_polyline(object, vtx, idx, pos, &(s.half_extents * 2.0), color)
+ }
+ #[cfg(feature = "dim3")]
+ TypedShape::Capsule(s) => {
+ let (vtx, idx) = s.to_outline(self.style.subdivisions);
+ backend.draw_polyline(object, &vtx, &idx, pos, &Vector::repeat(1.0), color)
+ }
+ TypedShape::Segment(s) => backend.draw_polyline(
+ object,
+ &[s.a, s.b],
+ &[[0, 1]],
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ ),
+ TypedShape::Triangle(s) => backend.draw_line_strip(
+ object,
+ &[s.a, s.b, s.c],
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ true,
+ ),
+ TypedShape::TriMesh(s) => {
+ for tri in s.triangles() {
+ self.render_shape(object, backend, &tri, pos, color)
+ }
+ }
+ TypedShape::Polyline(s) => backend.draw_polyline(
+ object,
+ s.vertices(),
+ s.indices(),
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ ),
+ TypedShape::HalfSpace(s) => {
+ let basis = s.normal.orthonormal_basis();
+ let a = Point::from(basis[0]) * 10_000.0;
+ let b = Point::from(basis[0]) * -10_000.0;
+ let c = Point::from(basis[1]) * 10_000.0;
+ let d = Point::from(basis[1]) * -10_000.0;
+ backend.draw_polyline(
+ object,
+ &[a, b, c, d],
+ &[[0, 1], [2, 3]],
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ )
+ }
+ TypedShape::HeightField(s) => {
+ for tri in s.triangles() {
+ self.render_shape(object, backend, &tri, pos, color)
+ }
+ }
+ TypedShape::Compound(s) => {
+ for (sub_pos, shape) in s.shapes() {
+ self.render_shape(object, backend, &**shape, &(pos * sub_pos), color)
+ }
+ }
+ TypedShape::ConvexPolyhedron(s) => {
+ let indices: Vec<_> = s
+ .edges()
+ .iter()
+ .map(|e| [e.vertices.x, e.vertices.y])
+ .collect();
+ backend.draw_polyline(
+ object,
+ s.points(),
+ &indices,
+ pos,
+ &Vector::repeat(1.0),
+ color,
+ )
+ }
+ TypedShape::Cylinder(s) => {
+ let (vtx, idx) = &self.instances[&TypeId::of::<Cylinder>()];
+ backend.draw_polyline(
+ object,
+ vtx,
+ idx,
+ pos,
+ &(Vector::new(s.radius, s.half_height, s.radius) * 2.0),
+ color,
+ )
+ }
+ TypedShape::Cone(s) => {
+ let (vtx, idx) = &self.instances[&TypeId::of::<Cone>()];
+ backend.draw_polyline(
+ object,
+ vtx,
+ idx,
+ pos,
+ &(Vector::new(s.radius, s.half_height, s.radius) * 2.0),
+ color,
+ )
+ }
+ /*
+ * Round shapes.
+ */
+ TypedShape::RoundCuboid(s) => {
+ self.render_shape(object, backend, &s.base_shape, pos, color)
+ }
+ TypedShape::RoundTriangle(s) => {
+ self.render_shape(object, backend, &s.base_shape, pos, color)
+ }
+ // TypedShape::RoundTriMesh(s) => self.render_shape(object, backend, &s.base_shape, pos, color),
+ // TypedShape::RoundHeightField(s) => {
+ // self.render_shape(object, backend, &s.base_shape, pos, color)
+ // }
+ TypedShape::RoundCylinder(s) => {
+ self.render_shape(object, backend, &s.base_shape, pos, color)
+ }
+ TypedShape::RoundCone(s) => {
+ self.render_shape(object, backend, &s.base_shape, pos, color)
+ }
+ TypedShape::RoundConvexPolyhedron(s) => {
+ self.rende