UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MeshSpatialSort.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "MathUtil.h"
6#include "MeshQueries.h"
8
9namespace UE
10{
11namespace Geometry
12{
13
14
33template <class TriangleMeshType>
35{
36public:
37
42
47
48 enum class ENestingMethod
49 {
50 InLargestParent, // meshes nest flatly in the largest mesh that contains them (simplest structure, fastest to compute, will never have nests inside nests)
51 InSmallestParent, // meshes nest in the smallest mesh that contains them, capturing nests inside nests
52 };
53
58
63
69
75
76
78
80 {
81 int OuterIndex; // index of the outer (positive volume) shell
82 int ParentIndex = -1; // only used if NestingMethod is InSmallestParent. Index of the mesh that contains the outer index mesh, or -1 if there is no such mesh.
83 TArray<int> InnerIndices; // indices of all meshes contained inside outer shell (unless they are recursively nested inside a child mesh)
84 };
85
90
95
97
110
111 void Compute()
112 {
113 if (!ensure(MeshBounds.Num() == InputMeshes.Num()))
114 {
115 InitBounds();
116 }
117
118 FAxisAlignedBox3d CombinedBounds;
119 for (const FAxisAlignedBox3d& Bounds : MeshBounds)
120 {
121 CombinedBounds.Contain(Bounds);
122 }
123
124 Nests.Empty();
125
126 int32 N = InputMeshes.Num();
127 TArray<int> MeshIndices;
128 MeshIndices.SetNum(N);
129 for (int i = 0; i < N; i++)
130 {
131 MeshIndices[i] = i;
132 }
133
134 // precomputed useful stats on input meshes
135 struct FMeshInfo
136 {
137 double Volume;
138 bool bPositiveVolume;
139 };
141 Info.SetNum(N);
142 double DimScaleFactor = 1.0 / (CombinedBounds.MaxDim() + KINDA_SMALL_NUMBER);
143 for (int i = 0; i < N; i++)
144 {
146 Info[i].bPositiveVolume = SignedVolume >= 0;
147 Info[i].Volume = FMathd::Abs(SignedVolume);
148 }
149
150 MeshIndices.Sort([&Info](int Ind1, int Ind2)
151 {
152 return Info[Ind1].Volume > Info[Ind2].Volume;
153 }
154 );
155
157 Parent.Init(-1, N);
158
159 // From largest mesh to smallest, greedily assign parents where possible
160 // (If not nesting in largest:
161 // If a mesh already has a parent, but a smaller containing parent is found, switch to the new parent)
162 for (int ParentCand = 0; ParentCand + 1 < N; ParentCand++)
163 {
164 int PIdx = MeshIndices[ParentCand];
165 const FMeshInfo& PInfo = Info[PIdx];
168 {
169 continue; // mesh was already contained in a larger mesh
170 }
171
173 {
174 // negative volume meshes can't be an 'outer shell,' so we can skip unless we're looking for nests-in-nests
175 continue;
176 }
177
178 double WindingTestSign = PInfo.bPositiveVolume ? 1 : -1;
181 for (int ChildCand = ParentCand + 1; ChildCand < N; ChildCand++)
182 {
183 int CIdx = MeshIndices[ChildCand];
184 const FMeshInfo& CInfo = Info[CIdx];
186 if (CMesh.VertexCount() == 0)
187 {
188 continue;
189 }
191 {
192 // InLargestParent nesting can't have recursive nests or reassign to smaller parents, so we can skip some tests
193 if ((bOnlyNestNegativeVolumes && CInfo.bPositiveVolume) || Parent[ChildCand] != -1)
194 {
195 continue;
196 }
197 }
199 {
200 FVector3d Vert;
201
202 for (int VID = 0; VID < CMesh.MaxVertexID(); VID++)
203 {
204 if (CMesh.IsVertex(VID))
205 {
206 Vert = CMesh.GetVertex(VID);
207 break;
208 }
209 }
210
211 double WindingNumber = Winding.FastWindingNumber(Vert);
213 {
215 }
216 }
217 else
218 {
219 bool bHasOutsideSample = false;
220 for (int VID = 0; VID < CMesh.MaxVertexID(); VID++)
221 {
222 if (CMesh.IsVertex(VID))
223 {
224 double WindingNumber = Winding.FastWindingNumber(CMesh.GetVertex(VID));
226 {
227 bHasOutsideSample = true;
228 break;
229 }
230 }
231 }
233 {
235 }
236 }
237 }
238 }
239
240 // Build nests from parent relationship
241 TArray<bool> Taken;
242 Taken.SetNumZeroed(N);
243 for (int NestCand = 0; NestCand < N; NestCand++)
244 {
245 int NIdx = MeshIndices[NestCand];
246 if (Taken[NestCand])
247 {
248 continue;
249 }
251 {
253 continue;
254 }
255 FMeshNesting& Nest = Nests.Emplace_GetRef();
256 Nest.OuterIndex = NIdx;
257
259 {
261 if (ParentCand > -1)
262 {
263 Nest.ParentIndex = MeshIndices[ParentCand];
264 }
265 }
266 for (int HoleCand = NestCand + 1; HoleCand < N; HoleCand++)
267 {
268 int MIdx = MeshIndices[HoleCand];
270 {
271 Nest.InnerIndices.Add(MIdx);
272 Taken[HoleCand] = true;
273 }
274 }
275 }
276 }
277
278private:
279
280 void InitBounds()
281 {
283 MeshBounds.Reserve(InputMeshes.Num());
284 for (const TriangleMeshType& Mesh : InputMeshes)
285 {
287 }
288 }
289};
290
291
292} // end namespace UE::Geometry
293} // end namespace UE
int Volume
Definition AndroidPlatformMisc.cpp:380
#define ensure( InExpression)
Definition AssertionMacros.h:464
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
#define KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:67
Definition ArrayView.h:139
UE_FORCEINLINE_HINT constexpr SizeType Num() const
Definition ArrayView.h:380
Definition Array.h:670
void SetNumZeroed(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2340
void Reset(SizeType NewSize=0)
Definition Array.h:2246
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 Init(const ElementType &Element, SizeType Number)
Definition Array.h:3043
UE_NODEBUG void Sort()
Definition Array.h:3418
static RealType Abs(const RealType Value)
Definition MathUtil.h:215
Definition FastWinding.h:316
Definition MeshAABBTree3.h:61
Definition MeshQueries.h:21
static double GetVolumeNonWatertight(const TriangleMeshType &Mesh, double DimScaleFactor=1)
Definition MeshQueries.h:107
Definition MeshSpatialSort.h:35
ENestingMethod NestingMethod
Definition MeshSpatialSort.h:57
bool bOnlyCheckSingleVertexForNesting
Definition MeshSpatialSort.h:74
bool bOnlyParentPostiveVolumes
Definition MeshSpatialSort.h:68
ENestingMethod
Definition MeshSpatialSort.h:49
TArray< FMeshNesting > Nests
Definition MeshSpatialSort.h:89
TMeshSpatialSort()
Definition MeshSpatialSort.h:96
TMeshSpatialSort(TArrayView< const TriangleMeshType > InputMeshes, TArrayView< const FAxisAlignedBox3d > MeshBoundsIn=TArrayView< const FAxisAlignedBox3d >())
Definition MeshSpatialSort.h:98
TArray< int > SkippedMeshIndices
Definition MeshSpatialSort.h:94
bool bOnlyNestNegativeVolumes
Definition MeshSpatialSort.h:62
TArray< FAxisAlignedBox3d > MeshBounds
Definition MeshSpatialSort.h:46
TArrayView< const TriangleMeshType > InputMeshes
Definition MeshSpatialSort.h:41
void Compute()
Definition MeshSpatialSort.h:111
Definition AdvancedWidgetsModule.cpp:13
void Contain(const TVector< RealType > &V)
Definition BoxTypes.h:438
RealType MaxDim() const
Definition BoxTypes.h:598
Outputs.
Definition MeshSpatialSort.h:80
int ParentIndex
Definition MeshSpatialSort.h:82
TArray< int > InnerIndices
Definition MeshSpatialSort.h:83
int OuterIndex
Definition MeshSpatialSort.h:81