diff options
| author | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
|---|---|---|
| committer | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
| commit | 754a48b7ff6d8c58b1ee08651e60112900b60455 (patch) | |
| tree | 7d777a6c003f1f5d8f8d24f533f35a95a88957fe /src_testbed/nphysics_backend.rs | |
| download | rapier-0.1.0.tar.gz rapier-0.1.0.tar.bz2 rapier-0.1.0.zip | |
First public release of Rapier.v0.1.0
Diffstat (limited to 'src_testbed/nphysics_backend.rs')
| -rw-r--r-- | src_testbed/nphysics_backend.rs | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src_testbed/nphysics_backend.rs b/src_testbed/nphysics_backend.rs new file mode 100644 index 0000000..43f3bf9 --- /dev/null +++ b/src_testbed/nphysics_backend.rs @@ -0,0 +1,212 @@ +use ncollide::shape::{Ball, Capsule, Cuboid, ShapeHandle}; +use nphysics::force_generator::DefaultForceGeneratorSet; +use nphysics::joint::{ + DefaultJointConstraintSet, FixedConstraint, PrismaticConstraint, RevoluteConstraint, +}; +use nphysics::object::{ + BodyPartHandle, ColliderDesc, DefaultBodyHandle, DefaultBodySet, DefaultColliderSet, + RigidBodyDesc, +}; +use nphysics::world::{DefaultGeometricalWorld, DefaultMechanicalWorld}; +use rapier::counters::Counters; +use rapier::dynamics::{ + IntegrationParameters, JointParams, JointSet, RigidBodyHandle, RigidBodySet, +}; +use rapier::geometry::{Collider, ColliderSet, Shape}; +use rapier::math::{Isometry, Vector}; +use std::collections::HashMap; +#[cfg(feature = "dim3")] +use {ncollide::shape::TriMesh, nphysics::joint::BallConstraint}; + +pub struct NPhysicsWorld { + rapier2nphysics: HashMap<RigidBodyHandle, DefaultBodyHandle>, + mechanical_world: DefaultMechanicalWorld<f32>, + geometrical_world: DefaultGeometricalWorld<f32>, + bodies: DefaultBodySet<f32>, + colliders: DefaultColliderSet<f32>, + joints: DefaultJointConstraintSet<f32>, + force_generators: DefaultForceGeneratorSet<f32>, +} + +impl NPhysicsWorld { + pub fn from_rapier( + gravity: Vector<f32>, + bodies: &RigidBodySet, + colliders: &ColliderSet, + joints: &JointSet, + ) -> Self { + let mut rapier2nphysics = HashMap::new(); + + let mechanical_world = DefaultMechanicalWorld::new(gravity); + let geometrical_world = DefaultGeometricalWorld::new(); + let mut nphysics_bodies = DefaultBodySet::new(); + let mut nphysics_colliders = DefaultColliderSet::new(); + let mut nphysics_joints = DefaultJointConstraintSet::new(); + let force_generators = DefaultForceGeneratorSet::new(); + + for (rapier_handle, rb) in bodies.iter() { + // let material = physics.create_material(rb.collider.friction, rb.collider.friction, 0.0); + let nphysics_rb = RigidBodyDesc::new().position(rb.position).build(); + let nphysics_rb_handle = nphysics_bodies.insert(nphysics_rb); + + rapier2nphysics.insert(rapier_handle, nphysics_rb_handle); + } + + for (_, collider) in colliders.iter() { + let parent = &bodies[collider.parent()]; + let nphysics_rb_handle = rapier2nphysics[&collider.parent()]; + if let Some(collider) = + nphysics_collider_from_rapier_collider(&collider, parent.is_dynamic()) + { + let nphysics_collider = collider.build(BodyPartHandle(nphysics_rb_handle, 0)); + nphysics_colliders.insert(nphysics_collider); + } else { + eprintln!("Creating shape unknown to the nphysics backend.") + } + } + + for joint in joints.iter() { + let b1 = BodyPartHandle(rapier2nphysics[&joint.body1], 0); + let b2 = BodyPartHandle(rapier2nphysics[&joint.body2], 0); + + match &joint.params { + JointParams::FixedJoint(params) => { + let c = FixedConstraint::new( + b1, + b2, + params.local_anchor1.translation.vector.into(), + params.local_anchor1.rotation, + params.local_anchor2.translation.vector.into(), + params.local_anchor2.rotation, + ); + nphysics_joints.insert(c); + } + #[cfg(feature = "dim3")] + JointParams::BallJoint(params) => { + let c = BallConstraint::new(b1, b2, params.local_anchor1, params.local_anchor2); + nphysics_joints.insert(c); + } + #[cfg(feature = "dim2")] + JointParams::BallJoint(params) => { + let c = + RevoluteConstraint::new(b1, b2, params.local_anchor1, params.local_anchor2); + nphysics_joints.insert(c); + } + #[cfg(feature = "dim3")] + JointParams::RevoluteJoint(params) => { + let c = RevoluteConstraint::new( + b1, + b2, + params.local_anchor1, + params.local_axis1, + params.local_anchor2, + params.local_axis2, + ); + nphysics_joints.insert(c); + } + JointParams::PrismaticJoint(params) => { + let mut c = PrismaticConstraint::new( + b1, + b2, + params.local_anchor1, + params.local_axis1(), + params.local_anchor2, + ); + + if params.limits_enabled { + c.enable_min_offset(params.limits[0]); + c.enable_max_offset(params.limits[1]); + } + + nphysics_joints.insert(c); + } + } + } + + Self { + rapier2nphysics, + mechanical_world, + geometrical_world, + bodies: nphysics_bodies, + colliders: nphysics_colliders, + joints: nphysics_joints, + force_generators, + } + } + + pub fn step(&mut self, counters: &mut Counters, params: &IntegrationParameters) { + self.mechanical_world + .integration_parameters + .max_position_iterations = params.max_position_iterations; + self.mechanical_world + .integration_parameters + .max_velocity_iterations = params.max_velocity_iterations; + self.mechanical_world + .integration_parameters + .set_dt(params.dt()); + + counters.step_started(); + self.mechanical_world.step( + &mut self.geometrical_world, + &mut self.bodies, + &mut self.colliders, + &mut self.joints, + &mut self.force_generators, + ); + counters.step_completed(); + } + + pub fn sync(&self, bodies: &mut RigidBodySet, colliders: &mut ColliderSet) { + for (rapier_handle, nphysics_handle) in self.rapier2nphysics.iter() { + let mut rb = bodies.get_mut(*rapier_handle).unwrap(); + let ra = self.bodies.rigid_body(*nphysics_handle).unwrap(); + let pos = *ra.position(); + rb.set_position(pos); + + for coll_handle in rb.colliders() { + let collider = &mut colliders[*coll_handle]; + collider.set_position_debug(pos * collider.delta()); + } + } + } +} + +fn nphysics_collider_from_rapier_collider( + collider: &Collider, + is_dynamic: bool, +) -> Option<ColliderDesc<f32>> { + let margin = ColliderDesc::<f32>::default_margin(); + let mut pos = Isometry::identity(); + + let shape = match collider.shape() { + Shape::Cuboid(cuboid) => { + ShapeHandle::new(Cuboid::new(cuboid.half_extents.map(|e| e - margin))) + } + Shape::Ball(ball) => ShapeHandle::new(Ball::new(ball.radius - margin)), + Shape::Capsule(capsule) => { + pos = capsule.transform_wrt_y(); + ShapeHandle::new(Capsule::new(capsule.half_height(), capsule.radius)) + } + Shape::HeightField(heightfield) => ShapeHandle::new(heightfield.clone()), + #[cfg(feature = "dim3")] + Shape::Trimesh(trimesh) => ShapeHandle::new(TriMesh::new( + trimesh.vertices().to_vec(), + trimesh + .indices() + .iter() + .map(|idx| na::convert(*idx)) + .collect(), + None, + )), + _ => return None, + }; + + let density = if is_dynamic { collider.density() } else { 0.0 }; + + Some( + ColliderDesc::new(shape) + .position(pos) + .density(density) + .sensor(collider.is_sensor()), + ) +} |
