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-126179 merge-to-USD into variants #2764

Merged
merged 3 commits into from
Dec 13, 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
18 changes: 15 additions & 3 deletions lib/mayaUsd/fileio/orphanedNodesManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ OrphanedNodesManager::Memento OrphanedNodesManager::remove(const Ufe::Path& pull
return oldPulledPrims;
}

const PullVariantInfo& OrphanedNodesManager::get(const Ufe::Path& pulledPath) const
{
const auto infoNode = pulledPrims().find(pulledPath);
if (!infoNode || !infoNode->hasData()) {
static const PullVariantInfo empty;
return empty;
}

return infoNode->data();
}

void OrphanedNodesManager::operator()(const Ufe::Notification& n)
{
const auto& sceneNotification = static_cast<const Ufe::SceneChanged&>(n);
Expand Down Expand Up @@ -521,9 +532,10 @@ void OrphanedNodesManager::recursiveSwitch(
// tree state don't match, the pulled node must be made invisible.
// Inactivation must not be considered, as the USD pulled node is made
// inactive on pull, to avoid rendering it.
const bool variantSetsMatch
= (trieNode->data().variantSetDescriptors == variantSetDescriptors(ufePath.pop()));
const bool orphaned = (pulledNode && !variantSetsMatch);
const auto& originalDesc = trieNode->data().variantSetDescriptors;
const auto currentDesc = variantSetDescriptors(ufePath.pop());
const bool variantSetsMatch = (originalDesc == currentDesc);
const bool orphaned = (pulledNode && !variantSetsMatch);
TF_VERIFY(setOrphaned(trieNode, orphaned));
} else {
const bool isGatewayToUsd = Ufe::SceneSegmentHandler::isGateway(ufePath);
Expand Down
4 changes: 4 additions & 0 deletions lib/mayaUsd/fileio/orphanedNodesManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ class OrphanedNodesManager : public Ufe::Observer
// purposes, to be used as argument to restore().
Memento remove(const Ufe::Path& pulledPath);

// Retrieve the variant information of a pulled prim.
// Returns an empty info if the prim was not tracked by the orphan manager.
const PullVariantInfo& get(const Ufe::Path& pulledPath) const;

// Preserve the trie of pulled prims into a memento.
Memento preserve() const;

Expand Down
39 changes: 23 additions & 16 deletions lib/mayaUsd/fileio/primUpdaterManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,11 +648,12 @@ bool pushCustomize(

MayaUsd::ProgressBarScope progressBar(2);

const bool isCopy = context.GetArgs()._copyOperation;
const auto& editTarget = context.GetUsdStage()->GetEditTarget();
auto dstRootPath = editTarget.MapToSpecPath(getDstSdfPath(ufePulledPath, srcRootPath, isCopy));
auto dstRootParentPath = dstRootPath.GetParentPath();
const auto& dstLayer = editTarget.GetLayer();
const bool isCopy = context.GetArgs()._copyOperation;
const UsdEditTarget& editTarget = context.GetUsdStage()->GetEditTarget();
const SdfPath dstPath = getDstSdfPath(ufePulledPath, srcRootPath, isCopy);
const SdfPath dstRootPath = editTarget.MapToSpecPath(dstPath);
const SdfPath dstRootParentPath = dstRootPath.GetParentPath();
const SdfLayerHandle& dstLayer = editTarget.GetLayer();

// Traverse the layer, creating a prim updater for each primSpec
// along the way, and call PushCopySpec on the prim.
Expand Down Expand Up @@ -980,6 +981,20 @@ bool PrimUpdaterManager::mergeToUsd(
scene.notify(Ufe::ObjectPreDelete(ufeMayaItem));
progressBar.advance();

// Remove the pulled path from the orphan node manager *before* exporting
// and merging into the original USD. Otherwise, the orphan manager can
// receive notification mid-way through the merge process, while the variants
// have not all been authored and think the variant set has changed back
// to the correct variant and thus decide to deactivate the USD prim again,
// thinking the Maya data shoudl be shown again...
#ifdef HAS_ORPHANED_NODES_MANAGER
if (_orphanedNodesManager) {
if (!TF_VERIFY(RemovePullVariantInfoUndoItem::execute(_orphanedNodesManager, pulledPath))) {
return false;
}
}
#endif

// Record all USD modifications in an undo block and item.
UsdUndoBlock undoBlock(
&UsdUndoableItemUndoItem::create("Merge to Maya USD data modifications"));
Expand Down Expand Up @@ -1138,7 +1153,9 @@ bool PrimUpdaterManager::editAsMaya(const Ufe::Path& path, const VtDictionary& u
progressBar.advance();

#ifdef HAS_ORPHANED_NODES_MANAGER
RecordPullVariantInfoUndoItem::execute(_orphanedNodesManager, path, importedPaths.first[0]);
if (_orphanedNodesManager) {
RecordPullVariantInfoUndoItem::execute(_orphanedNodesManager, path, importedPaths.first[0]);
}
#endif

if (!updaterArgs._copyOperation) {
Expand Down Expand Up @@ -1657,16 +1674,6 @@ bool PrimUpdaterManager::removePullParent(
return false;
}

#ifdef HAS_ORPHANED_NODES_MANAGER
if (!TF_VERIFY(_orphanedNodesManager)) {
return false;
}

if (!TF_VERIFY(RemovePullVariantInfoUndoItem::execute(_orphanedNodesManager, pulledPath))) {
return false;
}
#endif

MayaUsd::ProgressBarScope progressBar(2);
MStatus status = NodeDeletionUndoItem::deleteNode(
"Delete pull parent node", parentDagPath.fullPathName(), parentDagPath.node());
Expand Down
12 changes: 7 additions & 5 deletions lib/mayaUsd/fileio/utils/orphanedNodesManagerUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <ufe/trie.imp.h>

namespace MAYAUSD_NS_DEF {
namespace utils {

namespace {

Expand Down Expand Up @@ -59,6 +60,8 @@ void toText(std::string& buf, const char* pfix, const Ufe::Path& ufePath, int in
toText(buf, pfix, ufePath.string(), indent, eol);
}

} // namespace

void toText(std::string& buf, const VariantSelection& sel, int indent, bool eol)
{
toText(buf, "Variant ", sel.variantSetName, indent, eol);
Expand Down Expand Up @@ -92,9 +95,7 @@ void toText(std::string& buf, const PullVariantInfo& variantInfo, int indent, bo
toText(buf, "", "}", indent, eol);
}

} // namespace

void orphanedNodesManagerPullInfoToText(
void toText(
std::string& buffer,
const Ufe::TrieNode<PullVariantInfo>::Ptr& trieNode,
int indent,
Expand All @@ -112,7 +113,7 @@ void orphanedNodesManagerPullInfoToText(
}

for (const auto& childComp : node.childrenComponents()) {
orphanedNodesManagerPullInfoToText(buffer, node[childComp], indent + 1, eol);
toText(buffer, node[childComp], indent + 1, eol);
}

if (eol)
Expand All @@ -125,8 +126,9 @@ void printOrphanedNodesManagerPullInfo(
bool eol)
{
std::string buffer("Trie ==========================================\n");
orphanedNodesManagerPullInfoToText(buffer, trieNode, indent, eol);
toText(buffer, trieNode, indent, eol);
MGlobal::displayInfo(buffer.c_str());
}

} // namespace utils
} // namespace MAYAUSD_NS_DEF
22 changes: 21 additions & 1 deletion lib/mayaUsd/fileio/utils/orphanedNodesManagerUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,27 @@
#include <mayaUsd/fileio/orphanedNodesManager.h>

namespace MAYAUSD_NS_DEF {
namespace utils {

void orphanedNodesManagerPullInfoToText(
void toText(
std::string& buf,
const OrphanedNodesManager::VariantSelection& sel,
int indent = 0,
bool eol = true);

void toText(
std::string& buf,
const OrphanedNodesManager::VariantSetDescriptor& descriptor,
int indent = 0,
bool eol = true);

void toText(
std::string& buf,
const OrphanedNodesManager::PullVariantInfo& variantInfo,
int indent,
bool eol);

void toText(
std::string& buffer,
const Ufe::TrieNode<OrphanedNodesManager::PullVariantInfo>::Ptr& trieNode,
int indent = 0,
Expand All @@ -31,4 +50,5 @@ void printOrphanedNodesManagerPullInfo(
int indent = 0,
bool eol = true);

} // namespace utils
} // namespace MAYAUSD_NS_DEF
2 changes: 1 addition & 1 deletion lib/mayaUsd/resources/scripts/mayaUsdMergeToUsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def createMayaReferenceMenuItem(dagPath, precedingItem):
# If the pulled prim doesn't exist anymore, we won't delegate the reponsibility to
# another creator and handle the menu item in here. We already have all the information
# available.
if prim:
if prim and prim.IsDefined():
# If the pulled prim isn't a MayaReference, not our responsibility.
if prim.GetTypeName() != 'MayaReference':
return ''
Expand Down
1 change: 1 addition & 0 deletions lib/mayaUsd/utils/editRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ void copyTransform(
// attribute edits over to the Maya reference prim.
MayaUsdUtils::MergePrimsOptions options;
options.ignoreUpperLayerOpinions = false;
options.ignoreVariants = true;
TF_VERIFY(MayaUsdUtils::mergePrims(
srcStage, srcLayer, srcSdfPath, dstStage, dstLayer, dstSdfPathForMerge, options));
}
Expand Down
4 changes: 2 additions & 2 deletions lib/usd/utils/DiffMetadatas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ std::unordered_set<TfToken, TfToken::HashFunctor>& getIgnoredMetadata()
PXR_NS::SdfFieldKeys->SubLayers, // List of sub-layers names, we should not to deal with this when merging.
PXR_NS::SdfFieldKeys->SubLayerOffsets, // Time offset and scaling for the sub-layers. We treat animation data at the level it is already applied.
PXR_NS::SdfFieldKeys->TypeName, // Property data type. We should not have to copy this over by hand.
PXR_NS::SdfFieldKeys->VariantSetNames, // The merge/copy process will take care of copying the selected variant.
PXR_NS::SdfFieldKeys->VariantSelection, // The merge/copy process will take care of copying the selected variant.
});

// These other build-in metadata are allowed to be compared and merged:
Expand Down Expand Up @@ -92,6 +90,8 @@ std::unordered_set<TfToken, TfToken::HashFunctor>& getIgnoredMetadata()
// SdfFieldKeys->SymmetryFunction, // Property symmetry. (No docs)
// SdfFieldKeys->TimeCodesPerSecond, // Time code per second for playback (TCPS is advisory)
// SdfFieldKeys->Variability, // Control if the property can be animated.
// SdfFieldKeys->VariantSetNames, // The merge/copy process will take care of copying the selected variant.
// SdfFieldKeys->VariantSelection, // The merge/copy process will take care of copying the selected variant.
// clang-format on
return ignored;
}
Expand Down
78 changes: 72 additions & 6 deletions lib/usd/utils/MergePrims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <pxr/base/tf/stringUtils.h>
#include <pxr/usd/sdf/copyUtils.h>
#include <pxr/usd/usd/editContext.h>
#include <pxr/usd/usd/variantSets.h>
#include <pxr/usd/usdGeom/xformCommonAPI.h>

#include <algorithm>
Expand Down Expand Up @@ -383,8 +384,10 @@ bool isDataAtPathsModified(
{
DiffResult quickDiff = DiffResult::Same;

UsdPrim srcPrim = ctx.srcStage->GetPrimAtPath(src.path.GetPrimPath());
UsdPrim dstPrim = ctx.dstStage->GetPrimAtPath(dst.path.GetPrimPath());
UsdPrim srcPrim
= ctx.srcStage->GetPrimAtPath(src.path.GetPrimPath().StripAllVariantSelections());
UsdPrim dstPrim
= ctx.dstStage->GetPrimAtPath(dst.path.GetPrimPath().StripAllVariantSelections());
if (!srcPrim.IsValid() || !dstPrim.IsValid()) {
printInvalidField(ctx, src, "prim", srcPrim.IsValid(), dstPrim.IsValid());
return srcPrim.IsValid() != dstPrim.IsValid();
Expand Down Expand Up @@ -940,6 +943,57 @@ void createMissingParents(const SdfLayerRefPtr& dstLayer, const SdfPath& dstPath
SdfJustCreatePrimInLayer(dstLayer, dstPath.GetParentPath());
}

//----------------------------------------------------------------------------------------------------------------------
// Augment a USD SdfPath with the variants selections currently active at all levels.
std::pair<SdfPath, UsdEditTarget> augmentPathWithVariants(
const UsdStageRefPtr& stage,
const SdfLayerRefPtr& layer,
const SdfPath& path)
{
SdfPath pathWithVariants;
UsdEditTarget target = stage->GetEditTarget();

SdfPathVector rootToLeaf;
path.GetPrefixes(&rootToLeaf);
for (const SdfPath& prefix : rootToLeaf) {
if (pathWithVariants.IsEmpty()) {
pathWithVariants = prefix;
} else {
pathWithVariants = pathWithVariants.AppendChild(prefix.GetNameToken());
}

const UsdPrim prim = stage->GetPrimAtPath(prefix.StripAllVariantSelections());
if (prim.IsValid()) {
UsdVariantSets variants = prim.GetVariantSets();
for (const std::string& setName : variants.GetNames()) {
UsdVariantSet varSet = variants.GetVariantSet(setName);
pathWithVariants = pathWithVariants.AppendVariantSelection(
varSet.GetName(), varSet.GetVariantSelection());
}
}
}

// Note: any trailing variant selection must be used to create a UsdEditContext,
// it must not be part of the destination path, otherwise SdfCopySpec()
// will fail: it does not handle destination paths ending with a variant
// selection correctly.
//
// If SdfCopySpec() is called with a path ending with a variant selection,
// it assumes that it is inside its own iterations, about to add the
// selection name even though what is about to be added is a prim. So
// The GetParentPath() called in CreateSpec() in usd/sdf/childrenUtils.cpp
// around line 108 will strip the variant selection instead of stripping
// the prim (including variant selection). That will end-up causing an
// error when trying to create a field in SdfData::_GetOrCreateFieldValue
// in usd\sdf\data.cpp around line 260.
if (pathWithVariants.IsPrimVariantSelectionPath()) {
target = target.ForLocalDirectVariant(layer, pathWithVariants);
pathWithVariants = pathWithVariants.GetPrimPath();
}

return std::make_pair(pathWithVariants, target);
}

} // namespace

//----------------------------------------------------------------------------------------------------------------------
Expand All @@ -957,23 +1011,35 @@ bool mergePrims(
const SdfPath& dstPath,
const MergePrimsOptions& options)
{
createMissingParents(dstLayer, dstPath);
SdfPath augmentedDstPath = dstPath;
UsdEditTarget target = dstStage->GetEditTarget();

if (!options.ignoreVariants) {
const auto pathAndTarget = augmentPathWithVariants(dstStage, dstLayer, dstPath);
augmentedDstPath = pathAndTarget.first;
target = pathAndTarget.second;
}

UsdEditContext editCtx(dstStage, target);

createMissingParents(dstLayer, augmentedDstPath);

if (options.ignoreUpperLayerOpinions) {
auto tempStage = UsdStage::CreateInMemory();
SdfLayerHandle tempLayer = tempStage->GetSessionLayer();

tempLayer->TransferContent(dstLayer);

const bool success
= mergeDiffPrims(options, srcStage, srcLayer, srcPath, tempStage, tempLayer, dstPath);
const bool success = mergeDiffPrims(
options, srcStage, srcLayer, srcPath, tempStage, tempLayer, augmentedDstPath);

if (success)
dstLayer->TransferContent(tempLayer);

return success;
} else {
return mergeDiffPrims(options, srcStage, srcLayer, srcPath, dstStage, dstLayer, dstPath);
return mergeDiffPrims(
options, srcStage, srcLayer, srcPath, dstStage, dstLayer, augmentedDstPath);
}
}

Expand Down
4 changes: 4 additions & 0 deletions lib/usd/utils/MergePrimsOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ struct MergePrimsOptions
// if true, merges children too, otherwise merge only the given prim.
bool mergeChildren { false };

// Ignore variants when building the edit target.
// Used when the destination variants have already been set by the caller.
bool ignoreVariants { false };

// If true, the merge is done in a temporary layer so to ignore opinions
// from upper layers (and children of upper layers).
bool ignoreUpperLayerOpinions { false };
Expand Down
Loading