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-106486 Import UV set mappings #902

Merged
merged 5 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/mayaUsd/fileio/shading/shadingModeExporterContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved

TfTokenVector::const_iterator itNode = _nodesWithUVInput.cbegin();
TfTokenVector::const_iterator itName = uvNames.cbegin();
Expand Down
157 changes: 150 additions & 7 deletions lib/mayaUsd/fileio/translators/translatorMaterial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@
#include <pxr/base/tf/iterator.h>
#include <pxr/base/tf/token.h>
#include <pxr/base/vt/types.h>
#include <pxr/usd/pcp/layerStack.h>
#include <pxr/usd/pcp/node.h>
#include <pxr/usd/pcp/primIndex.h>
#include <pxr/usd/sdf/assetPath.h>
#include <pxr/usd/sdf/layer.h>
#include <pxr/usd/sdf/layerTree.h>
#include <pxr/usd/sdf/path.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdGeom/gprim.h>
Expand All @@ -38,8 +43,10 @@

#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnSet.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MGlobal.h>
#include <maya/MIntArray.h>
#include <maya/MObject.h>
#include <maya/MSelectionList.h>
Expand All @@ -51,6 +58,48 @@

PXR_NAMESPACE_OPEN_SCOPE

TF_DEFINE_PRIVATE_TOKENS(_tokens, (inputs)(varname));
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved

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();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure I understand why we're trying to find the root layer here. Don't we want to be considering the fully composed stage? Materials could be added or specialized, or opinions could be expressed, across multiple layers.


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<std::string> 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);
Copy link
Contributor

@mattyjams mattyjams Nov 6, 2020

Choose a reason for hiding this comment

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

Along the lines of the above comment, it seems like we'd want a stage-based traversal here rather than a layer-based one.


return retVal;
}
} // namespace

/* static */
MObject UsdMayaTranslatorMaterial::Read(
const UsdMayaJobImportArgs& jobArguments,
Expand All @@ -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) {
Expand All @@ -89,10 +143,87 @@ MObject UsdMayaTranslatorMaterial::Read(
return shadingEngine;
}

namespace {
using _UVBindings = std::map<TfToken, TfToken>;
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
}

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<std::string> splitName = usdAttr.SplitName();
if (splitName.size() != 3 || splitName[2] != _tokens->varname.GetString()) {
continue;
}
VtValue val;
usdAttr.Get(&val);
if (!val.IsHolding<TfToken>()) {
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>()] = 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);
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
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);
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
}
}

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;

Expand All @@ -117,6 +248,7 @@ static bool _AssignMaterialFaceSet(
"Could not add component to shadingEngine %s.", seFnSet.name().asChar());
return false;
}
_BindUVs(shapeDagPath, faceUVBindings);
}

return true;
Expand All @@ -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
Expand All @@ -164,6 +300,7 @@ bool UsdMayaTranslatorMaterial::AssignMaterial(
TF_RUNTIME_ERROR(
"Could not add shadingEngine for '%s'.", shapeDagPath.fullPathName().asChar());
}
_BindUVs(shapeDagPath, uvBindings);
}

return true;
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -208,20 +346,25 @@ 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
// there are no time-samples.
VtIntArray indices;
subset.GetIndicesAttr().Get(&indices, UsdTimeCode::EarliestTime());

if (!_AssignMaterialFaceSet(faceSubsetShadingEngine, shapeDagPath, indices)) {
if (!_AssignMaterialFaceSet(
faceSubsetShadingEngine, shapeDagPath, indices, faceUVBindings)) {
return false;
}
}
Expand Down
7 changes: 4 additions & 3 deletions lib/usd/translators/meshReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());

JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
// assign material
assignMaterial(mesh, _GetArgs(), meshRead.meshObject(), context);

// assign invisible faces
UsdMayaMeshReadUtils::assignInvisibleFaces(mesh, meshRead.meshObject());

Expand Down
13 changes: 13 additions & 0 deletions lib/usd/translators/shading/usdUVTextureReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ TF_DEFINE_PRIVATE_TOKENS(
// UsdUVTexture Input Names
(bias)(fallback)(scale)(wrapS)(wrapT)

// uv connections:
(outUvFilterSize)(uvFilterSize)(outUV)(uvCoord)
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved

// Values for wrapS and wrapT
(black)(repeat)

Expand Down Expand Up @@ -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);
}
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
MString connectCmd;
for (const TfToken& uvName : _Place2dTextureConnections) {
MPlug uvPlug = uvDepFn.findPlug(uvName.GetText(), true, &status);
Expand Down
1 change: 1 addition & 0 deletions test/lib/usd/translators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ set(TEST_SCRIPT_FILES
testUsdImportSessionLayer.py
testUsdImportShadingModeDisplayColor.py
testUsdImportShadingModePxrRis.py
testUsdImportUVSetMappings.py
testUsdExportImportRoundtripPreviewSurface.py
testUsdExportImportUDIM.py
testUsdImportSkeleton.py
Expand Down
Loading