Skip to content

Commit

Permalink
Merge pull request #3876 from Autodesk/bailp/EMSUSD-1432/dup-materials
Browse files Browse the repository at this point in the history
EMSUSD-1432 duplicate materials without meshes
  • Loading branch information
seando-adsk authored Aug 8, 2024
2 parents b3f8131 + 8a81a37 commit 0e258e8
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 99 deletions.
24 changes: 7 additions & 17 deletions lib/mayaUsd/commands/PullPushCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,9 @@ MStatus DuplicateCommand::doIt(const MArgList& argList)
OpUndoItemRecorder undoRecorder(_undoItemList);

auto& manager = PXR_NS::PrimUpdaterManager::getInstance();
status = manager.duplicate(_srcPath, _dstPath, userArgs) ? MS::kSuccess : MS::kFailure;
auto dstUfePaths = manager.duplicate(_srcPath, _dstPath, userArgs);

if (status == MS::kSuccess) {
if (dstUfePaths.size() > 0) {
// Select the duplicate.
//
// If the duplicate src is Maya, the duplicate child of the
Expand All @@ -463,22 +463,12 @@ MStatus DuplicateCommand::doIt(const MArgList& argList)
// - Maya duplicate to USD: we always duplicate directly under the
// proxy shape, so add a single path component USD path segment.
// - USD duplicate to Maya: no path segment to add.
Ufe::Path childPath;
if (_srcPath.runTimeId() == getMayaRunTimeId()) {
// Maya duplicate to USD
auto ps = Ufe::PathSegment(_srcPath.back(), getUsdRunTimeId(), '/');
childPath = _dstPath.empty() ? ps : _dstPath + ps;
} else {
// USD duplicate to Maya
if (_dstPath.empty()) {
childPath = Ufe::PathString::path("|" + _srcPath.back().string());
} else {
childPath = _dstPath + _srcPath.back();
}
}

const Ufe::Path& childPath = dstUfePaths[0];
auto childItem = Ufe::Hierarchy::createItem(childPath);
if (!childItem)
return MS::kFailure;
Ufe::Selection sn;
sn.append(Ufe::Hierarchy::createItem(childPath));
sn.append(childItem);
// It is appropriate to use the overload that uses the global list,
// as the undo recorder will transfer the items on the global list
// to fUndoItemList.
Expand Down
3 changes: 3 additions & 0 deletions lib/mayaUsd/fileio/jobs/jobArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,12 +361,15 @@ struct UsdMayaJobExportArgs
std::string GetResolvedFileName() const;

// Verify if meshes are exported. (i.e not excluded by excludeExportTypes)
MAYAUSD_CORE_PUBLIC
bool isExportingMeshes() const;

// Verify if cameras are exported. (i.e not excluded by excludeExportTypes)
MAYAUSD_CORE_PUBLIC
bool isExportingCameras() const;

// Verify if lights are exported. (i.e not excluded by excludeExportTypes)
MAYAUSD_CORE_PUBLIC
bool isExportingLights() const;

private:
Expand Down
4 changes: 4 additions & 0 deletions lib/mayaUsd/fileio/jobs/writeJob.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class UsdMaya_WriteJob
MAYAUSD_CORE_PUBLIC
const UsdMayaUtil::MDagPathMap<SdfPath>& GetDagPathToUsdPathMap() const;

// Retrieve all exported material paths.
MAYAUSD_CORE_PUBLIC
const std::vector<SdfPath>& GetMaterialPaths() { return mJobCtx.GetMaterialPaths(); }

private:
/// Begins constructing the USD stage, writing out the values at the default
/// time. Returns \c true if the stage can be created successfully.
Expand Down
144 changes: 87 additions & 57 deletions lib/mayaUsd/fileio/primUpdaterManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,18 +550,27 @@ void fillUserArgsFileIfEmpty(VtDictionary& userArgs, const std::string& fileName
// source SdfPath and SdfLayer for the next step, push customize. The source
// SdfPath will be empty on error.
using UsdPathToDagPathMap = TfHashMap<SdfPath, MDagPath, SdfPath::Hash>;
using UsdPathToDagPathMapPtr = std::shared_ptr<UsdPathToDagPathMap>;
using PushCustomizeSrc
= std::tuple<SdfPath, UsdStageRefPtr, SdfLayerRefPtr, UsdPathToDagPathMapPtr>;
struct PushExportResult
{

SdfPath srcRootPath;
UsdStageRefPtr stage;
SdfLayerRefPtr layer;
std::shared_ptr<UsdPathToDagPathMap> usdToDag;
std::vector<SdfPath> materialPaths;
};

PushCustomizeSrc pushExport(const MObject& mayaObject, const UsdMayaPrimUpdaterContext& context)
PushExportResult pushExport(const MObject& mayaObject, const UsdMayaPrimUpdaterContext& context)
{
MayaUsd::ProgressBarScope progressBar(3);

UsdStageRefPtr srcStage = UsdStage::CreateInMemory();
SdfLayerRefPtr srcLayer = srcStage->GetRootLayer();
UsdPathToDagPathMapPtr pathMapPtr;
auto pushCustomizeSrc = std::make_tuple(SdfPath(), srcStage, srcLayer, pathMapPtr);
UsdStageRefPtr srcStage = UsdStage::CreateInMemory();
SdfLayerRefPtr srcLayer = srcStage->GetRootLayer();

PushExportResult result;
result.srcRootPath = SdfPath();
result.stage = srcStage;
result.layer = srcLayer;

// Copy to be able to add the export root.
VtDictionary userArgs = context.GetUserArgs();
Expand All @@ -582,38 +591,54 @@ PushCustomizeSrc pushExport(const MObject& mayaObject, const UsdMayaPrimUpdaterC
std::vector<double> timeSamples;
UsdMayaJobExportArgs::GetDictionaryTimeSamples(userArgs, timeSamples);

// The pushed Dag node is the root of the export job.
std::vector<VtValue> rootPathString(
1, VtValue(std::string(dagPath.partialPathName().asChar())));
userArgs[UsdMayaJobExportArgsTokens->exportRoots] = rootPathString;

// This ensures the materials will be under the prim, so that
// when exported it is under the node being merged and will thus
// be merged too.
userArgs[UsdMayaJobExportArgsTokens->legacyMaterialScope] = true;
const bool isCopy = context.GetArgs()._copyOperation;
if (isCopy) {
// Make sure legacy material scope mode is off so that all materials
// will be placed under a single parent scope. This important for
// material-only duplication op, so that we have a single root node.
userArgs[UsdMayaJobExportArgsTokens->legacyMaterialScope] = false;
// Make sure we don't have any default prim, otherwise the materials
// would be put under it instead of as a root, which would be weird
// when doing material-only duplications.
userArgs[UsdMayaJobExportArgsTokens->defaultPrim] = "None";
} else {
// The pushed Dag node is the root of the export job.
std::vector<VtValue> rootPathString(
1, VtValue(std::string(dagPath.partialPathName().asChar())));
userArgs[UsdMayaJobExportArgsTokens->exportRoots] = rootPathString;
// Legacy mode ensures the materials will be under the prim, so that
// when exported it is under the node being merged and will thus
// be merged too.
userArgs[UsdMayaJobExportArgsTokens->legacyMaterialScope] = true;
}

UsdMayaJobExportArgs jobArgs = UsdMayaJobExportArgs::CreateFromDictionary(
userArgs, dagPaths, fullObjectList, timeSamples);
progressBar.advance();

UsdMaya_WriteJob writeJob(jobArgs);
if (!writeJob.Write(fileName, false /* append */)) {
return pushCustomizeSrc;
return result;
}
progressBar.advance();

std::get<SdfPath>(pushCustomizeSrc) = writeJob.MapDagPathToSdfPath(dagPath);
result.srcRootPath = writeJob.MapDagPathToSdfPath(dagPath);
if (result.srcRootPath.IsEmpty()) {
for (const SdfPath& matPath : writeJob.GetMaterialPaths()) {
result.srcRootPath = matPath.GetParentPath();
break;
}
}

// Invert the Dag path to USD path map, to return it for prim updater use.
auto usdPathToDagPathMap = std::make_shared<UsdPathToDagPathMap>();
result.usdToDag = std::make_shared<UsdPathToDagPathMap>();
for (const auto& v : writeJob.GetDagPathToUsdPathMap()) {
usdPathToDagPathMap->insert(UsdPathToDagPathMap::value_type(v.second, v.first));
result.usdToDag->insert(UsdPathToDagPathMap::value_type(v.second, v.first));
}

std::get<UsdPathToDagPathMapPtr>(pushCustomizeSrc) = usdPathToDagPathMap;
progressBar.advance();

return pushCustomizeSrc;
return result;
}

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -715,13 +740,13 @@ UsdMayaPrimUpdaterSharedPtr createUpdater(
// for each updater.
bool pushCustomize(
const Ufe::Path& ufePulledPath,
const PushCustomizeSrc& src,
const PushExportResult& exportResult,
const UsdMayaPrimUpdaterContext& context)

{
const auto& srcRootPath = std::get<SdfPath>(src);
const auto& srcLayer = std::get<SdfLayerRefPtr>(src);
const auto& srcStage = std::get<UsdStageRefPtr>(src);
const auto& srcRootPath = exportResult.srcRootPath;
const auto& srcLayer = exportResult.layer;
const auto& srcStage = exportResult.stage;
if (srcRootPath.IsEmpty() || !srcLayer || !srcStage) {
return false;
}
Expand Down Expand Up @@ -1111,21 +1136,22 @@ bool PrimUpdaterManager::mergeToUsd(
// per-prim customization.

// 1) Perform the export to the temporary layer.
auto pushCustomizeSrc = pushExport(depNodeFn.object(), context);
PushExportResult pushExportResult = pushExport(depNodeFn.object(), context);
progressBar.advance();

const auto& srcDagPathMap = std::get<UsdPathToDagPathMapPtr>(pushCustomizeSrc);

if (TF_VERIFY(srcDagPathMap)) {
const auto& srcRootPath = std::get<SdfPath>(pushCustomizeSrc);
const auto dstRootPath = getDstSdfPath(pulledPath, srcRootPath, isCopy);
processPushExtras(context._pushExtras, *srcDagPathMap, srcRootPath, dstRootPath);
if (TF_VERIFY(pushExportResult.usdToDag)) {
const auto dstRootPath = getDstSdfPath(pulledPath, pushExportResult.srcRootPath, isCopy);
processPushExtras(
context._pushExtras,
*pushExportResult.usdToDag,
pushExportResult.srcRootPath,
dstRootPath);
}

// 2) Traverse the in-memory layer, creating a prim updater for each prim,
// and call Push for each updater. Build a new context with the USD path
// to Maya path mapping information.
context.SetUsdPathToDagPathMap(srcDagPathMap);
context.SetUsdPathToDagPathMap(pushExportResult.usdToDag);

if (!isCopy) {
if (!FunctionUndoItem::execute(
Expand All @@ -1141,7 +1167,7 @@ bool PrimUpdaterManager::mergeToUsd(
}
progressBar.advance();

if (!pushCustomize(pulledPath, pushCustomizeSrc, context)) {
if (!pushCustomize(pulledPath, pushExportResult, context)) {
return false;
}
progressBar.advance();
Expand Down Expand Up @@ -1556,7 +1582,7 @@ void PrimUpdaterManager::discardPullSetIfEmpty()
}
}

bool PrimUpdaterManager::duplicate(
std::vector<Ufe::Path> PrimUpdaterManager::duplicate(
const Ufe::Path& srcPath,
const Ufe::Path& dstPath,
const VtDictionary& userArgs)
Expand All @@ -1572,7 +1598,7 @@ bool PrimUpdaterManager::duplicate(
if (srcProxyShape && dstProxyShape == nullptr) {
auto srcPrim = MayaUsd::ufe::ufePathToPrim(srcPath);
if (!srcPrim) {
return false;
return {};
}

MayaUsd::ProgressBarScope progressBar(3, "Duplicating to Maya Data");
Expand All @@ -1593,7 +1619,7 @@ bool PrimUpdaterManager::duplicate(
if (!MayaUsd::ufe::isMayaWorldPath(dstPath) && !dstPath.empty()) {
pullParentPath = MayaUsd::ufe::ufeToDagPath(dstPath);
if (!pullParentPath.isValid()) {
return false;
return {};
}
}
ctxArgs[kPullParentPathKey] = VtValue(std::string(pullParentPath.fullPathName().asChar()));
Expand All @@ -1603,20 +1629,24 @@ bool PrimUpdaterManager::duplicate(
context._pullExtras.initRecursive(Ufe::Hierarchy::createItem(srcPath));
progressBar.advance();

pullImport(srcPath, srcPrim, context);
PullImportPaths importedPaths = pullImport(srcPath, srcPrim, context);
progressBar.advance();

scopeIt.end();
executeAdditionalCommands(context);
progressBar.advance();

return true;
std::vector<Ufe::Path> dstPaths;
for (const auto& dagAndUfe : importedPaths)
dstPaths.push_back(MayaUsd::ufe::dagPathToUfe(dagAndUfe.first));

return dstPaths;
}
// Copy from DG to USD
else if (srcProxyShape == nullptr && dstProxyShape) {
MDagPath dagPath = PXR_NS::UsdMayaUtil::nameToDagPath(Ufe::PathString::string(srcPath));
if (!dagPath.isValid()) {
return false;
return {};
}

MayaUsd::ProgressBarScope progressBar(6, "Duplicating to USD");
Expand All @@ -1643,36 +1673,34 @@ bool PrimUpdaterManager::duplicate(
UsdMayaPrimUpdaterContext context(dstProxyShape->getTime(), dstStage, ctxArgs);

// Export out to a temporary layer.
auto pushExportOutput = pushExport(dagPath.node(), context);
const auto& srcRootPath = std::get<SdfPath>(pushExportOutput);
if (srcRootPath.IsEmpty()) {
return false;
PushExportResult pushExportResult = pushExport(dagPath.node(), context);
if (pushExportResult.srcRootPath.IsEmpty()) {
return {};
}
progressBar.advance();

// Copy the temporary layer contents out to the proper destination.
const auto& srcStage = std::get<UsdStageRefPtr>(pushExportOutput);
const auto& srcLayer = std::get<SdfLayerRefPtr>(pushExportOutput);
const auto& srcStage = pushExportResult.stage;
const auto& srcLayer = pushExportResult.layer;
const auto& editTarget = dstStage->GetEditTarget();
const auto& dstLayer = editTarget.GetLayer();

// Validate that the destination parent prim is valid.
UsdPrim dstParentPrim = MayaUsd::ufe::ufePathToPrim(dstPath);
if (!dstParentPrim.IsValid()) {
return false;
return {};
}
progressBar.advance();

// We need the parent path of the source and destination to
// fixup the paths of the source prims we copy to their
// destination paths.
const SdfPath srcParentPath = srcRootPath.GetParentPath();
const SdfPath srcParentPath = pushExportResult.srcRootPath.GetParentPath();
const SdfPath dstParentPath = dstParentPrim.GetPath();

const auto& srcPathMapPtr = std::get<UsdPathToDagPathMapPtr>(pushExportOutput);

if (TF_VERIFY(srcPathMapPtr)) {
processPushExtras(context._pushExtras, *srcPathMapPtr, srcParentPath, dstParentPath);
if (TF_VERIFY(pushExportResult.usdToDag)) {
processPushExtras(
context._pushExtras, *pushExportResult.usdToDag, srcParentPath, dstParentPath);
}

CopyLayerPrimsOptions options;
Expand All @@ -1685,7 +1713,7 @@ bool PrimUpdaterManager::duplicate(
dstStage,
dstLayer,
dstParentPath,
{ srcRootPath },
{ pushExportResult.srcRootPath },
options);

context._pushExtras.finalize(MayaUsd::ufe::stagePath(dstStage), copyResult.renamedPaths);
Expand All @@ -1700,11 +1728,13 @@ bool PrimUpdaterManager::duplicate(
executeAdditionalCommands(context);
progressBar.advance();

return true;
const Ufe::PathSegment pathSegment
= UsdUfe::usdPathToUfePathSegment(pushExportResult.srcRootPath);
return { Ufe::Path(dstPath + pathSegment) };
}

// Copy operations to the same data model not supported here.
return false;
return {};
}

void PrimUpdaterManager::onProxyContentChanged(
Expand Down
3 changes: 2 additions & 1 deletion lib/mayaUsd/fileio/primUpdaterManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ class PrimUpdaterManager : public PXR_NS::TfWeakBase
bool discardEdits(const MDagPath& dagPath);

/// \brief Copy USD data into USD or Maya data.
/// \return list of destination paths.
MAYAUSD_CORE_PUBLIC
bool duplicate(
std::vector<Ufe::Path> duplicate(
const Ufe::Path& srcPath,
const Ufe::Path& dstPath,
const VtDictionary& userArgs = VtDictionary());
Expand Down
7 changes: 5 additions & 2 deletions lib/mayaUsd/fileio/shading/shadingModeExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,12 @@ void UsdMayaShadingModeExporter::DoExport(
SdfPathSet boundPrimPaths;
Export(context, &mat, &boundPrimPaths);

if (mat && !boundPrimPaths.empty()) {
if (mat) {
writeJobContext.AddMaterialPath(mat.GetPath());
exportedMaterials.push_back(mat);
matAssignments.push_back(std::make_pair(_GetCollectionName(mat), boundPrimPaths));
if (!boundPrimPaths.empty()) {
matAssignments.push_back(std::make_pair(_GetCollectionName(mat), boundPrimPaths));
}
}
shadingEngineLoop.loopAdvance();
}
Expand Down
Loading

0 comments on commit 0e258e8

Please sign in to comment.