aboutsummaryrefslogtreecommitdiff
path: root/examples3d
diff options
context:
space:
mode:
authorThierry Berger <contact@thierryberger.com>2024-06-03 15:20:24 +0200
committerThierry Berger <contact@thierryberger.com>2024-06-03 15:20:24 +0200
commite1ed90603e618e28f48916690d761e0d8213e2ad (patch)
tree8399da9825ca9ee8edd601b1265e818fa303b541 /examples3d
parentfe336b9b98d5825544ad3a153a84cb59dc9171c6 (diff)
parent856675032e76b6eb4bc9e0be4dc87abdbcfe0421 (diff)
downloadrapier-e1ed90603e618e28f48916690d761e0d8213e2ad.tar.gz
rapier-e1ed90603e618e28f48916690d761e0d8213e2ad.tar.bz2
rapier-e1ed90603e618e28f48916690d761e0d8213e2ad.zip
Merge branch 'master' into collider-builder-debug
Diffstat (limited to 'examples3d')
-rw-r--r--examples3d/all_examples3.rs8
-rw-r--r--examples3d/character_controller3.rs77
-rw-r--r--examples3d/convex_decomposition3.rs125
-rw-r--r--examples3d/debug_deserialize3.rs2
-rw-r--r--examples3d/debug_internal_edges3.rs3
-rw-r--r--examples3d/debug_pop3.rs42
-rw-r--r--examples3d/debug_thin_cube_on_mesh3.rs56
-rw-r--r--examples3d/dynamic_trimesh3.rs145
-rw-r--r--examples3d/inverse_kinematics3.rs103
-rw-r--r--examples3d/vehicle_joints3.rs8
10 files changed, 416 insertions, 153 deletions
diff --git a/examples3d/all_examples3.rs b/examples3d/all_examples3.rs
index bac826e..3e6398f 100644
--- a/examples3d/all_examples3.rs
+++ b/examples3d/all_examples3.rs
@@ -23,12 +23,15 @@ mod debug_deserialize3;
mod debug_dynamic_collider_add3;
mod debug_friction3;
mod debug_infinite_fall3;
+mod debug_pop3;
mod debug_prismatic3;
mod debug_rollback3;
mod debug_shape_modification3;
+mod debug_thin_cube_on_mesh3;
mod debug_triangle3;
mod debug_trimesh3;
mod domino3;
+mod dynamic_trimesh3;
mod fountain3;
mod heightfield3;
mod joints3;
@@ -39,6 +42,7 @@ mod debug_cube_high_mass_ratio3;
mod debug_internal_edges3;
mod debug_long_chain3;
mod debug_multibody_ang_motor_pos3;
+mod inverse_kinematics3;
mod joint_motor_position3;
mod keva3;
mod locked_rotations3;
@@ -102,8 +106,10 @@ pub fn main() {
("Convex polyhedron", convex_polyhedron3::init_world),
("Damping", damping3::init_world),
("Domino", domino3::init_world),
+ ("Dynamic trimeshes", dynamic_trimesh3::init_world),
("Heightfield", heightfield3::init_world),
("Impulse Joints", joints3::init_world_with_joints),
+ ("Inverse kinematics", inverse_kinematics3::init_world),
("Joint Motor Position", joint_motor_position3::init_world),
("Locked rotations", locked_rotations3::init_world),
("One-way platforms", one_way_platforms3::init_world),
@@ -124,6 +130,7 @@ pub fn main() {
),
("(Debug) big colliders", debug_big_colliders3::init_world),
("(Debug) boxes", debug_boxes3::init_world),
+ ("(Debug) pop", debug_pop3::init_world),
(
"(Debug) dyn. coll. add",
debug_dynamic_collider_add3::init_world,
@@ -141,6 +148,7 @@ pub fn main() {
),
("(Debug) triangle", debug_triangle3::init_world),
("(Debug) trimesh", debug_trimesh3::init_world),
+ ("(Debug) thin cube", debug_thin_cube_on_mesh3::init_world),
("(Debug) cylinder", debug_cylinder3::init_world),
("(Debug) infinite fall", debug_infinite_fall3::init_world),
("(Debug) prismatic", debug_prismatic3::init_world),
diff --git a/examples3d/character_controller3.rs b/examples3d/character_controller3.rs
index 939cfd1..f031f0a 100644
--- a/examples3d/character_controller3.rs
+++ b/examples3d/character_controller3.rs
@@ -13,21 +13,37 @@ pub fn init_world(testbed: &mut Testbed) {
/*
* Ground
*/
+ let scale = 1.0; // Set to a larger value to check if it still works with larger units.
let ground_size = 5.0;
let ground_height = 0.1;
- let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]);
+ let rigid_body =
+ RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0] * scale);
+ let floor_handle = bodies.insert(rigid_body);
+ let collider = ColliderBuilder::cuboid(
+ ground_size * scale,
+ ground_height * scale,
+ ground_size * scale,
+ );
+ colliders.insert_with_parent(collider, floor_handle, &mut bodies);
+
+ let rigid_body =
+ RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, -ground_size] * scale); //.rotation(vector![-0.1, 0.0, 0.0]);
let floor_handle = bodies.insert(rigid_body);
- let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
+ let collider = ColliderBuilder::cuboid(
+ ground_size * scale,
+ ground_size * scale,
+ ground_height * scale,
+ );
colliders.insert_with_parent(collider, floor_handle, &mut bodies);
/*
* Character we will control manually.
*/
let rigid_body =
- RigidBodyBuilder::kinematic_position_based().translation(vector![-3.0, 5.0, 0.0]);
+ RigidBodyBuilder::kinematic_position_based().translation(vector![-3.0, 5.0, 0.0] * scale);
let character_handle = bodies.insert(rigid_body);
- let collider = ColliderBuilder::capsule_y(0.3, 0.15); // 0.15, 0.3, 0.15);
+ let collider = ColliderBuilder::capsule_y(0.3 * scale, 0.15 * scale); // 0.15, 0.3, 0.15);
colliders.insert_with_parent(collider, character_handle, &mut bodies);
/*
@@ -47,9 +63,9 @@ pub fn init_world(testbed: &mut Testbed) {
let y = j as f32 * shift + centery;
let z = k as f32 * shift + centerx;
- let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]);
+ let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z] * scale);
let handle = bodies.insert(rigid_body);
- let collider = ColliderBuilder::cuboid(rad, rad, rad);
+ let collider = ColliderBuilder::cuboid(rad * scale, rad * scale, rad * scale);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
@@ -64,8 +80,12 @@ pub fn init_world(testbed: &mut Testbed) {
let x = i as f32 * stair_width / 2.0;
let y = i as f32 * stair_height * 1.5 + 3.0;
- let collider = ColliderBuilder::cuboid(stair_width / 2.0, stair_height / 2.0, stair_width)
- .translation(vector![x, y, 0.0]);
+ let collider = ColliderBuilder::cuboid(
+ stair_width / 2.0 * scale,
+ stair_height / 2.0 * scale,
+ stair_width * scale,
+ )
+ .translation(vector![x * scale, y * scale, 0.0]);
colliders.insert(collider);
}
@@ -74,9 +94,13 @@ pub fn init_world(testbed: &mut Testbed) {
*/
let slope_angle = 0.2;
let slope_size = 2.0;
- let collider = ColliderBuilder::cuboid(slope_size, ground_height, slope_size)
- .translation(vector![ground_size + slope_size, -ground_height + 0.4, 0.0])
- .rotation(Vector::z() * slope_angle);
+ let collider = ColliderBuilder::cuboid(
+ slope_size * scale,
+ ground_height * scale,
+ slope_size * scale,
+ )
+ .translation(vector![ground_size + slope_size, -ground_height + 0.4, 0.0] * scale)
+ .rotation(Vector::z() * slope_angle);
colliders.insert(collider);
/*
@@ -84,22 +108,29 @@ pub fn init_world(testbed: &mut Testbed) {
*/
let impossible_slope_angle = 0.9;
let impossible_slope_size = 2.0;
- let collider = ColliderBuilder::cuboid(slope_size, ground_height, ground_size)
- .translation(vector![
+ let collider = ColliderBuilder::cuboid(
+ slope_size * scale,
+ ground_height * scale,
+ ground_size * scale,
+ )
+ .translation(
+ vector![
ground_size + slope_size * 2.0 + impossible_slope_size - 0.9,
-ground_height + 2.3,
0.0
- ])
- .rotation(Vector::z() * impossible_slope_angle);
+ ] * scale,
+ )
+ .rotation(Vector::z() * impossible_slope_angle);
colliders.insert(collider);
/*
* Create a moving platform.
*/
- let body = RigidBodyBuilder::kinematic_velocity_based().translation(vector![-8.0, 1.5, 0.0]);
+ let body =
+ RigidBodyBuilder::kinematic_velocity_based().translation(vector![-8.0, 1.5, 0.0] * scale);
// .rotation(-0.3);
let platform_handle = bodies.insert(body);
- let collider = ColliderBuilder::cuboid(2.0, ground_height, 2.0);
+ let collider = ColliderBuilder::cuboid(2.0 * scale, ground_height * scale, 2.0 * scale);
colliders.insert_with_parent(collider, platform_handle, &mut bodies);
/*
@@ -113,18 +144,18 @@ pub fn init_world(testbed: &mut Testbed) {
+ (j as f32 * ground_size.z / (nsubdivs as f32) / 2.0).cos()
});
- let collider =
- ColliderBuilder::heightfield(heights, ground_size).translation(vector![-8.0, 5.0, 0.0]);
+ let collider = ColliderBuilder::heightfield(heights, ground_size * scale)
+ .translation(vector![-8.0, 5.0, 0.0] * scale);
colliders.insert(collider);
/*
* A tilting dynamic body with a limited joint.
*/
- let ground = RigidBodyBuilder::fixed().translation(vector![0.0, 5.0, 0.0]);
+ let ground = RigidBodyBuilder::fixed().translation(vector![0.0, 5.0, 0.0] * scale);
let ground_handle = bodies.insert(ground);
- let body = RigidBodyBuilder::dynamic().translation(vector![0.0, 5.0, 0.0]);
+ let body = RigidBodyBuilder::dynamic().translation(vector![0.0, 5.0, 0.0] * scale);
let handle = bodies.insert(body);
- let collider = ColliderBuilder::cuboid(1.0, 0.1, 2.0);
+ let collider = ColliderBuilder::cuboid(1.0 * scale, 0.1 * scale, 2.0 * scale);
colliders.insert_with_parent(collider, handle, &mut bodies);
let joint = RevoluteJointBuilder::new(Vector::z_axis()).limits([-0.3, 0.3]);
impulse_joints.insert(ground_handle, handle, joint, true);
@@ -137,7 +168,7 @@ pub fn init_world(testbed: &mut Testbed) {
(run_state.time * 2.0).sin() * 2.0,
(run_state.time * 5.0).sin() * 1.5,
0.0
- ];
+ ] * scale;
// let angvel = run_state.time.sin() * 0.5;
// Update the velocity-based kinematic body by setting its velocity.
diff --git a/examples3d/convex_decomposition3.rs b/examples3d/convex_decomposition3.rs
index 0863430..eeaa682 100644
--- a/examples3d/convex_decomposition3.rs
+++ b/examples3d/convex_decomposition3.rs
@@ -1,128 +1,5 @@
-use obj::raw::object::Polygon;
-use rapier3d::parry::bounding_volume;
-use rapier3d::prelude::*;
use rapier_testbed3d::Testbed;
-use std::fs::File;
-use std::io::BufReader;
-/*
- * NOTE: The `r` macro is only here to convert from f64 to the `N` scalar type.
- * This simplifies experimentation with various scalar types (f32, fixed-point numbers, etc.)
- */
pub fn init_world(testbed: &mut Testbed) {
- /*
- * World
- */
- let mut bodies = RigidBodySet::new();
- let mut colliders = ColliderSet::new();
- let impulse_joints = ImpulseJointSet::new();
- let multibody_joints = MultibodyJointSet::new();
-
- /*
- * Ground
- */
- let ground_size = 50.0;
- let ground_height = 0.1;
-
- let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]);
- let handle = bodies.insert(rigid_body);
- let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
- colliders.insert_with_parent(collider, handle, &mut bodies);
-
- /*
- * Create the convex decompositions.
- */
- let geoms = models();
- let ngeoms = geoms.len();
- let width = (ngeoms as f32).sqrt() as usize;
- let num_duplications = 4;
- let shift = 5.0f32;
-
- for (igeom, obj_path) in geoms.into_iter().enumerate() {
- let deltas = Isometry::identity();
-
- let mut shapes = Vec::new();
- println!("Parsing and decomposing: {}", obj_path);
- let input = BufReader::new(File::open(obj_path).unwrap());
-
- if let Ok(model) = obj::raw::parse_obj(input) {
- let mut vertices: Vec<_> = model
- .positions
- .iter()
- .map(|v| point![v.0, v.1, v.2])
- .collect();
- let indices: Vec<_> = model
- .polygons
- .into_iter()
- .flat_map(|p| match p {
- Polygon::P(idx) => idx.into_iter(),
- Polygon::PT(idx) => Vec::from_iter(idx.into_iter().map(|i| i.0)).into_iter(),
- Polygon::PN(idx) => Vec::from_iter(idx.into_iter().map(|i| i.0)).into_iter(),
- Polygon::PTN(idx) => Vec::from_iter(idx.into_iter().map(|i| i.0)).into_iter(),
- })
- .collect();
-
- // Compute the size of the model, to scale it and have similar size for everything.
- let aabb = bounding_volume::details::point_cloud_aabb(&deltas, &vertices);
- let center = aabb.center();
- let diag = (aabb.maxs - aabb.mins).norm();
-
- vertices
- .iter_mut()
- .for_each(|p| *p = (*p - center.coords) * 6.0 / diag);
-
- let indices: Vec<_> = indices
- .chunks(3)
- .map(|idx| [idx[0] as u32, idx[1] as u32, idx[2] as u32])
- .collect();
-
- let decomposed_shape = SharedShape::convex_decomposition(&vertices, &indices);
- shapes.push(decomposed_shape);
-
- // let compound = SharedShape::compound(compound_parts);
-
- for k in 1..num_duplications + 1 {
- let x = (igeom % width) as f32 * shift;
- let y = (igeom / width) as f32 * shift + 4.0;
- let z = k as f32 * shift;
-
- let body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]);
- let handle = bodies.insert(body);
-
- for shape in &shapes {
- let collider = ColliderBuilder::new(shape.clone());
- colliders.insert_with_parent(collider, handle, &mut bodies);
- }
- }
- }
- }
-
- /*
- * Set up the testbed.
- */
- testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
- testbed.look_at(point![100.0, 100.0, 100.0], Point::origin());
-}
-
-fn models() -> Vec<String> {
- vec![
- "assets/3d/camel_decimated.obj".to_string(),
- "assets/3d/chair.obj".to_string(),
- "assets/3d/cup_decimated.obj".to_string(),
- "assets/3d/dilo_decimated.obj".to_string(),
- "assets/3d/feline_decimated.obj".to_string(),
- "assets/3d/genus3_decimated.obj".to_string(),
- "assets/3d/hand2_decimated.obj".to_string(),
- "assets/3d/hand_decimated.obj".to_string(),
- "assets/3d/hornbug.obj".to_string(),
- "assets/3d/octopus_decimated.obj".to_string(),
- "assets/3d/rabbit_decimated.obj".to_string(),
- // "assets/3d/rust_logo.obj".to_string(),
- "assets/3d/rust_logo_simplified.obj".to_string(),
- "assets/3d/screwdriver_decimated.obj".to_string(),
- "assets/3d/table.obj".to_string(),
- "assets/3d/tstTorusModel.obj".to_string(),
- // "assets/3d/tstTorusModel2.obj".to_string(),
- // "assets/3d/tstTorusModel3.obj".to_string(),
- ]
+ crate::dynamic_trimesh3::do_init_world(testbed, true);
}
diff --git a/examples3d/debug_deserialize3.rs b/examples3d/debug_deserialize3.rs
index b8b79fb..0762b4d 100644
--- a/examples3d/debug_deserialize3.rs
+++ b/examples3d/debug_deserialize3.rs
@@ -6,7 +6,7 @@ struct PhysicsState {
pub gravity: Vector<f32>,
pub integration_parameters: IntegrationParameters,
pub islands: IslandManager,
- pub broad_phase: BroadPhase,
+ pub broad_phase: DefaultBroadPhase,
pub narrow_phase: NarrowPhase,
pub bodies: RigidBodySet,
pub colliders: ColliderSet,
diff --git a/examples3d/debug_internal_edges3.rs b/examples3d/debug_internal_edges3.rs
index 7112fb0..86de1bd 100644
--- a/examples3d/debug_internal_edges3.rs
+++ b/examples3d/debug_internal_edges3.rs
@@ -11,7 +11,8 @@ pub fn init_world(testbed: &mut Testbed) {
let multibody_joints = MultibodyJointSet::new();
let heights = DMatrix::zeros(100, 100);
- let heightfield = HeightField::new(heights, vector![60.0, 1.0, 60.0]);
+ let heightfield =
+ HeightField::with_flags(heights, vector![60.0, 1.0, 60.0], HeightFieldFlags::all());
let rotation = vector![0.0, 0.0, 0.0]; // vector![-0.1, 0.0, 0.0];
colliders
.insert(ColliderBuilder::new(SharedShape::new(heightfield.clone())).rotation(rotation));
diff --git a/examples3d/debug_pop3.rs b/examples3d/debug_pop3.rs
new file mode 100644
index 0000000..93d58e0
--- /dev/null
+++ b/examples3d/debug_pop3.rs
@@ -0,0 +1,42 @@
+use rapier3d::prelude::*;
+use rapier_testbed3d::Testbed;
+
+pub fn init_world(testbed: &mut Testbed) {
+ /*
+ * World
+ */
+ let mut bodies = RigidBodySet::new();
+ let mut colliders = ColliderSet::new();
+ let impulse_joints = ImpulseJointSet::new();
+ let multibody_joints = MultibodyJointSet::new();
+
+ /*
+ * Ground
+ */
+ let ground_size = 10.0;
+ let ground_height = 10.0;
+
+ for _ in 0..1 {
+ let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]);
+ let handle = bodies.insert(rigid_body);
+ let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
+ colliders.insert_with_parent(collider, handle, &mut bodies);
+ }
+
+ // Build the dynamic box rigid body.
+ for _ in 0..1 {
+ let rigid_body = RigidBodyBuilder::dynamic()
+ // .translation(vector![0.0, 0.1, 0.0])
+ // .rotation(vector![0.8, 0.2, 0.1])
+ .can_sleep(false);
+ let handle = bodies.insert(rigid_body);
+ let collider = ColliderBuilder::cuboid(1.0, 1.0, 1.0);
+ colliders.insert_with_parent(collider.clone(), handle, &mut bodies);
+ }
+
+ /*
+ * Set up the testbed.
+ */
+ testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
+ testbed.look_at(point![10.0, 10.0, 10.0], Point::origin());
+}
diff --git a/examples3d/debug_thin_cube_on_mesh3.rs b/examples3d/debug_thin_cube_on_mesh3.rs
new file mode 100644
index 0000000..4ad557a
--- /dev/null
+++ b/examples3d/debug_thin_cube_on_mesh3.rs
@@ -0,0 +1,56 @@
+use rapier3d::prelude::*;
+use rapier_testbed3d::Testbed;
+
+// This shows a bug when a cylinder is in contact with a very large
+// but very thin cuboid. In this case the EPA returns an incorrect
+// contact normal, resulting in the cylinder falling through the floor.
+pub fn init_world(testbed: &mut Testbed) {
+ /*
+ * World
+ */
+ let mut bodies = RigidBodySet::new();
+ let mut colliders = ColliderSet::new();
+ let impulse_joints = ImpulseJointSet::new();
+ let multibody_joints = MultibodyJointSet::new();
+
+ /*
+ * Ground
+ */
+ // let vertices = vec![
+ // point![-50.0, 0.0, -50.0],
+ // point![-50.0, 0.0, 50.0],
+ // point![50.0, 0.0, 50.0],
+ // point![50.0, 0.0, -50.0],
+ // ];
+ // let indices = vec![[0, 1, 2], [0, 2, 3]];
+ //
+ // let collider = ColliderBuilder::trimesh_with_flags(vertices, indices, TriMeshFlags::all());
+ // colliders.insert(collider);
+
+ let heights = DMatrix::repeat(2, 2, 0.0);
+ let collider = ColliderBuilder::heightfield_with_flags(
+ heights,
+ Vector::new(50.0, 1.0, 50.0),
+ HeightFieldFlags::FIX_INTERNAL_EDGES,
+ );
+ colliders.insert(collider);
+
+ /*
+ * Create the cubes
+ */
+ // Build the rigid body.
+ let rigid_body = RigidBodyBuilder::dynamic()
+ .translation(vector![0.0, 5.0, 0.0])
+ .rotation(vector![0.5, 0.0, 0.5])
+ .linvel(vector![0.0, -100.0, 0.0])
+ .soft_ccd_prediction(10.0);
+ let handle = bodies.insert(rigid_body);
+ let collider = ColliderBuilder::cuboid(5.0, 0.015, 5.0);
+ colliders.insert_with_parent(collider, handle, &mut bodies);
+
+ /*
+ * Set up the testbed.
+ */
+ testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
+ testbed.look_at(point![100.0, 100.0, 100.0], Point::origin());
+}
diff --git a/examples3d/dynamic_trimesh3.rs b/examples3d/dynamic_trimesh3.rs
new file mode 100644
index 0000000..0a82476
--- /dev/null
+++ b/examples3d/dynamic_trimesh3.rs
@@ -0,0 +1,145 @@
+use obj::raw::object::Polygon;
+use rapier3d::parry::bounding_volume;
+use rapier3d::prelude::*;
+use rapier_testbed3d::Testbed;
+use std::fs::File;
+use std::io::BufReader;
+
+pub fn init_world(testbed: &mut Testbed) {
+ do_init_world(testbed, false);
+}
+
+pub fn do_init_world(testbed: &mut Testbed, use_convex_decomposition: bool) {
+ /*
+ * World
+ */
+ let mut bodies = RigidBodySet::new();
+ let mut colliders = ColliderSet::new();
+ let impulse_joints = ImpulseJointSet::new();
+ let multibody_joints = MultibodyJointSet::new();
+
+ /*
+ * Ground
+ */
+ //// OPTION 1: floor made of a single big box.
+ // let ground_size = 50.0;
+ // let ground_height = 0.1;
+ // let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]);
+ // let handle = bodies.insert(rigid_body);
+ // let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
+ // colliders.insert_with_parent(collider, handle, &mut bodies);
+
+ //// OPTION 2: floor made of a wavy mesh.
+ let nsubdivs = 100;
+ let heights = DMatrix::from_fn(nsubdivs + 1, nsubdivs + 1, |i, j| {
+ -(i as f32 * 40.0 / (nsubdivs as f32) / 2.0).cos()
+ - (j as f32 * 40.0 / (nsubdivs as f32) / 2.0).cos()
+ });
+ let heightfield = HeightField::new(heights, vector![100.0, 2.0, 100.0]);
+ let mut trimesh = TriMesh::from(heightfield);
+ let _ = trimesh.set_flags(TriMeshFlags::FIX_INTERNAL_EDGES);
+ colliders.insert(ColliderBuilder::new(SharedShape::new(trimesh.clone())));
+
+ /*
+ * Create the convex decompositions.
+ */
+ let geoms = models();
+ let ngeoms = geoms.len();
+ let width = (ngeoms as f32).sqrt() as usize;
+ let num_duplications = 4;
+ let shift_y = 8.0f32;
+ let shift_xz = 9.0f32;
+
+ for (igeom, obj_path) in geoms.into_iter().enumerate() {
+ let deltas = Isometry::identity();
+
+ let mut shapes = Vec::new();
+ println!("Parsing and decomposing: {}", obj_path);
+ let input = BufReader::new(File::open(obj_path).unwrap());
+
+ if let Ok(model) = obj::raw::parse_obj(input) {
+ let mut vertices: Vec<_> = model
+ .positions
+ .iter()
+ .map(|v| point![v.0, v.1, v.2])
+ .collect();
+ let indices: Vec<_> = model
+ .polygons
+ .into_iter()
+ .flat_map(|p| match p {
+ Polygon::P(idx) => idx.into_iter(),
+ Polygon::PT(idx) => Vec::from_iter(idx.into_iter().map(|i| i.0)).into_iter(),
+ Polygon::PN(idx) => Vec::from_iter(idx.into_iter().map(|i| i.0)).into_iter(),
+ Polygon::PTN(idx) => Vec::from_iter(idx.into_iter().map(|i| i.0)).into_iter(),
+ })
+ .collect();
+
+ // Compute the size of the model, to scale it and have similar size for everything.
+ let aabb = bounding_volume::details::point_cloud_aabb(&deltas, &vertices);
+ let center = aabb.center();
+ let diag = (aabb.maxs - aabb.mins).norm();
+
+ vertices
+ .iter_mut()
+ .for_each(|p| *p = (*p - center.coords) * 10.0 / diag);
+
+ let indices: Vec<_> = indices
+ .chunks(3)
+ .map(|idx| [idx[0] as u32, idx[1] as u32, idx[2] as u32])
+ .collect();
+
+ let decomposed_shape = if use_convex_decomposition {
+ SharedShape::convex_decomposition(&vertices, &indices)
+ } else {
+ // SharedShape::trimesh(vertices, indices)
+ SharedShape::trimesh_with_flags(vertices, indices, TriMeshFlags::FIX_INTERNAL_EDGES)
+ };
+ shapes.push(decomposed_shape);
+
+ // let compound = SharedShape::compound(compound_parts);
+
+ for k in 1..num_duplications + 1 {
+ let x =
+ (igeom % width) as f32 * shift_xz - num_duplications as f32 * shift_xz / 2.0;
+ let y = (igeom / width) as f32 * shift_y + 7.0;
+ let z = k as f32 * shift_xz - num_duplications as f32 * shift_xz / 2.0;
+
+ let body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]);
+ let handle = bodies.insert(body);
+
+ for shape in &shapes {
+ let collider = ColliderBuilder::new(shape.clone()).contact_skin(0.1);
+ colliders.insert_with_parent(collider, handle, &mut bodies);
+ }
+ }
+ }
+ }
+
+ /*
+ * Set up the testbed.
+ */
+ testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
+ testbed.look_at(point![100.0, 100.0, 100.0], Point::origin());
+}
+
+fn models() -> Vec<String> {
+ vec![
+ "assets/3d/camel_decimated.obj".to_string(),
+ "assets/3d/chair.obj".to_string(),
+ "assets/3d/cup_decimated.obj".to_string(),
+ "assets/3d/dilo_decimated.obj".to_string(),
+ "assets/3d/tstTorusModel2.obj".to_string(),
+ "assets/3d/feline_decimated.obj".to_string(),
+ "assets/3d/genus3_decimated.obj".to_string(),
+ // "assets/3d/hand2_decimated.obj".to_string(),
+ // "assets/3d/hand_decimated.obj".to_string(),
+ "assets/3d/hornbug.obj".to_string(),
+ "assets/3d/tstTorusModel.obj".to_string(),
+ "assets/3d/octopus_decimated.obj".to_string(),
+ "assets/3d/rabbit_decimated.obj".to_string(),
+ "assets/3d/rust_logo_simplified.obj".to_string(),
+ "assets/3d/screwdriver_decimated.obj".to_string(),
+ "assets/3d/table.obj".to_string(),
+ "assets/3d/tstTorusModel3.obj".to_string(),
+ ]
+}
diff --git a/examples3d/inverse_kinematics3.rs b/examples3d/inverse_kinematics3.rs
new file mode 100644
index 0000000..7905ae0
--- /dev/null
+++ b/examples3d/inverse_kinematics3.rs
@@ -0,0 +1,103 @@
+use rapier3d::prelude::*;
+use rapier_testbed3d::Testbed;
+
+pub fn init_world(testbed: &mut Testbed) {
+ /*
+ * World
+ */
+ let mut bodies = RigidBodySet::new();
+ let mut colliders = ColliderSet::new();
+ let impulse_joints = ImpulseJointSet::new();
+ let mut multibody_joints = MultibodyJointSet::new();
+
+ /*
+ * Ground
+ */
+ let ground_size = 0.2;
+ let ground_height = 0.01;
+
+ let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]);
+ let floor_handle = bodies.insert(rigid_body);
+ let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
+ colliders.insert_with_parent(collider, floor_handle, &mut bodies);
+
+ /*
+ * Setup groups
+ */
+ let num_segments = 10;
+ let body = RigidBodyBuilder::fixed();
+ let mut last_body = bodies.insert(body);
+ let mut last_link = MultibodyJointHandle::invalid();
+
+ for i in 0..num_segments {
+ let size = 1.0 / num_segments as f32;
+ let body = RigidBodyBuilder::dynamic().can_sleep(false);
+ let new_body = bodies.insert(body);
+ // NOTE: we add a sensor collider just to make the destbed draw a rectangle to make
+ // the demo look nicer. IK could be used without cuboid.
+ let collider = ColliderBuilder::cuboid(size / 8.0, size / 2.0, size / 8.0)
+ .density(0.0)
+ .sensor(true);
+ colliders.insert_with_parent(collider, new_body, &mut bodies);
+
+ let link_ab = SphericalJointBuilder::new()
+ .local_anchor1(point![0.0, size / 2.0 * (i != 0) as usize as f32, 0.0])
+ .local_anchor2(point![0.0, -size / 2.0, 0.0])
+ .build()
+ .data;
+
+ last_link = multibody_joints
+ .insert(last_body, new_body, link_ab, true)
+ .unwrap();
+
+ last_body = new_body;
+ }
+
+ let mut displacements = DVector::zeros(0);
+
+ testbed.add_callback(move |graphics, physics, _, _| {
+ let Some(graphics) = graphics else { return };
+ if let Some((multibody, link_id)) = physics.multibody_joints.get_mut(last_link) {
+ // Ensure our displacement vector has the right number of elements.
+ if displacements.nrows() < multibody.ndofs() {
+ displacements = DVector::zeros(multibody.ndofs());
+ } else {
+ displacements.fill(0.0);
+ }
+
+ let Some(mouse_ray) = graphics.mouse().ray else {
+ return;
+ };
+
+ // Cast a ray on a plane aligned with the camera passing through the origin.
+ let halfspace = HalfSpace {
+ normal: -UnitVector::new_normalize(graphics.camera_fwd_dir()),
+ };
+ let mouse_ray = Ray::new(mouse_ray.0, mouse_ray.1);
+ let Some(hit) = halfspace.cast_local_ray(&mouse_ray, f32::MAX, false) else {
+ return;
+ };
+ let target_point = mouse_ray.point_at(hit);
+
+ let options = InverseKinematicsOption {
+ constrained_axes: JointAxesMask::LIN_AXES,
+ ..Default::default()
+ };
+
+ multibody.inverse_kinematics(
+ &physics.bodies,
+ link_id,
+ &options,
+ &Isometry::from(target_point),
+ &mut displacements,
+ );
+ multibody.apply_displacements(displacements.as_slice());
+ }
+ });
+
+ /*
+ * Set up the testbed.
+ */
+ testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
+ testbed.look_at(point![0.0, 0.5, 2.5], point![0.0, 0.5, 0.0]);
+}
diff --git a/examples3d/vehicle_joints3.rs b/examples3d/vehicle_joints3.rs
index ddd672c..5eba608 100644
--- a/examples3d/vehicle_joints3.rs
+++ b/examples3d/vehicle_joints3.rs
@@ -138,16 +138,16 @@ pub fn init_world(testbed: &mut Testbed) {
for key in gfx.keys().get_pressed() {
match *key {
- KeyCode::Right => {
+ KeyCode::ArrowRight => {
steering = -1.0;
}
- KeyCode::Left => {
+ KeyCode::ArrowLeft => {
steering = 1.0;
}
- KeyCode::Up => {
+ KeyCode::ArrowUp => {
thrust = -drive_strength;
}
- KeyCode::Down => {
+ KeyCode::ArrowDown => {
thrust = drive_strength;
}
KeyCode::ShiftRight => {