立即注册
登录
搜索
前端开发
后端开发
虚幻引擎
U3D引擎
体感研发
数据库
论坛
BBS
本版
帖子
用户
麒麟软控
»
论坛
›
麒麟软控
›
虚幻引擎
›
UE4 骨骼动画姿势提取过程源码浅析
返回列表
发新帖
UE4 骨骼动画姿势提取过程源码浅析
陈卓
陈卓
当前离线
积分
13
2
主题
7
帖子
13
积分
新手上路
新手上路, 积分 13, 距离下一级还需 37 积分
新手上路, 积分 13, 距离下一级还需 37 积分
积分
13
发消息
发表于 2023-3-10 13:37:11
|
显示全部楼层
前言:本文主要介绍UE4骨骼动画Pose的获取大致过程,文章不一定全部正确,如有错误欢迎指正。本文分析的源码对应引擎版本为UE4.26。
1.问题引入
我们知道骨骼动画是通过Pose姿势来表现的,那这个姿势究竟是什么?又是怎么计算得到的呢?
2.Pose姿势介绍
其实所谓的Pose就是一个Transform数组,存储着每个骨骼当帧的位置、旋转、缩放信息,有了Pose数据和蒙皮信息就能渲染出当帧模型的最终表现。
那这个Transform数组存在哪儿,每帧又是怎么更新的呢,答案是在USkeletalMeshComponent中:
BoneSpace:
如USkeletalMeshComponent类图如所示,BoneSpaceTransforms存储的是每个骨骼的本地Transform信息,也就是相对于父骨骼的相对坐标,在预览界面其实就是如下的值:
ComponentSpace:
ComponentSpaceTransformsArray存储的是每个骨骼的组件Transform信息,也就是游戏里相对于SkeletalMeshComponent的Transform,也可以理解为以 root所在的坐标系为原点,每个骨骼在这个坐标系下的Transform。(注意不是相对于root,举个例子root坐标为(0,0,20),pelvis骨骼相对root为(0,0,50),那么pelvis的Component坐标就为(0,0,70)),在预览界面其实就是如下的值:
另外ComponentSpaceTransformsArray数组是两份数据,一份只读一份可写,USkinnedMeshComponent提供了几个函数用于获取只读的、可写的ComponentSpaceTransforms:
3.姿势提取过程
接下来我们来看下这些骨骼数据的提取过程。
如上面类图所示,在USkeletalMeshComponent上还有一个AnimEvaluationContext成员
这个结构也有一份ComponentSpaceTransforms和BoneSpaceTransforms,在进入Evaluate提取姿势之前,会先执行一次USkeletalMeshComponent::SwapEvaluationContextBuffers:
那这里交换两份数据的意义是什么呢,笔者的理解是:动画更新存在多线程执行,两份buffer骨骼数据的设计是为了避免线程冲突等问题,在动画线程上就访问AnimEvaluationContext成员来更新骨骼姿势,在主线程就访问USkeletalMeshComponent上的Transform数据。
在骨骼姿势提取到AnimEvaluationContext里面后,会再次调用SwapEvaluationContextBuffers函数来把最新骨骼tranfrom信息又交换回USkeletalMeshComponent上的tranform数据里。
即对于多线程动画更新:
// 进入动画线程前交互数据
USkeletalMeshComponent::DispatchParallelEvaluationTasks
USkeletalMeshComponent::SwapEvaluationContextBuffers
// 在动画线程更新AnimEvaluationContext数据
USkeletalMeshComponent::ParallelAnimationEvaluation
// 完成动画更新回到主线程再次交互数据
USkeletalMeshComponent::CompleteParallelAnimationEvaluation
USkeletalMeshComponent::SwapEvaluationContextBuffers
对于主线程动画更新:
USkeletalMeshComponent::DoParallelEvaluationTasks_OnGameThread
// 交互数据
USkeletalMeshComponent::SwapEvaluationContextBuffers
// 更新AnimEvaluationContext数据
USkeletalMeshComponent::ParallelAnimationEvaluation
// 再次交互数据
USkeletalMeshComponent::SwapEvaluationContextBuffers
3.1 提取BoneSpaceTransform
在执行第一次交换后,在ParallelAnimationEvaluation函数就会更新AnimEvaluationContext数据:
USkeletalMeshComponent::ParallelAnimationEvaluation
USkeletalMeshComponent::PerformAnimationProcessing:
如代码所示,首先创建FCompactPose临时对象EvaluatedPose,通过EvaluateAnimation函数将骨骼信息提到此对象中:
也就是获取名为Bones的FTransform数组,这个数组存的是每个骨骼的BoneSpace数据。
以一个动画序列的RawData(原始数据)提取过程为例,首先动画序列上有如下数据:
RawAnimationData数组的每个元素代表每个骨骼信息,具体信息包括起始帧到末尾帧的位置、旋转、缩放等;
TrackToSkeletonMapTable为RawAnimationData的元素下标所对应的BoneTreeIndex。
以UE自带的第三人称Walk动画资源为例,以上两个数组成员的元素下标均是按骨骼从上往下排列(仅供参考,不代表所有情况):
提取动画序列的上的姿势过程如下:
USkeletalMeshComponent::EvaluateAnimation
...
FAnimNode_SequencePlayer::Evaluate_AnyThread
...
BuildPoseFromRawDataInternal:
遍历RawAnimationData数组元素,根据TrackIndex下标通过TrackToSkeletonMapTable映射得到SkeletonBoneIndex,再通过FBoneContainer的SkeletonToCompactPose映射得到PoseBoneIndex:
FCompactPoseBoneIndex PoseBoneIndex正是我们需要获取的FCompactPose对象中Bones数组的元素下标,接着就对骨骼Bones数组元素进行更新来提取我们最终的Pose:
将姿势提取到FCompactPose EvaluatedPose对象后,USkeletalMeshComponent会调用FinalizePoseEvaluationResult函数将姿势应用到AnimEvaluationContext的BoneSpaceTransforms数组中:
会先通过FBoneContainer的BoneIndicesArray将FCompactPoseBoneIndex转换成FMeshPoseBoneIndex:
然后再通过MeshPoseIndex下标根据FCompactPose中的骨骼位置等信息对BoneSpaceTransforms数组进行填充。
3.2 计算ComponentSpaceTransform
前文提到,BoneSpace是每个骨骼相对父骨骼的,ComponentSpace是每个骨骼相对root所在坐标系的,所以有了BoneSpaceTransforms就可以计算得到ComponentSpaceTransforms数据。这一步是在FillComponentSpaceTransforms函数中处理:
USkeletalMeshComponent::FillComponentSpaceTransforms:
root骨骼排在数组第一个元素,因为没有父骨骼,所以ComponentSpace和BoneSpace都是一致的,所以直接赋值:
然后按骨骼链依次计算,当前骨骼的ComponentSpace信息就等于当前骨骼的BoneSpaceTransform相对于父骨骼ComponentSpaceTransform后的结果(因为按骨骼链计算能保证父骨骼先算,如有了root就能计算出pelvis,有了pelvis就能计算出spine_01):
至此,骨骼数组信息即姿势就提取到了AnimEvaluationContext中,最后就是执行上面提到的SwapEvaluationContextBuffers操作来把数据交换给USkeletalMeshComponent上的tranform数据里:
本文旨在交流学习,同时方便自己在实际开发中随时查阅笔记。感谢阅览,如有疏漏错误之处还望批评指正!
上一篇:
UE4学习笔记(一)安装与初见
下一篇:
扯电线,做绳子很烦?试试这款虚幻引擎的自动插件Tether ...
回复
举报
使用道具
分享
熊保柱
熊保柱
当前离线
积分
3
1
主题
3
帖子
3
积分
新手上路
新手上路, 积分 3, 距离下一级还需 47 积分
新手上路, 积分 3, 距离下一级还需 47 积分
积分
3
发消息
发表于 2023-3-10 13:37:49
|
显示全部楼层
刚点进来就爆炸了
回复
举报
使用道具
档下灬很忧郁
档下灬很忧郁
当前离线
积分
8
2
主题
8
帖子
8
积分
新手上路
新手上路, 积分 8, 距离下一级还需 42 积分
新手上路, 积分 8, 距离下一级还需 42 积分
积分
8
发消息
发表于 2023-3-10 13:38:27
|
显示全部楼层
坤味太重,律师函警告
回复
举报
使用道具
返回列表
发新帖
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
快速回复
返回顶部
返回列表