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

Tremblp/maya 102361/rename fixes #237

Merged
merged 8 commits into from
Feb 11, 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
6 changes: 5 additions & 1 deletion lib/ufe/Global.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "UsdTransform3dHandler.h"
#include "UsdSceneItemOpsHandler.h"

#include <ufe/rtid.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like we're actually adding a usage of Ufe::Rtid at line 130, so I'm not sure why we're taking this include out? I know it was added to the header, but since there's usage in both files, I'd prefer to see the include in both files.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not a huge deal, to be sure, but isn't that violating Don't Repeat Yourself? If maintenance removes the use of Ufe::Rtid, I'd now have two places to remove the include of ufe/rtid.h.

#include <ufe/runTimeMgr.h>
#include <ufe/hierarchyHandler.h>
#include <ufe/ProxyShapeHierarchyHandler.h>
Expand Down Expand Up @@ -128,5 +127,10 @@ MStatus finalize()
return MS::kSuccess;
}

Ufe::Rtid getUsdRunTimeId()
{
return g_USDRtid;
}

} // namespace ufe
} // namespace MayaUsd
6 changes: 6 additions & 0 deletions lib/ufe/Global.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include "../base/api.h"

#include <ufe/rtid.h>

#include <maya/MStatus.h>

MAYAUSD_NS_DEF {
Expand All @@ -32,5 +34,9 @@ MStatus initialize();
MAYAUSD_CORE_PUBLIC
MStatus finalize();

//! Return the run-time ID allocated to USD.
MAYAUSD_CORE_PUBLIC
Ufe::Rtid getUsdRunTimeId();

} // namespace ufe
} // namespace MayaUsd
22 changes: 19 additions & 3 deletions lib/ufe/ProxyShapeHierarchy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "ProxyShapeHierarchy.h"
#include "Utils.h"

#include <ufe/log.h>
#include <ufe/pathComponent.h>
#include <ufe/pathSegment.h>
#include <ufe/rtid.h>
Expand All @@ -37,7 +38,9 @@ extern Ufe::Rtid g_USDRtid;
// ProxyShapeHierarchy
//------------------------------------------------------------------------------

ProxyShapeHierarchy::ProxyShapeHierarchy(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler)
ProxyShapeHierarchy::ProxyShapeHierarchy(
const Ufe::HierarchyHandler::Ptr& mayaHierarchyHandler
)
: Ufe::Hierarchy()
, fMayaHierarchyHandler(mayaHierarchyHandler)
{
Expand All @@ -48,11 +51,22 @@ ProxyShapeHierarchy::~ProxyShapeHierarchy()
}

/*static*/
ProxyShapeHierarchy::Ptr ProxyShapeHierarchy::create(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler)
ProxyShapeHierarchy::Ptr ProxyShapeHierarchy::create(const Ufe::HierarchyHandler::Ptr& mayaHierarchyHandler)
{
return std::make_shared<ProxyShapeHierarchy>(mayaHierarchyHandler);
}

/*static*/
ProxyShapeHierarchy::Ptr ProxyShapeHierarchy::create(
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
const Ufe::HierarchyHandler::Ptr& mayaHierarchyHandler,
const Ufe::SceneItem::Ptr& item
)
{
auto hierarchy = create(mayaHierarchyHandler);
hierarchy->setItem(item);
return hierarchy;
}

