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

Improve rename logics #483

Conversation

HamedSabri-adsk
Copy link
Contributor

This change simplifies the rename operation by simply renaming a prim in place via SdfPrimSpec's SetName routine and removes the old work-flow involving SdfCopySpec.

This change simplifies the rename operation by simply renaming a prim in place via SdfPrimSpec's SetName routine and removes the old work-flow involving SdfCopySpec.
@HamedSabri-adsk HamedSabri-adsk requested a review from ppt-adsk May 6, 2020 15:26
//! Return a PrimSpec for the argument prim in the layer containing the stage's current edit target.
MAYA_USD_UTILS_PUBLIC
SdfPrimSpecHandle getPrimSpecAtEditTarget(UsdStageWeakPtr, const UsdPrim&);

} // namespace MayaUsdUtils
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added a utility function for getting a PrimSpec from a prim path in the layer containing the stage's current edit target.


const UsdPrim& _prim;
UsdStageWeakPtr _stage;
std::string _newName;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Simplified member variables. We no longer need _usdSrcPath, _usdDstPath, and _layer.

, _ufeDstItem(nullptr)
, _prim(srcItem->prim())
, _stage(_prim.GetStage())
, _newName(newName.string())
Copy link
Contributor Author

@HamedSabri-adsk HamedSabri-adsk May 6, 2020

Choose a reason for hiding this comment

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

Using initializer list.

}

return status;
return true;
Copy link
Contributor Author

@HamedSabri-adsk HamedSabri-adsk May 6, 2020

Choose a reason for hiding this comment

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

On Undo:
1- Get the SdfPrimSpec to the _ufeDstItem->prim() and check it's validity.
2- Set it's name to _prim's original name: primSpec->SetName(_prim.GetPath().GetElementString());
3- Set _ufeSrcItem and send UFE scene notification
4- Set _ufeDstItem = nullptr

@HamedSabri-adsk HamedSabri-adsk added core Related to core library ufe-usd Related to UFE-USD plugin in Maya-Usd labels May 6, 2020
Copy link
Collaborator

@ppt-adsk ppt-adsk left a comment

Choose a reason for hiding this comment

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

I think to best demonstrate that this change is robust I would like to see an addition to the rename test where you access a child of the renamed prim, and try to do something with it e.g. use the hierarchy interface on the child to get its parent, which should now be the renamed prim. This way we would know that the subtree of prims under the renamed prim is in a good state.

