- Main Page
- Classes
- Files
- Directories
- Examples

# ExportDocument/main.cxx

    /****************************************************************************************

       Copyright (C) 2012 Autodesk, Inc.
       All rights reserved.

       Use of this software is subject to the terms of the Autodesk license agreement
       provided at the time of installation or download, or which otherwise accompanies
       this software in either electronic or hard copy form.

    ****************************************************************************************/

    //
    // The document created in this example is a container for objects.
    // The document includes two sub-documents to contain materials and lights separately.
    //
    // The example illustrates how to:
    //        1) create document and export
    //        2) create objects that connect to document directly
    //        3) create sub-document
    //        4) create materials and textures, connect texture to material
    //        5) create lights
    //        6) export a document in a .FBX file (ASCII mode)
    //

    #include <fbxsdk.h>

    #ifdef IOS_REF
        #undef  IOS_REF
        #define IOS_REF (*(pSdkManager->GetIOSettings()))
    #endif

    #define SAMPLE_FILENAME "ExportDocument.fbx"

    bool CreateDocument(FbxManager* pSdkManager, FbxDocument* pDocument);
    void CreateMatDocument(FbxManager* pSdkManager, FbxDocument* pMatDocument);
    void CreateLightDocument(FbxManager* pSdkManager, FbxDocument* pLightDocument);
    FbxNode* CreatePlane(FbxManager* pSdkManager, char* pName);
    FbxSurfacePhong* CreateMaterial(FbxManager* pSdkManager);
    FbxTexture*  CreateTexture(FbxManager* pSdkManager);
    FbxNode* CreateLight(FbxManager* pSdkManager, FbxLight::EType pType);

    void InitializeSdkObjects(FbxManager*& pSdkManager)
    {
        // The first thing to do is to create the FBX SDK manager which is the
        // object allocator for almost all the classes in the SDK.
        pSdkManager = FbxManager::Create();

        if (!pSdkManager)
        {
            FBXSDK_printf("Unable to create the FBX SDK manager\n");
            exit(0);
        }

        // create an IOSettings object
        FbxIOSettings * ios = FbxIOSettings::Create(pSdkManager, IOSROOT );
        pSdkManager->SetIOSettings(ios);
    }

    void DestroySdkObjects(FbxManager* pSdkManager)
    {
        // Delete the FBX SDK manager. All the objects that have been allocated
        // using the FBX SDK manager and that haven't been explicitly destroyed
        // are automatically destroyed at the same time.
        if (pSdkManager) pSdkManager->Destroy();
        pSdkManager = NULL;
    }

    // Export document, the format is ascii by default
    bool SaveDocument(FbxManager* pSdkManager, FbxDocument* pDocument, const char* pFilename, int pFileFormat=-1, bool pEmbedMedia=false)
    {
        int lMajor, lMinor, lRevision;
        bool lStatus = true;

        // Create an exporter.
        FbxExporter* lExporter = FbxExporter::Create(pSdkManager, "");

        if( pFileFormat < 0 || pFileFormat >= pSdkManager->GetIOPluginRegistry()->GetWriterFormatCount() )
        {
            // Write in fall back format if pEmbedMedia is true
            pFileFormat = pSdkManager->GetIOPluginRegistry()->GetNativeWriterFormat();

            if (!pEmbedMedia)
            {
                //Try to export in ASCII if possible
                int lFormatIndex, lFormatCount = pSdkManager->GetIOPluginRegistry()->GetWriterFormatCount();

                for (lFormatIndex=0; lFormatIndex<lFormatCount; lFormatIndex++)
                {
                    if (pSdkManager->GetIOPluginRegistry()->WriterIsFBX(lFormatIndex))
                    {
                        FbxString lDesc =pSdkManager->GetIOPluginRegistry()->GetWriterFormatDescription(lFormatIndex);
                        char *lASCII = "ascii";
                        if (lDesc.Find(lASCII)>=0)
                        {
                            pFileFormat = lFormatIndex;
                            break;
                        }
                    }
                }
            }
        }

        // Set the export states. By default, the export states are always set to
        // true except for the option eEXPORT_TEXTURE_AS_EMBEDDED. The code below
        // shows how to change these states.
        IOS_REF.SetBoolProp(EXP_FBX_MATERIAL,        true);
        IOS_REF.SetBoolProp(EXP_FBX_TEXTURE,         true);
        IOS_REF.SetBoolProp(EXP_FBX_EMBEDDED,        pEmbedMedia);
        IOS_REF.SetBoolProp(EXP_FBX_ANIMATION,       true);
        IOS_REF.SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true);

        // Initialize the exporter by providing a filename.
        if(lExporter->Initialize(pFilename, pFileFormat, pSdkManager->GetIOSettings()) == false)
        {
            FBXSDK_printf("Call to FbxExporter::Initialize() failed.\n");
            FBXSDK_printf("Error returned: %s\n\n", lExporter->GetLastErrorString());
            return false;
        }

        FbxManager::GetFileFormatVersion(lMajor, lMinor, lRevision);
        FBXSDK_printf("FBX version number for this version of the FBX SDK is %d.%d.%d\n\n", lMajor, lMinor, lRevision);

        // Export the scene.
        lStatus = lExporter->Export(pDocument);

        // Destroy the exporter.
        lExporter->Destroy();
        return lStatus;
    }

    int main(int argc, char** argv)
    {
        FbxManager* lSdkManager = NULL;
        FbxDocument* lDocument = NULL;
        bool lResult;

        // Prepare the FBX SDK.
        InitializeSdkObjects(lSdkManager);

        // create the main document
        lDocument = FbxDocument::Create(lSdkManager,"RootDoc");

        // Create the scene.
        lResult = CreateDocument(lSdkManager, lDocument);

        if(lResult == false)
        {
            FBXSDK_printf("\n\nAn error occurred while creating the document...\n");
            DestroySdkObjects(lSdkManager);
            return 0;
        }

        // Save the document.

        // The example can take an output file name as an argument.
        if(argc > 1)
        {
            lResult = SaveDocument(lSdkManager, lDocument, argv[1]);
        }
        // A default output file name is given otherwise.
        else
        {
            lResult = SaveDocument(lSdkManager, lDocument, SAMPLE_FILENAME);
        }

        if(lResult == false)
        {
            FBXSDK_printf("\n\nAn error occurred while saving the document...\n");
            DestroySdkObjects(lSdkManager);
            return 0;
        }

        // Destroy all objects created by the FBX SDK.
        DestroySdkObjects(lSdkManager);

        return 0;
    }

    bool CreateDocument(FbxManager* pSdkManager, FbxDocument* pDocument)
    {
        int lCount;

        // create document info
        FbxDocumentInfo* lDocInfo = FbxDocumentInfo::Create(pSdkManager,"DocInfo");
        lDocInfo->mTitle = "Example document";
        lDocInfo->mSubject = "Illustrates the creation of FbxDocument with geometries, materials and lights.";
        lDocInfo->mAuthor = "ExportDocument.exe sample program.";
        lDocInfo->mRevision = "rev. 1.0";
        lDocInfo->mKeywords = "Fbx document";
        lDocInfo->mComment = "no particular comments required.";

        // add the documentInfo
        pDocument->SetDocumentInfo(lDocInfo);

        // NOTE: Objects created directly in the SDK Manager are not visible
        // to the disk save routines unless they are manually connected to the
        // documents (see below). Ideally, one would directly use the FbxScene/FbxDocument
        // during the creation of objects so they are automatically connected and become visible
        // to the disk save routines.
        FbxNode* lPlane = CreatePlane(pSdkManager, "Plane");

        // add the geometry to the main document.
        pDocument->AddRootMember(lPlane);
        lCount = pDocument->GetRootMemberCount();  // lCount = 1: only the lPlane
        lCount = pDocument->GetMemberCount();      // lCount = 3: the FbxNode - lPlane; FbxMesh belongs to lPlane; Material that connect to lPlane

        // Create sub document to contain materials.
        FbxDocument* lMatDocument = FbxDocument::Create(pSdkManager,"Material");

        CreateMatDocument(pSdkManager, lMatDocument);
        // Connect the light sub document to main document
        pDocument->AddMember(lMatDocument);

        // Create sub document to contain lights
        FbxDocument* lLightDocument = FbxDocument::Create(pSdkManager,"Light");
        CreateLightDocument(pSdkManager, lLightDocument);
        // Connect the light sub document to main document
        pDocument->AddMember(lLightDocument);

        lCount = pDocument->GetMemberCount();       // lCount = 5 : 3 add two sub document

        // document can contain animation. Please refer to other sample about how to set animation
        pDocument->CreateAnimStack("PlanAnim");

        lCount = pDocument->GetRootMemberCount();  // lCount = 1: only the lPlane
        lCount = pDocument->GetMemberCount();      // lCount = 7: 5 add AnimStack and AnimLayer
        lCount = pDocument->GetMemberCount(FBX_TYPE(FbxDocument));    // lCount = 2

        return true;
    }

    // Create material sub document
    void CreateMatDocument(FbxManager* pSdkManager, FbxDocument* pMatDocument)
    {
        // create document info
        FbxDocumentInfo* lDocInfo = FbxDocumentInfo::Create(pSdkManager,"DocInfo");
        lDocInfo->mTitle = "Sub document for materials";
        lDocInfo->mSubject = "Illustrates the creation of sub-FbxDocument with materials.";
        lDocInfo->mAuthor = "ExportDocument.exe sample program.";
        lDocInfo->mRevision = "rev. 1.0";
        lDocInfo->mKeywords = "Fbx material document";
        lDocInfo->mComment = "no particular comments required.";

        // add the documentInfo
        pMatDocument->SetDocumentInfo(lDocInfo);

        // add material object to the sub document
        pMatDocument->AddMember(CreateMaterial(pSdkManager));
    }

    // Create light sub document
    void CreateLightDocument(FbxManager* pSdkManager, FbxDocument* pLightDocument)
    {
        // create document info
        FbxDocumentInfo* lDocInfo = FbxDocumentInfo::Create(pSdkManager,"DocInfo");
        lDocInfo->mTitle = "Sub document for lights";
        lDocInfo->mSubject = "Illustrates the creation of sub-FbxDocument with lights.";
        lDocInfo->mAuthor = "ExportDocument.exe sample program.";
        lDocInfo->mRevision = "rev. 1.0";
        lDocInfo->mKeywords = "Fbx light document";
        lDocInfo->mComment = "no particular comments required.";

        // add the documentInfo
        pLightDocument->SetDocumentInfo(lDocInfo);

        // add light objects to the sub document
        pLightDocument->AddMember(CreateLight(pSdkManager, FbxLight::eSpot));
        pLightDocument->AddMember(CreateLight(pSdkManager, FbxLight::ePoint));
    }

    // Create a plane mesh.
    FbxNode* CreatePlane(FbxManager* pSdkManager, char* pName)
    {
        int i;
        FbxMesh* lMesh = FbxMesh::Create(pSdkManager,pName);

        FbxVector4 lControlPoint0(-50, 0,   50);
        FbxVector4 lControlPoint1(50,  0,   50);
        FbxVector4 lControlPoint2(50,  100, 50);
        FbxVector4 lControlPoint3(-50, 100, 50);

        FbxVector4 lNormalZPos(0, 0, 1);

        // Create control points.
        lMesh->InitControlPoints(4);
        FbxVector4* lControlPoints = lMesh->GetControlPoints();

        lControlPoints[0]  = lControlPoint0;
        lControlPoints[1]  = lControlPoint1;
        lControlPoints[2]  = lControlPoint2;
        lControlPoints[3]  = lControlPoint3;

        // We want to have one normal for each vertex (or control point),
        // so we set the mapping mode to eByControlPoint.
        FbxGeometryElementNormal* lElementNormal= lMesh->CreateElementNormal();

        lElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);

        // Set the normal values for every control point.
        lElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);

        lElementNormal->GetDirectArray().Add(lNormalZPos);
        lElementNormal->GetDirectArray().Add(lNormalZPos);
        lElementNormal->GetDirectArray().Add(lNormalZPos);
        lElementNormal->GetDirectArray().Add(lNormalZPos);

        // Array of polygon vertices.
        int lPolygonVertices[] = { 0, 1, 2, 3 };

        // Create UV for Diffuse channel.
        FbxGeometryElementUV* lUVDiffuseElement = lMesh->CreateElementUV( "DiffuseUV");
        FBX_ASSERT( lUVDiffuseElement != NULL);
        lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
        lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        FbxVector2 lVectors0(0, 0);
        FbxVector2 lVectors1(1, 0);
        FbxVector2 lVectors2(1, 1);
        FbxVector2 lVectors3(0, 1);

        lUVDiffuseElement->GetDirectArray().Add(lVectors0);
        lUVDiffuseElement->GetDirectArray().Add(lVectors1);
        lUVDiffuseElement->GetDirectArray().Add(lVectors2);
        lUVDiffuseElement->GetDirectArray().Add(lVectors3);

        //Now we have set the UVs as eIndexToDirect reference and in eByPolygonVertex  mapping mode
        //we must update the size of the index array.
        lUVDiffuseElement->GetIndexArray().SetCount(4);

        // Create polygons. Assign texture and texture UV indices.
        // all faces of the cube have the same texture
        lMesh->BeginPolygon(-1, -1, -1, false);

        for(i = 0; i < 4; i++)
        {
            // Control point index
            lMesh->AddPolygon(lPolygonVertices[i]);

            // update the index array of the UVs that map the texture to the face
            lUVDiffuseElement->GetIndexArray().SetAt(i, i);
        }

        lMesh->EndPolygon ();

        // create a FbxNode
        FbxNode* lNode = FbxNode::Create(pSdkManager,pName);

        // set the node attribute
        lNode->SetNodeAttribute(lMesh);

        // set the shading mode to view texture
        lNode->SetShadingMode(FbxNode::eTextureShading);

        // rotate the plane
        lNode->LclRotation.Set(FbxVector4(90, 0, 0));

        // Set material mapping.
        FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial();
        lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon);
        lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
        if( !lMesh->GetElementMaterial( 0))
            return NULL;

        // add material to the node.
        // the material can't in different document with the geometry node or in sub-document
        // we create a simple material here which belong to main document
        FbxString lMaterialName = "material_for_plane";
        FbxString lShadingName  = "Phong";
        FbxSurfacePhong* lMaterial = FbxSurfacePhong::Create(pSdkManager, lMaterialName.Buffer());

        lMaterial->Diffuse.Set(FbxDouble3(1.0, 1.0, 0));
        lMaterial->DiffuseFactor.Set(1.);

        lNode->AddMaterial(lMaterial);

        // We are in eByPolygon, so there's only need for index (a plane has 1 polygon).
        lMaterialElement->GetIndexArray().SetCount(lMesh->GetPolygonCount());

        // Set the Index to the material
        for(int i=0; i<lMesh->GetPolygonCount(); ++i)
            lMaterialElement->GetIndexArray().SetAt(i,0);

        // return the FbxNode
        return lNode;
    }

    // Create a texture
    FbxTexture*  CreateTexture(FbxManager* pSdkManager)
    {
        FbxFileTexture* lTexture = FbxFileTexture::Create(pSdkManager,"");

        // Resource file must be in the application's directory.
        FbxString lPath = FbxGetApplicationDirectory();
        FbxString lTexPath = lPath + "\\Crate.jpg";

        // Set texture properties.
        lTexture->SetFileName(lTexPath.Buffer());
        lTexture->SetName("Diffuse Texture");
        lTexture->SetTextureUse(FbxTexture::eStandard);
        lTexture->SetMappingType(FbxTexture::eUV);
        lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial);
        lTexture->SetSwapUV(false);
        lTexture->SetAlphaSource (FbxTexture::eNone);
        lTexture->SetTranslation(0.0, 0.0);
        lTexture->SetScale(1.0, 1.0);
        lTexture->SetRotation(0.0, 0.0);

        return lTexture;
    }

    // Create material.
    // FBX scene must connect materials FbxNode, otherwise materials will not be exported.
    // FBX document don't need connect materials to FbxNode, it can export standalone materials.
    FbxSurfacePhong* CreateMaterial(FbxManager* pSdkManager)
    {
        FbxString lMaterialName = "material";
        FbxString lShadingName  = "Phong";
        FbxDouble3 lBlack(0.0, 0.0, 0.0);
        FbxDouble3 lRed(1.0, 0.0, 0.0);
        FbxDouble3 lDiffuseColor(0.75, 0.75, 0.0);
        FbxSurfacePhong* lMaterial = FbxSurfacePhong::Create(pSdkManager, lMaterialName.Buffer());

        // Generate primary and secondary colors.
        lMaterial->Emissive      .Set(lBlack);
        lMaterial->Ambient       .Set(lRed);
        lMaterial->AmbientFactor .Set(1.);
        // Add texture for diffuse channel
        lMaterial->Diffuse       .ConnectSrcObject(CreateTexture(pSdkManager));
        lMaterial->DiffuseFactor .Set(1.);
        lMaterial->TransparencyFactor  .Set(0.4);
        lMaterial->ShadingModel        .Set(lShadingName);
        lMaterial->Shininess           .Set(0.5);
        lMaterial->Specular            .Set(lBlack);
        lMaterial->SpecularFactor      .Set(0.3);

        return lMaterial;
    }

    // Create light.
    FbxNode* CreateLight(FbxManager* pSdkManager, FbxLight::EType pType)
    {
        FbxString lLightName;
        FbxDouble val;

        switch (pType)
        {
            case FbxLight::eSpot:
                lLightName = "SpotLight";
                break;
            case FbxLight::ePoint:
                lLightName = "PointLight";
                break;
            case FbxLight::eDirectional:
                lLightName = "DirectionalLight";
                break;
            default:
                break;
        }

        FbxLight* lFbxLight = FbxLight::Create(pSdkManager, lLightName.Buffer());

        lFbxLight->LightType.Set(pType);

        // parameters for spot light
        if (pType == FbxLight::eSpot)
        {
            lFbxLight->InnerAngle.Set(40.0);
            val = lFbxLight->InnerAngle.Get(); // val = 40

            lFbxLight->OuterAngle.Set(40);
            val = lFbxLight->OuterAngle.Get(); // val = 40
        }

        //
        // Light Color...
        //
        FbxDouble3 lColor;
        lColor[0] = 0.0;
        lColor[1] = 1.0;
        lColor[2] = 0.5;
        lFbxLight->Color.Set(lColor);
        FbxDouble3 val3 = lFbxLight->Color.Get(); // val3 = (0, 1, 0.5)

        //
        // Light Intensity...
        //
        lFbxLight->Intensity.Set(100.0);
        val = lFbxLight->Intensity.Get(); // val = 100

        // create a FbxNode
        FbxNode* lNode = FbxNode::Create(pSdkManager,lLightName+"Node");

        // set the node attribute
        lNode->SetNodeAttribute(lFbxLight);
        lNode->LclTranslation.Set(FbxDouble3(20, 30, 100));
        val3 = lNode->LclTranslation.Get(); // val3 = (20, 30, 100)

        return lNode;
    }