Update to Parry 0.18 (#770)

* update to parry ~main

* use traverse_depth_first

* add example to test intersection

* rely on upstream PR rather than local

* re-enable profiler_ui for examples

* rely on official parry repository

* chore: switch back to the published version of parry

* chore: update changelog

* chore: remove dead code

* fix compilation of rapier3d-meshloader and rapier3d-urdf

* chore: cargo fmt

---------

Co-authored-by: Sébastien Crozet <sebcrozet@dimforge.com>
This commit is contained in:
Thierry Berger
2025-01-08 17:16:34 +01:00
committed by GitHub
parent cf77b5bf57
commit dc4bd24da8
26 changed files with 129 additions and 45 deletions

View File

@@ -19,6 +19,7 @@
- `InteractionGroups` default value for `memberships` is now `GROUP_1` (#706) - `InteractionGroups` default value for `memberships` is now `GROUP_1` (#706)
- `ImpulseJointSet::get_mut` has a new parameter `wake_up: bool`, to wake up connected bodies. - `ImpulseJointSet::get_mut` has a new parameter `wake_up: bool`, to wake up connected bodies.
- Removed unmaintained `instant` in favor of `web-time`. This effectively removes the `wasm-bindgen` transitive dependency as it's no longer needed. - Removed unmaintained `instant` in favor of `web-time`. This effectively removes the `wasm-bindgen` transitive dependency as it's no longer needed.
- Significantly improve performances of `QueryPipeline::intersection_with_shape`.
## v0.22.0 (20 July 2024) ## v0.22.0 (20 July 2024)

View File

@@ -38,7 +38,7 @@ pub fn init_world(testbed: &mut Testbed) {
let rigid_body = RigidBodyBuilder::fixed(); let rigid_body = RigidBodyBuilder::fixed();
let handle = bodies.insert(rigid_body); let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::trimesh(vertices, indices); let collider = ColliderBuilder::trimesh(vertices, indices).unwrap();
colliders.insert_with_parent(collider, handle, &mut bodies); colliders.insert_with_parent(collider, handle, &mut bodies);
/* /*

View File

@@ -68,7 +68,7 @@ vec_map = { version = "0.8", optional = true }
web-time = { version = "1.1", optional = true } web-time = { version = "1.1", optional = true }
num-traits = "0.2" num-traits = "0.2"
nalgebra = "0.33" nalgebra = "0.33"
parry2d-f64 = "0.17.0" parry2d-f64 = "0.18.0"
simba = "0.9" simba = "0.9"
approx = "0.5" approx = "0.5"
rayon = { version = "1", optional = true } rayon = { version = "1", optional = true }

View File

@@ -68,7 +68,7 @@ vec_map = { version = "0.8", optional = true }
web-time = { version = "1.1", optional = true } web-time = { version = "1.1", optional = true }
num-traits = "0.2" num-traits = "0.2"
nalgebra = "0.33" nalgebra = "0.33"
parry2d = "0.17.0" parry2d = "0.18.0"
simba = "0.9" simba = "0.9"
approx = "0.5" approx = "0.5"
rayon = { version = "1", optional = true } rayon = { version = "1", optional = true }

View File

@@ -71,7 +71,7 @@ vec_map = { version = "0.8", optional = true }
web-time = { version = "1.1", optional = true } web-time = { version = "1.1", optional = true }
num-traits = "0.2" num-traits = "0.2"
nalgebra = "0.33" nalgebra = "0.33"
parry3d-f64 = "0.17.0" parry3d-f64 = "0.18.0"
simba = "0.9" simba = "0.9"
approx = "0.5" approx = "0.5"
rayon = { version = "1", optional = true } rayon = { version = "1", optional = true }

View File

@@ -27,6 +27,6 @@ wavefront = ["mesh-loader/obj"]
[dependencies] [dependencies]
thiserror = "1.0.61" thiserror = "1.0.61"
profiling = "1.0" profiling = "1.0"
mesh-loader = { version = "0.1.12", optional = true } mesh-loader = "0.1.12"
rapier3d = { version = "0.22", path = "../rapier3d" } rapier3d = { version = "0.22", path = "../rapier3d" }

View File

@@ -19,9 +19,11 @@ license = "Apache-2.0"
edition = "2021" edition = "2021"
[features] [features]
stl = ["dep:rapier3d-meshloader", "rapier3d-meshloader/stl"] stl = ["dep:rapier3d-meshloader", "rapier3d-meshloader/stl", "__meshloader_is_enabled"]
collada = ["dep:rapier3d-meshloader", "rapier3d-meshloader/collada"] collada = ["dep:rapier3d-meshloader", "rapier3d-meshloader/collada", "__meshloader_is_enabled"]
wavefront = ["dep:rapier3d-meshloader", "rapier3d-meshloader/wavefront"] wavefront = ["dep:rapier3d-meshloader", "rapier3d-meshloader/wavefront", "__meshloader_is_enabled"]
## Private feature for detecting when meshloader is enabled by any of the file type features above.
__meshloader_is_enabled = []
[dependencies] [dependencies]
log = "0.4" log = "0.4"

View File

@@ -37,7 +37,6 @@ use rapier3d::{
geometry::{Collider, ColliderBuilder, ColliderHandle, ColliderSet, SharedShape, TriMeshFlags}, geometry::{Collider, ColliderBuilder, ColliderHandle, ColliderSet, SharedShape, TriMeshFlags},
math::{Isometry, Point, Real, Vector}, math::{Isometry, Point, Real, Vector},
na, na,
prelude::MeshConverter,
}; };
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path; use std::path::Path;
@@ -462,7 +461,7 @@ fn urdf_to_rigid_body(options: &UrdfLoaderOptions, inertial: &Inertial) -> Rigid
fn urdf_to_colliders( fn urdf_to_colliders(
options: &UrdfLoaderOptions, options: &UrdfLoaderOptions,
mesh_dir: &Path, _mesh_dir: &Path, // Unused if none of the meshloader features is enabled.
geometry: &Geometry, geometry: &Geometry,
origin: &Pose, origin: &Pose,
) -> Vec<Collider> { ) -> Vec<Collider> {
@@ -496,14 +495,20 @@ fn urdf_to_colliders(
Geometry::Sphere { radius } => { Geometry::Sphere { radius } => {
colliders.push(SharedShape::ball(*radius as Real)); colliders.push(SharedShape::ball(*radius as Real));
} }
#[cfg(not(feature = "__meshloader_is_enabled"))]
Geometry::Mesh { .. } => {
log::error!("Mesh loading is disabled by default. Enable one of the format features (`stl`, `collada`, `wavefront`) of `rapier3d-urdf` for mesh support.");
}
#[cfg(feature = "__meshloader_is_enabled")]
Geometry::Mesh { filename, scale } => { Geometry::Mesh { filename, scale } => {
let full_path = mesh_dir.join(filename); let full_path = _mesh_dir.join(filename);
let scale = scale let scale = scale
.map(|s| Vector::new(s[0] as Real, s[1] as Real, s[2] as Real)) .map(|s| Vector::new(s[0] as Real, s[1] as Real, s[2] as Real))
.unwrap_or_else(|| Vector::<Real>::repeat(1.0)); .unwrap_or_else(|| Vector::<Real>::repeat(1.0));
let Ok(loaded_mesh) = rapier3d_meshloader::load_from_path( let Ok(loaded_mesh) = rapier3d_meshloader::load_from_path(
full_path, full_path,
&MeshConverter::TriMeshWithFlags(options.trimesh_flags), &rapier3d::prelude::MeshConverter::TriMeshWithFlags(options.trimesh_flags),
scale, scale,
) else { ) else {
return Vec::new(); return Vec::new();

View File

@@ -71,7 +71,7 @@ vec_map = { version = "0.8", optional = true }
web-time = { version = "1.1", optional = true } web-time = { version = "1.1", optional = true }
num-traits = "0.2" num-traits = "0.2"
nalgebra = "0.33" nalgebra = "0.33"
parry3d = "0.17.0" parry3d = "0.18.0"
simba = "0.9" simba = "0.9"
approx = "0.5" approx = "0.5"
rayon = { version = "1", optional = true } rayon = { version = "1", optional = true }

View File

@@ -34,12 +34,12 @@ default = ["dim2"]
dim2 = [] dim2 = []
parallel = ["rapier/parallel", "num_cpus"] parallel = ["rapier/parallel", "num_cpus"]
other-backends = ["wrapped2d"] other-backends = ["wrapped2d"]
profiling = ["dep:puffin_egui", "profiling/profile-with-puffin"] profiler_ui = ["dep:puffin_egui", "profiling/profile-with-puffin"]
# See https://github.com/dimforge/rapier/issues/760. # See https://github.com/dimforge/rapier/issues/760.
unstable-puffin-pr-235 = [] unstable-puffin-pr-235 = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["parallel", "profiling"] features = ["parallel", "profiler_ui"]
[lints.clippy] [lints.clippy]
needless_lifetimes = "allow" needless_lifetimes = "allow"

View File

@@ -34,12 +34,12 @@ default = ["dim2"]
dim2 = [] dim2 = []
parallel = ["rapier/parallel", "num_cpus"] parallel = ["rapier/parallel", "num_cpus"]
other-backends = ["wrapped2d"] other-backends = ["wrapped2d"]
profiling = ["dep:puffin_egui", "profiling/profile-with-puffin"] profiler_ui = ["dep:puffin_egui", "profiling/profile-with-puffin"]
# See https://github.com/dimforge/rapier/issues/760. # See https://github.com/dimforge/rapier/issues/760.
unstable-puffin-pr-235 = [] unstable-puffin-pr-235 = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["parallel", "other-backends", "profiling"] features = ["parallel", "other-backends", "profiler_ui"]
[lints.clippy] [lints.clippy]
needless_lifetimes = "allow" needless_lifetimes = "allow"

View File

@@ -36,12 +36,12 @@ rust.unexpected_cfgs = { level = "warn", check-cfg = [
default = ["dim3"] default = ["dim3"]
dim3 = [] dim3 = []
parallel = ["rapier/parallel", "num_cpus"] parallel = ["rapier/parallel", "num_cpus"]
profiling = ["dep:puffin_egui", "profiling/profile-with-puffin"] profiler_ui = ["dep:puffin_egui", "profiling/profile-with-puffin"]
# See https://github.com/dimforge/rapier/issues/760. # See https://github.com/dimforge/rapier/issues/760.
unstable-puffin-pr-235 = [] unstable-puffin-pr-235 = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["parallel", "profiling"] features = ["parallel", "profiler_ui"]
[lints.clippy] [lints.clippy]
needless_lifetimes = "allow" needless_lifetimes = "allow"

View File

@@ -34,12 +34,12 @@ default = ["dim3"]
dim3 = [] dim3 = []
parallel = ["rapier/parallel", "num_cpus"] parallel = ["rapier/parallel", "num_cpus"]
other-backends = ["physx", "physx-sys", "glam"] other-backends = ["physx", "physx-sys", "glam"]
profiling = ["dep:puffin_egui", "profiling/profile-with-puffin"] profiler_ui = ["dep:puffin_egui", "profiling/profile-with-puffin"]
# See https://github.com/dimforge/rapier/issues/760. # See https://github.com/dimforge/rapier/issues/760.
unstable-puffin-pr-235 = [] unstable-puffin-pr-235 = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["parallel", "other-backends", "profiling"] features = ["parallel", "other-backends", "profiler_ui"]
[lints.clippy] [lints.clippy]
needless_lifetimes = "allow" needless_lifetimes = "allow"

View File

@@ -20,7 +20,7 @@ usvg = "0.14"
[dependencies.rapier_testbed2d] [dependencies.rapier_testbed2d]
path = "../crates/rapier_testbed2d" path = "../crates/rapier_testbed2d"
features = ["profiling"] features = ["profiler_ui"]
[dependencies.rapier2d] [dependencies.rapier2d]
path = "../crates/rapier2d" path = "../crates/rapier2d"

View File

@@ -16,6 +16,7 @@ mod convex_polygons2;
mod damping2; mod damping2;
mod debug_box_ball2; mod debug_box_ball2;
mod debug_compression2; mod debug_compression2;
mod debug_intersection2;
mod debug_total_overlap2; mod debug_total_overlap2;
mod debug_vertical_column2; mod debug_vertical_column2;
mod drum2; mod drum2;
@@ -99,6 +100,7 @@ pub fn main() {
("Joint motor position", joint_motor_position2::init_world), ("Joint motor position", joint_motor_position2::init_world),
("(Debug) box ball", debug_box_ball2::init_world), ("(Debug) box ball", debug_box_ball2::init_world),
("(Debug) compression", debug_compression2::init_world), ("(Debug) compression", debug_compression2::init_world),
("(Debug) intersection", debug_intersection2::init_world),
("(Debug) total overlap", debug_total_overlap2::init_world), ("(Debug) total overlap", debug_total_overlap2::init_world),
( (
"(Debug) vertical column", "(Debug) vertical column",

View File

@@ -0,0 +1,64 @@
use rapier2d::prelude::*;
use rapier_testbed2d::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();
let rad = 1.0;
let collider = ColliderBuilder::ball(rad);
let count = 100;
for x in 0..count {
for y in 0..count {
let rigid_body = RigidBodyBuilder::fixed().translation(vector![
(x as f32 - count as f32 / 2.0) * rad * 3.0,
(y as f32 - count as f32 / 2.0) * rad * 3.0
]);
let handle = bodies.insert(rigid_body);
colliders.insert_with_parent(collider.clone(), handle, &mut bodies);
testbed.set_initial_body_color(
handle,
[
x as f32 / count as f32,
(count - y) as f32 / count as f32,
0.5,
],
);
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(point![0.0, 0.0], 50.0);
testbed.add_callback(move |graphics, physics, _, run| {
let slow_time = run.timestep_id as f32 / 3.0;
let intersection = physics.query_pipeline.intersection_with_shape(
&physics.bodies,
&physics.colliders,
&Isometry::translation(slow_time.cos() * 10.0, slow_time.sin() * 10.0),
&Ball::new(rad / 2.0),
QueryFilter::default(),
);
if let Some(graphics) = graphics {
for (handle, _) in physics.bodies.iter() {
graphics.set_body_color(handle, [0.5, 0.5, 0.5]);
}
if let Some(intersection) = intersection {
let collider = physics.colliders.get(intersection).unwrap();
let body_handle = collider.parent().unwrap();
graphics.set_body_color(body_handle, [1.0, 0.0, 0.0]);
}
}
});
}

View File

@@ -85,6 +85,7 @@ pub fn init_world(testbed: &mut Testbed) {
for k in 0..5 { for k in 0..5 {
let collider = ColliderBuilder::trimesh(vertices.clone(), indices.clone()) let collider = ColliderBuilder::trimesh(vertices.clone(), indices.clone())
.unwrap()
.contact_skin(0.2); .contact_skin(0.2);
let rigid_body = RigidBodyBuilder::dynamic() let rigid_body = RigidBodyBuilder::dynamic()
.translation(vector![ith as f32 * 8.0 - 20.0, 20.0 + k as f32 * 11.0]) .translation(vector![ith as f32 * 8.0 - 20.0, 20.0 + k as f32 * 11.0])

View File

@@ -23,7 +23,7 @@ bincode = "1"
[dependencies.rapier_testbed3d] [dependencies.rapier_testbed3d]
path = "../crates/rapier_testbed3d" path = "../crates/rapier_testbed3d"
features = ["profiling"] features = ["profiler_ui"]
[dependencies.rapier3d] [dependencies.rapier3d]
path = "../crates/rapier3d" path = "../crates/rapier3d"

View File

@@ -48,7 +48,7 @@ pub fn init_world(testbed: &mut Testbed) {
let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, 0.0, 0.0]); let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, 0.0, 0.0]);
let handle = bodies.insert(rigid_body); let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::trimesh(vtx, idx); let collider = ColliderBuilder::trimesh(vtx, idx).expect("Could not create trimesh collider.");
colliders.insert_with_parent(collider, handle, &mut bodies); colliders.insert_with_parent(collider, handle, &mut bodies);
testbed.set_initial_body_color(handle, [0.3, 0.3, 0.3]); testbed.set_initial_body_color(handle, [0.3, 0.3, 0.3]);

View File

@@ -93,6 +93,7 @@ pub fn do_init_world(testbed: &mut Testbed, use_convex_decomposition: bool) {
} else { } else {
// SharedShape::trimesh(vertices, indices) // SharedShape::trimesh(vertices, indices)
SharedShape::trimesh_with_flags(vertices, indices, TriMeshFlags::FIX_INTERNAL_EDGES) SharedShape::trimesh_with_flags(vertices, indices, TriMeshFlags::FIX_INTERNAL_EDGES)
.unwrap()
}; };
shapes.push(decomposed_shape); shapes.push(decomposed_shape);

View File

@@ -42,7 +42,8 @@ pub fn init_world(testbed: &mut Testbed) {
vertices, vertices,
indices, indices,
TriMeshFlags::MERGE_DUPLICATE_VERTICES, TriMeshFlags::MERGE_DUPLICATE_VERTICES,
); )
.unwrap();
colliders.insert_with_parent(collider, handle, &mut bodies); colliders.insert_with_parent(collider, handle, &mut bodies);
/* /*

View File

@@ -10,7 +10,7 @@ use crate::pipeline::{ActiveEvents, ActiveHooks};
use crate::prelude::ColliderEnabled; use crate::prelude::ColliderEnabled;
use na::Unit; use na::Unit;
use parry::bounding_volume::{Aabb, BoundingVolume}; use parry::bounding_volume::{Aabb, BoundingVolume};
use parry::shape::{Shape, TriMeshFlags}; use parry::shape::{Shape, TriMeshBuilderError, TriMeshFlags};
#[cfg(feature = "dim3")] #[cfg(feature = "dim3")]
use crate::geometry::HeightFieldFlags; use crate::geometry::HeightFieldFlags;
@@ -685,8 +685,11 @@ impl ColliderBuilder {
} }
/// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers. /// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers.
pub fn trimesh(vertices: Vec<Point<Real>>, indices: Vec<[u32; 3]>) -> Self { pub fn trimesh(
Self::new(SharedShape::trimesh(vertices, indices)) vertices: Vec<Point<Real>>,
indices: Vec<[u32; 3]>,
) -> Result<Self, TriMeshBuilderError> {
Ok(Self::new(SharedShape::trimesh(vertices, indices)?))
} }
/// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers and /// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers and
@@ -695,8 +698,10 @@ impl ColliderBuilder {
vertices: Vec<Point<Real>>, vertices: Vec<Point<Real>>,
indices: Vec<[u32; 3]>, indices: Vec<[u32; 3]>,
flags: TriMeshFlags, flags: TriMeshFlags,
) -> Self { ) -> Result<Self, TriMeshBuilderError> {
Self::new(SharedShape::trimesh_with_flags(vertices, indices, flags)) Ok(Self::new(SharedShape::trimesh_with_flags(
vertices, indices, flags,
)?))
} }
/// Initializes a collider builder with a shape converted from the given triangle mesh index /// Initializes a collider builder with a shape converted from the given triangle mesh index

View File

@@ -1,6 +1,6 @@
use parry::bounding_volume; use parry::bounding_volume;
use parry::math::{Isometry, Point, Real}; use parry::math::{Isometry, Point, Real};
use parry::shape::{Cuboid, SharedShape, TriMeshFlags}; use parry::shape::{Cuboid, SharedShape, TriMeshBuilderError, TriMeshFlags};
#[cfg(feature = "dim3")] #[cfg(feature = "dim3")]
use parry::transformation::vhacd::VHACDParameters; use parry::transformation::vhacd::VHACDParameters;
@@ -17,6 +17,9 @@ pub enum MeshConverterError {
/// The convex hull calculation carried out by the [`MeshConverter::ConvexHull`] failed. /// The convex hull calculation carried out by the [`MeshConverter::ConvexHull`] failed.
#[error("convex-hull computation failed")] #[error("convex-hull computation failed")]
ConvexHullFailed, ConvexHullFailed,
/// The TriMesh building failed.
#[error("TriMesh building failed")]
TriMeshBuilderError(TriMeshBuilderError),
} }
/// Determines how meshes (generally when loaded from a file) are converted into Rapier colliders. /// Determines how meshes (generally when loaded from a file) are converted into Rapier colliders.
@@ -61,9 +64,11 @@ impl MeshConverter {
) -> Result<(SharedShape, Isometry<Real>), MeshConverterError> { ) -> Result<(SharedShape, Isometry<Real>), MeshConverterError> {
let mut transform = Isometry::identity(); let mut transform = Isometry::identity();
let shape = match self { let shape = match self {
MeshConverter::TriMesh => SharedShape::trimesh(vertices, indices), MeshConverter::TriMesh => SharedShape::trimesh(vertices, indices)
.map_err(MeshConverterError::TriMeshBuilderError)?,
MeshConverter::TriMeshWithFlags(flags) => { MeshConverter::TriMeshWithFlags(flags) => {
SharedShape::trimesh_with_flags(vertices, indices, *flags) SharedShape::trimesh_with_flags(vertices, indices, *flags)
.map_err(MeshConverterError::TriMeshBuilderError)?
} }
MeshConverter::Obb => { MeshConverter::Obb => {
let (pose, cuboid) = parry::utils::obb(&vertices); let (pose, cuboid) = parry::utils::obb(&vertices);

View File

@@ -480,20 +480,17 @@ impl QueryPipeline {
filter: QueryFilter, filter: QueryFilter,
) -> Option<ColliderHandle> { ) -> Option<ColliderHandle> {
let pipeline_shape = self.as_composite_shape(bodies, colliders, filter); let pipeline_shape = self.as_composite_shape(bodies, colliders, filter);
#[allow(deprecated)]
// TODO: replace this with IntersectionCompositeShapeShapeVisitor when it // TODO: replace this with IntersectionCompositeShapeShapeVisitor when it
// can return the shape part id. // can return the shape part id.
let mut visitor = let mut visitor = parry::query::details::IntersectionCompositeShapeShapeVisitor::new(
parry::query::details::IntersectionCompositeShapeShapeBestFirstVisitor::new( &*self.query_dispatcher,
&*self.query_dispatcher, shape_pos,
shape_pos, &pipeline_shape,
&pipeline_shape, shape,
shape, );
);
self.qbvh self.qbvh.traverse_depth_first(&mut visitor);
.traverse_best_first(&mut visitor) visitor.found_intersection
.map(|h| (h.1 .0))
} }
/// Find the projection of a point on the closest collider. /// Find the projection of a point on the closest collider.

View File

@@ -249,7 +249,7 @@ impl TestbedApp {
} }
pub fn run_with_init(mut self, mut init: impl FnMut(&mut App)) { pub fn run_with_init(mut self, mut init: impl FnMut(&mut App)) {
#[cfg(feature = "profiling")] #[cfg(feature = "profiler_ui")]
puffin_egui::puffin::set_scopes_on(true); puffin_egui::puffin::set_scopes_on(true);
let mut args = env::args(); let mut args = env::args();

View File

@@ -22,7 +22,7 @@ pub fn update_ui(
harness: &mut Harness, harness: &mut Harness,
debug_render: &mut DebugRenderPipelineResource, debug_render: &mut DebugRenderPipelineResource,
) { ) {
#[cfg(feature = "profiling")] #[cfg(feature = "profiler_ui")]
{ {
let window = egui::Window::new("Profiling"); let window = egui::Window::new("Profiling");
let window = window.default_open(false); let window = window.default_open(false);