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

wip parry_to_bevy_mesh #628

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
with:
prefix-key: ${{ env.RUST_CACHE_KEY }}
- name: Cargo doc
run: cargo doc
run: cargo doc --no-deps
test:
runs-on: ubuntu-latest
env:
Expand Down Expand Up @@ -72,6 +72,6 @@ jobs:
with:
prefix-key: ${{ env.RUST_CACHE_KEY }}
- name: Clippy bevy_rapier2d
run: cd bevy_rapier2d && cargo clippy --verbose --features wasm-bindgen,bevy/webgl2 --target wasm32-unknown-unknown
run: cd bevy_rapier2d && cargo clippy --verbose --features bevy/webgl2 --target wasm32-unknown-unknown
- name: Clippy bevy_rapier3d
run: cd bevy_rapier3d && cargo clippy --verbose --features wasm-bindgen,bevy/webgl2 --target wasm32-unknown-unknown
run: cd bevy_rapier3d && cargo clippy --verbose --features bevy/webgl2 --target wasm32-unknown-unknown
10 changes: 7 additions & 3 deletions bevy_rapier2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,20 @@ rapier-debug-render = ["rapier2d/debug-render"]
parallel = ["rapier2d/parallel"]
simd-stable = ["rapier2d/simd-stable"]
simd-nightly = ["rapier2d/simd-nightly"]
wasm-bindgen = ["rapier2d/wasm-bindgen"]
serde-serialize = ["rapier2d/serde-serialize", "bevy/serialize", "serde"]
enhanced-determinism = ["rapier2d/enhanced-determinism"]
headless = []
async-collider = ["bevy/bevy_asset", "bevy/bevy_scene", "bevy/bevy_render"]
async-collider = [
"bevy/bevy_asset",
"bevy/bevy_scene",
"bevy/bevy_render",
"bevy/bevy_image",
]

[dependencies]
bevy = { version = "0.15", default-features = false }
nalgebra = { version = "0.33", features = ["convert-glam029"] }
rapier2d = "0.22"
rapier2d = "0.23"
bitflags = "2.4"
log = "0.4"
serde = { version = "1", features = ["derive"], optional = true }
Expand Down
17 changes: 13 additions & 4 deletions bevy_rapier3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,20 @@ rapier-debug-render = ["rapier3d/debug-render"]
parallel = ["rapier3d/parallel"]
simd-stable = ["rapier3d/simd-stable"]
simd-nightly = ["rapier3d/simd-nightly"]
wasm-bindgen = ["rapier3d/wasm-bindgen"]
serde-serialize = ["rapier3d/serde-serialize", "bevy/serialize", "serde"]
enhanced-determinism = ["rapier3d/enhanced-determinism"]
headless = []
async-collider = ["bevy/bevy_asset", "bevy/bevy_scene", "bevy/bevy_render"]
async-collider = [
"bevy/bevy_asset",
"bevy/bevy_scene",
"bevy/bevy_render",
"bevy/bevy_image",
]

[dependencies]
bevy = { version = "0.15", default-features = false }
nalgebra = { version = "0.33", features = ["convert-glam029"] }
rapier3d = "0.22"
rapier3d = "0.23"
bitflags = "2.4"
log = "0.4"
serde = { version = "1", features = ["derive"], optional = true }
Expand All @@ -75,4 +79,9 @@ bevy_egui = "0.31"

[package.metadata.docs.rs]
# Enable all the features when building the docs on docs.rs
features = ["debug-render-3d", "serde-serialize"]
features = [
"debug-render-3d",
"serde-serialize",
"collider-to-bevy-mesh",
"async-collider",
]
182 changes: 182 additions & 0 deletions bevy_rapier3d/examples/rapier_to_bevy_mesh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
use bevy::{
pbr::wireframe::{WireframeConfig, WireframePlugin},
prelude::*,
};
use bevy_rapier3d::prelude::*;

fn main() {
App::new()
.insert_resource(ClearColor::default())
.add_plugins((
DefaultPlugins,
RapierPhysicsPlugin::<NoUserData>::default(),
RapierDebugRenderPlugin::default(),
WireframePlugin,
))
.add_systems(Startup, (setup_graphics, setup_physics))
.add_systems(Update, (toggle_wireframe, toggle_dynamic, rotate))
.run();
}

pub fn setup_graphics(mut commands: Commands) {
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 5.0, 20.0).looking_at(Vec3::new(0.0, 5.0, 0.0), Vec3::Y),
));
}

