2021-05-12 07:33:41 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "AnimPose.h"
2022-08-30 23:03:03 -04:00
2021-05-12 16:49:24 -04:00
# include "Animation/AnimBlueprint.h"
# include "Animation/AnimBlueprintGeneratedClass.h"
2022-08-30 23:03:03 -04:00
# include "Animation/AnimCurveTypes.h"
# include "Animation/AnimInstance.h"
# include "Animation/AnimNode_LinkedInputPose.h"
2021-09-07 05:02:01 -04:00
# include "Animation/AnimSequence.h"
2022-08-30 23:03:03 -04:00
# include "Animation/AnimSequenceBase.h"
# include "Animation/AnimationAsset.h"
# include "Animation/AttributesRuntime.h"
# include "Animation/Skeleton.h"
# include "Animation/SmartName.h"
# include "AnimationBlueprintLibrary.h"
# include "AnimationRuntime.h"
# include "BoneContainer.h"
# include "BoneIndices.h"
# include "BonePose.h"
# include "Components/SkeletalMeshComponent.h"
# include "Containers/BitArray.h"
# include "Containers/UnrealString.h"
# include "CoreTypes.h"
# include "Engine/SkeletalMesh.h"
# include "HAL/PlatformCrt.h"
# include "Logging/LogCategory.h"
# include "Logging/LogMacros.h"
# include "Math/TransformVectorized.h"
# include "Misc/AssertionMacros.h"
# include "Misc/MemStack.h"
# include "PreviewScene.h"
# include "ReferenceSkeleton.h"
# include "Templates/Casts.h"
# include "Trace/Detail/Channel.h"
# include "UObject/Object.h"
2021-05-12 07:33:41 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogAnimationPoseScripting , Verbose , All ) ;
void FAnimPose : : Init ( const FBoneContainer & InBoneContainer )
{
Reset ( ) ;
2022-01-04 11:25:06 -05:00
2022-04-06 10:45:20 -04:00
const FReferenceSkeleton & RefSkeleton = InBoneContainer . GetSkeletonAsset ( ) - > GetReferenceSkeleton ( ) ;
2022-01-04 11:25:06 -05:00
2022-04-06 10:45:20 -04:00
for ( const FBoneIndexType BoneIndex : InBoneContainer . GetBoneIndicesArray ( ) )
2021-05-12 07:33:41 -04:00
{
2021-05-12 12:09:21 -04:00
const FCompactPoseBoneIndex CompactIndex ( BoneIndex ) ;
2022-04-06 10:45:20 -04:00
const FCompactPoseBoneIndex CompactParentIndex = InBoneContainer . GetParentBoneIndex ( CompactIndex ) ;
2021-05-12 07:33:41 -04:00
2022-04-06 10:45:20 -04:00
const int32 SkeletonBoneIndex = InBoneContainer . GetSkeletonIndex ( CompactIndex ) ;
2021-05-12 12:09:21 -04:00
if ( SkeletonBoneIndex ! = INDEX_NONE )
{
2022-04-06 10:45:20 -04:00
const int32 ParentBoneIndex = CompactParentIndex . GetInt ( ) ! = INDEX_NONE ? InBoneContainer . GetSkeletonIndex ( CompactParentIndex ) : INDEX_NONE ;
2021-05-12 07:33:41 -04:00
2021-05-12 12:09:21 -04:00
BoneIndices . Add ( SkeletonBoneIndex ) ;
ParentBoneIndices . Add ( ParentBoneIndex ) ;
BoneNames . Add ( RefSkeleton . GetBoneName ( SkeletonBoneIndex ) ) ;
2022-04-06 10:45:20 -04:00
RefLocalSpacePoses . Add ( InBoneContainer . GetRefPoseTransform ( FCompactPoseBoneIndex ( BoneIndex ) ) ) ;
2021-05-12 12:09:21 -04:00
}
2021-05-12 07:33:41 -04:00
}
TArray < bool > Processed ;
Processed . SetNumZeroed ( BoneNames . Num ( ) ) ;
RefWorldSpacePoses . SetNum ( BoneNames . Num ( ) ) ;
for ( int32 EntryIndex = 0 ; EntryIndex < BoneNames . Num ( ) ; + + EntryIndex )
{
const int32 ParentIndex = ParentBoneIndices [ EntryIndex ] ;
const int32 TransformIndex = BoneIndices . IndexOfByKey ( ParentIndex ) ;
if ( TransformIndex ! = INDEX_NONE )
{
ensure ( Processed [ TransformIndex ] ) ;
RefWorldSpacePoses [ EntryIndex ] = RefLocalSpacePoses [ EntryIndex ] * RefWorldSpacePoses [ TransformIndex ] ;
}
else
{
RefWorldSpacePoses [ EntryIndex ] = RefLocalSpacePoses [ EntryIndex ] ;
}
Processed [ EntryIndex ] = true ;
}
}
void FAnimPose : : GetPose ( FCompactPose & InOutCompactPose ) const
{
if ( IsValid ( ) )
{
for ( int32 Index = 0 ; Index < BoneNames . Num ( ) ; + + Index )
{
const FName & BoneName = BoneNames [ Index ] ;
const FCompactPoseBoneIndex PoseBoneIndex = FCompactPoseBoneIndex ( InOutCompactPose . GetBoneContainer ( ) . GetPoseBoneIndexForBoneName ( BoneName ) ) ;
if ( PoseBoneIndex ! = INDEX_NONE )
{
InOutCompactPose [ PoseBoneIndex ] = LocalSpacePoses [ Index ] ;
}
}
}
}
void FAnimPose : : SetPose ( USkeletalMeshComponent * Component )
{
if ( IsInitialized ( ) )
{
const FBoneContainer & ContextBoneContainer = Component - > GetAnimInstance ( ) - > GetRequiredBones ( ) ;
LocalSpacePoses . SetNum ( RefLocalSpacePoses . Num ( ) ) ;
TArray < FTransform > BoneSpaceTransforms = Component - > GetBoneSpaceTransforms ( ) ;
for ( const FBoneIndexType BoneIndex : ContextBoneContainer . GetBoneIndicesArray ( ) )
{
const int32 SkeletonBoneIndex = ContextBoneContainer . GetSkeletonIndex ( FCompactPoseBoneIndex ( BoneIndex ) ) ;
LocalSpacePoses [ BoneIndices . IndexOfByKey ( SkeletonBoneIndex ) ] = BoneSpaceTransforms [ BoneIndex ] ;
}
ensure ( LocalSpacePoses . Num ( ) = = RefLocalSpacePoses . Num ( ) ) ;
GenerateWorldSpaceTransforms ( ) ;
}
}
void FAnimPose : : GenerateWorldSpaceTransforms ( )
{
if ( IsPopulated ( ) )
{
TArray < bool > Processed ;
Processed . SetNumZeroed ( BoneNames . Num ( ) ) ;
WorldSpacePoses . SetNum ( BoneNames . Num ( ) ) ;
for ( int32 EntryIndex = 0 ; EntryIndex < BoneNames . Num ( ) ; + + EntryIndex )
{
const int32 ParentIndex = ParentBoneIndices [ EntryIndex ] ;
const int32 TransformIndex = BoneIndices . IndexOfByKey ( ParentIndex ) ;
if ( TransformIndex ! = INDEX_NONE )
{
ensure ( Processed [ TransformIndex ] ) ;
WorldSpacePoses [ EntryIndex ] = LocalSpacePoses [ EntryIndex ] * WorldSpacePoses [ TransformIndex ] ;
}
else
{
WorldSpacePoses [ EntryIndex ] = LocalSpacePoses [ EntryIndex ] ;
}
Processed [ EntryIndex ] = true ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Anim Pose was not previously populated " ) ) ;
}
}
2022-04-06 10:45:20 -04:00
void FAnimPose : : SetPose ( const FAnimationPoseData & PoseData )
2021-05-12 07:33:41 -04:00
{
2022-04-06 10:45:20 -04:00
const FCompactPose & CompactPose = PoseData . GetPose ( ) ;
2021-05-12 07:33:41 -04:00
if ( IsInitialized ( ) )
{
const FBoneContainer & ContextBoneContainer = CompactPose . GetBoneContainer ( ) ;
LocalSpacePoses . SetNum ( RefLocalSpacePoses . Num ( ) ) ;
for ( const FCompactPoseBoneIndex BoneIndex : CompactPose . ForEachBoneIndex ( ) )
{
const int32 SkeletonBoneIndex = ContextBoneContainer . GetSkeletonIndex ( BoneIndex ) ;
LocalSpacePoses [ BoneIndices . IndexOfByKey ( SkeletonBoneIndex ) ] = CompactPose [ BoneIndex ] ;
}
ensure ( LocalSpacePoses . Num ( ) = = RefLocalSpacePoses . Num ( ) ) ;
GenerateWorldSpaceTransforms ( ) ;
2022-04-06 10:45:20 -04:00
const FBlendedCurve & Curve = PoseData . GetCurve ( ) ;
for ( TConstSetBitIterator It ( Curve . ValidCurveWeights ) ; It ; + + It )
{
const int32 EntryIndex = It . GetIndex ( ) ;
const uint16 CurveNameUID = ( * Curve . UIDToArrayIndexLUT ) . IsValidIndex ( EntryIndex ) ? ( * Curve . UIDToArrayIndexLUT ) [ EntryIndex ] : INDEX_NONE ;
FSmartName CurveSmartName ;
const USkeleton * Skeleton = ContextBoneContainer . GetSkeletonAsset ( ) ;
if ( Skeleton - > GetSmartNameByUID ( USkeleton : : AnimCurveMappingName , CurveNameUID , CurveSmartName ) )
{
CurveNames . Add ( CurveSmartName . DisplayName ) ;
CurveValues . Add ( Curve . CurveWeights [ EntryIndex ] ) ;
}
else
{
ensureMsgf ( false , TEXT ( " Unable to find SmartName for Curve with UID %i from Skeleton %s " ) , CurveNameUID , * Skeleton - > GetPathName ( ) ) ;
}
}
2021-05-12 07:33:41 -04:00
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Anim Pose was not previously initialized " ) ) ;
}
}
void FAnimPose : : SetToRefPose ( )
{
if ( IsInitialized ( ) )
{
LocalSpacePoses = RefLocalSpacePoses ;
WorldSpacePoses = RefWorldSpacePoses ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Anim Pose was not previously initialized " ) ) ;
}
}
bool FAnimPose : : IsValid ( ) const
{
const int32 ExpectedNumBones = BoneNames . Num ( ) ;
bool bIsValid = ExpectedNumBones ! = 0 ;
bIsValid & = BoneIndices . Num ( ) = = ExpectedNumBones ;
bIsValid & = ParentBoneIndices . Num ( ) = = ExpectedNumBones ;
bIsValid & = LocalSpacePoses . Num ( ) = = ExpectedNumBones ;
bIsValid & = WorldSpacePoses . Num ( ) = = ExpectedNumBones ;
bIsValid & = RefLocalSpacePoses . Num ( ) = = ExpectedNumBones ;
bIsValid & = RefWorldSpacePoses . Num ( ) = = ExpectedNumBones ;
return bIsValid ;
}
void FAnimPose : : Reset ( )
{
BoneNames . Empty ( ) ;
BoneIndices . Empty ( ) ;
ParentBoneIndices . Empty ( ) ;
LocalSpacePoses . Empty ( ) ;
WorldSpacePoses . Empty ( ) ;
RefLocalSpacePoses . Empty ( ) ;
RefWorldSpacePoses . Empty ( ) ;
}
bool UAnimPoseExtensions : : IsValid ( const FAnimPose & Pose )
{
return Pose . IsValid ( ) ;
}
void UAnimPoseExtensions : : GetBoneNames ( const FAnimPose & Pose , TArray < FName > & Bones )
{
Bones . Append ( Pose . BoneNames ) ;
}
2022-01-04 11:25:06 -05:00
const FTransform & UAnimPoseExtensions : : GetBonePose ( const FAnimPose & Pose , FName BoneName , EAnimPoseSpaces Space /*= EAnimPoseSpaces::Local*/ )
2021-05-12 07:33:41 -04:00
{
if ( Pose . IsValid ( ) )
{
const int32 BoneIndex = Pose . BoneNames . IndexOfByKey ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
return Space = = EAnimPoseSpaces : : Local ? Pose . LocalSpacePoses [ BoneIndex ] : Pose . WorldSpacePoses [ BoneIndex ] ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " No bone with name %s was found " ) , * BoneName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Provided Pose is not valid " ) ) ;
}
return FTransform : : Identity ;
}
void UAnimPoseExtensions : : SetBonePose ( FAnimPose & Pose , FTransform Transform , FName BoneName , EAnimPoseSpaces Space /*= EAnimPoseSpaces::Local*/ )
{
if ( Pose . IsValid ( ) )
{
const int32 BoneIndex = Pose . BoneNames . IndexOfByKey ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
if ( Space = = EAnimPoseSpaces : : Local )
{
Pose . LocalSpacePoses [ BoneIndex ] = Transform ;
}
else if ( Space = = EAnimPoseSpaces : : World )
{
const int32 ParentIndex = Pose . ParentBoneIndices [ BoneIndex ] ;
const FTransform ParentTransformWS = ParentIndex ! = INDEX_NONE ? Pose . WorldSpacePoses [ ParentIndex ] : FTransform : : Identity ;
Pose . LocalSpacePoses [ BoneIndex ] = Transform . GetRelativeTransform ( ParentTransformWS ) ;
}
Pose . GenerateWorldSpaceTransforms ( ) ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " No bone with name %s was found " ) , * BoneName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Provided Pose is not valid " ) ) ;
}
}
2022-01-04 11:25:06 -05:00
const FTransform & UAnimPoseExtensions : : GetRefBonePose ( const FAnimPose & Pose , FName BoneName , EAnimPoseSpaces Space /*= EAnimPoseSpaces::Local*/ )
2021-05-12 07:33:41 -04:00
{
if ( Pose . IsValid ( ) )
{
const int32 BoneIndex = Pose . BoneNames . IndexOfByKey ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
return Space = = EAnimPoseSpaces : : Local ? Pose . RefLocalSpacePoses [ BoneIndex ] : Pose . RefWorldSpacePoses [ BoneIndex ] ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " No bone with name %s was found " ) , * BoneName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Provided Pose is not valid " ) ) ;
}
return FTransform : : Identity ;
}
FTransform UAnimPoseExtensions : : GetRelativeTransform ( const FAnimPose & Pose , FName FromBoneName , FName ToBoneName , EAnimPoseSpaces Space /*= EAnimPoseSpaces::Local*/ )
{
if ( Pose . IsValid ( ) )
{
const int32 FromBoneIndex = Pose . BoneNames . IndexOfByKey ( FromBoneName ) ;
const int32 ToBoneIndex = Pose . BoneNames . IndexOfByKey ( ToBoneName ) ;
if ( FromBoneIndex ! = INDEX_NONE & & ToBoneIndex ! = INDEX_NONE )
{
const FTransform & From = Space = = EAnimPoseSpaces : : Local ? Pose . LocalSpacePoses [ FromBoneIndex ] : Pose . WorldSpacePoses [ FromBoneIndex ] ;
const FTransform & To = Space = = EAnimPoseSpaces : : Local ? Pose . LocalSpacePoses [ ToBoneIndex ] : Pose . WorldSpacePoses [ ToBoneIndex ] ;
const FTransform Relative = To . GetRelativeTransform ( From ) ;
return Relative ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " No bone with name %s or %s was found " ) , * FromBoneName . ToString ( ) , * ToBoneName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Provided Pose is not valid " ) ) ;
}
return FTransform : : Identity ;
}
FTransform UAnimPoseExtensions : : GetRelativeToRefPoseTransform ( const FAnimPose & Pose , FName BoneName , EAnimPoseSpaces Space /*= EAnimPoseSpaces::Local*/ )
{
if ( Pose . IsValid ( ) )
{
const int32 BoneIndex = Pose . BoneNames . IndexOfByKey ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
const FTransform & From = Space = = EAnimPoseSpaces : : Local ? Pose . RefLocalSpacePoses [ BoneIndex ] : Pose . RefWorldSpacePoses [ BoneIndex ] ;
const FTransform & To = Space = = EAnimPoseSpaces : : Local ? Pose . LocalSpacePoses [ BoneIndex ] : Pose . WorldSpacePoses [ BoneIndex ] ;
return To . GetRelativeTransform ( From ) ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " No bone with name %s was found " ) , * BoneName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Provided Pose is not valid " ) ) ;
}
return FTransform : : Identity ;
}
FTransform UAnimPoseExtensions : : GetRefPoseRelativeTransform ( const FAnimPose & Pose , FName FromBoneName , FName ToBoneName , EAnimPoseSpaces Space /*= EAnimPoseSpaces::Local*/ )
{
if ( Pose . IsValid ( ) )
{
const int32 FromBoneIndex = Pose . BoneNames . IndexOfByKey ( FromBoneName ) ;
const int32 ToBoneIndex = Pose . BoneNames . IndexOfByKey ( ToBoneName ) ;
if ( FromBoneIndex ! = INDEX_NONE & & ToBoneIndex ! = INDEX_NONE )
{
const FTransform & From = Space = = EAnimPoseSpaces : : Local ? Pose . RefLocalSpacePoses [ FromBoneIndex ] : Pose . RefWorldSpacePoses [ FromBoneIndex ] ;
const FTransform & To = Space = = EAnimPoseSpaces : : Local ? Pose . RefLocalSpacePoses [ ToBoneIndex ] : Pose . RefWorldSpacePoses [ ToBoneIndex ] ;
const FTransform Relative = From . GetRelativeTransform ( To ) ;
return Relative ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " No bone with name %s or %s was found " ) , * FromBoneName . ToString ( ) , * ToBoneName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Provided Pose is not valid " ) ) ;
}
return FTransform : : Identity ;
}
void UAnimPoseExtensions : : EvaluateAnimationBlueprintWithInputPose ( const FAnimPose & Pose , USkeletalMesh * TargetSkeletalMesh , UAnimBlueprint * AnimationBlueprint , FAnimPose & OutPose )
{
if ( Pose . IsValid ( ) )
{
if ( TargetSkeletalMesh )
{
if ( AnimationBlueprint )
{
UAnimBlueprintGeneratedClass * AnimGeneratedClass = AnimationBlueprint - > GetAnimBlueprintGeneratedClass ( ) ;
if ( AnimGeneratedClass )
{
if ( AnimGeneratedClass - > TargetSkeleton = = TargetSkeletalMesh - > GetSkeleton ( ) )
{
FMemMark Mark ( FMemStack : : Get ( ) ) ;
FPreviewScene PreviewScene ;
USkeletalMeshComponent * Component = NewObject < USkeletalMeshComponent > ( ) ;
Component - > SetSkeletalMesh ( TargetSkeletalMesh ) ;
Component - > SetAnimInstanceClass ( AnimationBlueprint - > GetAnimBlueprintGeneratedClass ( ) ) ;
PreviewScene . AddComponent ( Component , FTransform : : Identity ) ;
if ( UAnimInstance * AnimInstance = Component - > GetAnimInstance ( ) )
{
if ( FAnimNode_LinkedInputPose * InputNode = AnimInstance - > GetLinkedInputPoseNode ( ) )
{
2021-05-12 12:09:21 -04:00
const FBoneContainer & BoneContainer = AnimInstance - > GetRequiredBones ( ) ;
InputNode - > CachedInputPose . SetBoneContainer ( & BoneContainer ) ;
InputNode - > CachedInputCurve . InitFrom ( BoneContainer ) ;
InputNode - > CachedInputPose . ResetToRefPose ( ) ;
// Copy bone transform from input pose using skeleton index mapping
for ( FCompactPoseBoneIndex CompactIndex : InputNode - > CachedInputPose . ForEachBoneIndex ( ) )
{
const int32 SkeletonIndex = BoneContainer . GetSkeletonIndex ( CompactIndex ) ;
if ( SkeletonIndex ! = INDEX_NONE )
{
const int32 Index = Pose . BoneIndices . IndexOfByKey ( SkeletonIndex ) ;
if ( Index ! = INDEX_NONE )
{
InputNode - > CachedInputPose [ CompactIndex ] = Pose . LocalSpacePoses [ Index ] ;
}
}
}
2021-05-12 07:33:41 -04:00
OutPose . Init ( AnimInstance - > GetRequiredBones ( ) ) ;
Component - > InitAnim ( true ) ;
Component - > RefreshBoneTransforms ( ) ;
const TArray < FTransform > & LocalSpaceTransforms = Component - > GetBoneSpaceTransforms ( ) ;
OutPose . SetPose ( Component ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Failed to retrieve Input Pose Node from Animation Graph %s " ) , * AnimationBlueprint - > GetName ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Animation Blueprint target Skeleton %s does not match Target Skeletal Mesh its Skeleton %s " ) , * AnimGeneratedClass - > TargetSkeleton - > GetName ( ) , * TargetSkeletalMesh - > GetSkeleton ( ) - > GetName ( ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Failed to retrieve Animation Blueprint generated class " ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Invalid Animation Blueprint " ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Invalid Target Skeletal Mesh " ) ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Provided Pose is not valid " ) ) ;
}
}
void UAnimPoseExtensions : : GetReferencePose ( USkeleton * Skeleton , FAnimPose & OutPose )
{
if ( Skeleton )
{
const FReferenceSkeleton & RefSkeleton = Skeleton - > GetReferenceSkeleton ( ) ;
TArray < FBoneIndexType > RequiredBoneIndexArray ;
RequiredBoneIndexArray . AddUninitialized ( RefSkeleton . GetNum ( ) ) ;
for ( int32 BoneIndex = 0 ; BoneIndex < RequiredBoneIndexArray . Num ( ) ; + + BoneIndex )
{
RequiredBoneIndexArray [ BoneIndex ] = BoneIndex ;
}
FBoneContainer RequiredBones ;
RequiredBones . InitializeTo ( RequiredBoneIndexArray , FCurveEvaluationOption ( false ) , * Skeleton ) ;
OutPose . Init ( RequiredBones ) ;
OutPose . SetToRefPose ( ) ;
}
else
{
UE_LOG ( LogAnimationPoseScripting , Error , TEXT ( " Invalid Skeleton provided " ) ) ;
}
}
2022-04-06 10:45:20 -04:00
void UAnimPoseExtensions : : GetCurveNames ( const FAnimPose & Pose , TArray < FName > & Curves )
{
Curves . Append ( Pose . CurveNames ) ;
}
float UAnimPoseExtensions : : GetCurveWeight ( const FAnimPose & Pose , const FName & CurveName )
{
float CurveValue = 0.f ;
const int32 CurveIndex = Pose . CurveNames . IndexOfByKey ( CurveName ) ;
if ( CurveIndex ! = INDEX_NONE )
{
CurveValue = Pose . CurveValues [ CurveIndex ] ;
}
return CurveValue ;
}
2021-05-12 07:33:41 -04:00
void UAnimPoseExtensions : : GetAnimPoseAtFrame ( const UAnimSequenceBase * AnimationSequenceBase , int32 FrameIndex , FAnimPoseEvaluationOptions EvaluationOptions , FAnimPose & Pose )
{
[Backout] - CL20593017, 20594056, 20625634, 20645670, 20649179, 20649223, 20649380, 20658535
Add new custom version to specify a certain window of AnimSequences are not loadable
#fyi Jurre.deBaare
#robomerge EngineMerge
Original CL Desc
-----------------------------------------------------------------
**New**
- Engine
- IAnimationDataModel interface
- AnimationData plugin
- AnimSequencerDataModel, sequencer based implementation of IAnimationDataModel
- AnimSequencerDataController, controller for above (implementation of IAnimationDataController)
- Added FCompressedRichCurve::PopulateCurve, allowing users to convert back to a FRichCurve for validation/debugging
- Added DefaultFrameRate to AnimationSettings, this replaces the hardcoded 30FPS in code
- Added ::GetKeyIndicesFromTime which takes FFrameRate
- Added AnimSequenceBase::OnAnimModelLoaded, this is required for correct postloading behaviour of data model (specifically AnimSequencerDataModel, as it depends on data from its outer ? anim sequence)
- Added IAnimationDataModel ::Evaluate which now takes responsibility for evaluating raw animation bone, curve and attribute data. And moved all trackbased evaluation code into AnimDataModel.cpp
- Added a.ForceEvalRawData allowing to force evaluation of source data
- Added a.SkipDDC to force compressing animation data locally
**Changed**
- Reparent UAnimDataModel to IAnimationDataModel interface, and rejig behaviour
- AnimSequenceBase now reference AnimDataModel as IAnimationDataModel
- Upgrade path for legacy to IAnimationDataModel and existing UAnimDataModel to IAnimationDataModel through IAnimationDataController::PopulateWithExisting
- IAnimationDataModel data is now frame(number/rate/time) based rather than seconds/keyindices. This enforces frameborder aligned data from now on.
- Moved RichCurve evaluation code from RichCurve.cpp to separate file and consolidated all instances of copy-pasta behaviour
- Updated/removed deprecated EngineTests around AnimSequences
- Changed many instances to use a FFrameTime together with a known FFrameRate versus seconds and sequencelength in float involving frame \/ time calculations (including instances of FAnimKeyHelper)
- Switched anim sequence evaluation to use double in Extraction context for time value and patched up places with static\_cast\<double\>
- FRichCurve::Eval
- Make sure we always evaluate keys when T >= Key0.Time and T <= KeyN.Time to deal with crazy userweighted tangents
- Fixed WeightedKeyDataAdapter::GetKeyInterpMode/GetKeyTangentWeightMode retrieving invalid values, as it was indexing according to KeyIndex rather than KeyIndex\*2. This made it so that values were misinterpreted.
- Fixed WeightedEvalForTwoKeys for compressed data retrieving GetKeyInterpMode and GetKeyTangentWeightMode using the wrong index value. As they are not indexed using KeyDataHandle type.
- Fixed issue where compression could crash when containing zero-key scale additivebase track (tries to retrieve)
- Replaced instances of NULL with nullptr
- Moved required decompression information into FAnimSequenceDecompressionContext and reimplemented decompression within UE::Anim::Decompression namespace and new file
- Deprecated ::GetRawDataGuid and replaced with GetDataModel()->GenerateGuid()
- Fixed UAnimStreamable evaluation/compression (previously broken with MVC refactor)
- Updated Animation exporting pipeline to be frame-based rather than seconds
- Deprecated RetargetPose, replaced with FRetargetingScope (used within AnimModel::Evaluate)
- Fixed BaseAdditiveAnimation array become invalid/incorrect when removing zero-additve tracks during compression
- Updated EngineTest animation sequence related tests to new APIs (while maintaining deprecated path testing as well for now)
- AnimDataController / Animation Sequence tests now generate a USkeleton for the transient animation sequence (used to perform the test on)
**Removed**
- Unused file/class AnimData/AnimDataNotifyCollector.h
#rb Thomas.Sarkanen, Martin.Wilson, Alexis.Matte, Mike.Zyracki
#jira UE-131296
#preflight 62a308a8b0150a87f9d6891b
[CL 20677979 by Marc Audy in ue5-main branch]
2022-06-15 18:24:46 -04:00
float Time = 0.f ;
UAnimationBlueprintLibrary : : GetTimeAtFrame ( AnimationSequenceBase , FrameIndex , Time ) ;
2021-05-12 07:33:41 -04:00
GetAnimPoseAtTime ( AnimationSequenceBase , Time , EvaluationOptions , Pose ) ;
}
[Backout] - CL20593017, 20594056, 20625634, 20645670, 20649179, 20649223, 20649380, 20658535
Add new custom version to specify a certain window of AnimSequences are not loadable
#fyi Jurre.deBaare
#robomerge EngineMerge
Original CL Desc
-----------------------------------------------------------------
**New**
- Engine
- IAnimationDataModel interface
- AnimationData plugin
- AnimSequencerDataModel, sequencer based implementation of IAnimationDataModel
- AnimSequencerDataController, controller for above (implementation of IAnimationDataController)
- Added FCompressedRichCurve::PopulateCurve, allowing users to convert back to a FRichCurve for validation/debugging
- Added DefaultFrameRate to AnimationSettings, this replaces the hardcoded 30FPS in code
- Added ::GetKeyIndicesFromTime which takes FFrameRate
- Added AnimSequenceBase::OnAnimModelLoaded, this is required for correct postloading behaviour of data model (specifically AnimSequencerDataModel, as it depends on data from its outer ? anim sequence)
- Added IAnimationDataModel ::Evaluate which now takes responsibility for evaluating raw animation bone, curve and attribute data. And moved all trackbased evaluation code into AnimDataModel.cpp
- Added a.ForceEvalRawData allowing to force evaluation of source data
- Added a.SkipDDC to force compressing animation data locally
**Changed**
- Reparent UAnimDataModel to IAnimationDataModel interface, and rejig behaviour
- AnimSequenceBase now reference AnimDataModel as IAnimationDataModel
- Upgrade path for legacy to IAnimationDataModel and existing UAnimDataModel to IAnimationDataModel through IAnimationDataController::PopulateWithExisting
- IAnimationDataModel data is now frame(number/rate/time) based rather than seconds/keyindices. This enforces frameborder aligned data from now on.
- Moved RichCurve evaluation code from RichCurve.cpp to separate file and consolidated all instances of copy-pasta behaviour
- Updated/removed deprecated EngineTests around AnimSequences
- Changed many instances to use a FFrameTime together with a known FFrameRate versus seconds and sequencelength in float involving frame \/ time calculations (including instances of FAnimKeyHelper)
- Switched anim sequence evaluation to use double in Extraction context for time value and patched up places with static\_cast\<double\>
- FRichCurve::Eval
- Make sure we always evaluate keys when T >= Key0.Time and T <= KeyN.Time to deal with crazy userweighted tangents
- Fixed WeightedKeyDataAdapter::GetKeyInterpMode/GetKeyTangentWeightMode retrieving invalid values, as it was indexing according to KeyIndex rather than KeyIndex\*2. This made it so that values were misinterpreted.
- Fixed WeightedEvalForTwoKeys for compressed data retrieving GetKeyInterpMode and GetKeyTangentWeightMode using the wrong index value. As they are not indexed using KeyDataHandle type.
- Fixed issue where compression could crash when containing zero-key scale additivebase track (tries to retrieve)
- Replaced instances of NULL with nullptr
- Moved required decompression information into FAnimSequenceDecompressionContext and reimplemented decompression within UE::Anim::Decompression namespace and new file
- Deprecated ::GetRawDataGuid and replaced with GetDataModel()->GenerateGuid()
- Fixed UAnimStreamable evaluation/compression (previously broken with MVC refactor)
- Updated Animation exporting pipeline to be frame-based rather than seconds
- Deprecated RetargetPose, replaced with FRetargetingScope (used within AnimModel::Evaluate)
- Fixed BaseAdditiveAnimation array become invalid/incorrect when removing zero-additve tracks during compression
- Updated EngineTest animation sequence related tests to new APIs (while maintaining deprecated path testing as well for now)
- AnimDataController / Animation Sequence tests now generate a USkeleton for the transient animation sequence (used to perform the test on)
**Removed**
- Unused file/class AnimData/AnimDataNotifyCollector.h
#rb Thomas.Sarkanen, Martin.Wilson, Alexis.Matte, Mike.Zyracki
#jira UE-131296
#preflight 62a308a8b0150a87f9d6891b
[CL 20677979 by Marc Audy in ue5-main branch]
2022-06-15 18:24:46 -04:00
void UAnimPoseExtensions : : GetAnimPoseAtTime ( const UAnimSequenceBase * AnimationSequenceBase , float Time , FAnimPoseEvaluationOptions EvaluationOptions , FAnimPose & Pose )
2022-04-06 10:45:20 -04:00
{
TArray < FAnimPose > InOutPoses ;
GetAnimPoseAtTimeIntervals ( AnimationSequenceBase , { Time } , EvaluationOptions , InOutPoses ) ;
if ( InOutPoses . Num ( ) )
{
ensure ( InOutPoses . Num ( ) = = 1 ) ;
Pose = InOutPoses [ 0 ] ;
}
}
[Backout] - CL20593017, 20594056, 20625634, 20645670, 20649179, 20649223, 20649380, 20658535
Add new custom version to specify a certain window of AnimSequences are not loadable
#fyi Jurre.deBaare
#robomerge EngineMerge
Original CL Desc
-----------------------------------------------------------------
**New**
- Engine
- IAnimationDataModel interface
- AnimationData plugin
- AnimSequencerDataModel, sequencer based implementation of IAnimationDataModel
- AnimSequencerDataController, controller for above (implementation of IAnimationDataController)
- Added FCompressedRichCurve::PopulateCurve, allowing users to convert back to a FRichCurve for validation/debugging
- Added DefaultFrameRate to AnimationSettings, this replaces the hardcoded 30FPS in code
- Added ::GetKeyIndicesFromTime which takes FFrameRate
- Added AnimSequenceBase::OnAnimModelLoaded, this is required for correct postloading behaviour of data model (specifically AnimSequencerDataModel, as it depends on data from its outer ? anim sequence)
- Added IAnimationDataModel ::Evaluate which now takes responsibility for evaluating raw animation bone, curve and attribute data. And moved all trackbased evaluation code into AnimDataModel.cpp
- Added a.ForceEvalRawData allowing to force evaluation of source data
- Added a.SkipDDC to force compressing animation data locally
**Changed**
- Reparent UAnimDataModel to IAnimationDataModel interface, and rejig behaviour
- AnimSequenceBase now reference AnimDataModel as IAnimationDataModel
- Upgrade path for legacy to IAnimationDataModel and existing UAnimDataModel to IAnimationDataModel through IAnimationDataController::PopulateWithExisting
- IAnimationDataModel data is now frame(number/rate/time) based rather than seconds/keyindices. This enforces frameborder aligned data from now on.
- Moved RichCurve evaluation code from RichCurve.cpp to separate file and consolidated all instances of copy-pasta behaviour
- Updated/removed deprecated EngineTests around AnimSequences
- Changed many instances to use a FFrameTime together with a known FFrameRate versus seconds and sequencelength in float involving frame \/ time calculations (including instances of FAnimKeyHelper)
- Switched anim sequence evaluation to use double in Extraction context for time value and patched up places with static\_cast\<double\>
- FRichCurve::Eval
- Make sure we always evaluate keys when T >= Key0.Time and T <= KeyN.Time to deal with crazy userweighted tangents
- Fixed WeightedKeyDataAdapter::GetKeyInterpMode/GetKeyTangentWeightMode retrieving invalid values, as it was indexing according to KeyIndex rather than KeyIndex\*2. This made it so that values were misinterpreted.
- Fixed WeightedEvalForTwoKeys for compressed data retrieving GetKeyInterpMode and GetKeyTangentWeightMode using the wrong index value. As they are not indexed using KeyDataHandle type.
- Fixed issue where compression could crash when containing zero-key scale additivebase track (tries to retrieve)
- Replaced instances of NULL with nullptr
- Moved required decompression information into FAnimSequenceDecompressionContext and reimplemented decompression within UE::Anim::Decompression namespace and new file
- Deprecated ::GetRawDataGuid and replaced with GetDataModel()->GenerateGuid()
- Fixed UAnimStreamable evaluation/compression (previously broken with MVC refactor)
- Updated Animation exporting pipeline to be frame-based rather than seconds
- Deprecated RetargetPose, replaced with FRetargetingScope (used within AnimModel::Evaluate)
- Fixed BaseAdditiveAnimation array become invalid/incorrect when removing zero-additve tracks during compression
- Updated EngineTest animation sequence related tests to new APIs (while maintaining deprecated path testing as well for now)
- AnimDataController / Animation Sequence tests now generate a USkeleton for the transient animation sequence (used to perform the test on)
**Removed**
- Unused file/class AnimData/AnimDataNotifyCollector.h
#rb Thomas.Sarkanen, Martin.Wilson, Alexis.Matte, Mike.Zyracki
#jira UE-131296
#preflight 62a308a8b0150a87f9d6891b
[CL 20677979 by Marc Audy in ue5-main branch]
2022-06-15 18:24:46 -04:00
void UAnimPoseExtensions : : GetAnimPoseAtTimeIntervals ( const UAnimSequenceBase * AnimationSequenceBase , TArray < float > TimeIntervals , FAnimPoseEvaluationOptions EvaluationOptions , TArray < FAnimPose > & InOutPoses )
2021-05-12 07:33:41 -04:00
{
if ( AnimationSequenceBase & & AnimationSequenceBase - > GetSkeleton ( ) )
{
FMemMark Mark ( FMemStack : : Get ( ) ) ;
2022-04-06 10:45:20 -04:00
// asset to use for retarget proportions (can be either USkeletalMesh or USkeleton)
UObject * AssetToUse ;
int32 NumRequiredBones ;
if ( EvaluationOptions . OptionalSkeletalMesh )
{
AssetToUse = CastChecked < UObject > ( EvaluationOptions . OptionalSkeletalMesh ) ;
NumRequiredBones = EvaluationOptions . OptionalSkeletalMesh - > GetRefSkeleton ( ) . GetNum ( ) ;
2021-05-12 07:33:41 -04:00
}
else
{
2022-04-06 10:45:20 -04:00
AssetToUse = CastChecked < UObject > ( AnimationSequenceBase - > GetSkeleton ( ) ) ;
NumRequiredBones = AnimationSequenceBase - > GetSkeleton ( ) - > GetReferenceSkeleton ( ) . GetNum ( ) ;
}
TArray < FBoneIndexType > RequiredBoneIndexArray ;
RequiredBoneIndexArray . AddUninitialized ( NumRequiredBones ) ;
for ( int32 BoneIndex = 0 ; BoneIndex < RequiredBoneIndexArray . Num ( ) ; + + BoneIndex )
{
RequiredBoneIndexArray [ BoneIndex ] = BoneIndex ;
}
FBoneContainer RequiredBones ;
RequiredBones . InitializeTo ( RequiredBoneIndexArray , FCurveEvaluationOption ( EvaluationOptions . bEvaluateCurves ) , * AssetToUse ) ;
RequiredBones . SetUseRAWData ( EvaluationOptions . EvaluationType = = EAnimDataEvalType : : Raw ) ;
RequiredBones . SetUseSourceData ( EvaluationOptions . EvaluationType = = EAnimDataEvalType : : Source ) ;
RequiredBones . SetDisableRetargeting ( ! EvaluationOptions . bShouldRetarget ) ;
FCompactPose CompactPose ;
FBlendedCurve Curve ;
UE : : Anim : : FStackAttributeContainer Attributes ;
FAnimationPoseData PoseData ( CompactPose , Curve , Attributes ) ;
[Backout] - CL20593017, 20594056, 20625634, 20645670, 20649179, 20649223, 20649380, 20658535
Add new custom version to specify a certain window of AnimSequences are not loadable
#fyi Jurre.deBaare
#robomerge EngineMerge
Original CL Desc
-----------------------------------------------------------------
**New**
- Engine
- IAnimationDataModel interface
- AnimationData plugin
- AnimSequencerDataModel, sequencer based implementation of IAnimationDataModel
- AnimSequencerDataController, controller for above (implementation of IAnimationDataController)
- Added FCompressedRichCurve::PopulateCurve, allowing users to convert back to a FRichCurve for validation/debugging
- Added DefaultFrameRate to AnimationSettings, this replaces the hardcoded 30FPS in code
- Added ::GetKeyIndicesFromTime which takes FFrameRate
- Added AnimSequenceBase::OnAnimModelLoaded, this is required for correct postloading behaviour of data model (specifically AnimSequencerDataModel, as it depends on data from its outer ? anim sequence)
- Added IAnimationDataModel ::Evaluate which now takes responsibility for evaluating raw animation bone, curve and attribute data. And moved all trackbased evaluation code into AnimDataModel.cpp
- Added a.ForceEvalRawData allowing to force evaluation of source data
- Added a.SkipDDC to force compressing animation data locally
**Changed**
- Reparent UAnimDataModel to IAnimationDataModel interface, and rejig behaviour
- AnimSequenceBase now reference AnimDataModel as IAnimationDataModel
- Upgrade path for legacy to IAnimationDataModel and existing UAnimDataModel to IAnimationDataModel through IAnimationDataController::PopulateWithExisting
- IAnimationDataModel data is now frame(number/rate/time) based rather than seconds/keyindices. This enforces frameborder aligned data from now on.
- Moved RichCurve evaluation code from RichCurve.cpp to separate file and consolidated all instances of copy-pasta behaviour
- Updated/removed deprecated EngineTests around AnimSequences
- Changed many instances to use a FFrameTime together with a known FFrameRate versus seconds and sequencelength in float involving frame \/ time calculations (including instances of FAnimKeyHelper)
- Switched anim sequence evaluation to use double in Extraction context for time value and patched up places with static\_cast\<double\>
- FRichCurve::Eval
- Make sure we always evaluate keys when T >= Key0.Time and T <= KeyN.Time to deal with crazy userweighted tangents
- Fixed WeightedKeyDataAdapter::GetKeyInterpMode/GetKeyTangentWeightMode retrieving invalid values, as it was indexing according to KeyIndex rather than KeyIndex\*2. This made it so that values were misinterpreted.
- Fixed WeightedEvalForTwoKeys for compressed data retrieving GetKeyInterpMode and GetKeyTangentWeightMode using the wrong index value. As they are not indexed using KeyDataHandle type.
- Fixed issue where compression could crash when containing zero-key scale additivebase track (tries to retrieve)
- Replaced instances of NULL with nullptr
- Moved required decompression information into FAnimSequenceDecompressionContext and reimplemented decompression within UE::Anim::Decompression namespace and new file
- Deprecated ::GetRawDataGuid and replaced with GetDataModel()->GenerateGuid()
- Fixed UAnimStreamable evaluation/compression (previously broken with MVC refactor)
- Updated Animation exporting pipeline to be frame-based rather than seconds
- Deprecated RetargetPose, replaced with FRetargetingScope (used within AnimModel::Evaluate)
- Fixed BaseAdditiveAnimation array become invalid/incorrect when removing zero-additve tracks during compression
- Updated EngineTest animation sequence related tests to new APIs (while maintaining deprecated path testing as well for now)
- AnimDataController / Animation Sequence tests now generate a USkeleton for the transient animation sequence (used to perform the test on)
**Removed**
- Unused file/class AnimData/AnimDataNotifyCollector.h
#rb Thomas.Sarkanen, Martin.Wilson, Alexis.Matte, Mike.Zyracki
#jira UE-131296
#preflight 62a308a8b0150a87f9d6891b
[CL 20677979 by Marc Audy in ue5-main branch]
2022-06-15 18:24:46 -04:00
FAnimExtractContext Context ( 0.f , EvaluationOptions . bExtractRootMotion ) ;
2022-04-06 10:45:20 -04:00
FCompactPose BasePose ;
BasePose . SetBoneContainer ( & RequiredBones ) ;
CompactPose . SetBoneContainer ( & RequiredBones ) ;
Curve . InitFrom ( RequiredBones ) ;
FAnimPose Pose ;
Pose . Init ( RequiredBones ) ;
for ( int32 Index = 0 ; Index < TimeIntervals . Num ( ) ; + + Index )
{
[Backout] - CL20593017, 20594056, 20625634, 20645670, 20649179, 20649223, 20649380, 20658535
Add new custom version to specify a certain window of AnimSequences are not loadable
#fyi Jurre.deBaare
#robomerge EngineMerge
Original CL Desc
-----------------------------------------------------------------
**New**
- Engine
- IAnimationDataModel interface
- AnimationData plugin
- AnimSequencerDataModel, sequencer based implementation of IAnimationDataModel
- AnimSequencerDataController, controller for above (implementation of IAnimationDataController)
- Added FCompressedRichCurve::PopulateCurve, allowing users to convert back to a FRichCurve for validation/debugging
- Added DefaultFrameRate to AnimationSettings, this replaces the hardcoded 30FPS in code
- Added ::GetKeyIndicesFromTime which takes FFrameRate
- Added AnimSequenceBase::OnAnimModelLoaded, this is required for correct postloading behaviour of data model (specifically AnimSequencerDataModel, as it depends on data from its outer ? anim sequence)
- Added IAnimationDataModel ::Evaluate which now takes responsibility for evaluating raw animation bone, curve and attribute data. And moved all trackbased evaluation code into AnimDataModel.cpp
- Added a.ForceEvalRawData allowing to force evaluation of source data
- Added a.SkipDDC to force compressing animation data locally
**Changed**
- Reparent UAnimDataModel to IAnimationDataModel interface, and rejig behaviour
- AnimSequenceBase now reference AnimDataModel as IAnimationDataModel
- Upgrade path for legacy to IAnimationDataModel and existing UAnimDataModel to IAnimationDataModel through IAnimationDataController::PopulateWithExisting
- IAnimationDataModel data is now frame(number/rate/time) based rather than seconds/keyindices. This enforces frameborder aligned data from now on.
- Moved RichCurve evaluation code from RichCurve.cpp to separate file and consolidated all instances of copy-pasta behaviour
- Updated/removed deprecated EngineTests around AnimSequences
- Changed many instances to use a FFrameTime together with a known FFrameRate versus seconds and sequencelength in float involving frame \/ time calculations (including instances of FAnimKeyHelper)
- Switched anim sequence evaluation to use double in Extraction context for time value and patched up places with static\_cast\<double\>
- FRichCurve::Eval
- Make sure we always evaluate keys when T >= Key0.Time and T <= KeyN.Time to deal with crazy userweighted tangents
- Fixed WeightedKeyDataAdapter::GetKeyInterpMode/GetKeyTangentWeightMode retrieving invalid values, as it was indexing according to KeyIndex rather than KeyIndex\*2. This made it so that values were misinterpreted.
- Fixed WeightedEvalForTwoKeys for compressed data retrieving GetKeyInterpMode and GetKeyTangentWeightMode using the wrong index value. As they are not indexed using KeyDataHandle type.
- Fixed issue where compression could crash when containing zero-key scale additivebase track (tries to retrieve)
- Replaced instances of NULL with nullptr
- Moved required decompression information into FAnimSequenceDecompressionContext and reimplemented decompression within UE::Anim::Decompression namespace and new file
- Deprecated ::GetRawDataGuid and replaced with GetDataModel()->GenerateGuid()
- Fixed UAnimStreamable evaluation/compression (previously broken with MVC refactor)
- Updated Animation exporting pipeline to be frame-based rather than seconds
- Deprecated RetargetPose, replaced with FRetargetingScope (used within AnimModel::Evaluate)
- Fixed BaseAdditiveAnimation array become invalid/incorrect when removing zero-additve tracks during compression
- Updated EngineTest animation sequence related tests to new APIs (while maintaining deprecated path testing as well for now)
- AnimDataController / Animation Sequence tests now generate a USkeleton for the transient animation sequence (used to perform the test on)
**Removed**
- Unused file/class AnimData/AnimDataNotifyCollector.h
#rb Thomas.Sarkanen, Martin.Wilson, Alexis.Matte, Mike.Zyracki
#jira UE-131296
#preflight 62a308a8b0150a87f9d6891b
[CL 20677979 by Marc Audy in ue5-main branch]
2022-06-15 18:24:46 -04:00
const float EvalInterval = TimeIntervals [ Index ] ;
2022-04-06 10:45:20 -04:00
bool bValidTime = false ;
UAnimationBlueprintLibrary : : IsValidTime ( AnimationSequenceBase , EvalInterval , bValidTime ) ;
ensure ( bValidTime ) ;
Context . CurrentTime = EvalInterval ;
FAnimPose & FramePose = InOutPoses . AddDefaulted_GetRef ( ) ;
FramePose = Pose ;
Curve . InitFrom ( RequiredBones ) ;
if ( bValidTime )
{
if ( AnimationSequenceBase - > IsValidAdditive ( ) )
{
CompactPose . ResetToAdditiveIdentity ( ) ;
AnimationSequenceBase - > GetAnimationPose ( PoseData , Context ) ;
if ( EvaluationOptions . bRetrieveAdditiveAsFullPose )
{
const UAnimSequence * AnimSequence = Cast < const UAnimSequence > ( AnimationSequenceBase ) ;
FBlendedCurve BaseCurve ;
BaseCurve . InitFrom ( RequiredBones ) ;
UE : : Anim : : FStackAttributeContainer BaseAttributes ;
FAnimationPoseData BasePoseData ( BasePose , BaseCurve , BaseAttributes ) ;
AnimSequence - > GetAdditiveBasePose ( BasePoseData , Context ) ;
FAnimationRuntime : : AccumulateAdditivePose ( BasePoseData , PoseData , 1.f , AnimSequence - > GetAdditiveAnimType ( ) ) ;
BasePose . NormalizeRotations ( ) ;
FramePose . SetPose ( BasePoseData ) ;
}
else
{
FramePose . SetPose ( PoseData ) ;
}
}
else
{
CompactPose . ResetToRefPose ( ) ;
AnimationSequenceBase - > GetAnimationPose ( PoseData , Context ) ;
FramePose . SetPose ( PoseData ) ;
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Invalid time value %f for Animation Sequence %s supplied for GetBonePosesForTime " ) , EvalInterval , * AnimationSequenceBase - > GetName ( ) ) ;
}
2021-05-12 07:33:41 -04:00
}
}
else
{
UE_LOG ( LogAnimationPoseScripting , Warning , TEXT ( " Invalid Animation Sequence supplied for GetBonePosesForTime " ) ) ;
}
2021-05-12 12:09:21 -04:00
}