飞道的博客

【学习填坑之路】FBX-SDK初始化加载遍历场景

890人阅读  评论(0)

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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场