UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SpringMath.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Math/MathFwd.h"
6#include "Math/Vector.h"
7#include "Math/Quat.h"
8
9// Collection of useful spring methods which can be used for damping, simulating characters etc.
10// Reference https://theorangeduck.com/page/spring-roll-call
11
13{
14private:
15 static constexpr float SmoothingTimeToDamping(float SmoothingTime)
16 {
17 return 4.0f / FMath::Max(SmoothingTime, UE_KINDA_SMALL_NUMBER);
18 }
19
20public:
26 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
31
37 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
39 {
40 return HalfLife / UE_LN2;
41 }
42
48 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
50 {
51 return 2.0f / FMath::Max(SmoothingTime, UE_KINDA_SMALL_NUMBER);
52 }
53
59 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
61 {
62 return 2.0f / FMath::Max(Strength, UE_KINDA_SMALL_NUMBER);
63 }
64
75 template <typename T>
76 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
78 T& InOutX,
79 T& InOutV,
80 T TargetX,
81 float SmoothingTime,
82 float DeltaTime)
83 {
84 float Y = SmoothingTimeToDamping(SmoothingTime) / 2.0f;
85 T J0 = InOutX - TargetX;
86 T J1 = InOutV + J0 * Y;
87 float EyDt = FMath::InvExpApprox(Y * DeltaTime);
88
89 InOutX = EyDt * (J0 + J1 * DeltaTime) + TargetX;
90 InOutV = EyDt * (InOutV - J1 * Y * DeltaTime);
91 }
92
101 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
103 float& InOutAngleRadians,
105 float TargetAngleRadians,
106 float SmoothingTime,
107 float DeltaTime)
108 {
110 float Y = SmoothingTimeToDamping(SmoothingTime) / 2.0f;
112
115 float EyDt = FMath::InvExpApprox(Y * DeltaTime);
116
117 InOutAngleRadians = EyDt * (J0 + J1 * DeltaTime) + TargetAngleRadians;
119 }
120
129 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
133 const FQuat& TargetRotation,
134 float SmoothingTime,
135 float DeltaTime)
136 {
138 float Y = SmoothingTimeToDamping(SmoothingTime) / 2.0f;
140
141 FQuat Diff = InOutRotation * TargetRotation.Inverse();
143 FVector J0 = Diff.ToRotationVector();
145
146 float EyDt = FMath::InvExpApprox(Y * DeltaTime);
147
148
149 InOutRotation = FQuat::MakeFromRotationVector(EyDt * (J0 + J1 * DeltaTime)) * TargetRotation;
151 }
152
164 template <typename TFloat>
165 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
167 TFloat& InOutX,
168 TFloat& InOutV,
171 TFloat MaxSpeed,
172 float SmoothingTime,
173 float DeltaTime)
174 {
175 static_assert(std::is_floating_point_v<TFloat>, "TFloat must be floating point");
176
177 MaxSpeed = FMath::Max(MaxSpeed, 0.0f); // MaxSpeed can't be negative
178
179 TFloat XDiff = ((TargetX - InOutXi) > 0.0f
180 ? 1.0f
181 : -1.0f) * MaxSpeed;
182
186 : TargetX;
187
189
190 InOutXi = FMath::Abs(TargetX - InOutXi) > DeltaTime * MaxSpeed
191 ? InOutXi + XDiff * DeltaTime
192 : TargetX;
193 }
194
207 template <typename TVector>
208 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
210 TVector& InOutX,
211 TVector& InOutV,
212 TVector& InOutXi,
213 TVector TargetX,
214 float MaxSpeed,
215 float SmoothingTime,
216 float DeltaTime)
217 {
218 TVector XDiff = TargetX - InOutXi;
219 float XDiffLength = XDiff.Length();
222 : TVector::ZeroVector;
223
225 TVector XGoalFuture = XDiffLength > TGoalFuture * MaxSpeed
226 ? InOutXi + (XDiffDir * MaxSpeed) * TGoalFuture
227 : TargetX;
228
230
231 InOutXi = XDiffLength > DeltaTime * MaxSpeed
232 ? InOutXi + XDiffDir * MaxSpeed * DeltaTime
233 : TargetX;
234 }
235
248 template <typename TVector>
249 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
251 TVector& InOutPosition,
252 TVector& InOutVelocity,
253 TVector& InOutAcceleration,
254 const TVector& TargetVelocity,
255 float SmoothingTime,
256 float DeltaTime,
257 float VDeadzone = 1e-2f,
258 float ADeadzone = 1e-4f)
259 {
260 float Y = SmoothingTimeToDamping(SmoothingTime) / 2.0f;
261 TVector J0 = InOutVelocity - TargetVelocity;
262 TVector J1 = InOutAcceleration + J0 * Y;
263 float EyDt = FMath::InvExpApprox(Y * DeltaTime);
264
265 InOutPosition = EyDt * (((-J1) / (Y * Y)) + ((-J0 - J1 * DeltaTime) / Y)) +
266 (J1 / (Y * Y)) + J0 / Y + TargetVelocity * DeltaTime + InOutPosition;
267 InOutVelocity = EyDt * (J0 + J1 * DeltaTime) + TargetVelocity;
268 InOutAcceleration = EyDt * (InOutAcceleration - J1 * Y * DeltaTime);
269
270 if ((TargetVelocity - InOutVelocity).SquaredLength() < FMath::Square(VDeadzone))
271 {
272 // We reached our target
274
275 if (InOutAcceleration.SquaredLength() < FMath::Square(ADeadzone))
276 {
277 InOutAcceleration = TVector::ZeroVector;
278 }
279 }
280 }
281
298 template <typename TVector>
299 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
304 const TVector& CurrentPosition,
305 const TVector& CurrentVelocity,
306 const TVector& CurrentAcceleration,
307 const TVector& TargetVelocity,
308 float SmoothingTime,
310 float VDeadzone = 1e-2f,
311 float ADeadzone = 1e-4f)
312 {
314 check(PredictCount > 0);
317
318 for (int32 i = 0; i < PredictCount; i++)
319 {
320 OutPredictedPositions[i] = CurrentPosition;
323 }
324
325 for (int32 i = 0; i < PredictCount; i++)
326 {
327 const float PredictTime = (float)(i + 1) * SecondsPerPredictionStep; // Note i+1 since we want index 0 to be the first prediction step
332 }
333 }
334
351 template <typename TVector>
352 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
354 TVector& InOutPosition,
355 TVector& InOutVelocity,
357 TVector& InOutAcceleration,
358 TVector TargetVelocity,
359 float SmoothingTime,
360 float MaxAcceleration,
361 float DeltaTime,
362 float VDeadzone = 1e-2f,
363 float ADeadzone = 1e-4f)
364 {
366 float VDiffLength = VDiff.Length();
367 TVector VDiffDir = VDiffLength > 0.0001f
369 : TVector::ZeroVector;
370
372 TVector MaxVFuture = VDiffLength > TGoalFuture * MaxAcceleration
373 ? InOutVelocityIntermediate + (VDiffDir * MaxAcceleration) * TGoalFuture
375
376 float Y = SmoothingTimeToDamping(SmoothingTime) / 2.0f;
377 TVector J0 = InOutVelocity - MaxVFuture;
378 TVector J1 = InOutAcceleration + J0 * Y;
379 float EyDt = FMath::InvExpApprox(Y * DeltaTime);
380
381 InOutPosition = EyDt * (((-J1) / (Y * Y)) + ((-J0 - J1 * DeltaTime) / Y)) +
382 (J1 / (Y * Y)) + J0 / Y + MaxVFuture * DeltaTime + InOutPosition;
383 InOutVelocity = EyDt * (J0 + J1 * DeltaTime) + MaxVFuture;
384 InOutAcceleration = EyDt * (InOutAcceleration - J1 * Y * DeltaTime);
385 InOutVelocityIntermediate = VDiffLength > DeltaTime * MaxAcceleration
386 ? InOutVelocityIntermediate + VDiffDir * MaxAcceleration * DeltaTime
388
389 if ((TargetVelocity - InOutVelocity).SquaredLength() < FMath::Square(VDeadzone))
390 {
391 // We reached our target
393
394 if (InOutAcceleration.SquaredLength() < FMath::Square(ADeadzone))
395 {
396 InOutAcceleration = TVector::ZeroVector;
397 }
398 }
399 }
400
420 template <typename TVector>
421 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
427 const TVector& CurrentPosition,
428 const TVector& CurrentVelocity,
429 const TVector& CurrentIntermediateVelocity,
430 const TVector& CurrentAcceleration,
431 const TVector& TargetVelocity,
432 float SmoothingTime,
433 float MaxAcceleration,
435 float VDeadzone = 1e-2f,
436 float ADeadzone = 1e-4f)
437 {
439 check(PredictCount > 0);
443
444 for (int32 i = 0; i < PredictCount; i++)
445 {
446 OutPredictedPositions[i] = CurrentPosition;
450 }
451
452 for (int32 i = 0; i < PredictCount; i++)
453 {
454 const float PredictTime = (float)(i + 1) * SecondsPerPredictionStep; // Note i+1 since we want index 0 to be the first prediction step
461 MaxAcceleration,
463 VDeadzone,
464 ADeadzone);
465 }
466 }
467
479 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
501
510 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
522
531 UE_EXPERIMENTAL(5.7, "SpringMath is experimental")
543};
#define check(expr)
Definition AssertionMacros.h:314
#define PRAGMA_DISABLE_EXPERIMENTAL_WARNINGS
Definition CoreMiscDefines.h:370
#define PRAGMA_ENABLE_EXPERIMENTAL_WARNINGS
Definition CoreMiscDefines.h:371
#define UE_EXPERIMENTAL(Version, Message)
Definition CoreMiscDefines.h:369
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
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
#define UE_KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:131
#define UE_LN2
Definition UnrealMathUtility.h:160
Definition ArrayView.h:139
static constexpr UE_FORCEINLINE_HINT T Square(const T A)
Definition UnrealMathUtility.h:578
static constexpr auto FindDeltaAngleRadians(T A1, T2 A2) -> decltype(A1 - A2)
Definition UnrealMathUtility.h:914
static constexpr T InvExpApprox(T X)
Definition UnrealMathUtility.h:1546
Definition SpringMath.h:13
static constexpr void ExponentialSmoothingApproxQuat(FQuat &InOutRotation, const FQuat &InTargetRotation, const float InDeltaTime, const float InSmoothingTime)
Definition SpringMath.h:511
static void CriticalSpringDamperQuat(FQuat &InOutRotation, FVector &InOutAngularVelocityRadians, const FQuat &TargetRotation, float SmoothingTime, float DeltaTime)
Definition SpringMath.h:130
static void SpringCharacterPredict(TArrayView< TVector > OutPredictedPositions, TArrayView< TVector > OutPredictedVelocities, TArrayView< TVector > OutPredictedAccelerations, const TVector &CurrentPosition, const TVector &CurrentVelocity, const TVector &CurrentAcceleration, const TVector &TargetVelocity, float SmoothingTime, float SecondsPerPredictionStep, float VDeadzone=1e-2f, float ADeadzone=1e-4f)
Definition SpringMath.h:300
static constexpr float SmoothingTimeToStrength(float SmoothingTime)
Definition SpringMath.h:49
static constexpr float HalfLifeToSmoothingTime(float HalfLife)
Definition SpringMath.h:38
static constexpr void ExponentialSmoothingApproxAngle(float &InOutAngleRadians, const float &InTargetAngleRadians, const float InDeltaTime, const float InSmoothingTime)
Definition SpringMath.h:532
static void VelocitySpringCharacterUpdate(TVector &InOutPosition, TVector &InOutVelocity, TVector &InOutVelocityIntermediate, TVector &InOutAcceleration, TVector TargetVelocity, float SmoothingTime, float MaxAcceleration, float DeltaTime, float VDeadzone=1e-2f, float ADeadzone=1e-4f)
Definition SpringMath.h:353
static void VelocitySpringDamper(TVector &InOutX, TVector &InOutV, TVector &InOutXi, TVector TargetX, float MaxSpeed, float SmoothingTime, float DeltaTime)
Definition SpringMath.h:209
static void CriticalSpringDamperAngle(float &InOutAngleRadians, float &InOutAngularVelocityRadians, float TargetAngleRadians, float SmoothingTime, float DeltaTime)
Definition SpringMath.h:102
static constexpr float SmoothingTimeToHalfLife(float SmoothingTime)
Definition SpringMath.h:27
static void VelocitySpringCharacterPredict(TArrayView< TVector > OutPredictedPositions, TArrayView< TVector > OutPredictedVelocities, TArrayView< TVector > OutPredictedIntermediateVelocities, TArrayView< TVector > OutPredictedAccelerations, const TVector &CurrentPosition, const TVector &CurrentVelocity, const TVector &CurrentIntermediateVelocity, const TVector &CurrentAcceleration, const TVector &TargetVelocity, float SmoothingTime, float MaxAcceleration, float SecondsPerPredictionStep, float VDeadzone=1e-2f, float ADeadzone=1e-4f)
Definition SpringMath.h:422
static void SpringCharacterUpdate(TVector &InOutPosition, TVector &InOutVelocity, TVector &InOutAcceleration, const TVector &TargetVelocity, float SmoothingTime, float DeltaTime, float VDeadzone=1e-2f, float ADeadzone=1e-4f)
Definition SpringMath.h:250
static void CriticalSpringDamper(T &InOutX, T &InOutV, T TargetX, float SmoothingTime, float DeltaTime)
Definition SpringMath.h:77
static constexpr float StrengthToSmoothingTime(float Strength)
Definition SpringMath.h:60
static void VelocitySpringDamperF(TFloat &InOutX, TFloat &InOutV, TFloat &InOutXi, TFloat TargetX, TFloat MaxSpeed, float SmoothingTime, float DeltaTime)
Definition SpringMath.h:166
static void CriticalSpringDamperQuatPredict(TArrayView< FQuat > OutPredictedRotations, TArrayView< FVector > OutPredictedAngularVelocities, int32 PredictCount, const FQuat &CurrentRotation, const FVector &CurrentAngularVelocity, const FQuat &TargetRotation, float SmoothingTime, float SecondsPerPredictionStep)
Definition SpringMath.h:480
static TQuat< double > MakeFromRotationVector(const TVector< double > &RotationVector)
Definition Quat.h:1203
TQuat< T > Inverse() const
Definition Quat.h:1264
static UE_FORCEINLINE_HINT TQuat< double > Slerp(const TQuat< double > &Quat1, const TQuat< double > &Quat2, double Slerp)
Definition Quat.h:660
void EnforceShortestArcWith(const TQuat< T > &OtherQuat)
Definition Quat.h:1276
static CORE_API const TQuat< double > Identity
Definition Quat.h:63