Keywords: UE4, Animation, Runtime Procedural Programming

Usages

How to get bone name list of SkeletalMesh
void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();
    
    if(USkeletalMeshComponent* SkMeshComp = GetMesh())
    {
        TArray<FName> OutBoneNames;
        SkMeshComp->GetBoneNames(OutBoneNames);
    }
}
How to extract transform of bones from animation sequence

.Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "AnimationModifiers" });

cpp source

void AMyCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    
    if (USkeletalMeshComponent* SkMeshComp = GetMesh())
    {
        TArray<FName> OutBoneNames;
        SkMeshComp->GetBoneNames(OutBoneNames);

        if (UAnimSequence* AnimSeq = LoadObject<UAnimSequence>(nullptr, TEXT("AnimSequence'/Game/Mannequin/Animations/ThirdPersonWalk.ThirdPersonWalk'")))
        {
            const float FrameCost = 1.f / 30;

            AnimTime += FrameCost;
            
            if(AnimTime < AnimSeq->SequenceLength)
            {
                TArray<FTransform> OutPoses;
                UAnimationBlueprintLibrary::GetBonePosesForTime(AnimSeq, OutBoneNames, AnimTime, true, OutPoses);

                int TestIndex = 54;

                FName BoneName = OutBoneNames[TestIndex];

                FTransform Trans = OutPoses[TestIndex];
                FVector Translation = Trans.GetTranslation();
                FRotator Rotation = Trans.Rotator();
                FVector Scale = Trans.GetScale3D();

                FString Text = FString::Printf(TEXT("Bone: %s Time: %f Loc: %s Rot: %s"), *BoneName.ToString(), AnimTime, *Translation.ToString(), *Rotation.ToString());
                GEngine->AddOnScreenDebugMessage(0, 3.f, FColor::Yellow, Text, false);
            }
        }
    }
}
How to get user data sotred with animation asset

Engine\Source\Runtime\Engine\Classes\Engine\SkeletalMesh.h

UPROPERTY(EditAnywhere, AdvancedDisplay, Instanced, Category=SkeletalMesh)
TArray<UAssetUserData*> AssetUserData;
How to get bone index from bone name

Engine\Source\Runtime\Engine\Classes\Engine\SkeletalMesh.h

RefSkeleton.FindBoneIndex(BoneName);
Get Animation CompactPose (Transform) from AnimSequence by Current Time

Quoted from void FAnimInstanceProxy::SlotEvaluatePose()

FSlotEvaluationPose NewPose(EvalState.MontageWeight, AdditiveAnimType);

// Bone array has to be allocated prior to calling GetPoseFromAnimTrack
NewPose.Pose.SetBoneContainer(&RequiredBones);
NewPose.Curve.InitFrom(RequiredBones);

// Extract pose from Track
FAnimExtractContext ExtractionContext(EvalState.MontagePosition, Montage->HasRootMotion() && RootMotionMode != ERootMotionMode::NoRootMotionExtraction);
AnimTrack->GetAnimationPose(NewPose.Pose, NewPose.Curve, ExtractionContext);

API

Common API in AnimationBlueprintLibrary

Engine\Source\Editor\AnimationModifiers\Public\AnimationBlueprintLibrary.h

How to get bone pose:

/** Retrieves Bone Pose data for the given Bone Names at the specified Time from the given Animation Sequence */
UFUNCTION(BlueprintPure, Category = "AnimationBlueprintLibrary|Pose")
static void GetBonePosesForTime(const UAnimSequence* AnimationSequence, TArray<FName> BoneNames, float Time, bool bExtractRootMotion, TArray<FTransform>& Poses, const USkeletalMesh* PreviewMesh = nullptr);