void ProxyShapeHierarchy::setItem(const Ufe::SceneItem::Ptr& item)
{
// Our USD root prim is from the stage, which is from the item. So if we are
Expand Down Expand Up @@ -95,8 +109,10 @@ Ufe::SceneItem::Ptr ProxyShapeHierarchy::sceneItem() const
bool ProxyShapeHierarchy::hasChildren() const
{
const UsdPrim& rootPrim = getUsdRootPrim();
if (!rootPrim.IsValid())
if (!rootPrim.IsValid()) {
UFE_LOG("invalid root prim in ProxyShapeHierarchy::hasChildren()");
return false;
}
return !rootPrim.GetChildren().empty();
}

Expand Down
8 changes: 6 additions & 2 deletions lib/ufe/ProxyShapeHierarchy.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class MAYAUSD_CORE_PUBLIC ProxyShapeHierarchy : public Ufe::Hierarchy
public:
typedef std::shared_ptr<ProxyShapeHierarchy> Ptr;

ProxyShapeHierarchy(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler);
ProxyShapeHierarchy(const Ufe::HierarchyHandler::Ptr& mayaHierarchyHandler);
~ProxyShapeHierarchy() override;

// Delete the copy/move constructors assignment operators.
Expand All @@ -48,7 +48,11 @@ class MAYAUSD_CORE_PUBLIC ProxyShapeHierarchy : public Ufe::Hierarchy
ProxyShapeHierarchy& operator=(ProxyShapeHierarchy&&) = delete;

//! Create a ProxyShapeHierarchy from a UFE hierarchy handler.
static ProxyShapeHierarchy::Ptr create(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler);
static ProxyShapeHierarchy::Ptr create(const Ufe::HierarchyHandler::Ptr& mayaHierarchyHandler);
static ProxyShapeHierarchy::Ptr create(
const Ufe::HierarchyHandler::Ptr& mayaHierarchyHandler,
const Ufe::SceneItem::Ptr& item
);

void setItem(const Ufe::SceneItem::Ptr& item);

Expand Down
9 changes: 4 additions & 5 deletions lib/ufe/ProxyShapeHierarchyHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
#include "ProxyShapeHierarchyHandler.h"
#include "Utils.h"

#include <ufe/ProxyShapeHierarchy.h>

MAYAUSD_NS_DEF {
namespace ufe {

ProxyShapeHierarchyHandler::ProxyShapeHierarchyHandler(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler)
: Ufe::HierarchyHandler()
, fMayaHierarchyHandler(mayaHierarchyHandler)
{
fProxyShapeHierarchy = ProxyShapeHierarchy::create(mayaHierarchyHandler);
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
}
{}

ProxyShapeHierarchyHandler::~ProxyShapeHierarchyHandler()
{
Expand All @@ -45,8 +45,7 @@ Ufe::Hierarchy::Ptr ProxyShapeHierarchyHandler::hierarchy(const Ufe::SceneItem::
{
if (isAGatewayType(item->nodeType()))
{
fProxyShapeHierarchy->setItem(item);
return fProxyShapeHierarchy;
return ProxyShapeHierarchy::create(fMayaHierarchyHandler, item);
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
Expand Down
2 changes: 0 additions & 2 deletions lib/ufe/ProxyShapeHierarchyHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include "../base/api.h"

#include <ufe/hierarchyHandler.h>
#include <ufe/ProxyShapeHierarchy.h>

MAYAUSD_NS_DEF {
namespace ufe {
Expand Down Expand Up @@ -59,7 +58,6 @@ class MAYAUSD_CORE_PUBLIC ProxyShapeHierarchyHandler : public Ufe::HierarchyHand

private:
Ufe::HierarchyHandler::Ptr fMayaHierarchyHandler;
ProxyShapeHierarchy::Ptr fProxyShapeHierarchy;

}; // ProxyShapeHierarchyHandler

Expand Down
44 changes: 24 additions & 20 deletions lib/ufe/StagesSubject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,32 +174,36 @@ void StagesSubject::stageChanged(UsdNotice::ObjectsChanged const& notice, UsdSta
for (const auto& changedPath : notice.GetResyncedPaths())
{
const std::string& usdPrimPathStr = changedPath.GetPrimPath().GetString();
// Assume proxy shapes (and thus stages) cannot be instanced. We can
// therefore map the stage to a single UFE path. Lifting this
// restriction would mean sending one add or delete notification for
// each Maya Dag path instancing the proxy shape / stage.
Ufe::Path ufePath = stagePath(sender) + Ufe::PathSegment(usdPrimPathStr, g_USDRtid, '/');
auto prim = stage->GetPrimAtPath(changedPath);
// Changed paths could be xformOps.
// These are considered as invalid null prims
if (prim.IsValid() && !InPathChange::inPathChange())
{
auto sceneItem = Ufe::Hierarchy::createItem(ufePath);

// AL LayerCommands.addSubLayer test will cause Maya to crash
// if we don't filter invalid sceneItems. This patch is provided
// to prevent crashes, but more investigation will have to be
// done to understand why ufePath in case of sub layer
// creation causes Ufe::Hierarchy::createItem to fail.
if (!sceneItem)
continue;

if (prim.IsActive())
{
auto notification = Ufe::ObjectAdd(sceneItem);
Ufe::Scene::notifyObjectAdd(notification);
}
else
{
auto notification = Ufe::ObjectPostDelete(sceneItem);
Ufe::Scene::notifyObjectDelete(notification);
}
auto sceneItem = Ufe::Hierarchy::createItem(ufePath);

// AL LayerCommands.addSubLayer test will cause Maya to crash
// if we don't filter invalid sceneItems. This patch is provided
// to prevent crashes, but more investigation will have to be
// done to understand why ufePath in case of sub layer
// creation causes Ufe::Hierarchy::createItem to fail.
if (!sceneItem)
continue;

if (prim.IsActive())
{
auto notification = Ufe::ObjectAdd(sceneItem);
Ufe::Scene::notifyObjectAdd(notification);
}
else
{
auto notification = Ufe::ObjectPostDelete(sceneItem);
Ufe::Scene::notifyObjectDelete(notification);
}
}
}

Expand Down
80 changes: 71 additions & 9 deletions lib/ufe/UsdStageMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,43 @@
//

#include "UsdStageMap.h"
#include "Utils.h"

#include <maya/MFnDagNode.h>

#include <cassert>

namespace {

MObjectHandle proxyShapeHandle(const Ufe::Path& path)
{
// Get the MObjectHandle from the tail of the MDagPath. Remove the leading
// '|world' component.
auto noWorld = path.popHead().string();
auto dagPath = MayaUsd::ufe::nameToDagPath(noWorld);
MObjectHandle handle(dagPath.node());
if (!handle.isValid()) {
TF_CODING_ERROR("'%s' is not a path to a proxy shape node.",
noWorld.c_str());
}
return handle;
}

// Assuming proxy shape nodes cannot be instanced, simply return the first path.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'll admit I'm not sure I fully understand the context here, but is this a safe assumption? In our pipeline, we definitely do instance pxrUsdReferenceAssembly/pxrUsdProxyShape nodes using either nParticles or MASH.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Created an issue describing the problem, and some areas that would need to be worked on:
#256

Ufe::Path firstPath(const MObjectHandle& handle)
{
if (!TF_VERIFY(handle.isValid(),
"Cannot get path from invalid object handle")) {
return Ufe::Path();
}

MDagPath dagPath;
auto status = MFnDagNode(handle.object()).getPath(dagPath);
CHECK_MSTATUS(status);
return MayaUsd::ufe::dagPathToUfe(dagPath);
}

}

MAYAUSD_NS_DEF {
namespace ufe {
Expand All @@ -31,32 +68,57 @@ UsdStageMap g_StageMap;

void UsdStageMap::addItem(const Ufe::Path& path, UsdStageWeakPtr stage)
{
fPathToStage[path] = stage;
fStageToPath[stage] = path;
// We expect a path to the proxy shape node, therefore a single segment.
auto nbSegments =
#ifdef UFE_V0_2_6_FEATURES_AVAILABLE
path.nbSegments();
#else
path.getSegments().size();
#endif
if (nbSegments != 1) {
TF_CODING_ERROR("A proxy shape node path can have only one segment, path '%s' has %lu", path.string().c_str(), nbSegments);
return;
}

// Convert the tail of the UFE path to an MObjectHandle.
auto proxyShape = proxyShapeHandle(path);
if (!proxyShape.isValid()) {
return;
}

// Could get the stage from the proxy shape object in the stage() method,
// but since it's given here, simply store it.
fObjectToStage[proxyShape] = stage;
fStageToObject[stage] = proxyShape;
}

UsdStageWeakPtr UsdStageMap::stage(const Ufe::Path& path) const
{
auto proxyShape = proxyShapeHandle(path);
if (!proxyShape.isValid()) {
return nullptr;
}

// A stage is bound to a single Dag proxy shape.
auto iter = fPathToStage.find(path);
if (iter != std::end(fPathToStage))
auto iter = fObjectToStage.find(proxyShape);
if (iter != std::end(fObjectToStage))
return iter->second;
return nullptr;
}

Ufe::Path UsdStageMap::path(UsdStageWeakPtr stage) const
{
// A stage is bound to a single Dag proxy shape.
auto iter = fStageToPath.find(stage);
if (iter != std::end(fStageToPath))
return iter->second;
auto iter = fStageToObject.find(stage);
if (iter != std::end(fStageToObject))
return firstPath(iter->second);
return Ufe::Path();
}

void UsdStageMap::clear()
{
fPathToStage.clear();
fStageToPath.clear();
fObjectToStage.clear();
fStageToObject.clear();
}

} // namespace ufe
Expand Down
35 changes: 26 additions & 9 deletions lib/ufe/UsdStageMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,37 @@
#include <pxr/usd/usd/stage.h>
#include <pxr/base/tf/hash.h>

#include <maya/MObjectHandle.h>

#include <unordered_map>

// Allow for use of MObjectHandle with std::unordered_map.
namespace std {
template <> struct hash<MObjectHandle> {
std::size_t operator()(const MObjectHandle& handle) const {
return static_cast<std::size_t>(handle.hashCode());
}
};
}
Comment on lines +29 to +36
Copy link
Contributor

Choose a reason for hiding this comment

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

This would be a great candidate for the kind of Maya-as-the-only-dependency utilities library that Animal Logic has been advocating for. We actually had something for this in usdMaya (now migrated to mayaUsd) as well:

using MObjectHandleUnorderedMap =

There's nothing USD or UFE related about either implementation.


PXR_NAMESPACE_USING_DIRECTIVE

MAYAUSD_NS_DEF {
namespace ufe {

//! \brief USD Stage Map
/*!
Map of AL_usdmaya_ProxyShape UFE path to corresponding stage.

Map of stage to corresponding AL_usdmaya_ProxyShape UFE path. Ideally, we
would support dynamically computing the path for the AL_usdmaya_ProxyShape
node, but we assume here it will not be reparented. We will also assume that
a USD stage will not be instanced (even though nothing in the data model
prevents it).
Two-way map of proxy shape UFE path to corresponding stage.

We will assume that a USD proxy shape will not be instanced (even though
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Previous USD stage map was path-based, which was impossible to maintain in the presence of path changes through renaming. Simply use the proxy shape MObject instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

Again, slightly concerned about the no instancing assumption, but maybe I'm misunderstanding.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, you're not misunderstanding... As per other comment entered as
#256

nothing in the data model prevents it). To support renaming and repathing,
we store an MObjectHandle in the maps, which is invariant to renaming and
repathing, and compute the path on access. This is slower than a scheme
where we cache using the Ufe::Path, but such a cache must be refreshed on
rename and repath, which is non-trivial, since there is no guarantee on the
order of notification of Ufe observers. An earlier implementation with
rename observation had the Maya Outliner (which observes rename) access the
UsdStageMap on rename before the UsdStageMap had been updated.
*/
class MAYAUSD_CORE_PUBLIC UsdStageMap
{
Expand All @@ -64,8 +79,10 @@ class MAYAUSD_CORE_PUBLIC UsdStageMap

private:
// We keep two maps for fast lookup when there are many proxy shapes.
std::unordered_map<Ufe::Path, UsdStageWeakPtr> fPathToStage;
TfHashMap<UsdStageWeakPtr, Ufe::Path, TfHash> fStageToPath;
using ObjectToStage = std::unordered_map<MObjectHandle, UsdStageWeakPtr>;
using StageToObject = TfHashMap<UsdStageWeakPtr, MObjectHandle, TfHash>;
ObjectToStage fObjectToStage;
StageToObject fStageToObject;

}; // UsdStageMap

Expand Down
Loading