0. 写在前面
本文为个人学习的笔记整理,如有错误,望不吝指出。
1. 动画播放:FAnimNode_SequencePlayer
相关参数:
- UAnimSequenceBase Sequence:动画片段
- PlayRateBasis:播放速率基数,被PlayRate除
- PlayRate:播放速率,可以是负数,表示反向播
- PlayRateScaleBiasClamp:对PlayRate额外的处理(缩放,偏移和Clamp),在除Basis后操作
- StartPosition:该动画节点的启动位置
- bLoopAnimation:是否循环动画
1.1 UAnimSequence
继承自UAnimSequenceBase,保存动画序列的关键帧数据,并包含若干个轨道数据
1.主要数据:
TArray RawAnimationData; 原始未压缩的动画关键帧数据
TArray SourceRawAnimationData; RawAnimationData的复件,只在初始化时被修改
Struct FRawAnimSequenceTrack:单个关键帧数据,包含平移、旋转和缩放。
TArray<FVector> PosKeys; TArray<FQuat> RotKeys; TArray<FVector> ScaleKeys;
2.资源设置
a. Compression Set:动画压缩设置
详细内容见动画压缩篇
b. Addtive Set:叠加设置
- TEnumAsByte AdditiveAnimType; 叠加动画的类型
AAT_None
AAT_LocalSpaceBase 基于局部关节空间
AAT_RotationOffsetMeshSpace 旋转基于模型空间,平移基于局部关节空间 - TEnumAsByte RefPoseType; 基础姿势的类型
ABPT_None UMETA(DisplayName = “None”),
ABPT_RefPose UMETA(DisplayName = “Skeleton Reference Pose”),
ABPT_AnimScaled UMETA(DisplayName = “Selected animation scaled”),
ABPT_AnimFrame UMETA(DisplayName = “Selected animation frame”),
c. RootMotion Set
3.主要函数 【TODO】
- GetAnimationPose
- GetBonePose
- AnimCompressionTypes:: DecompressPose
- GetBonePose_Additive
2. RootMotion
2.1 RootMotionMontage
UAnimMontage:
1.ExtractRootMotionFromTrackRange:从Montage动画轨道中的一定范围内提取RootMotion数据
-
ExtractRootMotionFromTrack:
StartTrackPosition、EndTrackPosition:
从指定的开始时间到结束时间提取Montage内的RootMotion数据,最后输出到FRootMotionMovementParams对象 -
GetRootMotionExtractionStepsForTrackRange:
由于一个Montage的动画轨道可能由多个动画序列组成,所以按照逐动画序列的方式提取RootMotion数据,存在TArray中。
FRootMotionExtractionStep:其中存着一个动画序列(UAnimSequence)和提取RootMotion数据的范围(开始位置和结束位置)
可能会遇到回环播放的情况(StartTrackPosition>EndTrackPosition),需要按正确的顺序提取。
如果是回环播放,该动画轨道有多个动画序列的情况下需要从末位往前遍历。
否则就正常按顺序遍历动画序列列表。
-
FAnimSegment::GetRootMotionExtractionStepsForTrackRange
检查起始时间和结束时间是否落在该动画序列范围内,如果是的话加入到Step列表 -
ExtractRootMotionFromTrack:
- 计算完Step动画集合后,遍历Step
- 判断其中的动画是否开启了RootMotion。
- 对于开启RootMotion的Step(AnimSequence)
调用AnimSequence->ExtractRootMotionFromRange提取位移数据
FTransform StartTransform = ExtractRootTrackTransform(StartTrackPosition, NULL);
FTransform EndTransform = ExtractRootTrackTransform(EndTrackPosition, NULL);
=》UAnimSequence::GetBoneTransform
=》AnimEncodingLegacyBase::GetBoneAtom 最后调到该接口提取
-
然后将提取后的位移数据(DeltaTransform)存到FRootMotionMovementParams对象中
RootMotion.Accumulate(DeltaTransform),该函数是不输入权重的,直接1比1的融合出最终位移
2.2 RootMotion Anim
FAnimInstanceProxy::TickAssetPlayerInstances:
当RootMotion模式为RootMotionFromEverything时,在该函数中,根据权重将RootMotion数据提取到FRootMotionMovementParams对象中
2.3 RootMotion应用和同步
见移动同步篇。
3. 动画叠加:FAnimNode_ApplyAdditive
1.主要变量:
FPoseLink Base: 连接base动画节点
FPoseLink Additive: 连接叠加动画节点
float Alpha: 叠加权重
2.主要接口:
- FAnimNode_ApplyAdditive::Evaluate_AnyThread
- 获取Base节点和叠加节点的两个动画姿势
Base.Evaluate(Output);
const bool bExpectsAdditivePose = true;
FPoseContext AdditiveEvalContext(Output, bExpectsAdditivePose);
Additive.Evaluate(AdditiveEvalContext); - 计算叠加后的结果姿势
FAnimationRuntime::AccumulateAdditivePose
- 获取Base节点和叠加节点的两个动画姿势
- FAnimationRuntime::AccumulateAdditivePose
- 根据叠加的类型,选择不同接口计算
局部空间叠加:AccumulateLocalSpaceAdditivePoseInternal
网格体空间叠加:AccumulateMeshSpaceRotationAdditiveToLocalPoseInternal - 如果是曲线动画
BaseCurve.Accumulate(AdditiveCurve, Weight);
- 根据叠加的类型,选择不同接口计算
- FAnimationRuntime::AccumulateLocalSpaceAdditivePoseInternal
- 遍历BasePose的每根骨骼:
根据叠加权重,对每根骨骼进行叠加计算
叠加权重为1时:
BasePose[BoneIndex].AccumulateWithAdditiveScale(AdditivePose[BoneIndex], VBlendWeight);
叠加权重小于1时:
FTransform Additive = AdditivePose[BoneIndex];
FTransform::BlendFromIdentityAndAccumulate(BasePose[BoneIndex], Additive, VBlendWeight);
- 遍历BasePose的每根骨骼:
- AccumulateWithAdditiveScale:计算叠加后的Rotation、Translation、Scale数据
Atom:要叠加的姿势数据- 处理旋转:旋转的叠加,用四元数乘法:
const VectorRegister BlendedRotation = VectorMultiply(Atom.Rotation, BlendWeight.Value);
Rotation = VectorQuaternionMultiply2(BlendedRotation, Rotation); - 处理平移:向量相加即可
const VectorRegister BlendedTranslation = VectorMultiply(Atom.Translation, BlendWeight.Value);
Translation = VectorAdd(Translation, BlendedTranslation); - 处理缩放:
Scale3D = Base_Scale3D * (Default + (Atom_Scale3D * wight))
- 处理旋转:旋转的叠加,用四元数乘法:
- BlendFromIdentityAndAccumulate:同样是计算叠加后的Rotation、Translation、Scale数据
- 平移和缩放的处理上面一致
虽然用的是Lerp,但(0,0,0)和Atom按Weight做插值,实际上就是Atom * Weight的结果
- 旋转的处理
- 平移和缩放的处理上面一致