pub fn setup_physics(
mut commands: Commands,
mut assets_meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
/*
* Ground
*/
let ground_size = 200.1;
let ground_height = 0.1;

commands.spawn((
Transform::from_xyz(0.0, -ground_height, 0.0),
Collider::cuboid(ground_size, ground_height, ground_size),
));
/*
* Create the shapes
*/
let rad = 0.5;

let colors = [
Hsla::hsl(220.0, 1.0, 0.3),
Hsla::hsl(180.0, 1.0, 0.3),
Hsla::hsl(260.0, 1.0, 0.7),
];

let colliders: Vec<Collider> = vec![
Collider::cuboid(rad, rad, rad),
Collider::ball(rad),
Collider::capsule_y(rad, rad),
Collider::cone(rad, rad),
Collider::cylinder(rad, rad),
Collider::trimesh(
vec![
[-0.5, -0.5, -0.5].into(), // Vertex 0
[0.5, -0.5, -0.5].into(), // Vertex 1
[0.5, 0.5, -0.5].into(), // Vertex 2
[-0.5, 0.5, -0.5].into(), // Vertex 3
[-0.5, -0.5, 0.5].into(), // Vertex 4
[0.5, -0.5, 0.5].into(), // Vertex 5
[0.5, 0.5, 0.5].into(), // Vertex 6
[-0.5, 0.5, 0.5].into(), // Vertex 7
],
vec![
// Back face
[0, 2, 1],
[0, 3, 2],
// Front face
[4, 5, 6],
[4, 6, 7],
// Left face
[0, 4, 7],
[0, 7, 3],
// Right face
[1, 6, 5],
[1, 2, 6],
// Bottom face
[0, 1, 5],
[0, 5, 4],
// Top face
[3, 6, 2],
[3, 7, 6],
],
)
.unwrap(),
// Unsupported shapes
Collider::round_cylinder(rad, rad, rad / 10.0),
Collider::segment(Vec3::new(-rad, 0.0, 0.0), Vec3::new(rad, 0.0, 0.0)),
Collider::triangle(
Vec3::new(-rad, -rad, 0.0),
Vec3::new(rad, -rad, 0.0),
Vec3::new(0.0, rad, 0.0),
),
Collider::heightfield(
vec![0.0, 0.0, 0.0, rad, rad, rad, 0.0, 0.0, 0.0],
3,
3,
Vec3::new(rad, rad, rad),
),
];
let material = MeshMaterial3d(materials.add(Color::WHITE));
let colliders_count = colliders.len();
for (i, collider) in colliders.into_iter().enumerate() {
fn get_coordinates(id: usize, column_size: usize) -> Vec3 {
let x = id / column_size;
let y = id % column_size;
let z = 0;
Vec3::new(x as f32, y as f32, z as f32)
}
let column_height = 3;
// Get int coordinates from index
let coordinates = get_coordinates(i, column_height);
// Center the coordinates in x
let columns = colliders_count / column_height;
let coordinates = coordinates - Vec3::new(columns as f32 / 2.0, 0.0, 0.0);
// more space between shapes
let coordinates = coordinates * (1.0 + rad);
// Shift up
let coordinates = coordinates + Vec3::new(0.0, rad + 5.0, 0.0);
let mesh = Mesh::try_from(&collider);
commands
.spawn((
Visibility::default(),
Transform::from_rotation(Quat::from_rotation_x(0.3)),
))
.with_children(|child| {
let mut child = child.spawn((
Transform::from_translation(coordinates),
RigidBody::Fixed,
collider,
ColliderDebugColor(colors[i % 3]),
));
if let Ok(mut mesh) = mesh {
mesh.compute_normals();
child.insert((Mesh3d(assets_meshes.add(mesh)), material.clone()));
}
});
// light
commands.spawn((
PointLight {
shadows_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 8.0),
));
}
}

fn toggle_wireframe(
mut wireframe_config: ResMut<WireframeConfig>,
keyboard: Res<ButtonInput<KeyCode>>,
) {
if keyboard.just_pressed(KeyCode::Space) {
wireframe_config.global = !wireframe_config.global;
}
}

fn toggle_dynamic(mut bodies: Query<&mut RigidBody>, keyboard: Res<ButtonInput<KeyCode>>) {
if keyboard.just_pressed(KeyCode::KeyD) {
for mut body in &mut bodies.iter_mut() {
if body.is_dynamic() {
*body = RigidBody::Fixed;
} else {
*body = RigidBody::Dynamic;
}
}
}
}

fn rotate(mut query: Query<&mut Transform, With<RigidBody>>, time: Res<Time>) {
for mut transform in &mut query {
transform.rotate_y(time.delta_secs() / 2.);
transform.rotate_x(time.delta_secs() / 2.6);
}
}
4 changes: 2 additions & 2 deletions bevy_rapier3d/examples/static_trimesh3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub fn setup_physics(mut commands: Commands, mut ball_state: ResMut<BallState>)
indices.push([2 * i + 2, 2 * i + 1, 2 * i + 3]);
}

commands.spawn(Collider::trimesh(vertices, indices));
commands.spawn(Collider::trimesh(vertices, indices).unwrap());

// Create a bowl with a cosine cross-section,
// so that we can join the end of the ramp smoothly
Expand Down Expand Up @@ -97,7 +97,7 @@ pub fn setup_physics(mut commands: Commands, mut ball_state: ResMut<BallState>)
-bowl_size.y / 2.0,
bowl_size.z / 2.0 - ramp_size.z / 2.0,
),
Collider::trimesh(vertices, indices),
Collider::trimesh(vertices, indices).unwrap(),
));
}

