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

Allowing a new prim spec to be written in edit target layers #2390

Merged
merged 3 commits into from
Aug 31, 2022

Conversation

NickWu
Copy link

@NickWu NickWu commented May 30, 2022

This PR is for addressing the issue discussed in here #2212. In short, at Animal Logic, we found isAttributeEditAllowed function in UFE a bit confusing and was blocking our pipeline so we updated its logic in our internal code base. This PR is to promote our internal solution.

@seando-adsk seando-adsk added ufe Related to UFE component in Maya unit test Related to unit tests (both python or c++) labels May 30, 2022
@pierrebai-adsk
Copy link
Collaborator

I will have to understand well the change. We had internal discussions about loosening the restrictions, but we don't have a design yet. Getting this wrong could break reparent / renaming for example, which could leave prim stranded if they are build from opinions from different layers and a single one gets renamed.

@@ -96,6 +96,7 @@ uint32_t findLayerIndex(const UsdPrim& prim, const SdfLayerHandle& layer)
// to find the layer
for (SdfLayerRefPtr const& l : layerStack->GetLayers()) {
if (l == layer) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would prefer an explicit set to false at line 105 when not found, for clarity.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This would also avoid the need for the explicit reset of the variable to false in the caller, when it tries to call this a 2nd time, below.

Copy link
Author

Choose a reason for hiding this comment

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

I think that's a good idea. Thanks!

@@ -451,8 +452,15 @@ bool isAttributeEditAllowed(const PXR_NS::UsdAttribute& attr, std::string* errMs
return false;
}

bool foundLayer = false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

If I'm going to nit-pick: I'd prefer this variable declaration below the comment, right next to the target index layer, since they go together.

Copy link
Author

Choose a reason for hiding this comment

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

Makes sense. Will do.

attr.GetBaseName().GetText(),
strongestLayer->GetDisplayName().c_str());
attr.GetName().GetText(),
strongestLayer->GetIdentifier().c_str());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe display both the display name and identifier? (IIRC, the identifier is the filename?)

Copy link
Author

Choose a reason for hiding this comment

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

identifier can be an a full URI also. I updated this message because we found displayName, which is the base filename of the identifier, was not helpful enough to troubleshoot issues for us.


// If the edit target layer not found in the prim's layer stack, we return true to allow
// new future edits go to the edit target layer.
if (!foundLayer)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This would allow authoring below the stronger opinion. Is the goal to allow new opinion on layers without opinion only above the strongest one or anywhere? Currently for us anywhere would go against the current design, so I'll have to talk to the designer and PO/PM about it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If your use case is that you want to edit in a layer that currently has no opinion but is above the layer, then you could add a check when the layer is not found: search the top opinion layer, iterating through its ancestors and if you find the target layer then allow the edit.

The code already retrieve the strongestLayer a bit below, so move that variable up and use if when foundLayer is false and check that the target is above.

If your goal is to author a weaker opinion, then we may have to make that desired behaviour optional somehow through a stage option or environment variable or some similar mechanism.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I just look ed at your test and it does seem to already only allow stronger opinions, so the code as it is now would be fine?

I thought that primIndex.GetNodeRange() would only return layers where there are authored opinions, but it returns all intermediary layers too? I guess I'd need to trace in the code with your test layers to confirm.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I just recreated your layer stack and tested it... and the edition of the foo attribute on prim B is already working without your changes. So it is the case that primIndex.GetNodeRange() return all layers, even those without opinions.

So, I think your test is not testing what you hoped it would? You can confirm this by commenting out the early return here and run your test and see if it indeed passes without your changes.

It also means your changes might not be doing what you think it would?

To start, I would need the answer to the first question: is the goal to only allow new opinions on stronger layers or on any layer, even weaker ones?

Copy link
Collaborator

Choose a reason for hiding this comment

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

For an example of checking stronger layer, here is a bit of code we added recently to allow creating child prim on a stronger layer. The function returns which layer is stronger and that fact is used when allowing the parent command:

