feat: add support for Voxels collider (#823)
* feat: start adding voxels support and some additional testbed demo settings * feat: add support for parry’s new Voxels collider shape * fix voxels demos * feat: support rectangular voxels and additional voxels initialization * chore: switch to parry 0.20 * chore: fix cargo doc * Fix testbed build
This commit is contained in:
@@ -7,6 +7,9 @@ use bevy::input::mouse::MouseWheel;
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::camera::Camera;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
const LINE_TO_PIXEL_RATIO: f32 = 0.0005;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const LINE_TO_PIXEL_RATIO: f32 = 0.1;
|
||||
|
||||
#[derive(Component, PartialEq, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
extern crate nalgebra as na;
|
||||
|
||||
pub use crate::graphics::{BevyMaterial, GraphicsManager};
|
||||
|
||||
@@ -17,7 +17,7 @@ use rapier::math::{Isometry, Real, Vector};
|
||||
use crate::graphics::{BevyMaterial, InstancedMaterials, SELECTED_OBJECT_MATERIAL_KEY};
|
||||
#[cfg(feature = "dim2")]
|
||||
use {
|
||||
na::{Point2, Vector2},
|
||||
na::{vector, Point2, Vector2},
|
||||
rapier::geometry::{Ball, Cuboid},
|
||||
};
|
||||
|
||||
@@ -439,6 +439,26 @@ fn generate_collider_mesh(co_shape: &dyn Shape) -> Option<Mesh> {
|
||||
.collect();
|
||||
bevy_mesh((vertices, trimesh.indices().to_vec()))
|
||||
}
|
||||
ShapeType::Voxels => {
|
||||
let mut vtx = vec![];
|
||||
let mut idx = vec![];
|
||||
let voxels = co_shape.as_voxels().unwrap();
|
||||
let sz = voxels.voxel_size() / 2.0;
|
||||
for (_, center, data) in voxels.centers() {
|
||||
if !data.is_empty() {
|
||||
let bid = vtx.len() as u32;
|
||||
let center = point![center.x, center.y, 0.0];
|
||||
vtx.push(center + vector![sz.x, sz.y, 0.0]);
|
||||
vtx.push(center + vector![-sz.x, sz.y, 0.0]);
|
||||
vtx.push(center + vector![-sz.x, -sz.y, 0.0]);
|
||||
vtx.push(center + vector![sz.x, -sz.y, 0.0]);
|
||||
idx.push([bid, bid + 1, bid + 2]);
|
||||
idx.push([bid + 2, bid + 3, bid]);
|
||||
}
|
||||
}
|
||||
|
||||
bevy_mesh((vtx, idx))
|
||||
}
|
||||
ShapeType::Polyline => {
|
||||
let polyline = co_shape.as_polyline().unwrap();
|
||||
bevy_polyline((
|
||||
@@ -495,6 +515,10 @@ fn generate_collider_mesh(co_shape: &dyn Shape) -> Option<Mesh> {
|
||||
let poly = co_shape.as_round_convex_polyhedron().unwrap();
|
||||
bevy_mesh(poly.inner_shape.to_trimesh())
|
||||
}
|
||||
ShapeType::Voxels => {
|
||||
let voxels = co_shape.as_voxels().unwrap();
|
||||
bevy_mesh(voxels.to_trimesh())
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use indexmap::IndexMap;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum SettingValue {
|
||||
Label(String),
|
||||
U32 {
|
||||
value: u32,
|
||||
range: RangeInclusive<u32>,
|
||||
@@ -11,11 +12,18 @@ pub enum SettingValue {
|
||||
value: f32,
|
||||
range: RangeInclusive<f32>,
|
||||
},
|
||||
Bool {
|
||||
value: bool,
|
||||
},
|
||||
String {
|
||||
value: usize,
|
||||
range: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ExampleSettings {
|
||||
values: HashMap<String, SettingValue>,
|
||||
values: IndexMap<String, SettingValue>,
|
||||
}
|
||||
|
||||
impl ExampleSettings {
|
||||
@@ -35,6 +43,27 @@ impl ExampleSettings {
|
||||
self.values.iter_mut()
|
||||
}
|
||||
|
||||
pub fn set_bool(&mut self, key: &str, value: bool) {
|
||||
self.values
|
||||
.insert(key.to_string(), SettingValue::Bool { value });
|
||||
}
|
||||
|
||||
pub fn get_or_set_bool(&mut self, key: &'static str, default: bool) -> bool {
|
||||
let to_insert = SettingValue::Bool { value: default };
|
||||
let entry = self
|
||||
.values
|
||||
.entry(key.to_string())
|
||||
.or_insert(to_insert.clone());
|
||||
match entry {
|
||||
SettingValue::Bool { value } => *value,
|
||||
_ => {
|
||||
// The entry doesn’t have the right type. Overwrite with the new value.
|
||||
*entry = to_insert;
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_u32(&mut self, key: &str, value: u32, range: RangeInclusive<u32>) {
|
||||
self.values
|
||||
.insert(key.to_string(), SettingValue::U32 { value, range });
|
||||
@@ -90,6 +119,47 @@ impl ExampleSettings {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_string(&mut self, key: &str, selected: usize, range: Vec<String>) {
|
||||
self.values.insert(
|
||||
key.to_string(),
|
||||
SettingValue::String {
|
||||
value: selected,
|
||||
range,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn get_or_set_string(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
default: usize,
|
||||
range: Vec<String>,
|
||||
) -> usize {
|
||||
let to_insert = SettingValue::String {
|
||||
value: default,
|
||||
range,
|
||||
};
|
||||
let entry = self
|
||||
.values
|
||||
.entry(key.to_string())
|
||||
.or_insert(to_insert.clone());
|
||||
match entry {
|
||||
SettingValue::String { value, .. } => *value,
|
||||
_ => {
|
||||
// The entry doesn’t have the right type. Overwrite with the new value.
|
||||
*entry = to_insert;
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bool(&self, key: &'static str) -> Option<bool> {
|
||||
match self.values.get(key)? {
|
||||
SettingValue::Bool { value } => Some(*value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_u32(&self, key: &'static str) -> Option<u32> {
|
||||
match self.values.get(key)? {
|
||||
SettingValue::U32 { value, .. } => Some(*value),
|
||||
@@ -103,4 +173,23 @@ impl ExampleSettings {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_id(&self, key: &'static str) -> Option<usize> {
|
||||
match self.values.get(key)? {
|
||||
SettingValue::String { value, .. } => Some(*value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string(&self, key: &'static str) -> Option<&str> {
|
||||
match self.values.get(key)? {
|
||||
SettingValue::String { value, range } => Some(&range[*value]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_label(&mut self, key: &'static str, value: impl Into<String>) {
|
||||
self.values
|
||||
.insert(key.to_string(), SettingValue::Label(value.into()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,18 +1014,20 @@ fn draw_contacts(_nf: &NarrowPhase, _colliders: &ColliderSet) {
|
||||
#[cfg(feature = "dim3")]
|
||||
fn setup_graphics_environment(mut commands: Commands) {
|
||||
commands.insert_resource(AmbientLight {
|
||||
brightness: 100.0,
|
||||
brightness: 200.0,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
commands.spawn((
|
||||
DirectionalLight {
|
||||
shadows_enabled: false,
|
||||
// shadows_enabled: true,
|
||||
..Default::default()
|
||||
},
|
||||
Transform {
|
||||
translation: Vec3::new(10.0, 2.0, 10.0),
|
||||
rotation: Quat::from_rotation_x(-std::f32::consts::FRAC_PI_4),
|
||||
translation: Vec3::new(-100.0, 200.0, -100.0),
|
||||
rotation: Quat::from_rotation_x(
|
||||
-(std::f32::consts::FRAC_PI_4 + std::f32::consts::FRAC_PI_6),
|
||||
),
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
|
||||
@@ -439,6 +439,9 @@ fn example_settings_ui(ui_context: &mut EguiContexts, state: &mut TestbedState)
|
||||
for (name, value) in state.example_settings.iter_mut() {
|
||||
let prev_value = value.clone();
|
||||
match value {
|
||||
SettingValue::Label(value) => {
|
||||
ui.label(format!("{}: {}", name, value));
|
||||
}
|
||||
SettingValue::F32 { value, range } => {
|
||||
ui.add(Slider::new(value, range.clone()).text(name));
|
||||
}
|
||||
@@ -454,6 +457,19 @@ fn example_settings_ui(ui_context: &mut EguiContexts, state: &mut TestbedState)
|
||||
ui.add(Slider::new(value, range.clone()).text(name));
|
||||
});
|
||||
}
|
||||
SettingValue::Bool { value } => {
|
||||
ui.checkbox(value, name);
|
||||
}
|
||||
SettingValue::String { value, range } => {
|
||||
ComboBox::from_label(name)
|
||||
.width(150.0)
|
||||
.selected_text(&range[*value])
|
||||
.show_ui(ui, |ui| {
|
||||
for (id, name) in range.iter().enumerate() {
|
||||
ui.selectable_value(value, id, name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
any_changed = any_changed || *value != prev_value;
|
||||
|
||||
Reference in New Issue
Block a user