Tesbted physx backend: add heightfield, trimesh, and convex mesh support.
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
use na::Point3;
|
use na::Point3;
|
||||||
|
use rand::distributions::{Distribution, Standard};
|
||||||
|
use rand::{rngs::StdRng, SeedableRng};
|
||||||
use rapier3d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet};
|
use rapier3d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet};
|
||||||
use rapier3d::geometry::{ColliderBuilder, ColliderSet};
|
use rapier3d::geometry::{ColliderBuilder, ColliderSet};
|
||||||
use rapier_testbed3d::Testbed;
|
use rapier_testbed3d::Testbed;
|
||||||
@@ -28,14 +30,19 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
* Create the cubes
|
* Create the cubes
|
||||||
*/
|
*/
|
||||||
let num = 8;
|
let num = 8;
|
||||||
|
let scale = 2.0;
|
||||||
let rad = 1.0;
|
let rad = 1.0;
|
||||||
|
let border_rad = 0.1;
|
||||||
|
|
||||||
let shift = rad * 2.0 + rad;
|
let shift = border_rad * 2.0 + scale;
|
||||||
let centerx = shift * (num / 2) as f32;
|
let centerx = shift * (num / 2) as f32;
|
||||||
let centery = shift / 2.0;
|
let centery = shift / 2.0;
|
||||||
let centerz = shift * (num / 2) as f32;
|
let centerz = shift * (num / 2) as f32;
|
||||||
|
|
||||||
let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5;
|
let mut offset = -(num as f32) * shift * 0.5;
|
||||||
|
|
||||||
|
let mut rng = StdRng::seed_from_u64(0);
|
||||||
|
let distribution = Standard;
|
||||||
|
|
||||||
for j in 0usize..47 {
|
for j in 0usize..47 {
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
@@ -44,11 +51,16 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
let y = j as f32 * shift + centery + 3.0;
|
let y = j as f32 * shift + centery + 3.0;
|
||||||
let z = k as f32 * shift - centerz + offset;
|
let z = k as f32 * shift - centerz + offset;
|
||||||
|
|
||||||
|
let mut points = Vec::new();
|
||||||
|
for _ in 0..10 {
|
||||||
|
let pt: Point3<f32> = distribution.sample(&mut rng);
|
||||||
|
points.push(pt * scale);
|
||||||
|
}
|
||||||
|
|
||||||
// Build the rigid body.
|
// Build the rigid body.
|
||||||
let rigid_body = RigidBodyBuilder::new_dynamic().translation(x, y, z).build();
|
let rigid_body = RigidBodyBuilder::new_dynamic().translation(x, y, z).build();
|
||||||
let handle = bodies.insert(rigid_body);
|
let handle = bodies.insert(rigid_body);
|
||||||
let cylinder = rapier3d::cdl::shape::Cylinder::new(rad, rad).to_trimesh(4);
|
let collider = ColliderBuilder::round_convex_hull(&points, border_rad)
|
||||||
let collider = ColliderBuilder::round_convex_hull(&cylinder.0, 0.1)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.build();
|
.build();
|
||||||
colliders.insert(collider, handle, &mut bodies);
|
colliders.insert(collider, handle, &mut bodies);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::objects::box_node::Box as BoxNode;
|
|||||||
use crate::objects::heightfield::HeightField;
|
use crate::objects::heightfield::HeightField;
|
||||||
use crate::objects::node::{GraphicsNode, Node};
|
use crate::objects::node::{GraphicsNode, Node};
|
||||||
use rapier::dynamics::{RigidBodyHandle, RigidBodySet};
|
use rapier::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||||
use rapier::geometry::{Collider, ColliderHandle, ColliderSet, Shape};
|
use rapier::geometry::{ColliderHandle, ColliderSet, Shape};
|
||||||
//use crate::objects::capsule::Capsule;
|
//use crate::objects::capsule::Capsule;
|
||||||
use crate::objects::convex::Convex;
|
use crate::objects::convex::Convex;
|
||||||
//#[cfg(feature = "dim3")]
|
//#[cfg(feature = "dim3")]
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::objects::node::{self, GraphicsNode};
|
|||||||
use kiss3d::window::Window;
|
use kiss3d::window::Window;
|
||||||
use na::{Isometry3, Point3};
|
use na::{Isometry3, Point3};
|
||||||
use rapier::geometry::{ColliderHandle, ColliderSet};
|
use rapier::geometry::{ColliderHandle, ColliderSet};
|
||||||
use rapier::math::Isometry;
|
|
||||||
|
|
||||||
pub struct Ball {
|
pub struct Ball {
|
||||||
color: Point3<f32>,
|
color: Point3<f32>,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::objects::node::{self, GraphicsNode};
|
|||||||
use kiss3d::window;
|
use kiss3d::window;
|
||||||
use na::{Isometry3, Point3};
|
use na::{Isometry3, Point3};
|
||||||
use rapier::geometry::{ColliderHandle, ColliderSet};
|
use rapier::geometry::{ColliderHandle, ColliderSet};
|
||||||
use rapier::math::{Isometry, Vector};
|
use rapier::math::Vector;
|
||||||
|
|
||||||
pub struct Box {
|
pub struct Box {
|
||||||
color: Point3<f32>,
|
color: Point3<f32>,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::objects::node::{self, GraphicsNode};
|
|||||||
use kiss3d::window;
|
use kiss3d::window;
|
||||||
use na::{Isometry3, Point3};
|
use na::{Isometry3, Point3};
|
||||||
use rapier::geometry::{self, ColliderHandle, ColliderSet};
|
use rapier::geometry::{self, ColliderHandle, ColliderSet};
|
||||||
use rapier::math::Isometry;
|
|
||||||
|
|
||||||
pub struct Capsule {
|
pub struct Capsule {
|
||||||
color: Point3<f32>,
|
color: Point3<f32>,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::objects::node::{self, GraphicsNode};
|
|||||||
use kiss3d::window::Window;
|
use kiss3d::window::Window;
|
||||||
use na::{Isometry3, Point3};
|
use na::{Isometry3, Point3};
|
||||||
use rapier::geometry::{ColliderHandle, ColliderSet};
|
use rapier::geometry::{ColliderHandle, ColliderSet};
|
||||||
use rapier::math::Isometry;
|
|
||||||
|
|
||||||
pub struct Cone {
|
pub struct Cone {
|
||||||
color: Point3<f32>,
|
color: Point3<f32>,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::objects::node::{self, GraphicsNode};
|
|||||||
use kiss3d::window::Window;
|
use kiss3d::window::Window;
|
||||||
use na::{Isometry3, Point3};
|
use na::{Isometry3, Point3};
|
||||||
use rapier::geometry::{ColliderHandle, ColliderSet};
|
use rapier::geometry::{ColliderHandle, ColliderSet};
|
||||||
use rapier::math::Isometry;
|
|
||||||
|
|
||||||
pub struct Cylinder {
|
pub struct Cylinder {
|
||||||
color: Point3<f32>,
|
color: Point3<f32>,
|
||||||
|
|||||||
@@ -4,13 +4,19 @@ use na::{
|
|||||||
Isometry3, Matrix3, Matrix4, Point3, Quaternion, Rotation3, Translation3, Unit, UnitQuaternion,
|
Isometry3, Matrix3, Matrix4, Point3, Quaternion, Rotation3, Translation3, Unit, UnitQuaternion,
|
||||||
Vector3,
|
Vector3,
|
||||||
};
|
};
|
||||||
use physx::cooking::PxCooking;
|
use physx::cooking::{
|
||||||
|
ConvexMeshCookingResult, PxConvexMeshDesc, PxCooking, PxCookingParams, PxHeightFieldDesc,
|
||||||
|
PxTriangleMeshDesc, TriangleMeshCookingResult,
|
||||||
|
};
|
||||||
use physx::foundation::DefaultAllocator;
|
use physx::foundation::DefaultAllocator;
|
||||||
use physx::prelude::*;
|
use physx::prelude::*;
|
||||||
use physx::scene::FrictionType;
|
use physx::scene::FrictionType;
|
||||||
use physx::traits::Class;
|
use physx::traits::Class;
|
||||||
use physx::triangle_mesh::TriangleMesh;
|
use physx::triangle_mesh::TriangleMesh;
|
||||||
use physx_sys::{PxActor, PxRigidActor};
|
use physx_sys::{
|
||||||
|
PxBitAndByte, PxConvexFlags, PxConvexMeshGeometryFlags, PxHeightFieldSample,
|
||||||
|
PxMeshGeometryFlags, PxMeshScale_new, PxRigidActor,
|
||||||
|
};
|
||||||
use rapier::counters::Counters;
|
use rapier::counters::Counters;
|
||||||
use rapier::dynamics::{
|
use rapier::dynamics::{
|
||||||
IntegrationParameters, JointParams, JointSet, RigidBodyHandle, RigidBodySet,
|
IntegrationParameters, JointParams, JointSet, RigidBodyHandle, RigidBodySet,
|
||||||
@@ -167,6 +173,10 @@ impl PhysxWorld {
|
|||||||
let mut scene: Owner<PxScene> = physics.create(scene_desc).unwrap();
|
let mut scene: Owner<PxScene> = physics.create(scene_desc).unwrap();
|
||||||
let mut rapier2dynamic = HashMap::new();
|
let mut rapier2dynamic = HashMap::new();
|
||||||
let mut rapier2static = 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");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@@ -174,9 +184,6 @@ impl PhysxWorld {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
for (rapier_handle, rb) in bodies.iter() {
|
for (rapier_handle, rb) in bodies.iter() {
|
||||||
use physx::rigid_dynamic::RigidDynamic;
|
|
||||||
use physx::rigid_static::RigidStatic;
|
|
||||||
|
|
||||||
let pos = rb.position().into_physx();
|
let pos = rb.position().into_physx();
|
||||||
if rb.is_dynamic() {
|
if rb.is_dynamic() {
|
||||||
let mut actor = physics.create_dynamic(&pos, rapier_handle).unwrap();
|
let mut actor = physics.create_dynamic(&pos, rapier_handle).unwrap();
|
||||||
@@ -199,7 +206,7 @@ impl PhysxWorld {
|
|||||||
*/
|
*/
|
||||||
for (_, collider) in colliders.iter() {
|
for (_, collider) in colliders.iter() {
|
||||||
if let Some((mut px_shape, px_material, collider_pos)) =
|
if let Some((mut px_shape, px_material, collider_pos)) =
|
||||||
physx_collider_from_rapier_collider(&mut *physics, &collider)
|
physx_collider_from_rapier_collider(&mut *physics, &mut cooking, &collider)
|
||||||
{
|
{
|
||||||
let parent_body = &bodies[collider.parent()];
|
let parent_body = &bodies[collider.parent()];
|
||||||
|
|
||||||
@@ -454,7 +461,7 @@ impl PhysxWorld {
|
|||||||
|
|
||||||
fn physx_collider_from_rapier_collider(
|
fn physx_collider_from_rapier_collider(
|
||||||
physics: &mut PxPhysicsFoundation,
|
physics: &mut PxPhysicsFoundation,
|
||||||
// cooking: &PxCooking,
|
cooking: &PxCooking,
|
||||||
collider: &Collider,
|
collider: &Collider,
|
||||||
) -> Option<(Owner<PxShape>, Owner<PxMaterial>, Isometry3<f32>)> {
|
) -> Option<(Owner<PxShape>, Owner<PxMaterial>, Isometry3<f32>)> {
|
||||||
let mut local_pose = *collider.position_wrt_parent();
|
let mut local_pose = *collider.position_wrt_parent();
|
||||||
@@ -498,26 +505,109 @@ fn physx_collider_from_rapier_collider(
|
|||||||
* rot.unwrap_or(UnitQuaternion::identity());
|
* rot.unwrap_or(UnitQuaternion::identity());
|
||||||
let geometry = PxCapsuleGeometry::new(capsule.radius, capsule.half_height());
|
let geometry = PxCapsuleGeometry::new(capsule.radius, capsule.half_height());
|
||||||
physics.create_shape(&geometry, materials, true, shape_flags, ())
|
physics.create_shape(&geometry, materials, true, shape_flags, ())
|
||||||
} else if let Some(trimesh) = shape.as_trimesh() {
|
} else if let Some(heightfield) = shape.as_heightfield() {
|
||||||
return None;
|
let heights = heightfield.heights();
|
||||||
/*
|
let scale = heightfield.scale();
|
||||||
ColliderDesc::TriMesh {
|
local_pose = local_pose * Translation3::new(-scale.x / 2.0, 0.0, -scale.z / 2.0);
|
||||||
vertices: trimesh
|
const Y_FACTOR: f32 = 1_000f32;
|
||||||
.vertices()
|
let mut heightfield_desc;
|
||||||
|
unsafe {
|
||||||
|
let samples: Vec<_> = heights
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| pt.into_physx())
|
.map(|h| PxHeightFieldSample {
|
||||||
.collect(),
|
height: (*h * Y_FACTOR) as i16,
|
||||||
indices: trimesh.flat_indices().to_vec(),
|
materialIndex0: PxBitAndByte { mData: 0 },
|
||||||
mesh_scale: Vector3::repeat(1.0).into_glam(),
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
let heightfield_desc = PxHeightFieldDesc {
|
||||||
|
obj: heightfield_desc,
|
||||||
};
|
};
|
||||||
let desc = cooking.create_triangle_mesh(physics, desc);
|
let heightfield = cooking.create_height_field(physics, &heightfield_desc);
|
||||||
if let TriangleMeshCookingResult::Success(trimesh) = desc {
|
|
||||||
Some(trimesh)
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
let mut mesh_desc;
|
||||||
|
unsafe {
|
||||||
|
mesh_desc = physx_sys::PxTriangleMeshDesc_new();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mesh_desc = PxTriangleMeshDesc { obj: mesh_desc };
|
||||||
|
let trimesh = cooking.create_triangle_mesh(physics, &mesh_desc);
|
||||||
|
|
||||||
|
if let TriangleMeshCookingResult::Success(mut trimesh) = trimesh {
|
||||||
|
let flags = PxMeshGeometryFlags {
|
||||||
|
mBits: physx_sys::PxMeshGeometryFlag::eDOUBLE_SIDED as u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
let scaling = unsafe { PxMeshScale_new() };
|
||||||
|
let geometry = PxTriangleMeshGeometry::new(&mut trimesh, &scaling, flags);
|
||||||
|
physics.create_shape(&geometry, materials, true, shape_flags, ())
|
||||||
} else {
|
} else {
|
||||||
eprintln!("PhysX triangle mesh construction failed.");
|
eprintln!("PhysX triangle mesh construction failed.");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Creating a shape unknown to the PhysX backend.");
|
eprintln!("Creating a shape unknown to the PhysX backend.");
|
||||||
return None;
|
return None;
|
||||||
|
|||||||
Reference in New Issue
Block a user