0. 写在前面

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

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

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

1. SkeletalMeshComp流程

【AnimInstance】

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

SkeletalMeshComp中持有三种AnimInstance对象:

  • AnimScriptInstance:当前激活的动画蓝图对象
  • PostProcessAnimInstance
  • LinkedInstances

【入口】

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
      UpdateMontageEvaluationData
    • BlueprintUpdateAnimation,更新蓝图各种动画逻辑的入口,具体实现就是蓝图的动画树
    • 确定是否需要立即更新动画,如果不用立即更新动画的话,会由多线程调用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)
    • CacheBones
    • EvaluateAnimationNode_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数据,先初始化OutPose
  • EvaluateCurveData:提取曲线数据
  • DecompressPose:解压压缩的动画数据,完成OutPose的计算

4. 参考资料

https://docs.unrealengine.com/4.27/zh-CN/AnimatingObjects/SkeletalMeshAnimation/Optimization

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

  1. FreeSWITCH 1.10 源码阅读(3)-sofia 模块原理及其呼入处理流程

    文章目录 1. 前言 2. 源码分析 2.1 sofia 模块的加载 2.2 呼入的处理流程 1. 前言 SIP(Session Initiation Protocol) 是应用层的信令控制协议,有许 ...

  2. UE4源码阅读_骨骼模型与动画系统_Mesh

    写在前面 本文为个人学习的笔记整理,如有错误,望不吝指出. 1. Mesh数据 SkeletalMeshComponent中和骨骼模型相关的代码主要封装在USkeletalMesh类. USkelet ...

  3. UE4 源码阅读:从引擎启动到Receive Begin Play

    一.引擎主循环 UE版本:4.27 一.引擎主循环的位置: Launch.cpp : Guarded Main函数 二..Guarded Main函数执行逻辑: 1.EnginePreInit:加载大 ...

  4. 【Dubbo源码阅读系列】之远程服务调用(上)

    今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...

  5. android tcp socket框架_最流行的 Web 框架 Gin 源码阅读

    最近公司大部分项目开始往golang换, api的框架选定使用gin, 于是将 gin的源码看了一遍, 会用几篇文章将gin的流程及流程做一个梳理, 下面进入正题. gin框架预览 上图大概是 gin ...

  6. bert模型简介、transformers中bert模型源码阅读、分类任务实战和难点总结

    bert模型简介.transformers中bert模型源码阅读.分类任务实战和难点总结:https://blog.csdn.net/HUSTHY/article/details/105882989 ...

  7. 源码 状态机_[源码阅读] 阿里SOFA服务注册中心MetaServer(1)

    [源码阅读] 阿里SOFA服务注册中心MetaServer(1) 0x00 摘要 0x01 服务注册中心 1.1 服务注册中心简介 1.2 SOFARegistry 总体架构 1.3 为什么要分层 0 ...

  8. 【Flink】Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型

    1.概述 转载:Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型 相似文章:[Flink]Flink 基于 MailBox 实现的 StreamTask 线程模型 Fl ...

  9. 基于lis3dh的简易倾角仪c源码_开源网关apisix源码阅读和最佳实践

    大家应该都接手过这种项目,前人找一个开源软件改一改,发上线. 我这里便曾经遇到过类似的问题. 随着需求的增加,各种维护人员东改改西改改,原来的开源项目被改的面目全非,再也无法和上游合并. 甚至TLS协 ...

最新文章

  1. typedef和define具体的详细区别
  2. python与人工智能编程-最适合人工智能开发的5种编程语言,你知道几种?
  3. 三大趋势在移动互联网发展
  4. 转: 关于流量控制与令牌桶介绍
  5. 云耀云服务器性能怎么样,华为云测评:2CPU+4G内存+5M带宽的云耀云服务器HECS
  6. 每秒570000的写入,MySQL如何实现?
  7. centos7 二进制安装mysql,Centos7 二进制安装mysql5.7
  8. 一个页面可以重复调用的TAB选项卡切换js代码 鼠标悬浮
  9. 五个 PostgreSQL 典型故障案例及处理
  10. Javascript心得(一) Javascript数据类型
  11. 工程实践线切割3B代码参考
  12. 记某众测存储型xss漏洞小tips
  13. 人脑VS机器? AI时代经济决策的机遇与挑战?
  14. Solution of ZOJ 2748 Free Kick
  15. 将Macbook的光驱位升级成SSD
  16. 小学生组词词典 官方
  17. 杰里之104X之输出 3 路 PMW【篇】
  18. 【Nodejs】Http模块01
  19. 【netcore】MiniExcel轻量级开源组件使用
  20. 100天精通Andriod逆向——第3天:真机环境配置

热门文章

  1. Android APK打包流程
  2. Java开发和测试开发面试杂记
  3. Oracle错误——归档日志已满问题
  4. 西安交通大学大计基第十四周练习题
  5. 替换加密(恺撒加密法)
  6. 网易工程师亲历:一次sql缺少where条件的惨案…
  7. bootStrap 教程 文档
  8. 从某一点出发沿任意一方向旋转矩阵计算思考与实现
  9. 【Linux】exec()系列函数——execl(),execlp(),execle()等的区别
  10. tabindex,role属性