diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index 25b58ab544..b81d013b87 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -255,7 +255,6 @@ namespace AZ { return AZStd::make_pair(animation, anim); } - Events::ProcessingResult AssImpAnimationImporter::ImportAnimation(AssImpSceneNodeAppendedContext& context) { AZ_TraceContext("Importer", "Animation"); @@ -447,7 +446,22 @@ namespace AZ return combinedAnimationResult.GetResult(); } - decltype(boneAnimations) parentFillerAnimations; + + AZStd::unordered_set boneList; + + for (int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) + { + aiMesh* mesh = scene->mMeshes[meshIndex]; + + for (int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) + { + aiBone* bone = mesh->mBones[boneIndex]; + + boneList.insert(bone->mName.C_Str()); + } + } + + decltype(boneAnimations) fillerAnimations; // Go through all the animations and make sure we create animations for bones who's parents don't have an animation for (auto&& anim : boneAnimations) @@ -459,8 +473,8 @@ namespace AZ { if (!IsPivotNode(parent->mName)) { - if (boneAnimations.find(parent->mName.C_Str()) == boneAnimations.end() && - parentFillerAnimations.find(parent->mName.C_Str()) == parentFillerAnimations.end()) + if (!boneAnimations.contains(parent->mName.C_Str()) && + !fillerAnimations.contains(parent->mName.C_Str())) { // Create 1 key for each type that just copies the current transform ConsolidatedNodeAnim emptyAnimation; @@ -472,7 +486,7 @@ namespace AZ globalTransform.Decompose(scale, rotation, position); emptyAnimation.mNumRotationKeys = emptyAnimation.mNumPositionKeys = emptyAnimation.mNumScalingKeys = 1; - + emptyAnimation.m_ownedPositionKeys.emplace_back(0, position); emptyAnimation.mPositionKeys = emptyAnimation.m_ownedPositionKeys.data(); @@ -481,9 +495,9 @@ namespace AZ emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale); emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data(); - - parentFillerAnimations.insert( - AZStd::make_pair(parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); + + fillerAnimations.insert(AZStd::make_pair( + parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); } } @@ -491,7 +505,7 @@ namespace AZ } } - boneAnimations.insert(AZStd::make_move_iterator(parentFillerAnimations.begin()), AZStd::make_move_iterator(parentFillerAnimations.end())); + boneAnimations.insert(AZStd::make_move_iterator(fillerAnimations.begin()), AZStd::make_move_iterator(fillerAnimations.end())); auto animItr = boneAnimations.equal_range(currentNode->mName.C_Str()); diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 5b43941715..e726547c98 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -98,6 +98,20 @@ namespace AZ } } + aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode) + { + aiMatrix4x4 transform = {}; + const aiNode* iteratingNode = currentNode; + + while (iteratingNode) + { + transform = iteratingNode->mTransformation * transform; + iteratingNode = iteratingNode->mParent; + } + + return transform; + } + Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context) { AZ_TraceContext("Importer", "Bone"); @@ -111,12 +125,7 @@ namespace AZ } bool isBone = false; - - if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid())) - { - isBone = true; - } - else + { AZStd::unordered_map mainBoneList; AZStd::unordered_map boneLookup; @@ -170,15 +179,8 @@ namespace AZ { createdBoneData = AZStd::make_shared(); } - - aiMatrix4x4 transform = currentNode->mTransformation; - const aiNode* parent = currentNode->mParent; - while (parent) - { - transform = parent->mTransformation * transform; - parent = parent->mParent; - } + aiMatrix4x4 transform = CalculateWorldTransform(currentNode); SceneAPI::DataTypes::MatrixType globalTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform); diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h index bc4bdd474e..86069cdd9e 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h @@ -31,7 +31,7 @@ namespace AZ ~AssImpBoneImporter() override = default; static void Reflect(ReflectContext* context); - + Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context); }; } // namespace FbxSceneBuilder diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index bcc007e3a7..f7a85a161b 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -46,8 +46,9 @@ namespace AZ serializeContext->Class()->Version(1); } } - - void GetAllBones(const aiScene* scene, AZStd::unordered_map& boneLookup) + + void GetAllBones( + const aiScene* scene, AZStd::unordered_multimap& boneLookup) { for (unsigned meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { @@ -57,7 +58,7 @@ namespace AZ { const aiBone* bone = mesh->mBones[boneIndex]; - boneLookup[bone->mName.C_Str()] = bone; + boneLookup.emplace(bone->mName.C_Str(), bone); } } } @@ -73,41 +74,53 @@ namespace AZ return Events::ProcessingResult::Ignored; } - AZStd::unordered_map boneLookup; + AZStd::unordered_multimap boneLookup; GetAllBones(scene, boneLookup); auto boneIterator = boneLookup.find(currentNode->mName.C_Str()); const bool isBone = boneIterator != boneLookup.end(); - - aiMatrix4x4 combinedTransform; + + DataTypes::MatrixType localTransform; if (isBone) { - auto parentNode = currentNode->mParent; + AZStd::vector offsets, inverseOffsets; + auto iteratingNode = currentNode; - aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix; - aiMatrix4x4 parentOffset {}; - - auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str()); - - if (parentNode && parentBoneIterator != boneLookup.end()) + while (iteratingNode && boneLookup.count(iteratingNode->mName.C_Str())) { - const auto& parentBone = parentBoneIterator->second; + AZStd::string name = iteratingNode->mName.C_Str(); - parentOffset = parentBone->mOffsetMatrix; + auto range = boneLookup.equal_range(name); + + if (range.first != range.second) + { + // There can be multiple offsetMatrices for a given bone, we're only interested in grabbing the first one + auto boneFirstOffsetMatrix = range.first->second->mOffsetMatrix; + auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(boneFirstOffsetMatrix); + offsets.push_back(azMat); + inverseOffsets.push_back(azMat.GetInverseFull()); + } + + iteratingNode = iteratingNode->mParent; } - - auto inverseOffset = offsetMatrix; - inverseOffset.Inverse(); - - combinedTransform = parentOffset * inverseOffset; + + localTransform = + offsets.at(AZ::GetMin(offsets.size()-1, static_cast(1))) // parent bone offset, or if there is no parent, then current node offset + * inverseOffsets.at(inverseOffsets.size() - 1) // Inverse of root bone offset + * offsets.at(offsets.size() - 1) // Root bone offset + * inverseOffsets.at(0); // Inverse of current node offset } else { - combinedTransform = GetConcatenatedLocalTransform(currentNode); + localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode)); } - DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); + // Don't bother adding a node with the identity matrix + if (localTransform == DataTypes::MatrixType::Identity()) + { + return Events::ProcessingResult::Ignored; + } context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform); context.m_sourceSceneSystem.ConvertUnit(localTransform);