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

103 lines
5.0 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;
{
// 计算Source的旋转偏差值
const FQuat RotationDelta = Source.CurrentRotation * Source.InitialRotation.Inverse();
// 将偏移加到Target上
const FQuat RetargetedRotation = RotationDelta * Target.InitialRotation;
// 将RetargetSetting上的旋转偏差值加上。
Rotation = RetargetedRotation * Settings.RotationOffset.Quaternion();
Rotation = FQuat::FastLerp(Target.InitialRotation, Rotation, Settings.RotationAlpha);
Rotation.Normalize();
// 记录Target的旋转偏差值
Target.RootRotationDelta = RetargetedRotation * Target.InitialRotation.Inverse();
}
// 将数据应用到根骨骼上
FTransform& TargetRootTransform = OutTargetGlobalPose[Target.BoneIndex];
TargetRootTransform.SetTranslation(Position);
TargetRootTransform.SetRotation(Rotation);
```
## RunFKRetarget()
遍历所有骨骼链并执行FChainEncoderFK::EncodePose()与FChainDecoderFK::DecodePose()。
FChainEncoderFK::EncodePose()
1. 遍历所有骨骼链根据骨骼链Index得到BoneIndex之后将对应骨骼的WorldSpace Transform赋予到对应骨骼链Index的CurrentGlobalTransforms中。
2. Resize CurrentLocalTransforms其长度与SourceBoneIndices相同。
3. FillTransformsWithLocalSpaceOfChain()
1. 遍历所有骨骼链取得对应骨骼的Index以及父骨骼Index。跳过根骨骼
2. 计算相对Transform后放入对应ChainIndex的OutLocalTransforms中。
4. 根据ChainParentBoneIndex将父骨骼Transform赋予给ChainParentCurrentGlobalTransform。
FChainDecoderFK::DecodePose()