Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAYA-113077: componentTag IO to files #1755

Merged
merged 11 commits into from
Oct 27, 2021
70 changes: 70 additions & 0 deletions lib/mayaUsd/fileio/utils/meshReadUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,18 @@
#include <pxr/base/tf/token.h>
#include <pxr/base/vt/array.h>
#include <pxr/usd/usdGeom/mesh.h>
#include <pxr/usd/usdGeom/subset.h>
#include <pxr/usd/usdGeom/tokens.h>
#include <pxr/usd/usdUtils/pipeline.h>

#include <maya/MFloatVector.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MFnBlendShapeDeformer.h>
#include <maya/MFnComponentListData.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnPartition.h>
#include <maya/MFnSet.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MGlobal.h>
#include <maya/MIntArray.h>
#include <maya/MItMeshEdge.h>
Expand Down Expand Up @@ -882,4 +885,71 @@ MStatus UsdMayaMeshReadUtils::assignSubDivTagsToMesh(
return MS::kSuccess;
}

MStatus UsdMayaMeshReadUtils::createComponentTags(const UsdGeomMesh& mesh, const MObject& meshObj)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why to make this method available in older versions of Maya?

{
if (meshObj.apiType() != MFn::kMesh) {
return MS::kFailure;
}

MStatus status { MS::kSuccess };

#if MAYA_API_VERSION >= 20220000

MFnDependencyNode depNodeFn;
depNodeFn.setObject(meshObj);
MPlug ctPlug = depNodeFn.findPlug("componentTags", &status);
CHECK_MSTATUS_AND_RETURN_IT(status);

MObject ctAttr = depNodeFn.attribute("componentTags");
MObject ctNameAttr = depNodeFn.attribute("componentTagName");
MObject ctContentsAttr = depNodeFn.attribute("componentTagContents");

MPlug ctName(meshObj, ctNameAttr);
MPlug ctContent(meshObj, ctContentsAttr);

// Find all the prims defining componentTags
TfToken componentTagFamilyName("componentTag");
unsigned int idx = 0;
std::vector<UsdGeomSubset> subsets
= UsdGeomSubset::GetGeomSubsets(mesh, UsdGeomTokens->face, componentTagFamilyName);
for (auto& ss : subsets) {
// Get the tagName out of the subset
MString tagName(ss.GetPrim().GetName().GetText());

// Get the indices out of the subset
VtIntArray faceIndices;
UsdAttribute indicesAttribute = ss.GetIndicesAttr();
indicesAttribute.Get(&faceIndices);

MFnSingleIndexedComponent compFn;
MObject faceComp = compFn.create(MFn::kMeshPolygonComponent, &status);
if (!status) {
TF_RUNTIME_ERROR("Failed to create face component.");
return status;
}

MIntArray mFaces;
TF_FOR_ALL(fIdxIt, faceIndices) { mFaces.append(*fIdxIt); }
compFn.addElements(mFaces);

MFnComponentListData componentListFn;
MObject componentList = componentListFn.create();
status = componentListFn.add(faceComp);
CHECK_MSTATUS_AND_RETURN_IT(status);

// Set the attribute values
ctName.selectAncestorLogicalIndex(idx, ctAttr);
ctContent.selectAncestorLogicalIndex(idx, ctAttr);

ctName.setValue(tagName);
ctContent.setValue(componentList);

idx++;
}

#endif

return status;
}

PXR_NAMESPACE_CLOSE_SCOPE
3 changes: 3 additions & 0 deletions lib/mayaUsd/fileio/utils/meshReadUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ void assignInvisibleFaces(const UsdGeomMesh& mesh, const MObject& meshObj);
MAYAUSD_CORE_PUBLIC
MStatus assignSubDivTagsToMesh(const UsdGeomMesh&, MObject&, MFnMesh&);

MAYAUSD_CORE_PUBLIC
MStatus createComponentTags(const UsdGeomMesh& mesh, const MObject& meshObj);

} // namespace UsdMayaMeshReadUtils

PXR_NAMESPACE_CLOSE_SCOPE
Expand Down
52 changes: 52 additions & 0 deletions lib/mayaUsd/fileio/utils/meshWriteUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,16 @@
#include <pxr/usd/usdGeom/mesh.h>
#include <pxr/usd/usdGeom/pointBased.h>
#include <pxr/usd/usdGeom/primvar.h>
#include <pxr/usd/usdGeom/subset.h>
#include <pxr/usd/usdGeom/tokens.h>
#include <pxr/usd/usdUtils/pipeline.h>

#include <maya/MBoundingBox.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnGeometryData.h>
#include <maya/MFnMesh.h>
#include <maya/MFnSet.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MGlobal.h>
#include <maya/MIntArray.h>
#include <maya/MItDependencyGraph.h>
Expand Down Expand Up @@ -1369,4 +1372,53 @@ bool UsdMayaMeshWriteUtils::getMeshColorSetData(
return true;
}

MStatus UsdMayaMeshWriteUtils::exportComponentTags(UsdGeomMesh& primSchema, MObject obj)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why to even make this method available for older versions of Maya?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to change Hans code as little as possible, but I can move the #ifdef out and #ifdef atthe caller site too instead of having a do-nothing function in older versions of Maya.

