From 598c890cbc438ce0022625ac5edb14d0228ddd4e Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 29 Jun 2021 15:14:33 -0500 Subject: [PATCH] Fix nodes being incorrectly treated as bones Some nodes have aiBones created by AssImp even though they aren't bones. Filter these out by looking through the node graph and only considering Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../Importers/AssImpBoneImporter.cpp | 72 +++++++------------ .../Importers/AssImpTransformImporter.cpp | 29 +++++++- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 1828919c46..6ae228a8a8 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -40,59 +40,45 @@ namespace AZ } } - void EnumBonesInNode( - const aiScene* scene, const aiNode* node, AZStd::unordered_map& mainBoneList, - AZStd::unordered_map& boneLookup) + void MakeBoneMap(const aiScene* scene, AZStd::unordered_map& boneLookup) { - /* From AssImp Documentation - a) Create a map or a similar container to store which nodes are necessary for the skeleton. Pre-initialise it for all nodes with a "no". - b) For each bone in the mesh: - b1) Find the corresponding node in the scene's hierarchy by comparing their names. - b2) Mark this node as "yes" in the necessityMap. - b3) Mark all of its parents the same way until you 1) find the mesh's node or 2) the parent of the mesh's node. - c) Recursively iterate over the node hierarchy - c1) If the node is marked as necessary, copy it into the skeleton and check its children - c2) If the node is marked as not necessary, skip it and do not iterate over its children. - */ + AZStd::queue queue; + AZStd::unordered_set nodesWithNoMesh; - for (unsigned meshIndex = 0; meshIndex < node->mNumMeshes; ++meshIndex) + queue.push(scene->mRootNode); + + while (!queue.empty()) { - const aiMesh* mesh = scene->mMeshes[node->mMeshes[meshIndex]]; + const aiNode* currentNode = queue.front(); + queue.pop(); + + if (currentNode->mNumMeshes == 0) + { + nodesWithNoMesh.emplace(currentNode->mName.C_Str()); + } + + for (int childIndex = 0; childIndex < currentNode->mNumChildren; ++childIndex) + { + queue.push(currentNode->mChildren[childIndex]); + } + } + + for (unsigned meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) + { + const aiMesh* mesh = scene->mMeshes[meshIndex]; for (unsigned boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) { const aiBone* bone = mesh->mBones[boneIndex]; - const aiNode* boneNode = scene->mRootNode->FindNode(bone->mName); - const aiNode* boneParent = boneNode->mParent; - - mainBoneList[bone->mName.C_Str()] = boneNode; - boneLookup[bone->mName.C_Str()] = bone; - - while (boneParent && boneParent != node && boneParent != node->mParent && boneParent != scene->mRootNode) + if (nodesWithNoMesh.contains(bone->mName.C_Str())) { - mainBoneList[boneParent->mName.C_Str()] = boneParent; - - boneParent = boneParent->mParent; + boneLookup.emplace(bone->mName.C_Str(), bone); } } } } - void EnumChildren( - const aiScene* scene, const aiNode* node, AZStd::unordered_map& mainBoneList, - AZStd::unordered_map& boneLookup) - { - EnumBonesInNode(scene, node, mainBoneList, boneLookup); - - for (unsigned childIndex = 0; childIndex < node->mNumChildren; ++childIndex) - { - const aiNode* child = node->mChildren[childIndex]; - - EnumChildren(scene, child, mainBoneList, boneLookup); - } - } - aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode) { aiMatrix4x4 transform = {}; @@ -122,14 +108,10 @@ namespace AZ bool isBone = false; { - AZStd::unordered_map mainBoneList; AZStd::unordered_map boneLookup; - EnumChildren(scene, scene->mRootNode, mainBoneList, boneLookup); + MakeBoneMap(scene, boneLookup); - if (mainBoneList.find(currentNode->mName.C_Str()) != mainBoneList.end()) - { - isBone = true; - } + isBone = boneLookup.contains(currentNode->mName.C_Str()); // If we have an animation, the bones will be listed in there if (!isBone) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index 5f9ffbd9b3..2f515c6174 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -42,9 +42,29 @@ namespace AZ } } - void GetAllBones( - const aiScene* scene, AZStd::unordered_multimap& boneLookup) + void GetAllBones(const aiScene* scene, AZStd::unordered_multimap& boneLookup) { + AZStd::queue queue; + AZStd::unordered_set nodesWithNoMesh; + + queue.push(scene->mRootNode); + + while (!queue.empty()) + { + const aiNode* currentNode = queue.front(); + queue.pop(); + + if (currentNode->mNumMeshes == 0) + { + nodesWithNoMesh.emplace(currentNode->mName.C_Str()); + } + + for (int childIndex = 0; childIndex < currentNode->mNumChildren; ++childIndex) + { + queue.push(currentNode->mChildren[childIndex]); + } + } + for (unsigned meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { const aiMesh* mesh = scene->mMeshes[meshIndex]; @@ -53,7 +73,10 @@ namespace AZ { const aiBone* bone = mesh->mBones[boneIndex]; - boneLookup.emplace(bone->mName.C_Str(), bone); + if (nodesWithNoMesh.contains(bone->mName.C_Str())) + { + boneLookup.emplace(bone->mName.C_Str(), bone); + } } } }