UE4源码阅读_骨骼模型与动画系统_动画流程
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):
- FParallelAnimationEvaluationTask:该Task调用ParallelAnimationEvaluation
- SwapEvaluationContextBuffers:
2. AnimInstance&&Proxy流程
【游戏线程】
前面说到SkeletalMeshComp会调AnimInstance的UpdateAnimation接口处理该动画蓝图在游戏线程计算的逻辑。
- UpdateAnimation
- 在动画节点逻辑更新前先更新Montage
UpdateMontage(DeltaSeconds)
UpdateMontageSyncGroup
UpdateMontageEvaluationData - BlueprintUpdateAnimation,更新蓝图各种动画逻辑的入口,具体实现就是蓝图的动画树
- 确定是否需要立即更新动画,如果不用立即更新动画的话,会由多线程调用Proxy进行并行计算
const bool bWantsImmediateUpdate = bNeedsValidRootMotion || NeedsImmediateUpdate(DeltaSeconds);
如果需要立即更新,如RootMotion无法并行计算,则在该函数下调用更新接口
ParallelUpdateAnimation();
PostUpdateAnimation();
- 在动画节点逻辑更新前先更新Montage
【多线程】
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的AnimEvaluationContextFPoseContext 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源码阅读_骨骼模型与动画系统_动画流程相关推荐
- FreeSWITCH 1.10 源码阅读(3)-sofia 模块原理及其呼入处理流程
文章目录 1. 前言 2. 源码分析 2.1 sofia 模块的加载 2.2 呼入的处理流程 1. 前言 SIP(Session Initiation Protocol) 是应用层的信令控制协议,有许 ...
- UE4源码阅读_骨骼模型与动画系统_Mesh
写在前面 本文为个人学习的笔记整理,如有错误,望不吝指出. 1. Mesh数据 SkeletalMeshComponent中和骨骼模型相关的代码主要封装在USkeletalMesh类. USkelet ...
- UE4 源码阅读:从引擎启动到Receive Begin Play
一.引擎主循环 UE版本:4.27 一.引擎主循环的位置: Launch.cpp : Guarded Main函数 二..Guarded Main函数执行逻辑: 1.EnginePreInit:加载大 ...
- 【Dubbo源码阅读系列】之远程服务调用(上)
今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...
- android tcp socket框架_最流行的 Web 框架 Gin 源码阅读
最近公司大部分项目开始往golang换, api的框架选定使用gin, 于是将 gin的源码看了一遍, 会用几篇文章将gin的流程及流程做一个梳理, 下面进入正题. gin框架预览 上图大概是 gin ...
- bert模型简介、transformers中bert模型源码阅读、分类任务实战和难点总结
bert模型简介.transformers中bert模型源码阅读.分类任务实战和难点总结:https://blog.csdn.net/HUSTHY/article/details/105882989 ...
- 源码 状态机_[源码阅读] 阿里SOFA服务注册中心MetaServer(1)
[源码阅读] 阿里SOFA服务注册中心MetaServer(1) 0x00 摘要 0x01 服务注册中心 1.1 服务注册中心简介 1.2 SOFARegistry 总体架构 1.3 为什么要分层 0 ...
- 【Flink】Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型
1.概述 转载:Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型 相似文章:[Flink]Flink 基于 MailBox 实现的 StreamTask 线程模型 Fl ...
- 基于lis3dh的简易倾角仪c源码_开源网关apisix源码阅读和最佳实践
大家应该都接手过这种项目,前人找一个开源软件改一改,发上线. 我这里便曾经遇到过类似的问题. 随着需求的增加,各种维护人员东改改西改改,原来的开源项目被改的面目全非,再也无法和上游合并. 甚至TLS协 ...
最新文章
- typedef和define具体的详细区别
- python与人工智能编程-最适合人工智能开发的5种编程语言,你知道几种?
- 三大趋势在移动互联网发展
- 转: 关于流量控制与令牌桶介绍
- 云耀云服务器性能怎么样,华为云测评:2CPU+4G内存+5M带宽的云耀云服务器HECS
- 每秒570000的写入,MySQL如何实现?
- centos7 二进制安装mysql,Centos7 二进制安装mysql5.7
- 一个页面可以重复调用的TAB选项卡切换js代码 鼠标悬浮
- 五个 PostgreSQL 典型故障案例及处理
- Javascript心得(一) Javascript数据类型
- 工程实践线切割3B代码参考
- 记某众测存储型xss漏洞小tips
- 人脑VS机器? AI时代经济决策的机遇与挑战?
- Solution of ZOJ 2748 Free Kick
- 将Macbook的光驱位升级成SSD
- 小学生组词词典 官方
- 杰里之104X之输出 3 路 PMW【篇】
- 【Nodejs】Http模块01
- 【netcore】MiniExcel轻量级开源组件使用
- 100天精通Andriod逆向——第3天:真机环境配置