AssImpImporterUtilities.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <assimp/scene.h>
  9. #include <AzCore/Debug/Trace.h>
  10. #include <AzCore/std/containers/unordered_set.h>
  11. #include <AzCore/std/containers/queue.h>
  12. #include <AzCore/StringFunc/StringFunc.h>
  13. #include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
  14. #include <SceneAPI/SceneBuilder/Importers/AssImpImporterUtilities.h>
  15. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  16. namespace AZ
  17. {
  18. namespace SceneAPI
  19. {
  20. namespace SceneBuilder
  21. {
  22. bool IsSkinnedMesh(const aiNode& node, const aiScene& scene)
  23. {
  24. unsigned boneCount = 0;
  25. for (unsigned mesh = 0; mesh < node.mNumMeshes; ++mesh)
  26. {
  27. if (scene.mMeshes[node.mMeshes[mesh]]->HasBones())
  28. {
  29. ++boneCount;
  30. }
  31. }
  32. if (boneCount > 1 && boneCount != node.mNumMeshes)
  33. {
  34. AZ_Error("AssImpImporterUtilities", false, "Node has %d meshes but only %d are skinned. "
  35. "This is unexpected and may result in errors", node.mNumMeshes, boneCount);
  36. }
  37. return boneCount > 0;
  38. }
  39. bool IsPivotNode(const aiString& nodeName, size_t* pos)
  40. {
  41. AZStd::string_view name(nodeName.C_Str(), nodeName.length);
  42. size_t myPos;
  43. if (!pos)
  44. {
  45. pos = &myPos;
  46. }
  47. *pos = AZ::StringFunc::Find(name, PivotNodeMarker);
  48. return *pos != name.npos;
  49. }
  50. void SplitPivotNodeName(const aiString& nodeName, size_t pivotPos, AZStd::string_view& baseNodeName, AZStd::string_view& pivotType)
  51. {
  52. AZStd::string_view nodeNameView(nodeName.data, nodeName.length);
  53. baseNodeName = AZStd::string_view(nodeNameView.substr(0, pivotPos));
  54. pivotType = AZStd::string_view(nodeNameView.substr(pivotPos + sizeof PivotNodeMarker - 1));
  55. }
  56. aiMatrix4x4 GetConcatenatedLocalTransform(const aiNode* currentNode)
  57. {
  58. const aiNode* parent = currentNode->mParent;
  59. aiMatrix4x4 combinedTransform = currentNode->mTransformation;
  60. while (parent)
  61. {
  62. size_t pos;
  63. if (IsPivotNode(parent->mName, &pos))
  64. {
  65. combinedTransform = parent->mTransformation * combinedTransform;
  66. parent = parent->mParent;
  67. }
  68. else
  69. {
  70. break;
  71. }
  72. }
  73. return combinedTransform;
  74. }
  75. void FindAllBones(const aiScene* scene, AZStd::unordered_multimap<AZStd::string, const aiBone*>& outBoneByNameMap)
  76. {
  77. outBoneByNameMap.clear();
  78. AZStd::queue<const aiNode*> queue;
  79. AZStd::unordered_set<AZStd::string> nodesWithNoMesh;
  80. queue.push(scene->mRootNode);
  81. while (!queue.empty())
  82. {
  83. const aiNode* currentNode = queue.front();
  84. queue.pop();
  85. if (currentNode->mNumMeshes == 0)
  86. {
  87. nodesWithNoMesh.emplace(currentNode->mName.C_Str());
  88. }
  89. for (unsigned int childIndex = 0; childIndex < currentNode->mNumChildren; ++childIndex)
  90. {
  91. queue.push(currentNode->mChildren[childIndex]);
  92. }
  93. }
  94. for (unsigned meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex)
  95. {
  96. const aiMesh* mesh = scene->mMeshes[meshIndex];
  97. for (unsigned boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
  98. {
  99. const aiBone* bone = mesh->mBones[boneIndex];
  100. if (nodesWithNoMesh.contains(bone->mName.C_Str()))
  101. {
  102. outBoneByNameMap.emplace(bone->mName.C_Str(), bone);
  103. }
  104. }
  105. }
  106. }
  107. DataTypes::MatrixType GetLocalSpaceBindPoseTransform(const aiScene* scene, const aiNode* node)
  108. {
  109. AZStd::unordered_multimap<AZStd::string, const aiBone*> boneByNameMap;
  110. FindAllBones(scene, boneByNameMap);
  111. const aiBone* bone = FindFirstBoneByNodeName(node, boneByNameMap);
  112. if (bone)
  113. {
  114. const aiBone* parentBone = FindFirstBoneByNodeName(node->mParent, boneByNameMap);
  115. if (parentBone)
  116. {
  117. DataTypes::MatrixType inverseOffsetMatrix = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(bone->mOffsetMatrix).GetInverseFull();
  118. const DataTypes::MatrixType parentBoneOffsetMatrix = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(parentBone->mOffsetMatrix);
  119. return parentBoneOffsetMatrix * inverseOffsetMatrix;
  120. }
  121. }
  122. return AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(node));
  123. }
  124. const aiBone* FindFirstBoneByNodeName(const aiNode* node, AZStd::unordered_multimap<AZStd::string, const aiBone*>& boneByNameMap)
  125. {
  126. if (!node)
  127. {
  128. return nullptr;
  129. }
  130. auto boneIterator = boneByNameMap.find(node->mName.C_Str());
  131. if (boneIterator != boneByNameMap.end())
  132. {
  133. return boneIterator->second;
  134. }
  135. return nullptr;
  136. }
  137. bool RecursiveHasChildBone(const aiNode* node, const AZStd::unordered_multimap<AZStd::string, const aiBone*>& boneByNameMap, const AZStd::unordered_set<AZStd::string>& animatedNodesMap)
  138. {
  139. const bool isBone = boneByNameMap.contains(node->mName.C_Str()) || animatedNodesMap.contains(node->mName.C_Str());
  140. if (isBone)
  141. {
  142. return true;
  143. }
  144. for (unsigned int childIndex = 0; childIndex < node->mNumChildren; ++childIndex)
  145. {
  146. const aiNode* childNode = node->mChildren[childIndex];
  147. if (RecursiveHasChildBone(childNode, boneByNameMap, animatedNodesMap))
  148. {
  149. return true;
  150. }
  151. }
  152. return false;
  153. }
  154. } // namespace SceneBuilder
  155. } // namespace SceneAPI
  156. } // namespace AZ