From d841f0c0db73e4c2449360824425f55f1e3a43aa Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri, 4 Jun 2021 16:18:53 -0500 Subject: [PATCH 01/11] Got transform result close for 3 bone chain, longer chains are still not correct (cherry picked from commit 5ac65de6148dcc03b9f2953e97dd943493f23ed9) # Conflicts: # Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp --- .../Importers/AssImpTransformImporter.cpp | 64 +++++++++++++++++-- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index bcc007e3a7..153dfce69d 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -61,7 +61,7 @@ namespace AZ } } } - +#pragma optimize("", off) Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context) { AZ_TraceContext("Importer", "transform"); @@ -79,6 +79,11 @@ namespace AZ auto boneIterator = boneLookup.find(currentNode->mName.C_Str()); const bool isBone = boneIterator != boneLookup.end(); + if (currentNode->mName.C_Str() == AZStd::string("FrontCloth_02")) + { + __debugbreak(); + } + aiMatrix4x4 combinedTransform; if (isBone) @@ -87,20 +92,67 @@ namespace AZ aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix; aiMatrix4x4 parentOffset {}; + aiMatrix4x4 parentTransform{}; + + if (parentNode) + { + parentTransform = parentNode->mTransformation; + } + + auto azOffset = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(offsetMatrix); + decltype(azOffset) azParentOffset{}; + AZStd::vector transforms, offsets, inverseTransforms, inverseOffsets; + + auto addTransform = [&](AZStd::string, aiMatrix4x4 mat) + { + auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); + transforms.push_back(azMat); + inverseTransforms.push_back(azMat.GetInverseFull()); + }; + auto addOffset = [&]([[maybe_unused]] auto name, aiMatrix4x4 mat) + { + auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); + offsets.push_back(azMat); + inverseOffsets.push_back(azMat.GetInverseFull()); + }; + + auto curNode = currentNode; + + while (curNode && boneLookup.count(curNode->mName.C_Str())) + { + AZStd::string name = curNode->mName.C_Str(); + addOffset(name, boneLookup.at(name)->mOffsetMatrix); + addTransform(name, curNode->mTransformation); + + curNode = curNode->mParent; + } + + // Go up the tree to find the root bone. It's parent will be the scene mRootNode + while (parentNode && parentNode->mParent && parentNode->mParent != scene->mRootNode) + { + parentNode = parentNode->mParent; + } auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str()); + aiMatrix4x4 rootOffsetMatrix{}; - if (parentNode && parentBoneIterator != boneLookup.end()) + if (parentBoneIterator != boneLookup.end()) { - const auto& parentBone = parentBoneIterator->second; - - parentOffset = parentBone->mOffsetMatrix; + rootOffsetMatrix = parentBoneIterator->second->mOffsetMatrix; } auto inverseOffset = offsetMatrix; inverseOffset.Inverse(); - combinedTransform = parentOffset * inverseOffset; + auto parentTransformInverse = parentTransform; + parentTransformInverse.Inverse(); + + //auto azInverse = azOffset.GetInverseFull(); + //auto azCombined = azParentOffset * azInverse; + //combinedTransform = parentOffset * inverseOffset; + + //parentTransform ^-1 * parentParent * azOffsetInverse + combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; } else { From 66a030b800c0def8a0b15847b3661b990f925837 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 9 Jun 2021 22:35:03 -0500 Subject: [PATCH 02/11] Fix transform data Use first offsetMatrix for a bone (there may be multiple) and calculate using offsetOfParent * inverseRootOffset * rootOffset * inverseOffset (cherry picked from commit a8eae976dda39ad28f9aa235e1e6ba34715ac48a) # Conflicts: # Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp --- .../Importers/AssImpTransformImporter.cpp | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index 153dfce69d..dc59f59147 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,18 +74,19 @@ 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(); - if (currentNode->mName.C_Str() == AZStd::string("FrontCloth_02")) + if (currentNode->mName.C_Str() == AZStd::string("spine_C0_0_jnt")) { - __debugbreak(); + //__debugbreak(); } aiMatrix4x4 combinedTransform; + DataTypes::MatrixType finalMat; if (isBone) { @@ -121,7 +123,16 @@ namespace AZ while (curNode && boneLookup.count(curNode->mName.C_Str())) { AZStd::string name = curNode->mName.C_Str(); - addOffset(name, boneLookup.at(name)->mOffsetMatrix); + + auto range = boneLookup.equal_range(name); + + for (auto it = range.first; it != range.second; ++it) + { + addOffset(name, it->second->mOffsetMatrix); + break; + } + + //addOffset(name, boneLookup.at(name)->mOffsetMatrix); addTransform(name, curNode->mTransformation); curNode = curNode->mParent; @@ -152,14 +163,24 @@ namespace AZ //combinedTransform = parentOffset * inverseOffset; //parentTransform ^-1 * parentParent * azOffsetInverse - combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; + //combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; + + //azNodeLocal = offsets[1] * inverseOffsets[3] * (offsets[3] * inverseOffsets[0]) + finalMat = + offsets.at(AZ::GetMin(offsets.size()-1, (decltype(offsets.size()))1)) * inverseOffsets.at(inverseOffsets.size() - 1) * offsets.at(offsets.size() - 1) * inverseOffsets.at(0); } else { combinedTransform = GetConcatenatedLocalTransform(currentNode); } - DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); + //DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); + DataTypes::MatrixType localTransform = finalMat; + + if (localTransform == DataTypes::MatrixType::Identity()) + { + return Events::ProcessingResult::Ignored; + } context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform); context.m_sourceSceneSystem.ConvertUnit(localTransform); From 10999b699979aed380138557457440f55e3f0938 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Sat, 12 Jun 2021 13:26:25 -0500 Subject: [PATCH 03/11] All bones have animations (cherry picked from commit d17a8070010cdc5bc4e08d17b1549736d031414a) --- .../Importers/AssImpAnimationImporter.cpp | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index d72cdde8e7..f066540c50 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,24 +446,41 @@ namespace AZ return combinedAnimationResult.GetResult(); } + + AZStd::unordered_set boneList; + + for (int i = 0; i < scene->mNumMeshes; ++i) + { + auto mesh = scene->mMeshes[i]; + + for (auto boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) + { + auto bone = mesh->mBones[boneIndex]; + + boneList.insert(bone->mName.C_Str()); + } + } + decltype(boneAnimations) parentFillerAnimations; // 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) { - const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); - const aiNode* parent = node->mParent; + //const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); + //const aiNode* parent = node->mParent; - while (parent && parent != scene->mRootNode) + //while (parent && parent != scene->mRootNode) + for (auto boneName : boneList) { - if (!IsPivotNode(parent->mName)) + if (!IsPivotNode(aiString(boneName.c_str()))) { - if (boneAnimations.find(parent->mName.C_Str()) == boneAnimations.end() && - parentFillerAnimations.find(parent->mName.C_Str()) == parentFillerAnimations.end()) + if (boneAnimations.find(boneName) == boneAnimations.end() && + parentFillerAnimations.find(boneName) == parentFillerAnimations.end()) { // Create 1 key for each type that just copies the current transform ConsolidatedNodeAnim emptyAnimation; - aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(parent); + auto node = scene->mRootNode->FindNode(boneName.c_str()); + aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(node); aiVector3D position, scale; aiQuaternion rotation; @@ -483,11 +499,11 @@ namespace AZ emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data(); parentFillerAnimations.insert( - AZStd::make_pair(parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); + AZStd::make_pair(boneName, AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); } } - parent = parent->mParent; + //parent = parent->mParent; } } From 9b039c1f9da20e7c8b881bdf81d6df88af0342d4 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Sat, 12 Jun 2021 13:27:32 -0500 Subject: [PATCH 04/11] Fix creating bone data for non-bones (cherry picked from commit 8d1bdd1456e70e4efc47aa36dce660bc91e7dfcf) --- .../Importers/AssImpBoneImporter.cpp | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 5b43941715..694e3566f6 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -97,7 +97,7 @@ namespace AZ EnumChildren(scene, child, mainBoneList, boneLookup); } } - +#pragma optimize("", off) Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context) { AZ_TraceContext("Importer", "Bone"); @@ -112,11 +112,11 @@ namespace AZ bool isBone = false; - if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid())) - { - isBone = true; - } - else + //if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid())) + //{ + // isBone = true; + //} + //else { AZStd::unordered_map mainBoneList; AZStd::unordered_map boneLookup; @@ -171,11 +171,22 @@ namespace AZ createdBoneData = AZStd::make_shared(); } + // L_Lower_Eyelid_Jnt_01 + if (context.m_sourceNode.GetName() == AZStd::string("L_Lower_Eyelid_Jnt_01")) + { + //__debugbreak(); + } + + AZStd::vector transforms; aiMatrix4x4 transform = currentNode->mTransformation; const aiNode* parent = currentNode->mParent; - + + auto addTrans = [&](auto mat) { transforms.push_back(AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat)); }; + addTrans(transform); + while (parent) { + addTrans(parent->mTransformation); transform = parent->mTransformation * transform; parent = parent->mParent; } From 7dc4d8438b008ce914734638eb2bd46621107b9d Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Sat, 12 Jun 2021 20:33:50 -0500 Subject: [PATCH 05/11] Fix non-bone transforms setting the wrong matrix variable (cherry picked from commit 838a8b47da73e50fca4ea9ee5abc7c33250bf25d) --- .../FbxSceneBuilder/Importers/AssImpTransformImporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index dc59f59147..3e22bfc671 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -85,7 +85,7 @@ namespace AZ //__debugbreak(); } - aiMatrix4x4 combinedTransform; + //aiMatrix4x4 combinedTransform; DataTypes::MatrixType finalMat; if (isBone) @@ -171,7 +171,7 @@ namespace AZ } else { - combinedTransform = GetConcatenatedLocalTransform(currentNode); + finalMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode)); } //DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); From 57b19feca5d113ba6fc727cbc8e92e15bff5a9a9 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 16 Jun 2021 12:03:47 -0500 Subject: [PATCH 06/11] Cleanup code --- .../Importers/AssImpAnimationImporter.cpp | 8 +- .../Importers/AssImpBoneImporter.cpp | 34 ++---- .../Importers/AssImpTransformImporter.cpp | 104 ++++-------------- 3 files changed, 32 insertions(+), 114 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index f066540c50..7ab9deb141 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -463,13 +463,9 @@ namespace AZ decltype(boneAnimations) parentFillerAnimations; - // Go through all the animations and make sure we create animations for bones who's parents don't have an animation + // Go through all the animations and make sure we create placeholder animations for any bones missing them for (auto&& anim : boneAnimations) { - //const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); - //const aiNode* parent = node->mParent; - - //while (parent && parent != scene->mRootNode) for (auto boneName : boneList) { if (!IsPivotNode(aiString(boneName.c_str()))) @@ -502,8 +498,6 @@ namespace AZ AZStd::make_pair(boneName, AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); } } - - //parent = parent->mParent; } } diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 694e3566f6..648007ca47 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -97,7 +97,7 @@ namespace AZ EnumChildren(scene, child, mainBoneList, boneLookup); } } -#pragma optimize("", off) + Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context) { AZ_TraceContext("Importer", "Bone"); @@ -111,12 +111,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,25 +165,14 @@ namespace AZ { createdBoneData = AZStd::make_shared(); } - - // L_Lower_Eyelid_Jnt_01 - if (context.m_sourceNode.GetName() == AZStd::string("L_Lower_Eyelid_Jnt_01")) + + aiMatrix4x4 transform{}; + const aiNode* iteratingNode = currentNode; + + while (iteratingNode) { - //__debugbreak(); - } - - AZStd::vector transforms; - aiMatrix4x4 transform = currentNode->mTransformation; - const aiNode* parent = currentNode->mParent; - - auto addTrans = [&](auto mat) { transforms.push_back(AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat)); }; - addTrans(transform); - - while (parent) - { - addTrans(parent->mTransformation); - transform = parent->mTransformation * transform; - parent = parent->mParent; + transform = iteratingNode->mTransformation * transform; + iteratingNode = iteratingNode->mParent; } SceneAPI::DataTypes::MatrixType globalTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform); diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index 3e22bfc671..f7a85a161b 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -62,7 +62,7 @@ namespace AZ } } } -#pragma optimize("", off) + Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context) { AZ_TraceContext("Importer", "transform"); @@ -79,104 +79,44 @@ namespace AZ auto boneIterator = boneLookup.find(currentNode->mName.C_Str()); const bool isBone = boneIterator != boneLookup.end(); - - if (currentNode->mName.C_Str() == AZStd::string("spine_C0_0_jnt")) - { - //__debugbreak(); - } - - //aiMatrix4x4 combinedTransform; - DataTypes::MatrixType finalMat; + + DataTypes::MatrixType localTransform; if (isBone) { - auto parentNode = currentNode->mParent; + AZStd::vector offsets, inverseOffsets; + auto iteratingNode = currentNode; - aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix; - aiMatrix4x4 parentOffset {}; - aiMatrix4x4 parentTransform{}; - - if (parentNode) + while (iteratingNode && boneLookup.count(iteratingNode->mName.C_Str())) { - parentTransform = parentNode->mTransformation; - } - - auto azOffset = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(offsetMatrix); - decltype(azOffset) azParentOffset{}; - AZStd::vector transforms, offsets, inverseTransforms, inverseOffsets; - - auto addTransform = [&](AZStd::string, aiMatrix4x4 mat) - { - auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); - transforms.push_back(azMat); - inverseTransforms.push_back(azMat.GetInverseFull()); - }; - auto addOffset = [&]([[maybe_unused]] auto name, aiMatrix4x4 mat) - { - auto azMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(mat); - offsets.push_back(azMat); - inverseOffsets.push_back(azMat.GetInverseFull()); - }; - - auto curNode = currentNode; - - while (curNode && boneLookup.count(curNode->mName.C_Str())) - { - AZStd::string name = curNode->mName.C_Str(); + AZStd::string name = iteratingNode->mName.C_Str(); auto range = boneLookup.equal_range(name); - for (auto it = range.first; it != range.second; ++it) + if (range.first != range.second) { - addOffset(name, it->second->mOffsetMatrix); - break; + // 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()); } - //addOffset(name, boneLookup.at(name)->mOffsetMatrix); - addTransform(name, curNode->mTransformation); - - curNode = curNode->mParent; + iteratingNode = iteratingNode->mParent; } - - // Go up the tree to find the root bone. It's parent will be the scene mRootNode - while (parentNode && parentNode->mParent && parentNode->mParent != scene->mRootNode) - { - parentNode = parentNode->mParent; - } - - auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str()); - aiMatrix4x4 rootOffsetMatrix{}; - - if (parentBoneIterator != boneLookup.end()) - { - rootOffsetMatrix = parentBoneIterator->second->mOffsetMatrix; - } - - auto inverseOffset = offsetMatrix; - inverseOffset.Inverse(); - - auto parentTransformInverse = parentTransform; - parentTransformInverse.Inverse(); - - //auto azInverse = azOffset.GetInverseFull(); - //auto azCombined = azParentOffset * azInverse; - //combinedTransform = parentOffset * inverseOffset; - - //parentTransform ^-1 * parentParent * azOffsetInverse - //combinedTransform = parentTransformInverse * rootOffsetMatrix * inverseOffset; - - //azNodeLocal = offsets[1] * inverseOffsets[3] * (offsets[3] * inverseOffsets[0]) - finalMat = - offsets.at(AZ::GetMin(offsets.size()-1, (decltype(offsets.size()))1)) * inverseOffsets.at(inverseOffsets.size() - 1) * offsets.at(offsets.size() - 1) * inverseOffsets.at(0); + + 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 { - finalMat = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode)); + localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(GetConcatenatedLocalTransform(currentNode)); } - //DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); - DataTypes::MatrixType localTransform = finalMat; - + // Don't bother adding a node with the identity matrix if (localTransform == DataTypes::MatrixType::Identity()) { return Events::ProcessingResult::Ignored; From ff81b0bfd6eb54bb2e4420b1b709c4ed73bfe22b Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu, 17 Jun 2021 10:40:33 -0500 Subject: [PATCH 07/11] Use contains method instead of find. Rename parentFillerAnimations -> fillerAnimations --- .../Importers/AssImpAnimationImporter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index 5bdc5a8add..ed6d7dfe30 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -461,7 +461,7 @@ namespace AZ } } - decltype(boneAnimations) parentFillerAnimations; + decltype(boneAnimations) fillerAnimations; // Go through all the animations and make sure we create placeholder animations for any bones missing them for (auto&& anim : boneAnimations) @@ -470,8 +470,8 @@ namespace AZ { if (!IsPivotNode(aiString(boneName.c_str()))) { - if (boneAnimations.find(boneName) == boneAnimations.end() && - parentFillerAnimations.find(boneName) == parentFillerAnimations.end()) + if (!boneAnimations.contains(boneName) && + !fillerAnimations.contains(boneName)) { // Create 1 key for each type that just copies the current transform ConsolidatedNodeAnim emptyAnimation; @@ -494,14 +494,14 @@ namespace AZ emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale); emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data(); - parentFillerAnimations.insert( + fillerAnimations.insert( AZStd::make_pair(boneName, AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation)))); } } } } - 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()); From d2d588901e42cddc0a473edc1ffd3aefa59f3db1 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon, 21 Jun 2021 11:00:27 -0500 Subject: [PATCH 08/11] Address PR feedback --- .../Importers/AssImpAnimationImporter.cpp | 34 +++++++++++-------- .../Importers/AssImpBoneImporter.cpp | 23 ++++++++----- .../Importers/AssImpBoneImporter.h | 1 + 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index ed6d7dfe30..b81d013b87 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -449,13 +449,13 @@ namespace AZ AZStd::unordered_set boneList; - for (int i = 0; i < scene->mNumMeshes; ++i) + for (int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { - auto mesh = scene->mMeshes[i]; + aiMesh* mesh = scene->mMeshes[meshIndex]; - for (auto boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) + for (int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) { - auto bone = mesh->mBones[boneIndex]; + aiBone* bone = mesh->mBones[boneIndex]; boneList.insert(bone->mName.C_Str()); } @@ -463,20 +463,22 @@ namespace AZ decltype(boneAnimations) fillerAnimations; - // Go through all the animations and make sure we create placeholder animations for any bones missing them + // 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) { - for (auto boneName : boneList) + const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str()); + const aiNode* parent = node->mParent; + + while (parent && parent != scene->mRootNode) { - if (!IsPivotNode(aiString(boneName.c_str()))) + if (!IsPivotNode(parent->mName)) { - if (!boneAnimations.contains(boneName) && - !fillerAnimations.contains(boneName)) + 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; - auto node = scene->mRootNode->FindNode(boneName.c_str()); - aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(node); + aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(parent); aiVector3D position, scale; aiQuaternion rotation; @@ -484,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(); @@ -493,11 +495,13 @@ namespace AZ emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale); emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data(); - - fillerAnimations.insert( - AZStd::make_pair(boneName, 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)))); } } + + parent = parent->mParent; } } diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 648007ca47..1958c09b3c 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -98,6 +98,20 @@ namespace AZ } } + aiMatrix4x4 AssImpBoneImporter::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"); @@ -166,14 +180,7 @@ namespace AZ createdBoneData = AZStd::make_shared(); } - aiMatrix4x4 transform{}; - const aiNode* iteratingNode = currentNode; - - while (iteratingNode) - { - transform = iteratingNode->mTransformation * transform; - iteratingNode = iteratingNode->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..47cc1922cb 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h @@ -32,6 +32,7 @@ namespace AZ static void Reflect(ReflectContext* context); + aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode); Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context); }; } // namespace FbxSceneBuilder From 514cfc3b4c2bd2aae9704b6bfb71eb2b906ee1e9 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon, 21 Jun 2021 12:27:13 -0500 Subject: [PATCH 09/11] Fix compile error --- .../SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp | 2 +- .../SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp index 1958c09b3c..e726547c98 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp @@ -98,7 +98,7 @@ namespace AZ } } - aiMatrix4x4 AssImpBoneImporter::CalculateWorldTransform(const aiNode* currentNode) + aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode) { aiMatrix4x4 transform = {}; const aiNode* iteratingNode = currentNode; diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h index 47cc1922cb..86069cdd9e 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h @@ -31,8 +31,7 @@ namespace AZ ~AssImpBoneImporter() override = default; static void Reflect(ReflectContext* context); - - aiMatrix4x4 CalculateWorldTransform(const aiNode* currentNode); + Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context); }; } // namespace FbxSceneBuilder From 46f8c7c1ba9ccc77b09eca752062c278fa7312f6 Mon Sep 17 00:00:00 2001 From: cgalvan Date: Mon, 21 Jun 2021 16:03:49 -0500 Subject: [PATCH 10/11] [LYN-3412] Updated LandscapeCanvas component to properly serialize with prefabs. (#1224) * [LYN-3412] Updated LandscapeCanvas component to properly serialize with prefabs. * [LYN-3412] Updated PR with feedback. * [LYN-3412] Reverted unintentional changes. * [LYN-3412] Removed one more comment. * [LYN-3412] Additional PR feedback fixed. --- .../Material/MaterialAssignmentSerializer.cpp | 4 +- .../Integration/GraphCanvasMetadata.h | 1 + .../Code/Include/GraphModel/Model/Graph.h | 10 +- .../Code/Include/GraphModel/Model/Slot.h | 28 +++ .../Source/Integration/GraphController.cpp | 6 +- Gems/GraphModel/Code/Source/Model/Graph.cpp | 8 +- Gems/GraphModel/Code/Source/Model/Slot.cpp | 162 +++++++++++++++++- .../Code/Source/Editor/MainWindow.cpp | 42 ++++- .../Code/Source/Editor/MainWindow.h | 8 + 9 files changed, 248 insertions(+), 21 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp index a895c04b95..551b561200 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp @@ -173,7 +173,7 @@ namespace AZ { if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type")) { - // Requiring explicit type info to differentiate be=tween colors versus vectors and numeric types + // Requiring explicit type info to differentiate between colors versus vectors and numeric types const AZ::Uuid baseTypeId = azrtti_typeid(); AZ::Uuid typeId = AZ::Uuid::CreateNull(); result.Combine(LoadTypeId(typeId, inputPropertyValue, context, &baseTypeId)); @@ -198,7 +198,7 @@ namespace AZ { outputPropertyValue.SetObject(); - // Storing explicit type info to differentiate be=tween colors versus vectors and numeric types + // Storing explicit type info to differentiate between colors versus vectors and numeric types rapidjson::Value typeValue; result.Combine(StoreTypeId(typeValue, azrtti_typeid(), context)); outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator()); diff --git a/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h b/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h index d08acd0b17..1937341cd2 100644 --- a/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h +++ b/Gems/GraphModel/Code/Include/GraphModel/Integration/GraphCanvasMetadata.h @@ -14,6 +14,7 @@ // AZ #include +#include #include // Graph Model diff --git a/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h b/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h index 50c1287080..f3dd85575f 100644 --- a/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h +++ b/Gems/GraphModel/Code/Include/GraphModel/Model/Graph.h @@ -14,10 +14,10 @@ // AZ #include #include -#include #include // Graph Model +#include #include #include @@ -136,9 +136,9 @@ namespace GraphModel //! Set/gets a bundle of generic metadata that is provided by the node graph UI //! system. This may include node positions, comment blocks, node groupings, and //! bookmarks, for example. - void SetUiMetadata(const AZStd::any& uiMetadata); - const AZStd::any& GetUiMetadata() const; - AZStd::any& GetUiMetadata(); + void SetUiMetadata(const GraphModelIntegration::GraphCanvasMetadata& uiMetadata); + const GraphModelIntegration::GraphCanvasMetadata& GetUiMetadata() const; + GraphModelIntegration::GraphCanvasMetadata& GetUiMetadata(); AZStd::shared_ptr FindSlot(const Endpoint& endpoint); @@ -157,7 +157,7 @@ namespace GraphModel ConnectionList m_connections; //! Used to store and serialize metadata from the graph UI, like node positions, comments, group boxes, etc. - AZStd::any m_uiMetadata; + GraphModelIntegration::GraphCanvasMetadata m_uiMetadata; //! Used to store all of our node <-> wrapper node mappings NodeWrappingMap m_nodeWrappings; diff --git a/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h b/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h index 0ce02ffa9d..0b012fd2cd 100644 --- a/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h +++ b/Gems/GraphModel/Code/Include/GraphModel/Model/Slot.h @@ -12,6 +12,7 @@ #pragma once // AZ +#include #include #include #include @@ -165,6 +166,32 @@ namespace GraphModel ExtendableSlotConfiguration m_extendableSlotConfiguration; }; + //! Custom JSON serializer for Slot because we use an AZStd::any for m_value + class JsonSlotSerializer + : public AZ::BaseJsonSerializer + { + public: + AZ_RTTI(JsonSlotSerializer, "{8AC96D70-7BCD-4D68-8813-269938982D51}", AZ::BaseJsonSerializer); + AZ_CLASS_ALLOCATOR(JsonSlotSerializer, AZ::SystemAllocator, 0); + + AZ::JsonSerializationResult::Result Load( + void* outputValue, const AZ::Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) override; + + AZ::JsonSerializationResult::Result Store( + rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) override; + + private: + template + bool LoadAny( + AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context, + AZ::JsonSerializationResult::ResultCode& result); + template + bool StoreAny( + const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context, + AZ::JsonSerializationResult::ResultCode& result); + }; //!!! Start in Graph.h for high level GraphModel documentation !!! @@ -180,6 +207,7 @@ namespace GraphModel class Slot : public GraphElement, public AZStd::enable_shared_from_this { friend class Graph; // So the Graph can update the Slot's cache of Connection pointers + friend class JsonSlotSerializer; // So we can set the m_value and m_subId directly from the serializer public: AZ_CLASS_ALLOCATOR(Slot, AZ::SystemAllocator, 0); diff --git a/Gems/GraphModel/Code/Source/Integration/GraphController.cpp b/Gems/GraphModel/Code/Source/Integration/GraphController.cpp index f6ce6282f4..bb5291637e 100644 --- a/Gems/GraphModel/Code/Source/Integration/GraphController.cpp +++ b/Gems/GraphModel/Code/Source/Integration/GraphController.cpp @@ -1338,11 +1338,7 @@ namespace GraphModelIntegration GraphCanvasMetadata* GraphController::GetGraphMetadata() { - if (!m_graph->GetUiMetadata().is()) - { - m_graph->SetUiMetadata(AZStd::any(GraphCanvasMetadata())); - } - GraphCanvasMetadata* graphCanvasMetadata = AZStd::any_cast(&m_graph->GetUiMetadata()); + GraphCanvasMetadata* graphCanvasMetadata = &m_graph->GetUiMetadata(); AZ_Assert(graphCanvasMetadata, "GraphCanvasMetadata not initialized"); return graphCanvasMetadata; } diff --git a/Gems/GraphModel/Code/Source/Model/Graph.cpp b/Gems/GraphModel/Code/Source/Model/Graph.cpp index 809679e9f6..e82b5d8e15 100644 --- a/Gems/GraphModel/Code/Source/Model/Graph.cpp +++ b/Gems/GraphModel/Code/Source/Model/Graph.cpp @@ -37,7 +37,7 @@ namespace GraphModel if (serializeContext) { serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("m_nodes", &Graph::m_nodes) ->Field("m_connections", &Graph::m_connections) ->Field("m_uiMetadata", &Graph::m_uiMetadata) @@ -312,19 +312,19 @@ namespace GraphModel } - void Graph::SetUiMetadata(const AZStd::any& uiMetadata) + void Graph::SetUiMetadata(const GraphModelIntegration::GraphCanvasMetadata& uiMetadata) { m_uiMetadata = uiMetadata; } - const AZStd::any& Graph::GetUiMetadata() const + const GraphModelIntegration::GraphCanvasMetadata& Graph::GetUiMetadata() const { return m_uiMetadata; } - AZStd::any& Graph::GetUiMetadata() + GraphModelIntegration::GraphCanvasMetadata& Graph::GetUiMetadata() { return m_uiMetadata; } diff --git a/Gems/GraphModel/Code/Source/Model/Slot.cpp b/Gems/GraphModel/Code/Source/Model/Slot.cpp index e5fb9f8cb8..6433129af8 100644 --- a/Gems/GraphModel/Code/Source/Model/Slot.cpp +++ b/Gems/GraphModel/Code/Source/Model/Slot.cpp @@ -11,9 +11,14 @@ */ // AZ +#include +#include +#include +#include #include #include #include +#include #include // Graph Model @@ -294,13 +299,164 @@ namespace GraphModel ///////////////////////////////////////////////////////// // Slot + AZ::JsonSerializationResult::Result JsonSlotSerializer::Load( + void* outputValue, const AZ::Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) + { + namespace JSR = AZ::JsonSerializationResult; + + AZ_Assert( + azrtti_typeid() == outputValueTypeId, + "Unable to deserialize Slot from json because the provided type is %s.", + outputValueTypeId.ToString().c_str()); + + Slot* slot = reinterpret_cast(outputValue); + AZ_Assert(slot, "Output value for JsonSlotSerializer can't be null."); + + JSR::ResultCode result(JSR::Tasks::ReadField); + + auto serializedSlotValue = inputValue.FindMember("m_value"); + if (serializedSlotValue != inputValue.MemberEnd()) + { + AZStd::any slotValue; + if (LoadAny(slotValue, serializedSlotValue->value, context, result) || + LoadAny(slotValue, serializedSlotValue->value, context, result) || + LoadAny(slotValue, serializedSlotValue->value, context, result) || + LoadAny(slotValue, serializedSlotValue->value, context, result) || + LoadAny(slotValue, serializedSlotValue->value, context, result) || + LoadAny(slotValue, serializedSlotValue->value, context, result) || + LoadAny(slotValue, serializedSlotValue->value, context, result) || + LoadAny(slotValue, serializedSlotValue->value, context, result)) + { + slot->m_value = slotValue; + } + } + + // Load m_subId normally because it's just an int + { + SlotSubId slotSubId = 0; + result.Combine(ContinueLoadingFromJsonObjectField( + &slotSubId, azrtti_typeid(), inputValue, + "m_subId", context)); + slot->m_subId = slotSubId; + } + + return context.Report( + result, + result.GetProcessing() != JSR::Processing::Halted ? "Succesfully loaded Slot information." + : "Failed to load Slot information."); + } + + AZ::JsonSerializationResult::Result JsonSlotSerializer::Store( + rapidjson::Value& outputValue, const void* inputValue, [[maybe_unused]] const void* defaultValue, const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) + { + namespace JSR = AZ::JsonSerializationResult; + + AZ_Assert( + azrtti_typeid() == valueTypeId, + "Unable to Serialize Slot because the provided type is %s.", valueTypeId.ToString().c_str()); + + const Slot* slot = reinterpret_cast(inputValue); + AZ_Assert(slot, "Input value for JsonSlotSerializer can't be null."); + + outputValue.SetObject(); + + JSR::ResultCode result(JSR::Tasks::WriteValue); + + { + AZ::ScopedContextPath subPathPropertyOverrides(context, "m_value"); + + if (!slot->m_value.empty()) + { + rapidjson::Value outputPropertyValue; + if (StoreAny(slot->m_value, outputPropertyValue, context, result) || + StoreAny(slot->m_value, outputPropertyValue, context, result) || + StoreAny(slot->m_value, outputPropertyValue, context, result) || + StoreAny(slot->m_value, outputPropertyValue, context, result) || + StoreAny(slot->m_value, outputPropertyValue, context, result) || + StoreAny(slot->m_value, outputPropertyValue, context, result) || + StoreAny(slot->m_value, outputPropertyValue, context, result) || + StoreAny(slot->m_value, outputPropertyValue, context, result)) + { + outputValue.AddMember("m_value", outputPropertyValue, context.GetJsonAllocator()); + } + } + } + + { + AZ::ScopedContextPath subSlotId(context, "m_subId"); + SlotSubId defaultSubId = 0; + + result.Combine(ContinueStoringToJsonObjectField( + outputValue, "m_subId", &slot->m_subId, &defaultSubId, + azrtti_typeid(), context)); + } + + return context.Report( + result, + result.GetProcessing() != JSR::Processing::Halted ? "Successfully stored MaterialAssignment information." + : "Failed to store MaterialAssignment information."); + } + + template + bool JsonSlotSerializer::LoadAny( + AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context, + AZ::JsonSerializationResult::ResultCode& result) + { + auto valueItr = inputPropertyValue.FindMember("Value"); + auto typeItr = inputPropertyValue.FindMember("$type"); + if ((valueItr != inputPropertyValue.MemberEnd()) && (typeItr != inputPropertyValue.MemberEnd())) + { + // Requiring explicit type info to differentiate between colors versus vectors and numeric types + const AZ::Uuid baseTypeId = azrtti_typeid(); + AZ::Uuid typeId = AZ::Uuid::CreateNull(); + result.Combine(LoadTypeId(typeId, inputPropertyValue, context, &baseTypeId)); + + if (typeId == azrtti_typeid()) + { + T value; + result.Combine(ContinueLoadingFromJsonObjectField(&value, azrtti_typeid(), inputPropertyValue, "Value", context)); + propertyValue = value; + return true; + } + } + return false; + } + + template + bool JsonSlotSerializer::StoreAny( + const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context, + AZ::JsonSerializationResult::ResultCode& result) + { + if (propertyValue.is()) + { + outputPropertyValue.SetObject(); + + // Storing explicit type info to differentiate between colors versus vectors and numeric types + rapidjson::Value typeValue; + result.Combine(StoreTypeId(typeValue, azrtti_typeid(), context)); + outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator()); + + T value = AZStd::any_cast(propertyValue); + result.Combine( + ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid(), context)); + return true; + } + return false; + } + void Slot::Reflect(AZ::ReflectContext* context) { - AZ::SerializeContext* serializeContext = azrtti_cast(context); - if (serializeContext) + if (auto jsonContext = azrtti_cast(context)) + { + jsonContext->Serializer()->HandlesType(); + } + + if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("m_value", &Slot::m_value) ->Field("m_subId", &Slot::m_subId) // m_slotDescription is not reflected because that data is populated procedurally by each node diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp index 3879cd2597..2f3a7d7ab4 100644 --- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp +++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp @@ -460,10 +460,10 @@ namespace LandscapeCanvasEditor GraphCanvas::StyleManagerRequestBus::Event(editorId, &GraphCanvas::StyleManagerRequests::RegisterDataPaletteStyle, LandscapeCanvas::AreaTypeId, "VegetationAreaDataColorPalette"); LandscapeCanvas::LandscapeCanvasRequestBus::Handler::BusConnect(); - AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorPickModeNotificationBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); AzToolsFramework::EntityCompositionNotificationBus::Handler::BusConnect(); AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusConnect(); + AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect(); CrySystemEventBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); @@ -480,6 +480,7 @@ namespace LandscapeCanvasEditor { AZ::EntitySystemBus::Handler::BusDisconnect(); CrySystemEventBus::Handler::BusDisconnect(); + AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect(); AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect(); @@ -883,6 +884,10 @@ namespace LandscapeCanvasEditor if (landscapeCanvasComponent) { landscapeCanvasComponent->m_graph = *m_serializeContext->CloneObject(graph.get()); + + // Mark the Landscape Canvas entity as dirty so the changes to the graph will be picked up on the next save + AzToolsFramework::ScopedUndoBatch undo("Update Landscape Canvas Graph"); + AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, rootEntityId); } } } @@ -1572,7 +1577,7 @@ namespace LandscapeCanvasEditor void MainWindow::HandleEditorEntityCreated(const AZ::EntityId& entityId, GraphCanvas::GraphId graphId) { - if (m_ignoreGraphUpdates) + if (m_ignoreGraphUpdates || m_prefabPropagationInProgress) { return; } @@ -1622,6 +1627,11 @@ namespace LandscapeCanvasEditor void MainWindow::OnEditorEntityDeleted(const AZ::EntityId& entityId) { + if (m_prefabPropagationInProgress) + { + return; + } + m_queuedEntityDeletes.push_back(entityId); QTimer::singleShot(0, [this, entityId]() { @@ -2456,6 +2466,11 @@ namespace LandscapeCanvasEditor void MainWindow::EntityParentChanged(AZ::EntityId entityId, AZ::EntityId newParentId, AZ::EntityId oldParentId) { + if (m_prefabPropagationInProgress) + { + return; + } + GraphCanvas::GraphId oldGraphId = FindGraphContainingEntity(oldParentId); GraphCanvas::GraphId newGraphId = FindGraphContainingEntity(newParentId); @@ -2482,6 +2497,20 @@ namespace LandscapeCanvasEditor } } + void MainWindow::OnPrefabInstancePropagationBegin() + { + // Ignore graph updates during prefab propagation because the entities will be + // deleted and re-created, which would inadvertantly trigger our logic to close + // the graph when the corresponding entity is deleted. + m_prefabPropagationInProgress = true; + } + + void MainWindow::OnPrefabInstancePropagationEnd() + { + // See comment above in OnPrefabInstancePropagationBegin + m_prefabPropagationInProgress = false; + } + void MainWindow::OnCryEditorEndCreate() { UpdateGraphEnabled(); @@ -2490,6 +2519,15 @@ namespace LandscapeCanvasEditor void MainWindow::OnCryEditorEndLoad() { UpdateGraphEnabled(); + + AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); + } + + void MainWindow::OnCryEditorCloseScene() + { + UpdateGraphEnabled(); + + AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect(); } void MainWindow::OnCryEditorSceneClosed() diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h index eddf998d8d..e6887eecfd 100644 --- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h +++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,7 @@ namespace LandscapeCanvasEditor , private AzToolsFramework::EntityCompositionNotificationBus::Handler , private AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler , private AzToolsFramework::ToolsApplicationNotificationBus::Handler + , private AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler , private CrySystemEventBus::Handler { Q_OBJECT @@ -183,10 +185,15 @@ namespace LandscapeCanvasEditor void EntityParentChanged(AZ::EntityId entityId, AZ::EntityId newParentId, AZ::EntityId oldParentId) override; //////////////////////////////////////////////////////////////////////// + //! PrefabPublicNotificationBus overrides + void OnPrefabInstancePropagationBegin() override; + void OnPrefabInstancePropagationEnd() override; + //////////////////////////////////////////////////////////////////////// // CrySystemEventBus overrides void OnCryEditorEndCreate() override; void OnCryEditorEndLoad() override; + void OnCryEditorCloseScene() override; void OnCryEditorSceneClosed() override; //////////////////////////////////////////////////////////////////////// @@ -246,6 +253,7 @@ namespace LandscapeCanvasEditor AZ::SerializeContext* m_serializeContext = nullptr; bool m_ignoreGraphUpdates = false; + bool m_prefabPropagationInProgress = false; bool m_inObjectPickMode = false; using DeletedNodePositionsMap = AZStd::unordered_map; From ca76a4d1ab29074a209b190388b2149ea0ff08b5 Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Mon, 21 Jun 2021 16:11:50 -0500 Subject: [PATCH 11/11] Moved helpers to the top level menu bar above viewport (#1464) --- .../AzQtComponents/Images/Menu/helpers.svg | 24 +++++++++++++++++++ .../AzQtComponents/Images/resources.qrc | 1 + Code/Sandbox/Editor/ViewportTitleDlg.cpp | 16 +++++++------ Code/Sandbox/Editor/ViewportTitleDlg.h | 2 +- Code/Sandbox/Editor/ViewportTitleDlg.ui | 12 ++++++++++ 5 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg new file mode 100644 index 0000000000..e782a7066a --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/helpers.svg @@ -0,0 +1,24 @@ + + + Helpers Icon + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc index bf110c1899..74610dca90 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc @@ -29,5 +29,6 @@ Menu/trackview_editor.svg Menu/ui_editor.svg Menu/menu.svg + Menu/helpers.svg diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp index 491d31a2ff..5b13b1d308 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.cpp +++ b/Code/Sandbox/Editor/ViewportTitleDlg.cpp @@ -130,6 +130,7 @@ CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent) SetupCameraDropdownMenu(); SetupResolutionDropdownMenu(); SetupViewportInformationMenu(); + SetupHelpersButton(); SetupOverflowMenu(); Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequest, gSettings.bMuteAudio ? m_oMuteAudioRequest : m_oUnmuteAudioRequest); @@ -211,15 +212,16 @@ void CViewportTitleDlg::SetupViewportInformationMenu() } +void CViewportTitleDlg::SetupHelpersButton() +{ + connect(m_ui->m_helpers, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleHelpers); + m_ui->m_helpers->setChecked(Helpers::IsHelpersShown()); +} + void CViewportTitleDlg::SetupOverflowMenu() { // Setup the overflow menu QMenu* overFlowMenu = new QMenu(this); - m_debugHelpersAction = new QAction("Debug Helpers", overFlowMenu); - m_debugHelpersAction->setCheckable(true); - m_debugHelpersAction->setChecked(Helpers::IsHelpersShown()); - connect(m_debugHelpersAction, &QAction::triggered, this, &CViewportTitleDlg::OnToggleHelpers); - overFlowMenu->addAction(m_debugHelpersAction); m_audioMuteAction = new QAction("Mute Audio", overFlowMenu); connect(m_audioMuteAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedMuteAudio); @@ -333,7 +335,7 @@ void CViewportTitleDlg::OnMaximize() void CViewportTitleDlg::OnToggleHelpers() { Helpers::ToggleHelpers(); - m_debugHelpersAction->setChecked(Helpers::IsHelpersShown()); + m_ui->m_helpers->setChecked(Helpers::IsHelpersShown()); } void CViewportTitleDlg::SetNoViewportInfo() @@ -759,7 +761,7 @@ void CViewportTitleDlg::OnEditorNotifyEvent(EEditorNotifyEvent event) switch (event) { case eNotify_OnDisplayRenderUpdate: - m_debugHelpersAction->setChecked(Helpers::IsHelpersShown()); + m_ui->m_helpers->setChecked(Helpers::IsHelpersShown()); break; case eNotify_OnBeginGameMode: case eNotify_OnEndGameMode: diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.h b/Code/Sandbox/Editor/ViewportTitleDlg.h index 255354dcbb..e4670e7873 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.h +++ b/Code/Sandbox/Editor/ViewportTitleDlg.h @@ -102,6 +102,7 @@ protected: void SetupResolutionDropdownMenu(); void SetupViewportInformationMenu(); void SetupOverflowMenu(); + void SetupHelpersButton(); QString m_title; @@ -172,7 +173,6 @@ protected: QAction* m_normalInformationAction = nullptr; QAction* m_fullInformationAction = nullptr; QAction* m_compactInformationAction = nullptr; - QAction* m_debugHelpersAction = nullptr; QAction* m_audioMuteAction = nullptr; QAction* m_enableVRAction = nullptr; QAction* m_enableGridSnappingAction = nullptr; diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.ui b/Code/Sandbox/Editor/ViewportTitleDlg.ui index 58b4ec70c6..7d8e9d50d4 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.ui +++ b/Code/Sandbox/Editor/ViewportTitleDlg.ui @@ -81,6 +81,18 @@ + + + + + :/Menu/helpers.svg:/Menu/helpers.svg + + + + true + + +