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-104214 - As a user, I'd like to add a USD prim to an existing stage #489

Merged
merged 9 commits into from
May 13, 2020

Conversation

seando-adsk
Copy link
Collaborator

MAYA-104214 - As a user, I'd like to add a USD prim to an existing stage

  • Added new AE templates for basic prim types.
  • New ProxyShapeContextOpsHandler to decorate the one from Maya.
  • Send new Ufe::ObjectDestroyed notif when USD prim is deleted.
  • New context item sub-menu: "Add New Prim" with various prim types. Full undo/redo support thur new command. Added new context ops test "testAddNewPrim".
  • Fixed a bug where "visbility" context menu item was added to prims that don't support visibility attribute.

@@ -8,7 +8,7 @@ if (CMAKE_UFE_V2_FEATURES_AVAILABLE)
install(FILES __init__.py DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/ufe_ae/usd/nodes)

# Maya Attribute Editor python template files
foreach(_SUBDIR base camera material mesh scope shader xform)
foreach(_SUBDIR base camera capsule cone cube cylinder material mesh scope shader sphere xform)
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 AE templates for the missing prim types that are part of the menu. They are all just copies of the existing templates that have everything in the "AEBaseTemplate"

Comment on lines +112 to +114
g_MayaContextOpsHandler = Ufe::RunTimeMgr::instance().contextOpsHandler(g_MayaRtid);
auto proxyShapeContextOpsHandler = ProxyShapeContextOpsHandler::create(g_MayaContextOpsHandler);
Ufe::RunTimeMgr::instance().setContextOpsHandler(g_MayaRtid, proxyShapeContextOpsHandler);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Decorate the Maya context ops handler, just like we do with the Maya hier handler. Note: currently the Maya context ops handler is not used so it's null.

Comment on lines +55 to +58
auto usdItem = UsdSceneItem::create(item->path(), stage->GetPseudoRoot());
auto usdContextOpsHandler = UsdContextOpsHandler::create();
auto cOps = usdContextOpsHandler->contextOps(usdItem);
UsdContextOps::Ptr usdCOps = std::dynamic_pointer_cast<UsdContextOps>(cOps);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

From Maya the input Ufe::SceneItem will be of an internal type to Maya. We need to create a UsdSceneItem (that has a prim).

Comment on lines +239 to +245
#if UFE_PREVIEW_VERSION_NUM >= 2015
else if (!prim.IsValid())
{
auto notification = Ufe::ObjectDestroyed(ufePath);
Ufe::Scene::notifyObjectDelete(notification);
}
#endif
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 scene notification added in Ufe. When this message is sent the object is no longer valid. Thus we don't use the scene item, but instead just the path.

