UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
HierarchicalSpatialHashGrid.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "EngineDefines.h"
8#include "SceneCullingDefinitions.h"
10#include "SpanAllocator.h"
11#include "Tasks/Task.h"
12
15
16// Test implemented for perf comparison, may not scale exactly as size grows & not fully featured.
17#define USE_STATIC_HASH_TABLE 0
18
19#if USE_STATIC_HASH_TABLE
20template <typename InKeyType, typename InValueType>
22{
23public:
24 using KeyType = InKeyType;
25 using ValueType = InValueType;
26 struct FElement
27 {
28 KeyType Key;
29 ValueType Value;
30 };
31
32 struct FElementId
33 {
34 inline FElementId(int32 InIndex = INDEX_NONE)
35 : Index(InIndex)
36 {
37 }
39
40 int32 GetIndex() const { return Index; }
41 bool IsValid() const { return Index != INDEX_NONE; }
42 };
43
45
46 void Empty()
47 {
48 Elements.Reset();
49 HashTable.Clear();
50 }
51
52 void Reserve(int32 Num)
53 {
54 Elements.Reserve(Num);
55 }
56
57 inline FElementId FindIdByHash(uint16 Hash, const KeyType& Location) const
58 {
59 for (uint16 Index = HashTable.First(Hash); HashTable.IsValid(Index); Index = HashTable.Next(Index))
60 {
61 if (Hasher::Matches(Elements[Index].Key, Location))
62 {
63 return FElementId{ int32(Index) };
64 }
65 }
66 return FElementId{};
67 }
68
69 inline FElementId FindId(const KeyType& Location) const
70 {
71 uint16 Hash = uint16(Hasher::GetKeyHash(Location));
72 return FindIdByHash(Hash, Location);
73 }
74
75 inline FElementId FindOrAddId(const KeyType& Location, const ValueType& Value)
76 {
77 uint16 Hash = uint16(Hasher::GetKeyHash(Location));
78 FElementId Id = FindIdByHash(Hash, Location);
79 if (!Id.IsValid())
80 {
81 int32 NewIndex = Elements.Num();
82 Elements.Add(FElement{ Location, Value });
83 HashTable.Add(Hash, NewIndex);
84 Id = FElementId{ NewIndex };
85 }
86 return Id;
87 }
88
89 inline int32 GetMaxIndex() const { return Elements.Num(); }
90 inline int32 Num() const { return Elements.Num(); }
91
92 inline FElement& GetByElementId(FElementId Id) { return Elements[Id.Index]; }
93 inline const FElement& GetByElementId(FElementId Id) const { return Elements[Id.Index]; }
94
95 class FConstIteratorType
96 {
98
100
101 int32 Index;
102
103 inline FConstIteratorType(const TSpatialHashMap<KeyType, ValueType>& InTheMap, bool bIsStartIterator) : TheMap(InTheMap)
104 {
106 {
107 Index = 0;
108 }
109 else
110 {
111 Index = TheMap.Elements.Num();
112 }
113 }
114
115 public:
116 inline bool operator ==(const FConstIteratorType& Rhs) const
117 {
118 return Index == Rhs.Index;
119 }
120
121 inline bool operator !=(const FConstIteratorType& Rhs) const
122 {
123 return Index != Rhs.Index;
124 }
125
126 inline const FElement& operator*() const
127 {
128 return TheMap.Elements[Index];
129 }
130
131 inline FConstIteratorType& operator++()
132 {
133 ++Index;
134 return *this;
135 }
136
137 inline FElementId GetElementId() const
138 {
139 return FElementId{ Index };
140 }
141 };
142
143 inline FConstIteratorType begin() const
144 {
145 return FConstIteratorType(*this, true);
146 }
147
148 inline FConstIteratorType end() const
149 {
150 return FConstIteratorType(*this, false);
151 }
152
153 TArray<FElement> Elements;
155};
156
157#endif
158
159
160
162{
163 return FInt64Vector(FMath::FloorToInt(Vector.X), FMath::FloorToInt(Vector.Y), FMath::FloorToInt(Vector.Z));
164};
165
166template <typename BlockTraitsType>
168{
169public:
170 using FBlockLoc = typename BlockTraitsType::FBlockLoc;
171
172 static constexpr int32 CellBlockDimLog2 = BlockTraitsType::CellBlockDimLog2;
173 static constexpr int32 kMaxLevel = 64;
174 static constexpr int32 NumCellsPerBlockLog2 = CellBlockDimLog2 * 3; // number of bits needed for a local cell ID
175 static constexpr int32 CellBlockDim = 1 << CellBlockDimLog2;
178
183
184 template <typename ScalarType>
186 {
188
189 template <typename LambdaType>
190 inline void ForEach(LambdaType Lambda)
191 {
192 for (ScalarType Z = Min.Z; Z <= Max.Z; ++Z)
193 {
194 for (ScalarType Y = Min.Y; Y <= Max.Y; ++Y)
195 {
196 for (ScalarType X = Min.X; X <= Max.X; ++X)
197 {
200 L.Level = Level;
201 Lambda(L);
202 }
203 }
204 }
205 }
206
210 };
211
215
217 {
218 static uint32 constexpr CoarseCellMaskDimLog2 = 2U; // 2^2 == 4 -> 4x4x4 == 64
219 static uint32 constexpr CoarseCellMaskDim = 1U << CoarseCellMaskDimLog2; // 2^2 == 4 -> 4x4x4 == 64
220 static uint32 constexpr CoarseCellMaskCoordMask = (1U << CoarseCellMaskDimLog2) - 1u; // 2^2 == 4 -> 4x4x4 == 64
221
222 inline static int32 CalcCellOffset(const FInt8Vector3& Loc)
223 {
224 return ((int32(Loc.Z) * CellBlockDim) + int32(Loc.Y)) * CellBlockDim + int32(Loc.X);
225 };
226
228 {
229 return GridOffset + CalcCellOffset(Loc);
230 }
235
236 inline static uint64 CalcCellMask(const FInt8Vector3& Loc)
237 {
239 return 1ULL << CalcCellMaskOffset(MaskLoc);
240 };
241
243 {
247
248 uint64 Result = 0ULL;
249 // TODO: make this not stupid... figure out bit intervals etc, do incrementally.
250 FootprintInCoarse.ForEach([&](const FLocation8& Loc)
251 {
252 Result |= (1ULL << CalcCellMaskOffset(Loc.Coord));
253 });
254
255 return Result;
256 }
257
261 };
262
263
265
267 {
268 // Subtract 1 to make sure that intuitively, when we set a cell size of exact POT e.g., 4096, that is what we get (not the correctly conservative 8192).
269 FirstLevel = CalcLevel(MinCellSize - 1.0);
270 LastLevel = CalcLevel(MaxCellSize - 1.0);
271 check(GetCellSize(FirstLevel) >= MinCellSize && GetCellSize(FirstLevel - 1) < MinCellSize);
272 check(GetCellSize(LastLevel) >= MaxCellSize && GetCellSize(LastLevel - 1) < MaxCellSize);
273
274 LastLevelCellSize = GetCellSize(LastLevel);
275
276 // TODO: figure out number of bits in coordinate type minus those in the smallest level,
277 MaxCullingDistance = WORLD_MAX;
278
279 for (int32 Level = 0; Level < kMaxLevel; ++Level)
280 {
281 RecCellSizes[Level] = 1.0 / GetCellSize(Level);
282 }
283 }
284
285 void Empty()
286 {
287 HashMap.Empty();
288 }
289
290 inline int32 GetMaxNumBlocks() const { return HashMap.GetMaxIndex(); }
291
292 static inline int32 CalcLevel(float Size)
293 {
295 };
296
297 static inline int32 CalcLevelFromRadius(float Radius)
298 {
299 return CalcLevel(Radius * 2.0f);
300 };
301
302 static inline double GetCellSize(int32 Level)
303 {
305 };
306
307 inline double GetRecCellSize(int32 Level) const
308 {
309 return RecCellSizes[Level];
310 }
311
312 inline FLocation64 ToCellLoc(int32 Level, const FVector& WorldPos) const
313 {
314 FLocation64 Result;
315 double RecLevelCellSize = GetRecCellSize(Level);
316 Result.Level = Level;
318 return Result;
319 };
320
321 inline FFootprint64 CalcFootprintSphere(int32 Level, const FVector& Origin, double Radius) const
322 {
323 FFootprint64 Footprint;
324 double RecLevelCellSize = GetRecCellSize(Level);
325 Footprint.Level = Level;
326 Footprint.Min = FloorToInt64Vector((Origin - FVector(Radius, Radius, Radius)) * RecLevelCellSize);
327 Footprint.Max = FloorToInt64Vector((Origin + FVector(Radius, Radius, Radius)) * RecLevelCellSize);
328 return Footprint;
329 };
330
331 static inline FFootprint64 CalcCellBlockFootprint(const FFootprint64& Footprint)
332 {
334 BlockFootprint.Min = Footprint.Min >> CellBlockDimLog2;
335 BlockFootprint.Max = Footprint.Max >> CellBlockDimLog2;
336 BlockFootprint.Level = Footprint.Level + CellBlockDimLog2;
337 return BlockFootprint;
338 };
339
341 {
342 // Can't be lower than this, or the footprint might be larger than 2x2x2, globally the same, can pre-calc.
343 int32 Level = CalcLevelFromRadius(BoxSphereBounds.SphereRadius);
344
345 // Clamp to lowest level represented in the grid
346 Level = FMath::Max(FirstLevel, Level);
347
348 double RecLevelCellSize = GetRecCellSize(Level);
349
350 FFootprint64 Footprint;
351 Footprint.Level = Level;
352 Footprint.Min = FloorToInt64Vector((BoxSphereBounds.Origin - BoxSphereBounds.BoxExtent) * RecLevelCellSize);
353 Footprint.Max = FloorToInt64Vector((BoxSphereBounds.Origin + BoxSphereBounds.BoxExtent) * RecLevelCellSize);
354 return Footprint;
355 };
356
358 {
359 int32 Level = CalcLevelFromRadius(BoxSphereBounds.SphereRadius);
360
361 // Clamp to lowest level represented in the grid
362 Level = FMath::Max(FirstLevel, Level);
363
364 return ToCellLoc(Level, BoxSphereBounds.Origin);
365 };
366
368 {
370
371 // Clamp to lowest level represented in the grid
372 Level = FMath::Max(FirstLevel, Level);
373
374 return ToCellLoc(Level, FVector(Sphere));
375 };
376
377 inline bool IsValidLevel(int32 Level) const
378 {
379 return Level >= FirstLevel && Level <= LastLevel;
380 }
381
382 inline double GetLastLevelCellSize() const
383 {
384 return LastLevelCellSize;
385 }
386
387 inline double GetMaxCullingDistance() const
388 {
389 return MaxCullingDistance;
390 }
391 inline int32 NumLevels() const { return LastLevel - FirstLevel + 1; }
392
393 // Padded by half a cell size because of loose bounds
395 {
396 FBox Box;
397 double LevelCellSize = GetCellSize(CellLoc.Level);
398 Box.Min = FVector(CellLoc.Coord) * LevelCellSize;
399 Box.Max = Box.Min + LevelCellSize;
400
401 // Extend extent by half a cell size in all directions
402 Box.Min -= FVector(LevelCellSize * 0.5);
403 Box.Max += FVector(LevelCellSize * 0.5);
404
405 return Box;
406 }
407
408 // Padded by half a cell size since loose (NOT 1/2 block size!)
410 {
411 FBox Box;
412 double BlockLevelSize = GetCellSize(BlockLoc.Level);
413 Box.Min = FVector(BlockLoc.Coord) * BlockLevelSize;
414 Box.Max = Box.Min + BlockLevelSize;
415
416 // Extend extent by half a cell size in all directions
418 Box.Min -= FVector(LevelCellSize * 0.5);
419 Box.Max += FVector(LevelCellSize * 0.5);
420
421 return Box;
422 }
423
431
436 {
437 return BlockLoc.GetWorldPosition();
438 }
439
440 int32 GetFirstLevel() const { return FirstLevel; }
441
442#if USE_STATIC_HASH_TABLE
444 using FHashElementId = typename FSpatialHashMap::FElementId;
445 using FBlockId = typename FSpatialHashMap::FElementId;
446#else
447
448 struct FHasher : public TDefaultMapKeyFuncs<FBlockLoc, FCellBlock, false>
449 {
451 {
452 return Key.GetHash();
453 }
454 };
455
459
460#endif
461
462
463 FCellBlock &GetBlockById(const FBlockId &BlockId) { return HashMap.GetByElementId(BlockId).Value; }
464 const FCellBlock &GetBlockById(const FBlockId &BlockId) const { return HashMap.GetByElementId(BlockId).Value; }
465
466 FBlockLoc GetBlockLocById(const FBlockId &BlockId) const { return HashMap.GetByElementId(BlockId).Key; }
467
468 const FSpatialHashMap &GetHashMap() const { return HashMap; };
469 FSpatialHashMap &GetHashMap() { return HashMap; };
470
471private:
472 int32 FirstLevel;
473 int32 LastLevel;
474 double RecCellSizes[kMaxLevel];
475 double LastLevelCellSize;
476 double MaxCullingDistance;
477 FSpatialHashMap HashMap;
478};
479
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define check(expr)
Definition AssertionMacros.h:314
UE_FORCEINLINE_HINT FLinearColor operator*(float Scalar, const FLinearColor &Color)
Definition Color.h:473
@ INDEX_NONE
Definition CoreMiscDefines.h:150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define WORLD_MAX
Definition EngineDefines.h:53
#define X(Name, Desc)
Definition FormatStringSan.h:47
FInt64Vector FloorToInt64Vector(const FVector &Vector)
Definition HierarchicalSpatialHashGrid.h:161
#define FVector
Definition IOSSystemIncludes.h:8
UE_FORCEINLINE_HINT bool operator!=(const FIndexedPointer &Other) const
Definition LockFreeList.h:76
FInt64Vector3 FInt64Vector
Definition MathFwd.h:101
@ Num
Definition MetalRHIPrivate.h:234
uint32 Size
Definition VulkanMemory.cpp:4034
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition RobinHoodHashTable.h:72
IndexType GetMaxIndex() const
Definition RobinHoodHashTable.h:852
void Empty()
Definition RobinHoodHashTable.h:1059
ElementType & GetByElementId(FHashElementId Id)
Definition RobinHoodHashTable.h:857
Definition ScenePrimitiveUpdates.h:129
Definition ScenePrimitiveUpdates.h:116
Definition Array.h:670
Definition HierarchicalSpatialHashGrid.h:168
FFootprint64 CalcFootprintSphere(int32 Level, const FVector &Origin, double Radius) const
Definition HierarchicalSpatialHashGrid.h:321
const FCellBlock & GetBlockById(const FBlockId &BlockId) const
Definition HierarchicalSpatialHashGrid.h:464
FFootprint64 CalcLevelAndFootprint(const FBoxSphereBounds &BoxSphereBounds) const
Definition HierarchicalSpatialHashGrid.h:340
static constexpr uint32 LocalCellCoordMask
Definition HierarchicalSpatialHashGrid.h:176
double GetMaxCullingDistance() const
Definition HierarchicalSpatialHashGrid.h:387
int32 GetMaxNumBlocks() const
Definition HierarchicalSpatialHashGrid.h:290
static constexpr int32 NumCellsPerBlockLog2
Definition HierarchicalSpatialHashGrid.h:174
int32 GetFirstLevel() const
Definition HierarchicalSpatialHashGrid.h:440
static double GetCellSize(int32 Level)
Definition HierarchicalSpatialHashGrid.h:302
int32 NumLevels() const
Definition HierarchicalSpatialHashGrid.h:391
static constexpr int32 CellBlockDimLog2
Definition HierarchicalSpatialHashGrid.h:172
Experimental::TRobinHoodHashMap< FBlockLoc, FCellBlock, FHasher > FSpatialHashMap
Definition HierarchicalSpatialHashGrid.h:456
FLocation64 CalcLevelAndLocation(const FBoxSphereBounds &BoxSphereBounds) const
Definition HierarchicalSpatialHashGrid.h:357
FLocation64 ToCellLoc(int32 Level, const FVector &WorldPos) const
Definition HierarchicalSpatialHashGrid.h:312
const FSpatialHashMap & GetHashMap() const
Definition HierarchicalSpatialHashGrid.h:468
double GetLastLevelCellSize() const
Definition HierarchicalSpatialHashGrid.h:382
FBox CalcCellBounds(const FLocation64 &CellLoc) const
Definition HierarchicalSpatialHashGrid.h:394
FCellBlock & GetBlockById(const FBlockId &BlockId)
Definition HierarchicalSpatialHashGrid.h:463
FVector3d CalcBlockWorldPosition(const FLocation64 &BlockLoc) const
Definition HierarchicalSpatialHashGrid.h:427
Experimental::FHashElementId FBlockId
Definition HierarchicalSpatialHashGrid.h:457
double GetRecCellSize(int32 Level) const
Definition HierarchicalSpatialHashGrid.h:307
void Empty()
Definition HierarchicalSpatialHashGrid.h:285
static FFootprint64 CalcCellBlockFootprint(const FFootprint64 &Footprint)
Definition HierarchicalSpatialHashGrid.h:331
Experimental::FHashElementId FHashElementId
Definition HierarchicalSpatialHashGrid.h:458
THierarchicalSpatialHashGrid(double MinCellSize, double MaxCellSize)
Definition HierarchicalSpatialHashGrid.h:266
static constexpr int32 CellBlockSize
Definition HierarchicalSpatialHashGrid.h:177
FBlockLoc GetBlockLocById(const FBlockId &BlockId) const
Definition HierarchicalSpatialHashGrid.h:466
static constexpr int32 CellBlockDim
Definition HierarchicalSpatialHashGrid.h:175
bool IsValidLevel(int32 Level) const
Definition HierarchicalSpatialHashGrid.h:377
FVector3d CalcBlockWorldPosition(const FBlockLoc &BlockLoc) const
Definition HierarchicalSpatialHashGrid.h:435
static int32 CalcLevelFromRadius(float Radius)
Definition HierarchicalSpatialHashGrid.h:297
static constexpr int32 kMaxLevel
Definition HierarchicalSpatialHashGrid.h:173
FBox CalcBlockBounds(const FLocation64 &BlockLoc) const
Definition HierarchicalSpatialHashGrid.h:409
static int32 CalcLevel(float Size)
Definition HierarchicalSpatialHashGrid.h:292
typename BlockTraitsType::FBlockLoc FBlockLoc
Definition HierarchicalSpatialHashGrid.h:170
FLocation64 CalcLevelAndLocation(const FVector4d &Sphere) const
Definition HierarchicalSpatialHashGrid.h:367
FSpatialHashMap & GetHashMap()
Definition HierarchicalSpatialHashGrid.h:469
Definition HashTable.h:94
FVector3d CalcWorldPosition(const FLocation64 &Loc)
Definition RenderingSpatialHash.h:139
int32 CalcLevel(double Size)
Definition RenderingSpatialHash.h:79
double GetCellSize(int32 Level)
Definition RenderingSpatialHash.h:96
U16 Index
Definition radfft.cpp:71
Definition RenderingSpatialHash.h:17
FIntVector3 Coord
Definition RenderingSpatialHash.h:19
int32 Level
Definition RenderingSpatialHash.h:20
Definition Map.h:111
Definition Map.h:77
Definition HierarchicalSpatialHashGrid.h:217
static uint32 constexpr CoarseCellMaskDimLog2
Definition HierarchicalSpatialHashGrid.h:218
uint64 CoarseCellMask
Definition HierarchicalSpatialHashGrid.h:258
int32 NumItemChunks
Definition HierarchicalSpatialHashGrid.h:260
static uint32 constexpr CoarseCellMaskDim
Definition HierarchicalSpatialHashGrid.h:219
int32 GridOffset
Definition HierarchicalSpatialHashGrid.h:259
static uint32 CalcCellMaskOffset(const FInt8Vector3 &MaskLoc)
Definition HierarchicalSpatialHashGrid.h:231
static uint64 CalcCellMask(const FInt8Vector3 &Loc)
Definition HierarchicalSpatialHashGrid.h:236
static uint32 constexpr CoarseCellMaskCoordMask
Definition HierarchicalSpatialHashGrid.h:220
static int32 CalcCellOffset(const FInt8Vector3 &Loc)
Definition HierarchicalSpatialHashGrid.h:222
int32 GetCellGridOffset(const FInt8Vector3 &Loc) const
Definition HierarchicalSpatialHashGrid.h:227
static uint64 BuildFootPrintMask(const FFootprint8 &FootprintInBlock)
Definition HierarchicalSpatialHashGrid.h:242
Definition HierarchicalSpatialHashGrid.h:449
static FORCEINLINE uint32 GetKeyHash(const FBlockLoc &Key)
Definition HierarchicalSpatialHashGrid.h:450
Definition HierarchicalSpatialHashGrid.h:186
int32 Level
Definition HierarchicalSpatialHashGrid.h:209
FIntVector3 Min
Definition HierarchicalSpatialHashGrid.h:207
FIntVector3 Max
Definition HierarchicalSpatialHashGrid.h:208
void ForEach(LambdaType Lambda)
Definition HierarchicalSpatialHashGrid.h:190
Definition BoxSphereBounds.h:25
Definition IntVector.h:22
IntType Y
Definition IntVector.h:34
IntType X
Definition IntVector.h:31
IntType Z
Definition IntVector.h:37