Your First FBX SDK Program
 
 
 

This topic provides a basic overview of your first FBX SDK program.

For the purposes of this quick guide, the program will use the statically linked version of the FBX SDK. For additional information on how to install and configure the FBX SDK for your environment, see Installing and Configuring.

The following FBX SDK program will provide an overview on how to:

  1. Instantiate an FBX SDK memory management object (KFbxSdkManager)
  2. Import the contents of an FBX file into a scene (KFbxIOSettings, KFbxImporter, KFbxScene)
  3. Traverse the element hierarchy of a scene. (KFbxScene, KFbxNode, KFbxNodeAttribute)
  4. Access and print basic information about the elements of a scene. (KFbxNode, KFbxNodeAttribute, KString)

Managing Objects

Related topics:

The majority of objects manipulated by the FBX SDK are instantiated with a reference to the SDK's memory manager object (KFbxSdkManager). It is usually one of the first objects to be created in a program which uses the FBX SDK, and it is instantiated with the KFbxSdkManager::Create() function. A program only requires one instance of KFbxSdkManager. When an instance of KFbxSdkManager is destroyed via the KFbxSdkManager::Destroy() method, all the other FBX SDK objects which were created with it are also destroyed.

#include <fbxsdk.h>

// ...

/**
 * Main function - loads the hard-coded fbx file,
 * and prints its contents in an xml format to stdout.
 */
