-
Notifications
You must be signed in to change notification settings - Fork 202
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-104213 - add a new USD stage to an empty scene #478
Changes from all commits
698cbc9
6a0f1f2
c5bc21d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -496,6 +496,11 @@ MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
|
||
usdStage->SetEditTarget(usdStage->GetSessionLayer()); | ||
} | ||
else if (!usdStage) { | ||
// Create a new stage in memory with an anonymous root layer. | ||
UsdStageCacheContext ctx(UsdMayaStageCache::Get()); | ||
usdStage = UsdStage::CreateInMemory("", loadSet); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The empty string is for the identifier, which is used when naming the root layer. Here we just want it named as the default "anon", rather than "tmp.usda" |
||
} | ||
|
||
if (usdStage) { | ||
primPath = usdStage->GetPseudoRoot().GetPath(); | ||
|
@@ -621,7 +626,7 @@ MayaUsdProxyShapeBase::computeOutStageData(MDataBlock& dataBlock) | |
this, | ||
std::placeholders::_1)); | ||
|
||
UsdMayaProxyStageSetNotice(*this).Send(); | ||
MayaUsdProxyStageSetNotice(*this).Send(); | ||
|
||
return MS::kSuccess; | ||
} | ||
|
@@ -797,6 +802,7 @@ MayaUsdProxyShapeBase::setDependentsDirty(const MPlug& plug, MPlugArray& plugArr | |
plug == loadPayloadsAttr || | ||
plug == inStageDataAttr) { | ||
_IncreaseUsdStageVersion(); | ||
MayaUsdProxyStageInvalidateNotice(*this).Send(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Send the new stage invalidate notice whenever one of the plugs that affects outStageDataAttr changes. |
||
} | ||
|
||
return MPxSurfaceShape::setDependentsDirty(plug, plugArray); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
#include <mayaUsd/ufe/ProxyShapeHandler.h> | ||
#include <mayaUsd/ufe/UsdStageMap.h> | ||
#include <mayaUsd/ufe/Utils.h> | ||
#include <mayaUsd/nodes/proxyShapeBase.h> | ||
|
||
#include "private/InPathChange.h" | ||
|
||
|
@@ -100,6 +101,7 @@ StagesSubject::StagesSubject() | |
|
||
TfWeakPtr<StagesSubject> me(this); | ||
TfNotice::Register(me, &StagesSubject::onStageSet); | ||
TfNotice::Register(me, &StagesSubject::onStageInvalidate); | ||
} | ||
|
||
StagesSubject::~StagesSubject() | ||
|
@@ -170,29 +172,15 @@ void StagesSubject::afterOpen() | |
// frequent, we won't implement this for now. PPT, 22-Dec-2017. | ||
std::for_each(std::begin(fStageListeners), std::end(fStageListeners), | ||
[](StageListenerMap::value_type element) { TfNotice::Revoke(element.second); } ); | ||
|
||
StagesSubject::Ptr me(this); | ||
for (auto stage : ProxyShapeHandler::getAllStages()) | ||
{ | ||
fStageListeners[stage] = TfNotice::Register( | ||
me, &StagesSubject::stageChanged, stage); | ||
} | ||
Comment on lines
-174
to
-179
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should not get the stages here as that will pull, but the new stage may not be ready yet. |
||
fStageListeners.clear(); | ||
|
||
// Set up our stage to proxy shape UFE path (and reverse) | ||
// mapping. We do this with the following steps: | ||
// - get all proxyShape nodes in the scene. | ||
// - get their Dag paths. | ||
// - convert the Dag paths to UFE paths. | ||
// - get their stage. | ||
g_StageMap.clear(); | ||
auto proxyShapeNames = ProxyShapeHandler::getAllNames(); | ||
for (const auto& psn : proxyShapeNames) | ||
{ | ||
MDagPath dag = nameToDagPath(psn); | ||
Ufe::Path ufePath = dagPathToUfe(dag); | ||
auto stage = ProxyShapeHandler::dagPathToStage(psn); | ||
g_StageMap.addItem(ufePath, stage); | ||
} | ||
Comment on lines
-187
to
-195
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All this code was moved into the stage map. We just set it dirty now. It will be rebuilt when queried. |
||
g_StageMap.setDirty(); | ||
} | ||
|
||
void StagesSubject::stageChanged(UsdNotice::ObjectsChanged const& notice, UsdStageWeakPtr const& sender) | ||
|
@@ -277,9 +265,29 @@ void StagesSubject::stageChanged(UsdNotice::ObjectsChanged const& notice, UsdSta | |
} | ||
} | ||
|
||
void StagesSubject::onStageSet(const UsdMayaProxyStageSetNotice& notice) | ||
void StagesSubject::onStageSet(const MayaUsdProxyStageSetNotice& notice) | ||
{ | ||
// We should have no listerners and stage map is dirty. | ||
TF_VERIFY(g_StageMap.isDirty()); | ||
TF_VERIFY(fStageListeners.empty()); | ||
|
||
StagesSubject::Ptr me(this); | ||
for (auto stage : ProxyShapeHandler::getAllStages()) | ||
{ | ||
fStageListeners[stage] = TfNotice::Register( | ||
me, &StagesSubject::stageChanged, stage); | ||
} | ||
Comment on lines
+274
to
+279
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we get the stage set notice is when we can register. The stage(s) is(are) valid at this point. |
||
} | ||
|
||
void StagesSubject::onStageInvalidate(const MayaUsdProxyStageInvalidateNotice& notice) | ||
{ | ||
afterOpen(); | ||
|
||
#if UFE_PREVIEW_VERSION_NUM >= 2014 | ||
Ufe::SceneItem::Ptr sceneItem = Ufe::Hierarchy::createItem(notice.GetProxyShape().ufePath()); | ||
auto notification = Ufe::SubtreeInvalidate(sceneItem); | ||
Ufe::Scene::notifySubtreeInvalidate(notification); | ||
#endif | ||
Comment on lines
+286
to
+290
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Send a new UFE subtree invalidate notice when the stage is invalidated. Clients like the Outliner can use this to re-build. |
||
} | ||
|
||
#ifdef UFE_V2_FEATURES_AVAILABLE | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
|
||
#include <maya/MFnDagNode.h> | ||
|
||
#include <mayaUsd/ufe/ProxyShapeHandler.h> | ||
#include <mayaUsd/ufe/Utils.h> | ||
|
||
namespace { | ||
|
@@ -92,8 +93,10 @@ void UsdStageMap::addItem(const Ufe::Path& path, UsdStageWeakPtr stage) | |
fStageToObject[stage] = proxyShape; | ||
} | ||
|
||
UsdStageWeakPtr UsdStageMap::stage(const Ufe::Path& path) const | ||
UsdStageWeakPtr UsdStageMap::stage(const Ufe::Path& path) | ||
{ | ||
rebuildIfDirty(); | ||
Comment on lines
+96
to
+98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the query methods on the stage map, will now rebuild first if the map is flagged as dirty. |
||
|
||
auto proxyShape = proxyShapeHandle(path); | ||
if (!proxyShape.isValid()) { | ||
return nullptr; | ||
|
@@ -106,19 +109,37 @@ UsdStageWeakPtr UsdStageMap::stage(const Ufe::Path& path) const | |
return nullptr; | ||
} | ||
|
||
Ufe::Path UsdStageMap::path(UsdStageWeakPtr stage) const | ||
Ufe::Path UsdStageMap::path(UsdStageWeakPtr stage) | ||
{ | ||
rebuildIfDirty(); | ||
|
||
// A stage is bound to a single Dag proxy shape. | ||
auto iter = fStageToObject.find(stage); | ||
if (iter != std::end(fStageToObject)) | ||
return firstPath(iter->second); | ||
return Ufe::Path(); | ||
} | ||
|
||
void UsdStageMap::clear() | ||
void UsdStageMap::setDirty() | ||
{ | ||
fObjectToStage.clear(); | ||
fStageToObject.clear(); | ||
fDirty = true; | ||
} | ||
|
||
void UsdStageMap::rebuildIfDirty() | ||
{ | ||
if (!fDirty) return; | ||
|
||
auto proxyShapeNames = ProxyShapeHandler::getAllNames(); | ||
for (const auto& psn : proxyShapeNames) | ||
{ | ||
MDagPath dag = nameToDagPath(psn); | ||
Ufe::Path ufePath = dagPathToUfe(dag); | ||
auto stage = ProxyShapeHandler::dagPathToStage(psn); | ||
addItem(ufePath, stage); | ||
} | ||
Comment on lines
+134
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code was moved from the StagesSubject. |
||
fDirty = false; | ||
} | ||
|
||
} // namespace ufe | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,6 +58,15 @@ proc removeMenuCallback(string $menuName, string $cmd) { | |
// initRuntimeCommands | ||
// create all the runtime commands we'll use and the user can map to hotkeys | ||
proc initRuntimeCommands() { | ||
if (!`runTimeCommand -exists mayaUsdCreateStageWithNewLayer`) { | ||
runTimeCommand -default true | ||
-label "Stage with New Layer" | ||
-annotation "Create a new, empty USD Stage" | ||
-category "Menu items.Maya USD" | ||
-command "python(\"import mayaUsd_createStageWithNewLayer; mayaUsd_createStageWithNewLayer.createStageWithNewLayer()\")" | ||
mayaUsdCreateStageWithNewLayer; | ||
} | ||
|
||
if (!`runTimeCommand -exists mayaUsdCreateStageFromFile`) { | ||
runTimeCommand -default true | ||
-label "Stage From File..." | ||
|
@@ -103,6 +112,7 @@ global proc mayaUsdMenu_createMenuCallback() { | |
-label "Universal Scene Description (USD)" | ||
-annotation "Create a USD stage" | ||
-version $mayaVersion`; | ||
menuItem -runTimeCommand mayaUsdCreateStageWithNewLayer; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New menu item to create a new empty USD stage. |
||
menuItem -runTimeCommand mayaUsdCreateStageFromFile; | ||
menuItem -runTimeCommand mayaUsdCreateStageFromFileOptions -optionBox true; | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# 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 maya.cmds as cmds | ||
|
||
def createStageWithNewLayer(): | ||
"""For use in aggregating USD (Assembly) and creating layer structures (Layout) | ||
users need to be able to create a new empty stage. | ||
|
||
Executing this command should produce the following: | ||
- Proxyshape | ||
- Stage | ||
- Session Layer | ||
- Anonymous Root Layer (this is set as the target layer) | ||
""" | ||
|
||
# Simply create a proxy shape. Since it does not have a USD file associated | ||
# (in the .filePath attribute), the proxy shape base will create an empty | ||
# stage in memory. This will create the session and root layer as well. | ||
shapeNode = cmds.createNode('mayaUsdProxyShape', name='stageShape') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because of the changes in the proxyshapebase (to create stage in memory when no file attr) we simply need to create a proxy shape node here. That will create the stage, which will create the root layer and session layer. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -398,6 +398,18 @@ MStatus ProxyShape::setDependentsDirty(const MPlug& plugBeingDirtied, MPlugArray | |
{ | ||
MHWRender::MRenderer::setGeometryDrawDirty(thisMObject(), true); | ||
} | ||
|
||
if (plugBeingDirtied == outStageData() || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ProxyShapeBase is a base class...shouldn't we just forward it to the base class instead of making a copy? |
||
// All the plugs that affect outStageDataAttr | ||
plugBeingDirtied == filePath() || | ||
plugBeingDirtied == primPath() || | ||
plugBeingDirtied == m_populationMaskIncludePaths || | ||
plugBeingDirtied == m_stageDataDirty || | ||
plugBeingDirtied == m_assetResolverConfig) | ||
{ | ||
MayaUsdProxyStageInvalidateNotice(*this).Send(); | ||
} | ||
|
||
return MPxSurfaceShape::setDependentsDirty(plugBeingDirtied, plugs); | ||
} | ||
|
||
|
@@ -1432,7 +1444,7 @@ MStatus ProxyShape::computeOutStageData(const MPlug& plug, MDataBlock& dataBlock | |
return MS::kFailure; | ||
} | ||
|
||
UsdMayaProxyStageSetNotice(*this).Send(); | ||
MayaUsdProxyStageSetNotice(*this).Send(); | ||
|
||
return status; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed this one "UsdMaya" -> "MayaUsd" and made it a base notice class. Below created this existing one (deriving from this base) and new one for stage invalidate.