100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > UE4源码阅读_骨骼模型与动画系统_动画流程

UE4源码阅读_骨骼模型与动画系统_动画流程

时间:2022-07-31 17:15:08

相关推荐

UE4源码阅读_骨骼模型与动画系统_动画流程

0. 写在前面

本文为个人学习的笔记整理,如有错误,望不吝指出。

本篇粗略的描述UE4中每帧动画计算的主流程,该流程涉及的相关代码,因为动画设置的多样性,还有相当多的分支代码。

本篇只描述角色跑起一个最基础的动画,从SkeletalMeshComp到动画蓝图中动画播放节点的姿势计算所经历的流程。

1. SkeletalMeshComp流程

【AnimInstance】

动画实例,该类是控制动画逻辑的核心,可以理解为一个AnimInstance对象就对应着一个动画蓝图。

SkeletalMeshComp中持有三种AnimInstance对象:

AnimScriptInstance:当前激活的动画蓝图对象PostProcessAnimInstanceLinkedInstances

【入口】

1)SkinnedMeshComp->TickComponent

SkinnedMeshComp中的TickComponent是会被每帧调用的接口,该接口也是动画更新的入口

其中两个重要的函数:

TickPose:处理动画计算中非并行的部分RefreshBoneTransforms:处理动画计算中多线程并行的部分,且是由AnimInstanceProxy处理

注:UE4动画蓝图默认设置为多线程更新,动画计算中大部分的数据计算都由AnimInstanceProxy负责在多线程中并行处理。

2)SkeletalMeshComp->TickPose:

计算tick的时间间隔 DeltaTimeForTick调用TickAnimation(DeltaTimeForTick, bNeedsValidRootMotion)更新三种动画实例 调用AnimInstance的UpdateAnimation,这里处理动画在游戏线程计算的部分更新顺序为:先更新LinkedInstances,再更新AnimScriptInstance,最后更新PostProcessAnimInstance

3)SkeletalMeshComp->RefreshBoneTransforms接口:

DispatchParallelEvaluationTasks,负责发起多线程计算: SwapEvaluationContextBuffers:

计算前交换缓冲区中的上下文数据,把SkeletalMeshComp中缓存的一些动画数据交换到AnimEvaluationContext。

AnimEvaluationContext(FAnimationEvaluationContext):该变量在SkeletalMeshComp中负责缓存在计算该角色当前动画姿势时的全部数据。发起两个Task: FParallelAnimationEvaluationTask:该Task调用ParallelAnimationEvaluation PerformAnimationProcessing:该函数主要负责调动画实例的Update和Evaluate接口,这两个接口会逐节点更新动画数据,然后更新动画姿势。最后应用动画姿势数据。ParallelDuplicateAndInterpolate: FParallelAnimationCompletionTask:该Task调用CompleteParallelAnimationEvaluation SwapEvaluationContextBuffers:将AnimEvaluationContext的数据交换回SkeletalMeshComp中缓存,等渲染线程调用PostAnimEvaluation(AnimEvaluationContext):

2. AnimInstance&&Proxy流程

【游戏线程】

前面说到SkeletalMeshComp会调AnimInstance的UpdateAnimation接口处理该动画蓝图在游戏线程计算的逻辑。

UpdateAnimation 在动画节点逻辑更新前先更新Montage

UpdateMontage(DeltaSeconds)

UpdateMontageSyncGroup

UpdateMontageEvaluationDataBlueprintUpdateAnimation,更新蓝图各种动画逻辑的入口,具体实现就是蓝图的动画树确定是否需要立即更新动画,如果不用立即更新动画的话,会由多线程调用Proxy进行并行计算

const bool bWantsImmediateUpdate = bNeedsValidRootMotion || NeedsImmediateUpdate(DeltaSeconds);

如果需要立即更新,如RootMotion无法并行计算,则在该函数下调用更新接口

ParallelUpdateAnimation();

PostUpdateAnimation();

【多线程】

SkeletalMeshComp的PerformAnimationProcessing负责调用AnimInstance的Update和Evaluate,进行蓝图数据更新,和姿势数据更新。

几个关键的函数:

关于Update:

AnimInstance->ParallelUpdateAnimation关于Evaluate:

EvaluateAnimation

EvaluatePostProcessMeshInstance

FinalizePoseEvaluationResult

FillComponentSpaceTransforms

1)ParallelUpdateAnimation

调用堆栈,由其他线程调用

该函数调的是Proxy的UpdateAnimation接口,直接看Proxy:

FAnimationUpdateSharedContext SharedContext;FAnimationUpdateContext Context(this, CurrentDeltaSeconds, &SharedContext);UpdateAnimation_WithRoot(Context, RootNode, NAME_AnimGraph);

Context:创建一个上下文对象

UpdateAnimation_WithRoot:从动画蓝图的根节点(最后一个节点,也就是动画输出姿势节点)往前回溯,遍历所有的动画节点对每个节点进行Update。

2)Proxy->UpdateAnimation_WithRoot

主要做的几件事:

CacheBones

Proxy->UpdateAnimationNode(InContext)

通过调用根节点的Update_AnyThread接口,从根节点开始,并不断往前回溯,更新蓝图数据FAnimNode_Root->Update_AnyThread(Context)

通过连接线找到自己的上一个节点N,然后再调用N节点的Update_AnyThread

不停的往前回溯,直到到达尽头节点,不再有连接线。

FPoseLink:连接线对象。

FPoseLink->LinkedNode:连接线指向的节点

根节点:

具体的更新逻辑需深入到每个不同的动画蓝图节点逻辑,暂略。

3)SkeletalMeshComp->EvaluateAnimation

AnimInstance->ParallelEvaluateAnimation

调用堆栈:

创建一个临时的EvaluationContext上下文对象

计算结束后,将Curve和Pose结果赋值到Comp的AnimEvaluationContext

FPoseContext EvaluationContext(&Proxy);EvaluationContext.ResetToRefPose();Proxy.EvaluateAnimation(EvaluationContext);OutCurve.CopyFrom(EvaluationContext.Curve);OutPose.CopyBonesFrom(EvaluationContext.Pose);

Proxy.EvaluateAnimation(EvaluationContext)Proxy.EvaluateAnimation_WithRoot(Output, RootNode) CacheBonesEvaluateAnimationNode_WithRoot(Output, InRootNode) 和Update类似的流程,也是从根节点开始,通过连接线回溯,直到节点尽头。不过具体节点内部的Evaluate逻辑应该决定了和Update调用到的节点数不一样

4)SkeletalMeshComp->EvaluatePostProcessMeshInstance

EvaluatePostProcessMeshInstance也是调用的EvaluateAnimation,一样的更新流程,只是对象不一样:PostProcessAnimInstance

5)SkeletalMeshComp->FinalizePoseEvaluationResult

计算TArray& OutBoneSpaceTransforms

将压缩骨骼索引(CompactBoneIndex)转为网格骨骼索引(MeshBoneIndex)

注:三种骨骼索引:CompactBoneIndex、MeshBoneIndex、SkeletalBoneIndex输出FVector& OutRootBoneTranslation:RootBone相对位移

6)SkeletalMeshComp->FillComponentSpaceTransforms

获取平移、旋转、缩放向量,以更新每个骨骼的姿势矩阵

每个骨骼矩阵会从根骨骼开始逐个应用父骨的局部矩阵,即该函数输出的是一个全局姿势

OutComponentSpaceTransforms :AnimEvaluationContext.CachedComponentSpaceTransforms,最终输出的全局姿势矩阵

InBoneSpaceTransforms:由Evaluate计算的输入的关节姿势矩阵计算全局姿势

FTransform::Multiply(SpaceBase, LocalTransformsData + BoneIndex, ParentSpaceBase);

其中SpaceBase是OutTrans,LocalTransformData+BoneIndex是根据index索引的InTrans

Multiply(FTransform* OutTransform, const FTransform* A, const FTransform* B);

3. AnimNode流程

动画播放节点:FAnimNode_SequencePlayer

其中动画播放的具体逻辑在UAnimSequence对象

1)UAnimSequence->GetBonePose (FCompactPose& OutPose, FBlendedCurve& OutCurve, const FAnimExtractContext& ExtractionContext, bool bForceUseRawData=false) const;

初始化OutPose

根据设置,使用Retargeting Source的T-Pose,或者是自身的T-Pose数据,先初始化OutPoseEvaluateCurveData:提取曲线数据DecompressPose:解压压缩的动画数据,完成OutPose的计算

4. 参考资料

/4.27/zh-CN/AnimatingObjects/SkeletalMeshAnimation/Optimization

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。