diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp index 3d0cbca8e6..f14d73a9cf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp @@ -14,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -27,62 +29,42 @@ namespace AZ::RPI AZStd::unordered_map MorphTargetExporter::GetBlendShapeInfos( const Containers::Scene& scene, - const AZStd::optional& filterMeshName) const + const MeshData* meshData) const { const Containers::SceneGraph& sceneGraph = scene.GetGraph(); - const auto contentStorage = sceneGraph.GetContentStorage(); - const auto nameStorage = sceneGraph.GetNameStorage(); + + const auto foundBaseMeshIter = AZStd::find_if(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), [meshData](const auto& nodeData) + { + return nodeData.get() == meshData; + }); + if (foundBaseMeshIter == sceneGraph.GetContentStorage().cend()) + { + return {}; + } + + const auto baseMeshNodeIndex = sceneGraph.ConvertToNodeIndex(foundBaseMeshIter); + + const auto childBlendShapeDatas = Containers::MakeDerivedFilterView( + Containers::Views::MakeSceneGraphChildView(sceneGraph, baseMeshNodeIndex, sceneGraph.GetContentStorage().cbegin(), true) + ); AZStd::unordered_map result; - - const auto keyValueView = Containers::Views::MakePairView(nameStorage, contentStorage); - const auto filteredView = Containers::Views::MakeFilterView(keyValueView, Containers::DerivedTypeFilter()); - for (const auto& [name, object] : filteredView) + for (auto it = childBlendShapeDatas.cbegin(); it != childBlendShapeDatas.cend(); ++it) { - const Containers::SceneGraph::NodeIndex sceneNodeIndex = sceneGraph.Find(name.GetPath()); + const Containers::SceneGraph::NodeIndex blendShapeNodeIndex = sceneGraph.ConvertToNodeIndex(it.GetBaseIterator().GetBaseIterator().GetHierarchyIterator()); AZStd::set types; - Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, sceneNodeIndex); - if (types.find(Events::GraphMetaInfo::GetIgnoreVirtualType()) == types.end()) + Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, blendShapeNodeIndex); + if (!types.contains(Events::GraphMetaInfo::GetIgnoreVirtualType())) { - const char* sceneNodePath = name.GetPath(); - const Containers::SceneGraph::NodeIndex nodeIndex = sceneGraph.Find(sceneNodePath); - if (nodeIndex.IsValid()) - { - const AZStd::string meshNodeName = SourceBlendShapeInfo::GetMeshNodeName(sceneGraph, nodeIndex); - if (!filterMeshName.has_value() || - (filterMeshName.has_value() && filterMeshName.value() == meshNodeName)) - { - const AZStd::string blendShapeName = sceneGraph.GetNodeName(nodeIndex).GetName(); - SourceBlendShapeInfo& blendShapeInfo = result[blendShapeName]; - blendShapeInfo.m_sceneNodeIndices.push_back(nodeIndex); - } - } - else - { - AZ_Warning(ModelAssetBuilderComponent::s_builderName, false, "Cannot retrieve scene graph index for blend shape node with path %s.", sceneNodePath); - } + const AZStd::string blendShapeName{sceneGraph.GetNodeName(blendShapeNodeIndex).GetName(), sceneGraph.GetNodeName(blendShapeNodeIndex).GetNameLength()}; + result[blendShapeName].m_sceneNodeIndices.emplace_back(blendShapeNodeIndex); } } return result; } - AZStd::string MorphTargetExporter::SourceBlendShapeInfo::GetMeshNodeName(const Containers::SceneGraph& sceneGraph, - const Containers::SceneGraph::NodeIndex& sceneNodeIndex) - { - const auto* blendShapeData = - azrtti_cast(sceneGraph.GetNodeContent(sceneNodeIndex).get()); - AZ_Assert(blendShapeData, "Cannot get mesh node name from scene node. Node is expected to be a blend shape."); - if (blendShapeData) - { - Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex); - return sceneGraph.GetNodeName(morphMeshParentIndex).GetName(); - } - - return {}; - } - void MorphTargetExporter::ProduceMorphTargets(const Containers::Scene& scene, uint32_t vertexOffset, const ModelAssetBuilderComponent::SourceMeshContent& sourceMesh, @@ -92,9 +74,14 @@ namespace AZ::RPI { const Containers::SceneGraph& sceneGraph = scene.GetGraph(); +#if defined(AZ_ENABLE_TRACING) + const auto baseMeshIt = AZStd::find(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), sourceMesh.m_meshData); + const Containers::SceneGraph::NodeIndex baseMeshIndex = sceneGraph.ConvertToNodeIndex(baseMeshIt); + const AZStd::string_view baseMeshName{sceneGraph.GetNodeName(baseMeshIndex).GetName(), sceneGraph.GetNodeName(baseMeshIndex).GetNameLength()}; +#endif + // Get the blend shapes for the given mesh - const AZStd::string_view meshName = sourceMesh.m_name.GetStringView(); - AZStd::unordered_map blendShapeInfos = GetBlendShapeInfos(scene, meshName); + AZStd::unordered_map blendShapeInfos = GetBlendShapeInfos(scene, sourceMesh.m_meshData.get()); for (const auto& iter : blendShapeInfos) { @@ -109,12 +96,12 @@ namespace AZ::RPI { #if defined(AZ_ENABLE_TRACING) const Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex); - const char* meshNodeName = sceneGraph.GetNodeName(morphMeshParentIndex).GetName(); + const AZStd::string_view sourceMeshName{sceneGraph.GetNodeName(morphMeshParentIndex).GetName(), sceneGraph.GetNodeName(morphMeshParentIndex).GetNameLength()}; #endif - AZ_Assert(AZ::StringFunc::Equal(sourceMesh.m_name.GetCStr(), meshNodeName, /*bCaseSensitive=*/true), - "Scene graph mesh node (%s) has a different name than the product mesh (%s).", - meshNodeName, sourceMesh.m_name.GetCStr()); + AZ_Assert(AZ::StringFunc::Equal(baseMeshName, sourceMeshName, /*bCaseSensitive=*/true), + "Scene graph mesh node (%.*s) has a different name than the product mesh (%.*s).", + AZ_STRING_ARG(sourceMeshName), AZ_STRING_ARG(baseMeshName)); const DataTypes::MatrixType globalTransform = Utilities::BuildWorldTransform(sceneGraph, sceneNodeIndex); BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter, scene.GetSourceFilename()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h index 4845d7d1da..32f9e2e508 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h @@ -39,12 +39,9 @@ namespace AZ struct SourceBlendShapeInfo { AZStd::vector m_sceneNodeIndices; - - static AZStd::string GetMeshNodeName(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph, - const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& sceneNodeIndex); }; //! Retrieve all scene graph nodes per blend shape for all available blend shapes. - AZStd::unordered_map GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const AZStd::optional& filterMeshName = AZStd::nullopt) const; + AZStd::unordered_map GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const MeshData* meshData) const; //! Calculate position delta tolerance that is used to indicate whether a given vertex is part of the sparse set of morphed vertices //! or if it will be skipped and optimized out due to a hardly visible or no movement at all.