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

Added mesh export options to preserve and remap UV set names #2283

Merged
merged 6 commits into from
May 3, 2022
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
2 changes: 2 additions & 0 deletions lib/mayaUsd/commands/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ their own purposes, similar to the Alembic export chaser example.
| `-chaser` | `-chr` | string(multi) | none | Specify the export chasers to execute as part of the export. See "Export Chasers" below. |
| `-chaserArgs` | `-cha` | string[3](multi) | none | Pass argument names and values to export chasers. Each argument to `-chaserArgs` should be a triple of the form: (`<chaser name>`, `<argument name>`, `<argument value>`). See "Export Chasers" below. |
| `-convertMaterialsTo` | `-cmt` | string(multi) | `UsdPreviewSurface` | Selects how to convert materials on export. The default value `UsdPreviewSurface` will export to a UsdPreviewSurface shading network. A plugin mechanism allows more conversions to be registered. Use the `mayaUSDListShadingModesCommand` command to explore the possible options. |
| `-remapUVSetsTo` | `-ruv` | string[2](multi) | none | Specify UV sets by name to rename on export. Each argument should be a pair of the form: (`<from set name>`, `<to set name>`). This option takes priority over `-preserveUVSetNames` for any specified UV set. |
| `-compatibility` | `-com` | string | none | Specifies a compatibility profile when exporting the USD file. The compatibility profile may limit features in the exported USD file so that it is compatible with the limitations or requirements of third-party applications. Currently, there are only two profiles: `none` - Standard export with no compatibility options, `appleArKit` - Ensures that exported usdz packages are compatible with Apple's implementation (as of ARKit 2/iOS 12/macOS Mojave). Packages referencing multiple layers will be flattened into a single layer, and the first layer will have the extension `.usdc`. This compatibility profile only applies when exporting usdz packages; if you enable this profile and don't specify a file extension in the `-file` flag, the `.usdz` extension will be used instead. |
| `-defaultCameras` | `-dc` | noarg | false | Export the four Maya default cameras |
| `-defaultMeshScheme` | `-dms` | string | `catmullClark` | Sets the default subdivision scheme for exported Maya meshes, if the `USD_subdivisionScheme` attribute is not present on the Mesh. Valid values are: `none`, `catmullClark`, `loop`, `bilinear` |
Expand Down Expand Up @@ -153,6 +154,7 @@ their own purposes, similar to the Alembic export chaser example.
| `-materialsScopeName` | `-msn` | string | `Looks` | Materials Scope Name |
| `-mergeTransformAndShape` | `-mt` | bool | true | Combine Maya transform and shape into a single USD prim that has transform and geometry, for all "geometric primitives" (gprims). This results in smaller and faster scenes. Gprims will be "unpacked" back into transform and shape nodes when imported into Maya from USD. |
| `-normalizeNurbs` | `-nnu` | bool | false | When setm the UV coordinates of nurbs are normalized to be between zero and one. |
| `-preserveUVSetNames` | `-puv` | bool | false | Refrain from renaming UV sets additional to "map1" to "st1", "st2", etc. This option is overridden for any UV set specified in `-remapUVSetsTo`. |
| `-pythonPerFrameCallback` | `-pfc` | string | none | Python function called after each frame is exported |
| `-pythonPostCallback` | `-ppc` | string | none | Python function called when the export is done |
| `-parentScope` | `-psc` | string | none | Name of the USD scope that is the parent of the exported data |
Expand Down
11 changes: 11 additions & 0 deletions lib/mayaUsd/commands/baseExportCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ MSyntax MayaUSDExportCommand::createSyntax()
kNormalizeNurbsFlag,
UsdMayaJobExportArgsTokens->normalizeNurbs.GetText(),
MSyntax::kBoolean);
syntax.addFlag(
kPreserveUVSetNamesFlag,
UsdMayaJobExportArgsTokens->preserveUVSetNames.GetText(),
MSyntax::kBoolean);
syntax.addFlag(
kExportColorSetsFlag,
UsdMayaJobExportArgsTokens->exportColorSets.GetText(),
Expand Down Expand Up @@ -166,6 +170,13 @@ MSyntax MayaUSDExportCommand::createSyntax()
MSyntax::kString);
syntax.makeFlagMultiUse(kChaserArgsFlag);

