UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
RecordedTransformTrack.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"
10
11#include "RecordedTransformTrack.generated.h"
12
13USTRUCT()
15{
17
19 : Location(FVector(0.f))
20 , AccumulatedImpulse(FVector(0.f))
21 , Normal(FVector(0.f))
22 , Velocity1(FVector(0.f))
23 , Velocity2(FVector(0.f))
24 , AngularVelocity1(FVector(0.f))
25 , AngularVelocity2(FVector(0.f))
26 , Mass1(0.f)
27 , Mass2(0.f)
28 , ParticleIndex(INDEX_NONE)
29 , LevelsetIndex(INDEX_NONE)
30 , ParticleIndexMesh(INDEX_NONE)
31 , LevelsetIndexMesh(INDEX_NONE)
32 {}
33
41 , float InMass1
42 , float InMass2
47 : Location(InLocation)
48 , AccumulatedImpulse(InAccumulatedImpulse)
50 , Velocity1(InVelocity1)
51 , Velocity2(InVelocity2)
52 , AngularVelocity1(InAngularVelocity1)
53 , AngularVelocity2(InAngularVelocity2)
54 , Mass1(InMass1)
55 , Mass2(InMass2)
56 , ParticleIndex(InParticleIndex)
57 , LevelsetIndex(InLevelsetIndex)
58 , ParticleIndexMesh(InParticleIndexMesh)
59 , LevelsetIndexMesh(InLevelsetIndexMesh)
60 {}
61
62 UPROPERTY()
63 FVector Location;
64
65 UPROPERTY()
66 FVector AccumulatedImpulse;
67
68 UPROPERTY()
70
71 UPROPERTY()
72 FVector Velocity1;
73
74 UPROPERTY()
75 FVector Velocity2;
76
77 UPROPERTY()
78 FVector AngularVelocity1;
79
80 UPROPERTY()
81 FVector AngularVelocity2;
82
83 UPROPERTY()
84 float Mass1;
85
86 UPROPERTY()
87 float Mass2;
88
89 UPROPERTY()
90 int32 ParticleIndex;
91
92 UPROPERTY()
93 int32 LevelsetIndex;
94
95 UPROPERTY()
96 int32 ParticleIndexMesh;
97
98 UPROPERTY()
99 int32 LevelsetIndexMesh;
100};
101
102USTRUCT()
104{
106
108 : Location(FVector(0.f))
109 , Velocity(FVector(0.f))
111 , Mass(0.f)
112 , ParticleIndex(INDEX_NONE)
113 , ParticleIndexMesh(INDEX_NONE)
114 {}
115
116 UPROPERTY()
117 FVector Location;
118
119 UPROPERTY()
121
122 UPROPERTY()
124
125 UPROPERTY()
126 float Mass;
127
128 UPROPERTY()
129 int32 ParticleIndex;
130
131 UPROPERTY()
132 int32 ParticleIndexMesh;
133};
134
135USTRUCT()
137{
139
141 : Location(FVector(0.f))
142 , Velocity(FVector(0.f))
144 , Mass(0.f)
145 , ParticleIndex(INDEX_NONE)
146 , ParticleIndexMesh(INDEX_NONE)
147 {}
148
162
163 UPROPERTY()
164 FVector Location;
165
166 UPROPERTY()
168
169 UPROPERTY()
171
172 UPROPERTY()
173 float Mass;
174
175 UPROPERTY()
176 int32 ParticleIndex;
177
178 UPROPERTY()
179 int32 ParticleIndexMesh;
180
182 {
183 return ::GetTypeHash(Other.ParticleIndex);
184 }
185
187 {
188 return A.ParticleIndex == B.ParticleIndex;
189 }
190};
191
192UENUM()
200
205USTRUCT()
207{
209
210
215 UPROPERTY()
216 TArray<FTransform> Transforms;
217
222 UPROPERTY()
223 TArray<int32> TransformIndices;
224
230 UPROPERTY()
231 TArray<int32> PreviousTransformIndices;
232
237 UPROPERTY()
238 TArray<bool> DisabledFlags;
239
240 UPROPERTY()
242
243 UPROPERTY()
245
246 UPROPERTY()
247 TSet<FSolverTrailingData> Trailings;
248
249 UPROPERTY()
250 float Timestamp = 0.0f;
251
252 void Reset(int32 InNum = 0)
253 {
254 Transforms.Reset(InNum);
255 DisabledFlags.Reset(InNum);
256
257 if(InNum > 0)
258 {
259 Transforms.AddDefaulted(InNum);
260 DisabledFlags.AddDefaulted(InNum);
261 }
262
264
265 Collisions.Reset();
266 Breakings.Reset();
267 Trailings.Reset();
268 }
269};
270
271USTRUCT()
273{
275
276 UPROPERTY()
278
279 float GetDt() const
280 {
281 return Records.Num() > 1 ? Records[1].Timestamp - Records[0].Timestamp : 0;
282 }
283
287 bool IsTimeValid(float InTime) const
288 {
289 if(Records.Num() > 1)
290 {
291 const FRecordedFrame& First = Records[0];
292 const FRecordedFrame& Last = Records.Last();
293
294 return First.Timestamp <= InTime && InTime <= Last.Timestamp;
295 }
296
297 return false;
298 }
299
305 {
306 const int32 NumKeys = Records.Num();
307 if(NumKeys > 0)
308 {
309 float FirstKeyTime = Records[0].Timestamp;
310 float LastKeyTime = Records[NumKeys - 1].Timestamp;
311
312 if(LastKeyTime <= InTime)
313 {
314 // Past the end of the records
315 return NumKeys - 1;
316 }
317
318 if(FirstKeyTime >= InTime)
319 {
320 // Before the beginning of the records
321 return 0;
322 }
323
324 // Linear search
325 // #BG TODO Do something else, binary search
326 for(int32 KeyIndex = 1; KeyIndex < NumKeys; ++KeyIndex)
327 {
328 const float CurrTime = Records[KeyIndex].Timestamp;
329 if(CurrTime > InTime)
330 {
331 // Just passed over the specified time, last record is before
332 return KeyIndex - 1;
333 }
334 }
335 }
336
337 return INDEX_NONE;
338 }
339
344 {
345 for(const FRecordedFrame& Frame : Records)
346 {
348 {
349 return &Frame;
350 }
351 }
352
353 return nullptr;
354 }
355
360 {
361 for(FRecordedFrame& Frame : Records)
362 {
364 {
365 return &Frame;
366 }
367 }
368
369 return nullptr;
370 }
371
376 {
377 const int32 NumFrames = Records.Num();
378 for(int32 FrameIndex = 0; FrameIndex < NumFrames; ++FrameIndex)
379 {
380 const FRecordedFrame& Frame = Records[FrameIndex];
382 {
383 return FrameIndex;
384 }
385 }
386
387 return INDEX_NONE;
388 }
389
396 {
397 // If we're exactly on a frame, just return that
398 if(const FRecordedFrame* ExactFrame = FindRecordedFrame(InTime))
399 {
401 OutSecond = nullptr;
402
403 return;
404 }
405
406 const int32 KeyBeforeIndex = FindLastKeyBefore(InTime);
408
409 // Past then end, just return the last frame
410 if(KeyBeforeIndex == Records.Num() - 1)
411 {
412 OutFirst = &Records.Last();
413 OutSecond = nullptr;
414
415 return;
416 }
417
418 // Somewhere in the middle, return both
419 OutFirst = &Records[KeyBeforeIndex];
420 OutSecond = &Records[KeyAfterIndex];
421 }
422
427 {
428 // If we're exactly on a frame, just return that
429 if(const FRecordedFrame* ExactFrame = FindRecordedFrame(InTime))
430 {
431 return ExactFrame->Transforms[InIndex];
432 }
433
434 // Otherwise interpolate
435 const int32 KeyBeforeIndex = FindLastKeyBefore(InTime);
437
438 if(KeyBeforeIndex == Records.Num() - 1)
439 {
440 return Records.Last().Transforms[InIndex];
441 }
442
443 const FRecordedFrame& BeforeFrame = Records[KeyBeforeIndex];
444 const FRecordedFrame& AfterFrame = Records[KeyAfterIndex];
445
446 const float BeforeTime = BeforeFrame.Timestamp;
447 const float AfterTime = AfterFrame.Timestamp;
448 const float Alpha = (InTime - BeforeTime) / (AfterTime - BeforeTime);
449
450 FTransform Result;
451 Result.Blend(BeforeFrame.Transforms[InIndex], AfterFrame.Transforms[InIndex], Alpha);
452
453 return Result;
454 }
455
460 {
461 // If we're exactly on a frame, just return that
462 if(const FRecordedFrame* ExactFrame = FindRecordedFrame(InTime))
463 {
464 return ExactFrame->DisabledFlags[InIndex];
465 }
466
467 const int32 KeyBeforeIndex = FindLastKeyBefore(InTime);
468 return Records[KeyBeforeIndex].DisabledFlags[InIndex];
469 }
470
475 {
477 {
478 return !GetDisabledAtTime(InIndex, InBeginTime);
479 }
480
482 {
484 }
485
486 const int32 KeyBeforeBeginIndex = FindLastKeyBefore(InBeginTime);
487 const int32 KeyBeforeEndIndex = FindLastKeyBefore(InEndTime);
489
490 if(Offset < 2)
491 {
492 return !Records[KeyBeforeBeginIndex].DisabledFlags[InIndex];
493 }
494
496 {
497 if(!Records[KeyBeforeBeginIndex + WindowKeyIndex].DisabledFlags[InIndex])
498 {
499 return true;
500 }
501 }
502
503 return false;
504 }
505
509 FVector GetLinearVelocityAtTime(int32 InIndex, float InTime, float SampleWidth = 1.0f / 120.0f) const
510 {
511 if(Records.Num() == 0)
512 {
513 return FVector::ZeroVector;
514 }
515 // We're at the beginning of the cache, zero velocity (also guarantees we have at least SampleWidth before InTime)
516 if(FMath::Abs(InTime - Records[0].Timestamp) <= (SampleWidth + UE_SMALL_NUMBER))
517 {
518 return FVector::ZeroVector;
519 }
520
521 FTransform Prev = GetTransformAtTime(InIndex, InTime - SampleWidth);
522 FTransform Curr = GetTransformAtTime(InIndex, InTime);
523
524 return (Curr.GetTranslation() - Prev.GetTranslation()) / SampleWidth;
525 }
526
530 FVector GetAngularVelocityAtTime(int32 InIndex, float InTime, float SampleWidth = 1.0f / 120.0f) const
531 {
532 if(Records.Num() == 0)
533 {
534 return FVector::ZeroVector;
535 }
536 // We're at the beginning of the cache, zero velocity (also guarantees we have at least SampleWidth before InTime)
537 if(FMath::Abs(InTime - Records[0].Timestamp) <= (SampleWidth + UE_SMALL_NUMBER))
538 {
539 return FVector::ZeroVector;
540 }
541
542 FTransform Prev = GetTransformAtTime(InIndex, InTime - SampleWidth);
543 FTransform Curr = GetTransformAtTime(InIndex, InTime);
544
545 FQuat Delta = Curr.GetRotation() * Prev.GetRotation().Inverse();
548 Delta.ToAxisAndAngle(Axis, Angle);
549
550 return (Axis * Angle) / SampleWidth;
551 }
552
553 static CHAOS_API FRecordedTransformTrack ProcessRawRecordedData(const FRecordedTransformTrack& InCache);
554
555};
@ Normal
Definition AndroidInputInterface.h:116
@ 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
#define MAX_flt
Definition NumericLimits.h:29
#define UPROPERTY(...)
UObject definition macros.
Definition ObjectMacros.h:744
#define GENERATED_BODY(...)
Definition ObjectMacros.h:765
#define UENUM(...)
Definition ObjectMacros.h:749
#define USTRUCT(...)
Definition ObjectMacros.h:746
EGeometryCollectionCacheType
Definition RecordedTransformTrack.h:194
#define UE_SMALL_NUMBER
Definition UnrealMathUtility.h:130
uint32 Offset
Definition VulkanMemory.cpp:4033
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Array.h:670
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
Definition RecordedTransformTrack.h:207
float Timestamp
Definition RecordedTransformTrack.h:250
Definition RecordedTransformTrack.h:273
int32 FindRecordedFrameIndex(float InTime, float InTolerance=UE_SMALL_NUMBER) const
Definition RecordedTransformTrack.h:375
bool GetDisabledAtTime(int32 InIndex, float InTime) const
Definition RecordedTransformTrack.h:459
void GetFramesForTime(float InTime, const FRecordedFrame *&OutFirst, const FRecordedFrame *&OutSecond) const
Definition RecordedTransformTrack.h:395
bool GetWasActiveInWindow(int32 InIndex, float InBeginTime, float InEndTime) const
Definition RecordedTransformTrack.h:474
FTransform GetTransformAtTime(int32 InIndex, float InTime) const
Definition RecordedTransformTrack.h:426
const FRecordedFrame * FindRecordedFrame(float InTime, float InTolerance=UE_SMALL_NUMBER) const
Definition RecordedTransformTrack.h:343
FVector GetLinearVelocityAtTime(int32 InIndex, float InTime, float SampleWidth=1.0f/120.0f) const
Definition RecordedTransformTrack.h:509
FRecordedFrame * FindRecordedFrame(float InTime, float InTolerance=UE_SMALL_NUMBER)
Definition RecordedTransformTrack.h:359
bool IsTimeValid(float InTime) const
Definition RecordedTransformTrack.h:287
FVector GetAngularVelocityAtTime(int32 InIndex, float InTime, float SampleWidth=1.0f/120.0f) const
Definition RecordedTransformTrack.h:530
int32 FindLastKeyBefore(float InTime) const
Definition RecordedTransformTrack.h:304
Definition RecordedTransformTrack.h:104
Definition RecordedTransformTrack.h:15
FSolverCollisionData(FVector InLocation, FVector InAccumulatedImpulse, FVector InNormal, FVector InVelocity1, FVector InVelocity2, FVector InAngularVelocity1, FVector InAngularVelocity2, float InMass1, float InMass2, int32 InParticleIndex, int32 InLevelsetIndex, int32 InParticleIndexMesh, int32 InLevelsetIndexMesh)
Definition RecordedTransformTrack.h:34
Definition RecordedTransformTrack.h:137
FSolverTrailingData(FVector InLocation, FVector InVelocity, FVector InAngularVelocity, float InMass, int32 InParticleIndex, int32 InParticleIndexMesh)
Definition RecordedTransformTrack.h:149
friend bool operator==(const FSolverTrailingData &A, const FSolverTrailingData &B)
Definition RecordedTransformTrack.h:186
static CORE_API const TVector< double > ZeroVector
Definition Vector.h:79
double FReal
Definition Vector.h:55