#include <fbxsdk.h>
#include "../Common/Common.h"
#include "Thumbnail.h"
#define SAMPLE_FILENAME "ExportScene01.fbx"
bool CreateScene(KFbxSdkManager* pSdkManager, KFbxScene* pScene);
KFbxNode* CreatePatch(KFbxScene* pScene, char* pName);
KFbxNode* CreateSkeleton(KFbxScene* pScene, char* pName);
void LinkPatchToSkeleton(KFbxScene* pScene, KFbxNode* pPatch, KFbxNode* pSkeletonRoot);
void StoreBindPose(KFbxScene* pScene, KFbxNode* pPatch, KFbxNode* pSkeletonRoot);
void StoreRestPose(KFbxScene* pScene, KFbxNode* pSkeletonRoot);
void AnimateSkeleton(KFbxScene* pScene, KFbxNode* pSkeletonRoot);
void AddThumbnailToScene(KFbxScene* pScene);
void AddNodeRecursively(KArrayTemplate<KFbxNode*>& pNodeArray, KFbxNode* pNode);
void SetXMatrix(KFbxXMatrix& pXMatrix, const KFbxMatrix& pMatrix);
int main(int argc, char** argv)
{
KFbxSdkManager* lSdkManager = NULL;
KFbxScene* lScene = NULL;
bool lResult;
InitializeSdkObjects(lSdkManager, lScene);
lResult = CreateScene(lSdkManager, lScene);
if(lResult == false)
{
printf("\n\nAn error occurred while creating the scene...\n");
DestroySdkObjects(lSdkManager);
return 0;
}
if(argc > 1)
{
lResult = SaveScene(lSdkManager, lScene, argv[1]);
}
else
{
lResult = SaveScene(lSdkManager, lScene, SAMPLE_FILENAME);
}
if(lResult == false)
{
printf("\n\nAn error occurred while saving the scene...\n");
DestroySdkObjects(lSdkManager);
return 0;
}
DestroySdkObjects(lSdkManager);
return 0;
}
bool CreateScene(KFbxSdkManager *pSdkManager, KFbxScene* pScene)
{
KFbxDocumentInfo* sceneInfo = KFbxDocumentInfo::Create(pSdkManager,"SceneInfo");
sceneInfo->mTitle = "Example scene";
sceneInfo->mSubject = "Illustrates the creation and animation of a deformed cylinder.";
sceneInfo->mAuthor = "ExportScene01.exe sample program.";
sceneInfo->mRevision = "rev. 1.0";
sceneInfo->mKeywords = "deformed cylinder";
sceneInfo->mComment = "no particular comments required.";
pScene->SetSceneInfo(sceneInfo);
AddThumbnailToScene(pScene);
KFbxNode* lPatch = CreatePatch(pScene, "Patch");
KFbxNode* lSkeletonRoot = CreateSkeleton(pScene, "Skeleton");
KFbxNode* lRootNode = pScene->GetRootNode();
lRootNode->AddChild(lPatch);
lRootNode->AddChild(lSkeletonRoot);
LinkPatchToSkeleton(pScene, lPatch, lSkeletonRoot);
StoreBindPose(pScene, lPatch, lSkeletonRoot);
StoreRestPose(pScene, lSkeletonRoot);
AnimateSkeleton(pScene, lSkeletonRoot);
return true;
}
KFbxNode* CreatePatch(KFbxScene* pScene, char* pName)
{
KFbxPatch* lPatch = KFbxPatch::Create(pScene,pName);
lPatch->InitControlPoints(4, KFbxPatch::eBSPLINE, 7, KFbxPatch::eBSPLINE);
lPatch->SetStep(4, 4);
lPatch->SetClosed(true, false);
KFbxVector4* lVector4 = lPatch->GetControlPoints();
int i;
for (i = 0; i < 7; i++)
{
double lRadius = 15.0;
double lSegmentLength = 20.0;
lVector4[4*i + 0].Set(lRadius, 0.0, (i-3)*lSegmentLength);
lVector4[4*i + 1].Set(0.0, -lRadius, (i-3)*lSegmentLength);
lVector4[4*i + 2].Set(-lRadius, 0.0, (i-3)*lSegmentLength);
lVector4[4*i + 3].Set(0.0, lRadius, (i-3)*lSegmentLength);
}
KFbxNode* lNode = KFbxNode::Create(pScene,pName);
KFbxVector4 lR(-90.0, 0.0, 0.0);
lNode->LclRotation.Set(lR);
lNode->SetNodeAttribute(lPatch);
return lNode;
}
KFbxNode* CreateSkeleton(KFbxScene* pScene, char* pName)
{
KString lRootName(pName);
lRootName += "Root";
KFbxSkeleton* lSkeletonRootAttribute = KFbxSkeleton::Create(pScene, pName);
lSkeletonRootAttribute->SetSkeletonType(KFbxSkeleton::eROOT);
KFbxNode* lSkeletonRoot = KFbxNode::Create(pScene,lRootName.Buffer());
lSkeletonRoot->SetNodeAttribute(lSkeletonRootAttribute);
lSkeletonRoot->LclTranslation.Set(KFbxVector4(0.0, -40.0, 0.0));
KString lLimbNodeName1(pName);
lLimbNodeName1 += "LimbNode1";
KFbxSkeleton* lSkeletonLimbNodeAttribute1 = KFbxSkeleton::Create(pScene,lLimbNodeName1);
lSkeletonLimbNodeAttribute1->SetSkeletonType(KFbxSkeleton::eLIMB_NODE);
lSkeletonLimbNodeAttribute1->Size.Set(1.0);
KFbxNode* lSkeletonLimbNode1 = KFbxNode::Create(pScene,lLimbNodeName1.Buffer());
lSkeletonLimbNode1->SetNodeAttribute(lSkeletonLimbNodeAttribute1);
lSkeletonLimbNode1->LclTranslation.Set(KFbxVector4(0.0, 40.0, 0.0));
KString lLimbNodeName2(pName);
lLimbNodeName2 += "LimbNode2";
KFbxSkeleton* lSkeletonLimbNodeAttribute2 = KFbxSkeleton::Create(pScene,lLimbNodeName2);
lSkeletonLimbNodeAttribute2->SetSkeletonType(KFbxSkeleton::eLIMB_NODE);
lSkeletonLimbNodeAttribute2->Size.Set(1.0);
KFbxNode* lSkeletonLimbNode2 = KFbxNode::Create(pScene,lLimbNodeName2.Buffer());
lSkeletonLimbNode2->SetNodeAttribute(lSkeletonLimbNodeAttribute2);
lSkeletonLimbNode2->LclTranslation.Set(KFbxVector4(0.0, 40.0, 0.0));
lSkeletonRoot->AddChild(lSkeletonLimbNode1);
lSkeletonLimbNode1->AddChild(lSkeletonLimbNode2);
return lSkeletonRoot;
}
void LinkPatchToSkeleton(KFbxScene* pScene, KFbxNode* pPatch, KFbxNode* pSkeletonRoot)
{
int i, j;
KFbxXMatrix lXMatrix;
KFbxNode* lRoot = pSkeletonRoot;
KFbxNode* lLimbNode1 = pSkeletonRoot->GetChild(0);
KFbxNode* lLimbNode2 = lLimbNode1->GetChild(0);
KFbxCluster *lClusterToRoot = KFbxCluster::Create(pScene,"");
lClusterToRoot->SetLink(lRoot);
lClusterToRoot->SetLinkMode(KFbxCluster::eTOTAL1);
for(i=0; i<4; ++i)
for(j=0; j<4; ++j)
lClusterToRoot->AddControlPointIndex(4*i + j, 1.0 - 0.25*i);
KFbxCluster* lClusterToLimbNode1 = KFbxCluster::Create(pScene, "");
lClusterToLimbNode1->SetLink(lLimbNode1);
lClusterToLimbNode1->SetLinkMode(KFbxCluster::eTOTAL1);
for (i =1; i<6; ++i)
for (j=0; j<4; ++j)
lClusterToLimbNode1->AddControlPointIndex(4*i + j, (i == 1 || i == 5 ? 0.25 : 0.50));
KFbxCluster * lClusterToLimbNode2 = KFbxCluster::Create(pScene,"");
lClusterToLimbNode2->SetLink(lLimbNode2);
lClusterToLimbNode2->SetLinkMode(KFbxCluster::eTOTAL1);
for (i=3; i<7; ++i)
for (j=0; j<4; ++j)
lClusterToLimbNode2->AddControlPointIndex(4*i + j, 0.25*(i - 2));
KFbxScene* lScene = pPatch->GetScene();
if( lScene ) lXMatrix = pPatch->EvaluateGlobalTransform();
lClusterToRoot->SetTransformMatrix(lXMatrix);
lClusterToLimbNode1->SetTransformMatrix(lXMatrix);
lClusterToLimbNode2->SetTransformMatrix(lXMatrix);
if( lScene ) lXMatrix = lRoot->EvaluateGlobalTransform();
lClusterToRoot->SetTransformLinkMatrix(lXMatrix);
if( lScene ) lXMatrix = lLimbNode1->EvaluateGlobalTransform();
lClusterToLimbNode1->SetTransformLinkMatrix(lXMatrix);
if( lScene ) lXMatrix = lLimbNode2->EvaluateGlobalTransform();
lClusterToLimbNode2->SetTransformLinkMatrix(lXMatrix);
KFbxGeometry* lPatchAttribute = (KFbxGeometry*) pPatch->GetNodeAttribute();
KFbxSkin* lSkin = KFbxSkin::Create(pScene, "");
lSkin->AddCluster(lClusterToRoot);
lSkin->AddCluster(lClusterToLimbNode1);
lSkin->AddCluster(lClusterToLimbNode2);
lPatchAttribute->AddDeformer(lSkin);
}
void AnimateSkeleton(KFbxScene* pScene, KFbxNode* pSkeletonRoot)
{
KString lAnimStackName;
KTime lTime;
int lKeyIndex = 0;
KFbxNode* lRoot = pSkeletonRoot;
KFbxNode* lLimbNode1 = pSkeletonRoot->GetChild(0);
lAnimStackName = "Bend on 2 sides";
KFbxAnimStack* lAnimStack = KFbxAnimStack::Create(pScene, lAnimStackName);
KFbxAnimLayer* lAnimLayer = KFbxAnimLayer::Create(pScene, "Base Layer");
lAnimStack->AddMember(lAnimLayer);
KFbxAnimCurve* lCurve = lRoot->LclRotation.GetCurve<KFbxAnimCurve>(lAnimLayer, KFCURVENODE_R_Z, 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(1.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 45.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lTime.SetSecondDouble(2.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, -45.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lTime.SetSecondDouble(3.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 0.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lCurve->KeyModifyEnd();
}
lCurve = lLimbNode1->LclRotation.GetCurve<KFbxAnimCurve>(lAnimLayer, KFCURVENODE_R_Z, 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(1.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, -90.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lTime.SetSecondDouble(2.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 90.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lTime.SetSecondDouble(3.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 0.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lCurve->KeyModifyEnd();
}
lAnimStackName = "Bend and turn around";
lAnimStack = KFbxAnimStack::Create(pScene, lAnimStackName);
lAnimLayer = KFbxAnimLayer::Create(pScene, "Base Layer");
lAnimStack->AddMember(lAnimLayer);
lCurve = lRoot->LclRotation.GetCurve<KFbxAnimCurve>(lAnimLayer, 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_CUBIC);
lTime.SetSecondDouble(2.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 720.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lCurve->KeyModifyEnd();
}
lCurve = lLimbNode1->LclRotation.GetCurve<KFbxAnimCurve>(lAnimLayer, KFCURVENODE_R_Z, 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(1.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 90.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lTime.SetSecondDouble(2.0);
lKeyIndex = lCurve->KeyAdd(lTime);
lCurve->KeySetValue(lKeyIndex, 0.0);
lCurve->KeySetInterpolation(lKeyIndex, KFbxAnimCurveDef::eINTERPOLATION_CUBIC);
lCurve->KeyModifyEnd();
}
}
void AddThumbnailToScene(KFbxScene* pScene)
{
KFbxThumbnail* lThumbnail = KFbxThumbnail::Create(pScene,"");
lThumbnail->SetDataFormat(KFbxThumbnail::eRGB_24);
lThumbnail->SetSize(KFbxThumbnail::e64x64);
lThumbnail->SetThumbnailImage(cSceneThumbnail);
if (pScene->GetSceneInfo())
{
pScene->GetSceneInfo()->SetSceneThumbnail(lThumbnail);
}
}
void StoreBindPose(KFbxScene* pScene, KFbxNode* pPatch, KFbxNode* pSkeletonRoot)
{
KArrayTemplate<KFbxNode*> lClusteredFbxNodes;
int i, j;
if (pPatch && pPatch->GetNodeAttribute())
{
int lSkinCount=0;
int lClusterCount=0;
switch (pPatch->GetNodeAttribute()->GetAttributeType())
{
case KFbxNodeAttribute::eMESH:
case KFbxNodeAttribute::eNURB:
case KFbxNodeAttribute::ePATCH:
lSkinCount = ((KFbxGeometry*)pPatch->GetNodeAttribute())->GetDeformerCount(KFbxDeformer::eSKIN);
for(i=0; i<lSkinCount; ++i)
{
KFbxSkin *lSkin=(KFbxSkin*)((KFbxGeometry*)pPatch->GetNodeAttribute())->GetDeformer(i, KFbxDeformer::eSKIN);
lClusterCount+=lSkin->GetClusterCount();
}
break;
}
if (lClusterCount)
{
for (i=0; i<lSkinCount; ++i)
{
KFbxSkin *lSkin=(KFbxSkin*)((KFbxGeometry*)pPatch->GetNodeAttribute())->GetDeformer(i, KFbxDeformer::eSKIN);
lClusterCount=lSkin->GetClusterCount();
for (j=0; j<lClusterCount; ++j)
{
KFbxNode* lClusterNode = lSkin->GetCluster(j)->GetLink();
AddNodeRecursively(lClusteredFbxNodes, lClusterNode);
}
}
lClusteredFbxNodes.Add(pPatch);
}
}
if (lClusteredFbxNodes.GetCount())
{
KFbxPose* lPose = KFbxPose::Create(pScene,pPatch->GetName());
lPose->SetIsBindPose(true);
for (i=0; i<lClusteredFbxNodes.GetCount(); i++)
{
KFbxNode* lKFbxNode = lClusteredFbxNodes.GetAt(i);
KFbxMatrix lBindMatrix = lKFbxNode->EvaluateGlobalTransform();
lPose->Add(lKFbxNode, lBindMatrix);
}
pScene->AddPose(lPose);
}
}
void StoreRestPose(KFbxScene* pScene, KFbxNode* pSkeletonRoot)
{
KString lNodeName;
KFbxNode* lKFbxNode;
KFbxMatrix lTransformMatrix;
KFbxVector4 lT,lR,lS(1.0, 1.0, 1.0);
KFbxPose* lPose = KFbxPose::Create(pScene,"A Bind Pose");
lT.Set(10.0, 10.0, 10.0);
lR.Set( 0.0, 0.0, 45.0);
lTransformMatrix.SetTRS(lT, lR, lS);
lKFbxNode = pSkeletonRoot;
lPose->Add(lKFbxNode, lTransformMatrix, false );
lT.Set(0.0, 40.0, 0.0);
lR.Set(0.0, 0.0, -90.0);
lTransformMatrix.SetTRS(lT, lR, lS);
lKFbxNode = lKFbxNode->GetChild(0);
lPose->Add(lKFbxNode, lTransformMatrix, true );
lT.Set(0.0, 40.0, 0.0);
lR.Set(0.0, 0.0, 45.0);
lTransformMatrix.SetTRS(lT, lR, lS);
lKFbxNode = lKFbxNode->GetChild(0);
lNodeName = lKFbxNode->GetName();
lPose->Add(lKFbxNode, lTransformMatrix, true );
pScene->AddPose(lPose);
}
void AddNodeRecursively(KArrayTemplate<KFbxNode*>& pNodeArray, KFbxNode* pNode)
{
if (pNode)
{
AddNodeRecursively(pNodeArray, pNode->GetParent());
if (pNodeArray.Find(pNode) == -1)
{
pNodeArray.Add(pNode);
}
}
}
void SetXMatrix(KFbxXMatrix& pXMatrix, const KFbxMatrix& pMatrix)
{
memcpy((double*)pXMatrix, &pMatrix.mData[0][0], sizeof(pMatrix.mData));
}