UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ConvexHalfEdgeStructureData.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "Chaos/Core.h"
5#include "ChaosArchive.h"
6#include "ChaosCheck.h"
7#include "ChaosLog.h"
10
11namespace Chaos
12{
13 // Default convex structure index traits - assumes signed
14 template<typename T_INDEX>
16 {
17 using FIndex = T_INDEX;
20
21 static_assert(TIsSigned<T_INDEX>::Value, "The default TConvexStructureIndexTraits implementation is only valid for signed T_INDEX");
22 };
23
24 // uint8 uses 255 as InvalidIndex, and therefore supports elements with indices 0...254
25 template<>
32
33 // Convex half-edge structure data.
34 // Uses indices rather than pointers.
35 // Supports different index sizes.
36 template<typename T_INDEX>
38 {
39 public:
40 using FIndex = T_INDEX;
43
46
48
49 // A plane of a convex hull. Each plane has an array of half edges, stored
50 // as an index into the edge list and a count.
52 {
53 FIndex FirstHalfEdgeIndex; // index into HalfEdges
55
57 {
58 return Ar << Value.FirstHalfEdgeIndex << Value.NumHalfEdges;
59 }
60 };
61
62 // Every plane is bounded by a sequence of edges, and every edge should be shared
63 // by two planes. The edges that bound a plane are stored as a sequence of half-edges.
64 // Each half-edge references the starting vertex of the edge, the half-edge
65 // pointing in the opposite direction (belonging to the plane that shares the edge),
66 // and the next half-edge on the same plane.
68 {
69 FIndex PlaneIndex; // index into Planes
70 FIndex VertexIndex; // index into Vertices
71 FIndex TwinHalfEdgeIndex; // index into HalfEdges
72
74 {
75 return Ar << Value.PlaneIndex << Value.VertexIndex << Value.TwinHalfEdgeIndex;
76 }
77 };
78
79 // A vertex of a convex hull. We just store one edge that uses the vertex - the others
80 // can be found via the half-edge links.
82 {
83 FIndex FirstHalfEdgeIndex; // index into HalfEdges
84
86 {
87 return Ar << Value.FirstHalfEdgeIndex;
88 }
89 };
90
91 // We cache 3 planes per vertex since this is the most common request and a major bottleneck in GJK
92 // (SupportCoreScaled -> GetMarginAdjustedVertexScaled -> FindVertexPlanes
98
99 // List of 3 halfedges per vertex for regular convexes
105
106 // Initialize the structure data from the array of vertex indices per plane (in CW or CCW order - it is retained in structure)
107 // If this fails for some reason, the structure data will be invalid (check IsValid())
114
115 // Return true if we can support this convex, based on number of features and maximum index size
117 {
118 int32 HalfEdgeCount = 0;
119 for (int32 PlaneIndex = 0; PlaneIndex < InPlaneVertices.Num(); ++PlaneIndex)
120 {
121 HalfEdgeCount += InPlaneVertices[PlaneIndex].Num();
122 }
123
124 // For a well-formed convex HalfEdgeCount must be larger than NumPlanes and NumVerts, but check them all anyway just in case...
125 return ((HalfEdgeCount <= MaxIndex) && (InPlaneVertices.Num() <= MaxIndex) && (InNumVertices <= MaxIndex));
126 }
127
128
129 bool IsValid() const { return Planes.Num() > 0; }
130 int32 NumPlanes() const { return Planes.Num(); }
131 int32 NumHalfEdges() const { return HalfEdges.Num(); }
132 int32 NumVertices() const { return Vertices.Num(); }
133
134 // Number of unique half-edges (no half edge's twin is in also the list). Should be NumHalfEdges/2
135 int32 NumEdges() const { return Edges.Num(); }
136
137 FPlaneData& GetPlane(int32 PlaneIndex) { return Planes[PlaneIndex]; }
138 const FPlaneData& GetPlane(int32 PlaneIndex) const { return Planes[PlaneIndex]; }
140 const FHalfEdgeData& GetHalfEdge(int32 HalfEdgeIndex) const { return HalfEdges[HalfEdgeIndex]; }
141 int32 GetHalfEdgeIndex(int32 EdgeIndex) const { return Edges[EdgeIndex]; }
142 FVertexData& GetVertex(int32 VertexIndex) { return Vertices[VertexIndex]; }
143 const FVertexData& GetVertex(int32 VertexIndex) const { return Vertices[VertexIndex]; }
144
145 // The number of edges bounding the specified plane
146 int32 NumPlaneHalfEdges(int32 PlaneIndex) const
147 {
148 return GetPlane(PlaneIndex).NumHalfEdges;
149 }
150
151 // The edge index of one of the bounding edges of a plane
152 // PlaneIndex must be in range [0, NumPlanes())
153 // PlaneEdgeIndex must be in range [0, NumPlaneHalfEdges(PlaneIndex))
154 // return value is in range [0, NumHalfEdges())
156 {
157 check(PlaneEdgeIndex >= 0);
159 return GetPlane(PlaneIndex).FirstHalfEdgeIndex + PlaneEdgeIndex;
160 }
161
162 // The number of vertices that bound the specified plane (same as number of half edges)
163 // PlaneIndex must be in range [0, NumPlaneHalfEdges(PlaneIndex))
164 int32 NumPlaneVertices(int32 PlaneIndex) const
165 {
166 return GetPlane(PlaneIndex).NumHalfEdges;
167 }
168
169 // Get the index of one of the vertices bounding the specified plane
170 // PlaneIndex must be in range [0, NumPlanes())
171 // PlaneVertexIndex must be in [0, NumPlaneVertices(PlaneIndex))
172 // return value is in [0, NumVertices())
178
179 // HalfEdgeIndex must be in range [0, NumHalfEdges())
180 // return value is in range [0, NumPlanes())
185
186 // HalfEdgeIndex must be in range [0, NumHalfEdges())
187 // return value is in range [0, NumVertices())
192
193 // HalfEdgeIndex must be in range [0, NumHalfEdges())
194 // return value is in range [0, NumHalfEdges())
199
200 // Get the previous half edge on the same plane
201 // HalfEdgeIndex must be in range [0, NumHalfEdges())
202 // return value is in range [0, NumHalfEdges())
204 {
205 // Calculate the edge index on the plane
206 const int32 PlaneIndex = GetHalfEdge(HalfEdgeIndex).PlaneIndex;
208 return GetPrevPlaneHalfEdge(PlaneIndex, PlaneHalfEdgeIndex);
209 }
210
211 // Get the next half edge on the same plane
212 // HalfEdgeIndex must be in range [0, NumHalfEdges())
213 // return value is in range [0, NumHalfEdges())
215 {
216 // Calculate the edge index on the plane
217 const int32 PlaneIndex = GetHalfEdge(HalfEdgeIndex).PlaneIndex;
219 return GetNextPlaneHalfEdge(PlaneIndex, PlaneHalfEdgeIndex);
220 }
221
222 // Get a vertex in the specified Edge (NOTE: edge index, not half-edge index)
223 // EdgeIndex must be in range [0, NumEdges())
224 // EdgeVertexIndex must be 0 or 1
225 // return value is in range [0, NumVertices())
227 {
228 if (EdgeVertexIndex == 0)
229 {
230 return GetHalfEdgeVertex(Edges[EdgeIndex]);
231 }
232 else
233 {
234 return GetHalfEdgeVertex(GetTwinHalfEdge(Edges[EdgeIndex]));
235 }
236 }
237
238 // Get a plane for the specified Edge (NOTE: edge index, not half-edge index)
239 // EdgeIndex must be in range [0, NumEdges())
240 // EdgePlaneIndex must be 0 or 1
241 // return value is in range [0, NumPlanes())
243 {
244 if (EdgePlaneIndex == 0)
245 {
246 return GetHalfEdgePlane(Edges[EdgeIndex]);
247 }
248 else
249 {
250 return GetHalfEdgePlane(GetTwinHalfEdge(Edges[EdgeIndex]));
251 }
252 }
253
254 // VertexIndex must be in range [0, NumVertices())
255 // return value is in range [0, NumHalfEdges())
257 {
258 return GetVertex(VertexIndex).FirstHalfEdgeIndex;
259 }
260
261 // Iterate over the edges associated with a plane. These edges form the boundary of the plane.
262 // Visitor should return false to halt iteration.
263 // FVisitorType should be a function with signature: bool(int32 HalfEdgeIndex, int32 NextHalfEdgeIndex) that return false to stop the visit loop
264 template<typename FVisitorType>
265 inline void VisitPlaneEdges(int32 PlaneIndex, const FVisitorType& Visitor) const
266 {
267 const int32 FirstHalfEdgeIndex = GetPlane(PlaneIndex).FirstHalfEdgeIndex;
268 int32 HalfEdgeIndex0 = FirstHalfEdgeIndex;
270 {
271 bool bContinue = true;
272 do
273 {
276 {
278 }
280 } while (bContinue && (HalfEdgeIndex0 != FirstHalfEdgeIndex) && (HalfEdgeIndex0 != InvalidIndex));
281 }
282 }
283
284 // Iterate over the half-edges associated with a vertex (leading out from the vertex, so all half edges have the vertex as the root).
285 // Visitor should return false to halt iteration.
286 // FVisitorType should be a function with signature: bool(int32 HalfEdgeIndex) that returns false to stop the visit loop.
287 template<typename FVisitorType>
288 inline void VisitVertexHalfEdges(int32 VertexIndex, const FVisitorType& Visitor) const
289 {
290 const int32 FirstHalfEdgeIndex = GetVertex(VertexIndex).FirstHalfEdgeIndex;
291 int32 HalfEdgeIndex = FirstHalfEdgeIndex;
293 {
294 bool bContinue = true;
295 do
296 {
297 bContinue = Visitor(HalfEdgeIndex);
298 const int32 TwinHalfEdgeIndex = GetTwinHalfEdge(HalfEdgeIndex);
299 if (TwinHalfEdgeIndex == InvalidIndex)
300 {
301 break;
302 }
303 HalfEdgeIndex = GetNextHalfEdge(TwinHalfEdgeIndex);
304 } while (bContinue && (HalfEdgeIndex != FirstHalfEdgeIndex) && (HalfEdgeIndex != InvalidIndex));
305 }
306 }
307
308 // Fill an array with plane indices for the specified vertex. Return the number of planes found.
309 int32 FindVertexPlanes(int32 VertexIndex, int32* PlaneIndices, int32 MaxVertexPlanes) const
310 {
312
313 if (MaxVertexPlanes > 0)
314 {
315 VisitVertexHalfEdges(VertexIndex,
316 [this, PlaneIndices, MaxVertexPlanes, &NumPlanesFound](int32 HalfEdgeIndex)
317 {
320 });
321 }
322
323 return NumPlanesFound;
324 }
325
327 {
328 const FVertexPlanes& VertexPlane = VertexPlanes[VertexIndex];
329 PlaneIndex0 = (int32)VertexPlane.PlaneIndices[0];
330 PlaneIndex1 = (int32)VertexPlane.PlaneIndices[1];
331 PlaneIndex2 = (int32)VertexPlane.PlaneIndices[2];
332 return (int32)VertexPlane.NumPlaneIndices;
333 }
334
335 // Build half edge structure datas for regular convexes with exactly 3 faces per vertex
337 {
338 // Count the edges
339 int32 HalfEdgeCount = 0;
340 for (int32 PlaneIndex = 0; PlaneIndex < InPlaneVertices.Num(); ++PlaneIndex)
341 {
342 HalfEdgeCount += InPlaneVertices[PlaneIndex].Num();
343 }
344
345 if ((InPlaneVertices.Num() > MaxIndex) || (HalfEdgeCount > MaxIndex) || (InNumVertices > MaxIndex))
346 {
347 // We should never get here. See GetRequiredIndexType::GetRequiredIndexType which calls CanMake() on eachn index type until it fits
348 UE_LOG(LogChaos, Error, TEXT("Unable to create structure data for convex. MaxIndex too small (%" SIZE_T_FMT " bytes) for Planes: %d HalfEdges: %d Verts: %d"), sizeof(FIndex), InPlaneVertices.Num(), HalfEdgeCount, InNumVertices);
349 return false;
350 }
351
352 Planes.SetNum(InPlaneVertices.Num());
353 HalfEdges.SetNum(HalfEdgeCount);
354 Vertices.SetNum(InNumVertices);
355 VertexPlanes.SetNum(InNumVertices);
356
359
361 HalfEdgeVertices.SetNum(HalfEdgeCount);
362
363 // Initialize the vertex list - it will be filled in as we build the edge list
364 for (int32 VertexIndex = 0; VertexIndex < Vertices.Num(); ++VertexIndex)
365 {
367 }
368
369 // Build the planes and edges. The edges for a plane are stored sequentially in the half-edge array.
370 // On the first pass, the edges contain 2 vertex indices, rather than a vertex index and a twin edge index.
371 // We fix this up on a second pass.
373 for (int32 PlaneIndex = 0; PlaneIndex < InPlaneVertices.Num(); ++PlaneIndex)
374 {
375 const TArray<int32>& PlaneVertices = InPlaneVertices[PlaneIndex];
376
377 GetPlane(PlaneIndex) =
378 {
380 (FIndex)PlaneVertices.Num()
381 };
382
383 for (int32 PlaneVertexIndex = 0; PlaneVertexIndex < PlaneVertices.Num(); ++PlaneVertexIndex)
384 {
385 // Add a new edge
386 const int32 VertexIndex0 = PlaneVertices[PlaneVertexIndex];
387 const int32 VertexIndex1 = PlaneVertices[(PlaneVertexIndex + 1) % PlaneVertices.Num()];
389 {
390 (FIndex)PlaneIndex,
391 (FIndex)VertexIndex0,
392 (FIndex)VertexIndex1, // Will get converted to a half-edge index later
393 };
395
396 // If this is the first time Vertex0 has showed up, set its edge index
397 // For valid and regular convexes each vertices have 2 halfedges starting from itself
398 if (Vertices[VertexIndex0].FirstHalfEdgeIndex == InvalidIndex)
399 {
400 Vertices[VertexIndex0].FirstHalfEdgeIndex = (FIndex)NextHalfEdgeIndex;
401 }
402
403 // For regular convexes each vertices have exactly 3 halfedges
404 VertexHalfEdges[VertexIndex0].HalfEdgeIndices[VertexHalfEdges[VertexIndex0].NumHalfEdgeIndices++] = (FIndex)NextHalfEdgeIndex;
405
406 // For regular convexes each vertices have exactly 3 planes
407 VertexPlanes[VertexIndex0].PlaneIndices[VertexPlanes[VertexIndex0].NumPlaneIndices++] = (FIndex)PlaneIndex;
408
410 }
411 }
412 Edges.Empty();
413 Edges.Reserve(NumHalfEdges() / 2);
414
415 for (int32 HalfEdgeIndex = 0; HalfEdgeIndex < HalfEdges.Num(); ++HalfEdgeIndex)
416 {
417 const int32 VertexIndex0 = HalfEdges[HalfEdgeIndex].VertexIndex;
418 const int32 VertexIndex1 = HalfEdges[HalfEdgeIndex].TwinHalfEdgeIndex;
419
420 for(int32 VertexHalfEdgeIndex = 0, NumHalfEdgeIndices = VertexHalfEdges[VertexIndex1].NumHalfEdgeIndices;
421 VertexHalfEdgeIndex < NumHalfEdgeIndices; ++VertexHalfEdgeIndex)
422 {
423 const FIndex TwinHalfEdgeIndex = VertexHalfEdges[VertexIndex1].HalfEdgeIndices[VertexHalfEdgeIndex];
424 if(HalfEdgeVertices[TwinHalfEdgeIndex] == VertexIndex0)
425 {
426 HalfEdges[HalfEdgeIndex].TwinHalfEdgeIndex = TwinHalfEdgeIndex;
427 break;
428 }
429 }
430
431 if(VertexIndex0 < HalfEdges[HalfEdges[HalfEdgeIndex].TwinHalfEdgeIndex].VertexIndex)
432 {
433 Edges.Add((FIndex)HalfEdgeIndex);
434 }
435 }
436 return true;
437 }
438
439
440 // Initialize the structure data from the set of vertices associated with each plane.
441 // The vertex indices are assumed to be in CCW order (or CW order - doesn't matter here
442 // as long as it is sequential).
444 {
445 // Count the edges
446 int32 HalfEdgeCount = 0;
447 for (int32 PlaneIndex = 0; PlaneIndex < InPlaneVertices.Num(); ++PlaneIndex)
448 {
449 HalfEdgeCount += InPlaneVertices[PlaneIndex].Num();
450 }
451
452 if ((InPlaneVertices.Num() > MaxIndex) || (HalfEdgeCount > MaxIndex) || (InNumVertices > MaxIndex))
453 {
454 // We should never get here. See GetRequiredIndexType::GetRequiredIndexType which calls CanMake() on eachn index type until it fits
455 UE_LOG(LogChaos, Error, TEXT("Unable to create structure data for convex. MaxIndex too small (%" SIZE_T_FMT " bytes) for Planes: %d HalfEdges: %d Verts: %d"), sizeof(FIndex), InPlaneVertices.Num(), HalfEdgeCount, InNumVertices);
456 return false;
457 }
458
459 Planes.SetNum(InPlaneVertices.Num());
460 HalfEdges.SetNum(HalfEdgeCount);
461 Vertices.SetNum(InNumVertices);
462
463 // Initialize the vertex list - it will be filled in as we build the edge list
464 for (int32 VertexIndex = 0; VertexIndex < Vertices.Num(); ++VertexIndex)
465 {
467 }
468
469 // Build the planes and edges. The edges for a plane are stored sequentially in the half-edge array.
470 // On the first pass, the edges contain 2 vertex indices, rather than a vertex index and a twin edge index.
471 // We fix this up on a second pass.
473 for (int32 PlaneIndex = 0; PlaneIndex < InPlaneVertices.Num(); ++PlaneIndex)
474 {
475 const TArray<int32>& PlaneVertices = InPlaneVertices[PlaneIndex];
476
477 GetPlane(PlaneIndex) =
478 {
480 (FIndex)PlaneVertices.Num()
481 };
482
483 for (int32 PlaneVertexIndex = 0; PlaneVertexIndex < PlaneVertices.Num(); ++PlaneVertexIndex)
484 {
485 // Add a new edge
486 const int32 VertexIndex0 = PlaneVertices[PlaneVertexIndex];
487 const int32 VertexIndex1 = PlaneVertices[(PlaneVertexIndex + 1) % PlaneVertices.Num()];
489 {
490 (FIndex)PlaneIndex,
491 (FIndex)VertexIndex0,
492 (FIndex)VertexIndex1, // Will get converted to a half-edge index later
493 };
494
495 // If this is the first time Vertex0 has showed up, set its edge index
496 if (Vertices[VertexIndex0].FirstHalfEdgeIndex == InvalidIndex)
497 {
498 Vertices[VertexIndex0].FirstHalfEdgeIndex = (FIndex)NextHalfEdgeIndex;
499 }
500
502 }
503 }
504
505 // Find the twin half edge for each edge
506 // NOTE: we have to deal with mal-formed convexes which claim to have edges that use the
507 // same vertex pair in the same order.
508 // @todo(chaos): track down to source of the mal-formed convexes
509 // @todo(chaos): could use a map of vertex-index-pair to half edge to eliminate O(N^2) algorithm
512 TwinHalfEdgeIndices.SetNum(HalfEdges.Num());
513 HalfEdgeTwinned.SetNum(HalfEdges.Num());
515 {
518 }
519 for (int32 HalfEdgeIndex0 = 0; HalfEdgeIndex0 < HalfEdges.Num(); ++HalfEdgeIndex0)
520 {
521 const int32 VertexIndex0 = HalfEdges[HalfEdgeIndex0].VertexIndex;
522 const int32 VertexIndex1 = HalfEdges[HalfEdgeIndex0].TwinHalfEdgeIndex; // Actually a vertex index for now...
523
524 // Find the edge with the vertices the other way round
525 for (int32 HalfEdgeIndex1 = 0; HalfEdgeIndex1 < HalfEdges.Num(); ++HalfEdgeIndex1)
526 {
527 if ((HalfEdges[HalfEdgeIndex1].VertexIndex == VertexIndex1) && (HalfEdges[HalfEdgeIndex1].TwinHalfEdgeIndex == VertexIndex0))
528 {
529 // We deal with edge duplication by leaving a half edge without a twin
531 {
534 }
535 else
536 {
538 }
539 break;
540 }
541 }
542 }
543
544 // Set the twin edge indices
545 for (int32 HalfEdgeIndex = 0; HalfEdgeIndex < HalfEdges.Num(); ++HalfEdgeIndex)
546 {
548 }
549
550 BuildVertexPlanes();
551
552 BuildUniqueEdgeList();
553
554 return true;
555 }
556
558 {
560
561 Ar << Planes;
562 Ar << HalfEdges;
563 Ar << Vertices;
564
567 {
568 Ar << Edges;
569 }
570
571 // Handle older data without the edge list and also an issue where some assets were saved without having their EdgeList generated (now fixed)
572 // Avoid adding a new custom version for that fix because we want to integrate this into other streams
573 if (Ar.IsLoading() && (Edges.Num() == 0) && (HalfEdges.Num() > 0))
574 {
575 BuildUniqueEdgeList();
576 ensureMsgf(Edges.Num() > 0, TEXT("Invalid edge data on convex in Load"));
577 }
578
579 if (Ar.IsLoading())
580 {
581 BuildVertexPlanes();
582 }
583 }
584
586 {
587 Value.Serialize(Ar);
588 return Ar;
589 }
590
591#if INTEL_ISPC
592 // See PerParticlePBDCollisionConstraint.cpp
593 // ISPC code has matching structs for interpreting FImplicitObjects.
594 // This is used to verify that the structs stay the same.
595 struct FISPCDataVerifier
596 {
597 static constexpr int32 OffsetOfPlanes() { return offsetof(TConvexHalfEdgeStructureData, Planes); }
598 static constexpr int32 SizeOfPlanes() { return sizeof(TConvexHalfEdgeStructureData::Planes); }
599 static constexpr int32 OffsetOfHalfEdges() { return offsetof(TConvexHalfEdgeStructureData, HalfEdges); }
600 static constexpr int32 SizeOfHalfEdges() { return sizeof(TConvexHalfEdgeStructureData::HalfEdges); }
601 static constexpr int32 OffsetOfVertices() { return offsetof(TConvexHalfEdgeStructureData, Vertices); }
602 static constexpr int32 SizeOfVertices() { return sizeof(TConvexHalfEdgeStructureData::Vertices); }
603 static constexpr int32 OffsetOfEdges() { return offsetof(TConvexHalfEdgeStructureData, Edges); }
604 static constexpr int32 SizeOfEdges() { return sizeof(TConvexHalfEdgeStructureData::Edges); }
605 static constexpr int32 OffsetOfVertexPlanes() { return offsetof(TConvexHalfEdgeStructureData, VertexPlanes); }
606 static constexpr int32 SizeOfVertexPlanes() { return sizeof(TConvexHalfEdgeStructureData::VertexPlanes); }
607 };
608 friend FISPCDataVerifier;
609#endif // #if INTEL_ISPC
610
611 private:
612
613 // The edge index of the previous edge on the plane (loops)
614 // PlaneIndex must be in range [0, NumPlanes())
615 // PlaneHalfEdgeIndex must be in range [0, NumPlaneHalfEdges(PlaneIndex))
616 // return value is in range [0, NumHalfEdges())
617 int32 GetPrevPlaneHalfEdge(int32 PlaneIndex, int32 PlaneHalfEdgeIndex) const
618 {
619 // A plane's edges are sequential and loop
622 const int32 PlaneHalfEdgeCount = NumPlaneHalfEdges(PlaneIndex);
624 return GetPlaneHalfEdge(PlaneIndex, PrevPlaneHalfEdgeIndex);
625 }
626
627 // The edge index of the next edge on the plane (loops)
628 // PlaneIndex must be in range [0, NumPlanes())
629 // PlaneHalfEdgeIndex must be in range [0, NumPlaneHalfEdges(PlaneIndex))
630 // return value is in range [0, NumHalfEdges())
631 int32 GetNextPlaneHalfEdge(int32 PlaneIndex, int32 PlaneHalfEdgeIndex) const
632 {
633 // A plane's edges are sequential and loop
636 const int32 PlaneHalfEdgeCount = NumPlaneHalfEdges(PlaneIndex);
638 return GetPlaneHalfEdge(PlaneIndex, NextPlaneHalfEdgeIndex);
639 }
640
641 // Generate the set of half-edges where none of the edge twins are also in the list.
642 // this is effectively the set of full edges. This will also exclude any malformed edges if they exist.
643 void BuildUniqueEdgeList()
644 {
645 Edges.Empty();
646 Edges.Reserve(NumHalfEdges() / 2);
647
649 {
650 const FHalfEdgeData& Edge = GetHalfEdge(HalfEdgeIndex);
651 if (Edge.TwinHalfEdgeIndex != InvalidIndex)
652 {
653 const FHalfEdgeData& TwinEdge = GetHalfEdge(Edge.TwinHalfEdgeIndex);
654 if ((Edge.VertexIndex != InvalidIndex) && (TwinEdge.VertexIndex != InvalidIndex))
655 {
656 if (Edge.VertexIndex < TwinEdge.VertexIndex)
657 {
658 Edges.Add((FIndex)HalfEdgeIndex);
659 }
660 }
661 }
662 }
663 }
664
665 void BuildVertexPlanes()
666 {
667 VertexPlanes.SetNum(Vertices.Num());
668
669 for (int32 VertexIndex = 0; VertexIndex < NumVertices(); ++VertexIndex)
670 {
671 FVertexPlanes& VertexPlane = VertexPlanes[VertexIndex];
672 VertexPlane.NumPlaneIndices = 0;
673 VertexPlane.PlaneIndices[0] = FIndex(INDEX_NONE);
674 VertexPlane.PlaneIndices[1] = FIndex(INDEX_NONE);
675 VertexPlane.PlaneIndices[2] = FIndex(INDEX_NONE);
676
677 const int32 FirstHalfEdgeIndex = GetVertex(VertexIndex).FirstHalfEdgeIndex;
678 int32 HalfEdgeIndex = FirstHalfEdgeIndex;
680 {
681 do
682 {
683 if(VertexPlane.NumPlaneIndices < (FIndex)UE_ARRAY_COUNT(VertexPlane.PlaneIndices))
684 {
685 VertexPlane.PlaneIndices[VertexPlane.NumPlaneIndices] = (FIndex)GetHalfEdgePlane(HalfEdgeIndex);
686 }
687
688 // Caching of the Max number of plane indices on this vertex (could be higher than 3)
689 // This can be used to determine if a call to GetVertexPlanes3 will actually return all the planes
690 // that use a particular vertex. This is useful in collision detection for box-like objects
691 // to avoid calling FindVertexPlanes
692 ++VertexPlane.NumPlaneIndices;
693
694 // If we hit this there's a mal-formed convex case that we did not detect (we should be dealing with all cases - see SetPlaneVertices)
695 if (!ensure(VertexPlane.NumPlaneIndices <= Planes.Num()))
696 {
697 VertexPlane.NumPlaneIndices = 0;
698 break;
699 }
700
701 const int32 TwinHalfEdgeIndex = GetTwinHalfEdge(HalfEdgeIndex);
702 if (TwinHalfEdgeIndex == InvalidIndex)
703 {
704 break;
705 }
706 HalfEdgeIndex = GetNextHalfEdge(TwinHalfEdgeIndex);
707 } while ((HalfEdgeIndex != FirstHalfEdgeIndex) && (HalfEdgeIndex != InvalidIndex));
708 }
709 }
710 }
711
712 TArray<FPlaneData> Planes;
713 TArray<FHalfEdgeData> HalfEdges;
714 TArray<FVertexData> Vertices;
715 TArray<FIndex> Edges;
716 TArray<FVertexPlanes> VertexPlanes;
717 };
718
719
720 // Typedefs for the supported index sizes
724}
#define SIZE_T_FMT
Definition AndroidPlatformString.h:30
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define ensure( InExpression)
Definition AssertionMacros.h:464
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#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
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
#define UE_ARRAY_COUNT(array)
Definition UnrealTemplate.h:212
uint8_t uint8
Definition binka_ue_file_header.h:8
Definition ConvexHalfEdgeStructureData.h:38
int32 GetVertexPlanes3(int32 VertexIndex, int32 &PlaneIndex0, int32 &PlaneIndex1, int32 &PlaneIndex2) const
Definition ConvexHalfEdgeStructureData.h:326
friend class FVertexPlaneIterator
Definition ConvexHalfEdgeStructureData.h:47
FPlaneData & GetPlane(int32 PlaneIndex)
Definition ConvexHalfEdgeStructureData.h:137
void Serialize(FArchive &Ar)
Definition ConvexHalfEdgeStructureData.h:557
int32 GetPlaneVertex(int32 PlaneIndex, int32 PlaneVertexIndex) const
Definition ConvexHalfEdgeStructureData.h:173
int32 GetEdgePlane(int32 EdgeIndex, int32 EdgePlaneIndex) const
Definition ConvexHalfEdgeStructureData.h:242
static const int32 MaxIndex
Definition ConvexHalfEdgeStructureData.h:45
FVertexData & GetVertex(int32 VertexIndex)
Definition ConvexHalfEdgeStructureData.h:142
int32 NumEdges() const
Definition ConvexHalfEdgeStructureData.h:135
int32 GetHalfEdgeIndex(int32 EdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:141
const FHalfEdgeData & GetHalfEdge(int32 HalfEdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:140
const FPlaneData & GetPlane(int32 PlaneIndex) const
Definition ConvexHalfEdgeStructureData.h:138
FHalfEdgeData & GetHalfEdge(int32 HalfEdgeIndex)
Definition ConvexHalfEdgeStructureData.h:139
bool BuildRegularDatas(const TArray< TArray< int32 > > &InPlaneVertices, int32 InNumVertices)
Definition ConvexHalfEdgeStructureData.h:336
int32 GetPlaneHalfEdge(int32 PlaneIndex, int32 PlaneEdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:155
int32 GetEdgeVertex(int32 EdgeIndex, int32 EdgeVertexIndex) const
Definition ConvexHalfEdgeStructureData.h:226
T_INDEX FIndex
Definition ConvexHalfEdgeStructureData.h:40
void VisitVertexHalfEdges(int32 VertexIndex, const FVisitorType &Visitor) const
Definition ConvexHalfEdgeStructureData.h:288
int32 NumPlaneHalfEdges(int32 PlaneIndex) const
Definition ConvexHalfEdgeStructureData.h:146
int32 GetHalfEdgePlane(int32 HalfEdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:181
int32 GetHalfEdgeVertex(int32 HalfEdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:188
static bool CanMake(const TArray< TArray< int32 > > &InPlaneVertices, int32 InNumVertices)
Definition ConvexHalfEdgeStructureData.h:116
int32 NumHalfEdges() const
Definition ConvexHalfEdgeStructureData.h:131
void VisitPlaneEdges(int32 PlaneIndex, const FVisitorType &Visitor) const
Definition ConvexHalfEdgeStructureData.h:265
bool IsValid() const
Definition ConvexHalfEdgeStructureData.h:129
int32 GetTwinHalfEdge(int32 HalfEdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:195
int32 NumPlanes() const
Definition ConvexHalfEdgeStructureData.h:130
int32 GetVertexFirstHalfEdge(int32 VertexIndex) const
Definition ConvexHalfEdgeStructureData.h:256
bool SetPlaneVertices(const TArray< TArray< int32 > > &InPlaneVertices, int32 InNumVertices)
Definition ConvexHalfEdgeStructureData.h:443
int32 NumPlaneVertices(int32 PlaneIndex) const
Definition ConvexHalfEdgeStructureData.h:164
int32 FindVertexPlanes(int32 VertexIndex, int32 *PlaneIndices, int32 MaxVertexPlanes) const
Definition ConvexHalfEdgeStructureData.h:309
int32 GetPrevHalfEdge(int32 HalfEdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:203
const FVertexData & GetVertex(int32 VertexIndex) const
Definition ConvexHalfEdgeStructureData.h:143
static const FIndex InvalidIndex
Definition ConvexHalfEdgeStructureData.h:44
friend FArchive & operator<<(FArchive &Ar, FConvexHalfEdgeStructureData &Value)
Definition ConvexHalfEdgeStructureData.h:585
static FConvexHalfEdgeStructureData MakePlaneVertices(const TArray< TArray< int32 > > &InPlaneVertices, int32 InNumVertices)
Definition ConvexHalfEdgeStructureData.h:108
int32 GetNextHalfEdge(int32 HalfEdgeIndex) const
Definition ConvexHalfEdgeStructureData.h:214
int32 NumVertices() const
Definition ConvexHalfEdgeStructureData.h:132
Definition Archive.h:1208
virtual void Serialize(void *V, int64 Length)
Definition Archive.h:1689
virtual CORE_API void UsingCustomVersion(const struct FGuid &Guid)
Definition Archive.cpp:590
UE_FORCEINLINE_HINT bool IsLoading() const
Definition Archive.h:236
CORE_API int32 CustomVer(const struct FGuid &Key) const
Definition Archive.cpp:602
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
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 Empty(SizeType Slack=0)
Definition Array.h:2273
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition SkeletalMeshComponent.h:307
const FName VertexIndex("VertexIndex")
Definition MeshAttributes.h:28
Definition ConvexHalfEdgeStructureData.h:68
FIndex TwinHalfEdgeIndex
Definition ConvexHalfEdgeStructureData.h:71
FIndex PlaneIndex
Definition ConvexHalfEdgeStructureData.h:69
friend FArchive & operator<<(FArchive &Ar, FHalfEdgeData &Value)
Definition ConvexHalfEdgeStructureData.h:73
FIndex VertexIndex
Definition ConvexHalfEdgeStructureData.h:70
Definition ConvexHalfEdgeStructureData.h:52
FIndex FirstHalfEdgeIndex
Definition ConvexHalfEdgeStructureData.h:53
friend FArchive & operator<<(FArchive &Ar, FPlaneData &Value)
Definition ConvexHalfEdgeStructureData.h:56
FIndex NumHalfEdges
Definition ConvexHalfEdgeStructureData.h:54
Definition ConvexHalfEdgeStructureData.h:82
friend FArchive & operator<<(FArchive &Ar, FVertexData &Value)
Definition ConvexHalfEdgeStructureData.h:85
FIndex FirstHalfEdgeIndex
Definition ConvexHalfEdgeStructureData.h:83
Definition ConvexHalfEdgeStructureData.h:101
FIndex HalfEdgeIndices[3]
Definition ConvexHalfEdgeStructureData.h:102
FIndex NumHalfEdgeIndices
Definition ConvexHalfEdgeStructureData.h:103
Definition ConvexHalfEdgeStructureData.h:94
FIndex PlaneIndices[3]
Definition ConvexHalfEdgeStructureData.h:95
FIndex NumPlaneIndices
Definition ConvexHalfEdgeStructureData.h:96
uint8 FIndex
Definition ConvexHalfEdgeStructureData.h:28
Definition ConvexHalfEdgeStructureData.h:16
static const FIndex InvalidIndex
Definition ConvexHalfEdgeStructureData.h:18
T_INDEX FIndex
Definition ConvexHalfEdgeStructureData.h:17
static const FIndex MaxIndex
Definition ConvexHalfEdgeStructureData.h:19
@ ChaosConvexHasUniqueEdgeSet
Definition PhysicsObjectVersion.h:52
CORE_API static const FGuid GUID
Definition PhysicsObjectVersion.h:78
Definition IsSigned.h:12
Definition NumericLimits.h:41