pub struct VoxelSet {
pub origin: Point<f32>,
pub scale: f32,
/* private fields */
}Expand description
A sparse set of filled voxels resulting from voxelization.
VoxelSet is a memory-efficient storage format that only contains voxels marked as “filled”
during the voxelization process. This is much more efficient than storing a dense 3D array
for shapes that are mostly empty or have a hollow interior.
§Structure
Each VoxelSet contains:
- A list of filled voxels with their grid coordinates
- The origin point and scale factor for converting grid coordinates to world space
- Optional metadata tracking which primitives (triangles/segments) intersect each voxel
§Grid Coordinates vs World Coordinates
Voxels are stored with integer grid coordinates (i, j, k). To convert to world-space
coordinates, use:
world_position = origin + (i, j, k) * scaleThe get_voxel_point() method does this conversion for you.
§Memory Layout
Unlike VoxelizedVolume which stores a dense 3D array, VoxelSet uses sparse storage:
- Only filled voxels are stored (typically much fewer than total grid cells)
- Memory usage is
O(filled_voxels)instead ofO(resolution^3) - Ideal for shapes with low surface-to-volume ratio
§Example: Basic Usage
use parry3d::transformation::voxelization::{FillMode, VoxelSet};
use parry3d::shape::Cuboid;
use nalgebra::Vector3;
// Create and voxelize a shape
let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
let (vertices, indices) = cuboid.to_trimesh();
let voxels = VoxelSet::voxelize(
&vertices,
&indices,
10, // resolution
FillMode::SurfaceOnly, // hollow surface only
false, // no primitive mapping
);
// Query the voxel set
println!("Number of voxels: {}", voxels.len());
println!("Voxel size: {}", voxels.scale);
println!("Total volume: {}", voxels.compute_volume());
// Access voxels
for voxel in voxels.voxels() {
let world_pos = voxels.get_voxel_point(voxel);
println!("Voxel at {:?}", world_pos);
}§Example: Volume Computation
use parry3d::transformation::voxelization::{FillMode, VoxelSet};
use parry3d::shape::Ball;
///
let ball = Ball::new(1.0);
let (vertices, indices) = ball.to_trimesh(20, 20);
// Voxelize with interior filling
let voxels = VoxelSet::voxelize(
&vertices,
&indices,
20,
FillMode::FloodFill { detect_cavities: false },
false,
);
// Compute approximate volume
let voxel_volume = voxels.compute_volume();
let expected_volume = 4.0 / 3.0 * std::f32::consts::PI;
println!("Voxel volume: {:.3}, Expected: {:.3}", voxel_volume, expected_volume);Fields§
§origin: Point<f32>The 3D origin of this voxel-set.
scale: f32The scale factor between the voxel integer coordinates and their actual float world-space coordinates.
Implementations§
Source§impl VoxelSet
impl VoxelSet
Sourcepub fn voxel_volume(&self) -> f32
pub fn voxel_volume(&self) -> f32
The volume of a single voxel of this voxel set.
Sourcepub fn with_voxel_size(
points: &[Point<f32>],
indices: &[[u32; 3]],
voxel_size: f32,
fill_mode: FillMode,
keep_voxel_to_primitives_map: bool,
) -> Self
pub fn with_voxel_size( points: &[Point<f32>], indices: &[[u32; 3]], voxel_size: f32, fill_mode: FillMode, keep_voxel_to_primitives_map: bool, ) -> Self
Voxelizes a shape by specifying the physical size of each voxel.
This creates a voxelized representation of a shape defined by its boundary:
- In 3D: A triangle mesh (vertices and triangle indices)
- In 2D: A polyline (vertices and segment indices)
The resolution is automatically determined based on the shape’s bounding box and the requested voxel size.
§Parameters
-
points- Vertex buffer defining the boundary of the shape. These are the vertices of the triangle mesh (3D) or polyline (2D). -
indices- Index buffer defining the boundary primitives:- 3D: Each element is
[v0, v1, v2]defining a triangle - 2D: Each element is
[v0, v1]defining a line segment
- 3D: Each element is
-
voxel_size- The physical size (edge length) of each cubic voxel. Smaller values give higher resolution but use more memory. -
fill_mode- Controls which voxels are marked as filled:FillMode::SurfaceOnly: Only voxels intersecting the boundaryFillMode::FloodFill: Surface voxels plus interior voxels
-
keep_voxel_to_primitives_map- Iftrue, stores which primitives (triangles or segments) intersect each voxel. Required forcompute_exact_convex_hull()andcompute_primitive_intersections(), but uses additional memory.
§Returns
A sparse VoxelSet containing only the filled voxels.
§Example
use parry3d::transformation::voxelization::{FillMode, VoxelSet};
use parry3d::shape::Ball;
let ball = Ball::new(2.0); // radius = 2.0
let (vertices, indices) = ball.to_trimesh(20, 20);
// Create voxels with 0.1 unit size
let voxels = VoxelSet::with_voxel_size(
&vertices,
&indices,
0.1, // each voxel is 0.1 x 0.1 x 0.1
FillMode::SurfaceOnly,
false,
);
println!("Created {} voxels", voxels.len());
println!("Each voxel has volume {}", voxels.voxel_volume());Sourcepub fn voxelize(
points: &[Point<f32>],
indices: &[[u32; 3]],
resolution: u32,
fill_mode: FillMode,
keep_voxel_to_primitives_map: bool,
) -> Self
pub fn voxelize( points: &[Point<f32>], indices: &[[u32; 3]], resolution: u32, fill_mode: FillMode, keep_voxel_to_primitives_map: bool, ) -> Self
Voxelizes a shape by specifying the grid resolution along the longest axis.
This creates a voxelized representation of a shape defined by its boundary:
- In 3D: A triangle mesh (vertices and triangle indices)
- In 2D: A polyline (vertices and segment indices)
The voxel size is automatically computed to fit the specified number of subdivisions along the shape’s longest axis, while maintaining cubic (or square in 2D) voxels. Other axes will have proportionally determined resolutions.
§Parameters
-
points- Vertex buffer defining the boundary of the shape. These are the vertices of the triangle mesh (3D) or polyline (2D). -
indices- Index buffer defining the boundary primitives:- 3D: Each element is
[v0, v1, v2]defining a triangle - 2D: Each element is
[v0, v1]defining a line segment
- 3D: Each element is
-
resolution- Number of voxel subdivisions along the longest axis of the shape’s bounding box. Higher values give more detail but use more memory. For example,resolution = 10creates approximately 10 voxels along the longest dimension. -
fill_mode- Controls which voxels are marked as filled:FillMode::SurfaceOnly: Only voxels intersecting the boundaryFillMode::FloodFill: Surface voxels plus interior voxels
-
keep_voxel_to_primitives_map- Iftrue, stores which primitives (triangles or segments) intersect each voxel. Required forcompute_exact_convex_hull()andcompute_primitive_intersections(), but uses additional memory.
§Returns
A sparse VoxelSet containing only the filled voxels.
§Example
use parry3d::transformation::voxelization::{FillMode, VoxelSet};
use parry3d::shape::Cuboid;
use nalgebra::Vector3;
// Create a cuboid: 2 units wide (x), 1 unit tall (y), 0.5 units deep (z)
let cuboid = Cuboid::new(Vector3::new(1.0, 0.5, 0.25));
let (vertices, indices) = cuboid.to_trimesh();
// Voxelize with 20 subdivisions along the longest axis (x = 2.0)
// Other axes will be proportionally subdivided to maintain cubic voxels
let voxels = VoxelSet::voxelize(
&vertices,
&indices,
20, // 20 voxels along x-axis
FillMode::FloodFill {
detect_cavities: false,
},
false,
);
println!("Created {} voxels", voxels.len());
println!("Voxel scale: {}", voxels.scale); // automatically computed
println!("Total volume: {}", voxels.compute_volume());§Choosing Resolution
- Low (5-10): Fast, coarse approximation, good for rough collision proxies
- Medium (10-30): Balanced detail and performance, suitable for most use cases
- High (50+): Fine detail, high memory usage, used for precise volume computation
Sourcepub fn min_bb_voxels(&self) -> Point<u32>
pub fn min_bb_voxels(&self) -> Point<u32>
The minimal coordinates of the integer bounding-box of the voxels in this set.
Sourcepub fn max_bb_voxels(&self) -> Point<u32>
pub fn max_bb_voxels(&self) -> Point<u32>
The maximal coordinates of the integer bounding-box of the voxels in this set.
Sourcepub fn compute_volume(&self) -> f32
pub fn compute_volume(&self) -> f32
Computes the total volume occupied by all voxels in this set.
This calculates the approximate volume by multiplying the number of filled voxels by the volume of each individual voxel. The result is an approximation of the volume of the original shape.
§Accuracy
The accuracy depends on the voxelization resolution:
- Higher resolution (smaller voxels) → more accurate volume
- Lower resolution (larger voxels) → faster but less accurate
§Example
use parry3d::transformation::voxelization::{FillMode, VoxelSet};
use parry3d::shape::Ball;
let ball = Ball::new(1.0);
let (vertices, indices) = ball.to_trimesh(20, 20);
let voxels = VoxelSet::voxelize(
&vertices,
&indices,
30, // Higher resolution for better accuracy
FillMode::FloodFill { detect_cavities: false },
false,
);
let voxel_volume = voxels.compute_volume();
let expected_volume = 4.0 / 3.0 * std::f32::consts::PI * 1.0_f32.powi(3);
println!("Voxel volume: {:.3}", voxel_volume);
println!("Expected volume: {:.3}", expected_volume);
println!("Error: {:.1}%", ((voxel_volume - expected_volume).abs() / expected_volume * 100.0));Sourcepub fn get_voxel_point(&self, voxel: &Voxel) -> Point<f32>
pub fn get_voxel_point(&self, voxel: &Voxel) -> Point<f32>
Converts voxel grid coordinates to world-space coordinates.
Given a voxel, this computes the world-space position of the voxel’s center. The conversion formula is:
world_position = origin + (voxel.coords + 0.5) * scaleNote that we add 0.5 to get the center of the voxel rather than its corner.
§Example
use parry3d::transformation::voxelization::{FillMode, VoxelSet};
use parry3d::shape::Cuboid;
use nalgebra::Vector3;
let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
let (vertices, indices) = cuboid.to_trimesh();
let voxels = VoxelSet::voxelize(
&vertices,
&indices,
10,
FillMode::SurfaceOnly,
false,
);
// Convert grid coordinates to world coordinates
for voxel in voxels.voxels() {
let grid_coords = voxel.coords;
let world_coords = voxels.get_voxel_point(voxel);
println!("Grid: {:?} -> World: {:?}", grid_coords, world_coords);
}Sourcepub fn compute_bb(&mut self)
pub fn compute_bb(&mut self)
Update the bounding box of this voxel set.
Sourcepub fn compute_exact_convex_hull(
&self,
points: &[Point<f32>],
indices: &[[u32; 3]],
) -> (Vec<Point<f32>>, Vec<[u32; 3]>)
pub fn compute_exact_convex_hull( &self, points: &[Point<f32>], indices: &[[u32; 3]], ) -> (Vec<Point<f32>>, Vec<[u32; 3]>)
Computes a precise convex hull by clipping primitives against voxel boundaries.
This method produces a more accurate convex hull than compute_convex_hull() by:
- Finding which primitives (triangles/segments) intersect each voxel
- Clipping those primitives to the voxel boundaries
- Computing the convex hull from the clipped geometry
This approach gives much tighter convex hulls, especially at lower resolutions, because it uses the actual intersection geometry rather than just voxel centers.
§Requirements
This method requires that the voxel set was created with keep_voxel_to_primitives_map = true.
Otherwise, this method will panic.
§Parameters
points- The same vertex buffer used during voxelizationindices- The same index buffer used during voxelization
§Returns
In 2D: A vector of points forming the convex hull polygon
In 3D: A tuple of (vertices, triangle_indices) forming the convex hull mesh
§Panics
Panics if this VoxelSet was created with keep_voxel_to_primitives_map = false.
§Example
use parry3d::transformation::voxelization::{FillMode, VoxelSet};
use parry3d::shape::Cuboid;
use nalgebra::Vector3;
let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
let (vertices, indices) = cuboid.to_trimesh();
// IMPORTANT: Set keep_voxel_to_primitives_map = true
let voxels = VoxelSet::voxelize(
&vertices,
&indices,
10,
FillMode::SurfaceOnly,
true, // Enable primitive mapping
);
// Compute exact convex hull using triangle clipping
let (hull_vertices, hull_indices) = voxels.compute_exact_convex_hull(&vertices, &indices);
println!("Exact convex hull: {} vertices, {} triangles",
hull_vertices.len(), hull_indices.len());§Comparison with compute_convex_hull()
compute_exact_convex_hull(): More accurate, requires primitive mapping, slowercompute_convex_hull(): Approximate, uses voxel centers, faster
Sourcepub fn compute_primitive_intersections(
&self,
points: &[Point<f32>],
indices: &[[u32; 3]],
) -> Vec<Point<f32>> ⓘ
pub fn compute_primitive_intersections( &self, points: &[Point<f32>], indices: &[[u32; 3]], ) -> Vec<Point<f32>> ⓘ
Computes the intersections between all the voxels of this voxel set, and all the primitives (triangle or segments) it intersected (as per the voxel-to-primitives-map computed during voxelization).
Panics if the voxelization was performed without setting the parameter
voxel_to_primitives_map = true.
Sourcepub fn compute_convex_hull(
&self,
sampling: u32,
) -> (Vec<Point<f32>>, Vec<[u32; 3]>)
pub fn compute_convex_hull( &self, sampling: u32, ) -> (Vec<Point<f32>>, Vec<[u32; 3]>)
Compute the convex-hull of the voxels in this set.
§Parameters
sampling- The convex-hull computation will ignoresamplingvoxels at regular intervals. Useful to save some computation times if an exact result isn’t need. Use0to make sure no voxel is being ignored.
Trait Implementations§
Source§impl From<VoxelizedVolume> for VoxelSet
impl From<VoxelizedVolume> for VoxelSet
Source§fn from(shape: VoxelizedVolume) -> Self
fn from(shape: VoxelizedVolume) -> Self
Auto Trait Implementations§
impl Freeze for VoxelSet
impl RefUnwindSafe for VoxelSet
impl Send for VoxelSet
impl Sync for VoxelSet
impl Unpin for VoxelSet
impl UnwindSafe for VoxelSet
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&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
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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 moreSource§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.