UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
kDOP.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"
8#include <limits>
9
10// Indicates how many "k / 2" there are in the k-DOP. 3 == AABB == 6 DOP. The code relies on this being 3.
11#define NUM_PLANES 3
12
13template <typename COLL_DATA_PROVIDER, typename KDOP_IDX_TYPE> struct TkDOPLineCollisionCheck;
14
15struct FkHitResult
16{
20 float Time;
22 int32 Item;
23
25 : Normal (0,0,0,0)
26 , Time (1.0f)
28 {
29 }
30};
31
35struct FVector3SOA
36{
43};
44
48struct FVector4SOA
49{
58};
59
63struct FTriangleSOA
64{
70 uint32 Payload[4];
71};
72
74template<typename KDOP_IDX_TYPE>
76{
81 enum { NodeHistoryLength = 1 };
83
85 {
86 for (int32 NodeIndex = 0; NodeIndex < NodeHistoryLength; NodeIndex++)
87 {
88 // Initialize the history to invalid index
89 Nodes[NodeIndex] = 0xFFFFFFFF;
90 }
91 }
92
94 {
95 TTraversalHistory NewHistory;
96 // Move all the indices toward the end of the array one element
97 CopyAssignItems(NewHistory.Nodes + 1, Nodes, NodeHistoryLength - 1);
98 // Insert the new node at the beginning of the array
99 NewHistory.Nodes[0] = NewNodeIndex;
100 return NewHistory;
101 }
102
104 {
105 // Accesses the oldest node that this traversal history is tracking
106 return Nodes[NodeHistoryLength - 1];
107 }
108};
109
123FORCEINLINE bool appLineCheckTriangle(const FVector4& Start, const FVector4& End, const FVector4& Dir, const FVector4& V0, const FVector4& V1, const FVector4& V2, const FVector4& Normal, float& IntersectionTime)
124{
127
128 // Check if the line is completely on one side of the triangle, or if it's co-planar.
129#if 1
130 if ((StartDist == EndDist) || (StartDist < -0.001f && EndDist < -0.001f) || (StartDist > 0.001f && EndDist > 0.001f))
131#else
132 if ( (StartDist * EndDist) > -0.0001f )
133#endif
134 {
135 return false;
136 }
137
138 // Figure out when it will hit the triangle
139 float Time = float(-StartDist / (EndDist - StartDist)); // LWC_TODO: Precision loss
140
141 // If this triangle is not closer than the previous hit, reject it
143 {
144 return false;
145 }
146
147 // Calculate the line's point of intersection with the node's plane
148 const FVector4& Intersection = Start + Dir * Time;
149 const FVector4* Verts[3] =
150 {
151 &V0, &V1, &V2
152 };
153
154 // Check if the point of intersection is inside the triangle's edges.
155 for( int32 SideIndex = 0; SideIndex < 3; SideIndex++ )
156 {
157 const FVector4& SideDirection = Normal ^ (*Verts[(SideIndex + 1) % 3] - *Verts[SideIndex]);
158 const FVector4::FReal SideW = Dot3(SideDirection, *Verts[SideIndex]);
159 const FVector4::FReal DotW = Dot3(SideDirection, Intersection);
160 if ((DotW - SideW) >= 0.001f)
161 {
162 return false;
163 }
164 }
166 return true;
167}
168
170static const VectorRegister GSmallNegativeNumber = DECLARE_VECTOR_REGISTER(-0.0001f, -0.0001f, -0.0001f, -0.0001f);
171//extern const VectorRegister GSmallNegativeNumber;
172
174static const VectorRegister GSmallNumber = DECLARE_VECTOR_REGISTER(0.0001f, 0.0001f, 0.0001f, 0.0001f);
175//extern const VectorRegister GSmallNumber;
176
177static const VectorRegister GZeroVectorRegister = DECLARE_VECTOR_REGISTER(0.0f, 0.0f, 0.0f, 0.0f);
178
179static const VectorRegister VectorNegativeOne = MakeVectorRegister( -1.0f, -1.0f, -1.0f, -1.0f );
180
191static int32 appLineCheckTriangleSOA(const FVector3SOA& Start, const FVector3SOA& End, const FVector3SOA& Dir, const FTriangleSOA& Triangle4, float& InOutIntersectionTime)
192{
194
196 StartDist = VectorMultiplyAdd( Triangle4.Normals.X, Start.X, Triangle4.Normals.W );
199
201 EndDist = VectorMultiplyAdd( Triangle4.Normals.X, End.X, Triangle4.Normals.W );
202 EndDist = VectorMultiplyAdd( Triangle4.Normals.Y, End.Y, EndDist );
203 EndDist = VectorMultiplyAdd( Triangle4.Normals.Z, End.Z, EndDist );
204
205 // Are both end-points of the line on the same side of the triangle (or parallel to the triangle plane)?
207 if ( VectorMaskBits(TriangleMask) == 0 )
208 {
209 return -1;
210 }
211
212 // Figure out when it will hit the triangle
214
215 // If this triangle is not closer than the previous hit, reject it
219 if ( VectorMaskBits(TriangleMask) == 0 )
220 {
221 return -1;
222 }
223
224 // Calculate the line's point of intersection with the node's plane
228
229 // Check if the point of intersection is inside the triangle's edges.
230 for( int32 SideIndex = 0; SideIndex < 3; SideIndex++ )
231 {
232 const VectorRegister EdgeX = VectorSubtract( Triangle4.Positions[(SideIndex + 1) % 3].X, Triangle4.Positions[SideIndex].X );
233 const VectorRegister EdgeY = VectorSubtract( Triangle4.Positions[(SideIndex + 1) % 3].Y, Triangle4.Positions[SideIndex].Y );
234 const VectorRegister EdgeZ = VectorSubtract( Triangle4.Positions[(SideIndex + 1) % 3].Z, Triangle4.Positions[SideIndex].Z );
247 if ( VectorMaskBits(TriangleMask) == 0 )
248 {
249 return -1;
250 }
251 }
252
253 // Set all non-hitting times to 1.0
255
256 // Get the best intersection time out of the 4 possibilities.
260
261 // Get the triangle index that corresponds to the best time.
262 // NOTE: This will pick the first triangle, in case there are multiple hits at the same spot.
265
266 // Return results.
268 return SubIndex;
269}
270
271// This structure is used during the build process. It contains the triangle's
272// centroid for calculating which plane it should be split or not with
273template<typename KDOP_IDX_TYPE>
275{
279 FVector4 V0;
283 FVector4 V1;
287 FVector4 V2;
288
291
292 inline FVector4 GetCentroid() const
293 {
294 return (V0 + V1 + V2) / 3.f;
295 }
297 {
298 FVector4 LocalNormal = ((V1 - V2) ^ (V0 - V2)).GetSafeNormal();
300 return LocalNormal;
301 }
302
314};
315
316// Forward declarations
317template <typename COLL_DATA_PROVIDER,typename KDOP_IDX_TYPE> struct TkDOPNode;
318template <typename COLL_DATA_PROVIDER,typename KDOP_IDX_TYPE> struct TkDOPTree;
319template <typename COLL_DATA_PROVIDER,typename KDOP_IDX_TYPE> struct TkDOPLineCollisionCheck;
320
324struct FFourBox
325{
330
334 FVector4 Max[3];
335
343 {
344 using FVec4Real = decltype(FVector4::X);
346 Min[1].Component(BoundingVolumeIndex) = (FVec4Real)Box.Min.Y;
347 Min[2].Component(BoundingVolumeIndex) = (FVec4Real)Box.Min.Z;
351 }
352
367};
368
369#if PLATFORM_64BITS
370 #define kDOPArray TArray
371#else
372 #define kDOPArray TChunkedArray
373#endif
374
379template <typename COLL_DATA_PROVIDER, typename KDOP_IDX_TYPE>
381{
384
387
390
391 // Note this isn't smaller since 4 byte alignment will take over anyway
392 bool bIsLeaf;
394
395 // Union of either child kDOP nodes or a list of enclosed triangles
396 union
397 {
398 // This structure contains the left and right child kDOP indices
399 // These index values correspond to the array in the FkDOPTree
400 struct
401 {
404 } n;
405 // This structure contains the list of enclosed triangles
406 // These index values correspond to the triangle information in the
407 // FkDOPTree using the start and count as the means of delineating
408 // which triangles are involved
409 struct
410 {
413 } t;
414 };
415
420 {
421 n.LeftNode = ((KDOP_IDX_TYPE) -1);
422 n.RightNode = ((KDOP_IDX_TYPE) -1);
423 }
424
438 kDOPArray<FTriangleSOA>& SOATriangles,
439 kDOPArray<NodeType>& Nodes)
440 {
441 // Figure out if we are a leaf node or not
442 if (NumTris > 4)
443 {
444 // Still too many triangles, so continue subdividing the triangle list
445 bIsLeaf = 0;
446 Occupancy = 0;
447 int32 BestPlane = -1;
448 double BestMean = 0.f;
449 double BestVariance = 0.f;
450
451 // Determine how to split using the splatter algorithm
452 {
453 double Mean[NUM_PLANES] = { 0 };
454 double Variance[NUM_PLANES] = { 0 };
455
456 // Compute the mean for the triangle list
457 for (int32 nTriangle = Start; nTriangle < Start + NumTris; nTriangle++)
458 {
459 // Project the centroid of the triangle against the plane
460 // normals and accumulate to find the total projected
461 // weighting
462 FVector4 Centroid = BuildTriangles[nTriangle].GetCentroid();
463
464 for (int32 nPlane = 0; nPlane < NUM_PLANES; nPlane++)
465 {
466 Mean[nPlane] += Centroid[nPlane];
467 }
468 }
469
470 // Divide by the number of triangles to get the average
471 for (int32 nPlane = 0; nPlane < NUM_PLANES; nPlane++)
472 {
473 Mean[nPlane] /= NumTris;
474 }
475
476 // Compute variance of the triangle list
477 for (int32 nTriangle = Start; nTriangle < Start + NumTris; nTriangle++)
478 {
479 // Project the centroid again
480 FVector4 Centroid = BuildTriangles[nTriangle].GetCentroid();
481
482 // Now calculate the variance and accumulate it
483 for (int32 nPlane = 0; nPlane < NUM_PLANES; nPlane++)
484 {
485 Variance[nPlane] += (Centroid[nPlane] - Mean[nPlane]) * (Centroid[nPlane] - Mean[nPlane]);
486 }
487 }
488
489 // Determine which plane is the best to split on
490 for (int32 nPlane = 0; nPlane < NUM_PLANES; nPlane++)
491 {
492 // Get the average variance
495 {
498 BestMean = Mean[nPlane];
499 }
500 }
501 }
502
503 // Now that we have the plane to split on, work through the triangle
504 // list placing them on the left or right of the splitting plane
505 int32 Left = Start - 1;
506 int32 Right = Start + NumTris;
507 // Keep working through until the left index passes the right; we test that condition after each interior loop
508 for (;;)
509 {
510 // Loop invariants: (1) Left < Right,
511 // (2) All triangles <= Left belong on the left, all triangles >= Right belong on the right
512 // (3) Left+1 is an untested triangle, Right-1 is an untested triangle
514 // Increment Left until it points to triangle that belongs on the right, or Right==Left
515 for (++Left; Left < Right; ++Left)
516 {
517 Dot = BuildTriangles[Left].GetCentroid()[BestPlane];
518 if (Dot < BestMean)
519 {
520 break;
521 }
522 }
523 if (Left == Right)
524 {
525 break;
526 }
527 // Decrement Right until it points to triangle that belongs on the left, or Right==Left
528 for (--Right; Left < Right; --Right)
529 {
530 Dot = BuildTriangles[Right].GetCentroid()[BestPlane];
531 if (Dot >= BestMean)
532 {
533 break;
534 }
535 }
536 if (Left == Right)
537 {
538 break;
539 }
540 // Left points to a triangle that belongs on the Right; Right points to a triangle that belongs on the Left. Swap them.
542 }
543 // After loop array is partitioned and Left is the first index that belongs on the right side of the plane.
544 // Check for wacky degenerate case where more than GKDOPMaxTrisPerLeaf
545 // fall all in the same kDOP
546 if (Left == Start + NumTris || Right == Start)
547 {
548 Left = Start + (NumTris / 2);
549 }
550 // Add the two child nodes
551 n.LeftNode = Nodes.AddZeroed(2);
552 n.RightNode = n.LeftNode + 1;
553 // Have the left node recursively subdivide it's list and set bounding volume.
554 FBox LeftBoundingVolume = Nodes[n.LeftNode].SplitTriangleList(Start,Left - Start,BuildTriangles,SOATriangles,Nodes);
556 // Set unused index 2,3 to child nodes of left node.
557 BoundingVolumes.SetBox(2,Nodes[n.LeftNode].BoundingVolumes.GetBox(0));
558 BoundingVolumes.SetBox(3,Nodes[n.LeftNode].BoundingVolumes.GetBox(1));
559
560 // And now have the right node recursively subdivide it's list and set bounding volume.
561 FBox RightBoundingVolume = Nodes[n.RightNode].SplitTriangleList(Left,Start + NumTris - Left,BuildTriangles,SOATriangles,Nodes);
563
564 // Non-leaf node bounds are the "sum" of the left and right nodes' volumes.
566 }
567 else
568 {
569 // Build SOA triangles
570
571 // "NULL triangle", used when a leaf can't fill all 4 triangles in a FTriangleSOA.
572 // No line should ever hit these triangles, set the values so that it can never happen.
574
575 t.StartIndex = SOATriangles.Num();
576 t.NumTriangles = Align<int32>(NumTris, 4) / 4;
577 SOATriangles.AddZeroed( t.NumTriangles );
578
579 int32 BuildTriIndex = Start;
580 for ( uint32 SOAIndex=0; SOAIndex < t.NumTriangles; ++SOAIndex )
581 {
583 FTriangleSOA& SOA = SOATriangles[t.StartIndex + SOAIndex];
584 int32 SubIndex = 0;
585 for ( ; SubIndex < 4 && BuildTriIndex < (Start+NumTris); ++SubIndex, ++BuildTriIndex )
586 {
588 SOA.Payload[SubIndex] = Tris[SubIndex]->MaterialIndex;
589 }
590 for ( ; SubIndex < 4; ++SubIndex )
591 {
592 SOA.Payload[SubIndex] = 0xffffffff;
593 }
594
595 SOA.Positions[0].X = VectorSet( Tris[0]->V0.X, Tris[1]->V0.X, Tris[2]->V0.X, Tris[3]->V0.X );
596 SOA.Positions[0].Y = VectorSet( Tris[0]->V0.Y, Tris[1]->V0.Y, Tris[2]->V0.Y, Tris[3]->V0.Y );
597 SOA.Positions[0].Z = VectorSet( Tris[0]->V0.Z, Tris[1]->V0.Z, Tris[2]->V0.Z, Tris[3]->V0.Z );
598 SOA.Positions[1].X = VectorSet( Tris[0]->V1.X, Tris[1]->V1.X, Tris[2]->V1.X, Tris[3]->V1.X );
599 SOA.Positions[1].Y = VectorSet( Tris[0]->V1.Y, Tris[1]->V1.Y, Tris[2]->V1.Y, Tris[3]->V1.Y );
600 SOA.Positions[1].Z = VectorSet( Tris[0]->V1.Z, Tris[1]->V1.Z, Tris[2]->V1.Z, Tris[3]->V1.Z );
601 SOA.Positions[2].X = VectorSet( Tris[0]->V2.X, Tris[1]->V2.X, Tris[2]->V2.X, Tris[3]->V2.X );
602 SOA.Positions[2].Y = VectorSet( Tris[0]->V2.Y, Tris[1]->V2.Y, Tris[2]->V2.Y, Tris[3]->V2.Y );
603 SOA.Positions[2].Z = VectorSet( Tris[0]->V2.Z, Tris[1]->V2.Z, Tris[2]->V2.Z, Tris[3]->V2.Z );
604
605 const FVector4& Tris0LocalNormal = Tris[0]->GetLocalNormal();
606 const FVector4& Tris1LocalNormal = Tris[1]->GetLocalNormal();
607 const FVector4& Tris2LocalNormal = Tris[2]->GetLocalNormal();
608 const FVector4& Tris3LocalNormal = Tris[3]->GetLocalNormal();
609
614 }
615
616 // No need to subdivide further so make this a leaf node
617 bIsLeaf = 1;
618
619 check(NumTris <= std::numeric_limits<uint8>::max());
620 Occupancy = static_cast<uint8>(NumTris);
621
622 // Generate bounding volume for leaf which is passed up the call chain.
624 for (int32 TriangleIndex=Start; TriangleIndex<Start + NumTris; TriangleIndex++)
625 {
626 BoundingVolume += FVector(BuildTriangles[TriangleIndex].V0);
627 BoundingVolume += FVector(BuildTriangles[TriangleIndex].V1);
628 BoundingVolume += FVector(BuildTriangles[TriangleIndex].V2);
629 }
634
635 return BoundingVolume;
636 }
637 }
638
660 {
661#define PLAIN_C 0
662#if PLAIN_C
663 for( int32 BoxIndex=0; BoxIndex<4; BoxIndex++ )
664 {
665 // 0: Create constants
668
669 // 1: Calculate slabs.
670 FVector4 Slab1 = (BoxMin - Check.LocalStart) * Check.LocalOneOverDir;
671 FVector4 Slab2 = (BoxMax - Check.LocalStart) * Check.LocalOneOverDir;
672
673 // 2: Figure out per component min/ max
674 FVector4 SlabMin = FVector4( FMath::Min(Slab1.X, Slab2.X), FMath::Min(Slab1.Y, Slab2.Y), FMath::Min(Slab1.Z, Slab2.Z), FMath::Min(Slab1.W, Slab2.W) );
675 FVector4 SlabMax = FVector4( FMath::Max(Slab1.X, Slab2.X), FMath::Max(Slab1.Y, Slab2.Y), FMath::Max(Slab1.Z, Slab2.Z), FMath::Max(Slab1.W, Slab2.W) );
676
677 // 3: Figure out global min/ max
678 float MinTime = Max3( SlabMin.X, SlabMin.Y, SlabMin.Z );
679 float MaxTime = Min3( SlabMax.X, SlabMax.Y, SlabMax.Z );
680
681 // 4: Calculate hit time and determine whether there was a hit.
682 HitTime[BoxIndex] = MinTime;
683 NodeHit[BoxIndex] = (MaxTime >= 0 && MaxTime >= MinTime && MinTime < Check.Result->Time) ? 0xFFFFFFFF : 0;
684 }
685#else
686 // 0: load everything into registers
687 const VectorRegister OriginX = VectorSetFloat1( Check.LocalStart.X );
688 const VectorRegister OriginY = VectorSetFloat1( Check.LocalStart.Y );
689 const VectorRegister OriginZ = VectorSetFloat1( Check.LocalStart.Z );
690 const VectorRegister InvDirX = VectorSetFloat1( Check.LocalOneOverDir.X );
691 const VectorRegister InvDirY = VectorSetFloat1( Check.LocalOneOverDir.Y );
692 const VectorRegister InvDirZ = VectorSetFloat1( Check.LocalOneOverDir.Z );
693 const VectorRegister CurrentHitTime = VectorSetFloat1( Check.Result->Time );
694 // Boxes are FVector2D so we need to unshuffle the data.
701
702 // 1: Calculate slabs.
709
710 // 2: Figure out per component min/ max
717
718 // 3: Figure out global min/ max
720 const VectorRegister MinTime = VectorMax( SlabMinXY, SlabMinZ );
722 const VectorRegister MaxTime = VectorMin( SlabMaxXY, SlabMaxZ );
723
724 // 4: Calculate hit time and determine whether there was a hit.
725 VectorStoreAligned( MinTime, &HitTime );
726 const VectorRegister OutNodeHit = VectorBitwiseAnd( VectorCompareGE( MaxTime, VectorZero() ), VectorCompareGE( MaxTime, MinTime ) );
729#endif
730 }
731
740 {
741 bool bHit = 0;
742 // If this is a node, check the two child nodes and pick the closest one
743 // to recursively check against and only check the second one if there is
744 // not a hit or the hit returned is further out than the second node
745 if (bIsLeaf == 0)
746 {
747 // Check both left and right node at the same time.
749 MS_ALIGN(16) int32 NodeHit[4] GCC_ALIGN(16);
751
752 // Left node was hit.
753 if( NodeHit[0] )
754 {
755 // Left and Right node are hit.
756 if( NodeHit[1] )
757 {
758 // Left node is closer than right node.
759 if( NodeHitTime.X < NodeHitTime.Y )
760 {
761 bHit = Check.Nodes[n.LeftNode].LineCheckPreCalculated(Check,NodeHitTime,History.AddNode(n.LeftNode),NodeHit);
762 // Only check right node if it could possibly be a closer hit
763 if( NodeHitTime.Y < Check.Result->Time
764 // No need to check if we have a hit and don't care about closest
765 && (!bHit || Check.bFindClosestIntersection))
766 {
767 bHit |= Check.Nodes[n.RightNode].LineCheck(Check,History.AddNode(n.RightNode));
768 }
769 }
770 // Right node is closer than left node.
771 else
772 {
773 bHit = Check.Nodes[n.RightNode].LineCheck(Check,History.AddNode(n.RightNode));
774 // Only check left node if it could possibly be a closer hit
775 if( NodeHitTime.X < Check.Result->Time
776 // No need to check if we have a hit and don't care about closest
777 && (!bHit || Check.bFindClosestIntersection))
778 {
779 bHit |= Check.Nodes[n.LeftNode].LineCheckPreCalculated(Check,NodeHitTime,History.AddNode(n.LeftNode),NodeHit);
780 }
781 }
782 }
783 // Only left node was hit.
784 else
785 {
786 bHit = Check.Nodes[n.LeftNode].LineCheckPreCalculated(Check,NodeHitTime,History.AddNode(n.LeftNode),NodeHit);
787 }
788 }
789 // Left node was not hit.
790 else
791 {
792 // Only right node was hit.
793 if( NodeHit[1] )
794 {
795 bHit = Check.Nodes[n.RightNode].LineCheck(Check,History.AddNode(n.RightNode));
796 }
797 // No node was hit.
798 else
799 {
800 return false;
801 }
802 }
803 }
804 else
805 {
806 // This is a leaf, check the triangles for a hit
807 bHit = LineCheckTriangles(Check,History);
808 }
809 return bHit;
810 }
811
820 {
821 bool bHit = 0;
822 // If this is a node, check the two child nodes and pick the closest one
823 // to recursively check against and only check the second one if there is
824 // not a hit or the hit returned is further out than the second node
825 if (bIsLeaf == 0)
826 {
827 // Left node was hit.
828 if( NodeHit[2] )
829 {
830 // Left and Right node are hit.
831 if( NodeHit[3] )
832 {
833 // Left node is closer than right node.
834 if( NodeHitTime.Z < NodeHitTime.W )
835 {
836 bHit = Check.Nodes[n.LeftNode].LineCheck(Check,History.AddNode(n.LeftNode));
837 // Only check right node if it could possibly be a closer hit
838 if( NodeHitTime.W < Check.Result->Time
839 // No need to check if we have a hit and don't care about closest
840 && (!bHit || Check.bFindClosestIntersection))
841 {
842 bHit |= Check.Nodes[n.RightNode].LineCheck(Check,History.AddNode(n.RightNode));
843 }
844 }
845 // Right node is closer than left node.
846 else
847 {
848 bHit = Check.Nodes[n.RightNode].LineCheck(Check,History.AddNode(n.RightNode));
849 // Only check left node if it could possibly be a closer hit
850 if( NodeHitTime.Z < Check.Result->Time
851 // No need to check if we have a hit and don't care about closest
852 && (!bHit || Check.bFindClosestIntersection))
853 {
854 bHit |= Check.Nodes[n.LeftNode].LineCheck(Check,History.AddNode(n.LeftNode));
855 }
856 }
857 }
858 // Only left node was hit.
859 else
860 {
861 bHit = Check.Nodes[n.LeftNode].LineCheck(Check,History.AddNode(n.LeftNode));
862 }
863 }
864 // Left node was not hit.
865 else
866 {
867 // Only right node was hit.
868 if( NodeHit[3] )
869 {
870 bHit = Check.Nodes[n.RightNode].LineCheck(Check,History.AddNode(n.RightNode));
871 }
872 // No node was hit.
873 else
874 {
875 return false;
876 }
877 }
878 }
879 else
880 {
881 // This is a leaf, check the triangles for a hit
882 bHit = LineCheckTriangles(Check,History);
883 }
884 return bHit;
885 }
886
894 {
895 // Assume a miss
896 bool bHit = false;
897 for ( KDOP_IDX_TYPE SOAIndex = t.StartIndex; SOAIndex < (t.StartIndex + t.NumTriangles); SOAIndex++ )
898 {
899 const FTriangleSOA& TriangleSOA = Check.SOATriangles[SOAIndex];
900 int32 SubIndex = appLineCheckTriangleSOA( Check.StartSOA, Check.EndSOA, Check.DirSOA, TriangleSOA, Check.Result->Time );
901 if ( SubIndex >= 0 )
902 {
903 bHit = true;
904 Check.LocalHitNormal.X = (decltype(FVector4::X))VectorGetComponentDynamic(TriangleSOA.Normals.X, SubIndex);
905 Check.LocalHitNormal.Y = (decltype(FVector4::Y))VectorGetComponentDynamic(TriangleSOA.Normals.Y, SubIndex);
906 Check.LocalHitNormal.Z = (decltype(FVector4::X))VectorGetComponentDynamic(TriangleSOA.Normals.Z, SubIndex);
907 Check.Result->Item = TriangleSOA.Payload[SubIndex];
908 Check.HitNodeIndex = History.GetOldestNode();
909
910 // Early out if we don't care about the closest intersection.
911 if( !Check.bFindClosestIntersection )
912 {
913 break;
914 }
915 }
916 }
917 return bHit;
918 }
919};
920
925template<typename COLL_DATA_PROVIDER, typename KDOP_IDX_TYPE>
927{
930
933
936
939
947 {
948 float kDOPBuildTime = 0;
949 {
950 // Empty the current set of nodes and preallocate the memory so it doesn't
951 // reallocate memory while we are recursively walking the tree
952 // With near-perfect packing, we could easily size these to be
953 // Nodes = (n / 2) + 1 and SOATriangles = (n / 4) + 1
954 Nodes.Empty(BuildTriangles.Num());
955 SOATriangles.Empty(BuildTriangles.Num());
956
957 // Add the root node
958 Nodes.AddZeroed();
959
960 // Now tell that node to recursively subdivide the entire set of triangles
961 Nodes[0].SplitTriangleList(0,BuildTriangles.Num(),BuildTriangles,SOATriangles,Nodes);
962
963 // Don't waste memory.
964 Nodes.Shrink();
965 SOATriangles.Shrink();
966 }
967 }
968
976 {
977 // Recursively check for a hit
979 bool bHit = Nodes[0].LineCheck(Check, History.AddNode(0));
980 return bHit;
981 }
982};
983
989template <typename COLL_DATA_PROVIDER, typename KDOP_IDX_TYPE> struct TkDOPCollisionCheck
990{
993
996
999
1007 const TreeType& kDOPTree;
1016
1027};
1028
1034template <typename COLL_DATA_PROVIDER, typename KDOP_IDX_TYPE> struct TkDOPLineCollisionCheck :
1035 public TkDOPCollisionCheck<COLL_DATA_PROVIDER,KDOP_IDX_TYPE>
1036{
1041 // Constant input vars
1042 const FVector4& Start;
1043 const FVector4& End;
1044
1048 const bool bFindClosestIntersection;
1049 // Locally calculated vectors
1054 // Normal in local space which gets transformed to world at the very end
1056
1059
1066
1083 :
1085 Result(InResult),
1086 Start(InStart),
1087 End(InEnd),
1089 HitNodeIndex(0xFFFFFFFF)
1090 {
1092 // Move start and end to local space
1093 LocalStart = WorldToLocal.TransformPosition(Start);
1094 LocalEnd = WorldToLocal.TransformPosition(End);
1095 // Calculate the vector's direction in local space
1097 // Build the one over dir
1101
1102 // Construct the SOA data
1112 }
1113
1119 {
1120 // Transform the hit back into world space using the transpose adjoint
1121 FVector4 Normal = TkDOPCollisionCheck<COLL_DATA_PROVIDER,KDOP_IDX_TYPE>::CollDataProvider.GetLocalToWorldTransposeAdjoint().TransformVector(LocalHitNormal).GetSafeNormal();
1122 // Flip the normal if the triangle is inverted
1124 {
1125 Normal = -Normal;
1126 }
1127 return Normal;
1128 }
1129};
@ Normal
Definition AndroidInputInterface.h:116
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define GCC_ALIGN(n)
Definition AndroidPlatform.h:163
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
@ ForceInit
Definition CoreMiscDefines.h:155
#define MS_ALIGN(n)
Definition Platform.h:916
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FORCEINLINE void CopyAssignItems(ElementType *Dest, const ElementType *Source, SizeType Count)
Definition MemoryOps.h:137
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define NUM_PLANES
Definition kDOP.h:11
FORCEINLINE bool appLineCheckTriangle(const FVector4 &Start, const FVector4 &End, const FVector4 &Dir, const FVector4 &V0, const FVector4 &V1, const FVector4 &V2, const FVector4 &Normal, float &IntersectionTime)
Definition kDOP.h:123
#define FVector
Definition IOSSystemIncludes.h:8
UE::Math::TVector4< double > FVector4
Definition MathFwd.h:49
UE::Math::TPlane< double > FPlane
Definition MathFwd.h:52
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
FORCEINLINE VectorRegister4Float VectorSubtract(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:731
FORCEINLINE VectorRegister4Float VectorMin(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1686
FORCEINLINE VectorRegister4Float MakeVectorRegister(uint32 X, uint32 Y, uint32 Z, uint32 W)
Definition UnrealMathFPU.h:195
FORCEINLINE VectorRegister4Float VectorSetFloat1(float F)
Definition UnrealMathFPU.h:518
FORCEINLINE VectorRegister4Float VectorDivide(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:834
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 VectorRegister4Float VectorBitwiseAnd(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1165
FORCEINLINE VectorRegister4Float VectorLoadFloat1(const float *Ptr)
Definition UnrealMathFPU.h:468
VectorRegister4Float VectorLoadAligned(const float *Ptr)
Definition UnrealMathFPU.h:451
FORCEINLINE VectorRegister4Float VectorMultiplyAdd(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2, const VectorRegister4Float &Vec3)
Definition UnrealMathFPU.h:786
FORCEINLINE VectorRegister4Float VectorSelect(const VectorRegister4Float &Mask, const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1105
FORCEINLINE VectorRegister4Float VectorCompareGT(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:974
FORCEINLINE VectorRegister4Float VectorCompareGE(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1000
FORCEINLINE VectorRegister4Float VectorCompareLT(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1025
FORCEINLINE float VectorGetComponentDynamic(const VectorRegister4Float &Vec, uint32 ComponentIndex)
Definition UnrealMathFPU.h:369
FORCEINLINE int32 VectorMaskBits(const VectorRegister4Float &Vec1)
Definition UnrealMathFPU.h:1075
FORCEINLINE VectorRegister4Float VectorNegateMultiplyAdd(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2, const VectorRegister4Float &Vec3)
Definition UnrealMathFPU.h:815
void VectorStoreAligned(const VectorRegister4Float &Vec, float *Ptr)
Definition UnrealMathFPU.h:534
#define VectorSwizzle(Vec, X, Y, Z, W)
Definition UnrealMathFPU.h:639
#define DECLARE_VECTOR_REGISTER(X, Y, Z, W)
Definition UnrealMathFPU.h:155
FORCEINLINE VectorRegister4Float VectorCompareLE(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1050
FORCEINLINE VectorRegister4Float VectorCompareEQ(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:923
FORCEINLINE void VectorStoreFloat1(const VectorRegister4Float &Vec, float *Dst)
Definition UnrealMathFPU.h:610
#define VectorReplicate(Vec, ElementIndex)
Definition UnrealMathFPU.h:627
#define MAX_FLT
Definition UnrealMathUtility.h:78
FORCEINLINE VectorRegister4Float VectorZero(void)
Definition UnrealMathVectorCommon.h.inl:16
FORCEINLINE VectorRegister4Float VectorSet(float X, float Y, float Z, float W)
Definition UnrealMathVectorCommon.h.inl:867
FORCEINLINE VectorRegister4Float VectorOne(void)
Definition UnrealMathVectorCommon.h.inl:21
FORCEINLINE uint32 appCountTrailingZeros(uint32 Value)
Definition UnrealMathVectorCommon.h.inl:932
UE_FORCEINLINE_HINT T Dot3(const UE::Math::TVector4< T > &V1, const UE::Math::TVector4< T > &V2)
Definition Vector4.h:1018
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Array.h:670
@ Start
Definition GeoEnum.h:100
Definition kDOP.h:324
FBox GetBox(int32 BoundingVolumeIndex)
Definition kDOP.h:360
MS_ALIGN(16) FVector4 Min[3] GCC_ALIGN(16)
FVector4 Max[3]
Definition kDOP.h:333
void SetBox(int32 BoundingVolumeIndex, const FBox &Box)
Definition kDOP.h:341
Definition kDOP.h:63
FVector3SOA Positions[3]
Definition kDOP.h:65
uint32 Payload[4]
Definition kDOP.h:69
FVector4SOA Normals
Definition kDOP.h:67
Definition kDOP.h:35
VectorRegister Z
Definition kDOP.h:41
VectorRegister Y
Definition kDOP.h:39
VectorRegister X
Definition kDOP.h:37
Definition kDOP.h:48
VectorRegister W
Definition kDOP.h:56
VectorRegister Y
Definition kDOP.h:52
VectorRegister X
Definition kDOP.h:50
VectorRegister Z
Definition kDOP.h:54
Definition kDOP.h:274
FVector4 GetCentroid() const
Definition kDOP.h:292
FkDOPBuildCollisionTriangle(KDOP_IDX_TYPE InMaterialIndex, const FVector4 &vert0, const FVector4 &vert1, const FVector4 &vert2)
Definition kDOP.h:307
FVector4 GetLocalNormal() const
Definition kDOP.h:296
KDOP_IDX_TYPE MaterialIndex
Definition kDOP.h:289
FVector4 V2
Definition kDOP.h:286
FVector4 V1
Definition kDOP.h:282
FVector4 V0
Definition kDOP.h:278
Definition kDOP.h:15
FkHitResult()
Definition kDOP.h:24
int32 Item
Definition kDOP.h:21
float Time
Definition kDOP.h:19
FVector4 Normal
Definition kDOP.h:17
Definition kDOP.h:75
KDOP_IDX_TYPE Nodes[NodeHistoryLength]
Definition kDOP.h:81
KDOP_IDX_TYPE GetOldestNode() const
Definition kDOP.h:103
@ NodeHistoryLength
Definition kDOP.h:80
TTraversalHistory()
Definition kDOP.h:84
TTraversalHistory AddNode(KDOP_IDX_TYPE NewNodeIndex) const
Definition kDOP.h:93
Definition kDOP.h:986
const kDOPArray< FTriangleSOA > & SOATriangles
Definition kDOP.h:1011
const DataProviderType & CollDataProvider
Definition kDOP.h:999
TkDOPCollisionCheck(const DataProviderType &InCollDataProvider)
Definition kDOP.h:1020
TkDOPTree< DataProviderType, KDOP_IDX_TYPE > TreeType
Definition kDOP.h:998
TkDOPNode< DataProviderType, KDOP_IDX_TYPE > NodeType
Definition kDOP.h:995
const kDOPArray< NodeType > & Nodes
Definition kDOP.h:1007
const TreeType & kDOPTree
Definition kDOP.h:1003
COLL_DATA_PROVIDER DataProviderType
Definition kDOP.h:992
Definition kDOP.h:1036
FVector4 LocalStart
Definition kDOP.h:1046
KDOP_IDX_TYPE HitNodeIndex
Definition kDOP.h:1054
FkHitResult * Result
Definition kDOP.h:1036
FVector4 LocalHitNormal
Definition kDOP.h:1051
FVector4 LocalDir
Definition kDOP.h:1048
const FVector4 & Start
Definition kDOP.h:1038
const FVector4 & End
Definition kDOP.h:1039
FVector3SOA StartSOA
Definition kDOP.h:1057
TkDOPLineCollisionCheck(const FVector4 &InStart, const FVector4 &InEnd, bool bInbFindClosestIntersection, const COLL_DATA_PROVIDER &InCollDataProvider, FkHitResult *InResult)
Definition kDOP.h:1079
FVector3SOA EndSOA
Definition kDOP.h:1059
FVector3SOA DirSOA
Definition kDOP.h:1061
FVector4 LocalOneOverDir
Definition kDOP.h:1049
FVector4 LocalEnd
Definition kDOP.h:1047
FORCEINLINE FVector4 GetHitNormal(void)
Definition kDOP.h:1118
const bool bFindClosestIntersection
Definition kDOP.h:1044
Definition kDOP.h:381
FFourBox BoundingVolumes
Definition kDOP.h:387
bool LineCheck(TkDOPLineCollisionCheck< COLL_DATA_PROVIDER, KDOP_IDX_TYPE > &Check, TTraversalHistory< KDOP_IDX_TYPE > History) const
Definition kDOP.h:739
uint8 Occupancy
Definition kDOP.h:391
void LineCheckBounds(TkDOPLineCollisionCheck< COLL_DATA_PROVIDER, KDOP_IDX_TYPE > &Check, FVector4 &HitTime, int32 NodeHit[4]) const
Definition kDOP.h:655
FBox SplitTriangleList(int32 Start, int32 NumTris, TArray< FkDOPBuildCollisionTriangle< KDOP_IDX_TYPE > > &BuildTriangles, kDOPArray< FTriangleSOA > &SOATriangles, kDOPArray< NodeType > &Nodes)
Definition kDOP.h:436
FORCEINLINE TkDOPNode()
Definition kDOP.h:419
COLL_DATA_PROVIDER DataProviderType
Definition kDOP.h:383
bool LineCheckPreCalculated(TkDOPLineCollisionCheck< COLL_DATA_PROVIDER, KDOP_IDX_TYPE > &Check, const FVector4 &NodeHitTime, TTraversalHistory< KDOP_IDX_TYPE > History, int32 *NodeHit) const
Definition kDOP.h:819
bool LineCheckTriangles(TkDOPLineCollisionCheck< COLL_DATA_PROVIDER, KDOP_IDX_TYPE > &Check, const TTraversalHistory< KDOP_IDX_TYPE > &History) const
Definition kDOP.h:889
KDOP_IDX_TYPE StartIndex
Definition kDOP.h:410
KDOP_IDX_TYPE NumTriangles
Definition kDOP.h:409
KDOP_IDX_TYPE RightNode
Definition kDOP.h:401
bool bIsLeaf
Definition kDOP.h:390
TkDOPNode< DataProviderType, KDOP_IDX_TYPE > NodeType
Definition kDOP.h:386
FORCEINLINE void LineCheckBounds(TkDOPLineCollisionCheck< COLL_DATA_PROVIDER, KDOP_IDX_TYPE > &Check, FVector4 &HitTime, int32 NodeHit[4]) const
Definition kDOP.h:659
struct TkDOPNode::@1148::@1152 t
struct TkDOPNode::@1148::@1151 n
KDOP_IDX_TYPE LeftNode
Definition kDOP.h:400
Definition kDOP.h:927
kDOPArray< NodeType > Nodes
Definition kDOP.h:931
TkDOPNode< DataProviderType, KDOP_IDX_TYPE > NodeType
Definition kDOP.h:932
bool LineCheck(TkDOPLineCollisionCheck< COLL_DATA_PROVIDER, KDOP_IDX_TYPE > &Check) const
Definition kDOP.h:975
COLL_DATA_PROVIDER DataProviderType
Definition kDOP.h:929
void Build(TArray< FkDOPBuildCollisionTriangle< KDOP_IDX_TYPE > > &BuildTriangles)
Definition kDOP.h:946
kDOPArray< FTriangleSOA > SOATriangles
Definition kDOP.h:934
TVector< T > Min
Definition Box.h:39
TVector4< T > TransformPosition(const TVector< T > &V) const
Definition Matrix.inl:184
double FReal
Definition Plane.h:37
UE_FORCEINLINE_HINT T PlaneDot(const TVector< T > &P) const
Definition Plane.h:474
double Y
Definition Vector4.h:46
T & Component(int32 Index)
Definition Vector4.h:782
T Z
Definition Vector4.h:49
double X
Definition Vector4.h:43
double FReal
Definition Vector4.h:36
Definition UnrealMathFPU.h:42