BlueRoseNote/03-UnrealEngine/Animation/UE5动画重定向 & FBX文件格式.md

304 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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: ⭐
---
# ConvertAnimation()
主要逻辑位于`UAnimationEditorUtilityLibrary::ConvertAnimation()`或者`FIKRetargetBatchOperation::ConvertAnimation()`。核心重定向逻辑为`UIKRetargetProcessor::RunRetargeter()`
## RunRootRetarget()
FRootRetargeter::EncodePose():
取得输入的根骨骼Transform数据并给`FRootSource Source`赋值。
FRootRetargeter::DecodePose():
```c++
// InitialTransform 为重定向Pose计算出的数值通过比值计算出Target的Current数值
const FTransform InitialTransform = SourceSkeleton.RetargetGlobalPose[Source.BoneIndex];
float InitialHeight = InitialTransform.GetTranslation().Z;
Source.InitialHeightInverse = 1.0f / InitialHeight;
Source.CurrentPositionNormalized = Source.CurrentPosition * Source.InitialHeightInverse;
// generate basic retarget root position by scaling the normalized position by root height
const FVector RetargetedPosition = Source.CurrentPositionNormalized * Target.InitialHeight;
```
## RunFKRetarget()
FChainEncoderFK::EncodePose():
从骨骼链拷贝全局输入到CurrentGlobalTransforms
FChainDecoderFK::DecodePose():
## RunIKRetarget()
## RunPoleVectorMatching()
# UIKRetargetProcessor
# FBX SDK setup for Qt
https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_welcome_to_the_fbx_sdk_html
使用之前建议**仔细查看文档**。FBX Sdk有三种库分别为动态链接库(dll + lib)、静态链接库(/MD)、静态链接库(/MT)。
- 动态链接库使用Qt的导入库功能导入动态库之后只需要再添加一行`DEFINES += FBXSDK_SHARED`即可。例如:
```qmake
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
DEFINES += FBXSDK_SHARED
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
Common/Common.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
Common/Common.h \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/FBXSdk/lib/vs2022/x64/release/ -llibfbxsdk
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/FBXSdk/lib/vs2022/x64/debug/ -llibfbxsdk
INCLUDEPATH += $$PWD/FBXSdk/lib/vs2022/x64/debug
DEPENDPATH += $$PWD/FBXSdk/lib/vs2022/x64/debug
INCLUDEPATH += $$PWD/FBXSdk/include
```
- 静态链接库(/MD)使用Qt的导入库功能导入静态库之后
- 静态链接库(/MT)使用Qt的导入库功能导入静态库之后
## Qt相关设置添加
https://blog.csdn.net/libaineu2004/article/details/105718847
Qt在pro中设置运行时库MT、MTd、MD、MDd重点关注QMAKE_CFLAGS
多线程调试Dll (/MDd) 对应的是MD_DynamicDebug
多线程Dll (/MD) 对应的是MD_DynamicRelease
多线程(/MT) 对应的是MD_StaticRelease
多线程(/MTd)对应的是MD_StaticDebug
##  /NODEFAULTLIB:library
```cpp
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../LIBRARYNAME/Lib/ -lLIBRARY /NODEFAULTLIB:library
```
## Ubuntu安装需要额外安装Qt
```cpp
sudo apt install --reinstall libgl-dev
```
# FBX结构
![](https://help.autodesk.com/cloudhelp/2020/ENU/FBX-Developer-Help/images/scene_org.png)
FBX SDK场景图是通过`FbxScene`类抽象出来的。场景被组织为节点层次结构 ( `FbxNode`)。场景的根节点通过 访问`FbxScene::GetRootNode()`。场景元素(例如网格、灯光或相机)是通过将`FbxNode`与 的子类组合来定义的`FbxNodeAttribute`。
使用Ansii方式输出就可以使用vscode直接查看内部数据结构。
- GlobalMaterial世界坐标矩阵
- LocalMaterial相对空间矩阵
## 动画
- 动画堆栈 ( `FbxAnimStack`):动画数据最顶层容器,每一个**AnimStack**可以视为一个镜头,包含多个**FbxAnimLayer**。
- 动画层 ( `FbxAnimLayer`):每个**AnimLayer**中可以包含多个**FbxAnimCurve**。
- 动画曲线节点 ( `FbxAnimCurveNode`)
- 动画曲线 ( `FbxAnimCurve`) 动画以曲线的方式存在。可以针对骨骼的Location、Rotation分别添加曲线。
- 动画曲线关键点 ( `FbxAnimCurveKey`):动画关键帧。
每个动画数据都存在对应的节点的属性中Maya中可以给Shape的属性K帧可以通过类似`lAnimCurve = pNode->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y);`的方式取得动画曲线。
UE导出的FBX相关属性为
```json
AnimationStack: 1767515526080, "AnimStack::Unreal Take", "" {
Properties70: {
P: "Description", "KString", "", "", "Animation Take for Unreal."
P: "LocalStop", "KTime", "Time", "",183205094709
}
}
AnimationLayer: 1770224712128, "AnimLayer::Base Layer", "" {
}
NodeAttribute: 1767517959504, "NodeAttribute::Root", "Root" {
TypeFlags: "Null", "Skeleton", "Root"
}
NodeAttribute: 1767517960848, "NodeAttribute::Pelvis", "LimbNode" {
TypeFlags: "Skeleton"
}
NodeAttribute: 1767517959696, "NodeAttribute::L_Hip", "LimbNode" {
TypeFlags: "Skeleton"
}
NodeAttribute: 1767517960080, "NodeAttribute::L_Knee", "LimbNode" {
TypeFlags: "Skeleton"
}
AnimationCurve: 1770213770432, "AnimCurve::", "" {
Default: 0
KeyVer: 4009
KeyTime: *120 {
a: 0,1539538600,3079077200,4618615800,6158154400,7697693000,9237231600,10776770200,12316308800,13855847400,15395386000,16934924600,18474463200,20014001800,21553540400,23093079000,24632617600,26172156200,27711694800,29251233400,30790772000,32330310600,33869849200,35409387800,36948926400,38488465000,40028003600,41567542200,43107080800,44646619400,46186158000,47725696600,49265235200,50804773800,52344312400,53883851000,55423389600,56962928200,58502466800,60042005400,61581544000,63121082600,64660621200,66200159800,67739698400,69279237000,70818775600,72358314200,73897852800,75437391400,76976930000,78516468600,80056007200,81595545800,83135084400,84674623000,86214161600,87753700200,89293238800,90832777400,92372316000,93911854600,95451393200,96990931800,98530470400,100070009000,101609547600,103149086200,104688624800,106228163400,107767702000,109307240600,110846779200,112386317800,113925856400,115465395000,117004933600,118544472200,120084010800,121623549400,123163088000,124702626600,126242165200,127781703800,129321242400,130860781000,132400319600,133939858200,135479396800,137018935400,138558474000,140098012600,141637551200,143177089800,144716628400,146256167000,147795705600,149335244200,150874782800,152414321400,153953860000,155493398600,157032937200,158572475800,160112014400,161651553000,163191091600,164730630200,166270168800,167809707400,169349246000,170888784600,172428323200,173967861800,175507400400,177046939000,178586477600,180126016200,181665554800,183205093400
}
KeyValueFloat: *120 {
a: -0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0,-0
}
;KeyAttrFlags: Cubic|TangeantAuto|GenericTimeIndependent, Constant|ConstantStandard
KeyAttrFlags: *2 {
a: 8456,8194
}
;KeyAttrDataFloat: RightAuto:0, NextLeftAuto:0; RightSlope:0, NextLeftSlope:0, RightWeight:0.333333, NextLeftWeight:0.333333, RightVelocity:0, NextLeftVelocity:0
KeyAttrDataFloat: *8 {
a: 0,0,218434821,0,0,0,218434821,0
}
KeyAttrRefCount: *2 {
a: 119,1
}
}
AnimationCurve: 1770213768992, "AnimCurve::", "" {
Default: 0
KeyVer: 4009
KeyTime: *120 {
a: 0,1539538600,3079077200,4618615800,6158154400,7697693000,9237231600,10776770200,12316308800,13855847400,15395386000,16934924600,18474463200,20014001800,21553540400,23093079000,24632617600,26172156200,27711694800,29251233400,30790772000,32330310600,33869849200,35409387800,36948926400,38488465000,40028003600,41567542200,43107080800,44646619400,46186158000,47725696600,49265235200,50804773800,52344312400,53883851000,55423389600,56962928200,58502466800,60042005400,61581544000,63121082600,64660621200,66200159800,67739698400,69279237000,70818775600,72358314200,73897852800,75437391400,76976930000,78516468600,80056007200,81595545800,83135084400,84674623000,86214161600,87753700200,89293238800,90832777400,92372316000,93911854600,95451393200,96990931800,98530470400,100070009000,101609547600,103149086200,104688624800,106228163400,107767702000,109307240600,110846779200,112386317800,113925856400,115465395000,117004933600,118544472200,120084010800,121623549400,123163088000,124702626600,126242165200,127781703800,129321242400,130860781000,132400319600,133939858200,135479396800,137018935400,138558474000,140098012600,141637551200,143177089800,144716628400,146256167000,147795705600,149335244200,150874782800,152414321400,153953860000,155493398600,157032937200,158572475800,160112014400,161651553000,163191091600,164730630200,166270168800,167809707400,169349246000,170888784600,172428323200,173967861800,175507400400,177046939000,178586477600,180126016200,181665554800,183205093400
}
KeyValueFloat: *120 {
a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}
;KeyAttrFlags: Cubic|TangeantAuto|GenericTimeIndependent, Constant|ConstantStandard
KeyAttrFlags: *2 {
a: 8456,8194
}
;KeyAttrDataFloat: RightAuto:0, NextLeftAuto:0; RightSlope:0, NextLeftSlope:0, RightWeight:0.333333, NextLeftWeight:0.333333, RightVelocity:0, NextLeftVelocity:0
KeyAttrDataFloat: *8 {
a: 0,0,218434821,0,0,0,218434821,0
}
KeyAttrRefCount: *2 {
a: 119,1
}
}
```
添加动画关键帧的方式
```c++
FbxAnimCurve* lCurve = lRoot->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
if (lCurve)
{
lCurve->KeyModifyBegin();
lTime.SetSecondDouble(0.0);
//添加时间
lKeyIndex = lCurve->KeyAdd(lTime);
//添加数值与插值模式
lCurve->KeySetValue(lKeyIndex, 0.0);
lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
lTime.SetSecondDouble(1.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 45.0);
lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
lTime.SetSecondDouble(2.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, -45.0);
lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
lTime.SetSecondDouble(3.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 0.0);
lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
lCurve->KeyModifyEnd();
}
```
### BindPose
遍历所有节点并对取得GlobalTransform矩阵最后添加到Pose里。
```c++
// Now create a bind pose with the link list
if (lClusteredFbxNodes.GetCount())
{
// A pose must be named. Arbitrarily use the name of the patch node.
FbxPose* lPose = FbxPose::Create(pScene,pPatch->GetName());
// default pose type is rest pose, so we need to set the type as bind pose
lPose->SetIsBindPose(true);
for (i=0; i<lClusteredFbxNodes.GetCount(); i++)
{
FbxNode* lKFbxNode = lClusteredFbxNodes.GetAt(i);
FbxMatrix lBindMatrix = lKFbxNode->EvaluateGlobalTransform();
lPose->Add(lKFbxNode, lBindMatrix);
}
// Add the pose to the scene
pScene->AddPose(lPose);
}
```
### ResetPose
```c++
void StoreRestPose(FbxScene* pScene, FbxNode* pSkeletonRoot)
{
// This example show an arbitrary rest pose assignment.
// This rest pose will set the bone rotation to the same value
// as time 1 second in the first stack of animation, but the
// position of the bone will be set elsewhere in the scene.
FbxString lNodeName;
FbxNode* lKFbxNode;
FbxMatrix lTransformMatrix;
FbxVector4 lT,lR,lS(1.0, 1.0, 1.0);
// Create the rest pose
FbxPose* lPose = FbxPose::Create(pScene,"A Bind Pose");
// Set the skeleton root node to the global position (10, 10, 10)
// and global rotation of 45deg along the Z axis.
lT.Set(10.0, 10.0, 10.0);
lR.Set( 0.0, 0.0, 45.0);
lTransformMatrix.SetTRS(lT, lR, lS);
// 添加Root骨骼矩阵到Pose中
lKFbxNode = pSkeletonRoot;
lPose->Add(lKFbxNode, lTransformMatrix, false /*GlobalMatrix*/);
// Set the lLimbNode1 node to the local position of (0, 40, 0)
// and local rotation of -90deg along the Z axis. This show that
// you can mix local and global coordinates in a rest pose.
lT.Set(0.0, 40.0, 0.0);
lR.Set(0.0, 0.0, -90.0);
lTransformMatrix.SetTRS(lT, lR, lS);
// 添加第二个骨骼节点到Pose中
lKFbxNode = lKFbxNode->GetChild(0);
lPose->Add(lKFbxNode, lTransformMatrix, true /*LocalMatrix*/);
// Set the lLimbNode2 node to the local position of (0, 40, 0)
// and local rotation of 45deg along the Z axis.
lT.Set(0.0, 40.0, 0.0);
lR.Set(0.0, 0.0, 45.0);
lTransformMatrix.SetTRS(lT, lR, lS);
// Add the skeleton second node to the pose
lKFbxNode = lKFbxNode->GetChild(0);
lNodeName = lKFbxNode->GetName();
lPose->Add(lKFbxNode, lTransformMatrix, true /*LocalMatrix*/);
// Now add the pose to the scene
pScene->AddPose(lPose);
}
```
## GlobalSettings
场景的轴系统、系统单位、环境照明和时间设置可以通过`FbxScene::GetGlobalSettings()`获取FbxGlobalSettings来进行定义。