Skip to content

Commit

Permalink
Merge pull request #902 from Autodesk/t_gamaj/MAYA-106486/import_uvse…
Browse files Browse the repository at this point in the history
…t_mappings

MAYA-106486 Import UV set mappings
  • Loading branch information
Krystian Ligenza authored Nov 12, 2020
2 parents 7bc35c3 + 9fea448 commit a83cfc1
Show file tree
Hide file tree
Showing 8 changed files with 705 additions and 11 deletions.
2 changes: 1 addition & 1 deletion lib/mayaUsd/fileio/shading/shadingModeExporterContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,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();
Expand Down
172 changes: 165 additions & 7 deletions lib/mayaUsd/fileio/translators/translatorMaterial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
#include <pxr/base/tf/token.h>
#include <pxr/base/vt/types.h>
#include <pxr/usd/sdf/assetPath.h>
#include <pxr/usd/sdf/layer.h>
#include <pxr/usd/sdf/path.h>
#include <pxr/usd/usd/primCompositionQuery.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdGeom/gprim.h>
#include <pxr/usd/usdGeom/mesh.h>
Expand All @@ -38,8 +40,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 +55,66 @@

PXR_NAMESPACE_OPEN_SCOPE

// 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
//
bool _IsMergeableMaterial(const UsdShadeMaterial& shadeMaterial)
{
if (!shadeMaterial || !shadeMaterial.HasBaseMaterial()) {
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;
query.SetFilter(filter);
std::vector<UsdPrimCompositionQueryArc> arcs = query.GetCompositionArcs();
const UsdPrimCompositionQueryArc specializationArc = arcs.front();

const SdfLayerHandle layer = specializationArc.GetIntroducingLayer();
const SdfPrimSpecHandle primSpec = layer->GetPrimAtPath(shadeMaterial.GetPath());

// If the primSpec that specializes the base material introduces other
// namespace children, it can't be merged.
if (!primSpec->GetNameChildren().empty()) {
return false;
}

// Check that the only properties authored are varname inputs.
for (const SdfPropertySpecHandle& propSpec : primSpec->GetProperties()) {
const SdfPath propPath = propSpec->GetPath();

const std::vector<std::string> splitName = SdfPath::TokenizeIdentifier(propPath.GetName());
// We allow only ["inputs", "<texture_name>", "varname"]
if (splitName.size() != 3u || splitName[0u] != _tokens->inputs.GetString()
|| splitName[2u] != _tokens->varname.GetString()) {
return false;
}
}

return true;
}
} // namespace

/* static */
MObject UsdMayaTranslatorMaterial::Read(
const UsdMayaJobImportArgs& jobArguments,
Expand All @@ -70,6 +134,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 +158,87 @@ MObject UsdMayaTranslatorMaterial::Read(
return shadingEngine;
}

namespace {
using _UVBindings = std::map<TfToken, TfToken>;

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, &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);
}
}
} // namespace

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 +263,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 +288,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 +315,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 +349,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 +361,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,15 +127,16 @@ 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 invisible faces
UsdMayaMeshReadUtils::assignInvisibleFaces(mesh, meshRead.meshObject());

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

return true;
}

Expand Down
16 changes: 16 additions & 0 deletions lib/usd/translators/shading/usdUVTextureReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ TF_DEFINE_PRIVATE_TOKENS(
(wrapS)
(wrapT)

// uv connections:
(outUvFilterSize)
(uvFilterSize)
(outUV)
(uvCoord)

// Values for wrapS and wrapT
(black)
(repeat)
Expand Down Expand Up @@ -175,6 +181,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);
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

0 comments on commit a83cfc1

Please sign in to comment.