syntax.addFlag(
kRemapUVSetsToFlag,
UsdMayaJobExportArgsTokens->remapUVSetsTo.GetText(),
MSyntax::kString,
MSyntax::kString);
syntax.makeFlagMultiUse(kRemapUVSetsToFlag);

syntax.addFlag(
kMelPerFrameCallbackFlag,
UsdMayaJobExportArgsTokens->melPerFrameCallback.GetText(),
Expand Down
2 changes: 2 additions & 0 deletions lib/mayaUsd/commands/baseExportCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ class MAYAUSD_CORE_PUBLIC MayaUSDExportCommand : public MPxCommand
static constexpr auto kExportDisplayColorFlag = "dsp";
static constexpr auto kShadingModeFlag = "shd";
static constexpr auto kConvertMaterialsToFlag = "cmt";
static constexpr auto kRemapUVSetsToFlag = "ruv";
static constexpr auto kMaterialsScopeNameFlag = "msn";
static constexpr auto kExportMaterialCollectionsFlag = "mcs";
static constexpr auto kMaterialCollectionsPathFlag = "mcp";
static constexpr auto kExportCollectionBasedBindingsFlag = "cbb";
static constexpr auto kNormalizeNurbsFlag = "nnu";
static constexpr auto kPreserveUVSetNamesFlag = "puv";
static constexpr auto kReferenceObjectModeFlag = "rom";
static constexpr auto kExportRootsFlag = "ert";
static constexpr auto kExportSkelsFlag = "skl";
Expand Down
36 changes: 33 additions & 3 deletions lib/mayaUsd/fileio/jobs/jobArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,24 @@ _ChaserArgs(const VtDictionary& userArgs, const TfToken& key)
return result;
}

std::map<std::string, std::string> _UVSetRemaps(const VtDictionary& userArgs, const TfToken& key)
{
const std::vector<std::vector<VtValue>> uvRemaps = _Vector<std::vector<VtValue>>(userArgs, key);

std::map<std::string, std::string> result;
for (const std::vector<VtValue>& remap : uvRemaps) {
if (remap.size() != 2) {
TF_CODING_ERROR("Failed to parse remapping, all items must be pairs (from, to)");
return {};
}

const std::string& from = remap[0].Get<std::string>();
const std::string& to = remap[1].Get<std::string>();
result[from] = to;
}
return result;
}