/** Retrieves Bone Pose data for the given Bone Names at the specified Frame from the given Animation Sequence */
UFUNCTION(BlueprintPure, Category = "AnimationBlueprintLibrary|Pose")
static void GetBonePosesForFrame(const UAnimSequence* AnimationSequence, TArray<FName> BoneNames, int32 Frame, bool bExtractRootMotion, TArray<FTransform>& Poses, const USkeletalMesh* PreviewMesh = nullptr);

How to add or remove notify to animation at run-time:

/** Adds an Animation Notify Event to Notify track in the given Animation with the given Notify creation data */
UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
static UAnimNotify* AddAnimationNotifyEvent(UAnimSequence* AnimationSequence, FName NotifyTrackName, float StartTime, TSubclassOf<UAnimNotify> NotifyClass);

/** Adds an Animation Notify State Event to Notify track in the given Animation with the given Notify State creation data */
UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
static UAnimNotifyState* AddAnimationNotifyStateEvent(UAnimSequence* AnimationSequence, FName NotifyTrackName, float StartTime, float Duration, TSubclassOf<UAnimNotifyState> NotifyStateClass);

/** Adds an the specific Animation Notify to the Animation Sequence (requires Notify's outer to be the Animation Sequence) */
UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
static void AddAnimationNotifyEventObject(UAnimSequence* AnimationSequence, float StartTime, UAnimNotify* Notify, FName NotifyTrackName);

/** Adds an the specific Animation Notify State to the Animation Sequence (requires Notify State's outer to be the Animation Sequence) */
UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
static void AddAnimationNotifyStateEventObject(UAnimSequence* AnimationSequence, float StartTime, float Duration, UAnimNotifyState* NotifyState, FName NotifyTrackName);

/** Removes Animation Notify Events found by Name within the Animation Sequence, and returns the number of removed name instances */
UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
static int32 RemoveAnimationNotifyEventsByName(UAnimSequence* AnimationSequence, FName NotifyName);

/** Removes Animation Notify Events found by Track within the Animation Sequence, and returns the number of removed name instances */
UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
static int32 RemoveAnimationNotifyEventsByTrack(UAnimSequence* AnimationSequence, FName NotifyTrackName);	
Common API in BonePose

Engine\Source\Runtime\Engine\Public\BonePose.h

// Populate InOutPose based on raw animation data. 
extern void BuildPoseFromRawData(const TArray<FRawAnimSequenceTrack>& InAnimationData, const TArray<struct FTrackToSkeletonMap>& TrackToSkeletonMapTable, FCompactPose& InOutPose, float InTime, EAnimInterpolationType Interpolation, int32 NumFrames, float SequenceLength, FName RetargetSource);
Common API in AnimInstance

Engine\Source\Runtime\Engine\Classes\Animation\AnimInstance.h

// the below functions are the native overrides for each phase
// Native initialization override point
virtual void NativeInitializeAnimation();

// Native update override point. It is usually a good idea to simply gather data in this step and 
// for the bulk of the work to be done in NativeUpdateAnimation.
virtual void NativeUpdateAnimation(float DeltaSeconds);

// Native Post Evaluate override point
virtual void NativePostEvaluateAnimation();

// Native Uninitialize override point
virtual void NativeUninitializeAnimation();

// Executed when begin play is called on the owning component
virtual void NativeBeginPlay();
AnimationEditorPreviewActor

Path:
Engine\Source\Editor\Persona\Public\AnimationEditorPreviewActor.h

AnimationEditorPreviewActor is an Actor used to preview AnimSequence.
Example:

void UMyAnimNotify::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
{
    if(AActor* Actor = MeshComp->GetOwner())
    {
        if(GIsEditor)
        {
            AAnimationEditorPreviewActor* PrevActor = Cast<AAnimationEditorPreviewActor>(Actor);
        }
        else
        {
            AMyCharacter* Character = Cast<AMyCharacter>(Actor);
        }
    }
}

Build.cs:

PublicDependencyModuleNames.Add("Persona");

Engine Source Analytics

Callstack on FAnimNode_SkeletalControlBase::EvaluateSkeletalControl_AnyThread()
UE4Editor-CustomAnimNode-Win64-DebugGame.dll!FAnimNode_SpeedWarping::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext & Output, TArray<FBoneTransform,TSizedDefaultAllocator<32>> & OutBoneTransforms) Line 32	C++
UE4Editor-AnimGraphRuntime.dll!FAnimNode_SkeletalControlBase::EvaluateComponentSpace_AnyThread(FComponentSpacePoseContext & Output) Line 165	C++
UE4Editor-Engine.dll!FComponentSpacePoseLink::EvaluateComponentSpace(FComponentSpacePoseContext & Output) Line 443	C++
UE4Editor-Engine.dll!FAnimNode_ConvertComponentToLocalSpace::Evaluate_AnyThread(FPoseContext & Output) Line 34	C++
UE4Editor-Engine.dll!FPoseLink::Evaluate(FPoseContext & Output) Line 381	C++
UE4Editor-Engine.dll!FAnimInstanceProxy::EvaluateAnimationNode_WithRoot(FPoseContext & Output, FAnimNode_Base * InRootNode) Line 1365	C++
UE4Editor-Engine.dll!FAnimInstanceProxy::EvaluateAnimation_WithRoot(FPoseContext & Output, FAnimNode_Base * InRootNode) Line 1298	C++
UE4Editor-Engine.dll!UAnimInstance::ParallelEvaluateAnimation(bool bForceRefPose, const USkeletalMesh * InSkeletalMesh, FBlendedHeapCurve & OutCurve, FCompactPose & OutPose) Line 658	C++
UE4Editor-Engine.dll!USkeletalMeshComponent::EvaluateAnimation(const USkeletalMesh * InSkeletalMesh, UAnimInstance * InAnimInstance, FVector & OutRootBoneTranslation, FBlendedHeapCurve & OutCurve, FCompactPose & OutPose) Line 1755	C++
UE4Editor-Engine.dll!USkeletalMeshComponent::PerformAnimationProcessing(const USkeletalMesh * InSkeletalMesh, UAnimInstance * InAnimInstance, bool bInDoEvaluation, TArray<FTransform,TSizedDefaultAllocator<32>> & OutSpaceBases, TArray<FTransform,TSizedDefaultAllocator<32>> & OutBoneSpaceTransforms, FVector & OutRootBoneTranslation, FBlendedHeapCurve & OutCurve) Line 1838	C++
UE4Editor-Engine.dll!USkeletalMeshComponent::ParallelAnimationEvaluation() Line 3528	C++
UE4Editor-Engine.dll!FParallelAnimationEvaluationTask::DoTask(ENamedThreads::Type CurrentThread, const TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 110	C++
UE4Editor-Engine.dll!TGraphTask<FParallelAnimationEvaluationTask>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & NewTasks, ENamedThreads::Type CurrentThread) Line 847	C++
[Inline Frame] UE4Editor-Core.dll!FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & CurrentThread, ENamedThreads::Type) Line 514	C++
UE4Editor-Core.dll!FTaskThreadAnyThread::ProcessTasks() Line 1029	C++
UE4Editor-Core.dll!FTaskThreadAnyThread::ProcessTasksUntilQuit(int QueueIndex) Line 855	C++
[Inline Frame] UE4Editor-Core.dll!FTaskThreadBase::Run() Line 524	C++
UE4Editor-Core.dll!FTaskThreadAnyThread::Run() Line 931	C++
UE4Editor-Core.dll!FRunnableThreadWin::Run() Line 96	C++
UE4Editor-Core.dll!FRunnableThreadWin::GuardedRun() Line 45	C++

Docs

Offical Docs

Demystifying Bone Indices
https://www.unrealengine.com/en-US/tech-blog/demystifying-bone-indices


I distrust official charity.All charity should be done by stealth. ― Romain Rolland