parry3d/transformation/vhacd/
parameters.rs

1use crate::math::Real;
2use crate::transformation::voxelization::FillMode;
3
4/// Parameters controlling the VHACD convex decomposition algorithm.
5///
6/// These parameters control the trade-off between decomposition quality, performance,
7/// and the number of resulting convex parts. Understanding these parameters helps you
8/// achieve the desired balance for your specific use case.
9///
10/// # Quick Parameter Guide
11///
12/// | Parameter | Lower Values | Higher Values | Recommended For |
13/// |-----------|-------------|---------------|-----------------|
14/// | `concavity` | More parts, better fit | Fewer parts, faster | Games: 0.01-0.05, Simulation: 0.001-0.01 |
15/// | `resolution` | Faster, less detail | Slower, more detail | Preview: 32-64, Final: 64-256 |
16/// | `max_convex_hulls` | Simpler result | More accurate | Simple: 4-8, Complex: 16-32 |
17///
18/// # Examples
19///
20/// ## Default Parameters (Balanced)
21///
22/// ```
23/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
24/// use parry3d::transformation::vhacd::VHACDParameters;
25///
26/// let params = VHACDParameters::default();
27/// // Resolution: 64 (3D) or 256 (2D)
28/// // Concavity: 0.01 (3D) or 0.1 (2D)
29/// // Max convex hulls: 1024
30/// // Good starting point for most cases
31/// # }
32/// ```
33///
34/// ## High Quality (Slower, More Accurate)
35///
36/// ```
37/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
38/// use parry3d::transformation::vhacd::VHACDParameters;
39/// use parry3d::transformation::voxelization::FillMode;
40///
41/// let params = VHACDParameters {
42///     resolution: 256,           // High detail voxelization
43///     concavity: 0.001,          // Very tight fit to original
44///     max_convex_hulls: 64,      // Allow many parts
45///     plane_downsampling: 2,     // More precise plane search
46///     convex_hull_downsampling: 2, // More precise hulls
47///     alpha: 0.05,
48///     beta: 0.05,
49///     convex_hull_approximation: false, // Exact hulls
50///     fill_mode: FillMode::FloodFill {
51///         detect_cavities: false,
52///     },
53/// };
54/// // Best for: Critical collision accuracy, offline processing
55/// # }
56/// ```
57///
58/// ## Fast Preview (Quick Iteration)
59///
60/// ```
61/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
62/// use parry3d::transformation::vhacd::VHACDParameters;
63/// use parry3d::transformation::voxelization::FillMode;
64///
65/// let params = VHACDParameters {
66///     resolution: 32,            // Low resolution for speed
67///     concavity: 0.05,           // Allow some approximation
68///     max_convex_hulls: 16,      // Limit part count
69///     plane_downsampling: 8,     // Coarse plane search
70///     convex_hull_downsampling: 8, // Coarse hulls
71///     alpha: 0.05,
72///     beta: 0.05,
73///     convex_hull_approximation: true, // Fast approximation
74///     fill_mode: FillMode::FloodFill {
75///         detect_cavities: false,
76///     },
77/// };
78/// // Best for: Rapid prototyping, testing during development
79/// # }
80/// ```
81///
82/// ## Game-Ready (Performance & Quality)
83///
84/// ```
85/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
86/// use parry3d::transformation::vhacd::VHACDParameters;
87/// use parry3d::transformation::voxelization::FillMode;
88///
89/// let params = VHACDParameters {
90///     resolution: 128,           // Good balance
91///     concavity: 0.01,           // Reasonably tight
92///     max_convex_hulls: 32,      // Practical limit
93///     plane_downsampling: 4,     // Default precision
94///     convex_hull_downsampling: 4, // Default precision
95///     alpha: 0.05,
96///     beta: 0.05,
97///     convex_hull_approximation: true,
98///     fill_mode: FillMode::FloodFill {
99///         detect_cavities: false,
100///     },
101/// };
102/// // Best for: Game colliders, physics simulations
103/// # }
104/// ```
105///
106/// # See Also
107///
108/// - Original implementation: <https://github.com/kmammou/v-hacd>
109/// - Unity documentation: <https://github.com/Unity-Technologies/VHACD#parameters>
110/// - Module documentation: [`crate::transformation::vhacd`]
111#[derive(Debug, Clone, Copy, PartialEq)]
112pub struct VHACDParameters {
113    /// Maximum allowed concavity (deviation from convexity) for each part.
114    ///
115    /// This is the **most important parameter** controlling the quality vs. part count trade-off.
116    /// It measures how much the volume of each convex part can deviate from the actual geometry.
117    ///
118    /// # Behavior
119    ///
120    /// - **Lower values** (0.001 - 0.01): More convex parts, tighter fit to original shape
121    /// - **Higher values** (0.05 - 0.1): Fewer convex parts, more approximation
122    ///
123    /// # Typical Values
124    ///
125    /// - **Simulation/Robotics**: 0.001 - 0.005 (high accuracy)
126    /// - **Games**: 0.01 - 0.03 (balanced)
127    /// - **Prototyping**: 0.05 - 0.1 (fast preview)
128    ///
129    /// # Default
130    ///
131    /// - 2D: `0.1` (more tolerant due to simpler geometry)
132    /// - 3D: `0.01` (tighter tolerance for complex meshes)
133    ///
134    /// # Range
135    ///
136    /// Valid range: `[0.0, 1.0]`
137    ///
138    /// # Example
139    ///
140    /// ```
141    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
142    /// use parry3d::transformation::vhacd::VHACDParameters;
143    ///
144    /// // High precision (more parts)
145    /// let high_quality = VHACDParameters {
146    ///     concavity: 0.001,
147    ///     ..Default::default()
148    /// };
149    ///
150    /// // Low precision (fewer parts, faster)
151    /// let low_quality = VHACDParameters {
152    ///     concavity: 0.05,
153    ///     ..Default::default()
154    /// };
155    /// # }
156    /// ```
157    pub concavity: Real,
158
159    /// Bias toward splitting along symmetry planes (e.g., cutting a humanoid down the middle).
160    ///
161    /// This parameter influences the algorithm to prefer cutting planes that align with
162    /// the shape's symmetry. Higher values make the algorithm more likely to choose
163    /// symmetric splits, which can produce more aesthetically pleasing decompositions.
164    ///
165    /// # Behavior
166    ///
167    /// - **0.0**: No bias, purely based on concavity minimization
168    /// - **0.05** (default): Slight preference for symmetric splits
169    /// - **0.2+**: Strong preference for symmetric splits
170    ///
171    /// # When to Adjust
172    ///
173    /// - Increase for symmetric objects (characters, vehicles, buildings)
174    /// - Decrease for asymmetric or organic shapes
175    ///
176    /// # Default
177    ///
178    /// `0.05`
179    ///
180    /// # Range
181    ///
182    /// Valid range: `[0.0, 1.0]`
183    pub alpha: Real,
184
185    /// Bias toward splitting along revolution axes (e.g., cutting a cylinder lengthwise).
186    ///
187    /// This parameter influences the algorithm to prefer cutting planes that align with
188    /// axes of rotational symmetry. Useful for objects with cylindrical or rotational
189    /// features.
190    ///
191    /// # Behavior
192    ///
193    /// - **0.0**: No bias, purely based on concavity minimization
194    /// - **0.05** (default): Slight preference for revolution axis splits
195    /// - **0.2+**: Strong preference for revolution axis splits
196    ///
197    /// # When to Adjust
198    ///
199    /// - Increase for objects with cylindrical features (wheels, bottles, tunnels)
200    /// - Decrease for box-like or irregular shapes
201    ///
202    /// # Default
203    ///
204    /// `0.05`
205    ///
206    /// # Range
207    ///
208    /// Valid range: `[0.0, 1.0]`
209    pub beta: Real,
210
211    /// Resolution of the voxel grid used for decomposition.
212    ///
213    /// The input mesh is first converted to a voxel grid. This parameter determines
214    /// how fine that grid is. Higher resolution captures more detail but is slower
215    /// and uses more memory.
216    ///
217    /// # Behavior
218    ///
219    /// - **32-64**: Fast, suitable for simple shapes or preview
220    /// - **64-128**: Balanced, good for most game objects
221    /// - **128-256**: High quality, captures fine details
222    /// - **256+**: Very high quality, slow, for critical objects
223    ///
224    /// # Memory Usage
225    ///
226    /// Memory scales as O(resolution³) in 3D or O(resolution²) in 2D.
227    /// Resolution 64 ≈ 260KB, Resolution 128 ≈ 2MB, Resolution 256 ≈ 16MB
228    ///
229    /// # Default
230    ///
231    /// - 2D: `256` (2D voxelization is much cheaper)
232    /// - 3D: `64` (balances quality and performance)
233    ///
234    /// # Example
235    ///
236    /// ```
237    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
238    /// use parry3d::transformation::vhacd::VHACDParameters;
239    ///
240    /// // Quick preview
241    /// let preview = VHACDParameters {
242    ///     resolution: 32,
243    ///     ..Default::default()
244    /// };
245    ///
246    /// // Production quality
247    /// let production = VHACDParameters {
248    ///     resolution: 128,
249    ///     ..Default::default()
250    /// };
251    /// # }
252    /// ```
253    pub resolution: u32,
254
255    /// Granularity of the search for optimal clipping planes.
256    ///
257    /// During decomposition, the algorithm samples potential cutting planes along
258    /// each axis. This parameter controls how many planes to skip between samples.
259    /// Lower values mean more planes are tested (slower but more accurate).
260    ///
261    /// # Behavior
262    ///
263    /// - **1**: Test every possible plane (slowest, highest quality)
264    /// - **4** (default): Test every 4th plane (good balance)
265    /// - **8+**: Test fewer planes (faster, lower quality)
266    ///
267    /// # Performance Impact
268    ///
269    /// Reducing this value can significantly increase decomposition time, especially
270    /// with high `resolution` values. Often doubled for the initial coarse pass.
271    ///
272    /// # Default
273    ///
274    /// `4`
275    ///
276    /// # Example
277    ///
278    /// ```
279    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
280    /// use parry3d::transformation::vhacd::VHACDParameters;
281    ///
282    /// // Fast decomposition (coarse plane search)
283    /// let fast = VHACDParameters {
284    ///     plane_downsampling: 8,
285    ///     ..Default::default()
286    /// };
287    ///
288    /// // Precise decomposition (fine plane search)
289    /// let precise = VHACDParameters {
290    ///     plane_downsampling: 1,
291    ///     ..Default::default()
292    /// };
293    /// # }
294    /// ```
295    pub plane_downsampling: u32,
296
297    /// Precision of convex hull generation during plane selection.
298    ///
299    /// When evaluating potential cutting planes, the algorithm computes convex hulls
300    /// of the resulting parts. This parameter controls how much to downsample the
301    /// voxels before computing these hulls. Lower values = more precise but slower.
302    ///
303    /// # Behavior
304    ///
305    /// - **1**: Use all voxels (slowest, highest quality)
306    /// - **4** (default): Use every 4th voxel (good balance)
307    /// - **8+**: Use fewer voxels (faster, less precise)
308    ///
309    /// # Trade-off
310    ///
311    /// This primarily affects which cutting plane is chosen, not the final result.
312    /// Higher downsampling can still produce good results much faster.
313    ///
314    /// # Default
315    ///
316    /// `4`
317    ///
318    /// # Example
319    ///
320    /// ```
321    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
322    /// use parry3d::transformation::vhacd::VHACDParameters;
323    ///
324    /// // Faster hull computation
325    /// let fast = VHACDParameters {
326    ///     convex_hull_downsampling: 8,
327    ///     ..Default::default()
328    /// };
329    /// # }
330    /// ```
331    pub convex_hull_downsampling: u32,
332
333    /// How to fill the voxel grid from the input mesh or polyline.
334    ///
335    /// This controls the voxelization process, including how to handle the interior
336    /// of the shape and whether to detect special features like cavities.
337    ///
338    /// # Options
339    ///
340    /// - `FloodFill { detect_cavities: false, detect_self_intersections: false }` (default):
341    ///   Fast flood-fill from outside, works for most closed meshes
342    /// - `FloodFill { detect_cavities: true, ... }`:
343    ///   Also detect and preserve internal cavities (slower)
344    /// - `SurfaceOnly`:
345    ///   Only voxelize the surface, not the interior (for hollow shapes)
346    ///
347    /// # Default
348    ///
349    /// ```text
350    /// FillMode::FloodFill {
351    ///     detect_cavities: false,
352    ///     detect_self_intersections: false,  // 2D only
353    /// }
354    /// ```
355    ///
356    /// # Example
357    ///
358    /// ```
359    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
360    /// use parry3d::transformation::vhacd::VHACDParameters;
361    /// use parry3d::transformation::voxelization::FillMode;
362    ///
363    /// // For meshes with internal cavities (e.g., a bottle)
364    /// let with_cavities = VHACDParameters {
365    ///     fill_mode: FillMode::FloodFill {
366    ///         detect_cavities: true,
367    ///     },
368    ///     ..Default::default()
369    /// };
370    /// # }
371    /// ```
372    ///
373    /// # See Also
374    ///
375    /// [`FillMode`] for detailed documentation on voxelization modes.
376    pub fill_mode: FillMode,
377
378    /// Whether to use approximate convex hulls during decomposition.
379    ///
380    /// When `true`, the algorithm uses a faster but less precise method to compute
381    /// convex hulls during the decomposition process. This significantly speeds up
382    /// decomposition with minimal impact on the final quality.
383    ///
384    /// # Behavior
385    ///
386    /// - **`true`** (default): Clip the parent's convex hull and add sample points
387    ///   (fast, good quality)
388    /// - **`false`**: Compute exact convex hulls from all voxels
389    ///   (slower, slightly better quality)
390    ///
391    /// # Performance Impact
392    ///
393    /// Setting this to `false` can increase decomposition time by 2-5x, with often
394    /// negligible quality improvement. Recommended to keep `true` for most cases.
395    ///
396    /// # Default
397    ///
398    /// `true`
399    ///
400    /// # Example
401    ///
402    /// ```
403    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
404    /// use parry3d::transformation::vhacd::VHACDParameters;
405    ///
406    /// // Absolute highest quality (slow)
407    /// let exact = VHACDParameters {
408    ///     convex_hull_approximation: false,
409    ///     ..Default::default()
410    /// };
411    /// # }
412    /// ```
413    pub convex_hull_approximation: bool,
414
415    /// Maximum number of convex parts to generate.
416    ///
417    /// This acts as an upper limit on the number of convex hulls the algorithm will
418    /// produce. The actual number may be less if the shape can be decomposed with
419    /// fewer parts while meeting the `concavity` threshold.
420    ///
421    /// # Behavior
422    ///
423    /// The algorithm uses a binary tree decomposition with depth calculated to potentially
424    /// produce up to `max_convex_hulls` parts. If parts are already approximately convex
425    /// (concavity below threshold), they won't be split further.
426    ///
427    /// # Typical Values
428    ///
429    /// - **4-8**: Simple objects, performance-critical
430    /// - **16-32**: Standard game objects, good balance
431    /// - **32-64**: Complex objects, high quality
432    /// - **64+**: Very complex objects, offline processing
433    ///
434    /// # Performance Note
435    ///
436    /// More parts = more collision checks during physics simulation. Keep this
437    /// reasonable for dynamic objects (8-32). Static objects can afford more.
438    ///
439    /// # Default
440    ///
441    /// `1024` (effectively unlimited for most practical cases)
442    ///
443    /// # Example
444    ///
445    /// ```
446    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
447    /// use parry3d::transformation::vhacd::VHACDParameters;
448    ///
449    /// // Limit to reasonable number for game character
450    /// let game_character = VHACDParameters {
451    ///     max_convex_hulls: 16,
452    ///     concavity: 0.02,
453    ///     ..Default::default()
454    /// };
455    ///
456    /// // Allow many parts for static environment
457    /// let environment = VHACDParameters {
458    ///     max_convex_hulls: 128,
459    ///     concavity: 0.005,
460    ///     ..Default::default()
461    /// };
462    /// # }
463    /// ```
464    pub max_convex_hulls: u32,
465}
466
467impl Default for VHACDParameters {
468    fn default() -> Self {
469        Self {
470            #[cfg(feature = "dim3")]
471            resolution: 64,
472            #[cfg(feature = "dim3")]
473            concavity: 0.01,
474            #[cfg(feature = "dim2")]
475            resolution: 256,
476            #[cfg(feature = "dim2")]
477            concavity: 0.1,
478            plane_downsampling: 4,
479            convex_hull_downsampling: 4,
480            alpha: 0.05,
481            beta: 0.05,
482            convex_hull_approximation: true,
483            max_convex_hulls: 1024,
484            fill_mode: FillMode::FloodFill {
485                detect_cavities: false,
486                #[cfg(feature = "dim2")]
487                detect_self_intersections: false,
488            },
489        }
490    }
491}