UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ExactIntrTriangle3Triangle3.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3// Interface for exact predicates w/ Unreal Engine vector types
4
5#pragma once
6
7#include "VectorTypes.h"
8#include "TriangleTypes.h"
10
11namespace UE::Geometry {
12
13// An exact-math version of TIntrTriangle3Triangle3, with less persistent state -- results are returned per-function rather than kept on the struct.
14template <typename Real>
16{
17public:
18 // Inputs
20
21 // TODO: Implement the option to support coplanar intersection
22 // bool bIgnoreCoplanar = true;
23
27
32
37
43
44
45private:
46 // Note: Currently also does not handle degenerate (collinear or collapsed-to-point) inputs, and will report such as coplanar
47 template<bool bFindSegments>
48 static bool FindOrTestWithoutCoplanar(const TTriangle3<Real>& Triangle0, const TTriangle3<Real>& Triangle1, TVector<Real>& OutSegA, TVector<Real>& OutSegB, bool& bWasCoplanar)
49 {
50 bWasCoplanar = false; // default to false; will be set to true if coplanar case detected
51
52 // Currently implements the non-coplanar part of "Faster Triangle - Triangle Intersection Tests"
53 // by Olivier Devillers, Philippe Guigue (2006)
54 // Using exact predicate tests to detect intersection, and (inexact) plane intersection to find the OutSeg points
55
56 // Compute stats about the signs of the signed distance of each triangle vertices relative to the other triangle's plane,
57 // and return false in no-intersect or coplanar cases.
59 // For each triangle, count how many of its vertices had negative, zero, or positive signed distance (vs the other triangle's plane)
60 int32 SignCounts[2][3]{ {0,0,0},{0,0,0} };
61 // For each triangle, the index of a vertex in that triangle w/ negative, zero or positive signed distance, respectively. -1 indicates no vertex had that sign.
62 int32 SignSubIdx[2][3]{ {-1,-1,-1},{-1,-1,-1} };
63 for (int32 TriIdx = 0; TriIdx < 2; ++TriIdx)
64 {
65 const TTriangle3<Real>& CurTri = *Tris[TriIdx];
66 const TTriangle3<Real>& OtherTri = *Tris[1 - TriIdx];
67
68 for (int32 SubIdx = 0; SubIdx < 3; ++SubIdx)
69 {
70 Real VertSide = ExactPredicates::Orient3<Real>(OtherTri.V[0], OtherTri.V[1], OtherTri.V[2], CurTri.V[SubIdx]);
72 SignCounts[TriIdx][Sign + 1]++;
74 }
75 if (SignCounts[TriIdx][0] == 3 || SignCounts[TriIdx][2] == 3)
76 {
77 return false;
78 }
79 if (SignCounts[TriIdx][1] == 3)
80 {
81 bWasCoplanar = true;
82 return false;
83 }
84 }
85
86 // Figure out a canonical ordering for the vertices, so the first vertex is always the one that is alone on a side of the other triangle (or if there is no such case, then is on the triangle)
87 // and the other two vertices are on a relatively smaller-sign side (negative or zero)
88 int32 IdxMap[2][3];
89 int32 TrySignIdx[3]{ 2,0,1 }; // Look for the vertex that is alone on one side, testing the sides in order: Positive, Negative, Zero
90 bool OtherTriNeedsOrientationFlip[2]{ false,false };
91 for (int32 TriIdx = 0; TriIdx < 2; ++TriIdx)
92 {
93 for (int32 Idx = 0; Idx < 3; ++Idx)
94 {
96 if (SignCounts[TriIdx][SignIdx] == 1)
97 {
100 IdxMap[TriIdx][1] = (OffsideIdx + 1) % 3;
101 IdxMap[TriIdx][2] = (OffsideIdx + 2) % 3;
102 // If the isolated vertex is on the negative side, or if it's zero and the other two are positive,
103 // then we'll need to flip the other tri's orientation to ensure the isolated vertex is on the (more-)positive side instead
105 break;
106 }
107 }
108 }
109 for (int32 TriIdx = 0; TriIdx < 2; ++TriIdx)
110 {
112 {
113 Swap(IdxMap[1 - TriIdx][1], IdxMap[1 - TriIdx][2]);
114 }
115 }
116
117 // Friendly names for the remapped triangle vertices, matching the Devillers & Guigue paper Fig. 2 (reference above)
118 const TVector<Real>& P1 = Tris[0]->V[IdxMap[0][0]];
119 const TVector<Real>& Q1 = Tris[0]->V[IdxMap[0][1]];
120 const TVector<Real>& R1 = Tris[0]->V[IdxMap[0][2]];
121
122 const TVector<Real>& P2 = Tris[1]->V[IdxMap[1][0]];
123 const TVector<Real>& Q2 = Tris[1]->V[IdxMap[1][1]];
124 const TVector<Real>& R2 = Tris[1]->V[IdxMap[1][2]];
125
126 auto GetEdgePlaneCrossing = [](const TVector<Real>& A, const TVector<Real>& B, const TVector<Real>& N, const TVector<Real>& O)
127 {
128 Real AToPlane = N.Dot(O - A);
129 Real ABLenInPlaneDir = N.Dot(B - A);
130 // Note: ABLenInPlaneDir should be non-zero because we call this only in non-coplanar cases
131 // However, it could still be zero due to floating point error if the vectors involved are very small ...
132 // in that case for now, we fall back to the edge midpoint
133 if (ABLenInPlaneDir == 0)
134 {
135 return (A + B) * .5;
136 }
137 // Find the edge crossing, with a clamp to ensure it remains at least on the edge in numerically bad (near-coplanar) cases
138 Real FracMoveAlongAB = FMath::Clamp(AToPlane / ABLenInPlaneDir, (Real)0, (Real)1);
139 return A * (1 - FracMoveAlongAB) + B * FracMoveAlongAB;
140 };
141
142 if constexpr (!bFindSegments)
143 {
144 bool bIntersects =
145 ExactPredicates::Orient3<Real>(P1, Q1, P2, Q2) <= 0 &&
146 ExactPredicates::Orient3<Real>(P1, R1, R2, P2) <= 0;
147 return bIntersects;
148 }
149 else
150 {
151 // Decision tree from Fig. 5 of Devillers & Guigue paper (see reference above)
152 if (ExactPredicates::Orient3<Real>(P1, Q1, R2, P2) <= 0)
153 {
154 if (ExactPredicates::Orient3<Real>(P1, Q1, Q2, P2) >= 0)
155 {
156 if (ExactPredicates::Orient3<Real>(P1, R1, Q2, P2) < 0)
157 {
158 // Intersection is k,j segment -- crossings of p2,q2 to p1,q1
159 TVector<Real> N1 = VectorUtil::NormalDirection(P1, Q1, R1);
160 TVector<Real> N2 = VectorUtil::NormalDirection(P2, Q2, R2);
161 OutSegA = GetEdgePlaneCrossing(P2, Q2, N1, P1);
162 OutSegB = GetEdgePlaneCrossing(P1, Q1, N2, P2);
163 }
164 else
165 {
166 // Intersection is i,j segment -- crossings of p1,r1 to p1,q1
167 TVector<Real> N2 = VectorUtil::NormalDirection(P2, Q2, R2);
168 OutSegA = GetEdgePlaneCrossing(P1, R1, N2, P2);
169 OutSegB = GetEdgePlaneCrossing(P1, Q1, N2, P2);
170 }
171 }
172 else
173 {
174 return false;
175 }
176 }
177 else
178 {
179 if (ExactPredicates::Orient3<Real>(P1, R1, R2, P2) <= 0)
180 {
181 if (ExactPredicates::Orient3<Real>(P1, R1, Q2, P2) <= 0)
182 {
183 // Intersection is k,l segment -- crossings p2,q2 to p2, r2
184 TVector<Real> N1 = VectorUtil::NormalDirection(P1, Q1, R1);
185 OutSegA = GetEdgePlaneCrossing(P2, Q2, N1, P1);
186 OutSegB = GetEdgePlaneCrossing(P2, R2, N1, P1);
187 }
188 else
189 {
190 // Intersection is i,l segment -- crossings of p1,r1 to p2,r2
191 TVector<Real> N1 = VectorUtil::NormalDirection(P1, Q1, R1);
192 TVector<Real> N2 = VectorUtil::NormalDirection(P2, Q2, R2);
193 OutSegA = GetEdgePlaneCrossing(P1, R1, N2, P2);
194 OutSegB = GetEdgePlaneCrossing(P2, R2, N1, P1);
195 }
196 }
197 else
198 {
199 return false;
200 }
201 }
202
203 return true;
204 }
205 }
206
207};
208
209
212
213
214}// namespace UE::Geometry
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
static int32 SignAsInt(const RealType Value)
Definition MathUtil.h:228
Definition ExactIntrTriangle3Triangle3.h:16
TTriangle3< Real > Triangle0
Definition ExactIntrTriangle3Triangle3.h:19
static bool FindWithoutCoplanar(const TTriangle3< Real > &Triangle0, const TTriangle3< Real > &Triangle1, TVector< Real > &OutSegA, TVector< Real > &OutSegB, bool &bWasCoplanar)
Definition ExactIntrTriangle3Triangle3.h:33
bool Test(bool &bWasCoplanar)
Definition ExactIntrTriangle3Triangle3.h:28
static bool TestWithoutCoplanar(const TTriangle3< Real > &Triangle0, const TTriangle3< Real > &Triangle1, bool &bWasCoplanar)
Definition ExactIntrTriangle3Triangle3.h:38
TExactIntrTriangle3Triangle3(TTriangle3< Real > Triangle0, TTriangle3< Real > Triangle1)
Definition ExactIntrTriangle3Triangle3.h:25
TTriangle3< Real > Triangle1
Definition ExactIntrTriangle3Triangle3.h:19
TVector< RealType > NormalDirection(const TVector< RealType > &V0, const TVector< RealType > &V1, const TVector< RealType > &V2)
Definition VectorUtil.h:83
Definition ParametricSurfaceData.h:18
TExactIntrTriangle3Triangle3< float > FExactIntrTriangle3Triangle3f
Definition ExactIntrTriangle3Triangle3.h:210
TExactIntrTriangle3Triangle3< double > FExactIntrTriangle3Triangle3d
Definition ExactIntrTriangle3Triangle3.h:211
static constexpr UE_FORCEINLINE_HINT T Clamp(const T X, const T MinValue, const T MaxValue)
Definition UnrealMathUtility.h:592
Definition TriangleTypes.h:263
Definition Vector.h:51