UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ConvexDecomposition3.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "BoxTypes.h"
6#include "Containers/Array.h"
8#include "Containers/Map.h"
9#include "CoreMinimal.h"
11#include "IndexTypes.h"
12#include "Math/Sphere.h"
13#include "Math/UnrealMathSSE.h"
14#include "Math/Vector.h"
15#include "MathUtil.h"
17#include "PlaneTypes.h"
18#include "TransformTypes.h"
19#include "VectorTypes.h"
20
21namespace UE {
22namespace Geometry {
23
24// Forward declare fast winding tree for negative space sampling
25template<class TriangleMeshType>
26class TFastWindingTree;
27
28// TODO: To support meshes where volume is not well defined (e.g., open boundaries or many self-intersecting parts), we'll need alternative error metrics
30{
31 //GeometryToHullRayDistance,
32 //HullToGeometryDistance,
33 //BothDistances,
35};
36
38{
43
44 enum class ESampleMethod : uint8
45 {
46 // Place sample spheres in a uniform grid pattern
47 Uniform,
48 // Use voxel-based subtraction and offsetting methods to specifically target concavities
50 // Use a variant of VoxelSearch that aims to limit negative space to the space that can be accessed by a ball of radius >= MinRadius
52 };
53
54 // Enum to manage settings configurations for FNegativeSpaceSampleSettings
56 {
57 Latest
58 };
59
60 // Note: Class member default values are held fixed to avoid changing results for existing callers
61 // Use this method to request newer, recommended defaults
71
72 // Method used to place samples
74
75 // Target number of spheres to use to cover negative space. Intended as a rough guide; actual number used may be larger or smaller.
77
78 // Minimum desired spacing between sampling spheres; not a strictly enforced bound.
79 double MinSpacing = 3.0;
80
81 // Whether to allow samples w/ center inside other negative space spheres
83
84 // Space to allow between spheres and actual surface
85 double ReduceRadiusMargin = 3.0;
86
87 // Ignore spheres with smaller radius than this
88 double MinRadius = 10.0;
89
90 // Below options currently only apply to VoxelSearch.
91
92 // Whether to require that all candidate sample locations identified by Voxel Search are covered by negative space samples, up to the specified Min Sample Spacing.
93 // Note: This takes priority over TargetNumSamples if the TargetNumSamples did not achieve the required coverage.
95 // Whether to only consider negative space that is connected to the bounding convex hull, i.e., to ignore hollow inner pockets of negative space that cannot be reached from the outside (for VoxelSearch and Navigable methods)
97 // Maximum number of voxels to use per dimension, when performing VoxelSearch
99 // Attempt to keep negative space computation deterministic, at some additional runtime cost
100 bool bDeterministic = true;
101 // Scale factor for marching cubes grid used for VoxelSearch-based methods
103
104 // Whether to allow samples to be added inside the mesh, based on winding number. Can enabled for non-solid meshes; note the convex decomposition should then set bTreatAsSolid to false as well.
106
107 // How much to expand the bounding box used for voxel search algorithms
109
110 // Optional function to define an obstacle SDF which the negative space should also stay out of. Can be used for example to ignore anything below a ground plane.
111 // Note: Assumed to be in world space
113
114 // Optional function to define a bias (scalar multiplier) for the ReduceRadiusMargin value, to support scaling the tolerance based on location or direction to surfaces.
115 // The custom method takes the reference mesh, nearest triangle ID on that mesh, and the query position,
116 // and returns a scale factor between 0 and 1 to apply to the ReduceRadiusMargin
118
119 // Margin scales should be between this value and 1.0. When the MinCustomMarginScale is 1.0, no custom scaling is applied.
120 // Should be greater than 0. Note that the sampling will be more expensive to compute for smaller minimum scale values.
122
123 // @return the scale factor that has been applied by Rescale()
125 {
126 return AppliedScaleFactor;
127 }
128
129 UE_DEPRECATED(5.4, "Use SetResultTransform instead")
130 void Rescale(double ScaleFactor)
131 {
132 RescaleSettings(ScaleFactor);
133 }
134
136 {
137 RescaleSettings(ResultTransform.GetScale3D().X / InResultTransform.GetScale3D().X);
138 ResultTransform = InResultTransform;
139 }
141 {
142 return ResultTransform;
143 }
144
145 // Make sure the settings values are in valid ranges
146 void Sanitize()
147 {
148 TargetNumSamples = FMath::Max(1, TargetNumSamples);
149 MinSpacing = FMath::Max(0.0, MinSpacing);
150 ReduceRadiusMargin = FMath::Max(0.0, ReduceRadiusMargin);
151 MinRadius = FMath::Max(0.0, MinRadius);
154 }
155
156 // helper to evaluate OptionalObstacleSDF for local positions
157 inline double ObstacleDistance(const FVector3d& LocalPos) const
158 {
160 FVector3d WorldPos = ResultTransform.TransformPosition(LocalPos);
162 return WorldSD * AppliedScaleFactor;
163 }
164
165private:
166
167 // Track how the settings have been rescaled
168 double AppliedScaleFactor = 1;
169
170 // Track how to transform back to the original space
171 FTransform ResultTransform = FTransform::Identity;
172
173 void RescaleSettings(double ScaleFactor)
174 {
175 MinSpacing *= ScaleFactor;
176 ReduceRadiusMargin *= ScaleFactor;
177 MinRadius *= ScaleFactor;
178 AppliedScaleFactor *= ScaleFactor;
179 }
180};
181
182// Define a volume with a set of spheres
184{
185public:
186
187 inline int32 Num() const
188 {
189 return Position.Num();
190 }
191
192 inline FVector3d GetCenter(int32 Idx) const
193 {
194 return Position[Idx];
195 }
196
197 inline double GetRadius(int32 Idx) const
198 {
199 return Radius[Idx];
200 }
201
202 inline void SetRadius(int32 Idx, double UpdateRadius)
203 {
204 Radius[Idx] = UpdateRadius;
205 }
206
207 // Add spheres covering the negative space of the given fast winding tree
208 // @param Spatial Fast winding tree of the reference mesh, used to compute negative space
209 // @param Settings Settings controlling how negative space is computed
210 // @param bHasFlippedTriangles Whether the mesh referenced by Spatial has reversed triangle windings
211 // @return true if any spheres were added
213
214 // Note: This version of AddNegativeSpace assumed the input had flipped triangle orientations
215 UE_DEPRECATED(5.4, "Use the version of this function with a bHasFlippedTriangles parameter")
217 {
218 return AddNegativeSpace(Spatial, Settings, true);
219 }
220
221 void Reset()
222 {
223 Position.Reset();
224 Radius.Reset();
225 }
226
228 {
229 Position.Append(Other.Position);
230 Radius.Append(Other.Radius);
231 }
232
233 // Remove spheres with radius below a threshold
234 void RemoveSmaller(double MinRadius)
235 {
236 for (int32 Idx = 0; Idx < Radius.Num(); ++Idx)
237 {
238 if (Radius[Idx] < MinRadius)
239 {
241 Position.RemoveAtSwap(Idx, EAllowShrinking::No);
242 --Idx;
243 }
244 }
245 }
246
248 {
249 const int32 AddCount = Spheres.Num();
250 const int32 OrigCount = Position.Num();
251 Position.SetNum(AddCount + OrigCount);
252 Radius.SetNum(AddCount + OrigCount);
253 for (int32 Idx = 0; Idx < AddCount; ++Idx)
254 {
255 Position[Idx + OrigCount] = Spheres[Idx].Center;
256 Radius[Idx + OrigCount] = Spheres[Idx].W;
257 }
258 }
259
261 {
262 Position.Add(InCenter);
263 Radius.Add(InRadius);
264 }
265
266 // Apply transform to spheres
267 // Note: Non-uniform scales will scale the radius by the smallest scale axis's magnitude (matching how physics collision transforms spheres)
269 {
270 TransformRange(0, Position.Num(), Transform);
271 }
272
273 // Append spheres from Other w/ the given Transform
274 // Note: Non-uniform scales will scale the radius by the smallest scale axis's magnitude (matching how physics collision transforms spheres)
276 {
277 int32 AppendStart = Position.Num();
278 Position.Append(Other.Position);
279 Radius.Append(Other.Radius);
280 TransformRange(AppendStart, Position.Num(), Transform);
281 }
282
283private:
284 // Sphere centers
285 TArray<FVector3d> Position;
286 // Sphere radii
287 TArray<double> Radius;
288
289 void TransformRange(const int32 Start, const int32 Max, const FTransform& Transform)
290 {
291 for (int32 Idx = Start; Idx < Max; ++Idx)
292 {
293 Position[Idx] = Transform.TransformPosition(Position[Idx]);
294 }
295 double RadiusScale = Transform.GetScale3D().GetAbsMin();
296 for (int32 Idx = Start; Idx < Max; ++Idx)
297 {
298 Radius[Idx] *= RadiusScale;
299 }
300 }
301};
302
303
304
306{
307
308public:
309
313
314 FConvexDecomposition3(const FDynamicMesh3& SourceMesh, bool bMergeEdges = true)
315 {
316 InitializeFromMesh(SourceMesh, bMergeEdges);
317 }
318
320 {
321 // Whether to attempt to merge boundary edges before processing
322 bool bMergeEdges = true;
323
324 // If greater than zero, we can 'inflate' the input shape by this amount along any degenerate axes in cases where the hull failed to construct due to the input being coplanar/colinear
325 // Note: If passed to the FConvexDecomposition3 constructor, will also set the similar ThickenAfterHullFailure
326 // member, which applies to generated parts of the decomposition.
328
329 // CustomPreprocess takes the mesh to process, and that mesh's bounding box, and updates the mesh in place
330 // Applied after discarding attributes and applying Merge Edges (if enabled)
331 // Can be used e.g. to simplify/repair/solidify the input
333 };
334
336 {
338 InitializeFromMesh(SourceMesh, Options);
339 }
340
345 {
346 if (!ensureMsgf(Decomposition.Num() == 1 && !Decomposition[0].IsCompact(), TEXT("This method must be called after initializing with the input mesh, and before the decomposition has been computed.")))
347 {
348 return false;
349 }
350 return Decomposition[0].InternalGeo.IsClosed();
351 }
352
362
370
371 GEOMETRYCORE_API void InitializeFromMesh(const FDynamicMesh3& SourceMesh, bool bMergeEdges);
372 GEOMETRYCORE_API void InitializeFromMesh(const FDynamicMesh3& SourceMesh, const FPreprocessMeshOptions& Options);
373
389 GEOMETRYCORE_API void InitializeFromIndexMesh(TArrayView<const FVector3f> Vertices, TArrayView<const FIntVector> Faces, const FPreprocessMeshOptions& Options, int32 FaceVertexOffset = 0);
390
397
398 //
399 // Settings
400 //
401
402 // Note we automatically transform the input to a centered-unit-cube space, and tolerances are measured in that space
403 // In other words, distance-based tolerances are expressed as a fraction of the bounding box max axis
404
405 // Threshold for considering two convex parts close enough to consider merging
406 double ProximityTolerance = 1e-3;
407 // Threshold for considering two components to be touching
409 // Maximum 'on plane' distance for points during planar cuts
410 double OnPlaneTolerance = 1e-7;
411
412 // Scale factor for error on the largest axis; slightly favoring cutting on the largest axis helps get more consistent result when no initial cut will reduce error (e.g. a torus)
414
415 // Angle at edge above which we take 5 sample planes instead of 3, to better cover the wider range (expressed in degrees)
417 // Angle at edge above which we don't sample it as a convex edge (expressed in degrees)
419
420 // A bias term to favor merging away 'too thin' parts before merging other parts, expressed as a volume in units s.t. the longest axis of the original input bounding box is 1 unit long
421 // Because these merges *must* be done, it's generally safer to do them earlier, rather than hoping the error associated with them will go down after other merges are performed
423
424 // Maximum number of convex edges to sample for possible cutting planes when calling SplitWorst() to generate an initial convex decomposition
425 // Larger values will cost more to run but can let the algorithm find a cleaner decomposition
427
428 // Whether to, after each split, also detect whether a part is made up of disconnected pieces and further split them if so
430
431 // Whether to treat the input mesh as a solid shape -- controls whether, e.g., a hole-fill is performed after splitting the mesh to close off the resulting parts
432 bool bTreatAsSolid = true;
433
434 // If greater than zero, we can 'inflate' the input shape by this amount along any degenerate axes in cases where the hull failed to construct due to the input being coplanar/colinear.
435 // Note: This should be less than the smallest tolerance used negative space spheres. Do not use this parameter to control minimum thickness of the output shapes; that can be better enforced later (after merges).
437
438
439 // If > 0, search for best merges will be restricted to a greedy local search after testing this many connections. Helpful when there are many potential merges.
441
442 // TODO: Provide hull approximation options?
443
444
456 GEOMETRYCORE_API void Compute(int32 NumOutputHulls, int32 NumAdditionalSplits = 10, double ErrorTolerance = 0.0, double MinThicknessTolerance = 0, int32 MaxOutputHulls = -1, bool bOnlySplitIfNegativeSpaceCovered = false);
457
458 // Split the worst convex part, and return the increase in the total number of convex parts after splitting (can be more than 1 if result has multiple separate connected components)
459 // Note: could return 0 if no splits were possible
460 // @param bCanSkipUnreliableGeoVolumes if true, don't split hulls where we have questionable geometry volume results, unless there is no hull with good geometry volume results
461 // @param bOnlySplitIfNegativeSpaceCovered if true, don't split hulls unless they overlap with some covered Negative Space (stored in the corresponding member variable)
462 // @param MinSplitSize if > 0, don't split hulls with max bounds dimension lower than this
463 GEOMETRYCORE_API int32 SplitWorst(bool bCanSkipUnreliableGeoVolumes = false, double ErrorTolerance = 0.0, bool bOnlySplitIfNegativeSpaceCovered = false, double MinSplitSizeInWorldSpace = -1);
464
465 struct FConvexPart;
466
468 {
469 // Desired number of output parts
471 // If > 0, allow merging parts with error less than this tolerance
472 double ErrorTolerance = 0;
473 // Whether ErrorTolerance is allowed to keep merging below the TargetNumParts
475 // If > 0, maximum number of output parts; overrides ErrorTolerance and TargetNumParts if they would create more parts than this
477
478 // Optionally specify a minimum thickness (in cm) for convex parts; parts below this thickness will always be merged away. Overrides TargetNumParts and ErrorTolerance when needed.
480 // Allow the algorithm to discard underlying geometry once it will no longer be used, resulting in a smaller representation and faster merges
481 bool bAllowCompact = true;
482 // Require all hulls to have associated triangles after MergeBest is completed. (If using InitializeFromHulls, will need to triangulate any un-merged hulls.)
484
485 // Optional representation of negative space that should not be covered by merges
487 // Optional transform from space of the convex hulls into the space of the sphere covering; if not provided, assume spheres are in the same coordinate space as the hulls
489
490 // Optional callback, to be called when two parts are merged. Takes the original (pre-merge) convex decomposition part indices as input.
492
493 // Optional custom function to control whether parts are allowed to merge
495 };
496
497 // Merge the pairs of convex hulls in the decomposition that will least increase the error. Intermediate results can be used across merges, so it is best to do all merges in one call.
498 // @param TargetNumParts The target number of parts for the decomposition; will be overriden by non-default ErrorTolerance or MinPartThickness
499 // @param ErrorTolerance If > 0, continue to merge (if there are possible merges) until the resulting error would be greater than this value. Overrides TargetNumParts as the stopping condition.
500 // Note: ErrorTolerance is expressed in cm, and will be cubed for volumetric error.
501 // @param MinPartThickness Optionally specify a minimum thickness (in cm) for convex parts; parts below this thickness will always be merged away. Overrides TargetNumParts and ErrorTolerance when needed.
502 // Note: These parts may be further split so they can be merged into multiple hulls
503 // @param bAllowCompact Allow the algorithm to discard underlying geometry once it will no longer be used, resulting in a smaller representation & faster merges
504 // @param bRequireHullTriangles Require all hulls to have associated triangles after MergeBest is completed. (If using InitializeFromHulls, will need to triangulate any un-merged hulls.)
505 // @param MaxOutputHulls If > 0, maximum number of convex hulls to generate. Overrides ErrorTolerance and TargetNumParts when needed
506 // @param OptionalNegativeSpace Optional representation of negative space that should not be covered by merges
507 // @param OptionalNegativeSpaceTransform Optional transform from space of the convex hulls into the space of the sphere covering; if not provided, assume spheres are in the same coordinate space as the hulls
508 // @return The number of merges performed
509 GEOMETRYCORE_API int32 MergeBest(int32 TargetNumParts, double ErrorTolerance = 0, double MinThicknessTolerance = 0, bool bAllowCompact = true, bool bRequireHullTriangles = false, int32 MaxOutputHulls = -1,
510 const FSphereCovering* OptionalNegativeSpace = nullptr, const FTransform* OptionalTransformIntoNegativeSpace = nullptr);
511
512 // Merge the pairs of convex hulls in the decomposition that will least increase the error. Intermediate results can be used across merges, so it is best to do all merges in one call.
513 // @return The number of merges performed
515
516 // simple helper to convert an error tolerance expressed in world space to a local-space volume tolerance
523
524 // simple helper to convert an error tolerance expressed in world space to local space
526 {
527 double ScaleFactor = ResultTransform.GetScale().GetMax();
528 if (!ensure(ScaleFactor >= FMathd::Epsilon)) // If ScaleFactor is zero, ResultTransform is trying to collapse all the hulls to a degenerate space -- likely indicates an incorrect ResultTransform
529 {
530 ScaleFactor = FMathd::Epsilon;
531 }
532 double LocalDist = DistTolerance / ScaleFactor;
533 return LocalDist;
534 }
535
536 // Compact the decomposition representation to the minimal needed for output: Just the hull vertices and triangles, no internal geometry
537 // This will prevent some further processing on the representation; to ensure it is called only when the geometry is no longer needed,
538 // instead of calling this directly, call MergeBest with bAllowCompact=true
539 void Compact()
540 {
542 {
543 Part.Compact();
544 }
545 }
546
547 //
548 // Results
549 //
550
552 {
553 return Decomposition.Num();
554 }
555
558 {
559 return Decomposition[HullIdx].HullTriangles;
560 }
561
562 template<typename RealType>
564 {
565 TArray<TVector<RealType>> Vertices;
566 Vertices.SetNum(Decomposition[HullIdx].InternalGeo.MaxVertexID());
567 for (int32 VID = 0; VID < Decomposition[HullIdx].InternalGeo.MaxVertexID(); VID++)
568 {
569 if (Decomposition[HullIdx].InternalGeo.IsVertex(VID))
570 {
571 Vertices[VID] = (TVector<RealType>) ResultTransform.TransformPosition(Decomposition[HullIdx].InternalGeo.GetVertex(VID));
572 }
573 }
574 return Vertices;
575 }
576
578 {
580 for (int32 VID = 0; VID < Decomposition[HullIdx].InternalGeo.MaxVertexID(); VID++)
581 {
582 if (Decomposition[HullIdx].InternalGeo.IsVertex(VID))
583 {
585 }
586 else
587 {
588 HullMesh.AppendVertex(FVector3d::ZeroVector);
589 }
590 }
591 for (const FIndex3i& Tri : Decomposition[HullIdx].HullTriangles)
592 {
593 HullMesh.AppendTriangle(Tri);
594 }
595 return HullMesh;
596 }
597
598 // Get the non-hull geometry underlying a part of the convex decomposition
600 {
601 return Decomposition[HullIdx].InternalGeo;
602 }
603
605 {
606 return Decomposition[HullIdx].HullSourceID;
607 }
608
610 {
611 int32 Count = 0;
612 for (int32 HullIdx = 0; HullIdx < Decomposition.Num(); ++HullIdx)
613 {
614 Count += int32(Decomposition[HullIdx].HullSourceID < 0);
615 }
616 return Count;
617 }
618
619 // Representation of a convex hull in the decomposition + associated information to help further split or merge
621 {
623 FConvexPart(const FDynamicMesh3& SourceMesh, bool bMergeEdges, FTransformSRT3d& TransformOut);
627
628 // Allow direct construction of a compact part (e.g. to allow construction of a pre-existing convex hull)
631
632 void Reset()
633 {
635 HullTriangles.Reset();
636 HullPlanes.Reset();
637 HullSourceID = -1;
639 HullVolume = 0;
640 GeoVolume = 0;
641 SumHullsVolume = -FMathd::MaxReal;
644 HullError = FMathd::MaxReal;
645 bIsCompact = false;
646 bFailed = false;
648 bMustMerge = false;
649 }
650
651 // Underlying geometry represented by the convex part
652 // Note: If IsCompact(), this will only store vertices
654
655 inline bool IsCompact() const
656 {
657 return bIsCompact;
658 }
659
660 inline bool IsFailed() const
661 {
662 return bFailed;
663 }
664
666 TArray<FPlane3d> HullPlanes; // 1:1 with HullTriangles
667
668 int32 HullSourceID = -1; // Optional ID, cleared on merge, to track the origin of un-merged hulls
669
670 // Indices of NegativeSpace spheres that are overlapped by the part
672
673 // Measurements of the geo and hull, to be used when evaluating potential further splits
674 double HullVolume = 0, GeoVolume = 0;
675 double SumHullsVolume = -FMathd::MaxReal; // Sum of volume of any hulls that have been merged to form this hull; only valid if the FConvexPart was created by merging
676 FVector3d GeoCenter = FVector3d::ZeroVector; // Some central point of the geometry (e.g., an average of vertices)
679 bool bSplitFailed = false; // flag indicating that cutting has been attempted and failed, so the part should not be considered for splitting
680
681 // Flag indicating the hull should be merged into another part during a MergeBest() call
682 bool bMustMerge = false;
683
684 // Approximate value indicating how badly the hull mismatches the input geometry
685 double HullError = FMathd::MaxReal;
686
687 void ComputeHullPlanes();
688
689 // get the depth of a point inside the hull (positive values are inside the hull, negative outside)
691 {
692 int32 NumPlanes = HullPlanes.Num();
693 ensure(HullTriangles.Num() == NumPlanes);
694 if (NumPlanes == 0)
695 {
696 return 0;
697 }
698 double MaxDist = -FMathd::MaxReal;
699 for (int32 Idx = 0; Idx < NumPlanes; Idx++)
700 {
701 const FPlane3d& Plane = HullPlanes[Idx];
702 if (Plane.Normal == FVector3d::ZeroVector)
703 {
704 continue;
705 }
706 double Dist = Plane.DistanceTo(Pt);
707 MaxDist = FMath::Max(Dist, MaxDist);
708 }
709 return MaxDist == -FMathd::MaxReal ? 0 : -MaxDist;
710 }
711
712 // Helper to create hull after InternalGeo is set
713 bool ComputeHull(bool bComputePlanes = true, double ThickenAfterHullFailureInLocalSpace = 0.0);
714
715 // Helper to compute volumes, centroid, bounds, etc after the convex part is initialized
716 void ComputeStats();
717
718 void Compact();
719
720 protected:
721 bool bIsCompact = false;
722 bool bFailed = false;
723
724 private:
725 // helper to initialize the part from the already-set InternalGeo member; used to support constructors
727 };
728
729 // All convex hulls parts in the convex decomposition
730 // Note this must be an indirect array, not a TArray, because FConvexPart holds an FDynamicMesh3 mesh, which is not trivially movable
732
735
736 // Edge in a graph of merge candidates, indicating which Decomposition parts could be merged together
737 // Note a proximity link does not guarantee that the geometry (or convex hulls) are touching
739 {
740 FProximity() = default;
743
744 FIndex2i Link{ -1, -1 };
745
746 // the shared plane between the two hulls (because adjacent hulls are formed by planar cuts in the splitting step)
747 // Note: Plane becomes invalid in the merge-up phase; it is used to accelerate filtering in the split-down phase
749
750 // Whether the geometry is separated by Plane
751 bool bPlaneSeparates = false;
752
753 // Whether this merge can be allowed (e.g. has not been ruled out by negative space)
754 bool bIsValidLink = true;
755
756 // What the volume of the convex hull would be if we merged these two parts
758
760 {
761 if (!HasMergedVolume() || !DecompositionIn.IsValidIndex(Link.A) || !DecompositionIn.IsValidIndex(Link.B))
762 {
763 return FMathd::MaxReal;
764 }
765 ensure(DecompositionIn[Link.A].SumHullsVolume != -FMathd::MaxReal && DecompositionIn[Link.B].SumHullsVolume != -FMathd::MaxReal);
766 return MergedVolume - DecompositionIn[Link.A].SumHullsVolume - DecompositionIn[Link.B].SumHullsVolume;
767 }
768
769 bool HasMergedVolume() const
770 {
772 }
777
778 constexpr double VolumeNotComputed() const { return FMathd::MaxReal; }
779
780 };
781
782 // All potential merge edges between Decomposition FConvexParts
784
785 // Mapping from Decomposition indices to Proximity indices
787
788 // Helper function to delete a proximity relationship, and fix index references to account for the new array ordering
789 // @param ToRemove Indices of proximities that will be removed; note this function is destructive to this array
790 // @param bDeleteMapReferences If true, also update references in the DecompositionToProximity map
792
793 // Helper function to update all proximity data after splitting an FConvexPart apart
794 // @param SplitIdx The index of the FConvexPart that has been split into multiple parts. Now contains the first new part.
795 // @param NewIdxStart The first index in the Decomposition array of new FConvexParts aside from SplitIdx. Everything from this to the end of the Decomposition array must be new.
796 // @param CutPlane The plane used for the split
797 // @param SecondSideIdxStart The first index in the Decomposition array of new FConvexParts that were on the opposite side of the plane from SplitIdx. Will be different from NewIdxStart only if the first part was split into multiple components.
798 // @param OrigHullVolume The volume of the convex hull *before* the split was performed -- used to precompute the merge cost.
800
801 // Fix overlaps between current Decomposition and associated NegativeSpace, using the saved associations in the FConvexPart::OverlapsNegativeSpace
802 // Note the tolerance and min radius may not be the same as originally used to generate the negative space; they should just be large enough to
803 // avoid 'locking' the merge step for any hulls that still overlap negative space after splitting
804 GEOMETRYCORE_API void FixHullOverlapsInNegativeSpace(double NegativeSpaceTolerance = UE_DOUBLE_KINDA_SMALL_NUMBER, double NegativeSpaceMinRadius = UE_DOUBLE_KINDA_SMALL_NUMBER);
805
806 // Tests if a convex part overlaps a sphere
807 // @param Part Convex part to test for overlap with sphere
808 // @param Center Center of sphere
809 // @param Radius Radius of sphere
810 // @param TransformIntoSphereSpace If non-null, transform from convex hull to sphere coordinate space. Otherwise, hulls and spheres are assumed to be in the same space.
811 // @param OutDistanceSq If non-null, and there is an overlap, will be filled with the squared distance from the sphere center to the convex hull (0 if the center is inside the hull). If no overlap is found, value is not meaningful.
812 // @return true if the Part overlaps the sphere, false otherwise
813 GEOMETRYCORE_API static bool ConvexPartVsSphereOverlap(const FConvexPart& Part, FVector3d Center, double Radius, const FTransform* TransformIntoSphereSpace = nullptr, double* OutDistanceSq = nullptr);
814
815 // Get the current negative space tracked by the convex decomposition
816 // Note: Does not include externally-managed negative space passed to MergeBest.
817 // Note: Direct access is const-only; use InitializeNegativeSpace() to set the negative space.
819 {
820 return NegativeSpace;
821 }
822
823private:
824
825 // Initialize mappings from Decomposition parts to NegativeSpace indices (FConvexPart::OverlapsNegativeSpace)
826 void InitNegativeSpaceConvexPartMapping();
827
828 // Negative space to attempt to protect; can be referenced by the Decomposition parts
829 FSphereCovering NegativeSpace;
830
831 // Helper to implement SplitWorst
832 bool SplitWorstHelper(bool bCanSkipUnreliableGeoVolumes, double ErrorTolerance, bool bOnlySplitIfNegativeSpaceCovered, double MinSplitSizeInWorldSpace);
833};
834
835} // end namespace UE::Geometry
836} // end namespace UE
837
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define ensure( InExpression)
Definition AssertionMacros.h:464
double HullVolumes[2]
Definition ConvexDecomposition3.cpp:818
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::Math::TVector< double > FVector3d
Definition MathFwd.h:60
@ Compute
Definition MetalRHIPrivate.h:232
const bool
Definition NetworkReplayStreaming.h:178
#define UE_DOUBLE_KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:140
uint8_t uint8
Definition binka_ue_file_header.h:8
Definition ArrayView.h:139
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_FORCEINLINE_HINT void RemoveAtSwap(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2185
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
void Append(const TArray< OtherElementType, OtherAllocatorType > &Source)
Definition Array.h:2412
Definition AssetRegistryState.h:50
Definition AndroidPlatformMisc.h:14
Definition IndirectArray.h:20
Definition FunctionFwd.h:19
Definition ConvexDecomposition3.h:306
int32 RestrictMergeSearchToLocalAfterTestNumConnections
Definition ConvexDecomposition3.h:440
bool bSplitDisconnectedComponents
Definition ConvexDecomposition3.h:429
double ConnectedComponentTolerance
Definition ConvexDecomposition3.h:408
GEOMETRYCORE_API void InitializeProximityFromDecompositionBoundingBoxOverlaps(double BoundsExpandByMinDimFactor, double BoundsExpandByMaxDimFactor, double MinBoundsExpand)
Definition ConvexDecomposition3.cpp:2338
const int32 GetHullSourceID(int32 HullIdx) const
Definition ConvexDecomposition3.h:604
double ConvertDistanceToleranceToLocalSpace(double DistTolerance) const
Definition ConvexDecomposition3.h:525
double ConvexEdgeAngleMoreSamplesThreshold
Definition ConvexDecomposition3.h:416
const FDynamicMesh3 & GetInternalMesh(int32 HullIdx) const
Definition ConvexDecomposition3.h:599
GEOMETRYCORE_API void InitializeFromMesh(const FDynamicMesh3 &SourceMesh, bool bMergeEdges)
Definition ConvexDecomposition3.cpp:1584
const FSphereCovering & GetNegativeSpace() const
Definition ConvexDecomposition3.h:818
TArray< TVector< RealType > > GetVertices(int32 HullIdx, bool bTransformedToOutput=true) const
Definition ConvexDecomposition3.h:563
int32 MaxConvexEdgePlanes
Definition ConvexDecomposition3.h:426
const int32 CountMergedParts() const
Definition ConvexDecomposition3.h:609
TIndirectArray< FConvexPart > Decomposition
Definition ConvexDecomposition3.h:731
bool IsInputSolid()
Definition ConvexDecomposition3.h:344
FDynamicMesh3 GetHullMesh(int32 HullIdx) const
Definition ConvexDecomposition3.h:577
int32 NumHulls() const
Definition ConvexDecomposition3.h:551
GEOMETRYCORE_API void UpdateProximitiesAfterSplit(int32 SplitIdx, int32 NewIdxStart, FPlane3d CutPlane, int32 SecondSideIdxStart, double OrigHullVolume)
Definition ConvexDecomposition3.cpp:2177
double OnPlaneTolerance
Definition ConvexDecomposition3.h:410
FConvexDecomposition3(const FDynamicMesh3 &SourceMesh, const FPreprocessMeshOptions &Options)
Definition ConvexDecomposition3.h:335
double BiasToRemoveTooThinParts
Definition ConvexDecomposition3.h:422
double ConvexEdgeAngleThreshold
Definition ConvexDecomposition3.h:418
GEOMETRYCORE_API void DeleteProximity(TArray< int32 > &&ToRemove, bool bDeleteMapReferences)
Definition ConvexDecomposition3.cpp:2891
FConvexDecomposition3()
Definition ConvexDecomposition3.h:310
GEOMETRYCORE_API void InitializeFromHulls(int32 NumHulls, TFunctionRef< double(int32)> HullVolumes, TFunctionRef< int32(int32)> HullNumVertices, TFunctionRef< FVector3d(int32, int32)> HullVertices, TArrayView< const TPair< int32, int32 > > Proximity)
Definition ConvexDecomposition3.cpp:2299
static GEOMETRYCORE_API bool ConvexPartVsSphereOverlap(const FConvexPart &Part, FVector3d Center, double Radius, const FTransform *TransformIntoSphereSpace=nullptr, double *OutDistanceSq=nullptr)
Definition ConvexDecomposition3.cpp:102
TMultiMap< int32, int32 > DecompositionToProximity
Definition ConvexDecomposition3.h:786
FConvexDecomposition3(const FDynamicMesh3 &SourceMesh, bool bMergeEdges=true)
Definition ConvexDecomposition3.h:314
FTransformSRT3d ResultTransform
Transform taking the result hull vertices back to the original space of the inputs; automatically app...
Definition ConvexDecomposition3.h:734
double CutLargestAxisErrorScale
Definition ConvexDecomposition3.h:413
TArray< FIndex3i > const & GetTriangles(int32 HullIdx) const
Definition ConvexDecomposition3.h:557
GEOMETRYCORE_API int32 SplitWorst(bool bCanSkipUnreliableGeoVolumes=false, double ErrorTolerance=0.0, bool bOnlySplitIfNegativeSpaceCovered=false, double MinSplitSizeInWorldSpace=-1)
Definition ConvexDecomposition3.cpp:1874
GEOMETRYCORE_API bool InitializeNegativeSpace(const FNegativeSpaceSampleSettings &Settings, TArrayView< const FVector3d > RequestedSamples=TArrayView< const FVector3d >())
Definition ConvexDecomposition3.cpp:1713
double ProximityTolerance
Definition ConvexDecomposition3.h:406
TArray< FProximity > Proximities
Definition ConvexDecomposition3.h:783
GEOMETRYCORE_API void FixHullOverlapsInNegativeSpace(double NegativeSpaceTolerance=UE_DOUBLE_KINDA_SMALL_NUMBER, double NegativeSpaceMinRadius=UE_DOUBLE_KINDA_SMALL_NUMBER)
Definition ConvexDecomposition3.cpp:1747
GEOMETRYCORE_API void InitializeFromIndexMesh(TArrayView< const FVector3f > Vertices, TArrayView< const FIntVector > Faces, bool bMergeEdges, int32 FaceVertexOffset=0)
Definition ConvexDecomposition3.cpp:1692
GEOMETRYCORE_API int32 MergeBest(int32 TargetNumParts, double ErrorTolerance=0, double MinThicknessTolerance=0, bool bAllowCompact=true, bool bRequireHullTriangles=false, int32 MaxOutputHulls=-1, const FSphereCovering *OptionalNegativeSpace=nullptr, const FTransform *OptionalTransformIntoNegativeSpace=nullptr)
Definition ConvexDecomposition3.cpp:2380
double ThickenAfterHullFailure
Definition ConvexDecomposition3.h:436
double ConvertDistanceToleranceToLocalVolumeTolerance(double DistTolerance) const
Definition ConvexDecomposition3.h:517
bool bTreatAsSolid
Definition ConvexDecomposition3.h:432
void Compact()
Definition ConvexDecomposition3.h:539
Definition DynamicMesh3.h:108
GEOMETRYCORE_API int AppendVertex(const FVertexInfo &VertInfo)
Definition DynamicMesh3_Edits.cpp:9
GEOMETRYCORE_API void Clear()
Definition DynamicMesh3.cpp:446
Definition ConvexDecomposition3.h:184
void Reset()
Definition ConvexDecomposition3.h:221
FVector3d GetCenter(int32 Idx) const
Definition ConvexDecomposition3.h:192
void SetRadius(int32 Idx, double UpdateRadius)
Definition ConvexDecomposition3.h:202
double GetRadius(int32 Idx) const
Definition ConvexDecomposition3.h:197
void Append(const FSphereCovering &Other)
Definition ConvexDecomposition3.h:227
void RemoveSmaller(double MinRadius)
Definition ConvexDecomposition3.h:234
void AppendTransformed(const FSphereCovering &Other, const FTransform &Transform)
Definition ConvexDecomposition3.h:275
int32 Num() const
Definition ConvexDecomposition3.h:187
void AppendSpheres(TArrayView< const UE::Math::TSphere< double > > Spheres)
Definition ConvexDecomposition3.h:247
GEOMETRYCORE_API bool AddNegativeSpace(const TFastWindingTree< FDynamicMesh3 > &Spatial, const FNegativeSpaceSampleSettings &Settings, bool bHasFlippedTriangles)
Definition ConvexDecomposition3.cpp:249
void AddSphere(FVector3d InCenter, double InRadius)
Definition ConvexDecomposition3.h:260
void ApplyTransform(const FTransform &Transform)
Definition ConvexDecomposition3.h:268
Definition FastWinding.h:316
static TTransformSRT3< double > Identity()
Definition TransformTypes.h:83
const TVector< RealType > & GetScale() const
Definition TransformTypes.h:147
TVector< RealType2 > TransformPosition(const TVector< RealType2 > &P) const
Definition TransformTypes.h:217
EConvexErrorMethod
Definition ConvexDecomposition3.h:30
Definition AdvancedWidgetsModule.cpp:13
static constexpr UE_FORCEINLINE_HINT T Clamp(const T X, const T MinValue, const T MaxValue)
Definition UnrealMathUtility.h:592
Definition Tuple.h:652
Definition ConvexDecomposition3.h:621
FAxisAlignedBox3d Bounds
Definition ConvexDecomposition3.h:677
TArray< FIndex3i > HullTriangles
Definition ConvexDecomposition3.h:665
double GeoVolume
Definition ConvexDecomposition3.h:674
bool bSplitFailed
Definition ConvexDecomposition3.h:679
TArray< int32 > OverlapsNegativeSpace
Definition ConvexDecomposition3.h:671
double SumHullsVolume
Definition ConvexDecomposition3.h:675
double GetHullDepth(FVector3d Pt)
Definition ConvexDecomposition3.h:690
FVector3d GeoCenter
Definition ConvexDecomposition3.h:676
void Compact()
Definition ConvexDecomposition3.cpp:1550
bool ComputeHull(bool bComputePlanes=true, double ThickenAfterHullFailureInLocalSpace=0.0)
Definition ConvexDecomposition3.cpp:1807
int32 HullSourceID
Definition ConvexDecomposition3.h:668
bool bFailed
Definition ConvexDecomposition3.h:722
double HullError
Definition ConvexDecomposition3.h:685
void ComputeStats()
Definition ConvexDecomposition3.cpp:1858
bool bGeometryVolumeUnreliable
Definition ConvexDecomposition3.h:678
TArray< FPlane3d > HullPlanes
Definition ConvexDecomposition3.h:666
void Reset()
Definition ConvexDecomposition3.h:632
bool bIsCompact
Definition ConvexDecomposition3.h:721
bool IsFailed() const
Definition ConvexDecomposition3.h:660
FConvexPart(bool bIsCompact)
Definition ConvexDecomposition3.h:629
FConvexPart()
Definition ConvexDecomposition3.h:622
bool bMustMerge
Definition ConvexDecomposition3.h:682
bool IsCompact() const
Definition ConvexDecomposition3.h:655
double HullVolume
Definition ConvexDecomposition3.h:674
void ComputeHullPlanes()
Definition ConvexDecomposition3.cpp:1838
FDynamicMesh3 InternalGeo
Definition ConvexDecomposition3.h:653
Definition ConvexDecomposition3.h:468
TFunction< void(int32, int32)> MergeCallback
Definition ConvexDecomposition3.h:491
TFunction< bool(const FConvexDecomposition3::FConvexPart &A, const FConvexDecomposition3::FConvexPart &B)> CustomAllowMergeParts
Definition ConvexDecomposition3.h:494
const FTransform * OptionalTransformIntoNegativeSpace
Definition ConvexDecomposition3.h:488
const FSphereCovering * OptionalNegativeSpace
Definition ConvexDecomposition3.h:486
bool bAllowCompact
Definition ConvexDecomposition3.h:481
bool bRequireHullTriangles
Definition ConvexDecomposition3.h:483
int32 TargetNumParts
Definition ConvexDecomposition3.h:470
double ErrorTolerance
Definition ConvexDecomposition3.h:472
int32 MaxOutputHulls
Definition ConvexDecomposition3.h:476
bool bErrorToleranceOverridesNumParts
Definition ConvexDecomposition3.h:474
double MinThicknessTolerance
Definition ConvexDecomposition3.h:479
double ThickenInputAfterHullFailure
Definition ConvexDecomposition3.h:327
TUniqueFunction< void(FDynamicMesh3 &Mesh, const FAxisAlignedBox3d &Bounds)> CustomPreprocess
Definition ConvexDecomposition3.h:332
bool bMergeEdges
Definition ConvexDecomposition3.h:322
Definition ConvexDecomposition3.h:739
constexpr double VolumeNotComputed() const
Definition ConvexDecomposition3.h:778
bool bPlaneSeparates
Definition ConvexDecomposition3.h:751
FProximity(const FIndex2i &Link, const FPlane3d &Plane, bool bPlaneSeparates)
Definition ConvexDecomposition3.h:741
bool HasMergedVolume() const
Definition ConvexDecomposition3.h:769
void ClearMergedVolume()
Definition ConvexDecomposition3.h:773
double GetMergeCost(const TIndirectArray< FConvexPart > &DecompositionIn) const
Definition ConvexDecomposition3.h:759
bool bIsValidLink
Definition ConvexDecomposition3.h:754
FPlane3d Plane
Definition ConvexDecomposition3.h:748
double MergedVolume
Definition ConvexDecomposition3.h:757
FIndex2i Link
Definition ConvexDecomposition3.h:744
Definition IndexTypes.h:27
int A
Definition IndexTypes.h:32
int B
Definition IndexTypes.h:32
Definition IndexTypes.h:158
Definition ConvexDecomposition3.h:38
void Sanitize()
Definition ConvexDecomposition3.h:146
void ApplyDefaults(EConfigDefaults Settings=EConfigDefaults::Latest)
Definition ConvexDecomposition3.h:62
double VoxelExpandBoundsFactor
Definition ConvexDecomposition3.h:108
bool bRequireSearchSampleCoverage
Definition ConvexDecomposition3.h:94
bool bAllowSamplesInsideMesh
Definition ConvexDecomposition3.h:105
int32 TargetNumSamples
Definition ConvexDecomposition3.h:76
double MinCustomMarginScale
Definition ConvexDecomposition3.h:121
bool bOnlyConnectedToHull
Definition ConvexDecomposition3.h:96
bool bDeterministic
Definition ConvexDecomposition3.h:100
double MinSpacing
Definition ConvexDecomposition3.h:79
double MarchingCubesGridScale
Definition ConvexDecomposition3.h:102
double MinRadius
Definition ConvexDecomposition3.h:88
ESampleMethod
Definition ConvexDecomposition3.h:45
EConfigDefaults
Definition ConvexDecomposition3.h:56
int32 MaxVoxelsPerDim
Definition ConvexDecomposition3.h:98
double ObstacleDistance(const FVector3d &LocalPos) const
Definition ConvexDecomposition3.h:157
FNegativeSpaceSampleSettings(int32 TargetNumSamples, double MinSpacing, double ReduceRadiusMargin)
Definition ConvexDecomposition3.h:40
void Rescale(double ScaleFactor)
Definition ConvexDecomposition3.h:130
double ReduceRadiusMargin
Definition ConvexDecomposition3.h:85
void SetResultTransform(FTransform InResultTransform)
Definition ConvexDecomposition3.h:135
bool bAllowSamplesInsideSpheres
Definition ConvexDecomposition3.h:82
FTransform GetResultTransform() const
Definition ConvexDecomposition3.h:140
double GetAppliedScaleFactor() const
Definition ConvexDecomposition3.h:124
TFunction< double(const FDynamicMesh3 &Mesh, int32 NearTID, FVector3d QueryPos)> CustomRadiusMarginScale
Definition ConvexDecomposition3.h:117
ESampleMethod SampleMethod
Definition ConvexDecomposition3.h:73
TFunction< double(FVector Pos)> OptionalObstacleSDF
Definition ConvexDecomposition3.h:112
static TAxisAlignedBox3< double > Empty()
Definition BoxTypes.h:382
double DistanceTo(const UE::Math::TVector< RealType > &P) const
Definition PlaneTypes.h:88
Definition Sphere.h:29
static CORE_API const TTransform< double > Identity
Definition TransformNonVectorized.h:58
TVector< T > GetScale3D() const
Definition TransformNonVectorized.h:1131
UE_FORCEINLINE_HINT TVector< T > TransformPosition(const TVector< T > &V) const
Definition TransformNonVectorized.h:1423
static CORE_API const TVector< double > ZeroVector
Definition Vector.h:79
T GetMax() const
Definition Vector.h:1674
T X
Definition Vector.h:62