diff options
Diffstat (limited to 'src_testbed/physx_backend.rs')
| -rw-r--r-- | src_testbed/physx_backend.rs | 758 |
1 files changed, 405 insertions, 353 deletions
diff --git a/src_testbed/physx_backend.rs b/src_testbed/physx_backend.rs index 6ea207a..319736c 100644 --- a/src_testbed/physx_backend.rs +++ b/src_testbed/physx_backend.rs @@ -1,7 +1,21 @@ #![allow(dead_code)] -use na::{Isometry3, Matrix3, Matrix4, Point3, Rotation3, Translation3, UnitQuaternion, Vector3}; +use na::{ + Isometry3, Matrix3, Matrix4, Point3, Quaternion, Rotation3, Translation3, Unit, UnitQuaternion, + Vector3, +}; +use physx::cooking::{ + ConvexMeshCookingResult, PxConvexMeshDesc, PxCooking, PxCookingParams, PxHeightFieldDesc, + PxTriangleMeshDesc, TriangleMeshCookingResult, +}; +use physx::foundation::DefaultAllocator; use physx::prelude::*; +use physx::scene::FrictionType; +use physx::traits::Class; +use physx_sys::{ + PxBitAndByte, PxConvexFlags, PxConvexMeshGeometryFlags, PxHeightFieldSample, + PxMeshGeometryFlags, PxMeshScale_new, PxRigidActor, +}; use rapier::counters::Counters; use rapier::dynamics::{ IntegrationParameters, JointParams, JointSet, RigidBodyHandle, RigidBodySet, @@ -10,8 +24,6 @@ use rapier::geometry::{Collider, ColliderSet}; use rapier::utils::WBasis; use std::collections::HashMap; -const PX_PHYSICS_VERSION: u32 = physx::version(4, 1, 1); - trait IntoNa { type Output; fn into_na(self) -> Self::Output; @@ -24,37 +36,53 @@ impl IntoNa for glam::Mat4 { } } +impl IntoNa for PxVec3 { + type Output = Vector3<f32>; + fn into_na(self) -> Self::Output { + Vector3::new(self.x(), self.y(), self.z()) + } +} + +impl IntoNa for PxQuat { + type Output = Quaternion<f32>; + fn into_na(self) -> Self::Output { + Quaternion::new(self.w(), self.x(), self.y(), self.z()) + } +} + +impl IntoNa for PxTransform { + type Output = Isometry3<f32>; + fn into_na(self) -> Self::Output { + let tra = self.translation().into_na(); + let quat = self.rotation().into_na(); + let unit_quat = Unit::new_unchecked(quat); + Isometry3::from_parts(tra.into(), unit_quat) + } +} + trait IntoPhysx { type Output; fn into_physx(self) -> Self::Output; } impl IntoPhysx for Vector3<f32> { - type Output = physx_sys::PxVec3; + type Output = PxVec3; fn into_physx(self) -> Self::Output { - physx_sys::PxVec3 { - x: self.x, - y: self.y, - z: self.z, - } + PxVec3::new(self.x, self.y, self.z) } } impl IntoPhysx for Point3<f32> { - type Output = physx_sys::PxVec3; + type Output = PxVec3; fn into_physx(self) -> Self::Output { - physx_sys::PxVec3 { - x: self.x, - y: self.y, - z: self.z, - } + PxVec3::new(self.x, self.y, self.z) } } impl IntoPhysx for Isometry3<f32> { - type Output = physx_sys::PxTransform; + type Output = PxTransform; fn into_physx(self) -> Self::Output { - physx::transform::gl_to_px_tf(self.into_glam()) + self.into_glam().into() } } @@ -92,14 +120,23 @@ impl IntoGlam for Isometry3<f32> { } thread_local! { -pub static FOUNDATION: std::cell::RefCell<Foundation> = std::cell::RefCell::new(Foundation::new(PX_PHYSICS_VERSION)); +pub static FOUNDATION: std::cell::RefCell<PxPhysicsFoundation> = std::cell::RefCell::new(PhysicsFoundation::default()); } pub struct PhysxWorld { - physics: Physics, - cooking: Cooking, - scene: Scene, - rapier2physx: HashMap<RigidBodyHandle, BodyHandle>, + // physics: Physics, + // cooking: Cooking, + materials: Vec<Owner<PxMaterial>>, + shapes: Vec<Owner<PxShape>>, + scene: Option<Owner<PxScene>>, +} + +impl Drop for PhysxWorld { + fn drop(&mut self) { + let scene = self.scene.take(); + // FIXME: we get a segfault if we don't forget the scene. + std::mem::forget(scene); + } } impl PhysxWorld { @@ -112,123 +149,87 @@ impl PhysxWorld { use_two_friction_directions: bool, num_threads: usize, ) -> Self { - let mut rapier2physx = HashMap::new(); - let mut physics = FOUNDATION.with(|f| { - PhysicsBuilder::default() - .load_extensions(false) - .build(&mut *f.borrow_mut()) - }); - let mut cooking = FOUNDATION.with(|f| unsafe { - let sc = physx_sys::PxTolerancesScale_new(); - let params = physx_sys::PxCookingParams_new(&sc); - Cooking::new(PX_PHYSICS_VERSION, &mut *f.borrow_mut(), params) - }); - - let scene_desc = MySceneBuilder::default() - .set_gravity(gravity.into_glam()) - .set_simulation_threading(SimulationThreadType::Dedicated(num_threads as u32)) - // .set_broad_phase_type(BroadPhaseType::SweepAndPrune) - // .set_solver_type(physx_sys::PxSolverType::eTGS) - .build_desc(&mut physics); - - let raw_scene = - unsafe { physx_sys::PxPhysics_createScene_mut(physics.get_raw_mut(), &scene_desc) }; - - // FIXME: we do this because we are also using two - // friction directions. We should add to rapier the option to use - // one friction direction too, and perhaps an equivalent of physX - // ePATCH friction type. - if use_two_friction_directions { - unsafe { - physx_sys::PxScene_setFrictionType_mut( - raw_scene, - physx_sys::PxFrictionType::eTWO_DIRECTIONAL, - ); - } - } + FOUNDATION.with(|physics| { + let mut physics = physics.borrow_mut(); + let mut shapes = Vec::new(); + let mut materials = Vec::new(); - let mut scene = Scene::new(raw_scene); - - for (rapier_handle, rb) in bodies.iter() { - use physx::rigid_dynamic::RigidDynamic; - use physx::rigid_static::RigidStatic; - use physx::transform; + let friction_type = if use_two_friction_directions { + FrictionType::TwoDirectional + } else { + FrictionType::Patch + }; - let pos = transform::gl_to_px_tf(rb.position().to_homogeneous().into_glam()); - if rb.is_dynamic() { - let actor = unsafe { - physx_sys::PxPhysics_createRigidDynamic_mut(physics.get_raw_mut(), &pos) - }; + let scene_desc = SceneDescriptor { + gravity: gravity.into_physx(), + thread_count: num_threads as u32, + broad_phase_type: BroadPhaseType::AutomaticBoxPruning, + solver_type: SolverType::PGS, + friction_type, + ..SceneDescriptor::new(()) + }; - unsafe { - physx_sys::PxRigidDynamic_setSolverIterationCounts_mut( - actor, + let mut scene: Owner<PxScene> = physics.create(scene_desc).unwrap(); + let mut rapier2dynamic = HashMap::new(); + let mut rapier2static = HashMap::new(); + let cooking_params = + PxCookingParams::new(&*physics).expect("Failed to init PhysX cooking."); + let mut cooking = PxCooking::new(physics.foundation_mut(), &cooking_params) + .expect("Failed to init PhysX cooking"); + + /* + * + * Rigid bodies + * + */ + for (rapier_handle, rb) in bodies.iter() { + let pos = rb.position().into_physx(); + if rb.is_dynamic() { + let mut actor = physics.create_dynamic(&pos, rapier_handle).unwrap(); + actor.set_solver_iteration_counts( integration_parameters.max_position_iterations as u32, integration_parameters.max_velocity_iterations as u32, ); - } - let physx_handle = scene.add_dynamic(RigidDynamic::new(actor)); - rapier2physx.insert(rapier_handle, physx_handle); - } else { - let actor = unsafe { - physx_sys::PxPhysics_createRigidStatic_mut(physics.get_raw_mut(), &pos) - }; - - let physx_handle = scene.add_actor(RigidStatic::new(actor)); - rapier2physx.insert(rapier_handle, physx_handle); + rapier2dynamic.insert(rapier_handle, actor); + } else { + let actor = physics.create_static(pos, ()).unwrap(); + rapier2static.insert(rapier_handle, actor); + } } - } - for (_, collider) in colliders.iter() { - if let Some((px_collider, collider_pos)) = - physx_collider_from_rapier_collider(&collider) - { - let material = physics.create_material( - collider.friction, - collider.friction, - collider.restitution, - ); - let geometry = cooking.make_geometry(px_collider); - let flags = if collider.is_sensor() { - physx_sys::PxShapeFlags { - mBits: physx_sys::PxShapeFlag::eTRIGGER_SHAPE as u8, - } - } else { - physx_sys::PxShapeFlags { - mBits: physx_sys::PxShapeFlag::eSIMULATION_SHAPE as u8, // | physx_sys::PxShapeFlag::eSCENE_QUERY_SHAPE as u8, + /* + * + * Colliders + * + */ + for (_, collider) in colliders.iter() { + if let Some((mut px_shape, px_material, collider_pos)) = + physx_collider_from_rapier_collider(&mut *physics, &mut cooking, &collider) + { + let parent_body = &bodies[collider.parent()]; + + if !parent_body.is_dynamic() { + let actor = rapier2static.get_mut(&collider.parent()).unwrap(); + actor.attach_shape(&mut px_shape); + } else { + let actor = rapier2dynamic.get_mut(&collider.parent()).unwrap(); + actor.attach_shape(&mut px_shape); } - }; - let handle = rapier2physx[&collider.parent()]; - let parent_body = &bodies[collider.parent()]; - let parent = if !parent_body.is_dynamic() { - scene.get_static_mut(handle).unwrap().as_ptr_mut().ptr - as *mut physx_sys::PxRigidActor - } else { - scene.get_dynamic_mut(handle).unwrap().as_ptr_mut().ptr - as *mut physx_sys::PxRigidActor - }; + unsafe { + let pose = collider_pos.into_physx(); + physx_sys::PxShape_setLocalPose_mut(px_shape.as_mut_ptr(), &pose.into()); + } - unsafe { - let shape = physx_sys::PxPhysics_createShape_mut( - physics.get_raw_mut(), - geometry.as_raw(), - material, - true, - flags.into(), - ); - let pose = collider_pos.into_physx(); - physx_sys::PxShape_setLocalPose_mut(shape, &pose); - physx_sys::PxRigidActor_attachShape_mut(parent, shape); - }; + shapes.push(px_shape); + materials.push(px_material); + } } - } - // Update mass properties. - for (rapier_handle, physx_handle) in rapier2physx.iter() { - let rb = &bodies[*rapier_handle]; - if let Some(rp) = scene.get_dynamic_mut(*physx_handle) { + // Update mass properties. + for (rapier_handle, actor) in rapier2dynamic.iter_mut() { + let rb = &bodies[*rapier_handle]; let densities: Vec<_> = rb .colliders() .iter() @@ -237,7 +238,7 @@ impl PhysxWorld { unsafe { physx_sys::PxRigidBodyExt_updateMassAndInertia_mut( - rp.as_ptr_mut().ptr as *mut physx_sys::PxRigidBody, + std::mem::transmute(actor.as_mut()), densities.as_ptr(), densities.len() as u32, std::ptr::null(), @@ -245,39 +246,72 @@ impl PhysxWorld { ); } } - } - let mut res = Self { - physics, - cooking, - scene, - rapier2physx, - }; + /* + * + * Joints + * + */ + Self::setup_joints( + &mut physics, + joints, + &mut rapier2static, + &mut rapier2dynamic, + ); + + for (_, actor) in rapier2static { + scene.add_static_actor(actor); + } + + for (_, actor) in rapier2dynamic { + scene.add_dynamic_actor(actor); + } - res.setup_joints(joints); - res + Self { + scene: Some(scene), + shapes, + materials, + } + }) } - fn setup_joints(&mut self, joints: &JointSet) { + fn setup_joints( + physics: &mut PxPhysicsFoundation, + joints: &JointSet, + rapier2static: &mut HashMap<RigidBodyHandle, Owner<PxRigidStatic>>, + rapier2dynamic: &mut HashMap<RigidBodyHandle, Owner<PxRigidDynamic>>, + ) { unsafe { for joint in joints.iter() { - let actor1 = self.rapier2physx[&joint.1.body1]; - let actor2 = self.rapier2physx[&joint.1.body2]; + let actor1 = rapier2static + .get_mut(&joint.1.body1) + .map(|act| &mut **act as *mut PxRigidStatic as *mut PxRigidActor) + .or(rapier2dynamic + .get_mut(&joint.1.body1) + .map(|act| &mut **act as *mut PxRigidDynamic as *mut PxRigidActor)) + .unwrap(); + let actor2 = rapier2static + .get_mut(&joint.1.body2) + .map(|act| &mut **act as *mut PxRigidStatic as *mut PxRigidActor) + .or(rapier2dynamic + .get_mut(&joint.1.body2) + .map(|act| &mut **act as *mut PxRigidDynamic as *mut PxRigidActor)) + .unwrap(); match &joint.1.params { JointParams::BallJoint(params) => { - let frame1 = physx::transform::gl_to_px_tf( - Isometry3::new(params.local_anchor1.coords, na::zero()).into_glam(), - ); - let frame2 = physx::transform::gl_to_px_tf( - Isometry3::new(params.local_anchor2.coords, na::zero()).into_glam(), - ); + let frame1 = Isometry3::new(params.local_anchor1.coords, na::zero()) + .into_physx() + .into(); + let frame2 = Isometry3::new(params.local_anchor2.coords, na::zero()) + .into_physx() + .into(); physx_sys::phys_PxSphericalJointCreate( - self.physics.get_raw_mut(), - actor1.0 as *mut _, + physics.as_mut_ptr(), + actor1, &frame1 as *const _, - actor2.0 as *mut _, + actor2, &frame2 as *const _, ); } @@ -303,18 +337,18 @@ impl PhysxWorld { let axisangle1 = rotmat1.scaled_axis(); let axisangle2 = rotmat2.scaled_axis(); - let frame1 = physx::transform::gl_to_px_tf( - Isometry3::new(params.local_anchor1.coords, axisangle1).into_glam(), - ); - let frame2 = physx::transform::gl_to_px_tf( - Isometry3::new(params.local_anchor2.coords, axisangle2).into_glam(), - ); + let frame1 = Isometry3::new(params.local_anchor1.coords, axisangle1) + .into_physx() + .into(); + let frame2 = Isometry3::new(params.local_anchor2.coords, axisangle2) + .into_physx() + .into(); physx_sys::phys_PxRevoluteJointCreate( - self.physics.get_raw_mut(), - actor1.0 as *mut _, + physics.as_mut_ptr(), + actor1, &frame1 as *const _, - actor2.0 as *mut _, + actor2, &frame2 as *const _, ); } @@ -342,18 +376,18 @@ impl PhysxWorld { let axisangle1 = rotmat1.scaled_axis(); let axisangle2 = rotmat2.scaled_axis(); - let frame1 = physx::transform::gl_to_px_tf( - Isometry3::new(params.local_anchor1.coords, axisangle1).into_glam(), - ); - let frame2 = physx::transform::gl_to_px_tf( - Isometry3::new(params.local_anchor2.coords, axisangle2).into_glam(), - ); + let frame1 = Isometry3::new(params.local_anchor1.coords, axisangle1) + .into_physx() + .into(); + let frame2 = Isometry3::new(params.local_anchor2.coords, axisangle2) + .into_physx() + .into(); let joint = physx_sys::phys_PxPrismaticJointCreate( - self.physics.get_raw_mut(), - actor1.0 as *mut _, + physics.as_mut_ptr(), + actor1, &frame1 as *const _, - actor2.0 as *mut _, + actor2, &frame2 as *const _, ); @@ -376,16 +410,14 @@ impl PhysxWorld { } } JointParams::FixedJoint(params) => { - let frame1 = - physx::transform::gl_to_px_tf(params.local_anchor1.into_glam()); - let frame2 = - physx::transform::gl_to_px_tf(params.local_anchor2.into_glam()); + let frame1 = params.local_anchor1.into_physx().into(); + let frame2 = params.local_anchor2.into_physx().into(); physx_sys::phys_PxFixedJointCreate( - self.physics.get_raw_mut(), - actor1.0 as *mut _, + physics.as_mut_ptr(), + actor1, &frame1 as *const _, - actor2.0 as *mut _, + actor2, &frame2 as *const _, ); } @@ -395,43 +427,69 @@ impl PhysxWorld { } pub fn step(&mut self, counters: &mut Counters, params: &IntegrationParameters) { + let mut scratch = unsafe { ScratchBuffer::new(4) }; + counters.step_started(); - self.scene.step(params.dt, true); + self.scene + .as_mut() + .unwrap() + .step( + params.dt, + None::<&mut physx_sys::PxBaseTask>, + Some(&mut scratch), + true, + ) + .expect("error occurred during PhysX simulation"); counters.step_completed(); } - pub fn sync(&self, bodies: &mut RigidBodySet, colliders: &mut ColliderSet) { - for (rapier_handle, physx_handle) in self.rapier2physx.iter() { - let rb = bodies.get_mut(*rapier_handle).unwrap(); - let ra = self.scene.get_rigid_actor(*physx_handle).unwrap(); - let pos = ra.get_global_pose().into_na(); - let iso = na::convert_unchecked(pos); - rb.set_position(iso, false); - - if rb.is_kinematic() {} + pub fn sync(&mut self, bodies: &mut RigidBodySet, colliders: &mut ColliderSet) { + for actor in self.scene.as_mut().unwrap().get_dynamic_actors() { + let handle = actor.get_user_data(); + let pos = actor.get_global_pose().into_na(); + let rb = &mut bodies[*handle]; + rb.set_position(pos, false); for coll_handle in rb.colliders() { let collider = &mut colliders[*coll_handle]; - collider.set_position_debug(iso * collider.position_wrt_parent()); + collider.set_position_debug(pos * collider.position_wrt_parent()); } } } } fn physx_collider_from_rapier_collider( + physics: &mut PxPhysicsFoundation, + cooking: &PxCooking, collider: &Collider, -) -> Option<(ColliderDesc, Isometry3<f32>)> { +) -> Option<(Owner<PxShape>, Owner<PxMaterial>, Isometry3<f32>)> { let mut local_pose = *collider.position_wrt_parent(); let shape = collider.shape(); + let shape_flags = if collider.is_sensor() { + ShapeFlag::TriggerShape.into() + } else { + ShapeFlag::SimulationShape.into() + }; + let mut material = physics + .create_material( + collider.friction, + collider.friction, + collider.restitution, + (), + ) + .unwrap(); + let materials = &mut [material.as_mut()][..]; - let desc = if let Some(cuboid) = shape.as_cuboid() { - ColliderDesc::Box( + let shape = if let Some(cuboid) = shape.as_cuboid() { + let geometry = PxBoxGeometry::new( cuboid.half_extents.x, cuboid.half_extents.y, cuboid.half_extents.z, - ) + ); + physics.create_shape(&geometry, materials, true, shape_flags, ()) } else if let Some(ball) = shape.as_ball() { - ColliderDesc::Sphere(ball.radius) + let geometry = PxSphereGeometry::new(ball.radius); + physics.create_shape(&geometry, materials, true, shape_flags, ()) } else if let Some(capsule) = shape.as_capsule() { let center = capsule.center(); let mut dir = capsule.segment.b - capsule.segment.a; @@ -441,187 +499,181 @@ fn physx_collider_from_rapier_collider( } let rot = UnitQuaternion::rotation_between(&Vector3::x(), &dir); - local_pose *= Translation3::from(center.coords) * rot.unwrap_or(UnitQuaternion::identity()); - ColliderDesc::Capsule(capsule.radius, capsule.height()) - } else if let Some(trimesh) = shape.as_trimesh() { - ColliderDesc::TriMesh { - vertices: trimesh - .vertices() + local_pose = local_pose + * Translation3::from(center.coords) + * rot.unwrap_or(UnitQuaternion::identity()); + let geometry = PxCapsuleGeometry::new(capsule.radius, capsule.half_height()); + physics.create_shape(&geometry, materials, true, shape_flags, ()) + } else if let Some(heightfield) = shape.as_heightfield() { + let heights = heightfield.heights(); + let scale = heightfield.scale(); + local_pose = local_pose * Translation3::new(-scale.x / 2.0, 0.0, -scale.z / 2.0); + const Y_FACTOR: f32 = 1_000f32; + let mut heightfield_desc; + unsafe { + let samples: Vec<_> = heights .iter() - .map(|pt| pt.into_physx()) - .collect(), - indices: trimesh.flat_indices().to_vec(), - mesh_scale: Vector3::repeat(1.0).into_glam(), + .map(|h| PxHeightFieldSample { + height: (*h * Y_FACTOR) as i16, + materialIndex0: PxBitAndByte { mData: 0 }, + materialIndex1: PxBitAndByte { mData: 0 }, + }) + .collect(); + heightfield_desc = physx_sys::PxHeightFieldDesc_new(); + heightfield_desc.nbRows = heights.nrows() as u32; + heightfield_desc.nbColumns = heights.ncols() as u32; + heightfield_desc.samples.stride = std::mem::size_of::<PxHeightFieldSample>() as u32; + heightfield_desc.samples.data = samples.as_ptr() as *const std::ffi::c_void; } - } else { - eprintln!("Creating a shape unknown to the PhysX backend."); - return None; - }; - Some((desc, local_pose)) -} + let heightfield_desc = PxHeightFieldDesc { + obj: heightfield_desc, + }; + let heightfield = cooking.create_height_field(physics, &heightfield_desc); -/* - * - * XXX: All the remaining code is a duplicate from physx-rs to allow more customizations. - * - */ -use physx::scene::SimulationThreadType; - -pub struct MySceneBuilder { - gravity: glam::Vec3, - simulation_filter_shader: Option<physx_sys::SimulationFilterShader>, - simulation_threading: Option<SimulationThreadType>, - broad_phase_type: BroadPhaseType, - use_controller_manager: bool, - controller_manager_locking: bool, - call_default_filter_shader_first: bool, - use_ccd: bool, - enable_ccd_resweep: bool, - solver_type: u32, -} + if let Some(mut heightfield) = heightfield { + let flags = PxMeshGeometryFlags { + mBits: physx_sys::PxMeshGeometryFlag::eDOUBLE_SIDED as u8, + }; + let geometry = PxHeightFieldGeometry::new( + &mut *heightfield, + flags, + scale.y / Y_FACTOR, + scale.x / (heights.nrows() as f32 - 1.0), + scale.z / (heights.ncols() as f32 - 1.0), + ); + physics.create_shape(&geometry, materials, true, shape_flags, ()) + } else { + eprintln!("PhysX heightfield construction failed."); + return None; + } + } else if let Some(convex) = shape + .as_convex_polyhedron() + .or(shape.as_round_convex_polyhedron().map(|c| &c.base_shape)) + { + let vertices = convex.points(); + let mut convex_desc; + unsafe { + convex_desc = physx_sys::PxConvexMeshDesc_new(); + convex_desc.points.count = vertices.len() as u32; + convex_desc.points.stride = (3 * std::mem::size_of::<f32>()) as u32; + convex_desc.points.data = vertices.as_ptr() as *const std::ffi::c_void; + convex_desc.flags = PxConvexFlags { + mBits: physx_sys::PxConvexFlag::eCOMPUTE_CONVEX as u16, + }; + } -impl Default for MySceneBuilder { - fn default() -> Self { - Self { - gravity: glam::Vec3::new(0.0, -9.80665, 0.0), // standard gravity value - call_default_filter_shader_first: true, - simulation_filter_shader: None, - simulation_threading: None, - broad_phase_type: BroadPhaseType::SweepAndPrune, - use_controller_manager: false, - controller_manager_locking: false, - use_ccd: false, - enable_ccd_resweep: false, - solver_type: physx_sys::PxSolverType::ePGS, + let convex_desc = PxConvexMeshDesc { obj: convex_desc }; + let convex = cooking.create_convex_mesh(physics, &convex_desc); + + if let ConvexMeshCookingResult::Success(mut convex) = convex { + let flags = PxConvexMeshGeometryFlags { mBits: 0 }; + let scaling = unsafe { PxMeshScale_new() }; + let geometry = PxConvexMeshGeometry::new(&mut convex, &scaling, flags); + physics.create_shape(&geometry, materials, true, shape_flags, ()) + } else { + eprintln!("PhysX convex mesh construction failed."); + return None; } - } -} + } else if let Some(trimesh) = shape.as_trimesh() { + let vertices = trimesh.vertices(); + let indices = trimesh.flat_indices(); -impl MySceneBuilder { - /// Set the gravity for the scene. - /// - /// Default: [0.0, -9.80665, 0.0] (standard gravity) - pub fn set_gravity(&mut self, gravity: glam::Vec3) -> &mut Self { - self.gravity = gravity; - self - } + let mut mesh_desc; + unsafe { + mesh_desc = physx_sys::PxTriangleMeshDesc_new(); - /// Set a callback to be invoked on various simulation events. Note: - /// Currently only handles collision events - /// - /// Default: not set - pub fn set_simulation_filter_shader( - &mut self, - simulation_filter_shader: physx_sys::SimulationFilterShader, - ) -> &mut Self { - self.simulation_filter_shader = Some(simulation_filter_shader); - self - } + mesh_desc.points.count = trimesh.vertices().len() as u32; + mesh_desc.points.stride = (3 * std::mem::size_of::<f32>()) as u32; + mesh_desc.points.data = vertices.as_ptr() as *const std::ffi::c_void; - /// Enable the controller manager on the scene. - /// - /// Default: false, false - pub fn use_controller_manager( - &mut self, - use_controller_manager: bool, - locking_enabled: bool, - ) -> &mut Self { - self.use_controller_manager = use_controller_manager; - self.controller_manager_locking = locking_enabled; - self - } + mesh_desc.triangles.count = (indices.len() as u32) / 3; + mesh_desc.triangles.stride = (3 * std::mem::size_of::<u32>()) as u32; + mesh_desc.triangles.data = indices.as_ptr() as *const std::ffi::c_void; + } - pub fn set_solver_type(&mut self, solver_type: u32) -> &mut Self { - self.solver_type = solver_type; - self - } + let mesh_desc = PxTriangleMeshDesc { obj: mesh_desc }; + let trimesh = cooking.create_triangle_mesh(physics, &mesh_desc); - /// Sets whether the filter should begin by calling the default filter shader - /// PxDefaultSimulationFilterShader that emulates the PhysX 2.8 rules. - /// - /// Default: true - pub fn set_call_default_filter_shader_first( - &mut self, - call_default_filter_shader_first: bool, - ) -> &mut Self { - self.call_default_filter_shader_first = call_default_filter_shader_first; - self - } + if let TriangleMeshCookingResult::Success(mut trimesh) = trimesh { + let flags = PxMeshGeometryFlags { + mBits: physx_sys::PxMeshGeometryFlag::eDOUBLE_SIDED as u8, + }; - /// Set the number of threads to use for simulation - /// - /// Default: not set - pub fn set_simulation_threading( - &mut self, - simulation_threading: SimulationThreadType, - ) -> &mut Self { - self.simulation_threading = Some(simulation_threading); - self - } + let scaling = unsafe { PxMeshScale_new() }; + let geometry = PxTriangleMeshGeometry::new(&mut trimesh, &scaling, flags); + physics.create_shape(&geometry, materials, true, shape_flags, ()) + } else { + eprintln!("PhysX triangle mesh construction failed."); + return None; + } + } else { + eprintln!("Creating a shape unknown to the PhysX backend."); + return None; + }; - /// Set collision detection type - /// - /// Default: Sweep and prune - pub fn set_broad_phase_type(&mut self, broad_phase_type: BroadPhaseType) -> &mut Self { - self.broad_phase_type = broad_phase_type; - self - } + shape.map(|s| (s, material, local_pose)) +} - /// Set if CCD (continuous collision detection) should be available for use in the scene. - /// Doesn't automatically enable it for all rigid bodies, they still need to be flagged. - /// - /// If you don't set enable_ccd_resweep to true, eDISABLE_CCD_RESWEEP is set, which improves performance - /// at the cost of accuracy right after bounces. - /// - /// Default: false, false - pub fn set_use_ccd(&mut self, use_ccd: bool, enable_ccd_resweep: bool) -> &mut Self { - self.use_ccd = use_ccd; - self.enable_ccd_resweep = enable_ccd_resweep; - self +type PxPhysicsFoundation = PhysicsFoundation<DefaultAllocator, PxShape>; +type PxMaterial = physx::material::PxMaterial<()>; +type PxShape = physx::shape::PxShape<(), PxMaterial>; +type PxArticulationLink = physx::articulation_link::PxArticulationLink<(), PxShape>; +type PxRigidStatic = physx::rigid_static::PxRigidStatic<(), PxShape>; +type PxRigidDynamic = physx::rigid_dynamic::PxRigidDynamic<RigidBodyHandle, PxShape>; +type PxArticulation = physx::articulation::PxArticulation<(), PxArticulationLink>; +type PxArticulationReducedCoordinate = + physx::articulation_reduced_coordinate::PxArticulationReducedCoordinate<(), PxArticulationLink>; +type PxScene = physx::scene::PxScene< + (), + PxArticulationLink, + PxRigidStatic, + PxRigidDynamic, + PxArticulation, + PxArticulationReducedCoordinate, + OnCollision, + OnTrigger, + OnConstraintBreak, + OnWakeSleep, + OnAdvance, +>; + +/// Next up, the simulation event callbacks need to be defined, and possibly an +/// allocator callback as well. +struct OnCollision; +impl CollisionCallback for OnCollision { + fn on_collision( + &mut self, + _header: &physx_sys::PxContactPairHeader, + _pairs: &[physx_sys::PxContactPair], + ) { } +} +struct OnTrigger; +impl TriggerCallback for OnTrigger { + fn on_trigger(&mut self, _pairs: &[physx_sys::PxTriggerPair]) {} +} - pub(super) fn build_desc(&self, physics: &mut Physics) -> physx_sys::PxSceneDesc { - unsafe { - let tolerances = physics.get_tolerances_scale(); - let mut scene_desc = physx_sys::PxSceneDesc_new(tolerances); - - let dispatcher = match self.simulation_threading.as_ref().expect("foo") { - SimulationThreadType::Default => { - physx_sys::phys_PxDefaultCpuDispatcherCreate(1, std::ptr::null_mut()) as *mut _ - } - SimulationThreadType::Dedicated(count) => { - physx_sys::phys_PxDefaultCpuDispatcherCreate(*count, std::ptr::null_mut()) - as *mut _ - } - SimulationThreadType::Shared(dispatcher) => *dispatcher as *mut _, - }; - - scene_desc.cpuDispatcher = dispatcher; - scene_desc.gravity = physx::transform::gl_to_px_v3(self.gravity); - if self.use_ccd { - scene_desc.flags.mBits |= physx_sys::PxSceneFlag::eENABLE_CCD; - if !self.enable_ccd_resweep { - scene_desc.flags.mBits |= physx_sys::PxSceneFlag::eDISABLE_CCD_RESWEEP; - } - } - if let Some(filter_shader) = self.simulation_filter_shader { - physx_sys::enable_custom_filter_shader( - &mut scene_desc as *mut physx_sys::PxSceneDesc, - filter_shader, - if self.call_default_filter_shader_first { - 1 - } else { - 0 - }, - ); - } else { - scene_desc.filterShader = physx_sys::get_default_simulation_filter_shader(); - } +struct OnConstraintBreak; +impl ConstraintBreakCallback for OnConstraintBreak { + fn on_constraint_break(&mut self, _constraints: &[physx_sys::PxConstraintInfo]) {} +} +struct OnWakeSleep; +impl WakeSleepCallback<PxArticulationLink, PxRigidStatic, PxRigidDynamic> for OnWakeSleep { + fn on_wake_sleep( + &mut self, + _actors: &[&physx::actor::ActorMap<PxArticulationLink, PxRigidStatic, PxRigidDynamic>], + _is_waking: bool, + ) { + } +} - scene_desc.broadPhaseType = self.broad_phase_type.into(); - scene_desc.solverType = self.solver_type; - scene_desc - } +struct OnAdvance; +impl AdvanceCallback<PxArticulationLink, PxRigidDynamic> for OnAdvance { + fn on_advance( + &self, + _actors: &[&physx::rigid_body::RigidBodyMap<PxArticulationLink, PxRigidDynamic>], + _transforms: &[PxTransform], + ) { } } |
