242 lines
8.8 KiB
Markdown
242 lines
8.8 KiB
Markdown
---
|
||
title: Qt & FBX相关笔记
|
||
date: 2023-11-06 11:45:14
|
||
excerpt:
|
||
tags:
|
||
rating: ⭐
|
||
---
|
||
# 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`即可。例如:
|
||
```c++
|
||
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
|
||
```
|
||
|
||
新版本fbxsdk需要自己link xml2库,所以需要手动安装一下
|
||
```bash
|
||
sudo apt-get install libxml2-dev
|
||
sudo apt-get install libxml2
|
||
```
|
||
|
||
之后再qt的pro中添加`LIBS += -lxml2`即可。
|
||
|
||
之后运行程序会提示# (error while loading shared libraries: libfbxsdk.so: cannot open shared object file: No)
|
||
这是因为Linux的动态链接库寻找方式与windows不同所致,我们需要添加lib搜索路径:
|
||
使用VSCode打开/etc/ld.so.conf ,输入libfbxsdk.so的路径,再运行ldconfig,即可解决问题
|
||
```
|
||
1> vim /etc/ld.so.conf //在新的一行中加入库文件所在目录
|
||
2> /usr/lib //添加的目录路径
|
||
3> /usr/local/lib //添加的目录路径
|
||
3> ldconfig //更新/etc/ld.so.cache文件
|
||
```
|
||
|
||
参考
|
||
https://blog.csdn.net/sinat_14854721/article/details/111191139
|
||
|
||
|
||
另一种思路就是使用linuxdeployqt,打成类似MAC的APP包
|
||
- https://github.com/probonopd/linuxdeployqt
|
||
- https://blog.csdn.net/zyhse/article/details/106381937
|
||
|
||
# FBX结构
|
||

|
||
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相关属性为:
|
||
|
||
|
||
|
||
添加动画关键帧的方式
|
||
```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来进行定义。
|
||
|
||
## FBXStream & 共享内存
|
||
FBXStream案例:https://github.com/hamedsabri/FbxStream
|
||
|
||
之前考虑通过共享内存来实现文件传递以此来规避IO瓶颈,这里可以考虑参考FBXStream。本质是通过文字流使得 文件 <=> string。
|
||
这样就可以通过共享内存进行数据传递了。
|
||
|
||
让张柏林试试对一个文件使用Java进行字符串流化。
|
||
|
||
文档地址:
|
||
- https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_cpp_ref_class_fbx_stream_html
|
||
- https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_cpp_ref_class_fbx_importer_html |