-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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] factor out matching of xforms into PxrUsdMayaXformStack #287
[maya] factor out matching of xforms into PxrUsdMayaXformStack #287
Conversation
Filed as internal issue #151051. |
Just pushed an update for this PR - mostly just adds python wrappers and a bunch of tests (though also renames one of the class aliases). The commit in this PR is the consolidated version, if you want to see the incremental changes since the last push, you can see them here: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @elrond79, passing along code review notes from the sets team. We'd be happy to chat more about the comments re: FirstMatchingSubstack if that'd be helpful. Thanks!
MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/third_party/maya/plugin | ||
MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/third_party/maya/share/usd/plugins/usdMaya/resources | ||
MAYA_DISABLE_CIP=1 | ||
MAYA_APP_DIR=./maya_profile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we remove the MAYA_APP_DIR in this test registration for now, pending a resolution to the issues in #209?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, that was accidentally included. I'll get rid of it.
return std::vector<OpClassPtr>(); | ||
} | ||
|
||
/// \brief Runs MatchingSubstack against the given list of stacks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variadic template stuff here is neat, but we had some concerns about it because of the duplicated code in the Python wrapping. We'd really like to find a way to avoid that if possible.
Are there performance concerns or other reasons why this method couldn't accept something like a vector? I noticed PxrUsdMayaXformStack objects are non-copyable, but maybe we could relax that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, haven't done any benchmarking, but copying the entire stare object would end up copying multiple vectors, so I'd like to avoid it. I could make it take a vector of pointers, but then I'd either have to have it take raw pointers, or switch PxrUsdMayaXformStack to use either weak or ref ptrs.
I guess right now I'm leaning toward just making PxrUsdMayaXformStack derive from TfRefBase, switch everything to use refPtrs instead of refs, and then make FirstMatchingSubstack take a vector of those.
I'm also thinking I may just switch PxrUsdMayaXformOpClassification to use refPtrs, instead of weak ptrs... both for consistency with FirstMatchingSubstack, and because when I first chose weak ptrs, and because I've since realized that refPtrs are slightly lighter-weight (other than the initial copy from static memory to heap-allocated, but that will only be done once per stack). Again, will have to update everything to use refptrs... but will probably simplify things, and don't have to make any assumptions about how things are allocated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, after having found that you can't (or at least, it's difficult) to python-wrap const-ref-ptrs, I think I'm just going to make FirstMatchingSubstack take a vector of raw ptrs. It feels slightly yucky to use raw pointers, but it also feels like overkill to introduce weak pointers purely so they can be used with this function. Let me know if you'd prefer weak pointers, though (or any other approach), and I'll change it.
private: | ||
PxrUsdMayaXformStack( | ||
const OpClassList ops, | ||
const std::vector<std::pair<size_t, size_t> > inversionTwins, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean to pass a const-ref in here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, yes, that should be a const-ref. Good catch.
from maya.api import OpenMaya as OM | ||
from maya import standalone | ||
|
||
from pxr import Usd, UsdMaya |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you change the UsdMaya import here to look like they do in other tests, like:
https://github.com/PixarAnimationStudios/USD/blob/496775539c324af7cb2ea12ddbb80720865b6cb2/third_party/maya/lib/usdMaya/testenv/testUsdMayaReferenceAssemblyEdits.py#L26-L31
This is unfortunately an internal build issue that affects the USD repository; we'd like to fix the issue so this won't be needed in the future, but in the meantime we'd appreciate the change here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, easy fix...
@@ -164,6 +166,7 @@ pxr_test_scripts( | |||
testenv/testUsdMayaProxyShape.py | |||
testenv/testUsdMayaReferenceAssemblyEdits.py | |||
testenv/testUsdMayaUserExportedAttributes.py | |||
testenv/testUsdMayaXformStack.py |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for adding a test!
45172c6
to
c0f2461
Compare
Addressed the code review notes, as well as converted over both classes to be "value types", that store a refPtr to the actual data. Since both are immutable classes, this seemed a good compromise between safety / performance (ie, refPtr is lighter weight than weakPtr) / and ease-of-python-wrapping. Thanks to Alex Mohr for the suggestion! Once again, this is the collapsed PR - the (new) incremental changesets can be seen here: LumaPictures@728dfed |
Thanks! I've pulled these changes over again and am running them through builds now |
Unfortunately this change is causing some internal test failures for usdExport. I'm looking at this further now, I will see if I can package up the test and send it your way to get your take on it. |
Ok... so the test break is due to specifying rotateAxis using a single-axis (rotateX) xformOp. I had set rotateAxis to only accept rotateXYZ ops... because, unlike the "rotate" xform, it has no support for changing the rotation order (and, in fact, under the hood it's stored as a quaternion anyway!)... but it should at least be able to accept single-axis rotates, if not things like rotateZXY. However... on thinking about it a bit more, I think this highlights one of the current shortcomings of my design - the maya-centric way in which it's handling rotation order. Granted, it's currently only used for Maya... but it was designed in a way that should be usable by other applications. For rotation order, though, it assumes that is set based off of the "rotate" op... and in fact, it sets a maya-only class (MTransformationMatrix::RotationOrder) to indicate what it what set to. In a more general case, it's entirely possible for an xform stack to have 2 (or more) rotation ops, all of which may have their own independent rotation orders... so I think I'm going to get rid of handling of rotation-order as part of the API. Instead, the paradigm will be:
I should have these changes (and some more tests) by EOD |
Hi Paul,
Apologies as I haven't reviewed the code, but based on the last set of comments about rotationOrder, I just wanted to confirm that it will still be possible, using the new API, to encode triple-axis rotations in USD, as they will be three times faster to read than three single-axis, which adds up at scale.
…--Spiff
On Oct 25, 2017, at 11:09 AM, Paul Molodowitch ***@***.***> wrote:
Ok... so the test break is due to specifying rotateAxis using a single-axis (rotateX) xformOp. I had set rotateAxis to only accept rotateXYZ ops... because, unlike the "rotate" xform, it has no support for changing the rotation order (and, in fact, under the hood it's stored as a quaternion anyway!)... but it should at least be able to accept single-axis rotates, if not things like rotateZXY.
However... on thinking about it a bit more, I think this highlights one of the current shortcomings of my design - the maya-centric way in which it's handling rotation order. Granted, it's currently only used for Maya... but it was designed in a way that should be usable by other applications. For rotation order, though, it assumes that is set based off of the "rotate" op... and in fact, it sets a maya-only class (MTransformationMatrix::RotationOrder) to indicate what it what set to.
In a more general case, it's entirely possible for an xform stack to have 2 (or more) rotation ops, all of which may have their own independent rotation orders... so I think I'm going to get rid of handling of rotation-order as part of the API. Instead, the paradigm will be:
any 3-axis rotate in a stack is compatible with any-other 3-axis rotate (or 1-axis rotate)... since, at minimum, it is always possible to convert between them
it will be the responsibility of the user of the API to check the rotate-order of the matched xforms, and either set a rotate order in their app, or convert, as appropriate to their context
therefore, the optional RotationOrder* pointer will be dropped from the API for MatchingSubstack / FirstMatchingSubstack
I should have these changes (and some more tests) by EOD
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
c0f2461
to
afa18ee
Compare
So, made the changes I mentioned above. rotateAxis can now handle single-axis rotations, as well as will automatically cross-convert from non-XYZ-ordered triple-axis rotates. @spiffmon absolutely, triple-axis rotates are still recorded as such. I just meant that if you have a USD file that records it's rotateAxis as rotateYZX, this new version will automatically convert that to rotateXYZ on import, which is the only format that transform nodes will accept as input. It means that the maya stack is now slighly more tolerant (though an xformOp:rotateYZX:rotateAxis will not round-trip - ie, it will import fine, and maintain the same transformation / rotation, but when you re-ouput a new USD, it will be xformOp:rotateXYZ:rotateAxis). |
Oh, also, in case you want to see incremental commits: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our sets team had a few more notes in review, mostly just cosmetic cleanup and documentation updates. There's one larger note about not using exceptions in the codebase, but this should be hopefully easily replaced with TF_VERIFY.
Thanks!
@@ -0,0 +1,1161 @@ | |||
#!/pxrpythonsubst | |||
# | |||
# Copyright 2016 Pixar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2017 :)
|
||
PxrUsdMayaXformStack( | ||
const OpClassList& ops, | ||
const std::vector<std::pair<size_t, size_t> >& inversionTwins, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be const std::vector<IndexPair>& ...
?
OpClassList const & GetOps() const; | ||
|
||
PXRUSDMAYA_API | ||
std::vector<std::pair<size_t, size_t> > const & GetInversionTwins() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use const std::vector<IndexPair>& ...
here as well?
/// \param opName the name of the operator classification we wish to find | ||
/// \param isInvertedTwin the returned op classification object must match | ||
/// this param for it's IsInvertedTwin() - if an op is found that matches | ||
/// the name, but has the wrong invertedTwin status, nullptr is returned |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this should be "NO_INDEX is returned" instead of "nullptr is returned"
/// \param isInvertedTwin the returned op classification object must match | ||
/// this param for it's IsInvertedTwin() - if an op is found that matches | ||
/// the name, but has the wrong invertedTwin status, nullptr is returned | ||
/// return Undex to the op classification object with the given name (and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor typo: "Undex" instead of "Index"
|
||
_PxrUsdMayaXformStackData( | ||
const OpClassList& ops, | ||
const std::vector<std::pair<size_t, size_t> >& inversionTwins, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const std::vector<IndexPair>& ...
here?
return _sharedData->m_ops; | ||
} | ||
|
||
std::vector<std::pair<size_t, size_t> > const & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const std::vector<IndexPair>& ...
here?
// Insert, and check if it already existed | ||
if (!result.insert({attrName, indexPair}).second) | ||
{ | ||
// The attrName was already in the lookup map... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our coding convention is to not use exceptions in our code, so we'd prefer not to throw here. If this is something that should never happen (i.e., it's an invariant in the code and not reliant on user input), we prefer to use TF_VERIFY to indicate that something is wrong, like:
TF_VERIFY(result.insert({attrName, indexPair}).second,
"AttrName %s already found in attrName lookup map",
attrName.GetText());
This will cause the error output to be emitted if the condition is false, but allows the code to continue executing so that it doesn't cause the program to crash.
std::string msg = TfStringPrintf( | ||
"Op classification name %s already found in op lookup map", | ||
op.GetName().GetText()); | ||
throw std::invalid_argument(msg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See note about exceptions and TF_VERIFY above
{ | ||
const PxrUsdMayaXformOpClassification& first = m_ops[pair.first]; | ||
const PxrUsdMayaXformOpClassification& second = m_ops[pair.second]; | ||
if (first.GetName() != second.GetName()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See note about exceptions and TF_VERIFY above
afa18ee
to
129d38b
Compare
129d38b
to
007e6c0
Compare
Ok, addressed the notes. Incremental commit can be found here: Also made one other small tweak - marking the python wrapper for XformStack as noncopyable: |
[maya] factor out matching of xforms into PxrUsdMayaXformStack
Just wanted to note I had added a follow-up commit ddd583f to fix a build issue on Windows. I also had to remove the noncopyable change to the XformStack's Python wrapping, as it caused the associated unit test to fail. |
Doh - my mistake. Completely forgot that I had switched to the shared-data-ref-ptr paradigm, and that copies were now ok / preferred! In any case, thanks! |
Description of Change(s)
This factors out the code for defining standardized transform stacks into a new class, xformStack. This class is also responsible for checking compatibility with existing usd xform stacks. This code is also exposed through the API for use externally.
There's actually nothing in the code which is specific to maya, so in theory it could be promoted to somewhere in the usd core, but it may be premature if it's not used anywhere else yet... and, of course, I'm sure that would warrant a higher level of scrutiny.
Speaking of scrutiny - I'm planning to add some unit tests, but wanted to give a chance for comment now!