SdfLayerHandle getStrongerLayer(

Copy link
Author

@NickWu NickWu Jul 12, 2022

Choose a reason for hiding this comment

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

I found another alternative solution other than using foundLayer boolean, which is to replace prim.GetPrimIndex() with prim.ComputeExpandedPrimIndex() at the following line:

const PcpPrimIndex& primIndex = prim.GetPrimIndex();

From the doc of GetPrimIndex https://graphics.pixar.com/usd/release/api/class_usd_prim.html#ae6ae4259af3ac06b8a9898a787202a32.
It says:

The prim index returned by this function is optimized and may not include sites that do not contribute opinions to this prim. Use UsdPrim::ComputeExpandedPrimIndex to compute a prim index that includes all possible sites that could contribute opinions.

So by using ComputeExpandedPrimIndex function instead of GetPrimIndex, we'll be able to return an index number from findLayerIndex function even if the edit target layer doesn't have opinions on the target prim yet (but might contribute opinions in future).

Which one do you prefer - using ComputeExpandedPrimIndex or foundLayer boolean?

*EDIT: Also, from the doc of ComputeExpandedPrimIndex https://graphics.pixar.com/usd/release/api/class_usd_prim.html#ad642cd45c3326bb0a75c209fcb0ec9eb. It does say it could be potentially slower then GetPrimIndex though.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Your new suggestion seems like a clean answer. I would have a slight preference for it, but either ways would be fine.

At the risk of repeating myself, my main concern is having a unit unit test that replicates the problems you are seeing that would fail without your changes and pass with your changes applied.

Copy link
Author

@NickWu NickWu Jul 14, 2022

Choose a reason for hiding this comment

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

Ok, I'll update the code to use ComputeExpandedPrimIndex instead of foundLayer boolean as it seems to be cleaner and less code changes to me. I'll also update the unit test when I get a chance. Thanks!

Copy link
Author

Choose a reason for hiding this comment

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

Hey @pierrebai-adsk , sorry for the late reply. I finally got some time to update this PR. I have updated the unit tests to mimic the issue we were having in our production and use ComputeExpandedPrimIndex function instead of foundLayer boolean for the solution. The test should pass with my change and fail without my change. Please have a look, thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hi, I was on vacations until today. I will review your changes today or tomorrow when I'm fully back up to speed.

@@ -347,6 +349,83 @@ def testAttributeBlocking3dMatrixOps(self):

# authoring new transformation edit is allowed.
self.assertTrue(mayaUsdUfe.isAttributeEditAllowed(transformAttr))

def testIsAttributeEditAllowedFunction(self):
rootLayerStr = """\
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add a function doc explaining the goal of the test.

Copy link
Author

Choose a reason for hiding this comment

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

Will do, thanks.

Copy link
Author

@NickWu NickWu left a comment

Choose a reason for hiding this comment

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

Thanks @pierrebai-adsk for taking a look. I'll be working on addressing your comments next.

@@ -96,6 +96,7 @@ uint32_t findLayerIndex(const UsdPrim& prim, const SdfLayerHandle& layer)
// to find the layer
for (SdfLayerRefPtr const& l : layerStack->GetLayers()) {
if (l == layer) {
Copy link
Author

Choose a reason for hiding this comment

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

I think that's a good idea. Thanks!

@@ -451,8 +452,15 @@ bool isAttributeEditAllowed(const PXR_NS::UsdAttribute& attr, std::string* errMs
return false;
}

bool foundLayer = false;
Copy link
Author

Choose a reason for hiding this comment

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

Makes sense. Will do.

attr.GetBaseName().GetText(),
strongestLayer->GetDisplayName().c_str());
attr.GetName().GetText(),
strongestLayer->GetIdentifier().c_str());
Copy link
Author

Choose a reason for hiding this comment

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

identifier can be an a full URI also. I updated this message because we found displayName, which is the base filename of the identifier, was not helpful enough to troubleshoot issues for us.

@@ -347,6 +349,83 @@ def testAttributeBlocking3dMatrixOps(self):

# authoring new transformation edit is allowed.
self.assertTrue(mayaUsdUfe.isAttributeEditAllowed(transformAttr))

def testIsAttributeEditAllowedFunction(self):
rootLayerStr = """\
Copy link
Author

Choose a reason for hiding this comment

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

Will do, thanks.


// If the edit target layer not found in the prim's layer stack, we return true to allow
// new future edits go to the edit target layer.
if (!foundLayer)
Copy link
Author

Choose a reason for hiding this comment

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

I just recreated your layer stack and tested it... and the edition of the foo attribute on prim B is already working without your changes. So it is the case that primIndex.GetNodeRange() return all layers, even those without opinions.

So, I think your test is not testing what you hoped it would? You can confirm this by commenting out the early return here and run your test and see if it indeed passes without your changes.

It also means your changes might not be doing what you think it would?

As I found that isAttributeEditAllowed was getting used in many places so my intention of my test was to confirm it's not breaking the previous behaviour and at the same time allowed our pipeline continue to work as it was in maya 2020.

To start, I would need the answer to the first question: is the goal to only allow new opinions on stronger layers or on any layer, even weaker ones?

The goal is to allow new opinions on stronger layers and this was not possible without the change.


// If the edit target layer not found in the prim's layer stack, we return true to allow
// new future edits go to the edit target layer.
if (!foundLayer)
Copy link
Author

Choose a reason for hiding this comment

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

If your use case is that you want to edit in a layer that currently has no opinion but is above the layer, then you could add a check when the layer is not found: search the top opinion layer, iterating through its ancestors and if you find the target layer then allow the edit.

The code already retrieve the strongestLayer a bit below, so move that variable up and use if when foundLayer is false and check that the target is above.

That's a good idea. I'll give it a try. Thanks!

@seando-adsk seando-adsk added the ready-for-merge Development process is finished, PR is ready for merge label Aug 31, 2022
@seando-adsk seando-adsk merged commit b483f61 into Autodesk:dev Aug 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-for-merge Development process is finished, PR is ready for merge ufe Related to UFE component in Maya unit test Related to unit tests (both python or c++)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants