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-104213 - add a new USD stage to an empty scene #478

Merged
merged 3 commits into from
May 12, 2020
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
8 changes: 5 additions & 3 deletions lib/mayaUsd/listeners/proxyShapeNotice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@

PXR_NAMESPACE_OPEN_SCOPE

TF_INSTANTIATE_TYPE(UsdMayaProxyStageSetNotice,
TF_INSTANTIATE_TYPE(MayaUsdProxyStageSetNotice,
TfType::CONCRETE, TF_1_PARENT(TfNotice));
TF_INSTANTIATE_TYPE(MayaUsdProxyStageInvalidateNotice,
TfType::CONCRETE, TF_1_PARENT(TfNotice));

UsdMayaProxyStageSetNotice::UsdMayaProxyStageSetNotice(
MayaUsdProxyStageBaseNotice::MayaUsdProxyStageBaseNotice(
const MayaUsdProxyShapeBase& proxy)
: _proxy(proxy)
{
}

const MayaUsdProxyShapeBase&
UsdMayaProxyStageSetNotice::GetProxyShape() const
MayaUsdProxyStageBaseNotice::GetProxyShape() const
{
return _proxy;
}
Expand Down
20 changes: 16 additions & 4 deletions lib/mayaUsd/listeners/proxyShapeNotice.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef USDMAYA_PROXYSTAGE_NOTICE_H
#define USDMAYA_PROXYSTAGE_NOTICE_H
#ifndef MAYAUSD_PROXYSTAGE_NOTICE_H
#define MAYAUSD_PROXYSTAGE_NOTICE_H

#include <maya/MObject.h>

Expand All @@ -27,11 +27,11 @@ PXR_NAMESPACE_OPEN_SCOPE
class MayaUsdProxyShapeBase;

/// Notice sent when the ProxyShape loads a new stage
class UsdMayaProxyStageSetNotice : public TfNotice
class MayaUsdProxyStageBaseNotice : public TfNotice
Copy link
Collaborator Author

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.

{
public:
MAYAUSD_CORE_PUBLIC
UsdMayaProxyStageSetNotice(const MayaUsdProxyShapeBase& proxy);
MayaUsdProxyStageBaseNotice(const MayaUsdProxyShapeBase& proxy);

/// Get proxy shape which had stage set
MAYAUSD_CORE_PUBLIC
Expand All @@ -41,6 +41,18 @@ class UsdMayaProxyStageSetNotice : public TfNotice
const MayaUsdProxyShapeBase& _proxy;
};

class MayaUsdProxyStageSetNotice : public MayaUsdProxyStageBaseNotice
{
public:
using MayaUsdProxyStageBaseNotice::MayaUsdProxyStageBaseNotice;
};

class MayaUsdProxyStageInvalidateNotice : public MayaUsdProxyStageBaseNotice
{
public:
using MayaUsdProxyStageBaseNotice::MayaUsdProxyStageBaseNotice;
};

PXR_NAMESPACE_CLOSE_SCOPE

#endif
8 changes: 7 additions & 1 deletion lib/mayaUsd/nodes/proxyShapeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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();
Expand Down Expand Up @@ -621,7 +626,7 @@ MayaUsdProxyShapeBase::computeOutStageData(MDataBlock& dataBlock)
this,
std::placeholders::_1));

UsdMayaProxyStageSetNotice(*this).Send();
MayaUsdProxyStageSetNotice(*this).Send();

return MS::kSuccess;
}
Expand Down Expand Up @@ -797,6 +802,7 @@ MayaUsdProxyShapeBase::setDependentsDirty(const MPlug& plug, MPlugArray& plugArr
plug == loadPayloadsAttr ||
plug == inStageDataAttr) {
_IncreaseUsdStageVersion();
MayaUsdProxyStageInvalidateNotice(*this).Send();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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);
Expand Down
42 changes: 25 additions & 17 deletions lib/mayaUsd/ufe/StagesSubject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -100,6 +101,7 @@ StagesSubject::StagesSubject()

TfWeakPtr<StagesSubject> me(this);
TfNotice::Register(me, &StagesSubject::onStageSet);
TfNotice::Register(me, &StagesSubject::onStageInvalidate);
}

StagesSubject::~StagesSubject()
Expand Down Expand Up @@ -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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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)
Expand Down Expand Up @@ -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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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
Expand Down
5 changes: 4 additions & 1 deletion lib/mayaUsd/ufe/StagesSubject.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ class MAYAUSD_CORE_PUBLIC StagesSubject : public TfWeakBase

private:
// Notice listener method for proxy stage set
void onStageSet(const UsdMayaProxyStageSetNotice& notice);
void onStageSet(const MayaUsdProxyStageSetNotice& notice);

// Notice listener method for proxy stage invalidate.
void onStageInvalidate(const MayaUsdProxyStageInvalidateNotice& notice);

