FbxRerouteSkeleton.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // FbxRerouteSkeleton.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include <fbxsdk.h>
  5. #include <iostream>
  6. #include <string>
  7. #include <vector>
  8. #include <Windows.h>
  9. #include <map>
  10. #include "FbxDeleter.h"
  11. #include <memory>
  12. std::string wstringToUtf8(const std::wstring& src){
  13. auto size = WideCharToMultiByte(CP_UTF8, 0, src.c_str(), static_cast<int>(src.size()), nullptr, 0, nullptr, nullptr);
  14. std::string result;
  15. result.resize(size, ' ');
  16. WideCharToMultiByte(CP_UTF8, 0, src.c_str(), static_cast<int>(src.size()), &result[0], size, nullptr, nullptr);
  17. return result;
  18. }
  19. void populateNodeMap(std::map<std::string, FbxNode*>& m, FbxNode* currNode){
  20. if (currNode == nullptr){
  21. return;
  22. }
  23. m[currNode->GetName()] = currNode;
  24. auto mesh = currNode->GetMesh();
  25. if (mesh) {
  26. currNode->SetNodeAttribute(nullptr);
  27. }
  28. for (auto ix = 0; ix < currNode->GetChildCount(); ++ix){
  29. populateNodeMap(m, currNode->GetChild(ix));
  30. }
  31. }
  32. struct ScopedScene{
  33. FbxScene* scene = nullptr;
  34. ScopedScene(FbxManager* mgr) :scene(FbxScene::Create(mgr, "TempScene")){}
  35. ~ScopedScene(){
  36. if (scene){
  37. scene->Destroy(true);
  38. }
  39. }
  40. };
  41. void DeepClone(FbxNode* n, FbxNode* container){
  42. auto cloned = n->Clone(FbxObject::ECloneType::eDeepClone, container);
  43. for (auto ix = 0; ix < n->GetChildCount(); ++ix){
  44. DeepClone(n->GetChild(ix), (FbxNode*) cloned);
  45. }
  46. }
  47. void importAdditionalFile(FbxScene* globalScene, FbxImporter* importer, const std::string& file){
  48. importer->Initialize(file.c_str());
  49. ScopedScene tempScene(globalScene->GetFbxManager());
  50. importer->Import(tempScene.scene);
  51. auto tempRootNode = tempScene.scene->GetRootNode();
  52. std::vector<FbxNode*> childrenToMove;
  53. int lNumChildren = tempRootNode->GetChildCount();
  54. for (int i = 0; i < lNumChildren; i++) {
  55. // Obtain a child node from the currently loaded scene.
  56. FbxNode* lChildNode = tempRootNode->GetChild(i);
  57. if (lChildNode){
  58. childrenToMove.push_back(lChildNode);
  59. }
  60. }
  61. for (auto item : childrenToMove){
  62. //DeepClone(item, globalScene->GetRootNode());
  63. globalScene->GetRootNode()->AddChild(item);
  64. }
  65. // Remove the children from the root node.
  66. tempScene.scene->GetRootNode()->DisconnectAllSrcObject();
  67. std::vector<FbxObject* > objsToMove;
  68. // Move other objects to the reference scene.
  69. int lNumSceneObjects = tempScene.scene->GetSrcObjectCount();
  70. for (int i = 0; i < lNumSceneObjects; i++) {
  71. FbxObject* lObj = tempScene.scene->GetSrcObject(i);
  72. auto isAnimStack = lObj->GetClassId() == FbxAnimStack::ClassId;
  73. if (lObj == tempScene.scene->GetRootNode() || *lObj == tempScene.scene->GetGlobalSettings() || isAnimStack){
  74. // Don't move the root node or the scene's global settings; these
  75. // objects are created for every scene.
  76. continue;
  77. }
  78. objsToMove.push_back(lObj);
  79. }
  80. for (auto obj : objsToMove){
  81. obj->ConnectDstObject(globalScene);
  82. }
  83. tempScene.scene->DisconnectAllSrcObject();
  84. }
  85. void patchSkins(FbxNode* currentRoot, const std::map<std::string, FbxNode*>& animatedNodes, const std::string& prefix){
  86. auto mesh = currentRoot->GetMesh();
  87. if (mesh){
  88. auto skinCount = mesh->GetDeformerCount(FbxDeformer::EDeformerType::eSkin);
  89. for (auto ix = 0; ix < skinCount; ++ix){
  90. auto skin = (FbxSkin*) mesh->GetDeformer(ix, FbxDeformer::EDeformerType::eSkin);
  91. if (skin){
  92. std::vector<FbxCluster*> replacements;
  93. auto clusterCount = skin->GetClusterCount();
  94. for (auto clusterIx = 0; clusterIx < clusterCount; ++clusterIx){
  95. auto cluster = skin->GetCluster(clusterIx);
  96. if (cluster){
  97. auto linkNode = cluster->GetLink();
  98. if (linkNode){
  99. auto candidateName = prefix;
  100. candidateName.append(linkNode->GetName());
  101. auto found = animatedNodes.find(candidateName);
  102. if (found != animatedNodes.end()){
  103. FbxCluster* newCluster = FbxCluster::Create(currentRoot->GetScene(), "");
  104. newCluster->SetLink(found->second);
  105. newCluster->SetLinkMode(cluster->GetLinkMode());
  106. FbxAMatrix mat;
  107. newCluster->SetTransformAssociateModelMatrix(cluster->GetTransformAssociateModelMatrix(mat));
  108. newCluster->SetAssociateModel(cluster->GetAssociateModel());
  109. newCluster->SetTransformLinkMatrix(cluster->GetTransformLinkMatrix(mat));
  110. newCluster->SetTransformMatrix(cluster->GetTransformMatrix(mat));
  111. newCluster->SetTransformParentMatrix(cluster->GetTransformParentMatrix(mat));
  112. auto indicesAndWeightsCount = cluster->GetControlPointIndicesCount();
  113. for (auto ix = 0; ix < indicesAndWeightsCount; ++ix){
  114. newCluster->AddControlPointIndex(cluster->GetControlPointIndices()[ix], cluster->GetControlPointWeights()[ix]);
  115. }
  116. replacements.push_back(newCluster);
  117. }
  118. }
  119. }
  120. }
  121. if (replacements.size() == clusterCount){
  122. while (skin->GetClusterCount()>0){
  123. auto oldCluster = skin->GetCluster(skin->GetClusterCount() - 1);
  124. skin->RemoveCluster(oldCluster);
  125. oldCluster->Destroy();
  126. }
  127. for (auto c : replacements){
  128. skin->AddCluster(c);
  129. }
  130. }
  131. else{
  132. for (auto c : replacements){
  133. c->Destroy();
  134. }
  135. }
  136. }
  137. }
  138. }
  139. for (auto ix = 0; ix < currentRoot->GetChildCount(); ++ix){
  140. patchSkins(currentRoot->GetChild(ix), animatedNodes, prefix);
  141. }
  142. }
  143. int _tmain(int argc, _TCHAR* argv [])
  144. {
  145. std::cout << "usage : FbxRerouteSkeleton.exe /m:<origin mesh and skeleton data.fbx> /m:<other origin mesh and skeleton data.fbx> /a:<animated skeleton.fbx> /o:<output fbx> [/prefix:<prefix added to each bone in animated skeleton.fbx>]" << std::endl;
  146. std::vector<std::string> meshFiles;
  147. std::string skeletonFile;
  148. std::string outputPath;
  149. std::string prefix;
  150. for (auto ix = 1; ix < argc; ++ix){
  151. std::wstring warg = argv[ix];
  152. if (warg.find(L"/m:") == 0){
  153. meshFiles.push_back(wstringToUtf8(warg.substr(3)));
  154. }
  155. else if (warg.find(L"/a:") == 0)
  156. {
  157. if (skeletonFile.size()>0){
  158. std::wcout << L"only one animated skeleton file is allowed" << std::endl;
  159. return -2;
  160. }
  161. skeletonFile = wstringToUtf8(warg.substr(3));
  162. }
  163. else if (warg.find(L"/o:") == 0){
  164. if (outputPath.size() > 0){
  165. std::wcout << L"only one output file is allowed" << std::endl;
  166. return -3;
  167. }
  168. CloseHandle(CreateFile(warg.substr(3).c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr));
  169. outputPath = wstringToUtf8(warg.substr(3));
  170. }
  171. else if (warg.find(L"/prefix:") == 0){
  172. if (prefix.size() > 0){
  173. std::wcout << L"only one prefix is allowed" << std::endl;
  174. return -4;
  175. }
  176. prefix = wstringToUtf8(warg.substr(8));
  177. }
  178. else{
  179. std::wcout << L"unrecognized parameter " << warg << std::endl;
  180. return -1;
  181. }
  182. }
  183. if (meshFiles.size() == 0){
  184. std::wcout << L"no origin mesh file" << std::endl;
  185. return -5;
  186. }
  187. if (skeletonFile.size() == 0){
  188. std::wcout << L"skeleton file unspecified" << std::endl;
  189. return -6;
  190. }
  191. if (outputPath.size() == 0){
  192. std::wcout << L"output file unspecified" << std::endl;
  193. return -7;
  194. }
  195. auto fbxManager = std::unique_ptr<FbxManager, FbxManagerDeleter>( FbxManager::Create());
  196. auto iosettings = std::unique_ptr<FbxIOSettings, FbxDeleter>(FbxIOSettings::Create(fbxManager.get(), IOSROOT));
  197. iosettings->SetBoolProp(IMP_FBX_MATERIAL, true);
  198. iosettings->SetBoolProp(IMP_FBX_TEXTURE, true);
  199. iosettings->SetBoolProp(IMP_FBX_LINK, true);
  200. iosettings->SetBoolProp(IMP_FBX_SHAPE, true);
  201. iosettings->SetBoolProp(IMP_FBX_GOBO, true);
  202. iosettings->SetBoolProp(IMP_FBX_ANIMATION, true);
  203. iosettings->SetBoolProp(IMP_SKINS, true);
  204. iosettings->SetBoolProp(IMP_DEFORMATION, true);
  205. iosettings->SetBoolProp(IMP_FBX_GLOBAL_SETTINGS, true);
  206. iosettings->SetBoolProp(IMP_TAKE, true);
  207. iosettings->SetBoolProp(EXP_FBX_MATERIAL, true);
  208. iosettings->SetBoolProp(EXP_FBX_TEXTURE, true);
  209. iosettings->SetBoolProp(EXP_MESHPOLY, true);
  210. iosettings->SetBoolProp(EXP_FBX_SHAPE, true);
  211. iosettings->SetBoolProp(EXP_FBX_GOBO, true);
  212. iosettings->SetBoolProp(EXP_FBX_ANIMATION, true);
  213. iosettings->SetBoolProp(EXP_SKINS, true);
  214. iosettings->SetBoolProp(EXP_DEFORMATION, true);
  215. iosettings->SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true);
  216. iosettings->SetBoolProp(EXP_MESHTRIANGLE, true);
  217. iosettings->SetBoolProp(EXP_EMBEDTEXTURE, true);
  218. fbxManager->SetIOSettings(iosettings.get());
  219. auto importer = std::unique_ptr<FbxImporter, FbxDeleter> (FbxImporter::Create(fbxManager.get(), "SceneImporter"));
  220. importer->Initialize(skeletonFile.c_str(), -1, iosettings.get());
  221. auto globalScene = std::unique_ptr<FbxScene, FbxDeleter>(FbxScene::Create(fbxManager.get(), "merged scene"));
  222. importer->Import(globalScene.get());
  223. std::map<std::string, FbxNode*> animatedSkeletonNodesMap;
  224. populateNodeMap(animatedSkeletonNodesMap, globalScene->GetRootNode());
  225. for (auto& f : meshFiles){
  226. importAdditionalFile(globalScene.get(), importer.get(), f);
  227. }
  228. patchSkins(globalScene->GetRootNode(), animatedSkeletonNodesMap, prefix);
  229. auto exporter = std::unique_ptr<FbxExporter, FbxDeleter>(FbxExporter::Create(fbxManager.get(), "SceneExporter"));
  230. auto res = exporter->Initialize(outputPath.c_str(), -1, iosettings.get());
  231. res = exporter->Export(globalScene.get());
  232. auto status = exporter->GetStatus();
  233. return 0;
  234. }