UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
BonePose.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"
6#include "Stats/Stats.h"
7#include "BoneIndices.h"
10#include "Animation/AnimStats.h"
11#include "Misc/Base64.h"
12#include "Animation/Skeleton.h"
13#include "BoneContainer.h"
14
32
33// Comparison Operator for Sorting.
35{
36 inline bool operator()(const FBoneTransform& A, const FBoneTransform& B) const
37 {
38 return A.BoneIndex < B.BoneIndex;
39 }
40};
41
42
43template<class BoneIndexType, typename InAllocator>
45{
46public:
47 inline void InitBones(int32 NumBones) { Bones.Reset(NumBones); Bones.AddUninitialized(NumBones); }
48
49 inline int32 GetNumBones() const { return Bones.Num(); }
50
51 inline bool IsValidIndex(const BoneIndexType& BoneIndex) const
52 {
53 return Bones.IsValidIndex(BoneIndex.GetInt());
54 }
55
56 inline FTransform& operator[](const BoneIndexType& BoneIndex)
57 {
58 return Bones[BoneIndex.GetInt()];
59 }
60
61 inline const FTransform& operator[] (const BoneIndexType& BoneIndex) const
62 {
63 return Bones[BoneIndex.GetInt()];
64 }
65
70
71 //Bone Index Iteration
72 template<typename PoseType, typename IterType>
74 {
75 const PoseType& Pose;
76
78
79 IterType begin() { return Pose.MakeBeginIter(); }
80 IterType end() { return Pose.MakeEndIter(); }
81 };
82
83 template<typename PoseType, typename IterType>
85 {
86 const PoseType& Pose;
87
89
90 IterType begin() { return Pose.MakeBeginIterReverse(); }
91 IterType end() { return Pose.MakeEndIterReverse(); }
92 };
93
95
97
98protected:
100};
101
102template <typename InAllocator>
103struct FBaseCompactPose : FBasePose<FCompactPoseBoneIndex, InAllocator>
104{
105public:
106
108 : BoneContainer(nullptr)
109 {}
110
113 //--------------------------------------------------------------------------
114 //Bone Index Iteration
117
119 {
120 return RangedForBoneIndexFwd(*this);
121 }
122
124 {
125 return RangedForBoneIndexBwd(*this);
126 }
127
129
131
133
135 //--------------------------------------------------------------------------
136
138 {
140 return *BoneContainer;
141 }
142
148
155
161
163 {
164 SetBoneContainer(SrcPose.BoneContainer);
165 this->Bones = SrcPose.Bones;
166 }
167
169 {
170 SetBoneContainer(SrcPose.BoneContainer);
171 this->Bones = MoveTemp(SrcPose.Bones);
172 SrcPose.BoneContainer = nullptr;
173 }
174
175 // Copy bone transform from SrcPose to this
176 template <typename OtherAllocator>
178 {
179 this->Bones = SrcPose.GetBones();
180 BoneContainer = &SrcPose.GetBoneContainer();
181 }
182
184 {
185 if (this != &SrcPose)
186 {
187 this->Bones = SrcPose.GetBones();
188 BoneContainer = &SrcPose.GetBoneContainer();
189 }
190 }
191
193 {
194 if (this != &SrcPose)
195 {
196 this->Bones = SrcPose.MoveBones();
197 BoneContainer = &SrcPose.GetBoneContainer();
198 SrcPose.BoneContainer = nullptr;
199 }
200 }
201
202 template <typename OtherAllocator>
204 {
205 // only allow if the size is same
206 // if size doesn't match, we can't guarantee the bonecontainer would work
207 // so we can't accept
208 if (this->Bones.Num() == SrcPoseBones.Num())
209 {
210 this->Bones = SrcPoseBones;
211 }
212 }
213
214 template <typename OtherAllocator>
216 {
217 // this won't work if you're copying to FBaseCompactPose without BoneContainer data
218 // you'll like to make CopyBonesTo(FBaseCompactPose<OtherAllocator>& DestPose) to fix this properly
219 // if you need bone container
220 DestPoseBones = this->Bones;
221 }
222
223 // Moves transform data out of the supplied InTransforms. InTransform will be left empty
225 {
226 this->Bones = MoveTemp(InTransforms);
227 }
228
229 // Moves transform data out of this to the supplied InTransforms. Bones will be left empty
231 {
232 InTransforms = MoveTemp(this->Bones);
233 }
234
235 void Empty()
236 {
237 BoneContainer = nullptr;
238 this->Bones.Empty();
239 }
240
241 // Sets this pose to its ref pose
246
247 // Sets this pose to the supplied BoneContainers ref pose
248 void ResetToRefPose(const FBoneContainer& RequiredBones)
249 {
250 RequiredBones.FillWithCompactRefPose(this->Bones);
251
252 this->BoneContainer = &RequiredBones;
253
254 // If retargeting is disabled, copy ref pose from Skeleton, rather than mesh.
255 // this is only used in editor and for debugging.
256 if (RequiredBones.GetDisableRetargeting())
257 {
258 checkSlow(RequiredBones.IsValid());
259 // Only do this if we have a mesh. otherwise we're not retargeting animations.
260 if (RequiredBones.GetSkeletalMeshAsset())
261 {
263
264 for (const FCompactPoseBoneIndex BoneIndex : ForEachBoneIndex())
265 {
266 const int32 SkeletonBoneIndex = GetBoneContainer().GetSkeletonIndex(BoneIndex);
267
268 // Pose bone index should always exist in Skeleton
269 checkSlow(SkeletonBoneIndex != INDEX_NONE);
270 this->Bones[BoneIndex.GetInt()] = SkeletonRefPose[SkeletonBoneIndex];
271 }
272 }
273 }
274 }
275
276 // Sets every bone transform to Identity
278 {
279 for (FTransform& Bone : this->Bones)
280 {
281 Bone.SetIdentityZeroScale();
282 }
283 }
284
285 // returns true if all bone rotations are normalized
286 bool IsNormalized() const
287 {
288 for (const FTransform& Bone : this->Bones)
289 {
290 if (!Bone.IsRotationNormalized())
291 {
292 return false;
293 }
294 }
295
296 return true;
297 }
298
299 // Returns true if any bone rotation contains NaN or Inf
300 bool ContainsNaN() const
301 {
302 for (const FTransform& Bone : this->Bones)
303 {
304 if (Bone.ContainsNaN())
305 {
306 return true;
307 }
308 }
309
310 return false;
311 }
312
313
314 // Normalizes all rotations in this pose
316 {
317 for (FTransform& Bone : this->Bones)
318 {
319 Bone.NormalizeRotation();
320 }
321 }
322
323 bool IsValid() const
324 {
325 return (BoneContainer && BoneContainer->IsValid());
326 }
327
328 // Returns the bone index for the parent bone
329 BoneIndexType GetParentBoneIndex(const BoneIndexType& BoneIndex) const
330 {
331 return GetBoneContainer().GetParentBoneIndex(BoneIndex);
332 }
333
334 // Returns the ref pose for the supplied bone
335 const FTransform& GetRefPose(const BoneIndexType& BoneIndex) const
336 {
337 return GetBoneContainer().GetRefPoseTransform(BoneIndex);
338 }
339
340protected:
341
342 //Reference to our BoneContainer
344};
345
346struct FCompactPose : public FBaseCompactPose<FAnimStackAllocator>
347{
348 // Sets every bone transform to Identity
350
351 // Normalizes all rotations in this pose
353};
354
355struct FCompactHeapPose : public FBaseCompactPose<FDefaultAllocator>
356{
357 // Sets every bone transform to Identity
359
360 // Normalizes all rotations in this pose
362};
363
364struct FMeshPose : public FBasePose<FMeshPoseBoneIndex, FDefaultAllocator>
365{
366public:
368
370 {
372 return *BoneContainer;
373 }
374
381
382 // Sets this pose to its ref pose
384
385 // Sets every bone transform to Identity
386 void ResetToIdentity();
387
388 // returns true if all bone rotations are normalized
389 bool IsNormalized() const;
390
391 // Returns true if any bone rotation contains NaN
392 bool ContainsNaN() const;
393
394
396 {
398 }
399
400protected:
401
402 //Reference to our BoneContainer
404};
405
406template<class PoseType>
408{
409 // Set up our index type based on the type of pose we are manipulating
410 typedef typename PoseType::BoneIndexType BoneIndexType;
411 typedef typename PoseType::Allocator AllocatorType;
412
413 // overriding ctor, copy, move to allow deprecations.
415 FCSPose() = default;
416 ~FCSPose() = default;
417 FCSPose(const FCSPose& Other) = default;
418 FCSPose(FCSPose&& Other) = default;
419 FCSPose& operator=(const FCSPose& Other) = default;
422
423 // Init Pose
425 {
426 Pose.SetBoneContainer(InBoneContainer);
427 Pose.ResetToRefPose();
428 ComponentSpaceFlags.Empty(Pose.GetNumBones());
429 ComponentSpaceFlags.AddZeroed(Pose.GetNumBones());
430 ComponentSpaceFlags[0] = 1;
431 }
432
433 // Init Pose
435 {
436 Pose.InitFrom(SrcPose);
437 ComponentSpaceFlags.Empty(Pose.GetNumBones());
438 ComponentSpaceFlags.AddZeroed(Pose.GetNumBones());
439 ComponentSpaceFlags[0] = 1;
440 }
441
443 {
444 Pose.InitFrom(MoveTemp(SrcPose));
445 ComponentSpaceFlags.Empty(Pose.GetNumBones());
446 ComponentSpaceFlags.AddZeroed(Pose.GetNumBones());
447 ComponentSpaceFlags[0] = 1;
448 }
449
450 // Copy Pose
451 template <typename OtherPoseType>
453 {
454 Pose.CopyBonesFrom(SrcPose.GetPose());
455 ComponentSpaceFlags = SrcPose.GetComponentSpaceFlags();
456 }
457
459 {
460 Pose.CopyAndAssignBoneContainer(NewBoneContainer);
461 }
462
463 void Empty()
464 {
465 Pose.Empty();
466 ComponentSpaceFlags.Empty();
467
470 BoneMask.Empty();
472 }
473
474 const PoseType& GetPose() const { return Pose; }
476
477 // Get transform for supplied bone in local space
479
480 // Get Transform for supplied bone in component space
482
483 // Set the transform for the supplied bone
484 void SetComponentSpaceTransform(BoneIndexType BoneIndex, const FTransform& NewTransform);
485
486 // Calculate the component space transform for the supplied bone
488
493
500
510
520
529
542protected:
544
545 // Flags to track each bones current state (0 means local pose, 1 means component space pose)
547
548 UE_DEPRECATED(5.7, "Property no longer required. We now allocate it via TMemStackAllocator directly.")
550
553};
554
555template<class PoseType>
557{
558 checkSlow(Pose.IsValid());
559 check(Pose.IsValidIndex(BoneIndex));
560
561 // if evaluated, calculate it
562 if (ComponentSpaceFlags[BoneIndex])
563 {
564 const BoneIndexType ParentIndex = Pose.GetParentBoneIndex(BoneIndex);
565
566 if (ParentIndex != INDEX_NONE)
567 {
568 const FTransform& ParentTransform = GetComponentSpaceTransform(ParentIndex);
569 const FTransform& BoneTransform = Pose[BoneIndex];
570 // calculate local space
571 return BoneTransform.GetRelativeTransform(ParentTransform);
572 }
573 }
574
575 return Pose[BoneIndex];
576}
577
578template<class PoseType>
580{
581 checkSlow(Pose.IsValid());
582 check(Pose.IsValidIndex(BoneIndex)); // Invalid index supplied. If this came from an FBoneReference make sure you are
583 // handling lod changes properly. (for instance: if on an anim node initialize the reference in CacheBones)
584
585 check(!Pose[BoneIndex].ContainsNaN());
586 // if not evaluate, calculate it
587 if (ComponentSpaceFlags[BoneIndex] == 0)
588 {
590 }
591 check(!Pose[BoneIndex].ContainsNaN());
592 return Pose[BoneIndex];
593}
594
595template<class PoseType>
597{
598 checkSlow(Pose.IsValid());
599 check(Pose.IsValidIndex(BoneIndex));
600
601 // this one forcefully sets component space transform
602 Pose[BoneIndex] = NewTransform;
603 ComponentSpaceFlags[BoneIndex] = 1;
604}
605
606template<class PoseType>
608{
609 checkSlow(Pose.IsValid());
610 check(ComponentSpaceFlags[BoneIndex] == 0);
611
612 FMemMark Mark(FMemStack::Get());
615 BoneIndexStack.Add(BoneIndex); //Add a dummy index to avoid last element checks in the loop
616
617 do
618 {
619 // root is already verified, so root should not come here
620 // check AllocateLocalPoses
621 const BoneIndexType ParentIndex = Pose.GetParentBoneIndex(BoneIndex);
622
623 // if Parent already has been calculated, use it
624 if (ComponentSpaceFlags[ParentIndex] == 0)
625 {
626 BoneIndexStack.Add(BoneIndex);
627 BoneIndex = ParentIndex;
628 continue;
629 }
630
631 // current Bones(Index) should contain LocalPoses.
632 FTransform& Bone = Pose[BoneIndex];
633 FTransform& ParentBone = Pose[ParentIndex];
634
635 checkf(!Bone.ContainsNaN(), TEXT("Pose[%d] contains NaN: %s\nBase64: %s"),
636 BoneIndex.GetInt(),
637 *Bone.ToString(),
638 *FBase64::Encode(reinterpret_cast<const uint8*>(&Bone), sizeof(FTransform))
639 );
640
641 checkf(!ParentBone.ContainsNaN(), TEXT("Pose[%d] contains NaN: %s\nBase64: %s"),
642 ParentIndex.GetInt(),
644 *FBase64::Encode(reinterpret_cast<const uint8*>(&ParentBone), sizeof(FTransform))
645 );
646
647 FTransform ComponentTransform = Bone * ParentBone;
648 if (ComponentTransform.ContainsNaN())
649 {
650 // We've failed, output as much info as we can....
651 // Added for Jira UE-55511
652 auto BoolToStr = [](const bool& bValue) { return bValue ? TEXT("true") : TEXT("false"); };
653
654 const TCHAR* BoneHasNaN = BoolToStr(Bone.ContainsNaN());
655 const TCHAR* ParentHasNaN = BoolToStr(ParentBone.ContainsNaN());
656 FString ErrorMsg = FString(TEXT("NaN created in during FTransform Multiplication\n"));
657 ErrorMsg += FString::Format(TEXT("\tBoneIndex {0} : ParentBoneIndex {1} BoneTransformNaN={2} : ParentTransformNaN={3}\n"), { BoneIndex.GetInt(), ParentIndex.GetInt(), BoneHasNaN, ParentHasNaN });
658 ErrorMsg += FString::Format(TEXT("\tBone {0}\n"), { Bone.ToString() });
659 ErrorMsg += FString::Format(TEXT("\tParent {0}\n"), { ParentBone.ToString() });
660 ErrorMsg += FString::Format(TEXT("\tResult {0}\n"), { ComponentTransform.ToString() });
661 ErrorMsg += FString::Format(TEXT("\tBone B64 {0}\n"), { FBase64::Encode((uint8*)&Bone, sizeof(FTransform)) });
662 ErrorMsg += FString::Format(TEXT("\tParent B64 {0}\n"), { FBase64::Encode((uint8*)&ParentBone, sizeof(FTransform)) });
663 ErrorMsg += FString::Format(TEXT("\tResult B64 {0}\n"), { FBase64::Encode((uint8*)&ComponentTransform, sizeof(FTransform)) });
664 checkf(false, TEXT("Error during CalculateComponentSpaceTransform\n%s"), *ErrorMsg); // Failed during multiplication
665 }
666 Bone = ComponentTransform;
668
669 checkf(!Bone.ContainsNaN(), TEXT("Normalized ComponentTransform for Pose[%d] contains NaN: %s\nBase64: %s"),
670 BoneIndex.GetInt(),
671 *Bone.ToString(),
672 *FBase64::Encode(reinterpret_cast<const uint8*>(&Bone), sizeof(FTransform))
673 );
674
675 ComponentSpaceFlags[BoneIndex] = 1;
676
677 BoneIndex = BoneIndexStack.Pop(EAllowShrinking::No);
678 } while (BoneIndexStack.Num());
679}
680
681template<class PoseType>
683{
684 checkSlow(Pose.IsValid());
685
686 // If BoneTransform is in Component Space, then convert it.
687 // Never convert Root to Local Space.
688 if (!BoneIndex.IsRootBone() && ComponentSpaceFlags[BoneIndex] == 1)
689 {
690 const BoneIndexType ParentIndex = Pose.GetParentBoneIndex(BoneIndex);
691
692 // Verify that our Parent is also in Component Space. That should always be the case.
693 check(ComponentSpaceFlags[ParentIndex] == 1);
694
695 // Convert to local space.
696 Pose[BoneIndex].SetToRelativeTransform(Pose[ParentIndex]);
697 ComponentSpaceFlags[BoneIndex] = 0;
698 }
699}
700
701template<class PoseType>
703{
704 checkSlow(Pose.IsValid());
705
706 FMemMark Mark(FMemStack::Get());
708 StackBonesToConvert.Reserve(BoneTransforms.Num());
709
710 // Minimum bone index, we don't need to look at bones prior to this in the pose
711 const int32 MinIndex = BoneTransforms[0].BoneIndex.GetInt();
712
713 // Add BoneTransforms indices if they're in component space
714 for(const FBoneTransform& Transform : BoneTransforms)
715 {
716 if(ComponentSpaceFlags[Transform.BoneIndex] == 1)
717 {
718 StackBonesToConvert.Add(Transform.BoneIndex);
719 }
720 }
721
722 // Store the beginning of the child transforms, below we don't need to convert any bone added
723 // from BoneTransforms because they're about to be overwritten
725
728
729 // Add child bones if they're in component space
730 for(; Iter != EndIter; ++Iter)
731 {
732 const FCompactPoseBoneIndex BoneIndex = *Iter;
733 const FCompactPoseBoneIndex ParentIndex = Pose.GetParentBoneIndex(BoneIndex);
734
735 if(ComponentSpaceFlags[BoneIndex] == 1 && StackBonesToConvert.Contains(ParentIndex))
736 {
737 StackBonesToConvert.AddUnique(BoneIndex);
738 }
739 }
740
741 // Convert the bones, we walk backwards to process children first, the pose iteration above is sorted
742 // so we know we already have the right order. We also stop when we get to the bones contained in
743 // BoneTransforms because we're about to overwrite them anyway
745 for(int32 Idx = NumToConvert - 1; Idx >= FirstChildTransform; --Idx)
746 {
748 }
749
750 // Finally copy our Component Space transforms
751 for (const FBoneTransform& BoneTransform : BoneTransforms)
752 {
754
755 // Make sure our BoneTransforms were in Component Space in the first place, before we overwrite them
756 // Only check their parent to do minimal work needed.
757 const FCompactPoseBoneIndex ParentBoneIndex = Pose.GetParentBoneIndex(BoneIndex);
758 if (ParentBoneIndex != INDEX_NONE && ComponentSpaceFlags[ParentBoneIndex] == 0)
759 {
760 CalculateComponentSpaceTransform(ParentBoneIndex);
761 }
762
763 // Set new Component Space transform.
764 SetComponentSpaceTransform(BoneIndex, BoneTransform.Transform);
765 }
766}
767
768template<class PoseType>
770{
771 // if Alpha is small enough, skip
773 {
774 return;
775 }
776
777#if DO_CHECK
778 if (BoneTransforms.Num() > 0)
779 {
780 FCompactPoseBoneIndex LastIndex(BoneTransforms[0].BoneIndex);
781 // Make sure bones are sorted in "Parents before Children" order.
782 for (int32 I = 1; I < BoneTransforms.Num(); ++I)
783 {
784 check(BoneTransforms[I].BoneIndex >= LastIndex);
785 LastIndex = BoneTransforms[I].BoneIndex;
786 }
787 }
788#endif
789
790 // If we are not doing any blending, do a faster path.
791 // Set transforms directly in Component Space. But still refresh children.
792 if (Alpha >= 1.f - ZERO_ANIMWEIGHT_THRESH)
793 {
794 SafeSetCSBoneTransforms(BoneTransforms);
795 }
796 // Slower blending path.
797 else
798 {
799 // Bone Mask to keep track of which bones have to be converted to local space.
800 // This is basically BoneTransforms bones and their children.
801 FMemMark Mark(FMemStack::Get());
803 StackBoneMask.AddZeroed(Pose.GetNumBones());
804
806 LocalBoneTransforms.SetNumUninitialized(BoneTransforms.Num());
807
808 // First, save the current local-space poses for the modified bones
809 for (int32 Index = 0; Index < BoneTransforms.Num(); Index++)
810 {
811 const BoneIndexType BoneIndex = BoneTransforms[Index].BoneIndex;
812
813 // save current local pose - we will blend it back in later
814 LocalBoneTransforms[Index].Transform = GetLocalSpaceTransform(BoneIndex);
815 LocalBoneTransforms[Index].BoneIndex = BoneIndex;
816
817 StackBoneMask[BoneIndex] = 1;
818 }
819
820 // Next, update the pose as if Alpha = 1.0
821 SafeSetCSBoneTransforms(BoneTransforms);
822
823 // Then, convert MeshPose Bones from BoneTransforms list, and their children, to local space if they are not already.
824 for (const BoneIndexType BoneIndex : Pose.ForEachBoneIndex())
825 {
826 const BoneIndexType ParentIndex = Pose.GetParentBoneIndex(BoneIndex);
827 // Propagate our BoneMask to children.
828 if (ParentIndex != INDEX_NONE)
829 {
830 StackBoneMask[BoneIndex] |= StackBoneMask[ParentIndex];
831 }
832 }
833
834 for (const BoneIndexType BoneIndex : Pose.ForEachBoneIndexReverse())
835 {
836 if (!BoneIndex.IsRootBone())
837 {
838 // If this bone has to be converted to Local Space...
839 if (StackBoneMask[BoneIndex] != 0)
840 {
841 // .. And is not currently in Local Space, then convert it.
842 ConvertBoneToLocalSpace(BoneIndex);
843 }
844 }
845 }
846
847 // Lastly, do the blending in local space.
848 for (int32 Index = 0; Index < LocalBoneTransforms.Num(); Index++)
849 {
851 // Make sure this transform is in local space, because we are writing a local space one to it.
852 // If we are not in local space, this could mean trouble for our children.
853 check((ComponentSpaceFlags[BoneIndex] == 0) || (BoneIndex == 0));
854
855 // No need to normalize rotation since BlendWith() does it.
856 const float AlphaInv = 1.0f - Alpha;
857 Pose[BoneIndex].BlendWith(LocalBoneTransforms[Index].Transform, AlphaInv);
858 }
859 }
860}
861
862template<class PoseType>
864{
865 checkSlow(InPose.Pose.IsValid());
866 OutPose = InPose.Pose;
867
868 // now we need to convert back to local bases
869 // only convert back that has been converted to mesh base
870 // if it was local base, and if it hasn't been modified
871 // that is still okay even if parent is changed,
872 // that doesn't mean this local has to change
873 // go from child to parent since I need parent inverse to go back to local
874 // root is same, so no need to do Index == 0
876 if (InPose.ComponentSpaceFlags[RootBoneIndex])
877 {
878 OutPose[RootBoneIndex] = InPose.Pose[RootBoneIndex];
879 }
880
881 const int32 NumBones = InPose.Pose.GetNumBones();
882 for (int32 Index = NumBones - 1; Index > 0; Index--)
883 {
884 const BoneIndexType BoneIndex(Index);
885 if (InPose.ComponentSpaceFlags[BoneIndex])
886 {
887 const BoneIndexType ParentIndex = InPose.Pose.GetParentBoneIndex(BoneIndex);
888 // ensure if parent hasn't been calculated, otherwise, this assumption is not correct
889 ensureMsgf(InPose.ComponentSpaceFlags[ParentIndex], TEXT("Parent hasn't been calculated. Please use ConvertComponentPosesToLocalPosesSafe instead"));
890
891 OutPose[BoneIndex].SetToRelativeTransform(OutPose[ParentIndex]);
892 OutPose[BoneIndex].NormalizeRotation();
893 }
894 }
895}
896
897template<class PoseType>
899{
900 checkSlow(InPose.Pose.IsValid());
901
902 const int32 NumBones = InPose.Pose.GetNumBones();
903
904 // now we need to convert back to local bases
905 // only convert back that has been converted to mesh base
906 // if it was local base, and if it hasn't been modified
907 // that is still okay even if parent is changed,
908 // that doesn't mean this local has to change
909 // go from child to parent since I need parent inverse to go back to local
910 // root is same, so no need to do Index == 0
912 if (InPose.ComponentSpaceFlags[RootBoneIndex])
913 {
914 OutPose[RootBoneIndex] = InPose.Pose[RootBoneIndex];
915 }
916
917 OutPose = MoveTemp(InPose.Pose);
918
919 for (int32 Index = NumBones - 1; Index > 0; Index--)
920 {
921 const BoneIndexType BoneIndex(Index);
922 if (InPose.ComponentSpaceFlags[BoneIndex])
923 {
924 const BoneIndexType ParentIndex = OutPose.GetParentBoneIndex(BoneIndex);
925
926 // ensure if parent hasn't been calculated, otherwise, this assumption is not correct
927 // Pose has moved, but ComponentSpaceFlags should be safe here
928 ensureMsgf(InPose.ComponentSpaceFlags[ParentIndex], TEXT("Parent hasn't been calculated. Please use ConvertComponentPosesToLocalPosesSafe instead"));
929
930 OutPose[BoneIndex].SetToRelativeTransform(OutPose[ParentIndex]);
931 OutPose[BoneIndex].NormalizeRotation();
932 }
933 }
934}
935
936template<class PoseType>
938{
939 checkSlow(InPose.Pose.IsValid());
940
941 const int32 NumBones = InPose.Pose.GetNumBones();
942
943 // now we need to convert back to local bases
944 // only convert back that has been converted to mesh base
945 // if it was local base, and if it hasn't been modified
946 // that is still okay even if parent is changed,
947 // that doesn't mean this local has to change
948 // go from child to parent since I need parent inverse to go back to local
949 // root is same, so no need to do Index == 0
951 if (InPose.ComponentSpaceFlags[RootBoneIndex])
952 {
953 OutPose[RootBoneIndex] = InPose.Pose[RootBoneIndex];
954 }
955
956
957 for (int32 Index = NumBones - 1; Index > 0; Index--)
958 {
959 const BoneIndexType BoneIndex(Index);
960 if (InPose.ComponentSpaceFlags[BoneIndex])
961 {
962 const BoneIndexType ParentIndex = OutPose.GetParentBoneIndex(BoneIndex);
963
964 // if parent is local space, we have to calculate parent
965 if (!InPose.ComponentSpaceFlags[ParentIndex])
966 {
967 // if I'm calculated, but not parent, update parent
968 InPose.CalculateComponentSpaceTransform(ParentIndex);
969 }
970
971 OutPose[BoneIndex] = InPose.Pose[BoneIndex];
972 OutPose[BoneIndex].SetToRelativeTransform(InPose.Pose[ParentIndex]);
973 OutPose[BoneIndex].NormalizeRotation();
974 }
975 }
976}
977
978// Populate InOutPose based on raw animation data.
979UE_DEPRECATED(5.0, "BuildPoseFromRawData has been deprecated, use BuildPoseFromRawData signature with RetargetTransforms parameter")
984 float InTime,
985 EAnimInterpolationType Interpolation,
986 int32 NumFrames,
987 float SequenceLength,
988 FName RetargetSource,
990);
991
992UE_DEPRECATED(5.0, "BuildPoseFromRawData has been deprecated, use UE::Anim::BuildPoseFromModel")
997 float InTime,
998 EAnimInterpolationType Interpolation,
999 int32 NumFrames,
1000 float SequenceLength,
1001 FName SourceName,
1002 const TArray<FTransform>& RetargetTransforms,
1003 const TMap<int32, const FTransformCurve*>* AdditiveBoneTransformCurves = nullptr
1004 );
bool ContainsNaN(const TArray< FBoneTransform > &BoneTransforms)
Definition AnimNode_SkeletalControlBase.cpp:119
EAnimInterpolationType
Definition AnimTypes.h:689
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
ENGINE_API void BuildPoseFromRawData(const TArray< FRawAnimSequenceTrack > &InAnimationData, const TArray< struct FTrackToSkeletonMap > &TrackToSkeletonMapTable, FCompactPose &InOutPose, float InTime, EAnimInterpolationType Interpolation, int32 NumFrames, float SequenceLength, FName RetargetSource, const TMap< int32, const struct FTransformCurve * > *AdditiveBoneTransformCurves=nullptr)
Definition BonePose.cpp:316
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
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 PRAGMA_ENABLE_DEPRECATION_WARNINGS
Definition GenericPlatformCompilerPreSetup.h:12
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
Definition GenericPlatformCompilerPreSetup.h:8
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
#define ZERO_ANIMWEIGHT_THRESH
Definition VectorRegister.h:133
uint8_t uint8
Definition binka_ue_file_header.h:8
Definition MemStack.h:506
Definition NameTypes.h:617
CORE_API FString ToString() const
Definition UnrealNames.cpp:3537
Definition ArrayView.h:139
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void SetNumUninitialized(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2369
void Empty(SizeType Slack=0)
Definition Array.h:2273
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition UnrealString.h.inl:34
Definition MemStack.h:391
static FORCEINLINE FMemStack & Get()
Definition ThreadSingleton.h:101
Definition CustomBoneIndexArray.h:43
ENGINE_API const TArray< FTransform > & GetRefLocalPoses(FName RetargetSource=NAME_None) const
Definition Skeleton.cpp:1089
Definition AdvancedWidgetsModule.cpp:13
U16 Index
Definition radfft.cpp:71
static CORE_API FString Encode(const FString &Source, EBase64Mode Mode=EBase64Mode::Standard)
Definition Base64.cpp:53
Definition BonePose.h:104
void InitFrom(const FBaseCompactPose &SrcPose)
Definition BonePose.h:162
RangedForBoneIndexBwd ForEachBoneIndexReverse() const
Definition BonePose.h:123
void MoveBonesFrom(FBaseCompactPose< Allocator > &SrcPose)
Definition BonePose.h:192
void CopyAndAssignBoneContainer(FBoneContainer &NewBoneContainer)
Definition BonePose.h:156
const FBoneContainer * BoneContainer
Definition BonePose.h:343
FCompactPoseBoneIndex BoneIndexType
Definition BonePose.h:111
bool IsNormalized() const
Definition BonePose.h:286
void MoveBonesTo(TArray< FTransform, Allocator > &InTransforms)
Definition BonePose.h:230
FBasePose< FCompactPoseBoneIndex, Allocator >::template FRangedForSupport< FBaseCompactPose, FCompactPoseBoneIndexIterator > RangedForBoneIndexFwd
Definition BonePose.h:115
void ResetToRefPose()
Definition BonePose.h:242
const FTransform & GetRefPose(const BoneIndexType &BoneIndex) const
Definition BonePose.h:335
void CopyBonesFrom(const FBaseCompactPose< OtherAllocator > &SrcPose)
Definition BonePose.h:177
FCompactPoseBoneIndexReverseIterator MakeBeginIterReverse() const
Definition BonePose.h:132
FCompactPoseBoneIndexIterator MakeEndIter() const
Definition BonePose.h:130
FBoneContainer & GetBoneContainer()
Definition BonePose.h:143
BoneIndexType GetParentBoneIndex(const BoneIndexType &BoneIndex) const
Definition BonePose.h:329
FBaseCompactPose()
Definition BonePose.h:107
bool IsValid() const
Definition BonePose.h:323
bool ContainsNaN() const
Definition BonePose.h:300
void CopyBonesFrom(const TArray< FTransform, OtherAllocator > &SrcPoseBones)
Definition BonePose.h:203
void NormalizeRotations()
Definition BonePose.h:315
void InitFrom(FBaseCompactPose &&SrcPose)
Definition BonePose.h:168
InAllocator Allocator
Definition BonePose.h:112
void ResetToAdditiveIdentity()
Definition BonePose.h:277
void CopyBonesTo(TArray< FTransform, OtherAllocator > &DestPoseBones) const
Definition BonePose.h:215
void MoveBonesFrom(TArray< FTransform, Allocator > &&InTransforms)
Definition BonePose.h:224
FCompactPoseBoneIndexIterator MakeBeginIter() const
Definition BonePose.h:128
FBasePose< FCompactPoseBoneIndex, Allocator >::template FRangedForReverseSupport< FBaseCompactPose, FCompactPoseBoneIndexReverseIterator > RangedForBoneIndexBwd
Definition BonePose.h:116
void Empty()
Definition BonePose.h:235
void ResetToRefPose(const FBoneContainer &RequiredBones)
Definition BonePose.h:248
void CopyBonesFrom(const FBaseCompactPose< Allocator > &SrcPose)
Definition BonePose.h:183
void SetBoneContainer(const FBoneContainer *InBoneContainer)
Definition BonePose.h:149
const FBoneContainer & GetBoneContainer() const
Definition BonePose.h:137
FCompactPoseBoneIndexReverseIterator MakeEndIterReverse() const
Definition BonePose.h:134
RangedForBoneIndexFwd ForEachBoneIndex() const
Definition BonePose.h:118
Definition BonePose.h:85
IterType end()
Definition BonePose.h:91
IterType begin()
Definition BonePose.h:90
FRangedForReverseSupport(const PoseType &InPose)
Definition BonePose.h:88
const PoseType & Pose
Definition BonePose.h:86
Definition BonePose.h:74
FRangedForSupport(const PoseType &InPose)
Definition BonePose.h:77
const PoseType & Pose
Definition BonePose.h:75
IterType end()
Definition BonePose.h:80
IterType begin()
Definition BonePose.h:79
Definition BonePose.h:45
FTransform & operator[](const BoneIndexType &BoneIndex)
Definition BonePose.h:56
TArray< FTransform, InAllocator > Bones
Definition BonePose.h:99
bool IsValidIndex(const BoneIndexType &BoneIndex) const
Definition BonePose.h:51
TArrayView< FTransform > GetMutableBones()
Definition BonePose.h:66
const TArray< FTransform, InAllocator > & GetBones() const
Definition BonePose.h:94
int32 GetNumBones() const
Definition BonePose.h:49
void InitBones(int32 NumBones)
Definition BonePose.h:47
TArray< FTransform, InAllocator > && MoveBones()
Definition BonePose.h:96
Definition BoneContainer.h:192
const bool IsValid() const
Definition BoneContainer.h:270
const TArray< FBoneIndexType > & GetBoneIndicesArray() const
Definition BoneContainer.h:342
const int32 GetNumBones() const
Definition BoneContainer.h:408
bool GetDisableRetargeting() const
Definition BoneContainer.h:309
USkeletalMesh * GetSkeletalMeshAsset() const
Definition BoneContainer.h:287
ENGINE_API int32 GetParentBoneIndex(const int32 BoneIndex) const
Definition BoneContainer.cpp:512
USkeleton * GetSkeletonAsset(bool bEvenIfUnreachable=false) const
Definition BoneContainer.h:293
int32 GetSkeletonIndex(const FCompactPoseBoneIndex &BoneIndex) const
Definition BoneContainer.h:593
void FillWithCompactRefPose(ArrayType &OutTransforms) const
Definition BoneContainer.h:373
const FTransform & GetRefPoseTransform(const FCompactPoseBoneIndex &BoneIndex) const
Definition BoneContainer.h:386
int32 BoneIndex
Definition BoneIndices.h:27
int32 GetInt() const
Definition BoneIndices.h:14
Definition BonePose.h:16
FBoneTransform(FCompactPoseBoneIndex InBoneIndex, const FTransform &InTransform)
Definition BonePose.h:27
FBoneTransform()
Definition BonePose.h:23
FCompactPoseBoneIndex BoneIndex
Definition BonePose.h:18
FTransform Transform
Definition BonePose.h:21
Definition BonePose.h:408
static void ConvertComponentPosesToLocalPoses(FCSPose< PoseType > &&InPose, PoseType &OutPose)
Definition BonePose.h:898
PRAGMA_ENABLE_DEPRECATION_WARNINGS void InitPose(const FBoneContainer *InBoneContainer)
Definition BonePose.h:424
const TCustomBoneIndexArray< uint8, BoneIndexType, AllocatorType > & GetComponentSpaceFlags() const
Definition BonePose.h:475
FTransform GetLocalSpaceTransform(BoneIndexType BoneIndex)
Definition BonePose.h:556
TCustomBoneIndexArray< uint8, BoneIndexType, AllocatorType > BoneMask
Definition BonePose.h:549
void InitPose(const PoseType &SrcPose)
Definition BonePose.h:434
const PoseType & GetPose() const
Definition BonePose.h:474
PoseType Pose
Definition BonePose.h:543
TCustomBoneIndexArray< uint8, BoneIndexType, AllocatorType > ComponentSpaceFlags
Definition BonePose.h:546
void SafeSetCSBoneTransforms(TConstArrayView< FBoneTransform > BoneTransforms)
Definition BonePose.h:702
TArray< FCompactPoseBoneIndex, AllocatorType > BonesToConvert
Definition BonePose.h:552
void CopyPose(const OtherPoseType &SrcPose)
Definition BonePose.h:452
~FCSPose()=default
void Empty()
Definition BonePose.h:463
static void ConvertComponentPosesToLocalPosesSafe(FCSPose< PoseType > &InPose, PoseType &OutPose)
Definition BonePose.h:937
void SetComponentSpaceTransform(BoneIndexType BoneIndex, const FTransform &NewTransform)
Definition BonePose.h:596
void CopyAndAssignBoneContainer(FBoneContainer &NewBoneContainer)
Definition BonePose.h:458
void ConvertBoneToLocalSpace(BoneIndexType BoneIndex)
Definition BonePose.h:682
void CalculateComponentSpaceTransform(BoneIndexType BoneIndex)
Definition BonePose.h:607
FCSPose(FCSPose &&Other)=default
FCSPose & operator=(FCSPose &&Other)=default
FCSPose & operator=(const FCSPose &Other)=default
FCSPose(const FCSPose &Other)=default
void InitPose(PoseType &&SrcPose)
Definition BonePose.h:442
PRAGMA_DISABLE_DEPRECATION_WARNINGS FCSPose()=default
PoseType::Allocator AllocatorType
Definition BonePose.h:411
const FTransform & GetComponentSpaceTransform(BoneIndexType BoneIndex)
Definition BonePose.h:579
static void ConvertComponentPosesToLocalPoses(const FCSPose< PoseType > &InPose, PoseType &OutPose)
Definition BonePose.h:863
void LocalBlendCSBoneTransforms(TConstArrayView< FBoneTransform > BoneTransforms, float Alpha)
Definition BonePose.h:769
PoseType::BoneIndexType BoneIndexType
Definition BonePose.h:410
Definition BonePose.h:356
ENGINE_API void ResetToAdditiveIdentity()
Definition BonePose.cpp:108
ENGINE_API void NormalizeRotations()
Definition BonePose.cpp:82
Definition BoneContainer.h:140
Definition BoneContainer.h:153
Definition BoneIndices.h:63
Definition BonePose.h:347
ENGINE_API void ResetToAdditiveIdentity()
Definition BonePose.cpp:56
ENGINE_API void NormalizeRotations()
Definition BonePose.cpp:30
Definition BonePose.h:35
bool operator()(const FBoneTransform &A, const FBoneTransform &B) const
Definition BonePose.h:36
Definition BoneIndices.h:71
Definition BonePose.h:365
const FBoneContainer & GetBoneContainer() const
Definition BonePose.h:369
void SetBoneContainer(const FBoneContainer *InBoneContainer)
Definition BonePose.h:375
FMeshPoseBoneIndex BoneIndexType
Definition BonePose.h:367
bool ContainsNaN() const
Definition BonePose.cpp:144
BoneIndexType GetParentBone(const BoneIndexType &BoneIndex)
Definition BonePose.h:395
ENGINE_API void ResetToRefPose()
Definition BonePose.cpp:133
const FBoneContainer * BoneContainer
Definition BonePose.h:403
bool IsNormalized() const
Definition BonePose.cpp:159
void ResetToIdentity()
Definition BonePose.cpp:138
Definition AnimTypes.h:853
Definition ResourceArray.h:31
Definition AnimTypes.h:822
Definition AnimCurveTypes.h:308
bool ContainsNaN() const
Definition TransformNonVectorized.h:598
CORE_API TTransform< T > GetRelativeTransform(const TTransform< T > &Other) const
Definition Transform.cpp:169
CORE_API FString ToString() const
Definition Transform.cpp:50
void NormalizeRotation()
Definition TransformNonVectorized.h:1057