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 Handle UV linkage on material export #876

Merged
merged 3 commits into from
Nov 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
352 changes: 254 additions & 98 deletions lib/mayaUsd/fileio/shading/shadingModeExporterContext.cpp

Large diffs are not rendered by default.

22 changes: 16 additions & 6 deletions lib/mayaUsd/fileio/shading/shadingModeExporterContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ class UsdMayaShadingModeExportContext
/// targeting a subset of the bound prim's faces.
/// If the list of faceIndices is empty, it means the assignment targets
/// all the faces in the bound prim or the entire bound prim.
typedef std::pair<SdfPath, VtIntArray> Assignment;
struct Assignment
{
SdfPath boundPrimPath;
VtIntArray faceIndices;
TfToken shapeName;
};

/// Vector of assignments.
typedef std::vector<Assignment> AssignmentVector;
Expand All @@ -104,17 +109,22 @@ class UsdMayaShadingModeExportContext
MAYAUSD_CORE_PUBLIC
AssignmentVector GetAssignments() const;

/// Use this function to create a UsdShadeMaterial prim at the "standard"
/// location. The "standard" location may change depending on arguments
/// that are passed to the export script.
/// Use this function to create a UsdShadeMaterial prim at a "standard"
/// location computed by browsing the \p assignmentsToBind
MAYAUSD_CORE_PUBLIC
UsdPrim MakeStandardMaterialPrim(
const AssignmentVector& assignmentsToBind,
const std::string& name = std::string()) const;

/// Use this function to bind a UsdShadeMaterial prim to all assignments provided.
///
/// If \p boundPrimPaths is not NULL, it is populated with the set of
/// prim paths that were bound to the created material prim, based on the
/// given \p assignmentsToBind.
MAYAUSD_CORE_PUBLIC
UsdPrim MakeStandardMaterialPrim(
void BindStandardMaterialPrim(
const UsdPrim & materialPrim,
const AssignmentVector& assignmentsToBind,
const std::string& name=std::string(),
SdfPathSet* const boundPrimPaths=nullptr) const;

MAYAUSD_CORE_PUBLIC
Expand Down
5 changes: 2 additions & 3 deletions lib/mayaUsd/fileio/shading/shadingModePxrRis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,8 @@ class PxrRisShadingModeExporter : public UsdMayaShadingModeExporter {
return;
}

UsdPrim materialPrim = context.MakeStandardMaterialPrim(assignments,
std::string(),
boundPrimPaths);
UsdPrim materialPrim = context.MakeStandardMaterialPrim(assignments);
context.BindStandardMaterialPrim(materialPrim, assignments, boundPrimPaths);
UsdShadeMaterial material(materialPrim);
if (!material) {
return;
Expand Down
8 changes: 3 additions & 5 deletions lib/mayaUsd/fileio/shading/shadingModeUseRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,7 @@ class UseRegistryShadingModeExporter : public UsdMayaShadingModeExporter
return;
}

UsdPrim materialPrim =
context.MakeStandardMaterialPrim(
assignments,
std::string(),
boundPrimPaths);
UsdPrim materialPrim = context.MakeStandardMaterialPrim(assignments, std::string());
UsdShadeMaterial material(materialPrim);
if (!material) {
return;
Expand Down Expand Up @@ -381,6 +377,8 @@ class UseRegistryShadingModeExporter : public UsdMayaShadingModeExporter
material,
UsdShadeTokens->displacement,
renderContext);

context.BindStandardMaterialPrim(materialPrim, assignments, boundPrimPaths);
}
};

Expand Down
7 changes: 3 additions & 4 deletions lib/mayaUsd/fileio/utils/meshReadUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,12 @@ namespace
MString uvSetName(primvarName.GetText());
bool createUVSet = true;