void redo() override
{
if (_stage) {
auto newPrim = _stage->DefinePrim(_primPath, _primToken);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Create a prim with the specified path and of the specified type.

std::string("Make Visible") : std::string("Make Invisible");
items.emplace_back("Toggle Visibility", l);
// Top-level items. Variant sets and visibility. Do not add for gateway type node.
if (!fIsAGatewayType) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Lines 159-174 were indented inside this new if test. The gateway node will be the mayausd proxy shape.

Copy link
Collaborator

Choose a reason for hiding this comment

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

As I discussed with you, I'm still trying to figure out how we could have done this with a base class, and avoided the type-based conditional...

If we had a base class for the context ops that did not have variant sets and visibility, and a derived class that would have variant sets and visibility first, then would call the base class, would that work? Ordering would be preserved.

Maybe I'm too attached to that idea, and maybe it's just a minor improvement, but my feeling is that it would help with separation of concerns. The base class would take care of the proxy shape-only context ops, and the derived class would add in visibility and variant sets. Let me know what you think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It would work for now only because in our ordering we have the two non-gateway node stuff first and then a single item that applies to all. But as we add more context menu items this won't work. Example: my next task is to add menu item for "Layer Editor" as the first menu item. It will be added for all types. Once we add that I think the complexity of using a base/derived class outweighs the benefit.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with you, the base class approach isn't flexible enough to accomodate the ordering we'll need. Case closed.

"Variant Sets", "Variant Sets", Ufe::ContextItem::kHasChildren);
}
auto attributes = Ufe::Attributes::attributes(sceneItem());
if (attributes && attributes->hasAttribute(UsdGeomTokens->visibility)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added the hasAttribute() test here to fix a bug with prims that don't have a visibility attribute to toggle.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks. For my own education, which ones don't? The typeless defs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Typeless = yes, but also shaders, materials

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, of course. Can you add that in as a code comment, to avoid further questions?

Comment on lines 82 to 85
if (itemPath[1] == "Def")
_primToken = TfToken(); // create typeless prim
else
_primToken = TfToken(itemPath[1]);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Type of prim to create. Def is typeless.

* Added new AE templates for basic prim types.
* New ProxyShapeContextOpsHandler to decorate the one from Maya.
* Send new Ufe::ObjectDestroyed notif when USD prim is deleted.
* New context item sub-menu: "Add New Prim" with various prim types.
  Full undo/redo support thur new command. Added new context ops
  test "testAddNewPrim".
* Fixed a bug where "visbility" context menu item was added to prims
  that don't support visibility attribute.
@seando-adsk seando-adsk force-pushed the donnels/MAYA-104214/add_a_usd_prim_to_an_existing_stage branch from cb4eddb to ffc9e5c Compare May 8, 2020 17:48
public:
typedef std::shared_ptr<ProxyShapeContextOpsHandler> Ptr;

ProxyShapeContextOpsHandler(Ufe::ContextOpsHandler::Ptr mayaContextOpsHandler);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit-pick: should pass in the shared_ptr by const ref.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Agreed. I had originally copied this from the ProxyShapeHierarchyHandler. It wasn't const ref either so I changed it.

ProxyShapeContextOpsHandler& operator=(ProxyShapeContextOpsHandler&&) = delete;

//! Create a ProxyShapeContextOpsHandler from a UFE hierarchy handler.
static ProxyShapeContextOpsHandler::Ptr create(Ufe::ContextOpsHandler::Ptr mayaContextOpsHandler);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Pass by const ref.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Agreed - same as above.

_stage = MayaUsd::ufe::getStage(Ufe::Path(dagSegment));
if (_stage) {
// Rename the new prim for uniqueness, if needed.
Ufe::Path newUfePath = ufePath + itemPath[1];
Copy link
Collaborator

Choose a reason for hiding this comment

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

You've tried this, so clearly it works, but I'm just not sure how :) In the parenting code, when I parent just below the proxy shape, I needed to take care of the fact that the newly-added component is in a different run-time:
https://github.com/Autodesk/maya-usd/blob/dev/lib/mayaUsd/ufe/UsdUndoInsertChildCommand.cpp#L53
Why don't you have the same problem? If you just concatenate the prim name to the existing proxy shape UFE path, you'll get a path that is in the Maya run-time, which is incorrect.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You are right, I didn't think about this. But I just tested it again and it works. The reason is that in "uniqueChildName" it just does:

	std::string childName = childPath.back().string();

which in my case is fine, because it will just return the "itemPath[1]" that I appended. Then it loops thru all the existing child names to see if any match.

Do you think it is okay like this? Alternatively I could pass in (to the command) if I have a gateway node. When I do, I would know that the new prim name I need to append will be in a different runtime and I could handle that in a manner similar to what you did.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it's O.K. like this, but I'd add in a comment somehow to say something like "Hey I know this isn't 100% correct, but all uniqueName does is take the back() of the path, so it's fine."

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. I also added another code comment for the visibility.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks.

{
public:
AddNewPrimUndoableCommand(const MayaUsd::ufe::UsdSceneItem::Ptr& usdSceneItem,
const Ufe::ContextOps::ItemPath& itemPath)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like you're only using itemPath[1]. If that's the case, couldn't we just pass that in, and give it a more readable name, i.e. const std::string& primType, or something similar?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes I am, but this way it more matches the other undoable command which also takes in the itemPath.

Copy link
Collaborator

Choose a reason for hiding this comment

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

O.K.


// The type of prim we were asked to create.
if (itemPath[1] == "Def")
_primToken = TfToken(); // create typeless prim
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit-pick: could be in the constructor's initializer list as

_primToken(itemPath[1] == "Def" ? TfToken() : TfToken(itemPath[1]))

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll use the single line version, but I prefer to keep it here rather that in init list because I have some comments.

Copy link
Collaborator

Choose a reason for hiding this comment

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

O.K.

std::string("Make Visible") : std::string("Make Invisible");
items.emplace_back("Toggle Visibility", l);
// Top-level items. Variant sets and visibility. Do not add for gateway type node.
if (!fIsAGatewayType) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

As I discussed with you, I'm still trying to figure out how we could have done this with a base class, and avoided the type-based conditional...

If we had a base class for the context ops that did not have variant sets and visibility, and a derived class that would have variant sets and visibility first, then would call the base class, would that work? Ordering would be preserved.

Maybe I'm too attached to that idea, and maybe it's just a minor improvement, but my feeling is that it would help with separation of concerns. The base class would take care of the proxy shape-only context ops, and the derived class would add in visibility and variant sets. Let me know what you think.

"Variant Sets", "Variant Sets", Ufe::ContextItem::kHasChildren);
}
auto attributes = Ufe::Attributes::attributes(sceneItem());
if (attributes && attributes->hasAttribute(UsdGeomTokens->visibility)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks. For my own education, which ones don't? The typeless defs?


// At this point we know we have 2 arguments to execute the operation.
// itemPath[1] contains the new prim type to create.
return std::make_shared<AddNewPrimUndoableCommand>(fItem, itemPath);
Copy link
Collaborator

Choose a reason for hiding this comment

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

As per above I'd just pass in itemPath[1] 'cause that's all you need.

@kxl-adsk kxl-adsk added ufe-usd Related to UFE-USD plugin in Maya-Usd workflows Related to in-context workflows labels May 10, 2020
_stage = MayaUsd::ufe::getStage(Ufe::Path(dagSegment));
if (_stage) {
// Rename the new prim for uniqueness, if needed.
Ufe::Path newUfePath = ufePath + itemPath[1];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks.

* Fix problem with new Ufe::ObjectDestroyed() and invalid prim.
@seando-adsk
Copy link
Collaborator Author

I discovered a problem while doing some more local testing. We want to ignore resycn paths that prim paths. See commit 17c9a05

Comment on lines +212 to +213
if (!changedPath.IsPrimPath())
continue;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

At line 221 we specifically ask for the prim at path. So if this changed path is not a prim path we will get an invalid prim back.

@@ -184,6 +260,17 @@ Ufe::UndoableCommand::Ptr UsdContextOps::doOpCmd(const ItemPath& itemPath)
return visibility->setCmd(
current == UsdGeomTokens->invisible ? UsdGeomTokens->inherited : UsdGeomTokens->invisible);
} // Visibility
else if (!itemPath.empty() && (itemPath[0] == "Add New Prim")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Super minor comment: it may be a good idea to keep these operation strings (like "Add New Prim") in a unique place. That way it'd be easier to change if we ever need to. I've seen the "Add New Prim" string already three times during this review.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes good idea. See commit 14d8d4b

Copy link
Contributor

@pilarmolinalopez pilarmolinalopez left a comment

Choose a reason for hiding this comment

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

Except for a minor comment, it looks good to me. Thanks!

…outliner

* Added context menu item for opening USD Layer Editor.
@seando-adsk
Copy link
Collaborator Author

Since this all deals with context menu changes, I've also added one more small change in this commit for opening the USD Layer Editor.

// Ufe::ContextItem strings
// - the "Item" describe the operation to be performed.
// - the "Label" is used in the context menu (can be localized).
static constexpr char kUSDLayerEditorItem[] = "USD Layer Editor";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit-pick: is this some MSVC-specific requirement? Because otherwise, you're in an unnamed namespace, you don't need the static linkage specifier.

Copy link
Contributor

@pilarmolinalopez pilarmolinalopez left a comment

Choose a reason for hiding this comment

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

thanks! looks good to me

@seando-adsk seando-adsk force-pushed the donnels/MAYA-104214/add_a_usd_prim_to_an_existing_stage branch from 5744a52 to 7918a30 Compare May 12, 2020 21:19
@kxl-adsk kxl-adsk merged commit dac8880 into dev May 13, 2020
@kxl-adsk kxl-adsk deleted the donnels/MAYA-104214/add_a_usd_prim_to_an_existing_stage branch May 13, 2020 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ufe-usd Related to UFE-USD plugin in Maya-Usd workflows Related to in-context workflows
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants