FBX SDK Programmer's Guide > Nodes and the Scene Graph > FBX Scenes >

# Merging Two Scenes

This topic presents how to merge two imported scenes. It also provides basic insight on manipulating a scene and the nodes within it, and will initiate the reader to the concept of connections and connection management.

The steps taken for merging two scenes are as follows:

1. Load a scene.
2. Modify a node within the loaded scene.
3. Move the contents of the loaded scene into a reference scene.
4. Load a different scene.
5. Update the newly loaded scene with the contents of the reference scene.
6. Destroy the reference scene.

Loading and modifying the scene

The first object we create is the FbxManager; this step is required to create subsequent FBX SDK objects. A newly created FbxScene object, referred to as the "current scene", is then passed to our custom LoadScene() function, so it can be populated by the imported contents of "file1.fbx" (which should be in the same folder as the executable program). Once the scene's contents are populated, we simply change the name of the root node's first child (indexed at 0) to "Test Name".

        // Create an SDK manager.
        FbxManager* lSdkManager = FbxManager::Create();

        // Create a new scene so it can be populated by the imported file.
        FbxScene* lCurrentScene = FbxScene::Create(lSdkManager,"My Scene");

        // Load the scene.
        LoadScene(lSdkManager, lCurrentScene, "file1.fbx");

        // Modify the scene. In this example, only one node name is changed.
        lCurrentScene->GetRootNode()->GetChild(0)->SetName("Test Name");

Moving the contents of the loaded scene into a reference scene

Another FbxScene object is created, which we will refer to as the "reference scene". Note that when a FbxScene object is created, its root node and its global settings are also created with it. As such, the objective of this step is to remove the children from the current scene's root node so they may become the children of the reference scene's root node.

        // Create a reference scene to store the contents of the currently loaded scene.
        FbxScene *lMyRefScene = FbxScene::Create(lSdkManager, "My Reference Scene");

        // Move the node tree of the currently loaded scene into the reference scene.
        int lNumChildren = lCurrentScene->GetRootNode()->GetChildCount();
        for(int i = 0; i < lNumChildren; i++) {

            // Obtain a child node from the currently loaded scene.
            FbxNode* lChildNode = lCurrentScene->GetRootNode()->GetChild(i);

            // Attach the child node to the reference scene's root node.
            lMyRefScene->GetRootNode()->AddChild(lChildNode);
        }

        // Remove the children from the root node.
        lCurrentScene->GetRootNode()->DisconnectAllSrcObject();

Other FbxObjects contained in the current scene may need to be moved to the reference scene. Such objects may include instances of: FbxCharacter, FbxCharacterPose, and FbxDocumentInfo to name a few. Observe that these objects are not children of the current scene's root node, and need to be moved differently. To achieve this, we will require some basic knowledge of "connections" in the context of the FBX SDK.

A connection is a directional "source to destination" relationship between either: two FbxObjects, a FbxObject and a FbxProperty, or two FbxPropertys. For more information on connections, see Connections. In the scope of this tutorial, we want to disconnect all the relevant source objects from the current scene, and connect them the reference scene. We do this using the FbxObject::GetSrcObjectCount(), FbxObject::DisconnectAllSrcObject(), and FbxObject::ConnectDstObject().

        // Move other objects to the reference scene.
        int lNumSceneObjects = lCurrentScene->GetSrcObjectCount();
        for(int i = 0; i < lNumSceneObjects; i++) {
            FbxObject* lObj = lCurrentScene->GetSrcObject(i);
            if(lObj == lCurrentScene->GetRootNode() || *lObj == lCurrentScene->GetGlobalSettings()){
                // Don't move the root node or the scene's global settings; these
                // objects are created for every scene.
                continue;
            }
            // Attach the object to the reference scene.
            lObj->ConnectDstObject(lMyRefScene);
        }

        // Disconnect all scene objects.
        lCurrentScene->DisconnectAllSrcObject();

NoteYou can get all the objects of a certain type in a scene using the concept of connections. In the following code snippet, we iterate through the meshes connected to a scene by calling lScene->GetSrcObjectCount(FbxMesh::ClassId).

    for(int i = 0; i < lScene->GetSrcObjectCount(FbxMesh::ClassId); i++) {
        FbxMesh* lMesh = (FbxMesh*)lScene->GetSrcObject(FbxMesh::ClassId, i);
        //...
    }

Loading and updating a different scene

At this point, we have moved the elements of the current scene into the reference scene, and the current scene has become empty. We now take our current scene and repopulate it with the contents of "file2.fbx". Finally, we change the name of the root's first child in the current scene to the name of root's first child in the reference scene. In the end, the name of the root's first child in the current scene should be "Test Name".

        // Import the second file into lCurrentScene.
        LoadScene(lSdkManager, lCurrentScene, "file2.fbx");

        // Get the names after the second file is loaded.
        FbxString lNameBeforeUpdate = lCurrentScene->GetRootNode()->GetChild(0)->GetName();
        FbxString lReferenceName = lMyRefScene->GetRootNode()->GetChild(0)->GetName();

        // Update the root's child 0 name.
        lCurrentScene->GetRootNode()->GetChild(0)->SetName(lReferenceName);
        FbxString lNameAfterUpdate = lCurrentScene->GetRootNode()->GetChild(0)->GetName();

        // Destroy the reference scene.
        lMyRefScene->Destroy();
        lMyRefScene = NULL;

        // Verification step
        printf("Verification (0 for success): %d\n", lNameAfterUpdate.Compare("Test Name"));

Scene Merging Tutorial Program

The following is the scene merging tutorial program discussed above.

    #include <fbxsdk.h>

    /**
     * Load a scene given an FbxManager, a FbxScene, and a valid filename.
     */
    int LoadScene(FbxManager* pSdkManager, FbxScene* pScene, char* filename) {
        // Create the io settings object.
        FbxIOSettings *ios = FbxIOSettings::Create(pSdkManager, IOSROOT);
        pSdkManager->SetIOSettings(ios);

        // Create an importer using our sdk manager.
        FbxImporter* lImporter = FbxImporter::Create(pSdkManager,"");

        // Use the first argument as the filename for the importer.
        if(!lImporter->Initialize(filename, -1, pSdkManager->GetIOSettings())) {
            printf("Call to FbxImporter::Initialize() failed.\n");
            printf("Error returned: %s\n\n", lImporter->GetLastErrorString());
            lImporter->Destroy();
            return -1;
        }

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

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

    /**
     * Entry point for the merging two scenes sample program.
     */
    int main(int argc, char** argv) {
        // Create an SDK manager.
        FbxManager* lSdkManager = FbxManager::Create();

        // Create a new scene so it can be populated by the imported file.
        FbxScene* lCurrentScene = FbxScene::Create(lSdkManager,"My Scene");

        // Load the scene.
        LoadScene(lSdkManager, lCurrentScene, "file1.fbx");

        // Modify the scene. In this example, only one node name is changed.
        lCurrentScene->GetRootNode()->GetChild(0)->SetName("Test Name");

        // Create a reference scene to store the contents of the currently loaded scene.
        FbxScene *lMyRefScene = FbxScene::Create(lSdkManager, "My Reference Scene");

        // Move the node tree of the currently loaded scene into the reference scene.
        int lNumChildren = lCurrentScene->GetRootNode()->GetChildCount();
        for(int i = 0; i < lNumChildren; i++) {

            // Obtain a child node from the currently loaded scene.
            FbxNode* lChildNode = lCurrentScene->GetRootNode()->GetChild(i);

            // Attach the child node to the reference scene's root node.
            lMyRefScene->GetRootNode()->AddChild(lChildNode);
        }

        // Remove the children from the root node.
        lCurrentScene->GetRootNode()->DisconnectAllSrcObject();

        // Move other objects to the reference scene.
        int lNumSceneObjects = lCurrentScene->GetSrcObjectCount();
        for(int i = 0; i < lNumSceneObjects; i++) {
            FbxObject* lObj = lCurrentScene->GetSrcObject(i);
            if(lObj == lCurrentScene->GetRootNode() || *lObj == lCurrentScene->GetGlobalSettings()){
                // Don't move the root node or the scene's global settings; these
                // objects are created for every scene.
                continue;
            }
            // Attach the object to the reference scene.
            lObj->ConnectDstObject(lMyRefScene);
        }

        // Disconnect all scene objects.
        lCurrentScene->DisconnectAllSrcObject();

        // Import the second file into lCurrentScene.
        LoadScene(lSdkManager, lCurrentScene, "file1.fbx");

        // Get the names after the second file is loaded.
        FbxString lNameBeforeUpdate = lCurrentScene->GetRootNode()->GetChild(0)->GetName();
        FbxString lReferenceName = lMyRefScene->GetRootNode()->GetChild(0)->GetName();

        // Update the root's child 0 name.
        lCurrentScene->GetRootNode()->GetChild(0)->SetName(lReferenceName);
        FbxString lNameAfterUpdate = lCurrentScene->GetRootNode()->GetChild(0)->GetName();

        // Destroy the reference scene.
        lMyRefScene->Destroy();
        lMyRefScene = NULL;

        // Verification step
        printf("Verification (0 for success): %d\n", lNameAfterUpdate.Compare("Test Name"));

        // Destroy the sdk manager.
        lSdkManager->Destroy();
        exit(0);
    }

#### See Also

- Your First FBX SDK Program
- FBX Objects
- FBX Properties
- Connections