// The shadingMode args are stored as vectors of vectors (since this is how you
// would need to pass them in the Maya Python command API).
UsdMayaJobImportArgs::ShadingModes
Expand Down Expand Up @@ -594,6 +612,7 @@ UsdMayaJobExportArgs::UsdMayaJobExportArgs(
_GetMaterialsScopeName(_String(userArgs, UsdMayaJobExportArgsTokens->materialsScopeName)))
, mergeTransformAndShape(_Boolean(userArgs, UsdMayaJobExportArgsTokens->mergeTransformAndShape))
, normalizeNurbs(_Boolean(userArgs, UsdMayaJobExportArgsTokens->normalizeNurbs))
, preserveUVSetNames(_Boolean(userArgs, UsdMayaJobExportArgsTokens->preserveUVSetNames))
, stripNamespaces(_Boolean(userArgs, UsdMayaJobExportArgsTokens->stripNamespaces))
, parentScope(_AbsolutePath(userArgs, UsdMayaJobExportArgsTokens->parentScope))
, renderLayerMode(_Token(
Expand Down Expand Up @@ -622,9 +641,8 @@ UsdMayaJobExportArgs::UsdMayaJobExportArgs(
, jobContextNames(_TokenSet(userArgs, UsdMayaJobExportArgsTokens->jobContext))
, chaserNames(_Vector<std::string>(userArgs, UsdMayaJobExportArgsTokens->chaser))
, allChaserArgs(_ChaserArgs(userArgs, UsdMayaJobExportArgsTokens->chaserArgs))
,

melPerFrameCallback(_String(userArgs, UsdMayaJobExportArgsTokens->melPerFrameCallback))
, remapUVSetsTo(_UVSetRemaps(userArgs, UsdMayaJobExportArgsTokens->remapUVSetsTo))
, melPerFrameCallback(_String(userArgs, UsdMayaJobExportArgsTokens->melPerFrameCallback))
, melPostCallback(_String(userArgs, UsdMayaJobExportArgsTokens->melPostCallback))
, pythonPerFrameCallback(_String(userArgs, UsdMayaJobExportArgsTokens->pythonPerFrameCallback))
, pythonPostCallback(_String(userArgs, UsdMayaJobExportArgsTokens->pythonPostCallback))
Expand Down Expand Up @@ -680,6 +698,7 @@ std::ostream& operator<<(std::ostream& out, const UsdMayaJobExportArgs& exportAr
<< "materialsScopeName: " << exportArgs.materialsScopeName << std::endl
<< "mergeTransformAndShape: " << TfStringify(exportArgs.mergeTransformAndShape) << std::endl
<< "normalizeNurbs: " << TfStringify(exportArgs.normalizeNurbs) << std::endl
<< "preserveUVSetNames: " << TfStringify(exportArgs.preserveUVSetNames) << std::endl
<< "parentScope: " << exportArgs.parentScope << std::endl
<< "renderLayerMode: " << exportArgs.renderLayerMode << std::endl
<< "rootKind: " << exportArgs.rootKind << std::endl
Expand Down Expand Up @@ -716,6 +735,11 @@ std::ostream& operator<<(std::ostream& out, const UsdMayaJobExportArgs& exportAr
out << " " << chaserName << std::endl;
}

out << "remapUVSetsTo (" << exportArgs.remapUVSetsTo.size() << ")" << std::endl;
for (const auto& remapIt : exportArgs.remapUVSetsTo) {
out << " " << remapIt.first << " -> " << remapIt.second << std::endl;
}

out << "allChaserArgs (" << exportArgs.allChaserArgs.size() << ")" << std::endl;
for (const auto& chaserIter : exportArgs.allChaserArgs) {
// Chaser name.
Expand Down Expand Up @@ -897,6 +921,7 @@ const VtDictionary& UsdMayaJobExportArgs::GetDefaultDictionary()
d[UsdMayaJobExportArgsTokens->frameSample] = std::vector<double>();
d[UsdMayaJobExportArgsTokens->chaser] = std::vector<VtValue>();
d[UsdMayaJobExportArgsTokens->chaserArgs] = std::vector<VtValue>();
d[UsdMayaJobExportArgsTokens->remapUVSetsTo] = std::vector<VtValue>();
d[UsdMayaJobExportArgsTokens->compatibility] = UsdMayaJobExportArgsTokens->none.GetString();
d[UsdMayaJobExportArgsTokens->defaultCameras] = false;
d[UsdMayaJobExportArgsTokens->defaultMeshScheme] = UsdGeomTokens->catmullClark.GetString();
Expand Down Expand Up @@ -929,6 +954,7 @@ const VtDictionary& UsdMayaJobExportArgs::GetDefaultDictionary()
d[UsdMayaJobExportArgsTokens->melPostCallback] = std::string();
d[UsdMayaJobExportArgsTokens->mergeTransformAndShape] = true;
d[UsdMayaJobExportArgsTokens->normalizeNurbs] = false;
d[UsdMayaJobExportArgsTokens->preserveUVSetNames] = false;
d[UsdMayaJobExportArgsTokens->parentScope] = std::string();
d[UsdMayaJobExportArgsTokens->pythonPerFrameCallback] = std::string();
d[UsdMayaJobExportArgsTokens->pythonPostCallback] = std::string();
Expand Down Expand Up @@ -970,6 +996,8 @@ const VtDictionary& UsdMayaJobExportArgs::GetGuideDictionary()
const auto _string = VtValue(std::string());
const auto _doubleVector = VtValue(std::vector<double>());
const auto _stringVector = VtValue(std::vector<VtValue>({ _string }));
const auto _stringPair = VtValue(std::vector<VtValue>({ _string, _string }));
const auto _stringPairVector = VtValue(std::vector<VtValue>({ _stringPair }));
const auto _stringTriplet = VtValue(std::vector<VtValue>({ _string, _string, _string }));
const auto _stringTripletVector = VtValue(std::vector<VtValue>({ _stringTriplet }));

Expand All @@ -981,6 +1009,7 @@ const VtDictionary& UsdMayaJobExportArgs::GetGuideDictionary()
d[UsdMayaJobExportArgsTokens->frameSample] = _doubleVector;
d[UsdMayaJobExportArgsTokens->chaser] = _stringVector;
d[UsdMayaJobExportArgsTokens->chaserArgs] = _stringTripletVector;
d[UsdMayaJobExportArgsTokens->remapUVSetsTo] = _stringPairVector;
d[UsdMayaJobExportArgsTokens->compatibility] = _string;
d[UsdMayaJobExportArgsTokens->defaultCameras] = _boolean;
d[UsdMayaJobExportArgsTokens->defaultMeshScheme] = _string;
Expand Down Expand Up @@ -1011,6 +1040,7 @@ const VtDictionary& UsdMayaJobExportArgs::GetGuideDictionary()
d[UsdMayaJobExportArgsTokens->melPostCallback] = _string;
d[UsdMayaJobExportArgsTokens->mergeTransformAndShape] = _boolean;
d[UsdMayaJobExportArgsTokens->normalizeNurbs] = _boolean;
d[UsdMayaJobExportArgsTokens->preserveUVSetNames] = _boolean;
d[UsdMayaJobExportArgsTokens->parentScope] = _string;
d[UsdMayaJobExportArgsTokens->pythonPerFrameCallback] = _string;
d[UsdMayaJobExportArgsTokens->pythonPostCallback] = _string;
Expand Down
5 changes: 5 additions & 0 deletions lib/mayaUsd/fileio/jobs/jobArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,15 @@ TF_DECLARE_PUBLIC_TOKENS(
(melPostCallback) \
(mergeTransformAndShape) \
(normalizeNurbs) \
(preserveUVSetNames) \
(parentScope) \
(pythonPerFrameCallback) \
(pythonPostCallback) \
(renderableOnly) \
(renderLayerMode) \
(shadingMode) \
(convertMaterialsTo) \
(remapUVSetsTo) \
(stripNamespaces) \
(verbose) \
(staticSingleSample) \
Expand Down Expand Up @@ -200,6 +202,7 @@ struct UsdMayaJobExportArgs
/// a single node in the output USD.
const bool mergeTransformAndShape;
const bool normalizeNurbs;
const bool preserveUVSetNames;
const bool stripNamespaces;

/// This is the path of the USD prim under which *all* prims will be
Expand All @@ -221,6 +224,8 @@ struct UsdMayaJobExportArgs
const std::vector<std::string> chaserNames;
const std::map<std::string, ChaserArgs> allChaserArgs;

const std::map<std::string, std::string> remapUVSetsTo;

const std::string melPerFrameCallback;
const std::string melPostCallback;
const std::string pythonPerFrameCallback;
Expand Down
28 changes: 19 additions & 9 deletions lib/mayaUsd/fileio/utils/meshWriteUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,10 +938,12 @@ bool UsdMayaMeshWriteUtils::getMeshUVSetData(
}

bool UsdMayaMeshWriteUtils::writeUVSetsAsVec2fPrimvars(
const MFnMesh& meshFn,
UsdGeomMesh& primSchema,
const UsdTimeCode& usdTime,
UsdUtilsSparseValueWriter* valueWriter)
const MFnMesh& meshFn,
UsdGeomMesh& primSchema,
const UsdTimeCode& usdTime,
UsdUtilsSparseValueWriter* valueWriter,
bool preserveSetNames,
const std::map<std::string, std::string>& uvSetRemaps)
{
MStatus status { MS::kSuccess };

Expand All @@ -963,10 +965,18 @@ bool UsdMayaMeshWriteUtils::writeUVSetsAsVec2fPrimvars(
continue;
}

// All UV sets now get renamed st, st1, st2 in the order returned by getUVSetNames
MString setName("st");
if (i) {
setName += i;
MString setName(uvSetNames[i]);

auto it = uvSetRemaps.find(setName.asChar());
if (it != uvSetRemaps.end()) {
// Remap the UV set as specified
setName = it->second.c_str();
} else if (!preserveSetNames) {
// UV sets get renamed st, st1, st2 in the order returned by getUVSetNames
setName = "st";
if (i) {
setName += i;
}
}

// create UV PrimVar
Expand All @@ -980,7 +990,7 @@ bool UsdMayaMeshWriteUtils::writeUVSetsAsVec2fPrimvars(
valueWriter);

// Save the original name for roundtripping:
if (primVar) {
if (primVar && (setName != uvSetNames[i])) {
UsdMayaRoundTripUtil::SetPrimVarMayaName(
primVar.GetAttr(), TfToken(uvSetNames[i].asChar()));
}
Expand Down
10 changes: 6 additions & 4 deletions lib/mayaUsd/fileio/utils/meshWriteUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,12 @@ bool getMeshUVSetData(

MAYAUSD_CORE_PUBLIC
bool writeUVSetsAsVec2fPrimvars(
const MFnMesh& meshFn,
UsdGeomMesh& primSchema,
const UsdTimeCode& usdTime,
UsdUtilsSparseValueWriter* valueWriter);
const MFnMesh& meshFn,
UsdGeomMesh& primSchema,
const UsdTimeCode& usdTime,
UsdUtilsSparseValueWriter* valueWriter,
bool preserveSetNames,
const std::map<std::string, std::string>& uvSetRemaps);

MAYAUSD_CORE_PUBLIC
void writeSubdivInterpBound(
Expand Down
11 changes: 11 additions & 0 deletions lib/mayaUsd/python/wrapPrimWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,15 @@ boost::python::object get_allChaserArgs(UsdMayaJobExportArgs& self)
return boost::python::object(allChaserArgs);
}

boost::python::object get_remapUVSetsTo(UsdMayaJobExportArgs& self)
{
boost::python::dict uvSetRemaps;
for (auto&& remap : self.remapUVSetsTo) {
uvSetRemaps[remap.first] = remap.second;
}
return boost::python::object(uvSetRemaps);
}

// This class is used to expose protected members of UsdMayaPrimWriter to Python
class PrimWriterAllowProtected : public UsdMayaPrimWriter
{
Expand Down Expand Up @@ -487,6 +496,7 @@ void wrapJobExportArgs()
"convertMaterialsTo",
make_getter(
&UsdMayaJobExportArgs::convertMaterialsTo, return_value_policy<return_by_value>()))
.add_property("remapUVSetsTo", ::get_remapUVSetsTo)
//.add_property("dagPaths", requires exporting UsdMayaUtil::MDagPathSet)
.add_property(
"defaultMeshScheme",
Expand Down Expand Up @@ -549,6 +559,7 @@ void wrapJobExportArgs()
.def_readonly("melPostCallback", &UsdMayaJobExportArgs::melPostCallback)
.def_readonly("mergeTransformAndShape", &UsdMayaJobExportArgs::mergeTransformAndShape)
.def_readonly("normalizeNurbs", &UsdMayaJobExportArgs::normalizeNurbs)
.def_readonly("preserveUVSetNames", &UsdMayaJobExportArgs::preserveUVSetNames)
.add_property(
"parentScope",
make_getter(&UsdMayaJobExportArgs::parentScope, return_value_policy<return_by_value>()))
Expand Down
7 changes: 6 additions & 1 deletion lib/usd/translators/meshWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,12 @@ bool PxrUsdTranslators_MeshWriter::writeMeshAttrs(
// == Write UVSets as Vec2f Primvars
if (exportArgs.exportMeshUVs) {
UsdMayaMeshWriteUtils::writeUVSetsAsVec2fPrimvars(
finalMesh, primSchema, usdTime, _GetSparseValueWriter());
finalMesh,
primSchema,
usdTime,
_GetSparseValueWriter(),
exportArgs.preserveUVSetNames,
exportArgs.remapUVSetsTo);
}

// == Gather ColorSets
Expand Down
Loading