From be2e32f048db14f62a53ed91e18a297fe07edacd Mon Sep 17 00:00:00 2001 From: JGamache-autodesk Date: Thu, 5 Nov 2020 17:26:56 -0500 Subject: [PATCH 1/4] MAYA-106486 Import UV set mappings Applies uvChooser nodes whenever the selected UV is not the default UV. Will merge specialized materials that were created on export solely to handle UV set names mismatches. --- .../shading/shadingModeExporterContext.cpp | 2 +- .../fileio/translators/translatorMaterial.cpp | 157 ++++++- lib/usd/translators/meshReader.cpp | 7 +- .../shading/usdUVTextureReader.cpp | 13 + test/lib/usd/translators/CMakeLists.txt | 1 + .../UsdImportUVSetMappings.usda | 424 ++++++++++++++++++ .../UsdImportUVSetMappingsTest/lines.png | Bin 0 -> 197 bytes .../translators/testUsdImportUVSetMappings.py | 94 ++++ 8 files changed, 687 insertions(+), 11 deletions(-) create mode 100644 test/lib/usd/translators/UsdImportUVSetMappingsTest/UsdImportUVSetMappings.usda create mode 100644 test/lib/usd/translators/UsdImportUVSetMappingsTest/lines.png create mode 100644 test/lib/usd/translators/testUsdImportUVSetMappings.py diff --git a/lib/mayaUsd/fileio/shading/shadingModeExporterContext.cpp b/lib/mayaUsd/fileio/shading/shadingModeExporterContext.cpp index 2f16724c10..0f0828d6a9 100644 --- a/lib/mayaUsd/fileio/shading/shadingModeExporterContext.cpp +++ b/lib/mayaUsd/fileio/shading/shadingModeExporterContext.cpp @@ -527,7 +527,7 @@ class _UVMappingManager = _material.GetPrim().GetPath().GetParentPath().AppendChild(TfToken(newName.c_str())); UsdShadeMaterial newMaterial = UsdShadeMaterial::Define(_material.GetPrim().GetStage(), newPath); - newMaterial.GetPrim().GetSpecializes().AddSpecialize(_material.GetPrim().GetPath()); + newMaterial.SetBaseMaterial(_material); TfTokenVector::const_iterator itNode = _nodesWithUVInput.cbegin(); TfTokenVector::const_iterator itName = uvNames.cbegin(); diff --git a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp index c185c82611..47f6908199 100644 --- a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp +++ b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp @@ -27,7 +27,12 @@ #include #include #include +#include +#include +#include #include +#include +#include #include #include #include @@ -38,8 +43,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -51,6 +58,48 @@ PXR_NAMESPACE_OPEN_SCOPE +TF_DEFINE_PRIVATE_TOKENS(_tokens, (inputs)(varname)); + +namespace { +// We want to know if this material is a specialization that was created to handle UV mappings on +// export. For details, see the _UVMappingManager class in ..\shading\shadingModeExporterContext.cpp +// +// If the root layer contains anything that is not a varname input, we do not consider it a +// mergeable material. +bool _IsMergeableMaterial(const UsdShadeMaterial& shadeMaterial) +{ + if (!shadeMaterial || !shadeMaterial.HasBaseMaterial()) { + return false; + } + const PcpPrimIndex& primIndex = shadeMaterial.GetPrim().GetPrimIndex(); + PcpNodeRef primRoot = primIndex.GetRootNode(); + SdfPath primPath = primIndex.GetPath(); + const SdfLayerHandle& layer = primRoot.GetLayerStack()->GetLayerTree()->GetLayer(); + + bool retVal = true; + auto testFunction = [&](const SdfPath& path) { + // If we traverse anything that is not a varname specialization, we return false. + if (path == primPath) { + return; + } + if (path.GetParentPath() != primPath || !path.IsPrimPropertyPath()) { + retVal = false; + return; + } + std::vector splitName = SdfPath::TokenizeIdentifier(path.GetName()); + // We allow only ["inputs", "XXX", "varname"] + if (splitName.size() != 3 || splitName[0] != _tokens->inputs.GetString() + || splitName[2] != _tokens->varname.GetString()) { + retVal = false; + } + }; + + layer->Traverse(primPath, testFunction); + + return retVal; +} +} // namespace + /* static */ MObject UsdMayaTranslatorMaterial::Read( const UsdMayaJobImportArgs& jobArguments, @@ -70,6 +119,11 @@ MObject UsdMayaTranslatorMaterial::Read( return shadingEngine; } + if (_IsMergeableMaterial(shadeMaterial)) { + // Use the base material instead + return Read(jobArguments, shadeMaterial.GetBaseMaterial(), boundPrim, context); + } + UsdMayaJobImportArgs localArguments = jobArguments; for (const auto& shadingMode : jobArguments.shadingModes) { if (shadingMode.mode == UsdMayaShadingModeTokens->none) { @@ -89,10 +143,87 @@ MObject UsdMayaTranslatorMaterial::Read( return shadingEngine; } +namespace { +using _UVBindings = std::map; +} + +static _UVBindings +_GetUVBindingsFromMaterial(const UsdShadeMaterial& material, UsdMayaPrimReaderContext* context) +{ + _UVBindings retVal; + + if (!material || !context) { + return retVal; + } + const bool isMergeable = _IsMergeableMaterial(material); + // Find out the nodes requiring mapping. This code has deep knowledge of how the mappings are + // exported. See the _UVMappingManager class in ..\shading\shadingModeExporterContext.cpp for + // details. + for (const UsdShadeInput& input : material.GetInputs()) { + const UsdAttribute& usdAttr = input.GetAttr(); + std::vector splitName = usdAttr.SplitName(); + if (splitName.size() != 3 || splitName[2] != _tokens->varname.GetString()) { + continue; + } + VtValue val; + usdAttr.Get(&val); + if (!val.IsHolding()) { + continue; + } + SdfPath nodePath = isMergeable + ? material.GetBaseMaterial().GetPath().AppendChild(TfToken(splitName[1])) + : material.GetPath().AppendChild(TfToken(splitName[1])); + MObject mayaNode = context->GetMayaNode(nodePath, false); + MStatus status; + MFnDependencyNode depFn(mayaNode, &status); + if (!status) { + continue; + } + retVal[val.UncheckedGet()] = TfToken(depFn.name().asChar()); + } + + return retVal; +} + +static void _BindUVs(const MDagPath& shapeDagPath, const _UVBindings& uvBindings) +{ + if (uvBindings.empty()) { + return; + } + + MStatus status; + MFnMesh meshFn(shapeDagPath.node(), &status); + if (!status) { + return; + } + + MStringArray uvSets; + meshFn.getUVSetNames(uvSets); + + // We explicitly skip uvSet[0] since it is the default in Maya and does not require explicit + // linking: + for (unsigned int uvSetIndex = 1; uvSetIndex < uvSets.length(); uvSetIndex++) { + TfToken uvSetName(uvSets[uvSetIndex].asChar()); + _UVBindings::const_iterator iter = uvBindings.find(uvSetName); + if (iter == uvBindings.cend()) { + continue; + } + MString uvLinkCommand("uvLink -make -uvs \""); + uvLinkCommand += shapeDagPath.fullPathName(); + uvLinkCommand += ".uvSet["; + uvLinkCommand += uvSetIndex; + uvLinkCommand += "].uvSetName\" -t \""; + uvLinkCommand += iter->second.GetText(); // texture name + uvLinkCommand += "\";"; + status = MGlobal::executeCommand(uvLinkCommand); + } +} + static bool _AssignMaterialFaceSet( - const MObject& shadingEngine, - const MDagPath& shapeDagPath, - const VtIntArray& faceIndices) + const MObject& shadingEngine, + const MDagPath& shapeDagPath, + const VtIntArray& faceIndices, + const _UVBindings& faceUVBindings) { MStatus status; @@ -117,6 +248,7 @@ static bool _AssignMaterialFaceSet( "Could not add component to shadingEngine %s.", seFnSet.name().asChar()); return false; } + _BindUVs(shapeDagPath, faceUVBindings); } return true; @@ -141,14 +273,18 @@ bool UsdMayaTranslatorMaterial::AssignMaterial( MStatus status; const UsdShadeMaterialBindingAPI bindingAPI(primSchema.GetPrim()); - MObject shadingEngine = UsdMayaTranslatorMaterial::Read( - jobArguments, bindingAPI.ComputeBoundMaterial(), primSchema, context); + UsdShadeMaterial meshMaterial = bindingAPI.ComputeBoundMaterial(); + _UVBindings uvBindings; + MObject shadingEngine + = UsdMayaTranslatorMaterial::Read(jobArguments, meshMaterial, primSchema, context); if (shadingEngine.isNull()) { status = UsdMayaUtil::GetMObjectByName("initialShadingGroup", shadingEngine); if (status != MS::kSuccess) { return false; } + } else { + uvBindings = _GetUVBindingsFromMaterial(meshMaterial, context); } // If the gprim does not have a material faceSet which represents per-face @@ -164,6 +300,7 @@ bool UsdMayaTranslatorMaterial::AssignMaterial( TF_RUNTIME_ERROR( "Could not add shadingEngine for '%s'.", shapeDagPath.fullPathName().asChar()); } + _BindUVs(shapeDagPath, uvBindings); } return true; @@ -197,7 +334,8 @@ bool UsdMayaTranslatorMaterial::AssignMaterial( VtIntArray unassignedIndices = UsdGeomSubset::GetUnassignedIndices(faceSubsets, faceCount); - if (!_AssignMaterialFaceSet(shadingEngine, shapeDagPath, unassignedIndices)) { + if (!_AssignMaterialFaceSet( + shadingEngine, shapeDagPath, unassignedIndices, uvBindings)) { return false; } } @@ -208,12 +346,16 @@ bool UsdMayaTranslatorMaterial::AssignMaterial( if (boundMaterial) { MObject faceSubsetShadingEngine = UsdMayaTranslatorMaterial::Read( jobArguments, boundMaterial, UsdGeomGprim(), context); + + _UVBindings faceUVBindings; if (faceSubsetShadingEngine.isNull()) { status = UsdMayaUtil::GetMObjectByName( "initialShadingGroup", faceSubsetShadingEngine); if (status != MS::kSuccess) { return false; } + } else { + faceUVBindings = _GetUVBindingsFromMaterial(boundMaterial, context); } // Only transfer the first timeSample or default indices, if @@ -221,7 +363,8 @@ bool UsdMayaTranslatorMaterial::AssignMaterial( VtIntArray indices; subset.GetIndicesAttr().Get(&indices, UsdTimeCode::EarliestTime()); - if (!_AssignMaterialFaceSet(faceSubsetShadingEngine, shapeDagPath, indices)) { + if (!_AssignMaterialFaceSet( + faceSubsetShadingEngine, shapeDagPath, indices, faceUVBindings)) { return false; } } diff --git a/lib/usd/translators/meshReader.cpp b/lib/usd/translators/meshReader.cpp index 7547a0cbcf..c04d985e05 100644 --- a/lib/usd/translators/meshReader.cpp +++ b/lib/usd/translators/meshReader.cpp @@ -127,12 +127,13 @@ bool MayaUsdPrimReaderMesh::Read(UsdMayaPrimReaderContext* context) } } - // assign material - assignMaterial(mesh, _GetArgs(), meshRead.meshObject(), context); - // assign primvars to mesh UsdMayaMeshReadUtils::assignPrimvarsToMesh( mesh, meshRead.meshObject(), _GetArgs().GetExcludePrimvarNames()); + + // assign material + assignMaterial(mesh, _GetArgs(), meshRead.meshObject(), context); + // assign invisible faces UsdMayaMeshReadUtils::assignInvisibleFaces(mesh, meshRead.meshObject()); diff --git a/lib/usd/translators/shading/usdUVTextureReader.cpp b/lib/usd/translators/shading/usdUVTextureReader.cpp index 50f4a281c9..21c213a566 100644 --- a/lib/usd/translators/shading/usdUVTextureReader.cpp +++ b/lib/usd/translators/shading/usdUVTextureReader.cpp @@ -67,6 +67,9 @@ TF_DEFINE_PRIVATE_TOKENS( // UsdUVTexture Input Names (bias)(fallback)(scale)(wrapS)(wrapT) + // uv connections: + (outUvFilterSize)(uvFilterSize)(outUV)(uvCoord) + // Values for wrapS and wrapT (black)(repeat) @@ -137,6 +140,16 @@ bool PxrMayaUsdUVTexture_Reader::Read(UsdMayaPrimReaderContext* context) } // Connect manually (fileTexturePlacementConnect is not available in batch): + { + MPlug uvPlug = uvDepFn.findPlug(_tokens->outUV.GetText(), true, &status); + MPlug filePlug = depFn.findPlug(_tokens->uvCoord.GetText(), true, &status); + UsdMayaUtil::Connect(uvPlug, filePlug, false); + } + { + MPlug uvPlug = uvDepFn.findPlug(_tokens->outUvFilterSize.GetText(), true, &status); + MPlug filePlug = depFn.findPlug(_tokens->uvFilterSize.GetText(), true, &status); + UsdMayaUtil::Connect(uvPlug, filePlug, false); + } MString connectCmd; for (const TfToken& uvName : _Place2dTextureConnections) { MPlug uvPlug = uvDepFn.findPlug(uvName.GetText(), true, &status); diff --git a/test/lib/usd/translators/CMakeLists.txt b/test/lib/usd/translators/CMakeLists.txt index 08e8064550..e0640e4bd7 100644 --- a/test/lib/usd/translators/CMakeLists.txt +++ b/test/lib/usd/translators/CMakeLists.txt @@ -56,6 +56,7 @@ set(TEST_SCRIPT_FILES testUsdImportSessionLayer.py testUsdImportShadingModeDisplayColor.py testUsdImportShadingModePxrRis.py + testUsdImportUVSetMappings.py testUsdExportImportRoundtripPreviewSurface.py testUsdExportImportUDIM.py testUsdImportSkeleton.py diff --git a/test/lib/usd/translators/UsdImportUVSetMappingsTest/UsdImportUVSetMappings.usda b/test/lib/usd/translators/UsdImportUVSetMappingsTest/UsdImportUVSetMappings.usda new file mode 100644 index 0000000000..c98ebe2738 --- /dev/null +++ b/test/lib/usd/translators/UsdImportUVSetMappingsTest/UsdImportUVSetMappings.usda @@ -0,0 +1,424 @@ +#usda 1.0 +( + defaultPrim = "pPlane1" + metersPerUnit = 0.01 + upAxis = "Y" +) + +def Mesh "pPlane1" ( + prepend apiSchemas = ["MaterialBindingAPI"] + kind = "component" +) +{ + uniform bool doubleSided = 1 + float3[] extent = [(-0.5, 0, -0.5), (0.5, 0, 0.5)] + int[] faceVertexCounts = [4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 4, 3, 1, 2, 5, 4, 3, 4, 7, 6, 4, 5, 8, 7] + rel material:binding = + point3f[] points = [(-0.5, 0, 0.5), (0, 0, 0.5), (0.5, 0, 0.5), (-0.5, 0, 0), (0, 0, 0), (0.5, 0, 0), (-0.5, 0, -0.5), (0, 0, -0.5), (0.5, 0, -0.5)] + texCoord2f[] primvars:st = [(0, 0), (0.5, 0), (0.5, 0.5), (0, 0.5), (1, 0), (1, 0.5), (0.5, 1), (0, 1), (1, 1)] ( + interpolation = "vertex" + ) + texCoord2f[] primvars:st0 = [(0.633502, 0.0017636716), (0.8158692, 0.31763285), (0.5, 0.5), (0.31763285, 0.18413082), (0.9982363, 0.633502), (0.68236715, 0.8158692), (0.18413082, 0.68236715), (0.0017636716, 0.366498), (0.366498, 0.9982363)] ( + interpolation = "vertex" + ) + int[] primvars:st0:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + texCoord2f[] primvars:st1 = [(0.0017636716, 0.633502), (0.18413082, 0.31763285), (0.5, 0.5), (0.31763285, 0.8158692), (0.366498, 0.0017636716), (0.68236715, 0.18413082), (0.8158692, 0.68236715), (0.633502, 0.9982363), (0.9982363, 0.366498)] ( + interpolation = "vertex" + ) + int[] primvars:st1:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + int[] primvars:st:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + float3 xformOp:rotateXYZ = (90, 0, 0) + uniform token[] xformOpOrder = ["xformOp:rotateXYZ"] +} + +def Mesh "pPlane2" ( + prepend apiSchemas = ["MaterialBindingAPI"] + kind = "component" +) +{ + uniform bool doubleSided = 1 + float3[] extent = [(-0.5, -1.110223e-16, -0.5), (0.5, 1.110223e-16, 0.5)] + int[] faceVertexCounts = [4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 4, 3, 1, 2, 5, 4, 3, 4, 7, 6, 4, 5, 8, 7] + point3f[] points = [(-0.5, -1.110223e-16, 0.5), (0, -1.110223e-16, 0.5), (0.5, -1.110223e-16, 0.5), (-0.5, 0, 0), (0, 0, 0), (0.5, 0, 0), (-0.5, 1.110223e-16, -0.5), (0, 1.110223e-16, -0.5), (0.5, 1.110223e-16, -0.5)] + texCoord2f[] primvars:st = [(0, 0), (0.5, 0), (0.5, 0.5), (0, 0.5), (1, 0), (1, 0.5), (0.5, 1), (0, 1), (1, 1)] ( + interpolation = "vertex" + ) + texCoord2f[] primvars:st0 = [(0.633502, 0.0017636716), (0.8158692, 0.31763285), (0.5, 0.5), (0.31763285, 0.18413082), (0.9982363, 0.633502), (0.68236715, 0.8158692), (0.18413082, 0.68236715), (0.0017636716, 0.366498), (0.366498, 0.9982363)] ( + interpolation = "vertex" + ) + int[] primvars:st0:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + texCoord2f[] primvars:st1 = [(0.0017636716, 0.633502), (0.18413082, 0.31763285), (0.5, 0.5), (0.31763285, 0.8158692), (0.366498, 0.0017636716), (0.68236715, 0.18413082), (0.8158692, 0.68236715), (0.633502, 0.9982363), (0.9982363, 0.366498)] ( + interpolation = "vertex" + ) + int[] primvars:st1:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + int[] primvars:st:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + uniform token subsetFamily:materialBind:familyType = "partition" + float3 xformOp:rotateXYZ = (90, 0, 0) + double3 xformOp:translate = (1.2, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + + def GeomSubset "blinn1SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [1] + rel material:binding = + } + + def GeomSubset "blinn2SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [2] + rel material:binding = + } + + def GeomSubset "blinn3SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [3] + rel material:binding = + } + + def GeomSubset "blinn4SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [0] + rel material:binding = + } +} + +def Mesh "pPlane3" ( + prepend apiSchemas = ["MaterialBindingAPI"] + kind = "component" +) +{ + uniform bool doubleSided = 1 + float3[] extent = [(-0.5, -1.110223e-16, -0.5), (0.5, 1.110223e-16, 0.5)] + int[] faceVertexCounts = [4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 4, 3, 1, 2, 5, 4, 3, 4, 7, 6, 4, 5, 8, 7] + rel material:binding = + point3f[] points = [(-0.5, -1.110223e-16, 0.5), (0, -1.110223e-16, 0.5), (0.5, -1.110223e-16, 0.5), (-0.5, 0, 0), (0, 0, 0), (0.5, 0, 0), (-0.5, 1.110223e-16, -0.5), (0, 1.110223e-16, -0.5), (0.5, 1.110223e-16, -0.5)] + texCoord2f[] primvars:map1 = [(0, 0), (0.5, 0), (0.5, 0.5), (0, 0.5), (1, 0), (1, 0.5), (0.5, 1), (0, 1), (1, 1)] ( + interpolation = "vertex" + ) + int[] primvars:map1:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + texCoord2f[] primvars:uvSet1 = [(0.633502, 0.0017636716), (0.8158692, 0.31763285), (0.5, 0.5), (0.31763285, 0.18413082), (0.9982363, 0.633502), (0.68236715, 0.8158692), (0.18413082, 0.68236715), (0.0017636716, 0.366498), (0.366498, 0.9982363)] ( + interpolation = "vertex" + ) + int[] primvars:uvSet1:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + texCoord2f[] primvars:uvSet2 = [(0.0017636716, 0.633502), (0.18413082, 0.31763285), (0.5, 0.5), (0.31763285, 0.8158692), (0.366498, 0.0017636716), (0.68236715, 0.18413082), (0.8158692, 0.68236715), (0.633502, 0.9982363), (0.9982363, 0.366498)] ( + interpolation = "vertex" + ) + int[] primvars:uvSet2:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + float3 xformOp:rotateXYZ = (90, 0, 0) + double3 xformOp:translate = (0, 1.2, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] +} + +def Mesh "pPlane4" ( + prepend apiSchemas = ["MaterialBindingAPI"] + kind = "component" +) +{ + uniform bool doubleSided = 1 + float3[] extent = [(-0.5, -1.110223e-16, -0.5), (0.5, 1.110223e-16, 0.5)] + int[] faceVertexCounts = [4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 4, 3, 1, 2, 5, 4, 3, 4, 7, 6, 4, 5, 8, 7] + point3f[] points = [(-0.5, -1.110223e-16, 0.5), (0, -1.110223e-16, 0.5), (0.5, -1.110223e-16, 0.5), (-0.5, 0, 0), (0, 0, 0), (0.5, 0, 0), (-0.5, 1.110223e-16, -0.5), (0, 1.110223e-16, -0.5), (0.5, 1.110223e-16, -0.5)] + texCoord2f[] primvars:map1 = [(0, 0), (0.5, 0), (0.5, 0.5), (0, 0.5), (1, 0), (1, 0.5), (0.5, 1), (0, 1), (1, 1)] ( + interpolation = "vertex" + ) + int[] primvars:map1:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + texCoord2f[] primvars:uvSet1 = [(0.633502, 0.0017636716), (0.8158692, 0.31763285), (0.5, 0.5), (0.31763285, 0.18413082), (0.9982363, 0.633502), (0.68236715, 0.8158692), (0.18413082, 0.68236715), (0.0017636716, 0.366498), (0.366498, 0.9982363)] ( + interpolation = "vertex" + ) + int[] primvars:uvSet1:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + texCoord2f[] primvars:uvSet2 = [(0.0017636716, 0.633502), (0.18413082, 0.31763285), (0.5, 0.5), (0.31763285, 0.8158692), (0.366498, 0.0017636716), (0.68236715, 0.18413082), (0.8158692, 0.68236715), (0.633502, 0.9982363), (0.9982363, 0.366498)] ( + interpolation = "vertex" + ) + int[] primvars:uvSet2:indices = [0, 1, 4, 3, 2, 5, 7, 6, 8] + uniform token subsetFamily:materialBind:familyType = "partition" + float3 xformOp:rotateXYZ = (90, 0, 0) + double3 xformOp:translate = (1.2, 1.2, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"] + + def GeomSubset "blinn1SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [1] + rel material:binding = + } + + def GeomSubset "blinn2SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [2] + rel material:binding = + } + + def GeomSubset "blinn3SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [3] + rel material:binding = + } + + def GeomSubset "blinn4SG" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform token elementType = "face" + uniform token familyName = "materialBind" + int[] indices = [0] + rel material:binding = + } +} + +def Material "blinn1SG" ( + kind = "assembly" +) +{ + token inputs:file1:varname = "map1" + token inputs:file2:varname = "uvSet1" + token inputs:file3:varname = "uvSet2" + token outputs:surface.connect = + + def Shader "blinn1" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor.connect = + color3f inputs:emissiveColor.connect = + normal3f inputs:normal = (1, 1, 1) + float inputs:roughness = 0.3 + color3f inputs:specularColor.connect = + int inputs:useSpecularWorkflow = 1 + token outputs:displacement + token outputs:surface + } + + def Shader "file1" + { + uniform token info:id = "UsdUVTexture" + float4 inputs:fallback = (0.5, 0.5, 0.5, 1) + asset inputs:file = @lines.png@ + float2 inputs:st.connect = + token inputs:wrapS = "repeat" + token inputs:wrapT = "repeat" + float3 outputs:rgb + + def Shader "TexCoordReader" + { + uniform token info:id = "UsdPrimvarReader_float2" + token inputs:varname.connect = + float2 outputs:result + } + } + + def Shader "file2" + { + uniform token info:id = "UsdUVTexture" + float4 inputs:fallback = (0.5, 0.5, 0.5, 1) + asset inputs:file = @lines.png@ + float2 inputs:st.connect = + token inputs:wrapS = "repeat" + token inputs:wrapT = "repeat" + float3 outputs:rgb + + def Shader "TexCoordReader" + { + uniform token info:id = "UsdPrimvarReader_float2" + token inputs:varname.connect = + float2 outputs:result + } + } + + def Shader "file3" + { + uniform token info:id = "UsdUVTexture" + float4 inputs:fallback = (0.5, 0.5, 0.5, 1) + asset inputs:file = @lines.png@ + float2 inputs:st.connect = + token inputs:wrapS = "repeat" + token inputs:wrapT = "repeat" + float3 outputs:rgb + + def Shader "TexCoordReader" + { + uniform token info:id = "UsdPrimvarReader_float2" + token inputs:varname.connect = + float2 outputs:result + } + } +} + +def Material "blinn1SG_st_st0_st1" ( + prepend specializes = +) +{ + token inputs:file1:varname = "st" + token inputs:file2:varname = "st0" + token inputs:file3:varname = "st1" +} + +def Material "blinn2SG" ( + kind = "assembly" +) +{ + token inputs:file4:varname = "map1" + token outputs:surface.connect = + + def Shader "blinn2" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor.connect = + normal3f inputs:normal = (1, 1, 1) + float inputs:roughness = 0.3 + color3f inputs:specularColor = (0.35, 0.35, 0.35) + int inputs:useSpecularWorkflow = 1 + token outputs:displacement + token outputs:surface + } + + def Shader "file4" + { + uniform token info:id = "UsdUVTexture" + float4 inputs:fallback = (0.5, 0.5, 0.5, 1) + asset inputs:file = @lines.png@ + float2 inputs:st.connect = + token inputs:wrapS = "repeat" + token inputs:wrapT = "repeat" + float3 outputs:rgb + + def Shader "TexCoordReader" + { + uniform token info:id = "UsdPrimvarReader_float2" + token inputs:varname.connect = + float2 outputs:result + } + } +} + +def Material "blinn2SG_st" ( + prepend specializes = +) +{ + token inputs:file4:varname = "st" +} + +def Material "blinn3SG" ( + kind = "assembly" +) +{ + token inputs:file5:varname = "st0" + token outputs:surface.connect = + + def Shader "blinn3" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor.connect = + normal3f inputs:normal = (1, 1, 1) + float inputs:roughness = 0.3 + color3f inputs:specularColor = (0.35, 0.35, 0.35) + int inputs:useSpecularWorkflow = 1 + token outputs:displacement + token outputs:surface + } + + def Shader "file5" + { + uniform token info:id = "UsdUVTexture" + float4 inputs:fallback = (0.5, 0.5, 0.5, 1) + asset inputs:file = @lines.png@ + float2 inputs:st.connect = + token inputs:wrapS = "repeat" + token inputs:wrapT = "repeat" + float3 outputs:rgb + + def Shader "TexCoordReader" + { + uniform token info:id = "UsdPrimvarReader_float2" + token inputs:varname.connect = + float2 outputs:result + } + } +} + +def Material "blinn3SG_uvSet1" ( + prepend specializes = +) +{ + token inputs:file5:varname = "uvSet1" + token not:mergeable:anymore = "becauseModified" +} + +def Material "blinn4SG" ( + kind = "assembly" +) +{ + token inputs:file6:varname = "st1" + token outputs:surface.connect = + + def Shader "blinn4" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor.connect = + normal3f inputs:normal = (1, 1, 1) + float inputs:roughness = 0.3 + color3f inputs:specularColor = (0.35, 0.35, 0.35) + int inputs:useSpecularWorkflow = 1 + token outputs:displacement + token outputs:surface + } + + def Shader "file6" + { + uniform token info:id = "UsdUVTexture" + float4 inputs:fallback = (0.5, 0.5, 0.5, 1) + asset inputs:file = @lines.png@ + float2 inputs:st.connect = + token inputs:wrapS = "repeat" + token inputs:wrapT = "repeat" + float3 outputs:rgb + + def Shader "TexCoordReader" + { + uniform token info:id = "UsdPrimvarReader_float2" + token inputs:varname.connect = + float2 outputs:result + } + } +} + +def Material "blinn4SG_uvSet2" ( + prepend specializes = +) +{ + token inputs:file6:varname = "uvSet2" + def Shader "BlocksMerging" + { + uniform token info:id = "UsdPrimvarReader_float2" + } +} + diff --git a/test/lib/usd/translators/UsdImportUVSetMappingsTest/lines.png b/test/lib/usd/translators/UsdImportUVSetMappingsTest/lines.png new file mode 100644 index 0000000000000000000000000000000000000000..662d7acb5d028ae1a6145501445a1302fdbe8c5f GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1SD0tpLGJM9#0p?kc@k8ZyItn81S%OaNF~L z>fm12mH;N}yZwRQq)I~OBN b?2lLh<0lru?xWV{13_Y*u6{1-oD!M<_#r@z literal 0 HcmV?d00001 diff --git a/test/lib/usd/translators/testUsdImportUVSetMappings.py b/test/lib/usd/translators/testUsdImportUVSetMappings.py new file mode 100644 index 0000000000..4f4e2d183c --- /dev/null +++ b/test/lib/usd/translators/testUsdImportUVSetMappings.py @@ -0,0 +1,94 @@ +#!/pxrpythonsubst +# +# Copyright 2020 Pixar +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from pxr import Usd +from pxr import UsdShade + +from maya import cmds +from maya import standalone + +import os +import unittest + +import fixturesUtils + + +class testUsdImportUVSetMappings(unittest.TestCase): + + @classmethod + def setUpClass(cls): + input_path = fixturesUtils.setUpClass(__file__) + + cls.test_dir = os.path.join(input_path, + "UsdImportUVSetMappingsTest") + + @classmethod + def tearDownClass(cls): + standalone.uninitialize() + + def testImportUVSetMappings(self): + ''' + Tests that importing complex UV set mappings work: + ''' + usd_path = os.path.join(self.test_dir, "UsdImportUVSetMappings.usda") + options = ["shadingMode=[[useRegistry,UsdPreviewSurface]]", + "primPath=/"] + cmds.file(usd_path, i=True, type="USD Import", + ignoreVersion=True, ra=True, mergeNamespacesOnClash=False, + namespace="Test", pr=True, importTimeRange="combine", + options=";".join(options)) + + # With merging working, we expect exactly these shading groups (since + # two of them were made unmergeable) + expected_sg = set(['initialParticleSE', + 'initialShadingGroup', + 'USD_Materials:blinn1SG', + 'USD_Materials:blinn2SG', + 'USD_Materials:blinn3SG', + 'USD_Materials:blinn3SG_uvSet1', + 'USD_Materials:blinn4SG', + 'USD_Materials:blinn4SG_uvSet2']) + + self.assertEqual(set(cmds.ls(type="shadingEngine")), expected_sg) + + expected_links = [ + ("file1", ['pPlane4Shape.uvSet[0].uvSetName', + 'pPlane3Shape.uvSet[0].uvSetName', + 'pPlane1Shape.uvSet[0].uvSetName', + 'pPlane2Shape.uvSet[0].uvSetName']), + ("file2", ['pPlane4Shape.uvSet[1].uvSetName', + 'pPlane3Shape.uvSet[1].uvSetName', + 'pPlane1Shape.uvSet[1].uvSetName', + 'pPlane2Shape.uvSet[1].uvSetName']), + ("file3", ['pPlane4Shape.uvSet[2].uvSetName', + 'pPlane3Shape.uvSet[2].uvSetName', + 'pPlane1Shape.uvSet[2].uvSetName', + 'pPlane2Shape.uvSet[2].uvSetName']), + ("file4", ['pPlane4Shape.uvSet[0].uvSetName', + 'pPlane2Shape.uvSet[0].uvSetName']), + ("file5", ['pPlane2Shape.uvSet[1].uvSetName',]), + ("file6", ['pPlane2Shape.uvSet[2].uvSetName',]), + ("file7", ['pPlane4Shape.uvSet[1].uvSetName',]), + ("file8", ['pPlane4Shape.uvSet[2].uvSetName',]), + ] + for file_name, links in expected_links: + links = set(links) + self.assertEqual(set(cmds.uvLink(texture=file_name)), links) + + +if __name__ == '__main__': + unittest.main(verbosity=2) From 20844dbed7e64c66e3a177299acf845aafc328d2 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk Date: Mon, 9 Nov 2020 14:54:41 -0500 Subject: [PATCH 2/4] MAYA-106486 Use stage-based traversal --- .../fileio/translators/translatorMaterial.cpp | 46 ++++++++------ lib/usd/translators/meshReader.cpp | 6 +- .../shading/usdFileTextureWriter.cpp | 48 ++++++++++++--- .../shading/usdUVTextureReader.cpp | 61 ++++++++++++++++--- 4 files changed, 122 insertions(+), 39 deletions(-) diff --git a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp index 47f6908199..313a0e4c2c 100644 --- a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp +++ b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp @@ -27,13 +27,10 @@ #include #include #include -#include -#include -#include #include #include -#include #include +#include #include #include #include @@ -58,27 +55,42 @@ PXR_NAMESPACE_OPEN_SCOPE -TF_DEFINE_PRIVATE_TOKENS(_tokens, (inputs)(varname)); +// clang-format off +TF_DEFINE_PRIVATE_TOKENS( + _tokens, + + (inputs) + (varname) +); +// clang-format on namespace { // We want to know if this material is a specialization that was created to handle UV mappings on // export. For details, see the _UVMappingManager class in ..\shading\shadingModeExporterContext.cpp // -// If the root layer contains anything that is not a varname input, we do not consider it a -// mergeable material. bool _IsMergeableMaterial(const UsdShadeMaterial& shadeMaterial) { if (!shadeMaterial || !shadeMaterial.HasBaseMaterial()) { return false; } - const PcpPrimIndex& primIndex = shadeMaterial.GetPrim().GetPrimIndex(); - PcpNodeRef primRoot = primIndex.GetRootNode(); - SdfPath primPath = primIndex.GetPath(); - const SdfLayerHandle& layer = primRoot.GetLayerStack()->GetLayerTree()->GetLayer(); + UsdPrimCompositionQuery query(shadeMaterial.GetPrim()); + std::vector arcs = query.GetCompositionArcs(); + + // Check for materials created by _UVMappingManager::getMaterial(). This code could probably be + // expanded to be more generic and handle more complex composition arcs at a later stage. + + // Materials created by the _UVMappingManager have only 2 arcs: + if (arcs.size() != 2) { + return false; + } + + UsdPrimCompositionQueryArc specializationArc = arcs[1]; + SdfPath primPath = shadeMaterial.GetPath(); + + // Check that the specialization arc contains only opinions on varname inputs: bool retVal = true; - auto testFunction = [&](const SdfPath& path) { - // If we traverse anything that is not a varname specialization, we return false. + auto isVarnameOpinion = [&](const SdfPath& path) { if (path == primPath) { return; } @@ -87,14 +99,14 @@ bool _IsMergeableMaterial(const UsdShadeMaterial& shadeMaterial) return; } std::vector splitName = SdfPath::TokenizeIdentifier(path.GetName()); - // We allow only ["inputs", "XXX", "varname"] + // We allow only ["inputs", "", "varname"] if (splitName.size() != 3 || splitName[0] != _tokens->inputs.GetString() || splitName[2] != _tokens->varname.GetString()) { retVal = false; } }; - layer->Traverse(primPath, testFunction); + specializationArc.GetIntroducingLayer()->Traverse(primPath, isVarnameOpinion); return retVal; } @@ -145,7 +157,6 @@ MObject UsdMayaTranslatorMaterial::Read( namespace { using _UVBindings = std::map; -} static _UVBindings _GetUVBindingsFromMaterial(const UsdShadeMaterial& material, UsdMayaPrimReaderContext* context) @@ -192,7 +203,7 @@ static void _BindUVs(const MDagPath& shapeDagPath, const _UVBindings& uvBindings } MStatus status; - MFnMesh meshFn(shapeDagPath.node(), &status); + MFnMesh meshFn(shapeDagPath, &status); if (!status) { return; } @@ -218,6 +229,7 @@ static void _BindUVs(const MDagPath& shapeDagPath, const _UVBindings& uvBindings status = MGlobal::executeCommand(uvLinkCommand); } } +} // namespace static bool _AssignMaterialFaceSet( const MObject& shadingEngine, diff --git a/lib/usd/translators/meshReader.cpp b/lib/usd/translators/meshReader.cpp index c04d985e05..feacab2abd 100644 --- a/lib/usd/translators/meshReader.cpp +++ b/lib/usd/translators/meshReader.cpp @@ -131,12 +131,12 @@ bool MayaUsdPrimReaderMesh::Read(UsdMayaPrimReaderContext* context) UsdMayaMeshReadUtils::assignPrimvarsToMesh( mesh, meshRead.meshObject(), _GetArgs().GetExcludePrimvarNames()); - // assign material - assignMaterial(mesh, _GetArgs(), meshRead.meshObject(), context); - // assign invisible faces UsdMayaMeshReadUtils::assignInvisibleFaces(mesh, meshRead.meshObject()); + // assign material + assignMaterial(mesh, _GetArgs(), meshRead.meshObject(), context); + return true; } diff --git a/lib/usd/translators/shading/usdFileTextureWriter.cpp b/lib/usd/translators/shading/usdFileTextureWriter.cpp index 98a0d9e12b..8a35e8d246 100644 --- a/lib/usd/translators/shading/usdFileTextureWriter.cpp +++ b/lib/usd/translators/shading/usdFileTextureWriter.cpp @@ -68,22 +68,40 @@ class PxrUsdTranslators_FileTextureWriter : public UsdMayaShaderWriter PXRUSDMAYA_REGISTER_SHADER_WRITER(file, PxrUsdTranslators_FileTextureWriter); +// clang-format off TF_DEFINE_PRIVATE_TOKENS( _tokens, // Maya "file" node attribute names - (alphaGain)(alphaOffset)(colorGain)(colorOffset)(colorSpace)(defaultColor)(fileTextureName)( - outAlpha)(outColor)(outColorR)(outColorG)(outColorB)(outTransparency)(outTransparencyR)( - outTransparencyG)(outTransparencyB)(wrapU)(wrapV) + (alphaGain) + (alphaOffset) + (colorGain) + (colorOffset) + (colorSpace) + (defaultColor) + (fileTextureName) + (outAlpha) + (outColor) + (outColorR) + (outColorG) + (outColorB) + (outTransparency) + (outTransparencyR) + (outTransparencyG) + (outTransparencyB) + (wrapU) + (wrapV) // UDIM handling: - (uvTilingMode)((UDIMTag, "")) + (uvTilingMode) + ((UDIMTag, "")) // XXX: We duplicate these tokens here rather than create a dependency on // usdImaging in case the plugin is being built with imaging disabled. // If/when they move out of usdImaging to a place that is always available, // they should be pulled from there instead. - (UsdUVTexture)(UsdPrimvarReader_float2) + (UsdUVTexture) + (UsdPrimvarReader_float2) // UsdPrimvarReader_float2 Prim Name ((PrimvarReaderShaderName, "TexCoordReader")) @@ -95,14 +113,26 @@ TF_DEFINE_PRIVATE_TOKENS( (result) // UsdUVTexture Input Names - (bias)(fallback)(file)(scale)(st)(wrapS)(wrapT) + (bias) + (fallback) + (file) + (scale) + (st) + (wrapS) + (wrapT) // Values for wrapS and wrapT - (black)(repeat) + (black) + (repeat) // UsdUVTexture Output Names - ((RGBOutputName, "rgb"))((RedOutputName, "r"))((GreenOutputName, "g"))((BlueOutputName, "b"))( - (AlphaOutputName, "a"))); + ((RGBOutputName, "rgb")) + ((RedOutputName, "r")) + ((GreenOutputName, "g")) + ((BlueOutputName, "b")) + ((AlphaOutputName, "a")) +); +// clang-format off UsdMayaShaderWriter::ContextSupport PxrUsdTranslators_FileTextureWriter::CanExport(const UsdMayaJobExportArgs& exportArgs) diff --git a/lib/usd/translators/shading/usdUVTextureReader.cpp b/lib/usd/translators/shading/usdUVTextureReader.cpp index 21c213a566..8f7a388d5c 100644 --- a/lib/usd/translators/shading/usdUVTextureReader.cpp +++ b/lib/usd/translators/shading/usdUVTextureReader.cpp @@ -55,30 +55,71 @@ class PxrMayaUsdUVTexture_Reader : public UsdMayaShaderReader PXRUSDMAYA_REGISTER_SHADER_READER(UsdUVTexture, PxrMayaUsdUVTexture_Reader) +// clang-format off TF_DEFINE_PRIVATE_TOKENS( _tokens, // Maya "file" node attribute names - (file)(alphaGain)(alphaOffset)(colorGain)(colorOffset)(colorSpace)(defaultColor)( - fileTextureName)(outAlpha)(outColor)(outColorR)(outColorG)(outColorB)(place2dTexture)( - coverage)(translateFrame)(rotateFrame)(mirrorU)(mirrorV)(stagger)(wrapU)(wrapV)(repeatUV)( - offset)(rotateUV)(noiseUV)(vertexUvOne)(vertexUvTwo)(vertexUvThree)(vertexCameraOne) + (file) + (alphaGain) + (alphaOffset) + (colorGain) + (colorOffset) + (colorSpace) + (defaultColor) + (fileTextureName) + (outAlpha) + (outColor) + (outColorR) + (outColorG) + (outColorB) + (place2dTexture) + (coverage) + (translateFrame) + (rotateFrame) + (mirrorU) + (mirrorV) + (stagger) + (wrapU) + (wrapV) + (repeatUV) + (offset) + (rotateUV) + (noiseUV) + (vertexUvOne) + (vertexUvTwo) + (vertexUvThree) + (vertexCameraOne) // UsdUVTexture Input Names - (bias)(fallback)(scale)(wrapS)(wrapT) + (bias) + (fallback) + (scale) + (wrapS) + (wrapT) // uv connections: - (outUvFilterSize)(uvFilterSize)(outUV)(uvCoord) + (outUvFilterSize) + (uvFilterSize) + (outUV) + (uvCoord) // Values for wrapS and wrapT - (black)(repeat) + (black) + (repeat) // UsdUVTexture Output Names - ((RGBOutputName, "rgb"))((RedOutputName, "r"))((GreenOutputName, "g"))((BlueOutputName, "b"))( - (AlphaOutputName, "a")) + ((RGBOutputName, "rgb")) + ((RedOutputName, "r")) + ((GreenOutputName, "g")) + ((BlueOutputName, "b")) + ((AlphaOutputName, "a")) // UDIM detection - ((UDIMTag, ""))(uvTilingMode)); + ((UDIMTag, "")) + (uvTilingMode) +); +// clang-format off static const TfTokenVector _Place2dTextureConnections = { _tokens->coverage, _tokens->translateFrame, _tokens->rotateFrame, _tokens->mirrorU, From 75d92525823128110ef4616da13209aad92ef13d Mon Sep 17 00:00:00 2001 From: JGamache-autodesk Date: Wed, 11 Nov 2020 16:20:26 -0500 Subject: [PATCH 3/4] MAYA-106486 Remove layer traversal for faster merge detection --- .../fileio/translators/translatorMaterial.cpp | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp index 313a0e4c2c..da222d4bc6 100644 --- a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp +++ b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp @@ -74,41 +74,39 @@ bool _IsMergeableMaterial(const UsdShadeMaterial& shadeMaterial) return false; } - UsdPrimCompositionQuery query(shadeMaterial.GetPrim()); + // This is a little more robust than grabbing a specific arc index. + UsdPrimCompositionQuery::Filter filter; + filter.arcTypeFilter = UsdPrimCompositionQuery::ArcTypeFilter::Specialize; + UsdPrimCompositionQuery query(shadeMaterial.GetPrim(), filter); std::vector arcs = query.GetCompositionArcs(); + if (arcs.size() != 1) { + return false; + } + + const UsdPrimCompositionQueryArc specializationArc = arcs.front(); - // Check for materials created by _UVMappingManager::getMaterial(). This code could probably be - // expanded to be more generic and handle more complex composition arcs at a later stage. + const SdfLayerHandle layer = specializationArc.GetIntroducingLayer(); + const SdfPrimSpecHandle primSpec = layer->GetPrimAtPath(shadeMaterial.GetPath()); - // Materials created by the _UVMappingManager have only 2 arcs: - if (arcs.size() != 2) { + // If the primSpec that specializes the base material introduces other + // namespace children, it can't be merged. + if (!primSpec->GetNameChildren().empty()) { return false; } - UsdPrimCompositionQueryArc specializationArc = arcs[1]; - SdfPath primPath = shadeMaterial.GetPath(); + // Check that the only properties authored are varname inputs. + for (const SdfPropertySpecHandle& propSpec : primSpec->GetProperties()) { + const SdfPath propPath = propSpec->GetPath(); - // Check that the specialization arc contains only opinions on varname inputs: - bool retVal = true; - auto isVarnameOpinion = [&](const SdfPath& path) { - if (path == primPath) { - return; - } - if (path.GetParentPath() != primPath || !path.IsPrimPropertyPath()) { - retVal = false; - return; - } - std::vector splitName = SdfPath::TokenizeIdentifier(path.GetName()); + const std::vector splitName = SdfPath::TokenizeIdentifier(propPath.GetName()); // We allow only ["inputs", "", "varname"] - if (splitName.size() != 3 || splitName[0] != _tokens->inputs.GetString() - || splitName[2] != _tokens->varname.GetString()) { - retVal = false; + if (splitName.size() != 3u || splitName[0u] != _tokens->inputs.GetString() + || splitName[2u] != _tokens->varname.GetString()) { + return false; } - }; - - specializationArc.GetIntroducingLayer()->Traverse(primPath, isVarnameOpinion); + } - return retVal; + return true; } } // namespace From 9fea448cb4915289c8784839d1a636405a37c4f6 Mon Sep 17 00:00:00 2001 From: JGamache-autodesk Date: Wed, 11 Nov 2020 16:32:15 -0500 Subject: [PATCH 4/4] MAYA-106486 Added back missing check on arc counts --- .../fileio/translators/translatorMaterial.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp index da222d4bc6..d74cd77523 100644 --- a/lib/mayaUsd/fileio/translators/translatorMaterial.cpp +++ b/lib/mayaUsd/fileio/translators/translatorMaterial.cpp @@ -74,16 +74,21 @@ bool _IsMergeableMaterial(const UsdShadeMaterial& shadeMaterial) return false; } + // Check for materials created by _UVMappingManager::getMaterial(). This code could probably be + // expanded to be more generic and handle more complex composition arcs at a later stage. + + UsdPrimCompositionQuery query(shadeMaterial.GetPrim()); + if (query.GetCompositionArcs().size() != 2) { + // Materials created by the _UVMappingManager have only 2 arcs: + return false; + } + // This is a little more robust than grabbing a specific arc index. UsdPrimCompositionQuery::Filter filter; filter.arcTypeFilter = UsdPrimCompositionQuery::ArcTypeFilter::Specialize; - UsdPrimCompositionQuery query(shadeMaterial.GetPrim(), filter); + query.SetFilter(filter); std::vector arcs = query.GetCompositionArcs(); - if (arcs.size() != 1) { - return false; - } - - const UsdPrimCompositionQueryArc specializationArc = arcs.front(); + const UsdPrimCompositionQueryArc specializationArc = arcs.front(); const SdfLayerHandle layer = specializationArc.GetIntroducingLayer(); const SdfPrimSpecHandle primSpec = layer->GetPrimAtPath(shadeMaterial.GetPath());