Skip to content

Commit

Permalink
EMSUSD-1722 find the correct layer manager node
Browse files Browse the repository at this point in the history
When loading a Maya scene containing a stage, possibly through other Maya
reference, find the correct layer manager node for the stage. Each layer
manager node is specific to the scene or reference.

- Add an optional parameter to some layer manager function to specify
  the Maya reference that should contain the information.
- Pass the correct Maya reference, if any, when computing the proxy
  shape node layers.
- Add a unit test to load a stage in a Maya reference.
  • Loading branch information
pierrebai-adsk committed Oct 17, 2024
1 parent 7c72649 commit 4842fdb
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 25 deletions.
52 changes: 34 additions & 18 deletions lib/mayaUsd/nodes/layerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,16 @@ MStatus disconnectCompoundArrayPlug(MPlug arrayPlug)
return dgmod.doIt();
}

MayaUsd::LayerManager* findNode()
static bool isFromReference(const MFnReference* fromReference, const MFnDependencyNode& node)
{
if (fromReference) {
return fromReference->containsNodeExactly(node.object());
} else {
return !node.isFromReferencedFile();
}
}

MayaUsd::LayerManager* findNode(const MFnReference* fromReference)
{
// Check for cached layer manager before searching
MFnDependencyNode fn;
Expand All @@ -130,17 +139,17 @@ MayaUsd::LayerManager* findNode()
for (; !iter.isDone(); iter.next()) {
MObject mobj = iter.item();
fn.setObject(mobj);
if (fn.typeId() == MayaUsd::LayerManager::typeId && !fn.isFromReferencedFile()) {
if (fn.typeId() == MayaUsd::LayerManager::typeId && isFromReference(fromReference, fn)) {
layerManagerHandle = mobj;
return static_cast<MayaUsd::LayerManager*>(fn.userNode());
}
}
return nullptr;
}

MayaUsd::LayerManager* findOrCreateNode()
MayaUsd::LayerManager* findOrCreateNode(const MFnReference* fromReference)
{
MayaUsd::LayerManager* lm = findNode();
MayaUsd::LayerManager* lm = findNode(fromReference);
if (!lm) {
MDGModifier& modifier = MayaUsd::MDGModifierUndoItem::create("Node find or creation");
MObject manager = modifier.createNode(MayaUsd::LayerManager::typeId);
Expand Down Expand Up @@ -217,7 +226,7 @@ class LayerDatabase : public TfWeakBase
static void cleanupForExport(void*);
static void prepareForWriteCheck(bool*, bool);
static void cleanupForWrite();
static void loadLayersPostRead(void*);
static void loadLayersPostRead(const MFnReference* fromReference);
static void cleanUpNewScene(void*);
static void clearManagerNode(MayaUsd::LayerManager* lm);
static void removeManagerNode(MayaUsd::LayerManager* lm = nullptr);
Expand Down Expand Up @@ -600,7 +609,8 @@ std::string LayerDatabase::getSelectedStage() const { return _selectedStage; }

bool LayerDatabase::saveLayerManagerSelectedStage()
{
MayaUsd::LayerManager* lm = findOrCreateNode();
const MFnReference* fromReference = nullptr;
MayaUsd::LayerManager* lm = findOrCreateNode(fromReference);
if (!lm)
return false;

Expand All @@ -627,7 +637,8 @@ bool LayerDatabase::saveLayerManagerSelectedStage()

bool LayerDatabase::loadLayerManagerSelectedStage()
{
MayaUsd::LayerManager* lm = findNode();
const MFnReference* fromReference = nullptr;
MayaUsd::LayerManager* lm = findNode(fromReference);
if (!lm)
return false;

Expand Down Expand Up @@ -845,7 +856,8 @@ SaveStageToMayaResult saveStageToMayaFile(
SaveStageToMayaResult saveStageToMayaFile(const MObject& proxyNode, UsdStageRefPtr stage)
{
SaveStageToMayaResult result;
MayaUsd::LayerManager* lm = findOrCreateNode();
const MFnReference* fromReference = nullptr;
MayaUsd::LayerManager* lm = findOrCreateNode(fromReference);
if (!lm)
return result;

Expand All @@ -866,7 +878,8 @@ SaveStageToMayaResult saveStageToMayaFile(const MObject& proxyNode, UsdStageRefP

BatchSaveResult LayerDatabase::saveUsdToMayaFile()
{
MayaUsd::LayerManager* lm = findOrCreateNode();
const MFnReference* fromReference = nullptr;
MayaUsd::LayerManager* lm = findOrCreateNode(fromReference);
if (!lm) {
return MayaUsd::kNotHandled;
}
Expand Down Expand Up @@ -1009,7 +1022,8 @@ void LayerDatabase::convertAnonymousLayers(

void LayerDatabase::saveUsdLayerToMayaFile(SdfLayerRefPtr layer, bool asAnonymous)
{
MayaUsd::LayerManager* lm = findOrCreateNode();
const MFnReference* fromReference = nullptr;
MayaUsd::LayerManager* lm = findOrCreateNode(fromReference);
if (!lm)
return;

Expand All @@ -1026,9 +1040,9 @@ void LayerDatabase::saveUsdLayerToMayaFile(SdfLayerRefPtr layer, bool asAnonymou
dataBlock.setClean(lm->layers);
}

void LayerDatabase::loadLayersPostRead(void*)
void LayerDatabase::loadLayersPostRead(const MFnReference* fromReference)
{
MayaUsd::LayerManager* lm = findNode();
MayaUsd::LayerManager* lm = findNode(fromReference);
if (!lm)
return;

Expand Down Expand Up @@ -1267,7 +1281,8 @@ void LayerDatabase::clearManagerNode(MayaUsd::LayerManager* lm)
void LayerDatabase::removeManagerNode(MayaUsd::LayerManager* lm)
{
if (!lm) {
lm = findNode();
const MFnReference* fromReference = nullptr;
lm = findNode(fromReference);
}
if (!lm) {
return;
Expand Down Expand Up @@ -1417,21 +1432,21 @@ LayerManager::LayerManager()
LayerManager::~LayerManager() { }

/* static */
SdfLayerHandle LayerManager::findLayer(std::string identifier)
SdfLayerHandle LayerManager::findLayer(std::string identifier, const MFnReference* fromReference)
{
std::lock_guard<std::recursive_mutex> lock(findNodeMutex);

LayerDatabase::loadLayersPostRead(nullptr);
LayerDatabase::loadLayersPostRead(fromReference);

return LayerDatabase::instance().findLayer(identifier);
}

/* static */
LayerManager::LayerNameMap LayerManager::getLayerNameMap()
LayerManager::LayerNameMap LayerManager::getLayerNameMap(const MFnReference* fromReference)
{
std::lock_guard<std::recursive_mutex> lock(findNodeMutex);

LayerDatabase::loadLayersPostRead(nullptr);
LayerDatabase::loadLayersPostRead(fromReference);

return LayerDatabase::instance().getLayerNameMap();
}
Expand Down Expand Up @@ -1462,7 +1477,8 @@ void LayerManager::setSelectedStage(const std::string& stage)
/* static */
std::string LayerManager::getSelectedStage()
{
LayerDatabase::loadLayersPostRead(nullptr);
const MFnReference* fromReference = nullptr;
LayerDatabase::loadLayersPostRead(fromReference);
return LayerDatabase::instance().getSelectedStage();
}

Expand Down
6 changes: 4 additions & 2 deletions lib/mayaUsd/nodes/layerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <maya/MDagPath.h>
#include <maya/MDagPathArray.h>
#include <maya/MFnReference.h>
#include <maya/MMessage.h>
#include <maya/MObject.h>
#include <maya/MPxNode.h>
Expand Down Expand Up @@ -128,10 +129,11 @@ class MAYAUSD_CORE_PUBLIC LayerManager : public MPxNode
recreated layer, and all sublayers, with edits from a previous Maya session and should be
used to initialize the Proxy Shape in a call to UsdStage::Open().
*/
static SdfLayerHandle findLayer(std::string identifier);
static SdfLayerHandle
findLayer(std::string identifier, const MFnReference* fromReference = nullptr);

using LayerNameMap = std::map<std::string, std::string>;
static LayerNameMap getLayerNameMap();
static LayerNameMap getLayerNameMap(const MFnReference* fromReference = nullptr);

//! \brief returns true if the layer manager is currently saving files.
static bool isSaving();
Expand Down
37 changes: 32 additions & 5 deletions lib/mayaUsd/nodes/proxyShapeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,12 +684,35 @@ MStatus MayaUsdProxyShapeBase::compute(const MPlug& plug, MDataBlock& dataBlock)
return MS::kUnknownParameter;
}

static std::unique_ptr<MFnReference> getMayaReferenceOrigin(const MayaUsdProxyShapeBase& proxyShape)
{
MObject proxyShapeNode(proxyShape.thisMObject());

MStringArray referenceFileNames;
MFileIO::getReferences(referenceFileNames);
for (unsigned int rfni = 0; rfni < referenceFileNames.length(); ++rfni) {
MSelectionList selectionList;
selectionList.add(referenceFileNames[rfni]);
MObject referenceObject;
selectionList.getDependNode(0, referenceObject);
MFnReference mayaRef(referenceObject);

if (mayaRef.containsNode(proxyShapeNode)) {
return std::make_unique<MFnReference>(referenceObject);
}
}

return {};
}

/* virtual */
SdfLayerRefPtr MayaUsdProxyShapeBase::computeRootLayer(MDataBlock& dataBlock, const std::string&)
{
if (LayerManager::supportedNodeType(MPxNode::typeId())) {
auto rootLayerName = dataBlock.inputValue(rootLayerNameAttr).asString();
return LayerManager::findLayer(UsdMayaUtil::convert(rootLayerName));
auto rootLayerName = dataBlock.inputValue(rootLayerNameAttr).asString();
auto mayaRef = getMayaReferenceOrigin(*this);
const MFnReference* fromReference = mayaRef ? mayaRef.get() : nullptr;
return LayerManager::findLayer(UsdMayaUtil::convert(rootLayerName), fromReference);
} else {
return nullptr;
}
Expand All @@ -700,7 +723,9 @@ SdfLayerRefPtr MayaUsdProxyShapeBase::computeSessionLayer(MDataBlock& dataBlock)
{
if (LayerManager::supportedNodeType(MPxNode::typeId())) {
auto sessionLayerName = dataBlock.inputValue(sessionLayerNameAttr).asString();
return LayerManager::findLayer(UsdMayaUtil::convert(sessionLayerName));
auto mayaRef = getMayaReferenceOrigin(*this);
const MFnReference* fromReference = mayaRef ? mayaRef.get() : nullptr;
return LayerManager::findLayer(UsdMayaUtil::convert(sessionLayerName), fromReference);
} else {
return nullptr;
}
Expand Down Expand Up @@ -824,7 +849,9 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock)
UsdStageRefPtr finalUsdStage;
SdfPath primPath;

MayaUsd::LayerNameMap layerNameMap = LayerManager::getLayerNameMap();
auto mayaRef = getMayaReferenceOrigin(*this);
const MFnReference* fromReference = mayaRef ? mayaRef.get() : nullptr;
MayaUsd::LayerNameMap layerNameMap = LayerManager::getLayerNameMap(fromReference);

MDataHandle inDataHandle = dataBlock.inputValue(inStageDataAttr, &retValue);
CHECK_MSTATUS_AND_RETURN_IT(retValue);
Expand All @@ -844,7 +871,7 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock)
VtArray<std::string> updatedReferences;
for (const auto& identifier : referencedLayers) {
// Update the identifier reference in the customer layer data
auto layer = LayerManager::findLayer(identifier);
auto layer = LayerManager::findLayer(identifier, fromReference);
if (layer) {
updatedReferences.push_back(layer->GetIdentifier());
}
Expand Down
1 change: 1 addition & 0 deletions test/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
set(TEST_SCRIPT_FILES
testMayaUsdConverter.py
testMayaUsdCreateStageCommands.py
testMayaUsdCreateStageInMayaRef.py
testMayaUsdDirtyScene.py
testMayaUsdLayerEditorCommands.py
testMayaUsdProxyAccessor.py
Expand Down
103 changes: 103 additions & 0 deletions test/lib/testMayaUsdCreateStageInMayaRef.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env python

#
# Copyright 2020 Autodesk
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import unittest
import os.path

import fixturesUtils
from ufeUtils import ufeFeatureSetVersion

from maya import cmds
from maya import OpenMaya as om
from maya import standalone
import maya.mel as mel

import mayaUsd.lib
import mayaUsd.ufe
import mayaUsd_createStageWithNewLayer


class MayaUsdCreateStageInMayaRefTestCase(unittest.TestCase):
"""
Test reloading a Maya scene that contains a Maya reference which contain a USD stage.
"""

@classmethod
def setUpClass(cls):
fixturesUtils.setUpClass(__file__)
cmds.loadPlugin('mayaUsdPlugin')

@classmethod
def tearDownClass(cls):
standalone.uninitialize()

def testCreateStageInMayaRef(self):
'''
Test reloading a Maya scene that contains a Maya reference which contain a USD stage.
'''
testDir = os.path.join(os.path.abspath('.'),'testMayaUsdCreateStageInMayaRef')

# Note: for some reason, when Maya processes file path for Maya references,
# it really does not like backward slashes on Windows. So make sure
# all paths use forward slashes.
usd_cube_scene = os.path.join(testDir, "cube.usd").replace('\\', '/')
maya_with_usd_ref = os.path.join(testDir, "maya_with_usd_ref.ma").replace('\\', '/')
maya_with_maya_ref = os.path.join(testDir, "maya_with_maya_ref.ma").replace('\\', '/')

# Create a USD scene with a cube
cmds.file(new=True, force=True)
cmds.polyCube(name="cube1")
USD_EXPORT_SETTING = 1
cmds.optionVar(iv=("mayaUsd_SerializedUsdEditsLocation", USD_EXPORT_SETTING))
cmds.file(usd_cube_scene, exportAll=True, force=True, type="USD Export")

# Create a Maya scene with an empty USD stage
cmds.file(new=True, force=True)
proxy_shape = mayaUsd_createStageWithNewLayer.createStageWithNewLayer()
stage = mayaUsd.lib.GetPrim(proxy_shape).GetStage()
self.assertTrue(stage)

# Add a reference to the usd scene with the cube
usdCubePath = "/usd_cube"
ref_prim = stage.DefinePrim(usdCubePath)
self.assertTrue(ref_prim)
ref_prim.GetReferences().AddReference(usd_cube_scene)

# Save the scene
cmds.optionVar(iv=("mayaUsd_SerializedUsdEditsLocation", USD_EXPORT_SETTING))
om.MFileIO.saveAs(maya_with_usd_ref, "mayaAscii")

# Make sure we don't retain references to USD data.
stage = None
ref_prim = None

# Reference the Maya scene in a new scene
namespace = 'my_ref'
cmds.file(new=True, force=True)
cmds.file(maya_with_usd_ref, reference=True, namespace=namespace)
om.MFileIO.saveAs(maya_with_maya_ref, "mayaAscii")

cmds.file(new=True, force=True)
cmds.file(maya_with_maya_ref, open=True)

proxy_shape_in_ref = proxy_shape.replace('|', '|%s:' % namespace)

stage = mayaUsd.lib.GetPrim(proxy_shape_in_ref).GetStage()
self.assertTrue(stage)
ref_prim = stage.DefinePrim(usdCubePath)
self.assertTrue(ref_prim)

0 comments on commit 4842fdb

Please sign in to comment.