UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ConvexContactPointUtilities.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "Chaos/Core.h"
5#include "Chaos/Capsule.h"
9#include "Chaos/Triangle.h"
10
11namespace Chaos::Private
12{
13 // Project a convex onto an axis and return the projected range as well as the vertex indices that bound the range
14 template <typename ConvexType>
15 inline void ProjectOntoAxis(const ConvexType& Convex, const FVec3& AxisN, const FVec3& AxisX, FReal& PMin, FReal& PMax, int32& MinVertexIndex, int32& MaxVertexIndex, TArrayView<FReal>* VertexDs)
16 {
17 PMin = std::numeric_limits<FReal>::max();
18 PMax = std::numeric_limits<FReal>::lowest();
19 for (int32 VertexIndex = 0; VertexIndex < Convex.NumVertices(); ++VertexIndex)
20 {
21 const FVec3 V = Convex.GetVertex(VertexIndex);
22 const FReal D = FVec3::DotProduct(V - AxisX, AxisN);
23 if (D < PMin)
24 {
25 PMin = D;
26 MinVertexIndex = VertexIndex;
27 }
28 if (D > PMax)
29 {
30 PMax = D;
31 MaxVertexIndex = VertexIndex;
32 }
33 if (VertexDs != nullptr)
34 {
35 (*VertexDs)[VertexIndex] = D;
36 }
37 }
38 }
39
40 // Project a triangle onto an axis and return the projected range as well as the vertex indices that bound the range
41 inline void ProjectOntoAxis(const FTriangle& Triangle, const FVec3& AxisN, const FVec3& AxisX, FReal& PMin, FReal& PMax, int32& MinVertexIndex, int32& MaxVertexIndex)
42 {
43 const FVec3& V0 = Triangle.GetVertex(0);
44 const FVec3& V1 = Triangle.GetVertex(1);
45 const FVec3& V2 = Triangle.GetVertex(2);
46 const FReal Ds[3] =
47 {
48 FVec3::DotProduct(V0 - AxisX, AxisN),
49 FVec3::DotProduct(V1 - AxisX, AxisN),
50 FVec3::DotProduct(V2 - AxisX, AxisN)
51 };
52 MinVertexIndex = FMath::Min3Index(Ds[0], Ds[1], Ds[2]);
53 MaxVertexIndex = FMath::Max3Index(Ds[0], Ds[1], Ds[2]);
54 PMin = Ds[MinVertexIndex];
55 PMax = Ds[MaxVertexIndex];
56 }
57
58 // Project a capsule segment onto an axis and return the projected range as well as the vertex indices that bound the range
59 inline void ProjectOntoAxis(const FCapsule& Capsule, const FVec3& AxisN, const FVec3& AxisX, FReal& PMin, FReal& PMax, int32& MinVertexIndex, int32& MaxVertexIndex)
60 {
61 const FVec3 V0 = Capsule.GetX1f();
62 const FVec3 V1 = Capsule.GetX2f();
63 const FReal D0 = FVec3::DotProduct(V0 - AxisX, AxisN);
64 const FReal D1 = FVec3::DotProduct(V1 - AxisX, AxisN);
65 if (D0 < D1)
66 {
67 MinVertexIndex = 0;
68 MaxVertexIndex = 1;
69 PMin = D0;
70 PMax = D1;
71 }
72 else
73 {
74 MinVertexIndex = 1;
75 MaxVertexIndex = 0;
76 PMin = D1;
77 PMax = D0;
78 }
79 }
80
81 // Get the convex feature at the specific position and normal
82 template<typename ConvexType>
84 {
85 const FReal NormalTolerance = FReal(1.e-6);
86 const FReal PositionTolerance = FReal(1.e-4);
87 const FReal ToleranceSizeMultiplier = Convex.BoundingBox().Extents().GetAbsMax();
89
92
93 // Get the support vertex along the normal (which must point away from the convex)
95 Convex.SupportCore(Normal, 0, nullptr, SupportVertexIndex);
96
98 {
99 // See if the normal matches a face normal for any face using the vertex
100 int32 VertexPlanes[16];
101 int32 NumVertexPlanes = Convex.FindVertexPlanes(SupportVertexIndex, VertexPlanes, UE_ARRAY_COUNT(VertexPlanes));
102 for (int32 VertexPlaneIndex = 0; VertexPlaneIndex < NumVertexPlanes; ++VertexPlaneIndex)
103 {
104 const int32 PlaneIndex = VertexPlanes[VertexPlaneIndex];
106 Convex.GetPlaneNX(PlaneIndex, PlaneN, PlaneX);
107 const FReal PlaneDotNormal = FVec3::DotProduct(PlaneN, Normal);
108 if (FMath::IsNearlyEqual(PlaneDotNormal, FReal(1), NormalTolerance))
109 {
111 OutFeature.PlaneIndex = PlaneIndex;
112 OutFeature.PlaneFeatureIndex = 0;
113 return true;
114 }
115
117 {
118 BestPlaneIndex = PlaneIndex;
120 }
121 }
122
123 // See if any of the edges using the vertex are perpendicular to the normal
124 // @todo(chaos): we could visit the vertex edges here rather than use the plane edges
126 {
128
129 const int32 NumPlaneVertices = Convex.NumPlaneVertices(BestPlaneIndex);
130 for (int32 PlaneVertexIndex = 0; PlaneVertexIndex < NumPlaneVertices; ++PlaneVertexIndex)
131 {
132 const int32 VertexIndex0 = Convex.GetPlaneVertex(BestPlaneIndex, PlaneVertexIndex);
133 const int32 VertexIndex1 = (PlaneVertexIndex == NumPlaneVertices - 1) ? Convex.GetPlaneVertex(BestPlaneIndex, 0) : Convex.GetPlaneVertex(BestPlaneIndex, PlaneVertexIndex + 1);
134
135 if (VertexIndex0 == SupportVertexIndex)
136 {
138 }
139
140 if ((VertexIndex0 == SupportVertexIndex) || (VertexIndex1 == SupportVertexIndex))
141 {
142 const FVec3 Vertex0 = Convex.GetVertex(VertexIndex0);
143 const FVec3 Vertex1 = Convex.GetVertex(VertexIndex1);
144 const FVec3 EdgeDelta = Vertex1 - Vertex0;
145 const FReal EdgeDotNormal = FVec3::DotProduct(EdgeDelta, Normal);
146 if (FMath::Abs(EdgeDotNormal) < EdgeNormalTolerance)
147 {
148 // @todo(chaos): we need to be able to get an EdgeIndex (probably half edge index)
149 // Also, we probably want both the plane index and the edge index
151 OutFeature.PlaneIndex = BestPlaneIndex;
152 OutFeature.PlaneFeatureIndex = PlaneVertexIndex;
153 return true;
154 }
155 }
156 }
157
158 // Not a face or edge, so it should be the SupportVertex, but we need to specify the
159 // plane and plane-index rather than the convex vertex index (which we found just above)
161 {
163 OutFeature.PlaneIndex = BestPlaneIndex;
164 OutFeature.PlaneFeatureIndex = BestPlaneVertexIndex;
165 }
166 return true;
167 }
168 }
169
170 return false;
171 }
172
173 // Get the triangle feature at the specific position and normal
175 {
176 // @todo(chaos): pass in the triangle normal - we almost certainly calculated it elsewhere
177 // NOTE: The normal epsilon needs to be less than the maximu error that GJK/EPA produces when it hits a degenerate
178 // case, which can happen when we have almost exact face-to-face contact. The max error is hard to know, since it
179 // depends on the state of GJK on the iteration before it hits its tolerance, but seems to be typically ~0.01
180 const FReal NormalEpsilon = FReal(0.02);
181 const FReal NormalDot = FVec3::DotProduct(Normal, TriangleNormal);
183 {
185 OutFeature.PlaneIndex = 0;
186 OutFeature.PlaneFeatureIndex = 0;
187 return true;
188 }
189
190 const FReal BarycentricTolerance = FReal(1.e-6);
191 int32 VertexIndex0, VertexIndex1;
192 if (GetTriangleEdgeVerticesAtPosition(Position, &Triangle.GetVertex(0), VertexIndex0, VertexIndex1, BarycentricTolerance))
193 {
194 if ((VertexIndex0 != INDEX_NONE) && (VertexIndex1 != INDEX_NONE))
195 {
197 OutFeature.PlaneIndex = 0;
198 OutFeature.PlaneFeatureIndex = VertexIndex0;
199 return true;
200 }
201 else if (VertexIndex0 != INDEX_NONE)
202 {
204 OutFeature.PlaneIndex = 0;
205 OutFeature.PlaneFeatureIndex = VertexIndex0;
206 return true;
207 }
208 else if (VertexIndex1 != INDEX_NONE)
209 {
211 OutFeature.PlaneIndex = 0;
212 OutFeature.PlaneFeatureIndex = VertexIndex1;
213 return true;
214 }
215 }
216
217 return false;
218 }
219
220 // Check whether the two edges of two convex shapes contribute to the Minkowski sum.
221 // A and B are the face normals for the faces of the edge convex 1
222 // C and D are the negated face normals for the faces of the edge convex 2
223 template<typename RealType>
224 inline bool IsOnMinkowskiSumConvexConvex(const TVec3<RealType>& A, const TVec3<RealType>& B, const TVec3<RealType>& C, const TVec3<RealType>& D, const RealType Tolerance = 1.e-2f)
225 {
228 const RealType CBA = TVec3<RealType>::DotProduct(C, BA);
229 const RealType DBA = TVec3<RealType>::DotProduct(D, BA);
230 const RealType ADC = TVec3<RealType>::DotProduct(A, DC);
231 const RealType BDC = TVec3<RealType>::DotProduct(B, DC);
232
233 return ((CBA * DBA) < -Tolerance) && ((ADC * BDC) < -Tolerance) && ((CBA * BDC) > Tolerance);
234 }
235
236 // Check whether the convex-triangle edge pair form part of the Minkowski Sum. Only edge pairs
237 // that contribute to the Minkowki Sum surface need to be checked for separation. The inputs
238 // are the convex normals for the two faces that share the convex edge, and the normal and
239 // edge vector of the triangle.
240 //
241 // This is a custom version of IsOnMinkowskiSumConvexConvex for triangles where the two normals
242 // are directly opposing and therefore the regular edge vector calculation returns zero.
243 //
244 // @param A ConvexNormalA
245 // @param B ConvexNormalB
246 // @param BA ConvexEdge
247 // @param C TriNormal (negated)
248 // @param DC TriEdge
249 inline bool IsOnMinkowskiSumConvexTriangle(const FVec3& A, const FVec3& B, const FVec3& BA, const FVec3& C, const FVec3& DC)
250 {
251 const FReal CBA = FVec3::DotProduct(C, BA); // TriNormal | ConvexEdge
252 const FReal ADC = FVec3::DotProduct(A, DC); // ConvexNormalA | TriEdge
253 const FReal BDC = FVec3::DotProduct(B, DC); // ConvexNormalB | TriEdge
254
255 const FReal Tolerance = 1.e-2f;
256 return ((ADC * BDC) < -Tolerance) && ((CBA * BDC) > Tolerance);
257 }
258
259}
260
261namespace Chaos
262{
263 template <typename ConvexType>
264 UE_DEPRECATED(5.4, "Not part of public API")
265 inline void ProjectOntoAxis(const ConvexType& Convex, const FVec3& AxisN, const FVec3& AxisX, FReal& PMin, FReal& PMax, int32& MinVertexIndex, int32& MaxVertexIndex, TArrayView<FReal>* VertexDs)
266 {
267 return Private::ProjectOntoAxis(Convex, AxisN, AxisX, PMin, PMax, MinVertexIndex, MaxVertexIndex, VertexDs);
268 }
269
270 UE_DEPRECATED(5.4, "Not part of public API")
271 inline void ProjectOntoAxis(const FTriangle& Triangle, const FVec3& AxisN, const FVec3& AxisX, FReal& PMin, FReal& PMax, int32& MinVertexIndex, int32& MaxVertexIndex)
272 {
273 return Private::ProjectOntoAxis(Triangle, AxisN, AxisX, PMin, PMax, MinVertexIndex, MaxVertexIndex);
274 }
275
276 UE_DEPRECATED(5.4, "Not part of public API")
277 inline void ProjectOntoAxis(const FCapsule& Capsule, const FVec3& AxisN, const FVec3& AxisX, FReal& PMin, FReal& PMax, int32& MinVertexIndex, int32& MaxVertexIndex)
278 {
279 return Private::ProjectOntoAxis(Capsule, AxisN, AxisX, PMin, PMax, MinVertexIndex, MaxVertexIndex);
280 }
281}
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
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
#define UE_ARRAY_COUNT(array)
Definition UnrealTemplate.h:212
Definition Capsule.h:23
Definition ConvexFeature.h:20
Definition Vector.h:1000
Definition ArrayView.h:139
Definition BodyInstance.h:90
bool GetConvexFeature(const ConvexType &Convex, const FVec3 &Position, const FVec3 &Normal, Private::FConvexFeature &OutFeature)
Definition ConvexContactPointUtilities.h:83
bool IsOnMinkowskiSumConvexConvex(const TVec3< RealType > &A, const TVec3< RealType > &B, const TVec3< RealType > &C, const TVec3< RealType > &D, const RealType Tolerance=1.e-2f)
Definition ConvexContactPointUtilities.h:224
void ProjectOntoAxis(const ConvexType &Convex, const FVec3 &AxisN, const FVec3 &AxisX, FReal &PMin, FReal &PMax, int32 &MinVertexIndex, int32 &MaxVertexIndex, TArrayView< FReal > *VertexDs)
Definition ConvexContactPointUtilities.h:15
bool GetTriangleFeature(const FTriangle &Triangle, const FVec3 &TriangleNormal, const FVec3 &Position, const FVec3 &Normal, Private::FConvexFeature &OutFeature)
Definition ConvexContactPointUtilities.h:174
bool IsOnMinkowskiSumConvexTriangle(const FVec3 &A, const FVec3 &B, const FVec3 &BA, const FVec3 &C, const FVec3 &DC)
Definition ConvexContactPointUtilities.h:249
Definition SkeletalMeshComponent.h:307
FRealDouble FReal
Definition Real.h:22
void ProjectOntoAxis(const ConvexType &Convex, const FVec3 &AxisN, const FVec3 &AxisX, FReal &PMin, FReal &PMax, int32 &MinVertexIndex, int32 &MaxVertexIndex, TArrayView< FReal > *VertexDs)
Definition ConvexContactPointUtilities.h:265
bool GetTriangleEdgeVerticesAtPosition(const FVec3 &Position, const FVec3 VertexA, const FVec3 VertexB, const FVec3 VertexC, int32 &OutEdgeVertexIndexA, int32 &OutEdgeVertexIndexB, const FReal BaryCentricTolerance=UE_KINDA_SMALL_NUMBER)
Definition ContactTriangles.h:16
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
static constexpr UE_FORCEINLINE_HINT int32 Min3Index(const T A, const T B, const T C)
Definition UnrealMathUtility.h:571
static constexpr UE_FORCEINLINE_HINT int32 Max3Index(const T A, const T B, const T C)
Definition UnrealMathUtility.h:564