// Map of per-stage listeners, indexed by stage.
typedef TfHashMap<UsdStageWeakPtr, TfNotice::Key, TfHash> StageListenerMap;
Expand Down
27 changes: 24 additions & 3 deletions lib/mayaUsd/ufe/UsdStageMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <maya/MFnDagNode.h>

#include <mayaUsd/ufe/ProxyShapeHandler.h>
#include <mayaUsd/ufe/Utils.h>

namespace {
Expand Down Expand Up @@ -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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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;
Expand All @@ -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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code was moved from the StagesSubject.

fDirty = false;
}

} // namespace ufe
Expand Down
19 changes: 13 additions & 6 deletions lib/mayaUsd/ufe/UsdStageMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,30 @@ class MAYAUSD_CORE_PUBLIC UsdStageMap
UsdStageMap(UsdStageMap&&) = delete;
UsdStageMap& operator=(UsdStageMap&&) = delete;

//!Add the input Ufe path and USD Stage to the map.
void addItem(const Ufe::Path& path, UsdStageWeakPtr stage);

//! Get USD stage corresponding to argument Maya Dag path.
UsdStageWeakPtr stage(const Ufe::Path& path) const;
UsdStageWeakPtr stage(const Ufe::Path& path);

//! Return the ProxyShape node UFE path for the argument stage.
Ufe::Path path(UsdStageWeakPtr stage) const;
Ufe::Path path(UsdStageWeakPtr stage);

//! Set the stage map as dirty. It will be cleared immediately, but
//! only repopulated when stage info is requested.
void setDirty();

void clear();
//! Returns true if the stage map is dirty (meaning it needs to be filled in).
bool isDirty() const { return fDirty; }

private:
void addItem(const Ufe::Path& path, UsdStageWeakPtr stage);
void rebuildIfDirty();

private:
// We keep two maps for fast lookup when there are many proxy shapes.
using ObjectToStage = std::unordered_map<MObjectHandle, UsdStageWeakPtr>;
using StageToObject = TfHashMap<UsdStageWeakPtr, MObjectHandle, TfHash>;
ObjectToStage fObjectToStage;
StageToObject fStageToObject;
bool fDirty{true};

}; // UsdStageMap

Expand Down
2 changes: 1 addition & 1 deletion lib/usd/hdMaya/adapters/proxyAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void HdMayaProxyAdapter::PreFrame() {
_usdDelegate->PostSyncCleanup();
}

void HdMayaProxyAdapter::_OnStageSet(const UsdMayaProxyStageSetNotice& notice)
void HdMayaProxyAdapter::_OnStageSet(const MayaUsdProxyStageSetNotice& notice)
{
if(&notice.GetProxyShape() == _proxy)
{
Expand Down
2 changes: 1 addition & 1 deletion lib/usd/hdMaya/adapters/proxyAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class HdMayaProxyAdapter : public HdMayaShapeAdapter, public TfWeakBase {

private:
/// Notice listener method for proxy stage set
void _OnStageSet(const UsdMayaProxyStageSetNotice& notice);
void _OnStageSet(const MayaUsdProxyStageSetNotice& notice);

MayaUsdProxyShapeBase* _proxy{ nullptr };
std::unique_ptr<HdMayaProxyUsdImagingDelegate> _usdDelegate;
Expand Down
1 change: 1 addition & 0 deletions plugin/adsk/scripts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ list(APPEND scripts_src
AEmayaUsdProxyShapeTemplate.mel
mayaUsdMenu.mel
mayaUsd_createStageFromFile.mel
mayaUsd_createStageWithNewLayer.py
mayaUsd_createStageFromAsset.mel
)

Expand Down
10 changes: 10 additions & 0 deletions plugin/adsk/scripts/mayaUsdMenu.mel
Original file line number Diff line number Diff line change
Expand Up @@ -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..."
Expand Down Expand Up @@ -103,6 +112,7 @@ global proc mayaUsdMenu_createMenuCallback() {
-label "Universal Scene Description (USD)"
-annotation "Create a USD stage"
-version $mayaVersion`;
menuItem -runTimeCommand mayaUsdCreateStageWithNewLayer;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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 {
Expand Down
32 changes: 32 additions & 0 deletions plugin/adsk/scripts/mayaUsd_createStageWithNewLayer.py
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')
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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.

14 changes: 13 additions & 1 deletion plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,18 @@ MStatus ProxyShape::setDependentsDirty(const MPlug& plugBeingDirtied, MPlugArray
{
MHWRender::MRenderer::setGeometryDrawDirty(thisMObject(), true);
}

if (plugBeingDirtied == outStageData() ||
Copy link

Choose a reason for hiding this comment

The 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);
}

Expand Down Expand Up @@ -1432,7 +1444,7 @@ MStatus ProxyShape::computeOutStageData(const MPlug& plug, MDataBlock& dataBlock
return MS::kFailure;
}

UsdMayaProxyStageSetNotice(*this).Send();
MayaUsdProxyStageSetNotice(*this).Send();

return status;
}
Expand Down
Loading