Expand Down
2 changes: 1 addition & 1 deletion bevy_rapier_benches3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rapier3d = { features = ["profiler"], version = "0.22" }
rapier3d = { features = ["profiler"], version = "0.23" }
bevy_rapier3d = { version = "0.28", path = "../bevy_rapier3d" }
bevy = { version = "0.15", default-features = false }

Expand Down
12 changes: 8 additions & 4 deletions bevy_rapier_benches3d/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,25 @@ pub fn custom_bencher(steps: usize, setup: impl Fn(&mut App)) {
timer_full_update.start();
app.update();
timer_full_update.pause();
let elapsed_time = timer_full_update.time() as f32;
let elapsed_time = timer_full_update.time().as_millis();
let rc = app
.world_mut()
.query::<&RapierContextSimulation>()
.single(app.world());
rapier_step_times.push(rc.pipeline.counters.step_time.time() as f32);
rapier_step_times.push(rc.pipeline.counters.step_time.time().as_millis() as f32);
total_update_times.push(elapsed_time);
}
timer_total.pause();
let average_total = total_update_times.iter().sum::<f32>() / total_update_times.len() as f32;
let average_total = total_update_times
.iter()
.map(|time| *time as f32)
.sum::<f32>()
/ total_update_times.len() as f32;
println!("average total time: {} ms", average_total);
let average_rapier_step =
rapier_step_times.iter().sum::<f32>() / rapier_step_times.len() as f32;
println!("average rapier step time: {} ms", average_rapier_step);
let average_rapier_overhead = average_total - average_rapier_step;
println!("average bevy overhead: {} ms", average_rapier_overhead);
println!("total time: {} ms", timer_total.time());
println!("total time: {} ms", timer_total.time().as_millis());
}
27 changes: 16 additions & 11 deletions src/geometry/collider_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,29 +50,29 @@ impl Collider {
}

/// Initialize a new collider with a cylindrical shape defined by its half-height
/// (along along the y axis) and its radius.
/// (along the y axis) and its radius.
#[cfg(feature = "dim3")]
pub fn cylinder(half_height: Real, radius: Real) -> Self {
SharedShape::cylinder(half_height, radius).into()
}

/// Initialize a new collider with a rounded cylindrical shape defined by its half-height
/// (along along the y axis), its radius, and its roundedness (the
/// (along the y axis), its radius, and its roundedness (the
/// radius of the sphere used for dilating the cylinder).
#[cfg(feature = "dim3")]
pub fn round_cylinder(half_height: Real, radius: Real, border_radius: Real) -> Self {
SharedShape::round_cylinder(half_height, radius, border_radius).into()
}

/// Initialize a new collider with a cone shape defined by its half-height
/// (along along the y axis) and its basis radius.
/// (along the y axis) and its basis radius.
#[cfg(feature = "dim3")]
pub fn cone(half_height: Real, radius: Real) -> Self {
SharedShape::cone(half_height, radius).into()
}

/// Initialize a new collider with a rounded cone shape defined by its half-height
/// (along along the y axis), its radius, and its roundedness (the
/// (along the y axis), its radius, and its roundedness (the
/// radius of the sphere used for dilating the cylinder).
#[cfg(feature = "dim3")]
pub fn round_cone(half_height: Real, radius: Real, border_radius: Real) -> Self {
Expand Down Expand Up @@ -151,9 +151,12 @@ impl Collider {
}

/// Initializes a collider with a triangle mesh shape defined by its vertex and index buffers.
pub fn trimesh(vertices: Vec<Vect>, indices: Vec<[u32; 3]>) -> Self {
pub fn trimesh(
vertices: Vec<Vect>,
indices: Vec<[u32; 3]>,
) -> Result<Self, crate::rapier::prelude::TriMeshBuilderError> {
let vertices = vertices.into_iter().map(|v| v.into()).collect();
SharedShape::trimesh(vertices, indices).into()
Ok(SharedShape::trimesh(vertices, indices)?.into())
}

/// Initializes a collider with a triangle mesh shape defined by its vertex and index buffers, and flags
Expand All @@ -162,9 +165,9 @@ impl Collider {
vertices: Vec<Vect>,
indices: Vec<[u32; 3]>,
flags: TriMeshFlags,
) -> Self {
) -> Result<Self, crate::rapier::prelude::TriMeshBuilderError> {
let vertices = vertices.into_iter().map(|v| v.into()).collect();
SharedShape::trimesh_with_flags(vertices, indices, flags).into()
Ok(SharedShape::trimesh_with_flags(vertices, indices, flags)?.into())
}

/// Initializes a collider with a Bevy Mesh.
Expand All @@ -175,9 +178,11 @@ impl Collider {
let (vtx, idx) = extract_mesh_vertices_indices(mesh)?;

match collider_shape {
ComputedColliderShape::TriMesh(flags) => {
Some(SharedShape::trimesh_with_flags(vtx, idx, *flags).into())
}
ComputedColliderShape::TriMesh(flags) => Some(
SharedShape::trimesh_with_flags(vtx, idx, *flags)
.ok()?
.into(),
),
ComputedColliderShape::ConvexHull => {
SharedShape::convex_hull(&vtx).map(|shape| shape.into())
}
Expand Down
Loading
Loading