int main(int argc, char** argv) {

    // Change the following filename to a suitable filename value.
    const char* lFilename = "file.fbx";
    
    // Initialize the sdk manager. This object handles all our memory management.
    KFbxSdkManager* lSdkManager = KFbxSdkManager::Create();

Importing the Contents of an FBX File

Related topics:

To import the contents of an FBX file, a KFbxIOSettings object and a KFbxImporter object must be created. A KFbxImporter object is initialized by providing the filename of the file we want to import along with a KFbxIOSettings object which has been appropriately configured to suit our importing needs (see I/O Settings).

    // Create the io settings object.
    KFbxIOSettings *ios = KFbxIOSettings::Create(lSdkManager, IOSROOT);
    lSdkManager->SetIOSettings(ios);

    // Create an importer using our sdk manager.
    KFbxImporter* lImporter = KFbxImporter::Create(lSdkManager,"");
    
    // Use the first argument as the filename for the importer.
    if(!lImporter->Initialize(lFilename, -1, lSdkManager->GetIOSettings())) {
        printf("Call to KFbxImporter::Initialize() failed.\n");
        printf("Error returned: %s\n\n", lImporter->GetLastErrorString());
        exit(-1);
    }

The KFbxImporter object populates a provided KFbxScene object with the elements contained in the FBX file. Observe that the KFbxScene::Create() function is passed an empty string as its second parameter. Objects created in the FBX SDK can be given arbitrary, non-unique names, which allow the user or other programs to identify the object after it has been exported. After the KFbxScene is populated, the KFbxImporter can be safely destroyed.

    // Create a new scene so it can be populated by the imported file.
    KFbxScene* lScene = KFbxScene::Create(lSdkManager,"myScene");

    // Import the contents of the file into the scene.
    lImporter->Import(lScene);

    // The file has been imported; we can get rid of the importer.
    lImporter->Destroy();

Exploring the Scene

Related topics:

The KFbxScene object acts as a container for elements existing within the scene. Observe that there can only be one KFbxScene object per imported or exported file. A scene can contain a variety of elements including: meshes, lights, cameras, skeletons, and nurbs (to name but a few). The elements of a KFbxScene are organized in a hierarchical tree of KFbxNodes. The root node of a scene is accessed via KFbxScene::GetRootNode(). Note that the root node of a scene is not saved when the scene is exported to a file; only its children are saved. The children of a node can be accessed via KFbxNode::GetChild(). Likewise, the parent of a node can be accessed via KFbxNode::GetParent(). Conceptually, a KFbxNode acts as a container for one or more scene elements. For example, one KFbxNode in the scene can contain a camera, whereas another KFbxNode can contain a mesh. In the FBX SDK, scene elements such as meshes, lights, cameras, skeletons, nurbs, animation curves, etc, are defined by classes derived from KFbxNodeAttribute. There can be more than one KFbxNodeAttribute per KFbxNode.

    // 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.
    KFbxNode* lRootNode = lScene->GetRootNode();
    if(lRootNode) {
        for(int i = 0; i < lRootNode->GetChildCount(); i++)
            PrintNode(lRootNode->GetChild(i));
    }
    // Destroy the sdk manager and all other objects it was handling.
    lSdkManager->Destroy();

A KFbxNode provides access to its local translation (KFbxNode::LclTranslation), rotation (KFbxNode::LclRotation), and scaling (KFbxNode::LclScaling) properties. These properties represent the transformations applied to the parent node's position, orientation, and scale to obtain the current node's position, orientation, and scale.

/**
 * Print a node, its attributes, and all its children recursively.
 */
void PrintNode(KFbxNode* 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("<node name='%s' translation='(%f, %f, %f)' rotation='(%f, %f, %f)' scaling='(%f, %f, %f)'>\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 nodes.
    for(int j = 0; j < pNode->GetChildCount(); j++)
        PrintNode(pNode->GetChild(j));

    numTabs--;
    PrintTabs();
    printf("</node>\n");
}

Your First Program

#include <fbxsdk.h>

/* 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.
 */
KString GetAttributeTypeName(KFbxNodeAttribute::EAttributeType type) {
    switch(type) {
        case KFbxNodeAttribute::eUNIDENTIFIED: return "unidentified";
        case KFbxNodeAttribute::eNULL: return "null";
        case KFbxNodeAttribute::eMARKER: return "marker";
        case KFbxNodeAttribute::eSKELETON: return "skeleton";
        case KFbxNodeAttribute::eMESH: return "mesh";
        case KFbxNodeAttribute::eNURB: return "nurb";
        case KFbxNodeAttribute::ePATCH: return "patch";
        case KFbxNodeAttribute::eCAMERA: return "camera";
        case KFbxNodeAttribute::eCAMERA_STEREO:    return "stereo";
        case KFbxNodeAttribute::eCAMERA_SWITCHER: return "camera switcher";
        case KFbxNodeAttribute::eLIGHT: return "light";
        case KFbxNodeAttribute::eOPTICAL_REFERENCE: return "optical reference";
        case KFbxNodeAttribute::eOPTICAL_MARKER: return "marker";
        case KFbxNodeAttribute::eNURBS_CURVE: return "nurbs curve";
        case KFbxNodeAttribute::eTRIM_NURBS_SURFACE: return "trim nurbs surface";
        case KFbxNodeAttribute::eBOUNDARY: return "boundary";
        case KFbxNodeAttribute::eNURBS_SURFACE: return "nurbs surface";
        case KFbxNodeAttribute::eSHAPE: return "shape";
        case KFbxNodeAttribute::eLODGROUP: return "lodgroup";
        case KFbxNodeAttribute::eSUBDIV: return "subdiv";
        default: return "unknown";
    }
}

/**
 * Print an attribute.
 */
void PrintAttribute(KFbxNodeAttribute* pAttribute) {
    if(!pAttribute) return;
 
    KString typeName = GetAttributeTypeName(pAttribute->GetAttributeType());
    KString attrName = pAttribute->GetName();
    PrintTabs();
    // Note: to retrieve the chararcter array of a KString, use its Buffer() method.
    printf("<attribute type='%s' name='%s'/>\n", typeName.Buffer(), attrName.Buffer());
}

/**
 * Print a node, its attributes, and all its children recursively.
 */
void PrintNode(KFbxNode* 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("<node name='%s' translation='(%f, %f, %f)' rotation='(%f, %f, %f)' scaling='(%f, %f, %f)'>\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 nodes.
    for(int j = 0; j < pNode->GetChildCount(); j++)
        PrintNode(pNode->GetChild(j));

    numTabs--;
    PrintTabs();
    printf("</node>\n");
}

/**
 * Main function - loads the hard-coded fbx file,
 * and prints its contents in an xml format to stdout.
 */
int main(int argc, char** argv) {

    // Change the following filename to a suitable filename value.
    const char* lFilename = "file.fbx";
    
    // Initialize the sdk manager. This object handles all our memory management.
    KFbxSdkManager* lSdkManager = KFbxSdkManager::Create();
    
    // Create the io settings object.
    KFbxIOSettings *ios = KFbxIOSettings::Create(lSdkManager, IOSROOT);
    lSdkManager->SetIOSettings(ios);

    // Create an importer using our sdk manager.
    KFbxImporter* lImporter = KFbxImporter::Create(lSdkManager,"");
    
    // Use the first argument as the filename for the importer.
    if(!lImporter->Initialize(lFilename, -1, lSdkManager->GetIOSettings())) {
        printf("Call to KFbxImporter::Initialize() failed.\n");
        printf("Error returned: %s\n\n", lImporter->GetLastErrorString());
        exit(-1);
    }
    
    // Create a new scene so it can be populated by the imported file.
    KFbxScene* lScene = KFbxScene::Create(lSdkManager,"myScene");

    // Import the contents of the file into the scene.
    lImporter->Import(lScene);

    // The file has been imported; we can get rid of the importer.
    lImporter->Destroy();
    
    // 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.
    KFbxNode* lRootNode = lScene->GetRootNode();
    if(lRootNode) {
        for(int i = 0; i < lRootNode->GetChildCount(); i++)
            PrintNode(lRootNode->GetChild(i));
    }
    // Destroy the sdk manager and all other objects it was handling.
    lSdkManager->Destroy();
    return 0;
}