{
MStatus status { MS::kSuccess };

#if MAYA_API_VERSION >= 20220000

MFnDependencyNode dNode(obj, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);

const MFnDependencyNode depNodeFn(obj, &status);
MPlug outShp = depNodeFn.findPlug("outMesh", &status);
CHECK_MSTATUS_AND_RETURN_IT(status);

MDataHandle geomDataHandle = outShp.asMDataHandle();
MObject geomObj = geomDataHandle.data();
if (geomObj.hasFn(MFn::kGeometryData)) {
TfToken componentTagFamilyName("componentTag");
MFnGeometryData fnGeomData(geomObj);
MStringArray keys;
status = fnGeomData.componentTags(keys);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This status doesn't seem to be checked.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and it is not the only one, there are others a bit below. In all cases, the code seems to rely on the returned data (for example the set of keys) to be empty. Of course, that could cause silent failures. I'll add more early returns.

for (unsigned int i = 0; i < keys.length(); ++i) {
MFnGeometryData::ComponentTagCategory ctg
= fnGeomData.componentTagCategory(keys[i], &status);
if (ctg == MFnGeometryData::ComponentTagCategory::kFaces) {
MObject contents = fnGeomData.componentTagContents(keys[i], &status);
if (contents.hasFn(MFn::kSingleIndexedComponent)) {
MFnSingleIndexedComponent fnSingleIndexedComponent(contents, &status);
MIntArray curIndices;
status = fnSingleIndexedComponent.getElements(curIndices);
VtIntArray indices;
indices.reserve(curIndices.length());
for (unsigned int j = 0; j < curIndices.length(); ++j)
indices.push_back(curIndices[j]);
UsdGeomSubset ss = UsdGeomSubset::CreateGeomSubset(
primSchema,
TfToken(keys[i].asChar()),
UsdGeomTokens->face,
indices,
componentTagFamilyName);
}
}
}
}

#endif

return status;
}

PXR_NAMESPACE_CLOSE_SCOPE
3 changes: 3 additions & 0 deletions lib/mayaUsd/fileio/utils/meshWriteUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ bool getMeshColorSetData(
MFnMesh::MColorRepresentation* colorSetRep,
bool* clamped);

MAYAUSD_CORE_PUBLIC
MStatus exportComponentTags(UsdGeomMesh& primSchema, MObject obj);

} // namespace UsdMayaMeshWriteUtils

PXR_NAMESPACE_CLOSE_SCOPE
Expand Down
3 changes: 3 additions & 0 deletions lib/usd/translators/meshReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ bool MayaUsdPrimReaderMesh::Read(UsdMayaPrimReaderContext& context)
// assign invisible faces
UsdMayaMeshReadUtils::assignInvisibleFaces(mesh, meshRead.meshObject());

// Read componentTags
UsdMayaMeshReadUtils::createComponentTags(mesh, meshRead.meshObject());

// assign material
assignMaterial(mesh, _GetArgs(), meshRead.meshObject(), &context);

Expand Down
4 changes: 4 additions & 0 deletions lib/usd/translators/meshWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,10 @@ bool PxrUsdTranslators_MeshWriter::writeMeshAttrs(
_GetSparseValueWriter());
}

if (true /*exportArgs.exportComponentTags*/) {
pierrebai-adsk marked this conversation as resolved.
Show resolved Hide resolved
UsdMayaMeshWriteUtils::exportComponentTags(primSchema, GetMayaObject());
}

return true;
}

Expand Down
3 changes: 3 additions & 0 deletions plugin/adsk/plugin/exportTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ MStatus UsdMayaExportTranslator::writer(
const MString& optionsString,
MPxFileTranslator::FileAccessMode mode)
{
MStatus s = MPxFileTranslator::writer(file, optionsString, mode);
pierrebai-adsk marked this conversation as resolved.
Show resolved Hide resolved
if (s != MS::kFailure)
return s;

// If we are in neither of these modes then there won't be anything to do
if (mode != MPxFileTranslator::kExportActiveAccessMode
Expand Down
19 changes: 10 additions & 9 deletions test/lib/usd/translators/testUsdExportBlendshapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def BlendShape "blendShape"
prim = stage.GetPrimAtPath("/basic_cube_4_blendshapes_no_anim/base")
blendShapes = prim.GetChildren()
for bs in blendShapes:
self.assertEqual(bs.GetTypeName(), 'BlendShape')
self.assertIn(bs.GetTypeName(), ['BlendShape', 'GeomSubset'])

# NOTE: (yliangsiew) Test exporting empty blendshape targets.
om.MFileIO.open(self.scene_path, None, True)
Expand All @@ -102,14 +102,15 @@ def BlendShape "blendShape"
prim = stage.GetPrimAtPath("/cube_empty_blendshape_targets/base")
blendShapes = prim.GetChildren()
for bs in blendShapes:
self.assertEqual(bs.GetTypeName(), 'BlendShape')
skelBS = UsdSkel.BlendShape(bs)
normalsAttr = skelBS.GetNormalOffsetsAttr()
offsetsAttr = skelBS.GetOffsetsAttr()
normals = normalsAttr.Get()
offsets = offsetsAttr.Get()
self.assertEqual(len(normals), 0)
self.assertEqual(len(offsets), 0)
self.assertIn(bs.GetTypeName(), ['BlendShape', 'GeomSubset'])
if bs.GetTypeName() == 'BlendShape':
skelBS = UsdSkel.BlendShape(bs)
normalsAttr = skelBS.GetNormalOffsetsAttr()
offsetsAttr = skelBS.GetOffsetsAttr()
normals = normalsAttr.Get()
offsets = offsetsAttr.Get()
self.assertEqual(len(normals), 0)
self.assertEqual(len(offsets), 0)

# NOTE: (yliangsiew) Test duplicate shape names across multiple meshes.
cmds.select("basic_skinned_cube_duplicate_targets_names_across_meshes", r=True)
Expand Down