diff options
Diffstat (limited to 'examples3d')
| -rw-r--r-- | examples3d/all_examples3.rs | 8 | ||||
| -rw-r--r-- | examples3d/character_controller3.rs | 77 | ||||
| -rw-r--r-- | examples3d/convex_decomposition3.rs | 125 | ||||
| -rw-r--r-- | examples3d/debug_deserialize3.rs | 2 | ||||
| -rw-r--r-- | examples3d/debug_internal_edges3.rs | 3 | ||||
| -rw-r--r-- | examples3d/debug_pop3.rs | 42 | ||||
| -rw-r--r-- | examples3d/debug_thin_cube_on_mesh3.rs | 56 | ||||
| -rw-r--r-- | examples3d/dynamic_trimesh3.rs | 145 | ||||
| -rw-r--r-- | examples3d/inverse_kinematics3.rs | 103 | ||||
| -rw-r--r-- | examples3d/vehicle_joints3.rs | 8 |
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 => { |
