Skip to content

Commit

Permalink
add example with a few shapes
Browse files Browse the repository at this point in the history
  • Loading branch information
Vrixyz committed Jan 16, 2025
1 parent 5f971ab commit 9dfe1f5
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 12 deletions.
7 changes: 6 additions & 1 deletion bevy_rapier3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,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",
]
160 changes: 160 additions & 0 deletions bevy_rapier3d/examples/rapier_to_bevy_mesh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
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, 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>>,
) {
/*
* 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 mut mesh = Mesh::from(&collider);
mesh.compute_normals();
commands
.spawn((
Visibility::default(),
Transform::from_rotation(Quat::from_rotation_x(0.3)),
))
.with_children(|child| {
child.spawn((
Transform::from_translation(coordinates),
RigidBody::Fixed,
Mesh3d(assets_meshes.add(mesh)),
material.clone(),
collider,
ColliderDebugColor(colors[i % 3]),
));
});
// 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 rotate(mut query: Query<&mut Transform, With<Collider>>, time: Res<Time>) {
for mut transform in &mut query {
transform.rotate_y(time.delta_secs() / 2.);
transform.rotate_x(time.delta_secs() / 2.6);
}
}
26 changes: 15 additions & 11 deletions src/geometry/to_bevy_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use bevy::{
};
use rapier::prelude::{Shape, TriMesh, TypedShape};

pub fn typed_shape_to_mesh(typed_shape: TypedShape) -> Mesh {
pub fn typed_shape_to_mesh(typed_shape: &TypedShape) -> Mesh {
match typed_shape {
rapier::prelude::TypedShape::Ball(ball) => {
let radius = ball.radius;
let mesh = bevy::render::mesh::SphereMeshBuilder::new(
radius,
bevy::render::mesh::SphereKind::Ico { subdivisions: 10 },
bevy::render::mesh::SphereKind::Ico { subdivisions: 1 },
);
mesh.build()
}
Expand All @@ -32,9 +32,10 @@ pub fn typed_shape_to_mesh(typed_shape: TypedShape) -> Mesh {
let radius = capsule.radius;
let half_height = capsule.half_height();
#[cfg(feature = "dim2")]
let mesh = bevy::render::mesh::Capsule2dMeshBuilder::new(radius, half_height, 10);
let mesh = bevy::render::mesh::Capsule2dMeshBuilder::new(radius, half_height * 2.0, 10);
#[cfg(feature = "dim3")]
let mesh = bevy::render::mesh::Capsule3dMeshBuilder::new(radius, half_height, 10, 10);
let mesh =
bevy::render::mesh::Capsule3dMeshBuilder::new(radius, half_height * 2.0, 10, 10);
mesh.build()
}
rapier::prelude::TypedShape::Segment(segment) => {
Expand All @@ -53,7 +54,10 @@ pub fn typed_shape_to_mesh(typed_shape: TypedShape) -> Mesh {
}
rapier::prelude::TypedShape::TriMesh(tri_mesh) => {
let vertices = tri_mesh.vertices();
#[cfg(feature = "dim2")]
let vertices: Vec<_> = vertices.iter().map(|pos| [pos.x, pos.y, 0.0]).collect();
#[cfg(feature = "dim3")]
let vertices: Vec<_> = vertices.iter().map(|pos| [pos.x, pos.y, pos.z]).collect();
let indices = tri_mesh.indices();
let mesh = Mesh::new(
bevy::render::mesh::PrimitiveTopology::TriangleList,
Expand All @@ -77,7 +81,7 @@ pub fn typed_shape_to_mesh(typed_shape: TypedShape) -> Mesh {
{
// FIXME: we could use TriMesh::From(height_field), but that would clone, we should fix that in parry.
let (vtx, idx) = height_field.to_trimesh();
let tri_mesh = TriMesh::new(vtx, idx);
let tri_mesh = TriMesh::new(vtx, idx).unwrap();

// From Trimesh:
let vertices = tri_mesh.vertices();
Expand All @@ -98,7 +102,7 @@ pub fn typed_shape_to_mesh(typed_shape: TypedShape) -> Mesh {
let mut indices = Vec::new();
for shape in compound.shapes() {
let typed_shape = shape.1.as_typed_shape();
let mesh = typed_shape_to_mesh(typed_shape);
let mesh = typed_shape_to_mesh(&typed_shape);

assert!(mesh.primitive_topology() == bevy::render::mesh::PrimitiveTopology::TriangleList,
"Compound shape mesh conversion does not support shapes not converting to PrimitiveTopology::TriangleList.");
Expand Down Expand Up @@ -163,14 +167,14 @@ pub fn typed_shape_to_mesh(typed_shape: TypedShape) -> Mesh {
let radius = cone.radius;
let half_height = cone.half_height;
// TODO: implement Meshable for all TypedShape variants, that probably will have to be wrapped in a new type.
let mesh = bevy::render::mesh::ConeMeshBuilder::new(radius, half_height, 10);
let mesh = bevy::render::mesh::ConeMeshBuilder::new(radius, half_height * 2.0, 10);
mesh.build()
}
#[cfg(feature = "dim3")]
rapier::prelude::TypedShape::Cylinder(cylinder) => {
let radius = cylinder.radius;
let half_height = cylinder.half_height;
let mesh = bevy::render::mesh::CylinderMeshBuilder::new(radius, half_height, 10);
let mesh = bevy::render::mesh::CylinderMeshBuilder::new(radius, half_height * 2.0, 10);
mesh.build()
}
#[cfg(feature = "dim3")]
Expand Down Expand Up @@ -201,9 +205,9 @@ pub fn typed_shape_to_mesh(typed_shape: TypedShape) -> Mesh {
}
}

impl From<Collider> for Mesh {
fn from(shape: Collider) -> Self {
impl From<&Collider> for Mesh {
fn from(shape: &Collider) -> Self {
let typed_shape = shape.raw.as_typed_shape();
typed_shape_to_mesh(typed_shape)
typed_shape_to_mesh(&typed_shape)
}
}

0 comments on commit 9dfe1f5

Please sign in to comment.