void FBXSceneEncoder::loadBindShapes(FbxScene* fbxScene) { float m[16]; const int poseCount = fbxScene->GetPoseCount(); for (int i = 0; i < poseCount; ++i) { FbxPose* pose = fbxScene->GetPose(i); assert(pose); if (pose->IsBindPose() && pose->GetCount() > 0) { FbxNode* fbxNode = pose->GetNode(0); if (fbxNode->GetMesh() != NULL) { Node* node = _gamePlayFile.getNode(fbxNode->GetName()); assert(node && node->getModel()); Model* model = node->getModel(); if (model && model->getSkin()) { MeshSkin* skin = model->getSkin(); copyMatrix(pose->GetMatrix(0), m); skin->setBindShape(m); } } } } }
void SetBindPose() { assert( g_pFBXScene != nullptr ); g_BindPoses.clear(); INT iPoseCount = g_pFBXScene->GetPoseCount(); for( INT i = 0; i < iPoseCount; ++i ) { auto pPose = g_pFBXScene->GetPose( i ); INT iNodeCount = pPose->GetCount(); ExportLog::LogMsg( 4, "Found %spose: \"%s\" with %d nodes", pPose->IsBindPose() ? "bind " : "", pPose->GetName(), iNodeCount ); for( INT j = 0; j < iNodeCount; ++j ) { auto pPoseNode = pPose->GetNode( j ); ExportLog::LogMsg( 5, "Pose node %d: %s", j, pPoseNode->GetName() ); } if( pPose->IsBindPose() ) { g_BindPoses.push_back( pPose ); } } if( g_BindPoses.empty() ) { if( g_pScene->Settings().bExportAnimations ) { ExportLog::LogWarning( "No valid bind pose found; will export scene using the default pose." ); } return; } size_t dwPoseCount = g_BindPoses.size(); for( size_t i = 0; i < dwPoseCount; ++i ) { FbxPose* pPose = g_BindPoses[i]; INT iNodeCount = pPose->GetCount(); for( INT j = 0; j < iNodeCount; ++j ) { auto pNode = pPose->GetNode( j ); auto matNode = pPose->GetMatrix( j ); PoseMap::iterator iter = g_BindPoseMap.find( pNode ); if( iter != g_BindPoseMap.end() ) { FbxMatrix matExisting = iter->second; if( matExisting != matNode ) { ExportLog::LogWarning( "Node \"%s\" found in more than one bind pose, with conflicting transforms.", pNode->GetName() ); } } g_BindPoseMap[pNode] = matNode; } } ExportLog::LogMsg( 3, "Created bind pose map with %Iu nodes.", g_BindPoseMap.size() ); }
/** * Add a bind pose to the scene based on the FbxMesh and skinning settings of the given node */ void FFbxExporter::CreateBindPose(FbxNode* MeshRootNode) { if (!MeshRootNode) { return; } // In the bind pose, we must store all the link's global matrix at the time of the bind. // Plus, we must store all the parent(s) global matrix of a link, even if they are not // themselves deforming any model. // Create a bind pose with the link list FbxArray<FbxNode*> lClusteredFbxNodes; int i, j; if (MeshRootNode->GetNodeAttribute()) { int lSkinCount=0; int lClusterCount=0; switch (MeshRootNode->GetNodeAttribute()->GetAttributeType()) { case FbxNodeAttribute::eMesh: case FbxNodeAttribute::eNurbs: case FbxNodeAttribute::ePatch: lSkinCount = ((FbxGeometry*)MeshRootNode->GetNodeAttribute())->GetDeformerCount(FbxDeformer::eSkin); //Go through all the skins and count them //then go through each skin and get their cluster count for(i=0; i<lSkinCount; ++i) { FbxSkin *lSkin=(FbxSkin*)((FbxGeometry*)MeshRootNode->GetNodeAttribute())->GetDeformer(i, FbxDeformer::eSkin); lClusterCount+=lSkin->GetClusterCount(); } break; } //if we found some clusters we must add the node if (lClusterCount) { //Again, go through all the skins get each cluster link and add them for (i=0; i<lSkinCount; ++i) { FbxSkin *lSkin=(FbxSkin*)((FbxGeometry*)MeshRootNode->GetNodeAttribute())->GetDeformer(i, FbxDeformer::eSkin); lClusterCount=lSkin->GetClusterCount(); for (j=0; j<lClusterCount; ++j) { FbxNode* lClusterNode = lSkin->GetCluster(j)->GetLink(); AddNodeRecursively(lClusteredFbxNodes, lClusterNode); } } // Add the patch to the pose lClusteredFbxNodes.Add(MeshRootNode); } } // Now create a bind pose with the link list if (lClusteredFbxNodes.GetCount()) { // A pose must be named. Arbitrarily use the name of the patch node. FbxPose* lPose = FbxPose::Create(Scene, MeshRootNode->GetName()); // default pose type is rest pose, so we need to set the type as bind pose lPose->SetIsBindPose(true); for (i=0; i<lClusteredFbxNodes.GetCount(); i++) { FbxNode* lKFbxNode = lClusteredFbxNodes.GetAt(i); FbxMatrix lBindMatrix = lKFbxNode->EvaluateGlobalTransform(); lPose->Add(lKFbxNode, lBindMatrix); } // Add the pose to the scene Scene->AddPose(lPose); } }
void ExportBones(const Value& obj) { const Value& boneName = obj["BoneName"]; if (boneName.IsNull()) { return; } //string name = obj["Name"].GetString(); const Value& parentIndex = obj["ParentIndex"]; const Value& boneTransform = obj["BoneTransform"]; fbxBones.resize(boneName.Size()); for (uint32_t i = 0; i < fbxBones.size(); i++) { FbxNode* boneNode = FbxNode::Create(pScene, boneName[i].GetString()); fbxBones[i] = boneNode; double x, y, z, w; x = boneTransform[i * 7 + 0].GetDouble(); x = -x; y = boneTransform[i * 7 + 1].GetDouble(); z = boneTransform[i * 7 + 2].GetDouble(); boneNode->LclTranslation.Set(FbxDouble3(x, y, z)); x = boneTransform[i * 7 + 3].GetDouble(); y = boneTransform[i * 7 + 4].GetDouble(); z = boneTransform[i * 7 + 5].GetDouble(); w = boneTransform[i * 7 + 6].GetDouble(); FbxSkeleton* pSkeleton = FbxSkeleton::Create(pScene, boneName[i].GetString()); int parent = parentIndex[i].GetInt(); if (parent == -1) { pSkeleton->SetSkeletonType(FbxSkeleton::eRoot); } else { pSkeleton->SetSkeletonType(FbxSkeleton::eLimbNode); pSkeleton->Size.Set(0.1); } boneNode->SetNodeAttribute(pSkeleton); } for (uint32_t i = 0; i < fbxBones.size(); i++) { int parent = parentIndex[i].GetInt(); if (parent == -1) { pScene->GetRootNode()->AddChild(fbxBones[i]); } else { fbxBones[parent]->AddChild(fbxBones[i]); } } FbxPose* lPose = FbxPose::Create(pScene, boneName[0].GetString()); // default pose type is rest pose, so we need to set the type as bind pose lPose->SetIsBindPose(true); for (uint32_t i = 0; i < fbxBones.size(); i++) { FbxNode* lKFbxNode = fbxBones[i]; FbxMatrix lBindMatrix = lKFbxNode->EvaluateGlobalTransform(); lPose->Add(lKFbxNode, lBindMatrix); } pScene->AddPose(lPose); }