BlueRoseNote/03-UnrealEngine/Animation/UE5动画重定向核心逻辑笔记.md

97 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: UE5动画重定向核心逻辑笔记
date: 2023-08-18 18:08:12
excerpt:
tags:
rating: ⭐
---
# 前言
最近研究过了一下UE的重定向逻辑所以写点笔记作为记录。IK部分没有去看
- FIKRetargetBatchOperation::RunRetarget()编辑器调用的重定向函数。主要是复制对应需要重定向资产并且进行重定向之后通知UI。
- FIKRetargetBatchOperation::RetargetAssets():重定向资产逻辑。
- 复制所有曲线轨道(不含数值)。
- 设置Skeleton与PreviewMesh资产。
- 提前调用重定向资产的PostEditChange(),以避免编辑后钩子函数被调用,产生依赖顺序问题。
- ConvertAnimation()
- 替换动画蓝图并且编译。
# ConvertAnimation()
一开始是一些初始化逻辑主要的是调用UIKRetargetProcessor的Initialize()。里面初始化了
- SourceSkeleton & TargetSkeleton用于重定向计算用的数据载体存储了骨骼链、骨骼、当前重定向Pose等数据。
- RootRetargeter根骨骼重定向器。
- ChainPairsIK、ChainPairsFK用于FK与IK的骨骼链数据。
- UIKRigProcessorIK重定向处理器。
- 所有FIKRigGoal
从FRetargetSkeleton& SourceSkeleton & FTargetSkeleton& TargetSkeleton获取对应参数来进行之后的动画资产重定向循环循环逻辑如下
- 获取动画帧数,并且重新构建骨骼动画数据轨道。
- 取得速度曲线。
- 之后对每一帧Pose进行重定向主要是的逻辑是
- 取得当前帧Pose并将其转化WorldSpace。
- UIKRetargetProcessor Processor->RunRetargeter()
- 将重定向完的结果转化成LocalSpace并且将每个骨骼的数据放入对应骨骼动画数据轨道。
- 调用IAnimationDataController的AddBoneTrack() & SetBoneTrackKeys()给资产设置上关键帧。
# RunRetargeter()
此为核心重定向逻辑分为RunRootRetarget()、RunFKRetarget()、RunIKRetarget()、RunPoleVectorMatching()。
重定向数据会直接修改TargetSkeleton的Pose数据。Root与FK重定向执行完之后会调用UpdateGlobalTransformsBelowBone()更新后续骨骼的WorldSpace Transform。
## RunRootRetarget()
FRootRetargeter::EncodePose():
取得输入的根骨骼Transform数据并给`FRootSource Source`赋值。
FRootRetargeter::DecodePose():
```c++
FVector Position;
{
// 关键InitialTransform 为重定向Pose计算出的数值通过比值计算出Target的Current数值
const FVector RetargetedPosition = Source.CurrentPositionNormalized * Target.InitialHeight;
// 根据RetargetSetting中设置的BlendToSourceWeights与BlendToSource与SourcePosition进行混合。
Position = FMath::Lerp(RetargetedPosition, Source.CurrentPosition, Settings.BlendToSource*Settings.BlendToSourceWeights);
// 应用vertical / horizontal的缩放
FVector ScaledRetargetedPosition = Position;
ScaledRetargetedPosition.Z *= Settings.ScaleVertical;
const FVector HorizontalOffset = (ScaledRetargetedPosition - Target.InitialPosition) * FVector(Settings.ScaleHorizontal, Settings.ScaleHorizontal, 1.0f);
Position = Target.InitialPosition + HorizontalOffset;
// 应用RetargetSetting中Position偏移。
Position += Settings.TranslationOffset;
// blend with alpha
Position = FMath::Lerp(Target.InitialPosition, Position, Settings.TranslationAlpha);
// 记录偏差
Target.RootTranslationDelta = Position - RetargetedPosition;
}
FQuat Rotation;
{
// calc offset between initial source/target root rotations
const FQuat RotationDelta = Source.CurrentRotation * Source.InitialRotation.Inverse();
// add retarget pose delta to the current source rotation
const FQuat RetargetedRotation = RotationDelta * Target.InitialRotation;
// add static rotation offset
Rotation = RetargetedRotation * Settings.RotationOffset.Quaternion();
// blend with alpha
Rotation = FQuat::FastLerp(Target.InitialRotation, Rotation, Settings.RotationAlpha);
Rotation.Normalize();
// record the delta created by all the modifications made to the root rotation
Target.RootRotationDelta = RetargetedRotation * Target.InitialRotation.Inverse();
}
// apply to target
FTransform& TargetRootTransform = OutTargetGlobalPose[Target.BoneIndex];
TargetRootTransform.SetTranslation(Position);
TargetRootTransform.SetRotation(Rotation);
```
## RunFKRetarget()
FChainEncoderFK::EncodePose():
从骨骼链拷贝全局输入到CurrentGlobalTransforms
FChainDecoderFK::DecodePose():