SkinInfo.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include "SkinInfo.h"
  4. #include "NodeHelpers.h"
  5. #include "GlobalSettings.h"
  6. void ComputeBoneHierarchy(const std::vector<FbxNode*>& unsortedFlatListOfNodes,
  7. const std::vector<FbxCluster*>& unsortedFlatListOfClusters,
  8. std::vector<BoneInfo>& output, std::map<int, int>& clusterIndexToBoneIndex, std::map<int, std::vector<BoneIndexAndWeight>>& controlPointsData, FbxNode* currentRoot = nullptr, int currentRootIndex = -1){
  9. for (auto ix = 0u; ix < unsortedFlatListOfNodes.size(); ++ix){
  10. auto node = unsortedFlatListOfNodes[ix];
  11. auto nodeParent = node->GetParent();
  12. if (currentRoot == nullptr){
  13. // node is a match if its parent is not in the flat list
  14. auto foundParent = std::find(unsortedFlatListOfNodes.begin(), unsortedFlatListOfNodes.end(), nodeParent);
  15. if (foundParent != unsortedFlatListOfNodes.end()){
  16. continue;
  17. }
  18. }
  19. else{
  20. // node is a match if its parent is current root
  21. if (currentRoot != nodeParent){
  22. continue;
  23. }
  24. }
  25. // create boneInfo
  26. BoneInfo info;
  27. info.cluster = unsortedFlatListOfClusters[ix];
  28. info.FbxClusterIndex = ix;
  29. info.linkNode = unsortedFlatListOfNodes[ix];
  30. info.parentBoneIndex = currentRootIndex;
  31. info.name = getNodeId(node);
  32. auto boneIndex = static_cast<int>(output.size());
  33. output.push_back(info);
  34. clusterIndexToBoneIndex[ix] = boneIndex;
  35. auto controlledPointsCount = info.cluster->GetControlPointIndicesCount();
  36. for (auto cpIndex = 0; cpIndex < controlledPointsCount; ++cpIndex){
  37. auto controlPoint = info.cluster->GetControlPointIndices()[cpIndex];
  38. auto weight = info.cluster->GetControlPointWeights()[cpIndex];
  39. BoneIndexAndWeight biw;
  40. biw.index = boneIndex;
  41. biw.weight = weight;
  42. controlPointsData[controlPoint].push_back(biw);
  43. }
  44. // recursively parse children
  45. ComputeBoneHierarchy(unsortedFlatListOfNodes, unsortedFlatListOfClusters, output, clusterIndexToBoneIndex, controlPointsData, node, static_cast<int>(boneIndex));
  46. }
  47. }
  48. FbxAMatrix NotDecomposedMultiply(const FbxAMatrix& lhs, const FbxAMatrix& rhs){
  49. FbxMatrix matL(lhs);
  50. FbxMatrix matR(rhs);
  51. auto result = matL*matR;
  52. return *(FbxAMatrix*) (double*) &result;
  53. }
  54. //FbxAMatrix ComputeTotalMatrix(FbxNode* node, FbxTime time = FBXSDK_TIME_INFINITE){
  55. //
  56. //}
  57. SkinInfo::SkinInfo(FbxNode* meshNode) :
  58. _node(meshNode), _mesh(meshNode->GetMesh()), _skin(nullptr)
  59. {
  60. int deformerCount = _mesh->GetDeformerCount();
  61. for (auto ix = 0; ix < deformerCount; ++ix){
  62. auto skin = reinterpret_cast<FbxSkin*>(_mesh->GetDeformer(ix, FbxDeformer::eSkin));
  63. if (skin){
  64. _skin = skin;
  65. break;
  66. }
  67. }
  68. if (!_skin){
  69. return;
  70. }
  71. std::vector<FbxPose*> bindPoses;
  72. auto poseCount = _node->GetScene()->GetPoseCount();
  73. for (auto ix = 0; ix < poseCount; ++ix){
  74. auto pose = _node->GetScene()->GetPose(ix);
  75. if (pose->IsBindPose()){
  76. bindPoses.push_back(pose);
  77. }
  78. }
  79. std::vector<FbxNode*> unsortedFlatListOfNodes;
  80. std::vector<FbxCluster*> unsortedFlatListOfClusters;
  81. auto clusterCount = _skin->GetClusterCount();
  82. for (auto ix = 0; ix < clusterCount; ++ix){
  83. auto cluster = _skin->GetCluster(ix);
  84. if (!cluster)
  85. {
  86. std::cout << "Invalid skin" << std::endl;
  87. _skin = nullptr;
  88. return;
  89. }
  90. auto linkNode = cluster->GetLink();
  91. if (!linkNode){
  92. std::cout << "Invalid skin" << std::endl;
  93. _skin = nullptr;
  94. return;
  95. }
  96. unsortedFlatListOfClusters.push_back(cluster);
  97. unsortedFlatListOfNodes.push_back(linkNode);
  98. }
  99. ComputeBoneHierarchy(unsortedFlatListOfNodes, unsortedFlatListOfClusters, _bones, _fbxClusterIndexToBoneIndex, _controlPointToBoneIndicesAndWeights);
  100. auto deformType = _skin->GetDeformerType();
  101. auto geometryTransform = GetGeometryTransformation(meshNode);
  102. // compute all bones global inverse and global matrix
  103. for (auto& bone : _bones){
  104. FbxAMatrix transformMatrix;
  105. FbxAMatrix transformLinkMatrix;
  106. FbxMatrix globalBindposeInverseMatrix;
  107. bone.cluster->GetTransformMatrix(transformMatrix); // The transformation of the mesh at binding time
  108. bone.cluster->GetTransformLinkMatrix(transformLinkMatrix); // The transformation of the cluster(joint) at binding time from joint space to world space
  109. /*for (auto pose : bindPoses){
  110. auto inPoseIndex = pose->Find(bone.linkNode);
  111. if (inPoseIndex >= 0){
  112. auto tempMat = pose->GetMatrix(inPoseIndex);
  113. transformLinkMatrix = *(FbxAMatrix*) (double*) &tempMat;
  114. break;
  115. }
  116. }*/
  117. globalBindposeInverseMatrix = FbxMatrix(transformLinkMatrix.Inverse()) * FbxMatrix(transformMatrix) * geometryTransform;
  118. bone.matrixGlobalBindPose = ConvertToBabylonCoordinateSystem(globalBindposeInverseMatrix.Inverse());
  119. if (bone.parentBoneIndex == -1){
  120. bone.matrixLocalBindPose = bone.matrixGlobalBindPose;
  121. }
  122. else{
  123. bone.matrixLocalBindPose =
  124. _bones[bone.parentBoneIndex].matrixGlobalBindPose.Inverse()* bone.matrixGlobalBindPose;
  125. }
  126. }
  127. // compute anim
  128. auto animStack = _node->GetScene()->GetCurrentAnimationStack();
  129. FbxString animStackName = animStack->GetName();
  130. //FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName);
  131. auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode;
  132. auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate();
  133. auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode);
  134. auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode);
  135. auto animLengthInFrame = endFrame - startFrame + 1;
  136. for (auto ix = 0; ix < animLengthInFrame; ix++){
  137. FbxTime currTime;
  138. currTime.SetFrame(startFrame + ix, animTimeMode);
  139. auto currTransformOffset = FbxMatrix(meshNode->EvaluateGlobalTransform(currTime)) * geometryTransform;
  140. auto currTransformOffsetInverse = currTransformOffset.Inverse();
  141. // compute global transform and local
  142. for (auto& bone : _bones){
  143. BoneAnimKeyFrame kf;
  144. kf.frame = ix;
  145. kf.matrixGlobal = ConvertToBabylonCoordinateSystem(currTransformOffsetInverse*bone.linkNode->EvaluateGlobalTransform(currTime));
  146. if (bone.parentBoneIndex == -1){
  147. kf.matrixLocal = kf.matrixGlobal;
  148. }
  149. else{
  150. auto& parentBone = _bones[bone.parentBoneIndex];
  151. kf.matrixLocal = //bone.matrixLocalBindPose;
  152. parentBone.keyFrames[parentBone.keyFrames.size() - 1].matrixGlobal.Inverse()* kf.matrixGlobal;
  153. }
  154. bone.keyFrames.push_back(kf);
  155. }
  156. }
  157. }
  158. void SkinInfo::buildBabylonSkeleton(BabylonSkeleton& skel){
  159. if (!hasSkin()){
  160. return;
  161. }
  162. skel.name = getNodeId(_node) + L"_skeleton";
  163. for (auto& b : _bones){
  164. BabylonBone babbone;
  165. babbone.index = static_cast<int>(skel.bones.size());
  166. //babbone.matrix = ConvertToBabylonCoordinateSystem( b.matrixLocalBindPose);
  167. babbone.matrix = b.matrixLocalBindPose;
  168. babbone.name = b.name;
  169. babbone.parentBoneIndex = b.parentBoneIndex;
  170. auto animStack = _node->GetScene()->GetCurrentAnimationStack();
  171. FbxString animStackName = animStack->GetName();
  172. //FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName);
  173. auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode;
  174. auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate();
  175. auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode);
  176. auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode);
  177. auto animLengthInFrame = endFrame - startFrame + 1;
  178. auto matrixAnim = std::make_shared<BabylonAnimation<FbxMatrix>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"_matrix", L"_matrix", true, 0, static_cast<int>(animLengthInFrame), true);
  179. for (auto& kf : b.keyFrames){
  180. babylon_animation_key<FbxMatrix> key;
  181. key.frame = kf.frame;
  182. //key.values = ConvertToBabylonCoordinateSystem(kf.matrixLocal);
  183. key.values = kf.matrixLocal;
  184. matrixAnim->appendKey(key);
  185. }
  186. babbone.animation = matrixAnim;
  187. skel.bones.push_back(babbone);
  188. }
  189. }