Hi, the following code will create a basic humanoid skeleton and the associated character. Note that this is the very basic process and a lot of information is not filled (including the creation of the control rig)
#include <fbxsdk.h>
#include "../Common/Common.h"
FbxNode* CreateSkelMember(FbxScene* pScene, const char* pName, FbxNodeAttribute::EType pType, int pAttrType, FbxVector4 pT, FbxVector4 pR = FbxVector4(0,0,0))
{
FbxNode* lNode = FbxNode::Create(pScene, pName);
lNode->LclTranslation.Set(pT);
lNode->LclRotation.Set(pR);
FbxNodeAttribute* lAttr = nullptr;
switch (pType)
{
case FbxNodeAttribute::eNull:
lAttr = FbxNull::Create(pScene, "");
FbxCast<FbxNull>(lAttr)->Look.Set((FbxNull::ELook)pAttrType);
break;
case FbxNodeAttribute::eMarker:
lAttr = FbxMarker::Create(pScene, "");
FbxCast<FbxMarker>(lAttr)->SetType((FbxMarker::EType)pAttrType);
break;
case FbxNodeAttribute::eSkeleton:
lAttr = FbxSkeleton::Create(pScene, "");
FbxCast<FbxSkeleton>(lAttr)->SetSkeletonType((FbxSkeleton::EType)pAttrType);
switch ((FbxSkeleton::EType)pAttrType)
{
case FbxSkeleton::eRoot:
case FbxSkeleton::eEffector:
break;
case FbxSkeleton::eLimbNode:
FbxCast<FbxSkeleton>(lAttr)->Size.Set(100.0);
break;
case FbxSkeleton::eLimb:
FbxCast<FbxSkeleton>(lAttr)->LimbLength.Set(1.0);
break;
}
break;
}
lNode->SetNodeAttribute(lAttr);
return lNode;
}
void CreateSkeleton(FbxScene* pScene)
{
// Define a Humanoid skeleton
//
FbxNode* lRootNode = pScene->GetRootNode();
FbxNode *lNode, *lParent, *lRoot;
lNode = CreateSkelMember(pScene, "Hips", FbxNodeAttribute::eSkeleton, FbxSkeleton::eRoot, FbxVector4(0, 92, 0));
lRootNode->AddChild(lNode);
lRoot = lNode;
lParent = lNode;
// left leg
// hip
lNode = CreateSkelMember(pScene, "LeftUpLeg", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(6, -8, 0), FbxVector4(-10.0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// knee
lNode = CreateSkelMember(pScene, "LeftLeg", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, -43, 0), FbxVector4(20.0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// ankle
lNode = CreateSkelMember(pScene, "LeftFoot", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, -40, 0));
lParent->AddChild(lNode);
lParent = lNode;
// foot
lNode = CreateSkelMember(pScene, "LeftToeBase", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, 0, 12));
lParent->AddChild(lNode);
// right leg
lParent = lRoot;
// hip
lNode = CreateSkelMember(pScene, "RightUpLeg", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(-6, -8, 0), FbxVector4(-10.0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// knee
lNode = CreateSkelMember(pScene, "RightLeg", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, -43, 0), FbxVector4(20.0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// ankle
lNode = CreateSkelMember(pScene, "RightFoot", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, -40, 0));
lParent->AddChild(lNode);
lParent = lNode;
// foot
lNode = CreateSkelMember(pScene, "RightToeBase", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, 0, 12));
lParent->AddChild(lNode);
// waist
lParent = lRoot;
lNode = CreateSkelMember(pScene, "Spine", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, 8, 0), FbxVector4(0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// chest
lNode = CreateSkelMember(pScene, "Spine1", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, 50, 0), FbxVector4(0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
lRoot = lParent;
// Neck
lParent = lNode;
lNode = CreateSkelMember(pScene, "Neck", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, 2, -1), FbxVector4(0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// Head
lNode = CreateSkelMember(pScene, "Head", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(0, 20, 0), FbxVector4(0, 0, -7));
lParent->AddChild(lNode);
// Left Arm
// collar
lParent = lRoot;
lNode = CreateSkelMember(pScene, "LeftShoulder", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(20, 2, 0));
lParent->AddChild(lNode);
lParent = lNode;
// shoulder
lNode = CreateSkelMember(pScene, "LeftArm", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(5, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// elbow
lNode = CreateSkelMember(pScene, "LeftForeArm", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(27.0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// wrist
lNode = CreateSkelMember(pScene, "LeftHand", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(24.0, 0, 0));
lParent->AddChild(lNode);
// Right Arm
// collar
lParent = lRoot;
lNode = CreateSkelMember(pScene, "RightShoulder", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(-20, 2, 0));
lParent->AddChild(lNode);
lParent = lNode;
// shoulder
lNode = CreateSkelMember(pScene, "RightArm", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(-5, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// elbow
lNode = CreateSkelMember(pScene, "RightForeArm", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(-27.0, 0, 0));
lParent->AddChild(lNode);
lParent = lNode;
// wrist
lNode = CreateSkelMember(pScene, "RightHand", FbxNodeAttribute::eSkeleton, FbxSkeleton::eLimbNode, FbxVector4(-24.0, 0, 0));
lParent->AddChild(lNode);
}
void FillCharacterLink(FbxCharacterLink& pLink, FbxNode* pNode)
{
// Fill basic link data (typically, you also need to set limits and pre/post rotation vectors, rotation order, etc.)
pLink.mNode = pNode;
// CharacterLink needs global transforms
FbxAMatrix pNodeGM = pNode->EvaluateGlobalTransform();
pLink.mOffsetT = pNodeGM.GetT();
pLink.mOffsetR = pNodeGM.GetROnly();
pLink.mOffsetS = pNodeGM.GetS();
}
void CreateCharacter(FbxScene* pScene)
{
if (!pScene) return;
FbxCharacter* lCharacter = FbxCharacter::Create(pScene, "Character");
FbxArray<FbxCharacterLink> link;
for (int i = 0; i < pScene->GetSrcObjectCount<FbxNode>(); i++)
{
FbxNode* lNode = pScene->GetSrcObject<FbxNode>(i);
if (lNode == pScene->GetRootNode()) continue;
// create the character link based on the skeleton bones name
FbxCharacter::ENodeId nodeId;
if (FbxCharacter::GetCharacterNodeIdFromNodeName(lNode->GetName(), nodeId))
{
FbxCharacterLink l;
FillCharacterLink(l, lNode);
lCharacter->SetCharacterLink(nodeId, l);
}
}
}
int main(int argc, char** argv)
{
FbxManager* lSdkManager = NULL;
FbxScene* lScene = NULL;
bool lResult = true;
// Prepare the FBX SDK.
//The first thing to do is to create the FBX Manager which is the object allocator for almost all the classes in the SDK
lSdkManager = FbxManager::Create();
if (!lSdkManager)
{
FBXSDK_printf("Error: Unable to create FBX Manager!\n");
exit(1);
}
//Create an IOSettings object. This object holds all import/export settings.
FbxIOSettings* ios = FbxIOSettings::Create(lSdkManager, IOSROOT);
lSdkManager->SetIOSettings(ios);
//Load plugins from the executable directory (optional)
FbxString lPath = FbxGetApplicationDirectory();
lSdkManager->LoadPluginsDirectory(lPath.Buffer());
//Create an FBX scene. This object holds most objects imported/exported from/to files.
lScene = FbxScene::Create(lSdkManager, "My Scene");
if (!lScene)
{
FBXSDK_printf("Error: Unable to create FBX scene!\n");
exit(1);
}
// parse arguments
FbxString lFilePath("");
FbxString lOutFilePath("");
for( int i = 1, c = argc; i < c; ++i )
{
if( FbxString(argv[i]) == "-test" ) continue;
else if( lFilePath.IsEmpty() ) lFilePath = argv[i];
else if (lOutFilePath.IsEmpty()) lOutFilePath = argv[i];
}
if (!lFilePath.IsEmpty() && lFilePath != "-dummy")
{
lResult = LoadScene(lSdkManager, lScene, lFilePath.Buffer());
}
if (lResult)
{
CreateSkeleton(lScene);
CreateCharacter(lScene);
}
if (lResult && !lOutFilePath.IsEmpty())
{
lResult = SaveScene(lSdkManager, lScene, lOutFilePath.Buffer(), 1);
}
// Destroy all objects created by the FBX SDK.
DestroySdkObjects(lSdkManager, lResult);
return 0;
}