UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
HeightField.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "Chaos/Array.h"
6#include "ImplicitObject.h"
7#include "Box.h"
9#include "ChaosArchive.h"
11#include "Math/NumericLimits.h"
12#include "Templates/UniqueObj.h"
14#include "UniformGrid.h"
15#include "Utilities.h"
17
18namespace Chaos
19{
20 class FHeightfieldRaycastVisitor;
21 struct FMTDInfo;
22}
23
24namespace Chaos::Private
25{
26 class FMeshContactGenerator;
27}
28
29namespace Chaos
30{
31 class FHeightField final : public FImplicitObject
32 {
33 public:
35
39
40 // Not required as long as FImplicitObject also has deleted move constructor (adding this causes an error on Linux build)
41 //FHeightField(FHeightField&& Other) = default;
42
43 virtual ~FHeightField() {}
44
53 CHAOS_API bool IsHole(int32 InIndex) const;
58
59 int32 GetNumRows() const { return GeomData.NumRows; }
60 int32 GetNumCols() const { return GeomData.NumCols; }
61
62 CHAOS_API virtual FReal PhiWithNormal(const FVec3& x, FVec3& Normal) const;
63
64 CHAOS_API virtual bool Raycast(const FVec3& StartPoint, const FVec3& Dir, const FReal Length, const FReal Thickness, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex) const override;
65 CHAOS_API virtual bool Overlap(const FVec3& Point, const FReal Thickness) const override;
66
67 CHAOS_API bool OverlapGeom(const FSphere& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
68 CHAOS_API bool OverlapGeom(const TBox<FReal, 3>& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
69 CHAOS_API bool OverlapGeom(const FCapsule& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
70 CHAOS_API bool OverlapGeom(const FConvex& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
71 CHAOS_API bool OverlapGeom(const TImplicitObjectScaled<FSphere>& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
72 CHAOS_API bool OverlapGeom(const TImplicitObjectScaled<TBox<FReal, 3>>& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
73 CHAOS_API bool OverlapGeom(const TImplicitObjectScaled<FCapsule>& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
74 CHAOS_API bool OverlapGeom(const TImplicitObjectScaled<FConvex>& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
75
76 CHAOS_API bool SweepGeom(const FSphere& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
77 CHAOS_API bool SweepGeom(const TBox<FReal, 3>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
78 CHAOS_API bool SweepGeom(const FCapsule& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
79 CHAOS_API bool SweepGeom(const FConvex& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
80 CHAOS_API bool SweepGeom(const TImplicitObjectScaled<FSphere>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
81 CHAOS_API bool SweepGeom(const TImplicitObjectScaled<TBox<FReal, 3>>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
82 CHAOS_API bool SweepGeom(const TImplicitObjectScaled<FCapsule>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
83 CHAOS_API bool SweepGeom(const TImplicitObjectScaled<FConvex>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal, const FReal Thickness = 0, bool bComputeMTD = false) const;
84
85 // Sweep used for CCD. Ignores triangles we penetrate by less than IgnorePenetration, and calculate the TOI for a depth of TargetPenetration. If both are zero, this is equivalent to SweepGeom
86 CHAOS_API bool SweepGeomCCD(const FSphere& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
87 CHAOS_API bool SweepGeomCCD(const TBox<FReal, 3>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
88 CHAOS_API bool SweepGeomCCD(const FCapsule& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
89 CHAOS_API bool SweepGeomCCD(const FConvex& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
90 CHAOS_API bool SweepGeomCCD(const TImplicitObjectScaled<FSphere>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
91 CHAOS_API bool SweepGeomCCD(const TImplicitObjectScaled<TBox<FReal, 3>>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
92 CHAOS_API bool SweepGeomCCD(const TImplicitObjectScaled<FCapsule>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
93 CHAOS_API bool SweepGeomCCD(const TImplicitObjectScaled<FConvex>& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal) const;
94
95 CHAOS_API bool GJKContactPoint(const TBox<FReal, 3>& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FVec3& ContactLocation, FVec3& ContactNormal, FReal& ContactPhi, int32& ContactFaceIndex) const;
96 CHAOS_API bool GJKContactPoint(const FSphere& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FVec3& ContactLocation, FVec3& ContactNormal, FReal& ContactPhi, int32& ContactFaceIndex) const;
97 CHAOS_API bool GJKContactPoint(const FCapsule& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FVec3& ContactLocation, FVec3& ContactNormal, FReal& ContactPhi, int32& ContactFaceIndex) const;
98 CHAOS_API bool GJKContactPoint(const FConvex& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FVec3& ContactLocation, FVec3& ContactNormal, FReal& ContactPhi, int32& ContactFaceIndex) const;
103
104
107
113 {
114 // Convert the triangle index into a cell index and extract the cell row/column
115 // Reverse of FaceIndex0 = CellIndex * 2 + 0|1;
116 const int32 CellIndex = TriangleIndex / 2;
117 const int32 CellRowIndex = CellIndex / (GeomData.NumCols - 1);
118 const int32 CellColIndex = CellIndex % (GeomData.NumCols - 1);
119
120 // Calculate the vertex indices for the 4 cell corners
122 const int32 VertexIndex0 = CellVertexIndex;
123 const int32 VertexIndex1 = CellVertexIndex + 1;
126
127 // Get the vertices
128 const FVec3 Vertex0 = Transform.TransformPosition(GeomData.GetPointScaled(VertexIndex0));
129 const FVec3 Vertex1 = Transform.TransformPosition(GeomData.GetPointScaled(VertexIndex1));
130 const FVec3 Vertex2 = Transform.TransformPosition(GeomData.GetPointScaled(VertexIndex2));
131 const FVec3 Vertex3 = Transform.TransformPosition(GeomData.GetPointScaled(VertexIndex3));
132
133 // Set the output triangle which depends on winding (begative scales) and which of the two triangles in the cell we want
134 const bool bStandardWinding = ((GeomData.Scale.X * GeomData.Scale.Y * GeomData.Scale.Z) >= FReal(0));
135 const bool bIsFirstTriangle = ((TriangleIndex & 1) == 0);
137 {
139 {
141 OutVertexIndex0 = VertexIndex0;
142 OutVertexIndex1 = VertexIndex1;
144 }
145 else
146 {
148 OutVertexIndex0 = VertexIndex0;
150 OutVertexIndex2 = VertexIndex1;
151 }
152 }
153 else
154 {
156 {
158 OutVertexIndex0 = VertexIndex0;
161 }
162 else
163 {
165 OutVertexIndex0 = VertexIndex0;
168 }
169 }
170 }
171
180 template<typename TriangleVisitor>
182 {
183 FBounds2D GridQueryBounds;
184 GridQueryBounds.Min = FVec2(QueryBounds.Min()[0], QueryBounds.Min()[1]);
185 GridQueryBounds.Max = FVec2(QueryBounds.Max()[0], QueryBounds.Max()[1]);
186
187 // @todo(chaos): could we do the 3D bounds test here?
188 TArray<TVec2<int32>> Intersections;
189 GetGridIntersections(GridQueryBounds, Intersections);
190
191 const bool bStandardWinding = ((GeomData.Scale.X * GeomData.Scale.Y * GeomData.Scale.Z) >= FReal(0));
192
193 FVec3 Points[4];
194 FTriangle Triangles[2];
195
196 for (const TVec2<int32>& Cell : Intersections)
197 {
198 const int32 CellVertexIndex = Cell[1] * GeomData.NumCols + Cell[0]; // First vertex in cell
199 const int32 CellIndex = Cell[1] * (GeomData.NumCols - 1) + Cell[0];
200
201 // Check for holes and skip checking if we'll never collide
203 {
204 continue;
205 }
206
207 // The triangle is solid so proceed to test it
208 FAABB3 CellBounds;
210
211 if (CellBounds.Intersects(QueryBounds))
212 {
213 // Transform points into the space of the query
214 // @todo(chaos): duplicate work here when we overlap lots of cells. We could generate the transformed verts for the full query once...
215 Points[0] = QueryTransform.TransformPositionNoScale(Points[0]);
216 Points[1] = QueryTransform.TransformPositionNoScale(Points[1]);
217 Points[2] = QueryTransform.TransformPositionNoScale(Points[2]);
218 Points[3] = QueryTransform.TransformPositionNoScale(Points[3]);
219
220 // @todo(chaos): utility function for this
221 const int32 VertexIndex0 = CellVertexIndex;
222 const int32 VertexIndex1 = CellVertexIndex + 1;
225
226 // Generate contacts if overlapping
227 const int32 FaceIndex0 = CellIndex * 2 + 0;
228 const int32 FaceIndex1 = CellIndex * 2 + 1;
229
231 {
232 Triangles[0] = FTriangle(Points[0], Points[1], Points[3]);
233 Triangles[1] = FTriangle(Points[0], Points[3], Points[2]);
234 Visitor(Triangles[0], FaceIndex0, VertexIndex0, VertexIndex1, VertexIndex3);
235 Visitor(Triangles[1], FaceIndex1, VertexIndex0, VertexIndex3, VertexIndex2);
236 }
237 else
238 {
239 Triangles[0] = FTriangle(Points[0], Points[3], Points[1]);
240 Triangles[1] = FTriangle(Points[0], Points[2], Points[3]);
241 Visitor(Triangles[0], FaceIndex0, VertexIndex0, VertexIndex3, VertexIndex1);
242 Visitor(Triangles[1], FaceIndex1, VertexIndex0, VertexIndex2, VertexIndex3);
243 }
244 }
245 }
246 }
247
248 // Internal: do not use - this API will change as we optimize mesh collision
249 void CollectTriangles(const FAABB3& QueryBounds, const FRigidTransform3& QueryTransform, const FAABB3& ObjectBounds, Private::FMeshContactGenerator& Collector) const;
250
252 const FAABB3& QueryBounds,
254 const int32 RootObjectIndex,
255 int32& ObjectIndex,
257 const FImplicitHierarchyVisitor& VisitorFunc) const override final
258 {
260 {
261 VisitorFunc(this, ObjectTransform, RootObjectIndex, ObjectIndex, LeafObjectIndex);
262 }
263 ++ObjectIndex;
265 }
266
267 virtual bool IsOverlappingBoundsImpl(const FAABB3& QueryBounds) const override final
268 {
270 }
271
272 // Does the mesh-space QueryBounds overlap the bounds of any cells in the heightfield?
273 // @todo(chaos): we can return as soon as we overlap any cell so maybe use a
274 // custom function rather than GetBoundsScaled. Also we only care about Z overlap.
276 {
277 // Top-level bounds check
279 {
280 return false;
281 }
282
283 // Find all the cells that overlap in the X/Y plane
285 const FBounds2D FlatBounds = GetFlatBounds();
286
287 FBounds2D GridQueryBounds;
288 GridQueryBounds.Min = FVec2(QueryBounds.Min()[0], QueryBounds.Min()[1]);
289 GridQueryBounds.Max = FVec2(QueryBounds.Max()[0], QueryBounds.Max()[1]);
290 GridQueryBounds = FBounds2D::FromPoints(FlatBounds.Clamp(GridQueryBounds.Min) / Scale2D, FlatBounds.Clamp(GridQueryBounds.Max) / Scale2D);
291
293
294 // We want to capture the first cell (delta == 0) as well
297
300 return RegionBounds.Intersects(QueryBoundsSimd);
301 }
302
309
311
312 virtual uint16 GetMaterialIndex(uint32 HintIndex) const override
313 {
315
316 // If we've only got a default
317 if(GeomData.MaterialIndices.Num() == 1)
318 {
319 return GeomData.MaterialIndices[0];
320 }
321 else
322 {
323 // We store per cell for materials, so change to cell index
324 int32 CellIndex = HintIndex / 2;
326 {
327 return GeomData.MaterialIndices[CellIndex];
328 }
329 }
330
331 // INDEX_NONE will be out of bounds but it is an expected value. If we reach this section of the code and the index isn't INDEX_NONE, we have an issue
332 ensureMsgf(HintIndex == INDEX_NONE,TEXT("GetMaterialIndex called with an invalid MaterialIndex => %d"),HintIndex);
333
334 return 0;
335 }
336
337 virtual const FAABB3 BoundingBox() const
338 {
339 // Generate a correct bound including scales (may be negative)
340 CachedBounds = FAABB3::FromPoints(LocalBounds.Min() * GeomData.Scale, LocalBounds.Max() * GeomData.Scale);
341
342 return CachedBounds;
343 }
344
345 virtual uint32 GetTypeHash() const override
346 {
348 FMemoryWriter Writer(Bytes);
349 FChaosArchive ChaosAr(Writer);
350
351 // Saving to an archive is a const operation, but must be non-const
352 // to support loading. Cast const away here to get bytes written
353 const_cast<FHeightField*>(this)->Serialize(ChaosAr);
354
355 return FCrc::MemCrc32(Bytes.GetData(), (int32)Bytes.GetAllocatedSize());
356 }
357
359 {
361 }
362
363 virtual void Serialize(FChaosArchive& Ar) override
364 {
367
369
372 {
373 Ar << FlatGrid;
374 Ar << FlattenedBounds.Min;
375 Ar << FlattenedBounds.Max;
376 TBox<FReal, 3>::SerializeAsAABB(Ar, LocalBounds);
377 }
378 else
379 {
380 CalcBounds();
381 }
382
383
384 if(Ar.IsLoading())
385 {
386 BuildQueryData();
387 BoundingBox(); //temp hack to initialize cache
388 }
389 }
390
396
397 template<typename InStorageType>
398 struct FData
399 {
400 // For ease of access through typedefs
402
403 // Only supporting unsigned int types for the height range - really no difference using
404 // this or signed but this is a little nicer overall
405 static_assert(std::is_same_v<StorageType, uint8> ||
406 std::is_same_v<StorageType, uint16> ||
407 std::is_same_v<StorageType, uint32> ||
408 std::is_same_v<StorageType, uint64>,
409 "Expected unsigned integer type for heightfield data storage");
410
411 // Data sizes to validate during serialization
412 static constexpr int32 RealSize = sizeof(FReal);
413 static constexpr int32 StorageSize = sizeof(StorageType);
414
415 // Range of the chosen type (unsigned so Min is always 0)
417
418 static constexpr int32 LowResInc = 6;
419
420 // Heights in the chosen format. final placement of the vertex will be at
421 // MinValue + Heights[Index] * HeightPerUnit
422 // With HeightPerUnit being the range of the min/max FReal values of
423 // the heightfield divided by the range of StorageType
425
427 {
430
432 {
433 Ar << Min;
434 Ar << Max;
435 }
436 };
448
449 constexpr FReal GetCellWidth() const
450 {
451 return Scale[0];
452 }
453
454 constexpr FReal GetCellHeight() const
455 {
456 return Scale[1];
457 }
458
475 {
476 const int32 CellY = CellIndex / (NumCols - 1);
477 const int32 HeightIndex = CellIndex + CellY;
478 return HeightIndex;
479 }
480
482 {
483 const FReal Height = MinValue + Heights[Index] * HeightPerUnit;
484
485 const int32 X = Index % (NumCols);
486 const int32 Y = Index / (NumCols);
487
488 return {(FReal)X, (FReal)Y, Height};
489 }
490
492 {
493 return GetPoint(Index) * Scale;
494 }
495
497 {
499 const FReal H1 = MinValue + Heights[Index + 1] * HeightPerUnit;
502
503 const int32 X = Index % (NumCols);
504 const int32 Y = Index / (NumCols);
505
506 OutPts[0] = {(FReal)X, (FReal)Y, H0};
507 OutPts[1] = {(FReal)X + 1, (FReal)Y, H1};
508 OutPts[2] = {(FReal)X, (FReal)Y + 1, H2};
509 OutPts[3] = {(FReal)X + 1, (FReal)Y + 1, H3};
510 }
511
513 {
515 const FReal H1 = MinValue + Heights[Index + 1] * HeightPerUnit;
518
519 const int32 X = Index % (NumCols);
520 const int32 Y = Index / (NumCols);
521
522 OutPts[0] = { (FReal)X, (FReal)Y, H0 };
523 OutPts[1] = { (FReal)X + 1, (FReal)Y, H1 };
524 OutPts[2] = { (FReal)X, (FReal)Y + 1, H2 };
525 OutPts[3] = { (FReal)X + 1, (FReal)Y + 1, H3 };
526
527 const FReal MinZ = FMath::Min<FReal>(H0, FMath::Min<FReal>(H1, FMath::Min<FReal>(H2, H3)));
528 const FReal MaxZ = FMath::Max<FReal>(H0, FMath::Max<FReal>(H1, FMath::Max<FReal>(H2, H3)));
529
530 OutBounds = FAABB3(FVec3((FReal)X, (FReal)Y, MinZ), FVec3((FReal)X + 1, (FReal)Y + 1, MaxZ));
531 }
532
534 {
535 const FRealSingle H0 = static_cast<FRealSingle>(MinValue + Heights[Index] * HeightPerUnit);
536 const FRealSingle H1 = static_cast<FRealSingle>(MinValue + Heights[Index + 1] * HeightPerUnit);
538 const FRealSingle H3 = static_cast<FRealSingle>(MinValue + Heights[Index + NumCols + 1] * HeightPerUnit);
539
540 const int32 X = Index % (NumCols);
541 const int32 Y = Index / (NumCols);
542
547
548 const FRealSingle MinZ = FMath::Min<FRealSingle>(H0, FMath::Min<FRealSingle>(H1, FMath::Min<FRealSingle>(H2, H3)));
549 const FRealSingle MaxZ = FMath::Max<FRealSingle>(H0, FMath::Max<FRealSingle>(H1, FMath::Max<FRealSingle>(H2, H3)));
550
552 MakeVectorRegisterFloat((FRealSingle)X + 1, (FRealSingle)Y + 1, MaxZ, 0.0f));
553 }
554
556 {
557 const FRealSingle H0 = static_cast<FRealSingle>(MinValue + Heights[Index] * HeightPerUnit);
558 const FRealSingle H1 = static_cast<FRealSingle>(MinValue + Heights[Index + 1] * HeightPerUnit);
560 const FRealSingle H3 = static_cast<FRealSingle>(MinValue + Heights[Index + NumCols + 1] * HeightPerUnit);
561
562 const int32 X = Index % (NumCols);
563 const int32 Y = Index / (NumCols);
564
565 const FRealSingle MinZ = FMath::Min<FRealSingle>(H0, FMath::Min<FRealSingle>(H1, FMath::Min<FRealSingle>(H2, H3)));
566 const FRealSingle MaxZ = FMath::Max<FRealSingle>(H0, FMath::Max<FRealSingle>(H1, FMath::Max<FRealSingle>(H2, H3)));
567
569 MakeVectorRegisterFloat((FRealSingle)X + 1, (FRealSingle)Y + 1, MaxZ, 0.0f));
570 }
571
573 {
574 FRealSingle MinHeight = UE_BIG_NUMBER;
576
577 const int32 EndIndexX = CellIdx[0] + Area[0];
578 int32 FirstIndexX = FMath::Min<int32>(CellIdx[0], EndIndexX);
579 FirstIndexX = FMath::Max<int32>(FirstIndexX, 0);
580 int32 LastIndexX = FMath::Max<int32>(CellIdx[0], EndIndexX);
581 // Increment LastIndex to look into the four corners of a cell
582 LastIndexX++;
583 LastIndexX = FMath::Min<int32>(LastIndexX, NumCols-1);
584
585 const int32 EndIndexY = CellIdx[1] + Area[1];
586 int32 FirstIndexY = FMath::Min<int32>(CellIdx[1], EndIndexY);
587 FirstIndexY = FMath::Max<int32>(FirstIndexY, 0);
588 int32 LastIndexY = FMath::Max<int32>(CellIdx[1], EndIndexY);
589 LastIndexY++;
590 LastIndexY = FMath::Min<int32>(LastIndexY, NumRows-1);
591
592 for (int IndexY = FirstIndexY; IndexY <= LastIndexY; IndexY++)
593 {
594 for (int IndexX = FirstIndexX; IndexX <= LastIndexX; IndexX++)
595 {
596 const int32 Index = IndexY * NumCols + IndexX;
597 check(Index < Heights.Num());
599 MinHeight = FMath::Min<FRealSingle>(CurrHeight, MinHeight);
600 MaxHeight = FMath::Max<FRealSingle>(CurrHeight, MaxHeight);
601
602 }
603 }
604
605 const FRealSingle MinValueSingle = static_cast<FRealSingle>(MinValue);
607 MinHeight = MinValueSingle + MinHeight * HeightPerUnitSingle;
609
610 OutBounds = FAABBVectorized(MakeVectorRegisterFloat(static_cast<FRealSingle>(FirstIndexX), static_cast<FRealSingle>(FirstIndexY), MinHeight, 0.0f),
612 }
613
633
635 {
637
638 OutPts[0] *= Scale;
639 OutPts[1] *= Scale;
640 OutPts[2] *= Scale;
641 OutPts[3] *= Scale;
642 }
643
645 {
647
648 OutPts[0] *= Scale;
649 OutPts[1] *= Scale;
650 OutPts[2] *= Scale;
651 OutPts[3] *= Scale;
652
654 }
655
672
684
696
708
720
722 {
723 return MinValue;
724 }
725
727 {
728 return MaxValue;
729 }
730
732 {
733 // we need to account for the fact that FReal size may change
736
737
740
741 Ar << SerializedRealSize;
743
744 if(Ar.IsLoading())
745 {
746 // we only support float and double as FReal
747 checkf(SerializedRealSize == sizeof(float) || SerializedRealSize == sizeof(double), TEXT("Heightfield was serialized with unexpected real type size (expected: 4 or 8, found: %d)"), SerializedRealSize);
748 checkf(SerializedStorageSize == RunTimeStorageSize, TEXT("Heightfield was serialized with mismatched storage type size (expected: %d, found: %d)"), RunTimeStorageSize, SerializedStorageSize);
749 }
750
751 Ar << Heights;
752 Ar << Scale;
753 Ar << MinValue;
754 Ar << MaxValue;
755 Ar << NumRows;
756 Ar << NumCols;
757
759
762 {
763 Ar << Range;
764 Ar << HeightPerUnit;
765
767 {
768 // todo(chaos) this may not matter if the Vector types are handling serialization properly
769 // legacy, need to keep the inner box type as float ( not FReal )
771 Ar << CellBounds;
772 }
774 {
775 // legacy, need to keep the type as float ( not FReal )
777 Ar << OldHeights;
778 }
779 }
780
782 {
783 Ar << MaterialIndices;
784 }
785
787 if (Ar.CustomVer(FUE5MainStreamObjectVersion::GUID) == FUE5MainStreamObjectVersion::AddLowResolutionHeightField)
788 {
790 Ar << NumColsLowRes;
791 }
792 else if (Ar.CustomVer(FUE5MainStreamObjectVersion::GUID) >= FUE5MainStreamObjectVersion::DecreaseLowResolutionHeightField)
793 {
795 Ar << NumColsLowRes;
796 }
797 else
798 {
800 }
801 }
802
803 // A height bounds for grids of cells of size "LowResInc" square, for faster culling
805 {
806 const int32 NumRowsLowRes = FMath::CeilToInt(FRealSingle(NumRows) / LowResInc);
807 NumColsLowRes = uint16(FMath::CeilToInt(FRealSingle(NumCols) / LowResInc));
810
812 {
814 {
815 FDataType::StorageType MinHeight = std::numeric_limits<FDataType::StorageType>::max();
816 FDataType::StorageType MaxHeight = std::numeric_limits<FDataType::StorageType>::min();
818 {
820 {
822 MaxHeight = FMath::Max<FDataType::StorageType>(Heights[HeightIndex], MaxHeight);
823 MinHeight = FMath::Min<FDataType::StorageType>(Heights[HeightIndex], MinHeight);
824 }
825 }
829 }
830 }
831 }
832 };
833
836
837 private:
838
839 // Struct for 2D bounds and associated operations
840 struct FBounds2D
841 {
842 FVec2 Min;
843 FVec2 Max;
844
845 FBounds2D()
846 : Min(0)
847 , Max(0)
848 {}
849
850 FBounds2D(const FVec2& InMin, const FVec2& InMax)
851 : Min(InMin)
852 , Max(InMax)
853 {}
854
860 template<typename... Points>
861 static FBounds2D FromPoints(const FVec2& P0, const Points&... InPoints)
862 {
863 static_assert(sizeof...(InPoints) > 0);
864 static_assert(std::is_same_v<std::common_type_t<Points...>, FVec2>);
865
866 FBounds2D Result(P0, P0);
867 (Result.GrowToInclude(InPoints), ...);
868 return Result;
869 }
870
871 explicit FBounds2D(const FAABB3& In3DBounds)
872 {
874 }
875
876 void Set(const FAABB3& In3DBounds)
877 {
878 Min = {In3DBounds.Min()[0], In3DBounds.Min()[1]};
879 Max = {In3DBounds.Max()[0], In3DBounds.Max()[1]};
880 }
881
882 FVec2 GetExtent() const
883 {
884 return Max - Min;
885 }
886
887 bool IsInside(const FVec2& InPoint) const
888 {
889 return InPoint[0] >= Min[0] && InPoint[0] <= Max[0] && InPoint[1] >= Min[1] && InPoint[1] <= Max[1];
890 }
891
892 void GrowToInclude(const FVec2& InPoint)
893 {
894 Min = { FMath::Min(Min.X, InPoint.X), FMath::Min(Min.Y, InPoint.Y) };
895 Max = { FMath::Max(Max.X, InPoint.X), FMath::Max(Max.Y, InPoint.Y) };
896 }
897
898 void Inflate(const FVec2& InInflation)
899 {
900 Min -= InInflation;
901 Max += InInflation;
902 }
903
905 {
907 const FVec2 TestMin = Min + NudgeVec;
908 const FVec2 TestMax = Max - NudgeVec;
909
911
912 OutVec[0] = FMath::Max(OutVec[0], TestMin[0]);
913 OutVec[1] = FMath::Max(OutVec[1], TestMin[1]);
914
915 OutVec[0] = FMath::Min(OutVec[0], TestMax[0]);
916 OutVec[1] = FMath::Min(OutVec[1], TestMax[1]);
917
918 return OutVec;
919 }
920
921 bool IntersectLine(const FVec2& InStart, const FVec2& InEnd)
922 {
923 if(IsInside(InStart) || IsInside(InEnd))
924 {
925 return true;
926 }
927
928 const FVec2 Extent = GetExtent();
929 FReal TA, TB;
930
931 if(Utilities::IntersectLineSegments2D(InStart, InEnd, Min, FVec2(Min[0] + Extent[0], Min[1]), TA, TB)
932 || Utilities::IntersectLineSegments2D(InStart, InEnd, Min, FVec2(Min[0], Min[1] + Extent[1]), TA, TB)
933 || Utilities::IntersectLineSegments2D(InStart, InEnd, Max, FVec2(Max[0] - Extent[0], Max[1]), TA, TB)
934 || Utilities::IntersectLineSegments2D(InStart, InEnd, Max, FVec2(Max[0], Max[1] - Extent[1]), TA, TB))
935 {
936 return true;
937 }
938
939 return false;
940 }
941
942 bool ClipLine(const FVec3& InStart, const FVec3& InEnd, FVec2& OutClippedStart, FVec2& OutClippedEnd) const
943 {
945 FVec2 TempEnd(InEnd[0], InEnd[1]);
946
947 bool bLineIntersects = ClipLine(TempStart, TempEnd);
948
951
952 return bLineIntersects;
953 }
954
955 bool ClipLine(FVec2& InOutStart, FVec2& InOutEnd) const
956 {
957
958 // Test we don't need to clip at all, quite likely with a heightfield so optimize for it.
959 const bool bStartInside = IsInside(InOutStart);
960 const bool bEndInside = IsInside(InOutEnd);
962 {
963 return true;
964 }
965
966 const FVec2 Dir = InOutEnd - InOutStart;
967
968 // Tiny ray not inside so must be outside
969 if(Dir.SizeSquared() < 1e-4)
970 {
971 return false;
972 }
973
974 bool bPerpendicular[2];
975 FVec2 InvDir;
976 for(int Axis = 0; Axis < 2; ++Axis)
977 {
978 bPerpendicular[Axis] = Dir[Axis] == 0;
979 InvDir[Axis] = bPerpendicular[Axis] ? 0 : 1 / Dir[Axis];
980 }
981
982
983
984 if(bStartInside)
985 {
986 const FReal TimeToExit = ComputeTimeToExit(InOutStart,InvDir);
988 return true;
989 }
990
991 if(bEndInside)
992 {
993 const FReal TimeToExit = ComputeTimeToExit(InOutEnd,-InvDir);
995 return true;
996 }
997
998 //start and end outside, need to see if we even intersect
1001
1002 for(int Axis = 0; Axis < 2; ++Axis)
1003 {
1004 if(bPerpendicular[Axis])
1005 {
1006 if(InOutStart[Axis] >= Min[Axis] && InOutStart[Axis] <= Max[Axis])
1007 {
1008 TimesToEnter[Axis] = 0;
1009 }
1010 }
1011 else
1012 {
1013 if(Dir[Axis] > 0)
1014 {
1015 if(InOutStart[Axis] <= Max[Axis])
1016 {
1017 TimesToEnter[Axis] = FMath::Max<FReal>(Min[Axis] - InOutStart[Axis], 0) * InvDir[Axis];
1018 TimesToExit[Axis] = (Max[Axis] - InOutStart[Axis]) * InvDir[Axis];
1019 }
1020 }
1021 else if(Dir[Axis] < 0)
1022 {
1023 if(InOutStart[Axis] >= Min[Axis])
1024 {
1025 TimesToEnter[Axis] = FMath::Max<FReal>(InOutStart[Axis] - Max[Axis],0) * InvDir[Axis];
1026 TimesToExit[Axis] = (InOutStart[Axis] - Min[Axis]) * InvDir[Axis];
1027 }
1028 }
1029 }
1030 }
1031
1032 const FReal TimeToEnter = FMath::Max(FMath::Abs(TimesToEnter[0]),FMath::Abs(TimesToEnter[1]));
1033 const FReal TimeToExit = FMath::Min(FMath::Abs(TimesToExit[0]),FMath::Abs(TimesToExit[1]));
1034
1036 {
1037 //no intersection
1038 return false;
1039 }
1040
1041 InOutEnd = InOutStart + Dir * TimeToExit;
1043 return true;
1044 }
1045
1046 private:
1047 //This helper assumes Start is inside the min/max box and uses InvDir to compute how long it takes to exit
1048 FReal ComputeTimeToExit(const FVec2& Start,const FVec2& InvDir) const
1049 {
1051 for(int Axis = 0; Axis < 2; ++Axis)
1052 {
1053 if(InvDir[Axis] > 0)
1054 {
1055 Times[Axis] = (Max[Axis] - Start[Axis]) * InvDir[Axis];
1056 }
1057 else if(InvDir[Axis] < 0)
1058 {
1059 Times[Axis] = (Start[Axis] - Min[Axis]) * InvDir[Axis];
1060 }
1061 }
1062
1063 const FReal MinTime = FMath::Min(FMath::Abs(Times[0]),FMath::Abs(Times[1]));
1064 return MinTime;
1065 }
1066 };
1067
1068 // Helpers for accessing bounds
1069 CHAOS_API bool GetCellBounds2D(const TVec2<int32> InCoord, FBounds2D& OutBounds, const FVec2& InInflate = {0}) const;
1070 CHAOS_API bool GetCellBounds3D(const TVec2<int32> InCoord, FVec3& OutMin, FVec3& OutMax, const FVec3& InInflate = FVec3(0)) const;
1071 CHAOS_API bool GetCellBounds2DScaled(const TVec2<int32> InCoord, FBounds2D& OutBounds, const FVec2& InInflate = {0}) const;
1072 CHAOS_API bool GetCellBounds3DScaled(const TVec2<int32> InCoord, FVec3& OutMin, FVec3& OutMax, const FVec3& InInflate = FVec3(0)) const;
1073 CHAOS_API bool CalcCellBounds3D(const TVec2<int32> InCoord, FVec3& OutMin, FVec3& OutMax, const FVec3& InInflate = FVec3(0)) const;
1074
1075 // Query functions - sweep, ray, overlap
1076 template<typename SQVisitor>
1077 bool GridSweep(const FVec3& StartPoint, const FVec3& Dir, const FReal Length, const FVec3 InHalfExtents, SQVisitor& Visitor) const;
1078
1079 struct FWalkingData {
1080
1081 explicit FWalkingData(FHeightfieldRaycastVisitor& VisitorIn) : Visitor(VisitorIn) {}
1082 VectorRegister4Float CurrentLengthSimd;
1083 FVec2 ScaledMin;
1084 FReal CurrentLength;
1085 FReal ZMidPoint;
1086 FVec3 Dir;
1087 FVec3 InvDir;
1088 FVec3 NextStart;
1089 FVec3 ScaleSign;
1090 FVec3 ScaledDx;
1091 FVec2 ScaledDx2D;
1092 TVec2<int32> CellIdx;
1093 bool bParallel[3];
1094 FHeightfieldRaycastVisitor& Visitor;
1095 };
1096
1097 CHAOS_API bool WalkSlow(FWalkingData& WalkingData, int32 IndexLowResX, int32 IndexLowResY) const;
1098 CHAOS_API bool WalkFast(FWalkingData& WalkingData, const FVec2& Scale2D, const FVec3& DirScaled) const;
1099 CHAOS_API bool WalkOnLowRes(FWalkingData& WalkingData, const FVec2& Scale2D, const FVec3& DirScaled) const;
1100
1101 CHAOS_API bool GridCast(const FVec3& StartPoint, const FVec3& Dir, const FReal Length, FHeightfieldRaycastVisitor& Visitor) const;
1102 CHAOS_API bool GetGridIntersections(FBounds2D InFlatBounds, TArray<TVec2<int32>>& OutInterssctions) const;
1103 CHAOS_API bool GetGridIntersectionsBatch(FBounds2D InFlatBounds, TArray<TVec2<int32>>& OutIntersections, const FAABBVectorized& Bounds) const;
1104
1105 // Get the cell range that overlaps the QueryBounds (local space). NOTE: OutEndCell is like an end iterator (i.e., BeginCell==EndCell is an empty range)
1106 // NOTE: This is a 2D overlap, ignoring height
1107 CHAOS_API bool GetOverlappingCellRange(const FAABB3& QueryBounds, TVec2<int32>& OutBeginCell, TVec2<int32>& OutEndCell) const;
1108
1109 CHAOS_API FBounds2D GetFlatBounds() const;
1110
1111 // Grid for queries, faster than bounding volumes for heightfields
1112 TUniformGrid<FReal, 2> FlatGrid;
1113 // Bounds in 2D of the whole heightfield, to clip queries against
1114 FBounds2D FlattenedBounds;
1115 // 3D bounds for the heightfield, for insertion to the scene structure
1116 FAABB3 LocalBounds;
1117 // Cached when bounds are requested. Mutable to allow GetBounds to be logical const
1118 mutable FAABB3 CachedBounds;
1119
1120 CHAOS_API void CalcBounds();
1121 CHAOS_API void BuildQueryData();
1122
1123 // Needed for serialization
1124 FHeightField() : FImplicitObject(EImplicitObject::HasBoundingBox, ImplicitObjectType::HeightField) {}
1125 friend FImplicitObject;
1126
1127 template <typename QueryGeomType>
1128 bool OverlapGeomImp(const QueryGeomType& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FMTDInfo* OutMTD = nullptr) const;
1129
1130 template <typename QueryGeomType>
1131 bool SweepGeomImp(const QueryGeomType& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, const FReal Thickness, bool bComputeMTD) const;
1132
1133 template <typename QueryGeomType>
1134 bool SweepGeomCCDImp(const QueryGeomType& QueryGeom, const FRigidTransform3& StartTM, const FVec3& Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal& OutTOI, FReal& OutPhi, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex) const;
1135
1136 template <typename GeomType>
1137 bool GJKContactPointImp(const GeomType& QueryGeom, const FRigidTransform3& QueryTM, const FReal Thickness, FVec3& ContactLocation, FVec3& ContactNormal, FReal& ContactPhi, int32& ContactFaceIndex) const;
1138 };
1139
1140 FORCEINLINE FChaosArchive& operator<<(FChaosArchive& Ar, FHeightField::FDataType::MinMaxHeights& Value)
1141 {
1142 Value.Serialize(Ar);
1143 return Ar;
1144 }
1145}
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define ensure( InExpression)
Definition AssertionMacros.h:464
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ 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
const uint32 MaxHeight
Definition GameplayMediaEncoder.cpp:50
FORCEINLINE VectorRegister4Float VectorMin(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1686
FORCEINLINE VectorRegister4Float VectorMultiply(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:758
FORCEINLINE VectorRegister4Float VectorMax(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1713
FORCEINLINE VectorRegister4Double MakeVectorRegisterDouble(uint64 X, uint64 Y, uint64 Z, uint64 W)
Definition UnrealMathFPU.h:185
FORCEINLINE VectorRegister4Float MakeVectorRegisterFloat(uint32 X, uint32 Y, uint32 Z, uint32 W)
Definition UnrealMathFPU.h:175
FORCEINLINE VectorRegister4Float MakeVectorRegisterFloatFromDouble(const VectorRegister4Double &Vec4d)
Definition UnrealMathFPU.h:262
#define UE_BIG_NUMBER
Definition UnrealMathUtility.h:132
#define UE_SMALL_NUMBER
Definition UnrealMathUtility.h:130
uint8_t uint8
Definition binka_ue_file_header.h:8
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition AABBVectorized.h:15
Definition Capsule.h:23
Definition ChaosArchive.h:364
Definition ChaosArchive.h:167
Definition Convex.h:26
Definition HeightField.h:32
CHAOS_API FClosestFaceData FindClosestFace(const FVec3 &Position, FReal SearchDist) const
Definition HeightField.cpp:2356
CHAOS_API FReal GetHeightAt(const FVec2 &InGridLocationLocal) const
Definition HeightField.cpp:981
virtual bool IsOverlappingBoundsImpl(const FAABB3 &QueryBounds) const override final
Definition HeightField.h:267
virtual uint16 GetMaterialIndex(uint32 HintIndex) const override
Definition HeightField.h:312
void SetScale(const FVec3 &InScale)
Definition HeightField.h:391
CHAOS_API uint8 GetMaterialIndexAt(const FVec2 &InGridLocationLocal) const
Definition HeightField.cpp:882
CHAOS_API bool GJKContactPoint(const TBox< FReal, 3 > &QueryGeom, const FRigidTransform3 &QueryTM, const FReal Thickness, FVec3 &ContactLocation, FVec3 &ContactNormal, FReal &ContactPhi, int32 &ContactFaceIndex) const
Definition HeightField.cpp:1876
CHAOS_API uint8 GetMaterialIndex(int32 InIndex) const
Definition HeightField.cpp:872
virtual void VisitOverlappingLeafObjectsImpl(const FAABB3 &QueryBounds, const FRigidTransform3 &ObjectTransform, const int32 RootObjectIndex, int32 &ObjectIndex, int32 &LeafObjectIndex, const FImplicitHierarchyVisitor &VisitorFunc) const override final
Definition HeightField.h:251
virtual void Serialize(FChaosArchive &Ar) override
Definition HeightField.h:363
virtual ~FHeightField()
Definition HeightField.h:43
FHeightField(const FHeightField &Other)=delete
virtual CHAOS_API int32 FindMostOpposingFace(const FVec3 &Position, const FVec3 &UnitDir, int32 HintFaceIndex, FReal SearchDist) const override
Definition HeightField.cpp:2298
CHAOS_API FVec3 GetPointScaled(int32 InIndex) const
Definition HeightField.cpp:855
void GetTransformedTriangle(const int32 TriangleIndex, const FRigidTransform3 &Transform, FTriangle &OutTriangle, int32 &OutVertexIndex0, int32 &OutVertexIndex1, int32 &OutVertexIndex2) const
Generate the triangle at the specified index with the specified transform (including scale)
Definition HeightField.h:112
CHAOS_API bool OverlapGeom(const FSphere &QueryGeom, const FRigidTransform3 &QueryTM, const FReal Thickness, FMTDInfo *OutMTD=nullptr) const
Definition HeightField.cpp:2112
virtual const FAABB3 BoundingBox() const
Definition HeightField.h:337
virtual uint32 GetTypeHash() const override
Definition HeightField.h:345
int32 GetNumRows() const
Definition HeightField.h:59
virtual FName GetTypeName() const
Definition ImplicitObject.h:414
static constexpr EImplicitObjectType StaticType()
Definition HeightField.h:358
void VisitTriangles(const FAABB3 &QueryBounds, const FRigidTransform3 &QueryTransform, const TriangleVisitor &Visitor) const
Definition HeightField.h:181
void CollectTriangles(const FAABB3 &QueryBounds, const FRigidTransform3 &QueryTransform, const FAABB3 &ObjectBounds, Private::FMeshContactGenerator &Collector) const
Definition HeightField.cpp:2531
int32 GetNumCols() const
Definition HeightField.h:60
CHAOS_API bool SweepGeomCCD(const FSphere &QueryGeom, const FRigidTransform3 &StartTM, const FVec3 &Dir, const FReal Length, const FReal IgnorePenetration, const FReal TargetPenetration, FReal &OutTOI, FReal &OutPhi, FVec3 &OutPosition, FVec3 &OutNormal, int32 &OutFaceIndex, FVec3 &OutFaceNormal) const
Definition HeightField.cpp:2258
FDataType GeomData
Definition HeightField.h:835
CHAOS_API FReal GetHeight(int32 InIndex) const
Definition HeightField.cpp:844
CHAOS_API void EditHeights(TArrayView< FReal > InHeights, int32 InBeginRow, int32 InBeginCol, int32 InNumRows, int32 InNumCols)
Definition HeightField.cpp:809
virtual CHAOS_API FVec3 FindGeometryOpposingNormal(const FVec3 &DenormDir, int32 FaceIndex, const FVec3 &OriginalNormal) const override
Definition HeightField.cpp:2421
CHAOS_API bool IsHole(int32 InIndex) const
Definition HeightField.cpp:897
virtual CHAOS_API FReal PhiWithNormal(const FVec3 &x, FVec3 &Normal) const
Definition HeightField.cpp:2488
CHAOS_API bool SweepGeom(const FSphere &QueryGeom, const FRigidTransform3 &StartTM, const FVec3 &Dir, const FReal Length, FReal &OutTime, FVec3 &OutPosition, FVec3 &OutNormal, int32 &OutFaceIndex, FVec3 &OutFaceNormal, const FReal Thickness=0, bool bComputeMTD=false) const
Definition HeightField.cpp:2180
bool IsOverlappingAnyCells(const FAABB3 &QueryBounds) const
Definition HeightField.h:275
CHAOS_API FVec3 GetNormalAt(const FVec2 &InGridLocationLocal) const
Definition HeightField.cpp:975
Definition ImplicitObject.h:111
bool HasBoundingBox() const
Definition ImplicitObject.h:275
virtual FName GetTypeName() const
Definition ImplicitObject.h:414
CHAOS_API void SerializeImp(FArchive &Ar)
Definition ImplicitObject.cpp:337
Definition MeshContactGenerator.h:249
static TAABB< FReal, d > FromPoints(const TVector< FReal, d > &P0, const Points &... InPoints)
Definition AABB.h:699
FORCEINLINE const TVector< T, d > & Max() const
Definition AABB.h:596
FORCEINLINE bool Intersects(const TAABB< TReal, d > &Other) const
Definition AABB.h:112
FORCEINLINE const TVector< T, d > & Min() const
Definition AABB.h:595
Definition Box.h:23
static void SerializeAsAABB(FArchive &Ar, TAABB< T, d > &AABB)
Definition Box.h:467
Definition ImplicitObjectScaled.h:447
TVector< int32, d > Cell(const TVector< T, d > &X) const
Definition UniformGrid.h:157
virtual void Serialize(void *V, int64 Length) override
Definition ArchiveProxy.h:97
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 MemoryWriter.h:101
Definition ArrayView.h:139
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT bool IsValidIndex(SizeType Index) const
Definition Array.h:1122
Definition AssetRegistryState.h:50
@ HeightField
Definition ImplicitObjectType.h:25
Definition BodyInstance.h:90
bool IntersectLineSegments2D(const TVec2< T > &InStartA, const TVec2< T > &InEndA, const TVec2< T > &InStartB, const TVec2< T > &InEndB, T &OutTA, T &OutTB)
Definition Utilities.h:383
Definition SkeletalMeshComponent.h:307
TRigidTransform< FReal, 3 > FRigidTransform3
Definition Core.h:22
uint8 EImplicitObjectType
Definition ImplicitObjectType.h:41
TTriangle< FReal > FTriangle
Definition ImplicitFwd.h:31
@ Y
Definition SimulationModuleBase.h:153
@ X
Definition SimulationModuleBase.h:152
FChaosArchive & operator<<(FChaosArchive &Ar, FRigidParticleControlFlags &Flags)
Definition RigidParticleControlFlags.cpp:15
FRealDouble FReal
Definition Real.h:22
float FRealSingle
Definition Real.h:14
@ Raycast
Definition SimulationModuleBase.h:145
TVector< FReal, 3 > FVec3
Definition Core.h:17
TAABB< FReal, 3 > FAABB3
Definition ImplicitObject.h:34
TVector< FReal, 2 > FVec2
Definition Core.h:16
@ Visitor
Definition XmppMultiUserChat.h:94
U16 Index
Definition radfft.cpp:71
Definition HeightField.h:304
int32 FaceIndex
Definition HeightField.h:305
bool bWasSampleBehind
Definition HeightField.h:307
FReal DistanceToFaceSq
Definition HeightField.h:306
Definition HeightField.h:427
void Serialize(FChaosArchive &Ar)
Definition HeightField.h:431
StorageType Max
Definition HeightField.h:429
StorageType Min
Definition HeightField.h:428
Definition HeightField.h:399
FORCEINLINE void GetPointsScaled(int32 Index, FVec3 OutPts[4]) const
Definition HeightField.h:634
TArray< uint8 > MaterialIndices
Definition HeightField.h:438
FORCEINLINE FReal GetMaxHeight() const
Definition HeightField.h:726
FORCEINLINE void GetPoints(int32 Index, FVec3 OutPts[4]) const
Definition HeightField.h:496
void BuildLowResolutionData()
Definition HeightField.h:804
FORCEINLINE void GetBoundsScaled(TVec2< int32 > CellIdx, FAABBVectorized &OutBounds) const
Definition HeightField.h:697
FORCEINLINE void GetBoundsSimd(int32 Index, FAABBVectorized &OutBounds) const
Definition HeightField.h:555
FORCEINLINE FVec3 GetPoint(int32 Index) const
Definition HeightField.h:481
FORCEINLINE void GetBoundsScaledSimd(int32 Index, FAABBVectorized &OutBounds) const
Definition HeightField.h:673
FORCEINLINE int32 CellIndexToVertexIndex(const int32 CellIndex) const
Convert a Cell Index to a Vertex Index. Returns the vertex index of the first corner in the cell....
Definition HeightField.h:474
constexpr FReal GetCellHeight() const
Definition HeightField.h:454
uint16 NumRows
Definition HeightField.h:443
static constexpr int32 RealSize
Definition HeightField.h:412
FVec3 Scale
Definition HeightField.h:439
FORCEINLINE void GetPointsAndBoundsSimd(int32 Index, VectorRegister4Float OutPts[4], FAABBVectorized &OutBounds) const
Definition HeightField.h:533
FORCEINLINE FVec3 GetPointScaled(int32 Index) const
Definition HeightField.h:491
uint16 NumColsLowRes
Definition HeightField.h:447
TArray< StorageType > Heights
Definition HeightField.h:424
FReal MaxValue
Definition HeightField.h:442
void Serialize(FChaosArchive &Ar)
Definition HeightField.h:731
FORCEINLINE void GetLowResBoundsScaled(TVec2< int32 > CellIdx, FAABBVectorized &OutBounds) const
Definition HeightField.h:709
FORCEINLINE void GetPointsAndBounds(int32 Index, FVec3 OutPts[4], FAABB3 &OutBounds) const
Definition HeightField.h:512
FReal HeightPerUnit
Definition HeightField.h:446
FORCEINLINE void GetBoundsScaled(TVec2< int32 > CellIdx, TVec2< int32 > Area, FAABBVectorized &OutBounds) const
Definition HeightField.h:685
FORCEINLINE void GetLowResBounds(TVec2< int32 > CellIdx, FAABBVectorized &OutBounds) const
Definition HeightField.h:614
static constexpr int32 LowResInc
Definition HeightField.h:418
FORCEINLINE void GetPointsAndBoundsScaledSimd(int32 Index, VectorRegister4Float OutPts[4], FAABBVectorized &OutBounds) const
Definition HeightField.h:656
constexpr FReal GetCellWidth() const
Definition HeightField.h:449
static constexpr int32 StorageRange
Definition HeightField.h:416
InStorageType StorageType
Definition HeightField.h:401
FORCEINLINE FReal GetMinHeight() const
Definition HeightField.h:721
FORCEINLINE void GetBounds(TVec2< int32 > CellIdx, TVec2< int32 > Area, FAABBVectorized &OutBounds) const
Definition HeightField.h:572
static constexpr int32 StorageSize
Definition HeightField.h:413
uint16 NumCols
Definition HeightField.h:444
VectorRegister4Float ScaleSimd
Definition HeightField.h:440
FReal Range
Definition HeightField.h:445
FReal MinValue
Definition HeightField.h:441
TArray< MinMaxHeights > LowResolutionHeights
Definition HeightField.h:437
FORCEINLINE void GetPointsAndBoundsScaled(int32 Index, FVec3 OutPts[4], FAABB3 &OutBounds) const
Definition HeightField.h:644
Definition GeometryQueries.h:27
static UE_FORCEINLINE_HINT uint32 MemCrc32(const void *Data, int32 Length, uint32 CRC=0)
Definition Crc.h:31
CORE_API static const FGuid GUID
Definition ExternalPhysicsCustomObjectVersion.h:144
@ HeightfieldData
Definition ExternalPhysicsCustomObjectVersion.h:34
@ HeightfieldImplicitBounds
Definition ExternalPhysicsCustomObjectVersion.h:82
@ HeightfieldUsesHeightsDirectly
Definition ExternalPhysicsCustomObjectVersion.h:109
@ AddedMaterialManager
Definition ExternalPhysicsCustomObjectVersion.h:67
CORE_API static const FGuid GUID
Definition UE5MainStreamObjectVersion.h:22
Definition NumericLimits.h:41
Definition UnrealMathFPU.h:20