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

EMSUSD-26 fix center pivot command #3755

Merged
merged 1 commit into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/mayaUsd/ufe/UsdTransform3dMayaXformStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <usdUfe/undo/UsdUndoableItem.h>
#include <usdUfe/utils/editRouterContext.h>

#include <pxr/base/gf/math.h>

#include <maya/MEulerRotation.h>
#include <maya/MGlobal.h>

Expand Down Expand Up @@ -109,6 +111,13 @@ const std::unordered_map<TfToken, UsdTransform3dMayaXformStack::OpNdx, TfToken::
UsdTransform3dMayaXformStack::NdxPivotInverse }
};

bool isAlmostZero(const Ufe::Vector3d& value)
{
static const double epsilon = 0.0001;
return PXR_NS::GfIsClose(0., value.x(), epsilon) && PXR_NS::GfIsClose(0., value.y(), epsilon)
&& PXR_NS::GfIsClose(0., value.z(), epsilon);
}

} // namespace

namespace MAYAUSD_NS_DEF {
Expand Down Expand Up @@ -539,6 +548,26 @@ Ufe::Vector3d UsdTransform3dMayaXformStack::scalePivot() const
Ufe::TranslateUndoableCommand::Ptr
UsdTransform3dMayaXformStack::translateRotatePivotCmd(double x, double y, double z)
{
// Note: USD and Maya use different pivots: USD has a single pivot that is used
// for both translation and scale, while Maya has separate ones. When working
// in this Maya transform stack mode, the USD pivot affects the position of
// the manipulators, so we need to take it into account here.
//
// Otherwise, prim with USD-style picot won't work with the "center pivot"
// command.
TfToken commonPivotName
= UsdGeomXformOp::GetOpName(UsdGeomXformOp::TypeTranslate, UsdGeomTokens->pivot);
auto commonPivotAttr = prim().GetAttribute(commonPivotName);
if (commonPivotAttr && commonPivotAttr.HasAuthoredValue()) {
Ufe::Vector3d commonPivot = getVector3d<GfVec3f>(commonPivotName);
if (!isAlmostZero(commonPivot)) {
x = commonPivot.x() - x;
y = commonPivot.y() - y;
z = commonPivot.z() - z;
return setVector3dCmd(GfVec3f(x, y, z), commonPivotName);
}
}

auto opSuffix = getOpSuffix(NdxRotatePivotTranslate);
auto attrName = UsdGeomXformOp::GetOpName(UsdGeomXformOp::TypeTranslate, opSuffix);
return setVector3dCmd(GfVec3f(x, y, z), attrName, opSuffix);
Expand Down
96 changes: 96 additions & 0 deletions test/lib/ufe/testCenterPivot.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,102 @@ def verifyPointInstancerPosition():
# Verify the object did not move.
verifyPointInstancerPosition()

def testCenterPivotWithUSDPivot(self):
'''
Test centering the pivot when teh USD file has a USD-style pivot,
not a Maya-style pivot.

UFE Feature : Transform3d
Maya Feature : center pivot
Action : Center the pivot.
Applied On Selection : the Maya command always uses the selection.

Undo/Redo Test : Maya undoable command only.
'''
# Open the USD file containing the prim we want to affect.
testFile = getTestScene("pivot", "cube-far-pivot.usda")
testDagPath, stage = mayaUtils.createProxyFromFile(testFile)
self.assertIsNotNone(stage)

# Retrieve the UFE item to the prim and the prim.
cubeUfePathString = testDagPath + ",/Cube1"
cubeUfePath = ufe.PathString.path(cubeUfePathString)
cubeUfeItem = ufe.Hierarchy.createItem(cubeUfePath)
self.assertIsNotNone(cubeUfeItem)
cubeUsdPrim = stage.GetPrimAtPath("/Cube1")
self.assertIsNotNone(cubeUsdPrim)

# Verify the cube overall position.
def verifyCubePosition():
cubeUfeT3d = ufe.Transform3d.transform3d(cubeUfeItem)
cubeUfeMtx = cubeUfeT3d.matrix()
flatMtx = []
for row in cubeUfeMtx.matrix:
flatMtx.extend(row)
assertVectorAlmostEqual(self, flatMtx, [ 1., 0., 0., 0.,
0., 1., 0., 0.,
0., 0., 1., 0.,
0., 20., 0., 1.])

verifyCubePosition()

def verifyCubeUSDPivots(trPivot, tPivot, tsPivot, tstPivot):
namesAndValues = [
('xformOp:translate:rotatePivot', trPivot),
('xformOp:translate:pivot', tPivot), # Equivalent to trt below
('xformOp:translate:scalePivot', tsPivot),
('xformOp:translate:scalePivotTranslate', tstPivot),
]
for name, value in namesAndValues:
usdAttr = cubeUsdPrim.GetAttribute(name)
self.assertIsNotNone(usdAttr)
assertVectorAlmostEqual(self, usdAttr.Get(), value)

verifyCubeUSDPivots(
[2., -3., -1.], # translate rotate pivot
[7., 7., 8.], # translate pivot (equivalent to translate rotate translate pivot)
[2., -3., -1.], # translate scale pivot
[0., 0., 0.] # translate scale translate pivot
)

def verifyCubeUFEPivots(trPivot, trtPivot, tsPivot, tstPivot):
cubeUfeT3d = ufe.Transform3d.transform3d(cubeUfeItem)

assertVectorAlmostEqual(self, cubeUfeT3d.rotatePivot().vector, trPivot)
assertVectorAlmostEqual(self, cubeUfeT3d.rotatePivotTranslation().vector, trtPivot)
assertVectorAlmostEqual(self, cubeUfeT3d.scalePivot().vector, tsPivot)
assertVectorAlmostEqual(self, cubeUfeT3d.scalePivotTranslation().vector, tstPivot)

verifyCubeUFEPivots(
[2., -3., -1.], # translate rotate pivot
[7., 7., 8.], # translate rotate translate pivot
[2., -3., -1.], # translate scale pivot
[0., 0., 0.] # translate scale translate pivot
)

# Select the prim.
sn = ufe.GlobalSelection.get()
sn.clear()
sn.append(cubeUfeItem)

cmds.CenterPivot()

# Verify the object did not move.
verifyCubePosition()

verifyCubeUSDPivots(
[0., 0., 0.], # translate rotate pivot
[0., 0., 0.], # translate pivot (equivalent to translate rotate translate pivot)
[0., 0., 0.], # translate scale pivot
[0., 0., 0.] # translate scale translate pivot
)

verifyCubeUFEPivots(
[0., 0., 0.], # translate rotate pivot
[0., 0., 0.], # translate rotate translate pivot
[0., 0., 0.], # translate scale pivot
[0., 0., 0.] # translate scale translate pivot
)

if __name__ == '__main__':
unittest.main(verbosity=2)
36 changes: 36 additions & 0 deletions test/testSamples/pivot/cube-far-pivot.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#usda 1.0
(
defaultPrim = "Cube1"
endTimeCode = 12
framesPerSecond = 24
metersPerUnit = 0.01
startTimeCode = 12
timeCodesPerSecond = 24
upAxis = "Z"
)

def Mesh "Cube1" (
kind = "component"
)
{
uniform bool doubleSided = 1
float3[] extent = [(-5, -5, -5), (5, 5, 5)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
point3f[] points = [(-5, -5, 5), (5, -5, 5), (-5, 5, 5), (5, 5, 5), (-5, 5, -5), (5, 5, -5), (-5, -5, -5), (5, -5, -5)]
color3f[] primvars:displayColor = [(0.13320851, 0.13320851, 0.13320851)] (
customData = {
dictionary Maya = {
bool generated = 1
}
}
)

double3 xformOp:translate = (0, 20, 0)
float3 xformOp:translate:pivot = (7, 7, 8)
float3 xformOp:translate:rotatePivot = (2, -3, -1)
float3 xformOp:translate:scalePivot = (2, -3, -1)
float3 xformOp:translate:scalePivotTranslate = (0, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:translate:pivot", "xformOp:translate:rotatePivot", "!invert!xformOp:translate:rotatePivot", "xformOp:translate:scalePivotTranslate", "xformOp:translate:scalePivot", "!invert!xformOp:translate:scalePivot", "!invert!xformOp:translate:pivot"]
}