UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
DynamicBVH.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"
7#include "Math/Bounds.h"
8
10{
11 float operator()( const FBounds3f& Bounds ) const
12 {
13 FVector3f Extent = Bounds.Max - Bounds.Min;
14 return Extent.X * Extent.Y + Extent.X * Extent.Z + Extent.Y * Extent.Z;
15 }
16};
17
19{
20 int32 Num() const { return 0; }
21 void Add( uint32 Index ) {}
22 void Mark( uint32 Index ) {}
23
24 template< typename FFuncType >
25 void ForAll( const FFuncType& Func ) {}
26};
27
29{
32
33 int32 Num() const { return DirtyNodes.Num(); }
34
36 {
37 NodeIsDirty.Add( true );
39 }
40
42 {
43 if( !NodeIsDirty[ Index ] )
44 {
45 NodeIsDirty[ Index ] = true;
47 }
48 }
49
50 template< typename FFuncType >
51 void ForAll( const FFuncType& Func )
52 {
53 for( uint32 Index : DirtyNodes )
54 {
55 Func( Index );
56 NodeIsDirty[ Index ] = false;
57 }
59 }
60};
61
63{
64 struct FRoot
65 {
68
69 const FVector3f& ToRelative( const FVector3f& Position ) const { return Position; }
70 const FBounds3f& ToRelative( const FBounds3f& Other ) const { return Other; }
71 const FBounds3f& ToAbsolute( const FBounds3f& Other ) const { return Other; }
72 };
74
75 FRoot& FindOrAdd( const FBounds3f& Bounds ) { return Root; }
78
79 template< typename FFuncType >
80 void ForAll( const FFuncType& Func ) const
81 {
82 Func( Root );
83 }
84};
85
86// Supports LWC with a tile grid at the top where each tile points to a BVH in tile relative coordinates.
88{
89 struct FRoot
90 {
94
95 template< typename T >
97 {
98 return FVector3f( Position - Offset );
99 }
100
101 template< typename T >
103 {
104 return Other.ToRelative( Offset );
105 }
106
108 {
109 return Other.ToAbsolute( Offset );
110 }
111 };
113
114 template< typename T >
115 FRoot& FindOrAdd( const TBounds<T>& Bounds )
116 {
117 constexpr double TileSize = 1024.0 * 1024.0;
118
119 UE::Math::TVector<T> RootOffset = Bounds.GetCenter() / TileSize;
123 RootOffset *= TileSize;
124
125 FRoot* Root = Roots.FindByPredicate(
126 [ &RootOffset ]( FRoot& Root )
127 {
128 return Root.Offset == RootOffset;
129 } );
130
131 if( Root == nullptr )
132 {
133 Root = &Roots.AddDefaulted_GetRef();
135 Root->FirstChild = ~0u;
136 }
137
138 return *Root;
139 }
140
142 {
143 FRoot* Root = Roots.FindByPredicate(
145 {
146 return Root.FirstChild == RootFirstChild;
147 } );
148 check( Root );
149 return *Root;
150 }
151
153 {
154 Roots.RemoveAllSwap(
156 {
157 return Root.FirstChild == RootFirstChild;
158 },
160 }
161
162 template< typename FFuncType >
163 void ForAll( const FFuncType& Func ) const
164 {
165 for( const FRoot& Root : Roots )
166 {
167 Func( Root );
168 }
169 }
170};
171
172constexpr uint32 ConstLog2( uint32 x )
173{
174 return ( x < 2 ) ? 0 : 1 + ConstLog2( x / 2 );
175}
176
178{
180
181public:
182 void Reset()
183 {
184 CandidateHead = 0;
185 Candidates.Reset();
186 NumZeros = 0;
187 }
188
189 void Add( float NodeCost, uint32 NodeIndex )
190 {
191 if( NodeCost < UE_KINDA_SMALL_NUMBER && NumZeros < MaxZeros )
192 {
193 ZeroCostNodes[ NumZeros++ ] = NodeIndex;
194 }
195 else
196 {
197 Candidates.Add( FCandidate( NodeCost, NodeIndex ) );
198 }
199 }
200
201 bool GetNext( float BestCost, float& NodeCost, uint32& NodeIndex )
202 {
203 if( NumZeros )
204 {
205 NodeIndex = ZeroCostNodes[ --NumZeros ];
206 }
207 else
208 {
209 // Move head up
210 int32 Num = Candidates.Num();
211 while( CandidateHead < Num && Candidates[ CandidateHead ].Key >= BestCost )
212 CandidateHead++;
213 if( CandidateHead == Num )
214 return false;
215
216 // Find smallest linear search
217 float SmallestCost = Candidates[ CandidateHead ].Key;
218 int32 SmallestIndex = CandidateHead;
219 for( int32 i = CandidateHead + 1; i < Num; i++ )
220 {
221 float Cost = Candidates[i].Key;
222 if( Cost < SmallestCost )
223 {
224 SmallestCost = Cost;
225 SmallestIndex = i;
226 }
227 }
228
229 // Return smallest cost and NodeIndex
231 NodeIndex = Candidates[ SmallestIndex ].Value;
232
233 Candidates.RemoveAtSwap( SmallestIndex, EAllowShrinking::No);
234 }
235
236 return true;
237 }
238
239private:
240 TArray< FCandidate > Candidates;
241 int32 CandidateHead;
242
243 static constexpr uint32 MaxZeros = 32;
244 uint32 NumZeros = 0;
245 uint32 ZeroCostNodes[ MaxZeros ];
246};
247
248
249template<
251 typename FRootPolicy = FSingleRoot,
252 typename FDirtyPolicy = FIgnoreDirty,
254>
256{
257 using FRoot = typename FRootPolicy::FRoot;
258
259 FRootPolicy Roots;
260 FDirtyPolicy DirtyPolicy;
261 FCostMetric CostMetric;
262
263public:
264 FDynamicBVH();
265
266 int32 GetNumNodes() const { return Nodes.Num(); }
267 int32 GetNumLeaves() const { return Leaves.Num(); }
268 int32 GetNumDirty() const { return DirtyPolicy.Num(); }
269
270 template< typename T >
271 void Add( const TBounds<T>& Bounds, uint32 Index );
272 template< typename T >
273 void Update( const TBounds<T>& Bounds, uint32 Index );
274 void Remove( uint32 Index );
275
276 bool IsPresent( uint32 Index ) const { return Index < (uint32)Leaves.Num() && Leaves[ Index ] != ~0u; }
277 void AddDefaulted() { Leaves.Add( ~0u ); }
278 void SwapIndexes( uint32 Index0, uint32 Index1 );
279
280 void Build( const TArray< FBounds3f >& BoundsArray, uint32 FirstIndex );
281
282 template< typename T, typename FFuncType >
283 void ForAll( const TBounds<T>& Bounds, const FFuncType& Func ) const;
284 template< typename FPredicate, typename FFuncType >
285 void ForAll( const FPredicate& Predicate, const FFuncType& Func ) const;
286 template< typename FFuncType >
287 void ForAllDirty( const FFuncType& Func );
288
289 template< typename T, typename FFuncType >
291
292 // Not correct with FRootForest
294 {
295 check( Leaves[ Index ] != ~0u );
296 uint32 NodeIndex = Leaves[ Index ];
297 return GetNode( NodeIndex ).GetBounds( NodeIndex );
298 }
299
300 float GetTotalCost() const
301 {
302 float TotalCost = 0.0f;
303 for( auto& Node : Nodes )
304 {
305 for( uint32 i = 0; i < Node.NumChildren; i++ )
306 {
307 if( ( Node.ChildIndexes[i] & 1 ) == 0 )
308 TotalCost += CostMetric( Node.ChildBounds[i] );
309 }
310 }
311
312 return TotalCost;
313 }
314
315 bool Check() const
316 {
317 for( int32 i = 0; i < Nodes.Num(); i++ )
318 {
319 for( uint32 j = 0; j < Nodes[i].NumChildren; j++ )
320 {
321 CheckNode( (i << IndexShift) | j );
322 }
323 }
324
325 return true;
326 }
327
329
330protected:
331 static constexpr uint32 IndexShift = ConstLog2( MaxChildren );
332 static constexpr uint32 ChildMask = MaxChildren - 1;
333 static constexpr uint32 MaxChildren4 = (MaxChildren + 3) / 4;
334
335 struct FNode
336 {
337 // Index: low bits index child, high bits index FNode
339 uint32 NumChildren; // Lots of bits for this!
342
343 uint32 GetFirstChild( uint32 NodeIndex ) const { return ChildIndexes[ NodeIndex & ChildMask ]; }
344 const FBounds3f& GetBounds( uint32 NodeIndex ) const { return ChildBounds[ NodeIndex & ChildMask ]; }
345
346 bool IsRoot() const { return ParentIndex == ~0u; }
347 bool IsLeaf( uint32 NodeIndex ) const { return GetFirstChild( NodeIndex ) & 1; }
348 bool IsFull() const { return NumChildren == MaxChildren; }
349
351 {
352 FBounds3f Bounds;
353 for( uint32 i = 0; i < NumChildren; i++ )
354 {
355 Bounds += ChildBounds[i];
356 }
357 return Bounds;
358 }
359 };
360
364
366
367protected:
368 FNode& GetNode( uint32 NodeIndex ) { return Nodes[ NodeIndex >> IndexShift ]; }
369 const FNode& GetNode( uint32 NodeIndex ) const { return Nodes[ NodeIndex >> IndexShift ]; }
370
371 void MarkDirty( uint32 NodeIndex )
372 {
373 DirtyPolicy.Mark( NodeIndex >> IndexShift );
374 }
375
376 void Set( uint32 NodeIndex, const FBounds3f& Bounds, uint32 FirstChild )
377 {
378 GetNode( NodeIndex ).ChildBounds[ NodeIndex & ChildMask ] = Bounds;
379 SetFirstChild( NodeIndex, FirstChild );
380 }
381
382 void SetBounds( uint32 NodeIndex, const FBounds3f& Bounds )
383 {
384 GetNode( NodeIndex ).ChildBounds[ NodeIndex & ChildMask ] = Bounds;
385 MarkDirty( NodeIndex );
386 }
387
388 void SetFirstChild( uint32 NodeIndex, uint32 FirstChild )
389 {
390 GetNode( NodeIndex ).ChildIndexes[ NodeIndex & ChildMask ] = FirstChild;
391 MarkDirty( NodeIndex );
392
393 if( FirstChild & 1 )
394 {
395 Leaves[ FirstChild >> 1 ] = NodeIndex;
396 }
397 else
398 {
399 GetNode( FirstChild ).ParentIndex = NodeIndex;
400 MarkDirty( FirstChild );
401 }
402 }
403
405 uint32 FindBestInsertion_Greedy( uint32 NodeIndex, const FBounds3f& RESTRICT Bounds );
406
407 uint32 Insert( FRoot& RESTRICT Root, const FBounds3f& RESTRICT Bounds, uint32 NodeIndex );
408 void Extract( uint32 NodeIndex );
409 void RemoveAndSwap( uint32 NodeIndex );
410 bool RecursivePromoteChild( uint32 NodeIndex );
411 uint32 PromoteChild( uint32 NodeIndex );
412 void Rotate( uint32 NodeIndex );
413
415 void FreeNode( uint32 NodeIndex );
416
417 void CheckNode( uint32 NodeIndex ) const;
418};
419
420template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
422{
423 static_assert( MaxChildren > 1, "Must at least be binary tree." );
424 static_assert( ( MaxChildren & (MaxChildren - 1) ) == 0, "MaxChildren must be power of 2" );
425}
426
427template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
428template< typename T >
430{
431 if( Index >= (uint32)Leaves.Num() )
432 {
433 int32 Count = Index + 1 - Leaves.Num();
434 int32 First = Leaves.AddUninitialized( Count );
435 FMemory::Memset( &Leaves[ First ], 0xff, Count * sizeof( uint32 ) );
436 }
437
438 FRoot& Root = Roots.FindOrAdd( Bounds );
439
440 if( Root.FirstChild == ~0u )
441 {
442 Root.FirstChild = AllocNode();
443 GetNode( Root.FirstChild ).ParentIndex = ~0u;
444 GetNode( Root.FirstChild ).NumChildren = 0;
445 }
446
447 check( Leaves[ Index ] == ~0u );
448 Leaves[ Index ] = Insert( Root, Root.ToRelative( Bounds ), ( Index << 1 ) | 1 );
449
450 //CheckNode( Leaves[ Index ] );
451}
452
453template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
454template< typename T >
460
461template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
463{
464 check( Leaves[ Index ] != ~0u );
465 check( GetNode( Leaves[ Index ] ).GetFirstChild( Leaves[ Index ] ) == ( (Index << 1) | 1 ) );
466
467 Extract( Leaves[ Index ] );
468 Leaves[ Index ] = ~0u;
469}
470
471template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
473{
474 Swap( Leaves[ Index0 ], Leaves[ Index1 ] );
475
476 uint32 NodeIndex0 = Leaves[ Index0 ];
477 uint32 NodeIndex1 = Leaves[ Index1 ];
478
479 if( NodeIndex0 != ~0u )
480 {
481 GetNode( NodeIndex0 ).ChildIndexes[ NodeIndex0 & ChildMask ] = (Index0 << 1) | 1;
482 MarkDirty( NodeIndex0 );
483 }
484
485 if( NodeIndex1 != ~0u )
486 {
487 GetNode( NodeIndex1 ).ChildIndexes[ NodeIndex1 & ChildMask ] = (Index1 << 1) | 1;
488 MarkDirty( NodeIndex1 );
489 }
490}
491
492template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
494{
495 // Uses branch and bound search algorithm outlined in:
496 // [ Bittner et al. 2012, "Fast Insertion-Based Optimization of Bounding Volume Hierarchies" ]
497
498 // Binary tree nodes besides the root are always full meaning a new level will always be added.
499 float MinAddedCost = MaxChildren > 2 ? 0.0f : CostMetric( Bounds );
500
501 // Find best node to merge with.
502 float BestCost = MAX_flt;
503 uint32 BestIndex = 0;
504
505 Candidates.Reset();
506
507 float InducedCost = 0.0f;
508
509 while( true )
510 {
511 const FNode& RESTRICT Node = GetNode( NodeIndex );
512 NumTested++;
513
514 if( Node.IsFull() )
515 {
516 for( uint32 i = 0; i < Node.NumChildren; i += 4 )
517 {
518 FVector4f TotalCost;
520 constexpr uint32 Four = MaxChildren < 4 ? MaxChildren : 4;
521 for( uint32 j = 0; j < Four; j++ )
522 {
523 const FBounds3f& RESTRICT NodeBounds = Node.ChildBounds[ i + j ];
524
525 float DirectCost = CostMetric( Bounds + NodeBounds );
526 // Cost if we need to add a level
527 TotalCost[j] = InducedCost + DirectCost;
528 // Induced cost for children
529 ChildCost[j] = TotalCost[j] - CostMetric( NodeBounds );
530 }
531
532 for( uint32 j = 0; j < 4 && i + j < Node.NumChildren; j++ )
533 {
534 if( ChildCost[j] < BestCost )
535 {
536 if( TotalCost[j] < BestCost )
537 {
538 BestCost = TotalCost[j];
539 BestIndex = NodeIndex + i + j;
540 }
541
542 uint32 FirstChild = Node.ChildIndexes[ i + j ];
543 bool bIsLeaf = FirstChild & 1;
544 if( !bIsLeaf )
545 {
546 Candidates.Add( ChildCost[j], FirstChild );
547 }
548 }
549 }
550 }
551 }
552 else
553 {
554 // Don't need to add a level because we can add a child.
555 if( InducedCost < BestCost )
556 {
557 // Can't do better as this was already the smallest from the heap.
558 return Node.ParentIndex;
559 }
560 }
561
562 if( !Candidates.GetNext( BestCost, InducedCost, NodeIndex ) )
563 break;
564
566 {
567 // Not possible to reduce cost further.
568 break;
569 }
570 }
571
572 return BestIndex;
573}
574
575template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
577{
578 // Binary tree nodes besides the root are always full meaning a new level will always be added.
579 float MinAddedCost = MaxChildren > 2 ? 0.0f : CostMetric( Bounds );
580
581 // Find best node to merge with.
582 float BestCost = MAX_flt;
583 uint32 BestIndex = 0;
584
585 float InducedCost = 0.0f;
586
587 do
588 {
589 FNode& RESTRICT Node = GetNode( NodeIndex );
590 NumTested++;
591
592 if( Node.IsFull() )
593 {
594 float BestChildDist = MAX_flt;
596
597 for( uint32 i = 0; i < Node.NumChildren; i += 4 )
598 {
599 FVector4f Dist;
600 constexpr uint32 Four = MaxChildren < 4 ? MaxChildren : 4;
601 for( uint32 j = 0; j < Four; j++ )
602 {
603 const FBounds3f& RESTRICT NodeBounds = Node.ChildBounds[ i + j ];
604
605 FVector3f Delta = ( Bounds.Min - NodeBounds.Min ) + ( Bounds.Max - NodeBounds.Max );
606 Delta = Delta.GetAbs();
607 Dist[j] = Delta.X + Delta.Y + Delta.Z;
608 }
609
610 for( uint32 j = 0; j < 4 && i + j < Node.NumChildren; j++ )
611 {
612 if( Dist[j] < BestChildDist )
613 {
614 BestChildDist = Dist[j];
615 BestChildIndex = i + j;
616 }
617 }
618 }
619
620 const FBounds3f& RESTRICT ClosestBounds = Node.ChildBounds[ BestChildIndex ];
621
622 float DirectCost = CostMetric( Bounds + ClosestBounds );
623 // Cost if we need to add a level
624 float TotalCost = InducedCost + DirectCost;
625 // Induced cost for children
626 float ChildCost = TotalCost - CostMetric( ClosestBounds );
627
628 if( ChildCost >= BestCost )
629 break;
630
631 if( TotalCost < BestCost )
632 {
633 BestCost = TotalCost;
634 BestIndex = NodeIndex + BestChildIndex;
635 }
636
637 uint32 FirstChild = Node.ChildIndexes[ BestChildIndex ];
638 bool bIsLeaf = FirstChild & 1;
639 if( bIsLeaf )
640 break;
641
643 NodeIndex = FirstChild;
644 }
645 else
646 {
647 // Don't need to add a level because we can add a child.
648 // Can't do better. Cost is monotonic.
649 return Node.ParentIndex;
650 }
651
653 {
654 // Not possible to reduce cost further.
655 break;
656 }
657 }
658 while( NodeIndex != ~0u );
659
660 return BestIndex;
661}
662
663template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
665{
666 FNode& RootNode = GetNode( Root.FirstChild );
667 if( !RootNode.IsFull() )
668 {
669 uint32 NodeIndex = Root.FirstChild + RootNode.NumChildren++;
670 Set( NodeIndex, Bounds, Index );
671 Root.Bounds += Bounds;
672 return NodeIndex;
673 }
674
675 //uint32 BestIndex = FindBestInsertion_BranchAndBound( Root.FirstChild, Bounds );
676 uint32 BestIndex = FindBestInsertion_Greedy( Root.FirstChild, Bounds );
677
678 // Add to BestIndex's children
679 uint32 NodeIndex = GetNode( BestIndex ).GetFirstChild( BestIndex );
680 bool bIsLeaf = NodeIndex & 1;
681 bool bAddLevel = bIsLeaf || GetNode( NodeIndex ).IsFull();
682 if( bAddLevel )
683 {
684 // Create a new node and add NodeIndex as a child.
685 uint32 NewNodeIndex = AllocNode();
686 FNode& NewNode = GetNode( NewNodeIndex );
687
688 NewNode.NumChildren = 1;
690 GetNode( BestIndex ).GetBounds( BestIndex ),
691 GetNode( BestIndex ).GetFirstChild( BestIndex ) );
692
693 SetFirstChild( BestIndex, NewNodeIndex );
694
695 checkSlow( NewNode.ParentIndex == BestIndex );
696 checkSlow( NewNode.ChildIndexes[0] == NodeIndex );
697
698 NodeIndex = NewNodeIndex;
699 }
700
701 FNode& Children = GetNode( NodeIndex );
702
703 // Add child
704 NodeIndex |= Children.NumChildren++;
705 Set( NodeIndex, Bounds, Index );
706
707 // Propagate bounds up tree
708 FBounds3f PathBounds = Bounds;
710 while( PathIndex != ~0u )
711 {
712 FNode& PathNode = GetNode( PathIndex );
713 SetBounds( PathIndex, PathNode.GetBounds( PathIndex ) + PathBounds );
714
715 Rotate( PathIndex );
716
717 PathBounds = PathNode.GetBounds( PathIndex );
718 PathIndex = PathNode.ParentIndex;
719 }
720 Root.Bounds += PathBounds;
721
722 return NodeIndex;
723}
724
725template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
727{
728 FNode& Node = GetNode( NodeIndex );
729 check( Node.IsRoot() || Node.NumChildren > 1 );
730
731 RemoveAndSwap( NodeIndex );
732
733 // Propagate bounds up tree
736 uint32 RootIndex = NodeIndex;
737 while( PathIndex != ~0u )
738 {
739 RootIndex = PathIndex;
740
741 SetBounds( PathIndex, PathBounds );
742
743 FNode& PathNode = GetNode( PathIndex );
744 PathBounds = PathNode.UnionBounds();
745 PathIndex = PathNode.ParentIndex;
746 }
747 Roots.FindChecked( RootIndex & ~ChildMask ).Bounds = PathBounds;
748
749 if( !Node.IsRoot() && Node.NumChildren == 1 )
750 {
751 Set( Node.ParentIndex,
752 Node.ChildBounds[0],
753 Node.ChildIndexes[0] );
754
755 FreeNode( NodeIndex );
756 }
757 else if( Node.IsRoot() && Node.NumChildren == 0 )
758 {
759 Roots.Remove( NodeIndex & ~ChildMask );
760 FreeNode( NodeIndex );
761 }
762 else
763 {
764 RecursivePromoteChild( NodeIndex );
765 }
766}
767
768template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
770{
771 FNode& Node = GetNode( NodeIndex );
772
773 uint32 LastChild = --Node.NumChildren;
774 if( ( NodeIndex & ChildMask ) < LastChild )
775 {
776 // Fill with last
777 Set( NodeIndex,
778 Node.GetBounds( LastChild ),
779 Node.GetFirstChild( LastChild ) );
780 }
781}
782
783// Recursively promotes children to fill the hole until it reaches a leaf.
784// The result of doing this on every Extract is that all inner nodes are guarenteed to be full.
785template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
787{
788 bool bPromoted = false;
789
790 do
791 {
792 FNode& PathNode = GetNode( NodeIndex );
793
794 // Find best node to promote a child from.
795 float BestCost = 0.0f;
796 uint32 BestIndex = ~0u;
797 for( uint32 i = 0; i < PathNode.NumChildren; i++ )
798 {
799 if( !PathNode.IsLeaf(i) )
800 {
801 float Cost = CostMetric( PathNode.ChildBounds[i] );
802 if( Cost > BestCost )
803 {
804 BestCost = Cost;
805 BestIndex = ( NodeIndex & ~ChildMask ) | i;
806 }
807 }
808 }
809
810 if( BestIndex == ~0u )
811 break;
812
813 NodeIndex = PromoteChild( BestIndex );
814 bPromoted = true;
815 }
816 while( NodeIndex != ~0u );
817
818 return bPromoted;
819}
820
821template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
823{
824 FNode& Node = GetNode( NodeIndex );
825 check( !Node.IsLeaf( NodeIndex ) );
826 check( Node.NumChildren < MaxChildren );
827
828 uint32 FirstChild = Node.GetFirstChild( NodeIndex );
829 FNode& Children = GetNode( FirstChild );
830
831 FBounds3f Excluded[ MaxChildren ];
832
833 // Sweep forward and backward with prefix and postfix sums. Prefix + postfix sums == sum excluding this.
836 for( uint32 i = 0; i < Children.NumChildren; i++ )
837 {
838 uint32 j = Children.NumChildren - 1 - i;
839
840 Excluded[i] += Forward;
841 Excluded[j] += Back;
842
843 Forward += Children.ChildBounds[i];
844 Back += Children.ChildBounds[j];
845 }
846
847 float BestCost = MAX_flt;
848 uint32 BestIndex = ~0u;
849
850 for( uint32 i = 0; i < Children.NumChildren; i++ )
851 {
852 float Cost = CostMetric( Excluded[i] );
853 if( Cost < BestCost )
854 {
855 BestCost = Cost;
856 BestIndex = FirstChild | i;
857 }
858 }
859
860 // Promote from child to sibling
861
862 // Remove from bounds
863 CA_SUPPRESS(6385);
864 SetBounds( NodeIndex, Excluded[ BestIndex & ChildMask ] );
865
866 // Add as sibling
867 uint32 SiblingIndex = ( NodeIndex & ~ChildMask ) | Node.NumChildren;
869 Children.GetBounds( BestIndex ),
870 Children.GetFirstChild( BestIndex ) );
871 Node.NumChildren++;
872
873 // Remove from children
874 uint32 LastChild = --Children.NumChildren;
875 if( Children.NumChildren == 1 )
876 {
878
879 Set( NodeIndex,
880 Children.ChildBounds[ OtherChild ],
881 Children.ChildIndexes[ OtherChild ] );
882
883 // Delete Children
884 FreeNode( BestIndex );
885 BestIndex = ~0u;
886 }
887 else if( ( BestIndex & ChildMask ) != LastChild )
888 {
889 // Fill with last
890 Set( BestIndex,
891 Children.GetBounds( LastChild ),
892 Children.GetFirstChild( LastChild ) );
893 }
894
895 return BestIndex;
896}
897
898template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
900{
901 FNode& Node = GetNode( NodeIndex );
902
903 if( Node.IsRoot() )
904 return;
905
907 for( uint32 i = 0; i < Node.NumChildren; i++ )
908 {
909 if( i != (NodeIndex & ChildMask) )
910 ExcludedBounds += Node.ChildBounds[i];
911 }
912
913 FNode& ParentNode = GetNode( Node.ParentIndex );
914
915 float BestCost = CostMetric( ParentNode.GetBounds( Node.ParentIndex ) );
916 uint32 BestIndex = ~0u;
917 for( uint32 i = 0; i < ParentNode.NumChildren; i++ )
918 {
919 if( i != (Node.ParentIndex & ChildMask) )
920 {
921 // Parent's sibling
922 float Cost = CostMetric( ExcludedBounds + ParentNode.ChildBounds[i] );
923 if( Cost < BestCost )
924 {
925 BestCost = Cost;
926 BestIndex = ( Node.ParentIndex & ~ChildMask ) | i;
927 }
928 }
929 }
930
931 if( BestIndex != ~0u )
932 {
933 // Swap
934 FBounds3f Bounds = Node.GetBounds( NodeIndex );
935 uint32 FirstChild = Node.GetFirstChild( NodeIndex );
936
937 Set( NodeIndex, ParentNode.GetBounds( BestIndex ), ParentNode.GetFirstChild( BestIndex ) );
938 Set( BestIndex, Bounds, FirstChild );
939 }
940}
941
942template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
944{
945 if( FreeHead != ~0u )
946 {
947 uint32 NodeIndex = FreeHead;
948 uint32& NextIndex = GetNode( NodeIndex ).ParentIndex;
949 FreeHead = NextIndex;
950 NextIndex = ~0u;
951 return NodeIndex;
952 }
953 else
954 {
955 DirtyPolicy.Add( Nodes.Num() );
956 return Nodes.AddUninitialized() << IndexShift;
957 }
958}
959
960template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
962{
963 // Assumes nothing is still linking to it
964 GetNode( NodeIndex ).ParentIndex = FreeHead;
965 GetNode( NodeIndex ).NumChildren = 0;
966 FreeHead = NodeIndex & ~ChildMask;
967}
968
969template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
971{
972 const FNode& Node = GetNode( NodeIndex );
973
974 check( ( NodeIndex & ChildMask ) < Node.NumChildren );
975
976 if( !Node.IsRoot() )
977 {
978 check( Node.NumChildren > 1 );
979 check( GetNode( Node.ParentIndex ).GetFirstChild( Node.ParentIndex ) == ( NodeIndex & ~ChildMask ) );
980 }
981
982 uint32 FirstChild = Node.GetFirstChild( NodeIndex );
983 if( FirstChild & 1 )
984 {
985 check( Leaves[ FirstChild >> 1 ] == NodeIndex );
986 }
987 else
988 {
989 check( ( FirstChild & ChildMask ) == 0 );
990
991 const FNode& Children = GetNode( FirstChild );
992 for( uint32 i = 0; i < Children.NumChildren; i++ )
993 {
994 check( Children.ParentIndex == NodeIndex );
995 }
996 }
997}
998
999template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
1000template< typename T, typename FFuncType >
1002{
1004
1005 Roots.ForAll(
1006 [ this, &Stack, &Bounds, &Func ]( const FRoot& Root )
1007 {
1009
1010 if( !RelativeBounds.Intersect( Root.Bounds ) )
1011 return;
1012
1013 uint32 NodeIndex = Root.FirstChild;
1014
1015 while( true )
1016 {
1017 const FNode& RESTRICT Node = GetNode( NodeIndex );
1018
1019 for( uint32 i = 0; i < Node.NumChildren; i++ )
1020 {
1021 // TODO detect fully contained and stop intersection testing.
1022 if( RelativeBounds.Intersect( Node.ChildBounds[i] ) )
1023 {
1024 uint32 FirstChild = Node.ChildIndexes[i];
1025 if( FirstChild & 1 )
1026 {
1027 // Leaf
1028 Func( FirstChild >> 1 );
1029 }
1030 else
1031 {
1032 Stack.Push( FirstChild );
1033 }
1034 }
1035 }
1036
1037 if( Stack.Num() == 0 )
1038 break;
1039
1040 NodeIndex = Stack.Pop( EAllowShrinking::No );
1041 }
1042 } );
1043}
1044
1045template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
1046template< typename FPredicate, typename FFuncType >
1048{
1050
1051 Roots.ForAll(
1052 [ this, &Stack, &Predicate, &Func ]( const FRoot& Root )
1053 {
1054 if( !Predicate( Root.ToAbsolute( Root.Bounds ) ) )
1055 return;
1056
1057 uint32 NodeIndex = Root.FirstChild;
1058
1059 while( true )
1060 {
1061 const FNode& RESTRICT Node = GetNode( NodeIndex );
1062
1063 for( uint32 i = 0; i < Node.NumChildren; i++ )
1064 {
1065 if( Predicate( Root.ToAbsolute( Node.ChildBounds[i] ) ) )
1066 {
1067 uint32 FirstChild = Node.ChildIndexes[i];
1068 if( FirstChild & 1 )
1069 {
1070 // Leaf
1071 Func( FirstChild >> 1 );
1072 }
1073 else
1074 {
1075 Stack.Push( FirstChild );
1076 }
1077 }
1078 }
1079
1080 if( Stack.Num() == 0 )
1081 break;
1082
1083 NodeIndex = Stack.Pop( EAllowShrinking::No );
1084 }
1085 } );
1086}
1087
1088template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
1089template< typename FFuncType >
1091{
1092 DirtyPolicy.ForAll(
1093 [&]( uint32 Index )
1094 {
1095 Func( Index, GetNode( Index << IndexShift ) );
1096 }
1097 );
1098}
1099
1100template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
1101template< typename T, typename FFuncType >
1103{
1104 float ClosestDistSqr = MAX_flt;
1105 uint32 ClosestIndex = ~0u;
1106
1107 Candidates.Reset();
1108
1109 Roots.ForAll(
1110 [ this, &Position, &LeafDistSqr, &ClosestDistSqr, &ClosestIndex ]( const FRoot& Root )
1111 {
1112 FVector3f RelativePosition = Root.ToRelative( Position );
1113
1114 float NodeDistSqr = Root.Bounds.DistSqr( RelativePosition );
1115 uint32 NodeIndex = Root.FirstChild;
1116
1117 while( NodeDistSqr < ClosestDistSqr )
1118 {
1119 const FNode& RESTRICT Node = GetNode( NodeIndex );
1120
1121 for( uint32 i = 0; i < Node.NumChildren; i += 4 )
1122 {
1124 constexpr uint32 Four = MaxChildren < 4 ? MaxChildren : 4;
1125 for( uint32 j = 0; j < Four; j++ )
1126 {
1127 const FBounds3f& RESTRICT NodeBounds = Node.ChildBounds[ i + j ];
1128
1130 }
1131
1132 for( uint32 j = 0; j < 4 && i + j < Node.NumChildren; j++ )
1133 {
1134 if( ChildDistSqr[j] < ClosestDistSqr )
1135 {
1136 uint32 FirstChild = Node.ChildIndexes[ i + j ];
1137 if( FirstChild & 1 )
1138 {
1139 uint32 Index = FirstChild >> 1;
1140 float DistSqr = LeafDistSqr( Position, Index );
1141 if( DistSqr < ClosestDistSqr )
1142 {
1143 ClosestDistSqr = DistSqr;
1145 }
1146 }
1147 else
1148 {
1149 Candidates.Add( ChildDistSqr[j], FirstChild );
1150 }
1151 }
1152 }
1153 }
1154
1155 if( !Candidates.GetNext( ClosestDistSqr, NodeDistSqr, NodeIndex ) )
1156 break;
1157 }
1158 } );
1159
1160 return ClosestIndex;
1161}
1162
1164{
1165public:
1166 struct FRange
1167 {
1170
1171 int32 Num() const { return End - Begin; }
1172 };
1173
1174public:
1176
1177 uint32 GetIndex( int32 i ) const { return Sorted[i].Index; }
1178 uint32 Split( const FRange& Range );
1179
1180private:
1181 void RegenerateCodes( const FRange& Range );
1182
1183 struct FSortPair
1184 {
1185 uint32 Code;
1186 uint32 Index;
1187
1188 bool operator<( const FSortPair& Other ) const { return Code < Other.Code; }
1189 };
1190 TArray< FSortPair > Sorted;
1191
1192 const TArray< FBounds3f >& Bounds;
1193};
1194
1196{
1197 uint32 Code0 = Sorted[ Range.Begin ].Code;
1198 uint32 Code1 = Sorted[ Range.End - 1 ].Code;
1199 uint32 Diff = Code0 ^ Code1;
1200 if( Diff == 0 )
1201 {
1202 RegenerateCodes( Range );
1203
1204 Code0 = Sorted[ Range.Begin ].Code;
1205 Code1 = Sorted[ Range.End - 1 ].Code;
1206 Diff = Code0 ^ Code1;
1207
1208 if( Diff == 0 )
1209 return ( Range.Begin + Range.End ) >> 1;
1210 }
1211
1212 uint32 HighestBitDiff = FMath::FloorLog2( Diff );
1213 uint32 Mask = 1 << HighestBitDiff;
1214
1215 int32 Min = Range.Begin;
1216 int32 Max = Range.End;
1217 while( Min + 1 != Max )
1218 {
1219 int32 Mid = ( Min + Max ) >> 1;
1220 if( Sorted[ Mid ].Code & Mask )
1221 Max = Mid;
1222 else
1223 Min = Mid;
1224 }
1225
1226 return Max;
1227}
1228
1229template< uint32 MaxChildren, typename FRootPolicy, typename FDirtyPolicy, typename FCostMetric >
1231{
1232 if( FirstIndex + BoundsArray.Num() > (uint32)Leaves.Num() )
1233 {
1234 int32 Count = FirstIndex + BoundsArray.Num() - Leaves.Num();
1235 int32 First = Leaves.AddUninitialized( Count );
1236 FMemory::Memset( &Leaves[ First ], 0xff, Count * sizeof( uint32 ) );
1237 }
1238
1240
1241 using FRange = FMortonArray::FRange;
1242
1243 // TEMP Start empty
1244 FRoot& Root = Roots.FindOrAdd( FBounds3f( { FVector3f::ZeroVector, FVector3f::ZeroVector } ) );
1245 Root.FirstChild = 0;
1246
1247 struct FCreateNode
1248 {
1249 uint32 ParentIndex;
1250 FRange Range;
1251 };
1253
1254 uint32 ParentIndex = ~0u;
1255 FRange Range = { 0, BoundsArray.Num() };
1256
1257 while( true )
1258 {
1259 uint32 NodeIndex = AllocNode();
1260 FNode& Node = GetNode( NodeIndex );
1261
1262 Node.ParentIndex = ParentIndex;
1263 if( ParentIndex != ~0u )
1264 SetFirstChild( ParentIndex, NodeIndex );
1265
1266 check( Range.Begin < Range.End );
1267
1268 int32 NumLeaves = Range.Num();
1269 if( NumLeaves <= MaxChildren )
1270 {
1271 Node.NumChildren = NumLeaves;
1272 for( int32 i = 0; i < NumLeaves; i++ )
1273 {
1274 uint32 Index = MortonArray.GetIndex( Range.Begin + i );
1275 Set( NodeIndex + i, BoundsArray[ Index ], ( ( FirstIndex + Index ) << 1 ) | 1 );
1276 }
1277
1278 // Propagate bounds up tree
1281 while( PathIndex != ~0u )
1282 {
1283 SetBounds( PathIndex, PathBounds );
1284
1285 // Only continue if first child, which signifies the node is complete.
1286 if( PathIndex & ChildMask )
1287 break;
1288
1289 FNode& PathNode = GetNode( PathIndex );
1290 PathBounds = PathNode.UnionBounds();
1291 PathIndex = PathNode.ParentIndex;
1292 }
1293 // TODO: RootBounds
1294
1295 if( Stack.Num() == 0 )
1296 break;
1297
1298 ParentIndex = Stack.Last().ParentIndex;
1299 Range = Stack.Last().Range;
1300
1301 Stack.Pop( EAllowShrinking::No );
1302 }
1303 else
1304 {
1305 FRange Children[ MaxChildren ];
1306 Children[0] = Range;
1307
1308 int32 NumChildren = 1;
1309 int32 SplitIndex = 0;
1310 do
1311 {
1312 FRange Child = Children[ SplitIndex ];
1313
1314 uint32 Middle = MortonArray.Split( Child );
1315 check( Middle != Child.Begin );
1316 check( Middle != Child.End );
1317
1318 Children[ SplitIndex ].Begin = Child.Begin;
1319 Children[ SplitIndex ].End = Middle;
1320 Children[ NumChildren ].Begin = Middle;
1321 Children[ NumChildren ].End = Child.End;
1322 NumChildren++;
1323
1324 int32 LargestNum = 0;
1325 int32 LargestIndex = -1;
1326 for( int32 i = 0; i < NumChildren; i++ )
1327 {
1328 int32 Num = Children[i].Num();
1329 if( Num <= MaxChildren )
1330 continue;
1331
1332 if( Num > LargestNum )
1333 {
1334 LargestNum = Num;
1335 LargestIndex = i;
1336 }
1337 }
1338
1340 }
1342
1343 Node.NumChildren = NumChildren;
1344
1345 // Move leaves to the back
1346 for( int32 Front = 0, Back = NumChildren - 1; Front < Back; )
1347 {
1348 if( Children[ Front ].Num() == 1 )
1349 Swap( Children[ Front ], Children[ Back-- ] );
1350 else
1351 Front++;
1352 }
1353
1354 NumLeaves = 0;
1355 for( int32 i = NumChildren - 1; i >= 0; i-- )
1356 {
1357 bool bIsLeaf = Children[i].Num() == 1;
1358 if( !bIsLeaf )
1359 break;
1360 NumLeaves++;
1361
1362 uint32 Index = MortonArray.GetIndex( Children[i].Begin );
1363 Set( NodeIndex + i, BoundsArray[ Index ], ( ( FirstIndex + Index ) << 1 ) | 1 );
1364 }
1365 check( NumLeaves < NumChildren );
1366
1367 int32 Last = NumChildren - NumLeaves - 1;
1368 for( int32 i = 0; i < Last; i++ )
1369 {
1370 Stack.Push( { NodeIndex + i, Children[i] } );
1371 }
1372
1373 ParentIndex = NodeIndex + Last;
1374 Range = Children[ Last ];
1375 }
1376 }
1377}
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
TBounds< float > FBounds3f
Definition Bounds.h:154
#define CA_SUPPRESS(WarningNumber)
Definition CoreMiscDefines.h:125
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define RESTRICT
Definition Platform.h:706
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
constexpr uint32 ConstLog2(uint32 x)
Definition DynamicBVH.h:172
bool operator<(const FTextFormatString &LHS, const FTextFormatString &RHS)
Definition ITextFormatArgumentModifier.h:147
UE::Math::TVector< float > FVector3f
Definition MathFwd.h:73
@ Num
Definition MetalRHIPrivate.h:234
#define MAX_flt
Definition NumericLimits.h:29
#define Split(a, ahi, alo)
Definition Predicates.inl:204
@ Four
Definition PropertyPathHelpersTest.h:19
#define UE_KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:131
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition DynamicBVH.h:256
uint32 FindBestInsertion_BranchAndBound(uint32 NodeIndex, const FBounds3f &RESTRICT Bounds)
Definition DynamicBVH.h:493
float GetTotalCost() const
Definition DynamicBVH.h:300
TArray< uint32 > Leaves
Definition DynamicBVH.h:362
void RemoveAndSwap(uint32 NodeIndex)
Definition DynamicBVH.h:769
const FNode & GetNode(uint32 NodeIndex) const
Definition DynamicBVH.h:369
uint32 Insert(FRoot &RESTRICT Root, const FBounds3f &RESTRICT Bounds, uint32 NodeIndex)
Definition DynamicBVH.h:664
void Add(const TBounds< T > &Bounds, uint32 Index)
void SetBounds(uint32 NodeIndex, const FBounds3f &Bounds)
Definition DynamicBVH.h:382
int32 GetNumLeaves() const
Definition DynamicBVH.h:267
FNode & GetNode(uint32 NodeIndex)
Definition DynamicBVH.h:368
bool Check() const
Definition DynamicBVH.h:315
void Update(const TBounds< T > &Bounds, uint32 Index)
int32 GetNumDirty() const
Definition DynamicBVH.h:268
void MarkDirty(uint32 NodeIndex)
Definition DynamicBVH.h:371
static constexpr uint32 ChildMask
Definition DynamicBVH.h:332
uint32 AllocNode()
Definition DynamicBVH.h:943
uint32 FindBestInsertion_Greedy(uint32 NodeIndex, const FBounds3f &RESTRICT Bounds)
Definition DynamicBVH.h:576
FDynamicBVH()
Definition DynamicBVH.h:421
void FreeNode(uint32 NodeIndex)
Definition DynamicBVH.h:961
FLowestCostList Candidates
Definition DynamicBVH.h:365
void Rotate(uint32 NodeIndex)
Definition DynamicBVH.h:899
void ForAll(const TBounds< T > &Bounds, const FFuncType &Func) const
Definition DynamicBVH.h:1001
const FBounds3f & GetBounds(uint32 Index) const
Definition DynamicBVH.h:293
void SetFirstChild(uint32 NodeIndex, uint32 FirstChild)
Definition DynamicBVH.h:388
uint32 FreeHead
Definition DynamicBVH.h:363
void Build(const TArray< FBounds3f > &BoundsArray, uint32 FirstIndex)
Definition DynamicBVH.h:1230
void AddDefaulted()
Definition DynamicBVH.h:277
void Set(uint32 NodeIndex, const FBounds3f &Bounds, uint32 FirstChild)
Definition DynamicBVH.h:376
static constexpr uint32 IndexShift
Definition DynamicBVH.h:331
void CheckNode(uint32 NodeIndex) const
Definition DynamicBVH.h:970
void ForAllDirty(const FFuncType &Func)
Definition DynamicBVH.h:1090
void SwapIndexes(uint32 Index0, uint32 Index1)
Definition DynamicBVH.h:472
uint32 NumTested
Definition DynamicBVH.h:328
bool IsPresent(uint32 Index) const
Definition DynamicBVH.h:276
uint32 PromoteChild(uint32 NodeIndex)
Definition DynamicBVH.h:822
bool RecursivePromoteChild(uint32 NodeIndex)
Definition DynamicBVH.h:786
TArray< FNode > Nodes
Definition DynamicBVH.h:361
int32 GetNumNodes() const
Definition DynamicBVH.h:266
void Extract(uint32 NodeIndex)
Definition DynamicBVH.h:726
void Remove(uint32 Index)
Definition DynamicBVH.h:462
static constexpr uint32 MaxChildren4
Definition DynamicBVH.h:333
uint32 FindClosest(const UE::Math::TVector< T > &Position, const FFuncType &LeafDistSqr)
Definition DynamicBVH.h:1102
Definition DynamicBVH.h:178
void Reset()
Definition DynamicBVH.h:182
bool GetNext(float BestCost, float &NodeCost, uint32 &NodeIndex)
Definition DynamicBVH.h:201
void Add(float NodeCost, uint32 NodeIndex)
Definition DynamicBVH.h:189
Definition DynamicBVH.h:1164
uint32 Split(const FRange &Range)
Definition DynamicBVH.h:1195
uint32 GetIndex(int32 i) const
Definition DynamicBVH.h:1177
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Last(SizeType IndexFromTheEnd=0) UE_LIFETIMEBOUND
Definition Array.h:1263
UE_NODEBUG UE_FORCEINLINE_HINT void Push(ElementType &&Item)
Definition Array.h:1224
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
ElementType Pop(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:1196
int32 Add(const bool Value)
Definition BitArray.h:615
U16 Index
Definition radfft.cpp:71
Definition DynamicBVH.h:336
bool IsLeaf(uint32 NodeIndex) const
Definition DynamicBVH.h:347
bool IsRoot() const
Definition DynamicBVH.h:346
uint32 GetFirstChild(uint32 NodeIndex) const
Definition DynamicBVH.h:343
uint32 ChildIndexes[MaxChildren]
Definition DynamicBVH.h:340
FBounds3f UnionBounds() const
Definition DynamicBVH.h:350
const FBounds3f & GetBounds(uint32 NodeIndex) const
Definition DynamicBVH.h:344
uint32 ParentIndex
Definition DynamicBVH.h:338
uint32 NumChildren
Definition DynamicBVH.h:339
FBounds3f ChildBounds[MaxChildren]
Definition DynamicBVH.h:341
bool IsFull() const
Definition DynamicBVH.h:348
Definition DynamicBVH.h:19
void Mark(uint32 Index)
Definition DynamicBVH.h:22
int32 Num() const
Definition DynamicBVH.h:20
void Add(uint32 Index)
Definition DynamicBVH.h:21
void ForAll(const FFuncType &Func)
Definition DynamicBVH.h:25
static UE_FORCEINLINE_HINT float RoundToZero(float F)
Definition UnrealMathUtility.h:2209
static UE_FORCEINLINE_HINT void * Memset(void *Dest, uint8 Char, SIZE_T Count)
Definition UnrealMemory.h:119
Definition DynamicBVH.h:1167
int32 Num() const
Definition DynamicBVH.h:1171
int32 Begin
Definition DynamicBVH.h:1168
int32 End
Definition DynamicBVH.h:1169
Definition DynamicBVH.h:90
uint32 FirstChild
Definition DynamicBVH.h:93
FBounds3d ToAbsolute(const FBounds3f &Other) const
Definition DynamicBVH.h:107
FVector3d Offset
Definition DynamicBVH.h:91
FBounds3f ToRelative(const TBounds< T > &Other) const
Definition DynamicBVH.h:102
FVector3f ToRelative(const UE::Math::TVector< T > &Position) const
Definition DynamicBVH.h:96
FBounds3f Bounds
Definition DynamicBVH.h:92
Definition DynamicBVH.h:88
FRoot & FindChecked(uint32 RootFirstChild)
Definition DynamicBVH.h:141
FRoot & FindOrAdd(const TBounds< T > &Bounds)
Definition DynamicBVH.h:115
TArray< FRoot > Roots
Definition DynamicBVH.h:112
void Remove(uint32 RootFirstChild)
Definition DynamicBVH.h:152
void ForAll(const FFuncType &Func) const
Definition DynamicBVH.h:163
Definition DynamicBVH.h:65
const FBounds3f & ToRelative(const FBounds3f &Other) const
Definition DynamicBVH.h:70
const FVector3f & ToRelative(const FVector3f &Position) const
Definition DynamicBVH.h:69
uint32 FirstChild
Definition DynamicBVH.h:67
FBounds3f Bounds
Definition DynamicBVH.h:66
const FBounds3f & ToAbsolute(const FBounds3f &Other) const
Definition DynamicBVH.h:71
Definition DynamicBVH.h:63
FRoot Root
Definition DynamicBVH.h:73
FRoot & FindOrAdd(const FBounds3f &Bounds)
Definition DynamicBVH.h:75
FRoot & FindChecked(uint32 RootFirstChild)
Definition DynamicBVH.h:76
void ForAll(const FFuncType &Func) const
Definition DynamicBVH.h:80
void Remove(uint32 RootFirstChild)
Definition DynamicBVH.h:77
Definition DynamicBVH.h:10
float operator()(const FBounds3f &Bounds) const
Definition DynamicBVH.h:11
Definition DynamicBVH.h:29
TBitArray NodeIsDirty
Definition DynamicBVH.h:30
void Mark(uint32 Index)
Definition DynamicBVH.h:41
int32 Num() const
Definition DynamicBVH.h:33
TArray< uint32 > DirtyNodes
Definition DynamicBVH.h:31
void ForAll(const FFuncType &Func)
Definition DynamicBVH.h:51
void Add(uint32 Index)
Definition DynamicBVH.h:35
TVector4< T > Max
Definition Bounds.h:19
TBounds< float > ToRelative(const TVector< U > &Offset) const
Definition Bounds.h:105
T DistSqr(const TVector< T > &Point) const
Definition Bounds.h:63
TVector4< T > Min
Definition Bounds.h:18
UE_FORCEINLINE_HINT TVector< T > GetCenter() const
Definition Bounds.h:72
auto ToAbsolute(const TVector< U > &Offset) const
Definition Bounds.h:94
Definition Tuple.h:652
T X
Definition Vector4.h:43
T Z
Definition Vector.h:68
T Y
Definition Vector.h:65
static CORE_API const TVector< float > ZeroVector
Definition Vector.h:79
T X
Definition Vector.h:62
TVector< T > GetAbs() const
Definition Vector.h:1710