UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
CorePlane.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "ChaosCheck.h"
5#include "Chaos/Core.h"
7
8namespace Chaos
9{
10 template <typename T, int d = 3>
12 {
13 public:
14
15 // Scale the plane and assume that any of the scale components could be zero
17 {
18 const TVec3<T> ScaledX = Plane.MX * Scale;
19
20 // If all 3 scale components are non-zero we can just inverse-scale the normal
21 // If 1 scale component is zero, the normal will point in that direction of the zero scale
22 // If 2 scale components are zero, the normal will be zero along the non-zero scale direction
23 // If 3 scale components are zero, the normal will be unchanged
24 const int32 ZeroX = FMath::IsNearlyZero(Scale.X) ? 1 : 0;
25 const int32 ZeroY = FMath::IsNearlyZero(Scale.Y) ? 1 : 0;
26 const int32 ZeroZ = FMath::IsNearlyZero(Scale.Z) ? 1 : 0;
27 const int32 NumZeros = ZeroX + ZeroY + ZeroZ;
29 if (NumZeros == 0)
30 {
31 // All 3 scale components non-zero
32 ScaledN = TVec3<T>(Plane.MNormal.X / Scale.X, Plane.MNormal.Y / Scale.Y, Plane.MNormal.Z / Scale.Z);
33 }
34 else if (NumZeros == 1)
35 {
36 // Exactly one Scale component is zero
38 (ZeroX) ? 1.0f : 0.0f,
39 (ZeroY) ? 1.0f : 0.0f,
40 (ZeroZ) ? 1.0f : 0.0f);
41 }
42 else if (NumZeros == 2)
43 {
44 // Exactly two Scale components is zero
46 (ZeroX) ? Plane.MNormal.X : 0.0f,
47 (ZeroY) ? Plane.MNormal.Y : 0.0f,
48 (ZeroZ) ? Plane.MNormal.Z : 0.0f);
49 }
50 else // (NumZeros == 3)
51 {
52 // All 3 scale components are zero
53 ScaledN = Plane.MNormal;
54 }
55
56 // Even after all the above, we may still get a zero normal (e.g., we scale N=(1,0,0) by S=(0,1,0))
57 const T ScaleN2 = ScaledN.SizeSquared();
59 {
60 ScaledN = ScaledN * FMath::InvSqrt(ScaleN2);
61 }
62 else
63 {
64 ScaledN = Plane.MNormal;
65 }
66
68 }
69
70 // Scale the plane and assume that none of the scale components are zero
71 template <typename U>
73 {
74 const TVec3<T> ScaledX = TVec3<T>(Plane.X()) * Scale;
75 TVec3<T> ScaledN = TVec3<T>(Plane.Normal()) * InvScale;
76
77 // We don't handle zero scales, but we could still end up with a small normal
78 const T ScaleN2 = ScaledN.SizeSquared();
80 {
81 ScaledN = ScaledN * FMath::InvSqrt(ScaleN2);
82 }
83 else
84 {
85 ScaledN = TVec3<T>(Plane.Normal());
86 }
87
89 }
90
91 template <typename U>
92 static FORCEINLINE void MakeScaledUnsafe(const TVec3<U>& PlaneN, const TVec3<U>& PlaneX, const TVec3<T>& Scale, const TVec3<T>& InvScale, TVec3<T>& OutN, TVec3<T>& OutX)
93 {
95 TVec3<T> ScaledN = TVec3<T>(PlaneN * InvScale);
96
97 // We don't handle zero scales, but we could still end up with a small normal
98 const T ScaleN2 = ScaledN.SizeSquared();
100 {
101 ScaledN = ScaledN * FMath::InvSqrt(ScaleN2);
102 }
103 else
104 {
106 }
107
108 OutN = ScaledN;
109 OutX = ScaledX;
110 }
111
112
113 template <typename U>
115 {
116 return TCorePlane<T>(TVec3<T>(Plane.X()), TVec3<T>(Plane.Normal()));
117 }
118
119
120 TCorePlane() = default;
122 : MX(InX)
123 , MNormal(InNormal)
124 {
125 static_assert(d == 3, "Only dimension 3 is supported");
126 }
127
131 template <typename U>
132 U SignedDistance(const TVec3<U>& x) const
133 {
134 return TVec3<U>::DotProduct(x - TVec3<U>(MX), TVec3<U>(MNormal));
135 }
136
141 {
142 Normal = MNormal;
143 return FVec3::DotProduct(x - (FVec3)MX, (FVec3)MNormal);
144 }
145
146 FVec3 FindClosestPoint(const FVec3& x, const FReal Thickness = (FReal)0) const
147 {
148 auto Dist = FVec3::DotProduct(x - (FVec3)MX, (FVec3)MNormal) - Thickness;
149 return x - FVec3(Dist * MNormal);
150 }
151
152 bool Raycast(const FVec3& StartPoint, const FVec3& Dir, const FReal Length, const FReal Thickness, FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex) const
153 {
155 CHAOS_ENSURE(Length > 0);
156 OutFaceIndex = INDEX_NONE;
157 OutTime = 0;
158
159 // This is mainly to fix static analysis warnings
160 OutPosition = FVec3(0);
161 OutNormal = FVec3(0);
162
163 const FReal SignedDist = FVec3::DotProduct(StartPoint - (FVec3)MX, (FVec3)MNormal);
164 if (FMath::Abs(SignedDist) < Thickness)
165 {
166 //initial overlap so stop
167 //const FReal DirDotNormal = FVec3::DotProduct(Dir, (FVec3)MNormal);
168 //OutPosition = StartPoint;
169 //OutNormal = DirDotNormal < 0 ? MNormal : -MNormal;
170 //OutTime = 0;
171 return true;
172 }
173
174 const FVec3 DirTowardsPlane = SignedDist < 0 ? MNormal : -MNormal;
175 const FReal RayProjectedTowardsPlane = FVec3::DotProduct(Dir, DirTowardsPlane);
176 const FReal Epsilon = 1e-7f;
177 if (RayProjectedTowardsPlane < Epsilon) //moving parallel or away
178 {
179 return false;
180 }
181
182 //No initial overlap so we are outside the thickness band of the plane. So translate the plane to account for thickness
183 const FVec3 TranslatedPlaneX = (FVec3)MX - Thickness * DirTowardsPlane;
187
189 {
190 return false; //never reach
191 }
192
193 OutTime = LengthAlongRay;
194 OutPosition = StartPoint + (LengthAlongRay + Thickness) * Dir;
195 OutNormal = -DirTowardsPlane;
196 return true;
197 }
198
199 Pair<FVec3, bool> FindClosestIntersection(const FVec3& StartPoint, const FVec3& EndPoint, const FReal Thickness) const
200 {
201 FVec3 Direction = EndPoint - StartPoint;
202 FReal Length = Direction.Size();
203 Direction = Direction.GetSafeNormal();
204 FVec3 XPos = (FVec3)MX + (FVec3)MNormal * Thickness;
205 FVec3 XNeg = (FVec3)MX - (FVec3)MNormal * Thickness;
206 FVec3 EffectiveX = ((XNeg - StartPoint).Size() < (XPos - StartPoint).Size()) ? XNeg : XPos;
207 FVec3 PlaneToStart = EffectiveX - StartPoint;
208 FReal Denominator = FVec3::DotProduct(Direction, MNormal);
209 if (Denominator == 0)
210 {
211 if (FVec3::DotProduct(PlaneToStart, MNormal) == 0)
212 {
213 return MakePair(EndPoint, true);
214 }
215 return MakePair(FVec3(0), false);
216 }
217 FReal Root = FVec3::DotProduct(PlaneToStart, MNormal) / Denominator;
219 {
220 return MakePair(FVec3(0), false);
221 }
222 return MakePair(FVec3(Root * Direction + StartPoint), true);
223 }
224
225 const TVec3<T>& X() const { return MX; }
226 const TVec3<T>& Normal() const { return MNormal; }
227 const TVec3<T>& Normal(const TVec3<T>&) const { return MNormal; }
228
230 {
231 Ar << MX << MNormal;
232 }
233
235 {
237 }
238
239 private:
240
241 TVec3<T> MX;
242 TVec3<T> MNormal;
243 };
244
245 template <typename T>
247 {
248 PlaneConcrete.Serialize(Ar);
249 return Ar;
250 }
251
252 template <typename T, int d = 3>
254} // namespace Chaos
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define ensure( InExpression)
Definition AssertionMacros.h:464
#define CHAOS_ENSURE(Condition)
Definition ChaosCheck.h:22
@ INDEX_NONE
Definition CoreMiscDefines.h:150
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
constexpr uint32 HashCombine(uint32 A, uint32 C)
Definition TypeHash.h:36
#define UE_SMALL_NUMBER
Definition UnrealMathUtility.h:130
#define UE_KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:131
uint32 Size
Definition VulkanMemory.cpp:4034
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition CorePlane.h:12
const TVec3< T > & X() const
Definition CorePlane.h:225
FVec3 FindClosestPoint(const FVec3 &x, const FReal Thickness=(FReal) 0) const
Definition CorePlane.h:146
const TVec3< T > & Normal() const
Definition CorePlane.h:226
static FORCEINLINE TCorePlane< T > MakeScaledUnsafe(const TCorePlane< U > &Plane, const TVec3< T > &Scale, const TVec3< T > &InvScale)
Definition CorePlane.h:72
bool Raycast(const FVec3 &StartPoint, const FVec3 &Dir, const FReal Length, const FReal Thickness, FReal &OutTime, FVec3 &OutPosition, FVec3 &OutNormal, int32 &OutFaceIndex) const
Definition CorePlane.h:152
FORCEINLINE void Serialize(FArchive &Ar)
Definition CorePlane.h:229
uint32 GetTypeHash() const
Definition CorePlane.h:234
const TVec3< T > & Normal(const TVec3< T > &) const
Definition CorePlane.h:227
static FORCEINLINE void MakeScaledUnsafe(const TVec3< U > &PlaneN, const TVec3< U > &PlaneX, const TVec3< T > &Scale, const TVec3< T > &InvScale, TVec3< T > &OutN, TVec3< T > &OutX)
Definition CorePlane.h:92
TCorePlane(const TVec3< T > &InX, const TVec3< T > &InNormal)
Definition CorePlane.h:121
U SignedDistance(const TVec3< U > &x) const
Definition CorePlane.h:132
FReal PhiWithNormal(const FVec3 &x, FVec3 &Normal) const
Definition CorePlane.h:140
static TCorePlane< T > MakeScaledSafe(const TCorePlane< T > &Plane, const TVec3< T > &Scale)
Definition CorePlane.h:16
Pair< FVec3, bool > FindClosestIntersection(const FVec3 &StartPoint, const FVec3 &EndPoint, const FReal Thickness) const
Definition CorePlane.h:199
static FORCEINLINE TCorePlane< T > MakeFrom(const TCorePlane< U > &Plane)
Definition CorePlane.h:114
TCorePlane()=default
Definition Vector.h:1000
FORCEINLINE T SizeSquared() const
Definition Vector.h:1067
Definition Archive.h:1208
Definition SkeletalMeshComponent.h:307
FChaosArchive & operator<<(FChaosArchive &Ar, FRigidParticleControlFlags &Flags)
Definition RigidParticleControlFlags.cpp:15
FRealDouble FReal
Definition Real.h:22
Pair< T1, T2 > MakePair(const T1 &First, const T2 &Second)
Definition Pair.h:45
TVector< FReal, 3 > FVec3
Definition Core.h:17
uint32 GetTypeHash(const TBox< T > &Box)
Definition Box.h:1008
Definition Pair.h:8
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
static UE_FORCEINLINE_HINT bool IsNearlyZero(float Value, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:407