UsdEditContext ctx(_stage, _layer);
status = _stage->RemovePrim(_ufeSrcItem->prim().GetPath());
}
auto primSpec = MayaUsdUtils::getPrimSpecAtEditTarget(_stage, _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: wonder if it wouldn't be clearer to just early-out false if !primSpec:

if (!primSpec) {
return false;
}

assert(newPrim);
#endif
// set prim's name
primSpec->SetName(_prim.GetPath().GetElementString());
Copy link
Collaborator

Choose a reason for hiding this comment

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

How is this setting the name back to the original name? Also, is prim still valid, since you've changed its name?

_ufeSrcItem = createSiblingSceneItem(_ufeDstItem->path(), _usdSrcPath.GetElementString());
// shouldn't have to again create a sibling sceneItem here since we already have a valid _ufeSrcItem
// however, I get random crashes if I don't which needs furthur investigation. HS, 6-May-2020.
_ufeSrcItem = createSiblingSceneItem(_ufeDstItem->path(), _prim.GetPath().GetElementString());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't the prim in the original _ufeSrcItem now invalid?

…operations in undo/redo.

- To read the code better, I added a new member variable _oldName that holds the prim's original name.
// XXX: SetName successfuly returns true but when you examine the _prim.GetName()
// after the rename, the prim name shows the original name HS, 6-May-2020.
bool status = primSpec->SetName(_newName);
if (!status) {
return false;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do an early check for primSpec and SetName result.

@ppt-adsk there is something troubling happening here which I am trying to understand:

On Redo, I get the primspec for _prim object and rename it's name to the _newName. This operation return successful BUT when I query the _prim's name right after, I still get the _prim's original name. Huh???

I then set _ufeDstItem and when I print it's USD name and it gives me the _newName which is expected.

@@ -47,6 +47,7 @@ UsdUndoRenameCommand::UsdUndoRenameCommand(const UsdSceneItem::Ptr& srcItem, con
, _prim(srcItem->prim())
, _stage(_prim.GetStage())
, _newName(newName.string())
, _oldName(_prim.GetName().GetString())
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added _oldName that holds the _prim name before it is changed.

@HamedSabri-adsk
Copy link
Contributor Author

I think to best demonstrate that this change is robust I would like to see an addition to the rename test where you access a child of the renamed prim, and try to do something with it e.g. use the hierarchy interface on the child to get its parent, which should now be the renamed prim. This way we would know that the subtree of prims under the renamed prim is in a good state.

@ppt-adsk Very valid point. I will update the rename test.

…sd file for testing purposes.

- Renamed testRename to testRenameUndo
- Added new logics for testing new way of renaming a prim name via SdfPrimSpec.

# HS, 6-May-2020. defualtPrim in null?? This can't be null....
# defualtPrim = stage.GetDefaultPrim()
# self.assertEqual(defualtPrim.GetName(), 'TreeBase_potato')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ppt-adsk Unless I am missing something really obvious, defualtPrim can not be null in line 138??

Both assert passed in line 134,135 which to me indicates the subtree under the renamed prim is in a good state.

Copy link
Contributor Author

@HamedSabri-adsk HamedSabri-adsk May 7, 2020

Choose a reason for hiding this comment

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

@ppt-adsk OK, I did a little more digging into this and the good news is that the tree/subtree graph is in a good state after the rename. It is just that we can't no longer rely on the stage which looks like a bug on USD side to me or perhaps there is a rational reason for this behavior that I don't know.

# set primspec name
primspec.name = "TreeBase_potato"

potatoPrim = stage.GetPrimAtPath('/TreeBase_potato')
self.assertEqual(potatoPrim.GetName(), 'TreeBase_potato')   // Pass

Traverse the stage

/TreeBase_potato
/TreeBase_potato/leavesXform
/TreeBase_potato/leavesXform/leaves
/TreeBase_potato/trunk

# defualtPrim = stage.GetDefaultPrim()
# self.assertEqual(defualtPrim.GetName(), 'TreeBase_potato')

def testRenameUndo(self):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

renamed original testRename to testRenameUndo.

Hamed Sabri added 2 commits May 7, 2020 12:27
…s around the stage behavior that deserves an explanation.
- Add a simple testRenameRestrictionExternalReference unit test.
with self.assertRaises(RuntimeError):
newName = 'leaf_ref_2_renaming'
cmds.rename(newName)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a simple unit test around rename restriction for an external reference.

NOTE: I originally didn't want to add treeRef.usda and treeRef.ma and my plan was to use already added tree.ma and programmatically add internal reference, however AddInternalReference didn't seem to give me what I wanted.

What I wanted was to add a typeless prim, append an internal reference, author bunch of attributes and be done.
e.g

    def "leaf_ref_1" (
        append references = </TreeBase/leavesXform/greenLeaf>
    )
    {
        double3 xformOp:translate = (2.0, 2.5, 0)
        uniform token[] xformOpOrder = ["xformOp:translate"]
        double radius = 0.5
    }

Here is how I originally planned to add in code:

refPrim = stage.DefinePrim('/TreeBase/leaf_ref_1')
refPrim.GetReferences().AddInternalReference('/TreeBase/leavesXform/greenLeaf')

# author refPrim's xform and radius
xform = UsdGeom.Xformable(refPrim)
xform.AddTranslateOp().Set(Gf.Vec3d(2.0, 2.5, 0))

radiusAttr = refPrim.GetAttribute('radius')
radiusAttr.Set(0.5)

Instead I get something like this:

def Sphere "leaf_ref_1"
{
    float3[] extent = [(-2, -2, -2), (2, 2, 2)]
    color3f[] primvars:displayColor = [(0, 1, 0)]
    double radius = 0.5
    double3 xformOp:translate = (2, 2.5, 0)
    uniform token[] xformOpOrder = ["xformOp:translate"]
}

@HamedSabri-adsk HamedSabri-adsk added the unit test Related to unit tests (both python or c++) label May 11, 2020
lib/mayaUsd/ufe/UsdUndoRenameCommand.cpp Show resolved Hide resolved
// account for internal vs external references
if (_prim.HasAuthoredReferences()) {
auto primSpec = MayaUsdUtils::getPrimSpecAtEditTarget(_stage, _prim);
for (const SdfReference& ref : primSpec->GetReferenceList().GetAddedOrExplicitItems()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Feels strange that this is going through a loop... Because in the loop body, the if part of the conditional returns, and the else part of the conditional throws, so there is no way you'll get anything beyond the first item in the loop!

Also, is it possible for _prim.HasAuthoredReferences() to be true, but primSpec->GetReferenceList().GetAddedOrExplicitItmes() to return an empty list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ppt-adsk yes that was my first impression about the loop but that's what we have got.

Because in the loop body, the if part of the conditional returns, and the else part of the conditional throws, so there is no way you'll get anything beyond the first item in the loop!

Yes I agree. This is a first pass and I am sure I am going to modify this code as I understand more edge cases.

Also, is it possible for _prim.HasAuthoredReferences() to be true, but primSpec->GetReferenceList().GetAddedOrExplicitItmes() to return an empty list?

I don't think that would be the case at least by looking at the low-level code. I could be wrong.

auto layers = MayaUsdUtils::layersWithPrimSpec(prim);
// account for internal vs external references
if (_prim.HasAuthoredReferences()) {
auto primSpec = MayaUsdUtils::getPrimSpecAtEditTarget(_stage, _prim);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Given that you've submitted a pull request to Pixar to better handle this functionality, wouldn't it be good to encapsulate this behind a utility function so that this code won't have to change when internal reference testing improves? The encapsulation would be specially useful since you'll have to support different implementations, depending on the version of USD that's being used. E.g. something like
bool isInternalReference(primSpec)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, will make one in the next commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ppt-adsk please see a305af9

Copy link
Collaborator

@ppt-adsk ppt-adsk left a comment

Choose a reason for hiding this comment

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

Almost there, just a couple of trivial things and we're done!

throw std::runtime_error(err.c_str());
}

if(MayaUsdUtils::isInternalReference(primSpec)) {
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 just be
if (!MayaUsdUtils::isInternalReference(primSpec)) {
throw blablabla;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

lib/usd/utils/util.cpp Show resolved Hide resolved
@HamedSabri-adsk HamedSabri-adsk requested a review from ppt-adsk May 12, 2020 22:24
…things more readable.

- change the container type for layersWithContribution method from std::vector to std::set to guarantee having unique layers.
@HamedSabri-adsk
Copy link
Contributor Author

@ppt-adsk please see 3cf2acc

@HamedSabri-adsk HamedSabri-adsk merged commit 7bb77b3 into sabrih/MAYA-104215/improve_usd_rename_operation May 13, 2020
@HamedSabri-adsk HamedSabri-adsk deleted the sabrih/MAYA-104215/improve_rename_logics branch May 13, 2020 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Related to core library ufe-usd Related to UFE-USD plugin in Maya-Usd unit test Related to unit tests (both python or c++)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants