ExportScene04/main.cxx

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

 Copyright (C) 2001 - 2010 Autodesk, Inc. and/or its licensors.
 All Rights Reserved.

 The coded instructions, statements, computer programs, and/or related material 
 (collectively the "Data") in these files contain unpublished information 
 proprietary to Autodesk, Inc. and/or its licensors, which is protected by 
 Canada and United States of America federal copyright law and by international 
 treaties. 
 
 The Data may not be disclosed or distributed to third parties, in whole or in
 part, without the prior written consent of Autodesk, Inc. ("Autodesk").

 THE DATA IS PROVIDED "AS IS" AND WITHOUT WARRANTY.
 ALL WARRANTIES ARE EXPRESSLY EXCLUDED AND DISCLAIMED. AUTODESK MAKES NO
 WARRANTY OF ANY KIND WITH RESPECT TO THE DATA, EXPRESS, IMPLIED OR ARISING
 BY CUSTOM OR TRADE USAGE, AND DISCLAIMS ANY IMPLIED WARRANTIES OF TITLE, 
 NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE OR USE. 
 WITHOUT LIMITING THE FOREGOING, AUTODESK DOES NOT WARRANT THAT THE OPERATION
 OF THE DATA WILL BE UNINTERRUPTED OR ERROR FREE. 
 
 IN NO EVENT SHALL AUTODESK, ITS AFFILIATES, PARENT COMPANIES, LICENSORS
 OR SUPPLIERS ("AUTODESK GROUP") BE LIABLE FOR ANY LOSSES, DAMAGES OR EXPENSES
 OF ANY KIND (INCLUDING WITHOUT LIMITATION PUNITIVE OR MULTIPLE DAMAGES OR OTHER
 SPECIAL, DIRECT, INDIRECT, EXEMPLARY, INCIDENTAL, LOSS OF PROFITS, REVENUE
 OR DATA, COST OF COVER OR CONSEQUENTIAL LOSSES OR DAMAGES OF ANY KIND),
 HOWEVER CAUSED, AND REGARDLESS OF THE THEORY OF LIABILITY, WHETHER DERIVED
 FROM CONTRACT, TORT (INCLUDING, BUT NOT LIMITED TO, NEGLIGENCE), OR OTHERWISE,
 ARISING OUT OF OR RELATING TO THE DATA OR ITS USE OR ANY OTHER PERFORMANCE,
 WHETHER OR NOT AUTODESK HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS
 OR DAMAGE. 

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

//
// The scene created in this example is a group of lights, a marker and
// a camera. An animation stack rotates the lights and moves the camera 
// around.
//
// The example illustrates how to:
//        1) create a light and it assign a gobo
//        2) set global light settings
//        3) create a marker
//        4) create a camera and link it to a point of interest
//        5) create an animation stack
//        6) export a scene in a .FBX file
//

#include <math.h>

#include <fbxsdk.h>

#include "../Common/Common.h"

#define SAMPLE_FILENAME "ExportScene04.fbx"


// Function prototypes.
bool CreateScene(KFbxScene* pScene);

KFbxNode* CreateLightGroup(KFbxScene* pScene, char* pName);
KFbxNode* CreateLight(KFbxScene* pScene, char* pName);
KFbxNode* CreateMarker(KFbxScene* pScene, char* pName);
KFbxNode* CreateCamera(KFbxScene* pScene, char* pName);

void SetCameraPointOfInterest(KFbxNode* pCamera, KFbxNode* pPointOfInterest);

void SetLightGroupDefaultPosition(KFbxNode* pLightGroup);
void SetLightDefaultPosition(KFbxNode* pLight, int pIndex);
void SetMarkerDefaultPosition(KFbxNode* pMarker);
void SetCamera1DefaultPosition(KFbxNode* pCamera);
void SetCamera2DefaultPosition(KFbxNode* pCamera);

void AnimateLightGroup(KFbxNode* pLightGroup, KFbxAnimLayer* pAnimLayer);
void AnimateLight(KFbxNode* pLight, int pIndex, KFbxAnimLayer* pAnimLayer);
void AnimateCamera(KFbxNode* pLightGroup, KFbxAnimLayer* pAnimLayer);


int main(int argc, char** argv)
{
    KFbxSdkManager* lSdkManager = NULL;
    KFbxScene* lScene = NULL;
    bool lResult;

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

    // Create the scene.

    lResult = CreateScene(lScene);

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

    // Save the scene.

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

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

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

    return 0;
}

bool CreateScene(KFbxScene* pScene)
{
    KFbxNode* lLightGroup = CreateLightGroup(pScene, "LightGroup");
    KFbxNode* lMarker = CreateMarker(pScene, "Marker");
    KFbxNode* lCamera1 = CreateCamera(pScene, "Camera1");
    KFbxNode* lCamera2 = CreateCamera(pScene, "Camera2");

    pScene->GetGlobalSettings().SetAmbientColor(KFbxColor(1.0, 0.5, 0.2));

    SetCameraPointOfInterest(lCamera1, lMarker);
    SetCameraPointOfInterest(lCamera2, lCamera1);

    SetLightGroupDefaultPosition(lLightGroup);
    SetMarkerDefaultPosition(lMarker);
    SetCamera1DefaultPosition(lCamera1);
    SetCamera2DefaultPosition(lCamera2);

    // Create the Animation Stack
    KFbxAnimStack* lAnimStack = KFbxAnimStack::Create(pScene, "Rotating lights");

        // The animation nodes can only exist on AnimLayers therefore it is mandatory to
        // add at least one AnimLayer to the AnimStack. And for the purpose of this example,
        // one layer is all we need.
        KFbxAnimLayer* lAnimLayer = KFbxAnimLayer::Create(pScene, "Base Layer");
        lAnimStack->AddMember(lAnimLayer);

    // Build the scene graph.
    KFbxNode* lRootNode = pScene->GetRootNode();
    lRootNode->AddChild(lLightGroup);
    lRootNode->AddChild(lMarker);
    lRootNode->AddChild(lCamera1);
    lCamera1->AddChild(lCamera2);


    // Set perspective camera as the default camera.
    pScene->GetGlobalSettings().SetDefaultCamera(PRODUCER_PERSPECTIVE);

    AnimateLightGroup(lLightGroup, lAnimLayer);
    AnimateCamera(lCamera1, lAnimLayer);

    return true;
}

// Create 6 lights and set global light settings.
KFbxNode* CreateLightGroup(KFbxScene* pScene, char* pName)
{
    KString lLightName;
    KFbxNode* lGroup = NULL;
    KFbxNode* lNode = NULL;
    KFbxLight* lLight = NULL;
    int i;

    lGroup = KFbxNode::Create(pScene,pName);

    for(i = 0; i < 6; i++)
    {
        lLightName = pName;
        lLightName += "-Light";
        lLightName += i;

        lNode = CreateLight(pScene, lLightName.Buffer());
        lGroup->AddChild(lNode);
    }

    for (i = 0; i < 6; i++)
    {
        lLight = (KFbxLight*) lGroup->GetChild(i)->GetNodeAttribute();
        lLight->FileName.Set("gobo.tif");// Resource file is in current directory.
        lLight->DrawGroundProjection.Set(true);
        lLight->DrawVolumetricLight.Set(true);
        lLight->DrawFrontFacingVolumetricLight.Set(false);
    }

    return lGroup;
}

// Create a spotlight. 
KFbxNode* CreateLight(KFbxScene* pScene, char* pName)
{
    KFbxLight* lLight = KFbxLight::Create(pScene,pName);

    lLight->LightType.Set(KFbxLight::eSPOT);
    lLight->CastLight.Set(true);

    KFbxNode* lNode = KFbxNode::Create(pScene,pName);

    lNode->SetNodeAttribute(lLight);

    return lNode;
}

// Create a marker to use a point of interest for the camera. 
KFbxNode* CreateMarker(KFbxScene* pScene, char* pName)
{
    KFbxMarker* lMarker = KFbxMarker::Create(pScene,pName);

    KFbxNode* lNode = KFbxNode::Create(pScene,pName);

    lNode->SetNodeAttribute(lMarker);

    return lNode;
}

KFbxNode* CreateCamera(KFbxScene* pScene, char* pName)
{
    KFbxCamera* lCamera = KFbxCamera::Create(pScene,pName);

    // Modify some camera default settings.
    lCamera->SetApertureMode(KFbxCamera::eVERTICAL);
    lCamera->SetApertureWidth(0.816);
    lCamera->SetApertureHeight(0.612);
    lCamera->SetSqueezeRatio(0.5);

    KFbxNode* lNode = KFbxNode::Create(pScene,pName);

    lNode->SetNodeAttribute(lCamera);

    return lNode;
}

void SetCameraPointOfInterest(KFbxNode* pCamera, KFbxNode* pPointOfInterest)
{
    // Set the camera to always point at this node.
    pCamera->SetTarget(pPointOfInterest);
}

// The light group is just over the XZ plane.
void SetLightGroupDefaultPosition(KFbxNode* pLightGroup)
{
    int i;

    for (i = 0; i < pLightGroup->GetChildCount(); i++)
    {
        SetLightDefaultPosition(pLightGroup->GetChild(i), i);
    }

    pLightGroup->LclTranslation.Set(KFbxVector4(0.0, 15.0, 0.0));
    pLightGroup->LclRotation.Set(KFbxVector4(0.0, 0.0, 0.0));
    pLightGroup->LclScaling.Set(KFbxVector4(1.0, 1.0, 1.0));
}

void SetLightDefaultPosition(KFbxNode* pLight, int pIndex)
{
    // Set light location depending of it's index.
    pLight->LclTranslation.Set(KFbxVector4((cos((double)pIndex) * 40.0), 0.0, (sin((double)pIndex) * 40.0)));
    pLight->LclRotation.Set(KFbxVector4(20.0, (90.0 - pIndex * 60.0), 0.0));
    pLight->LclScaling.Set(KFbxVector4(1.0, 1.0, 1.0));

    // Set light attributes depending of it's index.
    fbxDouble3 lColor[6] = 
    {
        fbxDouble3(1.0, 0.0, 0.0), 
        fbxDouble3(1.0, 1.0, 0.0), 
        fbxDouble3(0.0, 1.0, 0.0), 
        fbxDouble3(0.0, 1.0, 1.0), 
        fbxDouble3(0.0, 0.0, 1.0), 
        fbxDouble3(1.0, 0.0, 1.0)
    };

    KFbxLight* light = pLight->GetLight();
    if (light)
    {
        light->Color.Set(lColor[pIndex % 6]);
        light->Intensity.Set(33.0);
        light->ConeAngle.Set(90.0);
        light->Fog.Set(100.0);
    }
}

void SetMarkerDefaultPosition(KFbxNode* pMarker)
{
    // The marker is at the origin.
    pMarker->LclTranslation.Set(KFbxVector4(0.0, 0.0, 0.0));
    pMarker->LclRotation.Set(KFbxVector4(0.0, 0.0, 0.0));
    pMarker->LclScaling.Set(KFbxVector4(1.0, 1.0, 1.0));
}

// The code below shows how to compute the camera rotation.
// In the present case, it wouldn't be necessary since the
// camera is set to point to the marker. 
void SetCamera1DefaultPosition(KFbxNode* pCamera)
{
    KFbxVector4 lCameraLocation(0.0, 100.0, -300.0);
    KFbxVector4 lDefaultPointOfInterest(1.0, 100.0, -300.0);
    KFbxVector4 lNewPointOfInterest(0, 0, 0);
    KFbxVector4 lRotation;
    KFbxVector4 lScaling(1.0, 1.0, 1.0);

    KFbxVector4::AxisAlignmentInEulerAngle(lCameraLocation, lDefaultPointOfInterest, lNewPointOfInterest, lRotation);

    pCamera->LclTranslation.Set(lCameraLocation);
    pCamera->LclRotation.Set(lRotation);
    pCamera->LclScaling.Set(lScaling);
}

void SetCamera2DefaultPosition(KFbxNode* pCamera)
{
    pCamera->LclTranslation.Set(KFbxVector4(-150.0, 0.0, 75.0));
}

// The light group rises and rotates.
void AnimateLightGroup(KFbxNode* pLightGroup, KFbxAnimLayer* pAnimLayer)
{
    KFbxAnimCurve* lCurve = NULL;
    KTime lTime;
    int i;
    int lKeyIndex = 0;

    for (i = 0; i < pLightGroup->GetChildCount(); i++)
    {
        AnimateLight(pLightGroup->GetChild(i), i, pAnimLayer);
    }

    // Create the CurveNodes (they are necessary for the GetCurve to successfully allocate the Animation curve)
    pLightGroup->LclRotation.GetCurveNode(pAnimLayer, true);
    pLightGroup->LclTranslation.GetCurveNode(pAnimLayer, true);

    // Y axis rotation.
    lCurve = pLightGroup->LclRotation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_R_Y, true);
    if (lCurve)
    {
        lCurve->KeyModifyBegin();

        lTime.SetSecondDouble(0.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 0.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);

        lTime.SetSecondDouble(10.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 5*360.0);

        lCurve->KeyModifyEnd();
    }

    // Y axis translation.
    lCurve = pLightGroup->LclTranslation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_T_Y, true);
    if (lCurve)
    {
        lCurve->KeyModifyBegin();

        lTime.SetSecondDouble(0.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 15.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

        lTime.SetSecondDouble(5.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 200.0);

        lCurve->KeyModifyEnd();
    }
}

// The lights are changing color, intensity, orientation and cone angle.
void AnimateLight(KFbxNode* pLight, int pIndex, KFbxAnimLayer* pAnimLayer)
{
    KFbxAnimCurve* lCurve = NULL;
    KTime lTime;
    int i, j;
    int lKeyIndex = 0;

    KFbxLight* light = pLight->GetLight();

    // Intensity fade in/out.
    // Create the CurveNode (it is necessary for the GetCurve to successfully allocate the Animation curve)
    light->Intensity.GetCurveNode(pAnimLayer, true);
    lCurve = light->Intensity.GetCurve<KFbxAnimCurve>(pAnimLayer, true);
    if (lCurve)
    {
        lCurve->KeyModifyBegin();

        lTime.SetSecondDouble(0.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 0.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

        lTime.SetSecondDouble(3.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 33.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);

        lTime.SetSecondDouble(7.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 33.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

        lTime.SetSecondDouble(10.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 0.0);

        lCurve->KeyModifyEnd();
    }

    // Fog fade in/out
    // Create the CurveNode (it is necessary for the GetCurve to successfully allocate the Animation curve)
    light->Fog.GetCurveNode(pAnimLayer, true);
    lCurve = light->Fog.GetCurve<KFbxAnimCurve>(pAnimLayer, true);
    if (lCurve)
    {
        lCurve->KeyModifyBegin();

        lTime.SetSecondDouble(0.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 0.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

        lTime.SetSecondDouble(3.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 33.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);

        lTime.SetSecondDouble(7.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 33.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

        lTime.SetSecondDouble(10.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, 0.0);

        lCurve->KeyModifyEnd();
    }

    // X rotation swoops & cone angle woobles.
    {
        // Create the CurveNodes (they are necessary for the GetCurve to successfully allocate the Animation curve)
        pLight->LclRotation.GetCurveNode(pAnimLayer, true);
        light->ConeAngle.GetCurveNode(pAnimLayer, true);

        lCurve = pLight->LclRotation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_R_X, true);
        KFbxAnimCurve* lConeCurve = light->ConeAngle.GetCurve<KFbxAnimCurve>(pAnimLayer,true);
        double lValue;

        lCurve->KeyModifyBegin();
        lConeCurve->KeyModifyBegin();

        for (i = 0; i < 8; i++)
        {
            lTime.SetSecondDouble((double)i * 0.833333);
            lValue = cos((((double)i) + (((double)pIndex) * 60.0)) * 72.0);

            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, float((lValue - 0.4) * 30.0));
            lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
            lKeyIndex = lConeCurve->KeyAdd(lTime);
            lConeCurve->KeySetValue(lKeyIndex, float((2.0 - (lValue + 1.0)) * 45.0));
            lConeCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);
        }

        // Finally, have the lights spread out and lose focus.
        lTime.SetSecondDouble(10.0);

        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySetValue(lKeyIndex, -90.0);
        lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

        lKeyIndex = lConeCurve->KeyAdd(lTime);
        lConeCurve->KeySetValue(lKeyIndex, 180.0);
        lConeCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);

        lCurve->KeyModifyEnd();
        lConeCurve->KeyModifyEnd();
    }

    // Color cycling.
    {
        fbxDouble3 lColor[6] = 
        {
            fbxDouble3(1.0, 0.0, 0.0), 
            fbxDouble3(1.0, 1.0, 0.0), 
            fbxDouble3(0.0, 1.0, 0.0), 
            fbxDouble3(0.0, 1.0, 1.0), 
            fbxDouble3(0.0, 0.0, 1.0), 
            fbxDouble3(1.0, 0.0, 1.0)
        };

        KFbxAnimCurve* lCurve[3];
        // Create the CurveNodes (they are necessary for the GetCurve to successfully allocate the Animation curve)
        light->Color.GetCurveNode(pAnimLayer, true);
        lCurve[0] = light->Color.GetCurve<KFbxAnimCurve>(pAnimLayer,KFCURVENODE_COLOR_RED, true);
        lCurve[1] = light->Color.GetCurve<KFbxAnimCurve>(pAnimLayer,KFCURVENODE_COLOR_GREEN, true);
        lCurve[2] = light->Color.GetCurve<KFbxAnimCurve>(pAnimLayer,KFCURVENODE_COLOR_BLUE, true);

        if (lCurve[0] && lCurve[1] && lCurve[2])
        {
            lCurve[0]->KeyModifyBegin();
            lCurve[1]->KeyModifyBegin();
            lCurve[2]->KeyModifyBegin();

            for (i = 0; i < 24; i++)
            {
                j = i + pIndex;

                while (j > 5)
                {
                    j -= 6;
                }

                lTime.SetSecondDouble((double)i * 0.4166666);

                lKeyIndex = lCurve[0]->KeyAdd(lTime);
                lCurve[0]->KeySetValue(lKeyIndex, (kFCurveDouble)lColor[j][0]);
                lCurve[0]->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

                lKeyIndex = lCurve[1]->KeyAdd(lTime);
                lCurve[1]->KeySetValue(lKeyIndex, (kFCurveDouble)lColor[j][1]);
                lCurve[1]->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);

                lKeyIndex = lCurve[2]->KeyAdd(lTime);
                lCurve[2]->KeySetValue(lKeyIndex, (kFCurveDouble)lColor[j][2]);
                lCurve[2]->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
            }

            lCurve[0]->KeyModifyEnd();
            lCurve[1]->KeyModifyEnd();
            lCurve[2]->KeyModifyEnd();
        }
    }
}

// The camera is rising and rolling twice.
void AnimateCamera(KFbxNode* pCamera, KFbxAnimLayer* pAnimLayer)
{
    KFbxAnimCurve* lCurve = NULL;
    KTime lTime;
    int lKeyIndex = 0;

    // Create the CurveNode (it is necessary for the GetCurve to successfully allocate the Animation curve)
    pCamera->LclTranslation.GetCurveNode(pAnimLayer, true);

    // X translation.
    lCurve = pCamera->LclTranslation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_T_X, true);
    if (lCurve)
    {
        lCurve->KeyModifyBegin();

        lTime.SetSecondDouble(0.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySet(lKeyIndex, lTime, 0.0, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);

        lTime.SetSecondDouble(10.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySet(lKeyIndex, lTime, 200.0);

        lCurve->KeyModifyEnd();
    }

    // Y translation.
    lCurve = pCamera->LclTranslation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_T_Y, true);
    if (lCurve)
    {
        lCurve->KeyModifyBegin();

        lTime.SetSecondDouble(0.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySet(lKeyIndex, lTime, 0.0, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);

        lTime.SetSecondDouble(10.0);
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySet(lKeyIndex, lTime, 300.0);

        lCurve->KeyModifyEnd();
    }

    // Camera roll.
    KFbxCamera* cam = pCamera->GetCamera();
    // Create the CurveNode (it is necessary for the GetCurve to successfully allocate the Animation curve)
    cam->Roll.GetCurveNode(pAnimLayer, true);
    lCurve = cam->Roll.GetCurve<KFbxAnimCurve>(pAnimLayer, true);
    if (lCurve)
    {
        lCurve->KeyModifyBegin();

        lTime.SetSecondDouble (0.0); 
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySet(lKeyIndex, lTime, 0.0, KFbxAnimCurveDef::eINTERPOLATION_LINEAR);

        lTime.SetSecondDouble(10.0); 
        lKeyIndex = lCurve->KeyAdd(lTime);
        lCurve->KeySet(lKeyIndex, lTime, 2*360.0);

        lCurve->KeyModifyEnd();
    }    
}