FBX-SDK 简介
FBX-SDK是Autodesk FBX技术的一部分,FBX是独立于平台的3D创作和交换格式,可从大多数3D供应商和平台访问3D内容。该FBX文件格式支持所有主要的2D、3D模型元素,音频和视频媒体元素,是用于跨平台的免费三维数据交换的格式。Autodesk FBX通过使它们混合和匹配各种2D和3D数据创建应用程序,目前被 众多的标准建模软件所支持,在游戏开发领域也常用来作为各种建模工具的标准导出格式。
Autodesk提供了基于C++(还有Python)的SDK来实现对FBX格式的各种读写、修改以及转换等操作,FBX的格式不是公开的,这也是FBX的诟病之一,我们用文本打开是乱码因为是ascll值。与FBX相对的则是格式开源的Collada,它的应用也很广泛。下面以Autodesk自己放入产品使用到FBX技术为例:
FBX文件(.fbx)通常以二进制(或本机)格式保存,但也可以以ASCII格式保存。二进制FBX文件和ASCII FBX文件都使用 .fbx文件扩展名。FBX文件存储有关摄像机,灯光,网格,NURBS以及3D场景其他元素的数据。Autodesk 3ds Max,Autodesk Maya和Autodesk MotionBuilder等应用程序可以从FBX文件导入全部或部分场景数据。他们还可以将其场景数据导出到FBX文件。所有这些操作都使用FBX SDK,下面是使用场景介绍。
FBX-SDk配置
配置环境
查看上一篇博客:FBX-SDK环境配置记录
支持的文件格式
FBX SDK可以直接导入导出的包括:
FBX各种文件、
Collada DAE (.dae)文件、
FBX binary (.fbx)二进制文件、
FBX ascii (.fbx)文件、
OBJ (.obj)文件、
AutoCAD DXF 文件(*.dxf)。
max文件和.3ds文件不能直接被fbx-sdk读取。
支持的场景元素
1、场景元素-FbxScene
2、网格元素- FbxMesh
3、细节程度(LOD)组-FbxLodGroup
4、相机元素(包括3D立体相机)-FbxCamera
5、灯和遮光罩元素- FbxLight,FbxGobo
6、曲面建模 -FbxNurbs FbxNurbsCurveFbxNurbsSurfaceFbxTrimNurbsSurface
7、几何图形上进行纹理映射- FbxTexture
8、几何上的材质映射- FbxSurfaceMaterial
9、约束性质-FbxConstraint
10、几何控制点上的顶点缓存动画- FbxDeformer
11、提供上轴(X / Y /Z)和场景缩放(单位)的场景设置- FbxGlobalSettings,FbxAxisSystem
12、转换数据,包括位置,旋转,比例,父级- FbxNode
13、元素标记- FbxMarker
14、线元素- FbxLine
15、骨架段(根,四肢和四肢节点)- FbxSkeleton
16、动画曲线元素- FbxAnimCurve
17、节点(骨骼和几何体)绑定属性- FbxPose
FBX模型初了解
FBX的组织结构
FBX是以场景树的结构来存储模型的所有信息(也可以认为是一个多叉树),我们可以通过场景分别获取到贴图和节点数据,再通过贴图或者节点获取包括贴图名,路径,节点名、对应材质材质名,以及各自的属性。整个Scene是从一个空属性的根结点RootNode开始,包含Mesh、Camera、Light等子节点,所有对象之间的关联均是双向的,比如从子结点可以索引到父结点,从父结点也可以索引到子结点;从单个结点可以索引到整个Scene,从Scene也可以索引到该结点。
我们实现一个FBX程序主要的顺序如下:
1、实例化FBX SDK内存管理对象。(FbxManager)
2、将FBX文件的内容导入场景。(FbxIOSettings,FbxImporter,FbxScene)
3、遍历场景的元素层次结构。(FbxScene,FbxNode,FbxNodeAttribute)
4、访问和打印有关场景元素的基本信息。(FbxNode,FbxNodeAttribute,FbxString)
FBX初始化-管理对象
创建一个FBX SDK管理器
FBX SDK操纵的大多数对象都是通过引用SDK的**内存管理器对象(FbxManager)**实例化的。FbxManager类负责创建,管理和销毁FBX SDK对象。它通常是FBX SDK的程序中要创建的第一个对象,并使用FbxManager::Create()函数实例化。一个程序只需要一个实例FbxManager。FbxManager使用FbxManager::Destroy()方法销毁的实例时,使用该实例创建的所有其他FBX SDK对象也将销毁。
FbxManager* lSdkManager = FbxManager::Create();
使用FBX SDK管理器创建对象
FBX SDK需要各自的创建或销毁他们的Create()和Destroy()成员函数。我们通常将FbxManager作为第一个参数参数传递给FbxScene::Create()函数以实例化新场景。
FbxScene* lScene = FbxScene::Create(lSdkManager, "Scene Name");
内存分配
SDK对象管理器(FbxManager)自动分配足够的内存以处理新对象。
命名FBX对象
FbxScene::Create()的第二个参数是一个字符串。在创建对象时,可以使用字符串指定新对象的名称。该字符串可以传递一个空字符串" "。这样可以简化FBX SDK应用程序及其输出的调试。
注意:
不能保证FBX SDK的是线程安全的。使用相同的对象创建的对象FbxManager,但是在不同线程中访问的对象可能会导致应用程序崩溃。
在场景中创建对象
一个FbxScene对象可以包含各种场景元素,例如网格,灯光,动画,角色等。这些元素应参考它们的场景来创建。因此,导出场景时,所有元素也将导出。当场景被销毁时,分配给所有对象的内存也会释放。
// Create a node object
FbxNode* lNode = FbxNode::Create(lScene, "node");
// Create a mesh object
FbxMesh* lMesh = FbxMesh::Create(lScene, "");
注意:
有可能创建的场景元素FbxScene删除,但这些场景元素将不会一起销毁坏; 它们只会被函数调用销毁或FbxManager销毁时销毁。
摧毁物体
FBX SDK对象通过调用Destroy()成员函数显式销毁。在FbxManager将自动释放分配给该对象的存储器,并且将更新所有的内部连接对象(FbxObject),以及性质(FbxProperty),和其他FbxObject之间的关系。
// Destroy these objects
lMesh->Destroy(); // Destroy the mesh
lNode->Destroy(); // Destroy the node
lScene->Destroy(); // Destroy the scene and its objects
lSDKManager->Destroy() // Destroy SDK Manager and any remaining objects which it manages.
FBX初始化-导入FBX文件的内容
要导入FBX文件的内容,必须创建一个FbxIOSettings对象和一个FbxImporter对象。FbxImporter通过提供导入文件的文件名以及FbxIOSettings的属性配置来初始化对象。
// Create the IO settings object.
FbxIOSettings *ios = FbxIOSettings::Create(lSdkManager, IOSROOT);
lSdkManager->SetIOSettings(ios);
// Create an importer using the SDK manager.
FbxImporter* lImporter = FbxImporter::Create(lSdkManager,"");
// Use the first argument as the filename for the importer.
if(!lImporter->Initialize(lFilename, -1, lSdkManager->GetIOSettings())) {
printf("Call to FbxImporter::Initialize() failed.\n");
printf("Error returned: %s\n\n", lImporter->GetStatus().GetErrorString());
exit(-1);
// Create a new scene so that it can be populated by the imported file.
FbxScene* lScene = FbxScene::Create(lSdkManager,"myScene");
// Import the contents of the file into the scene.
lImporter->Import(lScene);
// The file is imported, so get rid of the importer.
lImporter->Destroy();
FBX初始化-探索场景
FbxScene对象是作为场景元素的容器。而且每个FbxScene导入或导出的文件只能有一个对象。场景可以包含各种元素:网格,灯光,摄像机,骨骼和NURBS等。FbxScene的元素FbxNodes组织是深度树组织。通过访问FbxScene::GetRootNode()来访问场景的根节点。而且将场景导出到文件时,不会保存场景的根节点但他的子元素会被导出。场景的子元素可以通过访问FbxNode::GetChild()来访问。同样,可以通过FbxNode::GetParent()访问节点的父节点。从概念上讲,一个FbxNode充当一个或多个场景元素的容器。例如,FbxNode场景中的一个可以包含一台摄像机,而另一个FbxNode可以包含一个网格。在FBX SDK中,场景元素(例如,网格,灯光,相机,骨骼,nurb,动画曲线等)由从派生的类定义FbxNodeAttribute。FbxNode可以有一个以上FbxNodeAttribute。一个FbxNode可以访问本地的位置转换(FbxNode::LclTranslation),旋转(FbxNode::LclRotation)和缩放(FbxNode::LclScaling)等属性。这些属性继承父节点的位置,方向和比例的转换,以获得当前子节点的位置,方向和比例。
// Print the nodes of the scene and their attributes recursively.
// Note that we are not printing the root node because it should
// not contain any attributes.
FbxNode* lRootNode = lScene->GetRootNode();
if(lRootNode) {
for(int i = 0; i < lRootNode->GetChildCount(); i++)
PrintNode(lRootNode->GetChild(i));
}
// Destroy the SDK manager and all the other objects it was handling.
lSdkManager->Destroy();
/**
* Print a node, its attributes, and all its children recursively.
*/
void PrintNode(FbxNode* pNode) {
PrintTabs();
const char* nodeName = pNode->GetName();
FbxDouble3 translation = pNode->LclTranslation.Get();
FbxDouble3 rotation = pNode->LclRotation.Get();
FbxDouble3 scaling = pNode->LclScaling.Get();
// Print the contents of the node.
printf("\n",
nodeName,
translation[0], translation[1], translation[2],
rotation[0], rotation[1], rotation[2],
scaling[0], scaling[1], scaling[2]
);
numTabs++;
// Print the node's attributes.
for(int i = 0; i < pNode->GetNodeAttributeCount(); i++)
PrintAttribute(pNode->GetNodeAttributeByIndex(i));
// Recursively print the children.
for(int j = 0; j < pNode->GetChildCount(); j++)
PrintNode(pNode->GetChild(j));
numTabs--;
PrintTabs();
printf("\n");
}
FBX初始化-打印对象
通过递归从根节点开始输出每个节点的各种属性和名称、子节点。
/* Tab character ("\t") counter */
int numTabs = 0;
/**
* Print the required number of tabs.
*/
void PrintTabs() {
for(int i = 0; i < numTabs; i++)
printf("\t");
}
/**
* Return a string-based representation based on the attribute type.
*/
FbxString GetAttributeTypeName(FbxNodeAttribute::EType type) {
switch(type) {
case FbxNodeAttribute::eUnknown: return "unidentified";
case FbxNodeAttribute::eNull: return "null";
case FbxNodeAttribute::eMarker: return "marker";
case FbxNodeAttribute::eSkeleton: return "skeleton";
case FbxNodeAttribute::eMesh: return "mesh";
case FbxNodeAttribute::eNurbs: return "nurbs";
case FbxNodeAttribute::ePatch: return "patch";
case FbxNodeAttribute::eCamera: return "camera";
case FbxNodeAttribute::eCameraStereo: return "stereo";
case FbxNodeAttribute::eCameraSwitcher: return "camera switcher";
case FbxNodeAttribute::eLight: return "light";
case FbxNodeAttribute::eOpticalReference: return "optical reference";
case FbxNodeAttribute::eOpticalMarker: return "marker";
case FbxNodeAttribute::eNurbsCurve: return "nurbs curve";
case FbxNodeAttribute::eTrimNurbsSurface: return "trim nurbs surface";
case FbxNodeAttribute::eBoundary: return "boundary";
case FbxNodeAttribute::eNurbsSurface: return "nurbs surface";
case FbxNodeAttribute::eShape: return "shape";
case FbxNodeAttribute::eLODGroup: return "lodgroup";
case FbxNodeAttribute::eSubDiv: return "subdiv";
default: return "unknown";
}
}
/**
* Print an attribute.
*/
void PrintAttribute(FbxNodeAttribute* pAttribute) {
if(!pAttribute) return;
FbxString typeName = GetAttributeTypeName(pAttribute->GetAttributeType());
FbxString attrName = pAttribute->GetName();
PrintTabs();
// Note: to retrieve the character array of a FbxString, use its Buffer() method.
printf("\n", typeName.Buffer(), attrName.Buffer());
}
/**
* Print a node, its attributes, and all its children recursively.
*/
void PrintNode(FbxNode* pNode) {
PrintTabs();
const char* nodeName = pNode->GetName();
FbxDouble3 translation = pNode->LclTranslation.Get();
FbxDouble3 rotation = pNode->LclRotation.Get();
FbxDouble3 scaling = pNode->LclScaling.Get();
// Print the contents of the node.
printf("\n",
nodeName,
translation[0], translation[1], translation[2],
rotation[0], rotation[1], rotation[2],
scaling[0], scaling[1], scaling[2]
);
numTabs++;
// Print the node's attributes.
for(int i = 0; i < pNode->GetNodeAttributeCount(); i++)
PrintAttribute(pNode->GetNodeAttributeByIndex(i));
// Recursively print the children.
for(int j = 0; j < pNode->GetChildCount(); j++)
PrintNode(pNode->GetChild(j));
numTabs--;
PrintTabs();
printf("\n");
}
转载:https://blog.csdn.net/Dragonpigz/article/details/106584126