if (primvarName == UsdUtilsGetPrimaryUVSetName()) {
if (primvarName == UsdUtilsGetPrimaryUVSetName() && UsdMayaReadUtil::ReadSTAsMap1()) {
// We assume that the primary USD UV set maps to Maya's default 'map1'
// set which always exists, so we shouldn't try to create it.
uvSetName = UsdMayaMeshPrimvarTokens->DefaultMayaTexcoordName.GetText();
createUVSet = false;
} else if (!hasDefaultUVSet) {
// If map1 still exists, we rename and re-use it:
} else if (!hasDefaultUVSet) { // If map1 still exists, we rename and re-use it:
MStringArray uvSetNames;
meshFn.getUVSetNames(uvSetNames);
if (uvSetNames[0] == UsdMayaMeshPrimvarTokens->DefaultMayaTexcoordName.GetText()) {
Expand Down Expand Up @@ -633,7 +632,7 @@ UsdMayaMeshReadUtils::assignPrimvarsToMesh(const UsdGeomMesh& mesh,
|| (UsdMayaReadUtil::ReadFloat2AsUV() && typeName == SdfValueTypeNames->Float2Array)) {
const TfToken fullName = primvar.GetPrimvarName();
if (fullName == UsdMayaMeshPrimvarTokens->DefaultMayaTexcoordName
|| fullName == UsdUtilsGetPrimaryUVSetName()) {
|| (fullName == UsdUtilsGetPrimaryUVSetName() && UsdMayaReadUtil::ReadSTAsMap1())) {
hasDefaultUVSet = true;
}
}
Expand Down
7 changes: 3 additions & 4 deletions lib/mayaUsd/fileio/utils/meshWriteUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,11 +828,10 @@ UsdMayaMeshWriteUtils::writeUVSetsAsVec2fPrimvars(const MFnMesh& meshFn,
continue;
}

// XXX: We should be able to configure the UV map name that triggers this
// behavior, and the name to which it exports.
// The UV Set "map1" is renamed st. This is a Pixar/USD convention.
// Rename "map1" as "st" to follow Pixar/USD convention if requested.
TfToken setName(uvSetNames[i].asChar());
if (setName == UsdMayaMeshPrimvarTokens->DefaultMayaTexcoordName.GetText()) {
if (setName == UsdMayaMeshPrimvarTokens->DefaultMayaTexcoordName.GetText()
&& UsdMayaWriteUtil::WriteMap1AsST()) {
setName = UsdUtilsGetPrimaryUVSetName();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The removes the automatic "map1"-> "st" renaming on export. Should I create an env var for shops that have internal tools that depend on this behavior?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, definitely. Having the Maya USD export portion of our asset builds suddenly writing map1 primvars instead of st primvars would be a non-trivial pipeline change for us, so at least for now, we'll need to be able to opt out of that.

Including a setting for import, maybe a pair of TfEnvSettings like this?:

TF_DEFINE_ENV_SETTING(
    MAYAUSD_IMPORT_PRIMARY_UV_SET_AS_MAP1,
    false,
    "Translates the primary UV set in USD to the map1 UV set in Maya. "
    "When disabled, UV set names are translated directly (st in USD becomes st in Maya).");

TF_DEFINE_ENV_SETTING(
    MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET,
    false,
    "Translates the map1 UV set in Maya to the primary UV set in USD. "
    "When disabled, UV set names are translated directly (map1 in Maya becomes map1 in USD).");

Thanks! :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes agreed, having the env variable to make a switch would be useful. Thanks

}

Expand Down
14 changes: 14 additions & 0 deletions lib/mayaUsd/fileio/utils/readUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ UsdMayaReadUtil::ReadFloat2AsUV()
return readFloat2AsUV;
}

TF_DEFINE_ENV_SETTING(
MAYAUSD_IMPORT_PRIMARY_UV_SET_AS_MAP1,
false,
"Translates the primary UV set in USD to the map1 UV set in Maya. "
"When disabled, UV set names are translated directly (st in USD becomes st in Maya).");

bool
UsdMayaReadUtil::ReadSTAsMap1()
{
static const bool readSTAsMap1 =
TfGetEnvSetting(MAYAUSD_IMPORT_PRIMARY_UV_SET_AS_MAP1);
return readSTAsMap1;
}

MObject
UsdMayaReadUtil::FindOrCreateMayaAttr(
const SdfValueTypeName& typeName,
Expand Down
5 changes: 5 additions & 0 deletions lib/mayaUsd/fileio/utils/readUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ struct UsdMayaReadUtil
MAYAUSD_CORE_PUBLIC
static bool ReadFloat2AsUV();

/// Returns whether the environment setting for renaming st TexCoord to map1
/// is set to true
MAYAUSD_CORE_PUBLIC
static bool ReadSTAsMap1();

/// Given the \p typeName and \p variability, try to create a Maya attribute
/// on \p depNode with the name \p attrName.
/// If the \p typeName isn't supported by this function, raises a runtime
Expand Down
13 changes: 13 additions & 0 deletions lib/mayaUsd/fileio/utils/writeUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ TF_DEFINE_ENV_SETTING(
"TexCoord2d, TexCoord3h, TexCoord3f, TexCoord3d and their associated "
"Array types)");

TF_DEFINE_ENV_SETTING(
MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET,
false,
"Translates the map1 UV set in Maya to the primary UV set in USD. "
"When disabled, UV set names are translated directly (map1 in Maya becomes map1 in USD).");

static
bool
Expand Down Expand Up @@ -130,6 +135,14 @@ UsdMayaWriteUtil::WriteUVAsFloat2()
return writeUVAsFloat2;
}

bool
UsdMayaWriteUtil::WriteMap1AsST()
{
static const bool writeMap1AsST =
TfGetEnvSetting(MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET);
return writeMap1AsST;
}

/* static */
UsdAttribute
UsdMayaWriteUtil::GetOrCreateUsdAttr(
Expand Down
5 changes: 5 additions & 0 deletions lib/mayaUsd/fileio/utils/writeUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ struct UsdMayaWriteUtil
MAYAUSD_CORE_PUBLIC
static bool WriteUVAsFloat2();

/// Returns whether the environment setting for renaming map1 TexCoord to st
/// is set to true
MAYAUSD_CORE_PUBLIC
static bool WriteMap1AsST();

/// Given an \p attrPlug, try to create a USD attribute on \p usdPrim with
/// the name \p attrName. Note, it's value will not be set.
///
Expand Down
2 changes: 2 additions & 0 deletions lib/mayaUsd/python/wrapReadUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ void wrapReadUtil()
class_<This>("ReadUtil", no_init)
.def("ReadFloat2AsUV", This::ReadFloat2AsUV)
.staticmethod("ReadFloat2AsUV")
.def("ReadSTAsMap1", This::ReadSTAsMap1)
.staticmethod("ReadSTAsMap1")
.def("FindOrCreateMayaAttr", _FindOrCreateMayaAttr,
(arg("typeName"), arg("variability"), arg("nodeName"),
arg("attrName"), arg("attrNiceName")=std::string()))
Expand Down
2 changes: 2 additions & 0 deletions lib/mayaUsd/python/wrapWriteUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ void wrapWriteUtil()
class_<This>("WriteUtil", no_init)
.def("WriteUVAsFloat2", This::WriteUVAsFloat2)
.staticmethod("WriteUVAsFloat2")
.def("WriteMap1AsST", This::WriteMap1AsST)
.staticmethod("WriteMap1AsST")
.def("GetVtValue", _GetVtValue)
.staticmethod("GetVtValue")
;
Expand Down
4 changes: 2 additions & 2 deletions lib/mayaUsd/render/mayaToHydra/shadingModeExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ class MtohShadingModeExporter : public UsdMayaShadingModeExporter {
context.GetAssignments();
if (assignments.empty()) { return; }

UsdPrim materialPrim = context.MakeStandardMaterialPrim(
assignments, std::string(), boundPrimPaths);
UsdPrim materialPrim = context.MakeStandardMaterialPrim(assignments);
context.BindStandardMaterialPrim(materialPrim, assignments, boundPrimPaths);
UsdShadeMaterial material(materialPrim);
if (!material) { return; }

Expand Down
33 changes: 29 additions & 4 deletions lib/usd/translators/shading/usdFileTextureWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <pxr/usd/sdf/types.h>
#include <pxr/usd/usdShade/input.h>
#include <pxr/usd/usdShade/output.h>
#include <pxr/usd/usdShade/material.h>
#include <pxr/usd/usdShade/shader.h>
#include <pxr/usd/usdUtils/pipeline.h>
#include <pxr/usdImaging/usdImaging/tokens.h>
Expand Down Expand Up @@ -170,11 +171,35 @@ PxrUsdTranslators_FileTextureWriter::PxrUsdTranslators_FileTextureWriter(
primvarReaderShaderSchema.CreateIdAttr(
VtValue(_tokens->UsdPrimvarReader_float2));

// XXX: We'll eventually need to to determine which UV set to use if we're
// not using the default (i.e. "map1" in Maya -> "st" in USD).
primvarReaderShaderSchema.CreateInput(
UsdShadeInput varnameInput = primvarReaderShaderSchema.CreateInput(
_tokens->varname,
SdfValueTypeNames->Token).Set(UsdUtilsGetPrimaryUVSetName());
SdfValueTypeNames->Token);

// We expose the primvar reader varname attribute to the material to allow
// easy specialization based on UV mappings to geometries:
SdfPath materialPath = GetUsdPath().GetParentPath();
UsdShadeMaterial materialSchema(GetUsdStage()->GetPrimAtPath(materialPath));
while (!materialSchema && !materialPath.IsEmpty()) {
materialPath = materialPath.GetParentPath();
materialSchema = UsdShadeMaterial(GetUsdStage()->GetPrimAtPath(materialPath));
}

if (materialSchema) {
TfToken inputName(
TfStringPrintf("%s:%s", depNodeFn.name().asChar(), _tokens->varname.GetText()));
UsdShadeInput materialInput
= materialSchema.CreateInput(inputName, SdfValueTypeNames->Token);
materialInput.Set(UsdUtilsGetPrimaryUVSetName());
varnameInput.ConnectToSource(materialInput);
// Note: This needs to be done for all nodes that require UV input. In
// the UsdPreviewSurface case, the file node is the only one, but for
// other Maya nodes like cloth, checker, mandelbrot, we will also need
// to resolve the UV channels. This means traversing UV inputs until we
// find the unconnected one that implicitly connects to uvSet[0] of the
// geometry, or an explicit uvChooser node connecting to alternate uvSets.
} else {
varnameInput.Set(UsdUtilsGetPrimaryUVSetName());
}

UsdShadeOutput primvarReaderOutput =
primvarReaderShaderSchema.CreateOutput(
Expand Down
1 change: 1 addition & 0 deletions plugin/pxr/maya/lib/usdMaya/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ pxr_register_test(testUsdMayaUserExportedAttributes
MAYA_DISABLE_CIP=1
MAYA_NO_STANDALONE_ATEXIT=1
MAYA_APP_DIR=<PXR_TEST_DIR>/maya_profile
MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET=1
)

pxr_install_test_dir(
Expand Down
40 changes: 40 additions & 0 deletions test/lib/usd/translators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ mayaUsd_add_test(testUsdExportUVSets
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_WRITE_UV_AS_FLOAT2=0"
"MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET=0"
)
set_property(TEST testUsdExportUVSets APPEND PROPERTY LABELS translators)

Expand All @@ -108,14 +109,43 @@ mayaUsd_add_test(testUsdExportUVSetsFloat
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_WRITE_UV_AS_FLOAT2=1"
"MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET=0"
)
set_property(TEST testUsdExportUVSetsFloat APPEND PROPERTY LABELS translators)

mayaUsd_add_test(testUsdExportUVSetsST
PYTHON_MODULE testUsdExportUVSets
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_WRITE_UV_AS_FLOAT2=0"
"MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET=1"
)
set_property(TEST testUsdExportUVSetsST APPEND PROPERTY LABELS translators)

mayaUsd_add_test(testUsdExportUVSetMappings
PYTHON_MODULE testUsdExportUVSetMappings
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_WRITE_UV_AS_FLOAT2=0"
"MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET=0"
)
set_property(TEST testUsdExportUVSetMappings APPEND PROPERTY LABELS translators)

mayaUsd_add_test(testUsdExportUVSetMappingsST
PYTHON_MODULE testUsdExportUVSetMappings
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_WRITE_UV_AS_FLOAT2=0"
"MAYAUSD_EXPORT_MAP1_AS_PRIMARY_UV_SET=1"
)
set_property(TEST testUsdExportUVSetMappingsST APPEND PROPERTY LABELS translators)

mayaUsd_add_test(testUsdImportUVSets
PYTHON_MODULE testUsdImportUVSets
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_READ_FLOAT2_AS_UV=0"
"MAYAUSD_IMPORT_PRIMARY_UV_SET_AS_MAP1=0"
)
set_property(TEST testUsdImportUVSets APPEND PROPERTY LABELS translators)

Expand All @@ -124,9 +154,19 @@ mayaUsd_add_test(testUsdImportUVSetsFloat
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_READ_FLOAT2_AS_UV=1"
"MAYAUSD_IMPORT_PRIMARY_UV_SET_AS_MAP1=0"
)
set_property(TEST testUsdImportUVSetsFloat APPEND PROPERTY LABELS translators)

mayaUsd_add_test(testUsdImportUVSetsST
PYTHON_MODULE testUsdImportUVSets
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
ENV
"PIXMAYA_READ_FLOAT2_AS_UV=0"
"MAYAUSD_IMPORT_PRIMARY_UV_SET_AS_MAP1=1"
)
set_property(TEST testUsdImportUVSetsST APPEND PROPERTY LABELS translators)

# Test using standardSurface, which was introduced in Maya 2020.
if (MAYA_APP_VERSION VERSION_GREATER_EQUAL 2020)
set(CUSTOM_TEST_SCRIPT_FILES
Expand Down
Loading