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}