Skip to content

Commit

Permalink
[maya] xformStack - remove handling of rotation order from API
Browse files Browse the repository at this point in the history
  • Loading branch information
pmolodo committed Oct 25, 2017
1 parent 9bb528b commit 3215095
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 186 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#usda 1.0
(
defaultPrim = "World"
upAxis = "Z"
)

def Xform "World" (
kind = "component"
)
{
def Xform "X"
{
float xformOp:rotateX:rotateAxis = 60
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateX:rotateAxis", "xformOp:scale"]
}

def Xform "Y"
{
float xformOp:rotateY:rotateAxis = 60
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateY:rotateAxis", "xformOp:scale"]
}

def Xform "Z"
{
float xformOp:rotateZ:rotateAxis = 60
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZ:rotateAxis", "xformOp:scale"]
}

def Xform "XYZ"
{
float3 xformOp:rotateXYZ:rotateAxis = (60, 120, 180)
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ:rotateAxis", "xformOp:scale"]
}

def Xform "YZX"
{
float3 xformOp:rotateYZX:rotateAxis = (60, 120, 180)
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateYZX:rotateAxis", "xformOp:scale"]
}

def Xform "ZXY"
{
float3 xformOp:rotateZXY:rotateAxis = (60, 120, 180)
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZXY:rotateAxis", "xformOp:scale"]
}

def Xform "XZY"
{
float3 xformOp:rotateXZY:rotateAxis = (60, 120, 180)
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXZY:rotateAxis", "xformOp:scale"]
}

def Xform "YXZ"
{
float3 xformOp:rotateYXZ:rotateAxis = (60, 120, 180)
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateYXZ:rotateAxis", "xformOp:scale"]
}

def Xform "ZYX"
{
float3 xformOp:rotateZYX:rotateAxis = (60, 120, 180)
float3 xformOp:scale = (0.5, 0.5, 0.5)
double3 xformOp:translate = (1.0, 2.0, 3.0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZYX:rotateAxis", "xformOp:scale"]
}
}
48 changes: 45 additions & 3 deletions third_party/maya/lib/usdMaya/testenv/testUsdImportXforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ def setUpClass(cls):
standalone.initialize('usd')
cmds.loadPlugin('pxrUsd')

usdFile = os.path.abspath('UsdImportXformsTest.usda')
cmds.usdImport(file=usdFile, shadingMode='none')

@classmethod
def tearDownClass(cls):
standalone.uninitialize()
Expand All @@ -62,6 +59,9 @@ def testImportInverseXformOpsOnly(self):
Tests that importing a USD cube mesh that has XformOps on it all tagged
as inverse ops results in the correct transform when imported into Maya.
"""
usdFile = os.path.abspath('UsdImportXformsTest.usda')
cmds.usdImport(file=usdFile, shadingMode='none')

mayaTransform = self._GetMayaTransform('InverseOpsOnlyCube')
transformationMatrix = mayaTransform.transformation()

Expand Down Expand Up @@ -189,6 +189,48 @@ def testImportMayaXformVariations(self):
print "full failed xform:"
pprint.pprint(attrVals)
raise

def testImportXformsRotateAxis(self):
"""
Tests that importing xforms that have a rotateAxis with rotate order other than just XYZ
still imports correctly
"""
usdFile = os.path.abspath('UsdImportXformsTestRotateAxis.usda')
cmds.usdImport(file=usdFile, shadingMode='none')

expectedRotates = {
'X': (60, 0, 0),
'Y': (0, 60, 0),
'Z': (0, 0, 60),
'XYZ': (-120, 60, 0),
'YZX': (-106.1021138, 25.6589063, 56.3099325),
'ZXY': (120, -60, 0),
'XZY': (-120, -60, 0),
'YXZ': (106.1021138, 25.6589063, -56.3099325),
'ZYX': (-106.1021138, -25.6589063, -56.3099325),
}
expectedScale = (.5, .5, .5)
expectedTranslation = (1.0, 2.0, 3.0)

for rotOrderName, expectedRotation in expectedRotates.iteritems():
mayaTransform = self._GetMayaTransform(rotOrderName)
transformationMatrix = mayaTransform.transformation()

actualTranslation = list(
transformationMatrix.translation(OM.MSpace.kTransform))
self.assertTrue(
Gf.IsClose(expectedTranslation, actualTranslation, self.EPSILON))

expectedRotation = [Gf.DegreesToRadians(x) for x in expectedRotation]
actualRotation = transformationMatrix.rotationOrientation().asEulerRotation()
actualRotation = list(actualRotation)
#print rotOrderName, actualRotation
self.assertTrue(
Gf.IsClose(expectedRotation, actualRotation, self.EPSILON))

actualScale = list(transformationMatrix.scale(OM.MSpace.kTransform))
self.assertTrue(
Gf.IsClose(expectedScale, actualScale, self.EPSILON))


if __name__ == '__main__':
Expand Down
73 changes: 52 additions & 21 deletions third_party/maya/lib/usdMaya/testenv/testUsdMayaXformStack.py
Original file line number Diff line number Diff line change
Expand Up @@ -872,30 +872,65 @@ def testMatchingSubstack_rotOrder(self):
self.ops['rotateYXZ'] = self.xform.AddRotateYXZOp(opSuffix='rotate')
self.ops['rotateZYX'] = self.xform.AddRotateZYXOp(opSuffix='rotate')

allRotates = [
'rotateX',
'rotateY',
'rotateZ',
'rotateXYZ',
'rotateYZX',
'rotateZXY',
'rotateXZY',
'rotateYXZ',
'rotateZYX',
]

expectedList = [self.stack.FindOp('translate'), self.stack.FindOp('rotate')]
for rotateOpName in allRotates:
orderedOps = [self.ops['translate'], self.ops[rotateOpName]]
resultList = self.stack.MatchingSubstack(orderedOps)
self.assertEqual(resultList, expectedList)

# test a failed match
orderedOps = [self.ops[rotateOpName], self.ops['translate']]
resultList = self.stack.MatchingSubstack(orderedOps)
self.assertEqual(resultList, [])

def testMatchingSubstack_rotOrder_rotAxis(self):
from maya.OpenMaya import MEulerRotation

self.makeMayaStackAttrs()
self.ops['rotateAxisX'] = self.xform.AddRotateXOp(opSuffix='rotateAxis')
self.ops['rotateAxisY'] = self.xform.AddRotateYOp(opSuffix='rotateAxis')
self.ops['rotateAxisZ'] = self.xform.AddRotateZOp(opSuffix='rotateAxis')
self.ops['rotateAxisXYZ'] = self.ops['rotateAxis']
self.ops['rotateAxisYZX'] = self.xform.AddRotateYZXOp(opSuffix='rotateAxis')
self.ops['rotateAxisZXY'] = self.xform.AddRotateZXYOp(opSuffix='rotateAxis')
self.ops['rotateAxisXZY'] = self.xform.AddRotateXZYOp(opSuffix='rotateAxis')
self.ops['rotateAxisYXZ'] = self.xform.AddRotateYXZOp(opSuffix='rotateAxis')
self.ops['rotateAxisZYX'] = self.xform.AddRotateZYXOp(opSuffix='rotateAxis')

allRotates = {
'rotateX': MEulerRotation.kXYZ,
'rotateY': MEulerRotation.kXYZ,
'rotateZ': MEulerRotation.kXYZ,
'rotateXYZ': MEulerRotation.kXYZ,
'rotateYZX': MEulerRotation.kYZX,
'rotateZXY': MEulerRotation.kZXY,
'rotateXZY': MEulerRotation.kXZY,
'rotateYXZ': MEulerRotation.kYXZ,
'rotateZYX': MEulerRotation.kZYX,
'rotateAxisX',
'rotateAxisY',
'rotateAxisZ',
'rotateAxisXYZ',
'rotateAxisYZX',
'rotateAxisZXY',
'rotateAxisXZY',
'rotateAxisYXZ',
'rotateAxisZYX',
}

expectedList = [self.stack.FindOp('translate'), self.stack.FindOp('rotate')]
for rotateOpName, expectedRotateOrder in allRotates.iteritems():
expectedList = [self.stack.FindOp('translate'), self.stack.FindOp('rotateAxis')]
for rotateOpName in allRotates:
orderedOps = [self.ops['translate'], self.ops[rotateOpName]]
resultList, resultRotateOrder = self.stack.MatchingSubstack(orderedOps, returnRotOrder=True)
resultList = self.stack.MatchingSubstack(orderedOps)
self.assertEqual(resultList, expectedList)
self.assertEqual(resultRotateOrder, expectedRotateOrder)

# test a failed match
orderedOps = [self.ops[rotateOpName], self.ops['translate']]
resultList, resultRotateOrder = self.stack.MatchingSubstack(orderedOps, returnRotOrder=True)
resultList = self.stack.MatchingSubstack(orderedOps)
self.assertEqual(resultList, [])
self.assertEqual(resultRotateOrder, MEulerRotation.kXYZ)

def doFirstMatchingTest(self, stacks, opNames, matchingStack, expectEmpty=False):
orderedOps, expected = self.makeXformOpsAndExpectedClassifications(
Expand Down Expand Up @@ -1114,16 +1149,12 @@ def stackName(x):
errMessage = '\nstackNames: ' + str(stackNames)

expectNone = not (mayaStack in stackList or commonStack in stackList)
# resultList, resultRotateOrder = UsdMaya.XformStack.FirstMatchingSubstack(
# stackList, orderedOps, returnRotOrder=True)
resultList, resultRotateOrder = UsdMaya.XformStack.FirstMatchingSubstack(
stackList, orderedOps, True)
resultList = UsdMaya.XformStack.FirstMatchingSubstack(
stackList, orderedOps)
if expectNone:
self.assertEqual(resultList, [], str(stackNames))
self.assertEqual(resultRotateOrder, MEulerRotation.kXYZ, errMessage)
else:
self.assertEqual(resultList, expectedList, str(stackNames))
self.assertEqual(resultRotateOrder, expectedRotateOrder, errMessage)


if __name__ == '__main__':
Expand Down
50 changes: 39 additions & 11 deletions third_party/maya/lib/usdMaya/translatorXformable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <maya/MDagModifier.h>
#include <maya/MFnAnimCurve.h>
#include <maya/MFnTransform.h>
#include <maya/MEulerRotation.h>
#include <maya/MGlobal.h>
#include <maya/MPlug.h>
#include <maya/MTransformationMatrix.h>
Expand Down Expand Up @@ -261,6 +262,43 @@ static bool _pushUSDXformOpToMayaXform(
_setMayaAttribute(MdagNode, xValue, yValue, zValue, timeArray, MString("scalePivotTranslate"), "X", "Y", "Z", context);
}
else {
if (opName==PxrUsdMayaXformStackTokens->rotate) {
MFnTransform trans;
if(trans.setObject(MdagNode.object()))
{
auto MrotOrder =
PxrUsdMayaXformStack::RotateOrderFromOpType<MTransformationMatrix::RotationOrder>(
xformop.GetOpType());
MPlug plg = MdagNode.findPlug("rotateOrder");
if ( !plg.isNull() ) {
trans.setRotationOrder(MrotOrder, /*no need to reorder*/ false);
}
}
}
else if(opName==PxrUsdMayaXformStackTokens->rotateAxis)
{
// Rotate axis only accepts input in XYZ form
// (though it's actually stored as a quaternion),
// so we need to convert other rotation orders to XYZ
const auto opType = xformop.GetOpType();
if (opType != UsdGeomXformOp::TypeRotateXYZ
&& opType != UsdGeomXformOp::TypeRotateX
&& opType != UsdGeomXformOp::TypeRotateY
&& opType != UsdGeomXformOp::TypeRotateZ)
{
for (size_t i = 0u; i < xValue.size(); ++i)
{
auto MrotOrder =
PxrUsdMayaXformStack::RotateOrderFromOpType<MEulerRotation::RotationOrder>(
xformop.GetOpType());
MEulerRotation eulerRot(xValue[i], yValue[i], zValue[i], MrotOrder);
eulerRot.reorderIt(MEulerRotation::kXYZ);
xValue[i] = eulerRot.x;
yValue[i] = eulerRot.y;
zValue[i] = eulerRot.z;
}
}
}
_setMayaAttribute(MdagNode, xValue, yValue, zValue, timeArray, MString(opName.GetText()), "X", "Y", "Z", context);
}
return true;
Expand Down Expand Up @@ -383,8 +421,6 @@ PxrUsdMayaTranslatorXformable::Read(
std::vector<UsdGeomXformOp> xformops = xformSchema.GetOrderedXformOps(
&resetsXformStack);

MTransformationMatrix::RotationOrder MrotOrder = MTransformationMatrix::kXYZ;

// When we find ops, we match the ops by suffix ("" will define the basic
// translate, rotate, scale) and by order. If we find an op with a
// different name or out of order that will miss the match, we will rely on
Expand All @@ -396,7 +432,7 @@ PxrUsdMayaTranslatorXformable::Read(
&PxrUsdMayaXformStack::MayaStack(),
&PxrUsdMayaXformStack::CommonStack()
},
xformops, &MrotOrder);
xformops);

bool importedPivots = false;
MFnDagNode MdagNode(mayaNode);
Expand All @@ -411,14 +447,6 @@ PxrUsdMayaTranslatorXformable::Read(

const TfToken& opName(opDef.GetName());

if (opName==PxrUsdMayaXformStackTokens->rotate) {
MPlug plg = MdagNode.findPlug("rotateOrder");
if ( !plg.isNull() ) {
MFnTransform trans;
trans.setObject(mayaNode);
trans.setRotationOrder(MrotOrder, /*no need to reorder*/ false);
}
}
_pushUSDXformOpToMayaXform(xformop, opName, MdagNode, &importedPivots,
args, context);
}
Expand Down
Loading

0 comments on commit 3215095

Please sign in to comment.