Struct VHACD

Source
pub struct VHACD { /* private fields */ }
Expand description

Approximate convex decomposition using the VHACD algorithm.

This structure holds the result of the V-HACD (Volumetric Hierarchical Approximate Convex Decomposition) algorithm, which decomposes a concave shape into multiple approximately-convex parts.

§Overview

The VHACD struct stores the decomposition result as a collection of voxelized parts, where each part is approximately convex. These parts can be converted to convex hulls for use in collision detection and physics simulation.

§Basic Workflow

  1. Decompose: Create a VHACD instance using VHACD::decompose or VHACD::from_voxels
  2. Access Parts: Get the voxelized parts using voxel_parts
  3. Generate Hulls: Compute convex hulls with compute_convex_hulls or compute_exact_convex_hulls

§Examples

§Basic Usage

use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

// Define a simple mesh (tetrahedron)
let vertices = vec![
    Point::new(0.0, 0.0, 0.0),
    Point::new(1.0, 0.0, 0.0),
    Point::new(0.5, 1.0, 0.0),
    Point::new(0.5, 0.5, 1.0),
];
let indices = vec![
    [0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 3, 2],
];

// Decompose with default parameters
let decomposition = VHACD::decompose(
    &VHACDParameters::default(),
    &vertices,
    &indices,
    false,
);

// Access the results
println!("Generated {} parts", decomposition.voxel_parts().len());

// Get convex hulls for collision detection
let hulls = decomposition.compute_convex_hulls(4);

§With Custom Parameters

use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

// High-quality decomposition settings
let params = VHACDParameters {
    resolution: 128,
    concavity: 0.001,
    max_convex_hulls: 32,
    ..Default::default()
};

let decomposition = VHACD::decompose(&params, &vertices, &indices, false);

§See Also

Implementations§

Source§

impl VHACD

Source

pub fn decompose( params: &VHACDParameters, points: &[Point<f32>], indices: &[[u32; 3]], keep_voxel_to_primitives_map: bool, ) -> Self

Decompose the given polyline (in 2D) or triangle mesh (in 3D).

This is the primary method for performing approximate convex decomposition. It takes a mesh defined by vertices and indices, voxelizes it, and decomposes it into approximately-convex parts using the V-HACD algorithm.

§Parameters
  • params - Configuration parameters controlling the decomposition process. See VHACDParameters for details on each parameter.

  • points - The vertex positions of your mesh (3D) or polyline (2D). Each point represents a vertex in world space.

  • indices - The connectivity information:

    • 3D: Triangle indices [u32; 3] - each entry defines a triangle using 3 vertex indices
    • 2D: Segment indices [u32; 2] - each entry defines a line segment using 2 vertex indices
  • keep_voxel_to_primitives_map - Whether to maintain a mapping between voxels and the original mesh primitives (triangles/segments) they intersect.

§Returns

A VHACD instance containing the decomposition results. Use voxel_parts to access the raw voxelized parts, or compute_convex_hulls to generate convex hull geometry.

§Performance

Decomposition time depends primarily on:

  • resolution: Higher = slower (cubic scaling in 3D)
  • max_convex_hulls: More parts = more splits = longer time
  • Mesh complexity: More vertices/triangles = slower voxelization

Typical times (on modern CPU):

  • Simple mesh (1K triangles, resolution 64): 100-500ms
  • Complex mesh (10K triangles, resolution 128): 1-5 seconds
  • Very complex (100K triangles, resolution 256): 10-60 seconds
§Examples
§Basic Decomposition
use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

// Simple L-shaped mesh
let vertices = vec![
    Point::new(0.0, 0.0, 0.0), Point::new(2.0, 0.0, 0.0),
    Point::new(2.0, 1.0, 0.0), Point::new(1.0, 1.0, 0.0),
];
let indices = vec![
    [0, 1, 2], [0, 2, 3],
];

let decomposition = VHACD::decompose(
    &VHACDParameters::default(),
    &vertices,
    &indices,
    false, // Don't need exact hulls
);

