diff --git a/lib/mayaUsd/fileio/translators/translatorBlendShape.cpp b/lib/mayaUsd/fileio/translators/translatorBlendShape.cpp index 8efbcf9829..92a26d9bd8 100644 --- a/lib/mayaUsd/fileio/translators/translatorBlendShape.cpp +++ b/lib/mayaUsd/fileio/translators/translatorBlendShape.cpp @@ -149,6 +149,10 @@ bool UsdMayaTranslatorBlendShape::Read(const UsdPrim& meshPrim, UsdMayaPrimReade const auto blendShapeObj = blendFn.create(objToBlendShape, MFnBlendShapeDeformer::kLocalOrigin, &status); CHECK_MSTATUS_AND_RETURN(status, false) + MFnDependencyNode blendShapeDepNodeFn; + blendShapeDepNodeFn.setObject(blendShapeObj); + blendShapeDepNodeFn.setName(MString( + TfStringPrintf("%s_Deformer", meshPrim.GetPath().GetElementString().c_str()).c_str())); MObject deformedMeshObject; VtVec3fArray deltaPoints, deltaNormals; diff --git a/lib/mayaUsd/fileio/translators/translatorSkel.cpp b/lib/mayaUsd/fileio/translators/translatorSkel.cpp index bd6baabad9..633a5633dc 100644 --- a/lib/mayaUsd/fileio/translators/translatorSkel.cpp +++ b/lib/mayaUsd/fileio/translators/translatorSkel.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -28,21 +29,18 @@ #include #include -#include #include #include #include +#include #include #include -#include -#include #include #include #include #include #include #include -#include #include #include @@ -1317,8 +1315,27 @@ bool UsdMayaTranslatorSkel::CreateSkinCluster( const auto skinSrc = shapeToSkinInMesh.source(); if (!skinSrc.isNull()) { + MObjectArray blendShapeDeformers; + UsdMayaMeshWriteUtils::getBlendShapesOfMesh( + shapeToSkin, blendShapeDeformers, &status); + dgMod.disconnect(skinSrc, shapeToSkinInMesh); - status = dgMod.connect(skinSrc, groupPartsInputGeometry); + + // If the mesh has blendShapes, it has already been created prior to this step. + // When that's the case, we need to disconnect the blendShape outputGeometry + // and connect it to the groupParts.inputGeometry which drives the skel/skinCluster. + // Then, the output of the groupParts will be connected to the end mesh. + if (blendShapeDeformers.length() > 0) { + MFnBlendShapeDeformer blendShapeFn(blendShapeDeformers[0], &status); + MPlug blenshapeOutputPlug + = blendShapeFn.findPlug(_MayaTokens->outputGeometry, &status); + MPlug blenshapeOutputPlug0 + = blenshapeOutputPlug.elementByLogicalIndex(0, &status); + + status = dgMod.connect(blenshapeOutputPlug0, groupPartsInputGeometry); + } else { + status = dgMod.connect(skinSrc, groupPartsInputGeometry); + } CHECK_MSTATUS_AND_RETURN(status, false); } else { // For the case where there were no blendShapes attached to the mesh, create a rest diff --git a/lib/mayaUsd/fileio/utils/meshWriteUtils.cpp b/lib/mayaUsd/fileio/utils/meshWriteUtils.cpp index 01f148ccc0..2f34235acb 100644 --- a/lib/mayaUsd/fileio/utils/meshWriteUtils.cpp +++ b/lib/mayaUsd/fileio/utils/meshWriteUtils.cpp @@ -419,6 +419,36 @@ MStatus UsdMayaMeshWriteUtils::getSkinClustersUpstreamOfMesh( return stat; } +void UsdMayaMeshWriteUtils::getBlendShapesOfMesh( + const MObject& mesh, + MObjectArray& blendShapes, + MStatus* stat) +{ + if (mesh.isNull() || !mesh.hasFn(MFn::kMesh)) { + if (stat) { + *stat = MStatus::kInvalidParameter; + } + return; + } + + blendShapes.clear(); + MObject searchObj = MObject(mesh); + MItDependencyGraph itDg( + searchObj, + MFn::kInvalid, + MItDependencyGraph::kUpstream, + MItDependencyGraph::kDepthFirst, + MItDependencyGraph::kNodeLevel, + stat); + while (!itDg.isDone()) { + MObject curNode = itDg.currentItem(); + if (curNode.hasFn(MFn::kBlendShape)) { + blendShapes.append(curNode); + } + itDg.next(); + } +} + MBoundingBox UsdMayaMeshWriteUtils::calcBBoxOfMeshes(const MObjectArray& meshes) { unsigned int numMeshes = meshes.length(); diff --git a/lib/mayaUsd/fileio/utils/meshWriteUtils.h b/lib/mayaUsd/fileio/utils/meshWriteUtils.h index 444af86080..0f40dbdc32 100644 --- a/lib/mayaUsd/fileio/utils/meshWriteUtils.h +++ b/lib/mayaUsd/fileio/utils/meshWriteUtils.h @@ -66,6 +66,9 @@ MStatus getSkinClusterConnectedToMesh(const MObject& mesh, MObject& skinCluster) MAYAUSD_CORE_PUBLIC MStatus getSkinClustersUpstreamOfMesh(const MObject& mesh, MObjectArray& skinClusters); +MAYAUSD_CORE_PUBLIC +void getBlendShapesOfMesh(const MObject& mesh, MObjectArray& blendShapes, MStatus* stat); + /** * Calculates the union bounding box of a given array of meshes. * @@ -73,8 +76,7 @@ MStatus getSkinClustersUpstreamOfMesh(const MObject& mesh, MObjectArray& skinClu * * @return The union bounding box. */ -MAYAUSD_CORE_PUBLIC -MBoundingBox calcBBoxOfMeshes(const MObjectArray& meshes); +MAYAUSD_CORE_PUBLIC MBoundingBox calcBBoxOfMeshes(const MObjectArray& meshes); /// Helper method for getting Maya mesh normals as a VtVec3fArray. MAYAUSD_CORE_PUBLIC diff --git a/lib/usd/translators/meshWriterBlendShapes.cpp b/lib/usd/translators/meshWriterBlendShapes.cpp index 65aa04eb72..b534de49e7 100644 --- a/lib/usd/translators/meshWriterBlendShapes.cpp +++ b/lib/usd/translators/meshWriterBlendShapes.cpp @@ -666,16 +666,9 @@ MObject PxrUsdTranslators_MeshWriter::writeBlendShapeData(UsdGeomMesh& primSchem MString curTargetLongNameMStr; if (!targetMesh.isNull()) { MFnDagNode dagNode(targetMesh); - MString nodeName; - if (dagNode.parentCount() > 0) { - MFnDagNode parentDagNode(dagNode.parent(0)); - curTargetNameMStr - = UsdMayaUtil::GetUniqueNameOfDagNode(parentDagNode.object()); - curTargetLongNameMStr = curTargetNameMStr; - } else { - curTargetNameMStr = UsdMayaUtil::GetUniqueNameOfDagNode(targetMesh); - curTargetLongNameMStr = curTargetNameMStr; - } + curTargetNameMStr = UsdMayaUtil::GetUniqueNameOfDagNode(targetMesh); + curTargetLongNameMStr = curTargetNameMStr; + // NOTE: (yliangsiew) Because UsdSkelBlendShape does not // support animated targets (the `normalOffsets` and // `offsets` attributes are defined as uniforms), we cannot diff --git a/test/lib/usd/translators/testUsdExportBlendshapes.py b/test/lib/usd/translators/testUsdExportBlendshapes.py index 8b4ee90c4d..22fa2e313b 100644 --- a/test/lib/usd/translators/testUsdExportBlendshapes.py +++ b/test/lib/usd/translators/testUsdExportBlendshapes.py @@ -58,7 +58,7 @@ def testBlendShapesExport(self): cmds.mayaUSDExport(f=temp_file, v=True, sl=True, ebs=True, skl="auto") stage = Usd.Stage.Open(temp_file) - prim = stage.GetPrimAtPath("/root/base/blend") + prim = stage.GetPrimAtPath("/root/base/blendShape") offsets = prim.GetAttribute("offsets").Get() for i, coords in enumerate(offsets): @@ -68,7 +68,7 @@ def testBlendShapesExport(self): """ Sample BlendShape prim: - def BlendShape "blend" + def BlendShape "blendShape" { uniform vector3f[] normalOffsets = [(0, 0, 0), (0, 0, 0), (0, 0, 0)] uniform vector3f[] offsets = [(0, -0.25, 0), (0, -0.25, 0), (0, 0.25, 0)] diff --git a/test/lib/usd/translators/testUsdImportBlendShapes.py b/test/lib/usd/translators/testUsdImportBlendShapes.py index 016e645164..a17dccc93b 100644 --- a/test/lib/usd/translators/testUsdImportBlendShapes.py +++ b/test/lib/usd/translators/testUsdImportBlendShapes.py @@ -66,28 +66,28 @@ def test_BlendShapesImport(self): skinningQuery = skelCache.GetSkinningQuery(meshPrim) self.assertTrue(skinningQuery) - self.assertEqual(cmds.nodeType("blendShape1"), "blendShape") + self.assertEqual(cmds.nodeType("b1_Deformer"), "blendShape") regularShape = sorted( cmds.listConnections( - "blendShape1.inputTarget[0].inputTargetGroup[0].inputTargetItem[6000].inputGeomTarget", + "b1_Deformer.inputTarget[0].inputTargetGroup[0].inputTargetItem[6000].inputGeomTarget", destination=False, source=True, plugs=True)) self.assertEqual(regularShape, ['Box0002.worldMesh']) inBetween = sorted( cmds.listConnections( - "blendShape1.inputTarget[0].inputTargetGroup[0].inputTargetItem[4000].inputGeomTarget", + "b1_Deformer.inputTarget[0].inputTargetGroup[0].inputTargetItem[4000].inputGeomTarget", destination=False, source=True, plugs=True)) self.assertEqual(inBetween, ['IBT_1.worldMesh']) cmds.currentTime(0) - self.assertEqual(sorted(cmds.getAttr("blendShape1.weight")[0]), [-1.0]) + self.assertEqual(sorted(cmds.getAttr("b1_Deformer.weight")[0]), [-1.0]) cmds.currentTime(3) - self.assertEqual(sorted(cmds.getAttr("blendShape1.weight")[0]), [-0.14404296875]) + self.assertEqual(sorted(cmds.getAttr("b1_Deformer.weight")[0]), [-0.14404296875]) cmds.currentTime(5) - self.assertEqual(sorted(cmds.getAttr("blendShape1.weight")[0]), [0.13427734375]) + self.assertEqual(sorted(cmds.getAttr("b1_Deformer.weight")[0]), [0.13427734375]) cmds.currentTime(8) - self.assertEqual(sorted(cmds.getAttr("blendShape1.weight")[0]), [1.0]) + self.assertEqual(sorted(cmds.getAttr("b1_Deformer.weight")[0]), [1.0]) if __name__ == '__main__':