rapier3d_meshloader/
lib.rs

1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3
4use mesh_loader::Mesh;
5use rapier3d::geometry::{MeshConverter, SharedShape};
6use rapier3d::math::{Isometry, Point, Real, Vector};
7use rapier3d::prelude::MeshConverterError;
8use std::path::Path;
9
10/// The result of loading a shape.
11pub struct LoadedShape {
12    /// The shape loaded from the file and converted by the [`MeshConverter`].
13    pub shape: SharedShape,
14    /// The shape’s pose.
15    pub pose: Isometry<Real>,
16    /// The raw mesh read from the file without any modification.
17    pub raw_mesh: Mesh,
18}
19
20/// Error while loading an STL file.
21#[derive(thiserror::Error, Debug)]
22pub enum MeshLoaderError {
23    /// An error triggered by rapier’s [`MeshConverter`].
24    #[error(transparent)]
25    MeshConverter(#[from] MeshConverterError),
26    /// A generic IO error.
27    #[error(transparent)]
28    Io(#[from] std::io::Error),
29}
30
31/// Loads parry shapes from a file.
32///
33/// # Parameters
34/// - `path`: the file’s path.
35/// - `converter`: controls how the shapes are computed from the content. In particular, it lets
36///   you specify if the computed [`SharedShape`] is a triangle mesh, its convex hull,
37///   bounding box, etc.
38/// - `scale`: the scaling factor applied to the geometry input to the `converter`. This scale will
39///   affect at the geometric level the [`LoadedShape::shape`]. Note that raw mesh value stored
40///   in [`LoadedShape::raw_mesh`] remains unscaled.
41pub fn load_from_path(
42    path: impl AsRef<Path>,
43    converter: &MeshConverter,
44    scale: Vector<Real>,
45) -> Result<Vec<Result<LoadedShape, MeshConverterError>>, MeshLoaderError> {
46    let loader = mesh_loader::Loader::default();
47    let mut colliders = vec![];
48    let scene = loader.load(path)?;
49    for (raw_mesh, _) in scene.meshes.into_iter().zip(scene.materials) {
50        let shape = load_from_raw_mesh(&raw_mesh, converter, scale);
51
52        colliders.push(shape.map(|(shape, pose)| LoadedShape {
53            shape,
54            pose,
55            raw_mesh,
56        }));
57    }
58    Ok(colliders)
59}
60
61/// Loads an file as a shape from a preloaded raw [`mesh_loader::Mesh`].
62///
63/// # Parameters
64/// - `raw_mesh`: the raw mesh.
65/// - `converter`: controls how the shape is computed from the STL content. In particular, it lets
66///   you specify if the computed [`SharedShape`] is a triangle mesh, its convex hull,
67///   bounding box, etc.
68/// - `scale`: the scaling factor applied to the geometry input to the `converter`. This scale will
69///   affect at the geometric level the [`LoadedShape::shape`]. Note that raw mesh value stored
70///   in [`LoadedShape::raw_mesh`] remains unscaled.
71pub fn load_from_raw_mesh(
72    raw_mesh: &Mesh,
73    converter: &MeshConverter,
74    scale: Vector<Real>,
75) -> Result<(SharedShape, Isometry<Real>), MeshConverterError> {
76    let mut vertices: Vec<_> = raw_mesh
77        .vertices
78        .iter()
79        .map(|xyz| Point::new(xyz[0], xyz[1], xyz[2]))
80        .collect();
81    vertices
82        .iter_mut()
83        .for_each(|pt| pt.coords.component_mul_assign(&scale));
84    let indices: Vec<_> = raw_mesh.faces.clone();
85    converter.convert(vertices, indices)
86}