println!("Parts: {}", decomposition.voxel_parts().len());
§With Exact Hull Generation
use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

// Enable voxel-to-primitive mapping for exact hulls
let decomposition = VHACD::decompose(
    &VHACDParameters::default(),
    &vertices,
    &indices,
    true, // <-- Enable for exact hulls
);

// Now we can compute exact hulls using original mesh
let exact_hulls = decomposition.compute_exact_convex_hulls(&vertices, &indices);
§Custom Parameters
use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

// High-quality settings for important objects
let params = VHACDParameters {
    resolution: 128,        // High detail
    concavity: 0.001,       // Tight fit
    max_convex_hulls: 32,   // Allow many parts
    ..Default::default()
};

let decomposition = VHACD::decompose(&params, &vertices, &indices, false);
§See Also
Source

pub fn from_voxels(params: &VHACDParameters, voxels: VoxelSet) -> Self

Perform an approximate convex decomposition of a pre-voxelized set of voxels.

This method allows you to decompose a shape that has already been voxelized, bypassing the voxelization step. This is useful if you:

  • Already have voxelized data from another source
  • Want to decompose the same voxelization with different parameters
  • Need more control over the voxelization process
§Parameters
  • params - Configuration parameters for the decomposition algorithm. See VHACDParameters for details.

  • voxels - A pre-voxelized volume represented as a VoxelSet. You can create this using VoxelizedVolume::voxelize or other voxelization methods.

§Returns

A VHACD instance containing the decomposition results.

§Examples
use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};
use parry3d::transformation::voxelization::{VoxelizedVolume, FillMode};

// First, voxelize the mesh manually
let voxelized = VoxelizedVolume::voxelize(
    &vertices,
    &indices,
    64, // resolution
    FillMode::FloodFill {
        detect_cavities: false,
    },
    false, // don't keep primitive mapping
);

// Then decompose the voxels
let decomposition = VHACD::from_voxels(
    &VHACDParameters::default(),
    voxelized.into(),
);
§See Also
Source

pub fn voxel_parts(&self) -> &[VoxelSet]

Returns the approximately-convex voxelized parts computed by the VHACD algorithm.

Each part in the returned slice represents an approximately-convex region of the original shape, stored as a set of voxels. These voxelized parts are the direct result of the decomposition algorithm.

§Returns

A slice of VoxelSet structures, where each set represents one convex part. The number of parts depends on the shape’s complexity and the parameters used (especially concavity and max_convex_hulls).

§Usage

You typically don’t use the voxel parts directly for collision detection. Instead:

However, accessing voxel parts directly is useful for:

  • Debugging and visualization of the decomposition
  • Custom processing of the voxelized representation
  • Understanding how the algorithm divided the shape
§Examples
use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

let decomposition = VHACD::decompose(
    &VHACDParameters::default(),
    &vertices,
    &indices,
    false,
);

let parts = decomposition.voxel_parts();
println!("Generated {} convex parts", parts.len());

// Inspect individual parts
for (i, part) in parts.iter().enumerate() {
    println!("Part {}: {} voxels", i, part.voxels().len());
}
§See Also
Source

pub fn compute_primitive_intersections( &self, points: &[Point<f32>], indices: &[[u32; 3]], ) -> Vec<Vec<Point<f32>>>

Compute the intersections between the voxelized convex part of this decomposition, and all the primitives from the original decomposed polyline/trimesh,

This will panic if keep_voxel_to_primitives_map was set to false when initializing self.

Source

pub fn compute_exact_convex_hulls( &self, points: &[Point<f32>], indices: &[[u32; 3]], ) -> Vec<(Vec<Point<f32>>, Vec<[u32; 3]>)>

Compute exact convex hulls using the original mesh geometry (3D version).

This method generates convex hulls for each decomposed part by computing the convex hull of the intersection between the voxelized part and the original triangle mesh primitives. This produces more accurate hulls than the voxel-based method, preserving the original geometry’s detail.

§Requirements

This method requires that keep_voxel_to_primitives_map was set to true when calling VHACD::decompose. If it was false, this method will panic.

