向右拖动,降低缩放比例就能看到了。
USkeletalMeshComponent
有动画。
UAnimInstance
动画实例,动画蓝图的父类。
FAnimInstanceProxy
动画实例的代理。保存大量动画相关数据,例如AnimInstance,SkeletalMeshComponent,ComponentTransform等,同时分担动画蓝图的更新工作。此外也是使用多线程进行动画优化的核心
FAnimNode_Base
动画节点的基类。
USkeletalMeshComponent::TickAnimation
USkeletalMeshComponent::TickAnimInstances
先遍历了LinkedInstances列表并对它里头的每个动画实例调用了UpdateAnimation。这个列表LinkedAnimInstance是我们通过LinkAnimGraph动画节点链接上去的动画蓝图,可以作为独立的动画功能模块,根据需要使用,可动态插拔,在实际使用中更具灵活性。
然后对AnimScriptInstance调用了UpdateAnimation,这个实例是现在正在活动的动画实例。很多地方都用到了。
最后是对PostProcessAnimInstance动画实例(后处理动画蓝图)调用UpdateAnimation函数。
UAnimInstance::UpdateAnimation
UAnimInstance::UpdateMontage
遍历当前所有正在播放的Montage实例,逐个调用Montage实例的对应方法计算权重,完成同步组处理、动画播放、动画通知入队、分段衔接、混出、计算RootMotion等任务
UAnimInstance::Montage_UpdateWeight
UAnimInstance::Montage_Advance
FAnimMontageInstance::Advance
FMontageSubStepper::AddEvaluationTime()
FMontageSubStepper是一个辅助结构,用于实现蒙太奇的动画步进,跳跃,循环等功能。内含“是否正向播放”,“当前播放到第几节”“当前播放的小节的时间长度”“播放速率”等等成员变量。
FMontageSubStepper::Advance()
对蒙太奇中具体的动画序列进行步进
UAnimInstance::UpdateMontageSyncGroup
根据上一次更新的记录计算同步组的Leader
UAnimInstance::UpdateMontageEvaluationData
重置当前的记录在AnimInstanceProxy中的Montage计算数据,然后将上面几步MontageInstance更新后的数据记录在当前AnimInstanceProxy中,以便在后续的更新和动画计算阶段使用。
UAnimInstance::NativeUpdateAnimation
C++虚函数,继承UAnimInstance后即可覆写
UAnimInstance::BlueprintUpdateAnimation
在蓝图里覆写。这个就是我们最常用的“蓝图更新动画”函数。也就是说,蓝图更新动画函数中的值的更新,是要优先于节点中的值的更新的。
特地强调这一点是因为到了UE5中,动画图表的很多节点都可以绑定各种函数,对值进行计算。
UAnimInstance::ParallelUpdateAnimation
FAnimInstanceProxy::UpdateAnimation
这个函数也很重要,我们在动画蓝图的动画图表中链接的那些节点,都在这里进行了处理。
FAnimInstanceProxy::UpdateAnimation_WithRoot
FAnimInstanceProxy::CacheBones()
动画实例中的动画节点都是通过PoseLink连接起来,形成树状的结构,该方法会从动画实例中的RootNode开始,通过PoseLink逐一触发LinkedNode的CacheBones_AnyThread方法
UpdateAnimationNode_WithRoot
遍历缓存好骨骼姿势的节点,为它们调用PostGraphUpdate函数。
FAnimNode_SaveCachedPose::PostGraphUpdate
调用FPoseLink
在这个函数里会挨个尝试调用“初次更新时”“变得相关时”“更新时”这三个绑定的函数。UE5特有的。
FAnimNode_Base::Update_AnyThread
虚函数,可被覆写。在自定义动画节点时估计是要用到。
UAnimInstance::PostUpdateAnimation
FAnimInstanceProxy::PostUpdate
将待触发的动画通知添加到动画队列NotifyQueue中,打印动画Debug和日志信息,将Proxy中的RootMotion参数转交给AnimInstance保管,并根据动画Slot的权重对RootMotion数据再次进行计算。
USkeletalMeshComponent::DispatchParallelTickPose
USkeletalMeshComponent::DoTask
USkinnedMeshComponent
蒙皮的骨骼网格体,持有SkeletalMesh,但是没有动画。
优秀的解读文章推荐:https://blog.csdn.net/qq_23030843/article/details/109103433
FAnimNode_StateMachine::Update_AnyThread
动画状态机节点的更新函数
一个DoWhile循环,把状态机看成图,过渡条件就是边。通过遍历这张图找到所有可以通行的边。(但是是没有岔路的,一个状态节点只能通向另一个状态节点,不能通向多个)
先调用FindValidTransition函数,判断当前的这个状态节点有没有可通行的过渡条件。
如果有的话,就启动状态转换的通知,然后调用SetState函数更新上下文中存储的CurrentState
判断激活的过渡条件数量是否达到此帧上限,若达到了则退出循环
遍历激活了的过渡条件,调用它们的Update函数(比如更新一下混合的透明度,这个混合的透明度更新还会用到我们设置的混合曲线。)
判断每个过渡条件是否还没过渡完成,如果是的话则调用UpdateTransitionStates更新它连接的两个状态节点
FAnimNode_StateMachine::UpdateTransitionStates
为PrevState和NextState分别调用UpdateState函数。
FAnimNode_StateMachine::UpdateState
如果没有过渡条件被激活(没有过渡在进行),就只单纯地更新现在处于激活状态的那个状态节点StatePoseLinks[CurrentState].Update(Context);
FPoseLinkBase::Update
最后遍历所有的状态节点,调用GetStateWeight函数更新它们的权重。这个函数也会扫描已被激活的过渡条件数组,通过判断这个状态节点与激活了的过渡条件之间有无联系来决定具体的权重更新。
作者:知乎 DarkFlameMaster
https://www.zhihu.com/people/VanishmentThisWorld
更新的起点
USkeletalMeshComponent::TickComponent
USkinnedMeshComponent::TickComponent
骨骼网格体的基类,蒙皮网格体组件的Tick
USkinnedMeshComponent::TickPose
USkeletalMeshComponent::RefreshBoneTransforms
该函数在蒙皮网格体中是虚函数,到骨骼网格体中被实现了
USkeletalMeshComponent::DoInstancePreEvaluation
UAnimInstance::PreEvaluateAnimation
重点函数
FAnimInstanceProxy::PreEvaluateAnimation
UAnimInstance::ParallelEvaluation
FAnimInstanceProxy::InitializeObjects
这个方法会接受当前AnimInstance作为参数,拷贝缓存所有可能用到的对象,例如SkeletalMeshComponent、MainInstanceProxy、Skeleton等
先
USkeletalMeshComponent::TickAnimation
计算当前帧驱动动画的变量,收集动画通知、更新动画曲线值等
USkeletalMeshComponent::DoParallelEvaluationTasks_OnGameThread
后
USkeletalMeshComponent::ParallelAnimationEvaluation
根据UpdateAnimation计算后产生的控制变量,计算修改骨骼Transfrom
USkeletalMeshComponent::PerformAnimationProcessing
首先会调用AnimInstance和PostAnimInstance的UAnimInstance::ParallelUpdateAnimation方法来完成动画的并行Update,接下来处理正常运行中的动画计算,相比AnimInstance,PostAnimInstance会首先将主动画蓝图中的Pose、曲线、Attributes拷贝至InputNode中,通过InputNode,PostAnimInstance可以获取到AnimInstance最终的Pose,在此基础上计算新的Pose
USkeletalMeshComponent::EvaluatePostProcessMeshInstance
PostAnimInstance会首先将主动画蓝图中的Pose、曲线、Attributes拷贝至InputNode中,通过InputNode,PostAnimInstance可以获取到AnimInstance最终的Pose,在此基础上计算新的Pose。
USkeletalMeshComponent::EvaluateAnimation
UAnimInstance::ParallelEvaluateAnimation
重点函数
FAnimInstanceProxy::EvaluateAnimation
FAnimInstanceProxy::EvaluateAnimation_WithRoot
调用所有动画节点的CacheBones,缓存相应需要用到的骨骼信息
FAnimInstanceProxy::Evaluate_WithRoot
重写点。其中可以实现我们自己的动画计算逻辑。并且它的返回值将决定了是否调用动画节点原生的计算逻辑,即函数EvaluateAnimationNode_WithRoot
FAnimInstanceProxy::EvaluateAnimationNode_WithRoot
FAnimNode_Base::Evaluate_AnyThread
由不同的动画节点本身自己具体实现的函数,可被覆写。该节点也就是动画图表中层层FPoseLink递归链接的出入口了。
USkeletalMeshComponent::PostAnimEvaluation
USkeletalMeshComponent::DoInstancePostEvaluation
UAnimInstance::PostEvaluateAnimation
重点函数
FAnimInstanceProxy::PostEvaluate
UCharacterMovementComponent::TickComponent
调用USkeletalMeshComponent::TickPose
Super::TickPose