§Parameters
  • points - The same vertex buffer used when calling VHACD::decompose
  • indices - The same index buffer (triangle indices [u32; 3]) used when calling VHACD::decompose
§Returns

A vector of convex hulls (one per decomposed part), where each hull is represented as a tuple (vertices, indices):

  • vertices: Vec<Point<Real>> - The hull vertices
  • indices: Vec<[u32; 3]> - Triangle indices defining the hull surface
§Performance

This is more expensive than compute_convex_hulls because it needs to compute intersections with the original primitives and then compute convex hulls. However, it produces more accurate results that better match the original mesh.

§Examples
use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

// IMPORTANT: Set keep_voxel_to_primitives_map to true
let decomposition = VHACD::decompose(
    &VHACDParameters::default(),
    &vertices,
    &indices,
    true, // <-- Required for exact hulls
);

// Compute exact convex hulls using original geometry
let exact_hulls = decomposition.compute_exact_convex_hulls(&vertices, &indices);

for (i, (verts, tris)) in exact_hulls.iter().enumerate() {
    println!("Hull {}: {} vertices, {} triangles", i, verts.len(), tris.len());
}
§Panics

Panics if keep_voxel_to_primitives_map was false during decomposition.

§See Also
Source

pub fn compute_convex_hulls( &self, downsampling: u32, ) -> Vec<(Vec<Point<f32>>, Vec<[u32; 3]>)>

Compute convex hulls from the voxelized parts (3D version).

This method generates convex meshes for each decomposed part by computing the convex hull of the voxel vertices. This is faster than compute_exact_convex_hulls but the hulls are based on the voxelized representation rather than the original geometry.

§Parameters
  • downsampling - Controls how many voxels to skip when generating the hull. Higher values = fewer points = simpler hulls = faster computation.

    • 1: Use all voxel vertices (highest quality, slowest)
    • 4: Use every 4th voxel (good balance, recommended)
    • 8+: Use fewer voxels (fastest, simpler hulls)

    Values less than 1 are clamped to 1.

§Returns

A vector of convex hulls (one per decomposed part), where each hull is represented as a tuple (vertices, indices):

  • vertices: Vec<Point<Real>> - The hull vertices
  • indices: Vec<[u32; 3]> - Triangle indices defining the hull surface
§Performance

This method is faster than compute_exact_convex_hulls because it works directly with voxel data without needing to intersect with original mesh primitives. The performance scales with the number of voxels and the downsampling factor.

§When to Use

Use this method when:

  • You don’t need the highest accuracy
  • Performance is important
  • You didn’t enable keep_voxel_to_primitives_map during decomposition
  • The voxel resolution is high enough for your needs
  • You’re using this for real-time collision detection

Use compute_exact_convex_hulls when:

  • You need the most accurate representation of the original geometry
  • You have enabled keep_voxel_to_primitives_map
  • Quality is more important than speed
§Examples
use parry3d::math::Point;
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};

let decomposition = VHACD::decompose(
    &VHACDParameters::default(),
    &vertices,
    &indices,
    false, // voxel-to-primitive mapping not needed
);

// Compute voxel-based convex hulls with moderate downsampling
let hulls = decomposition.compute_convex_hulls(4);

for (i, (verts, tris)) in hulls.iter().enumerate() {
    println!("Hull {}: {} vertices, {} triangles", i, verts.len(), tris.len());
}
§Creating a Compound Shape for Collision Detection
use parry3d::math::Point;
use parry3d::shape::{SharedShape, Compound};
use parry3d::transformation::vhacd::{VHACD, VHACDParameters};
use parry3d::na::Isometry3;

let decomposition = VHACD::decompose(
    &VHACDParameters::default(),
    &vertices,
    &indices,
    false,
);

let hulls = decomposition.compute_convex_hulls(4);
§See Also

Auto Trait Implementations§

§

impl Freeze for VHACD

§

impl RefUnwindSafe for VHACD

§

impl Send for VHACD

§

impl Sync for VHACD

§

impl Unpin for VHACD

§

impl UnwindSafe for VHACD

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Sync + Send>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.