def setUp(self): # Load plugins self.assertTrue(self.pluginsLoaded) # Load a file that has the same scene in both the Maya Dag # hierarchy and the USD hierarchy. mayaUtils.openTestScene("parentCmd", "simpleSceneMayaPlusUSD_TRS.ma") # Create multiple scene items. We will alternate between selecting a # Maya item and a USD item, 3 items each data model, one item at a # time, so we select 6 different items, one at a time. shapeSegment = mayaUtils.createUfePathSegment( "|mayaUsdProxy1|mayaUsdProxyShape1") ufeNames = ["cubeXform", "cylinderXform", "sphereXform"] mayaNames = ["pCube1", "pCylinder1", "pSphere1"] usdPaths = [] for n in ["/" + o for o in ufeNames]: usdPaths.append( ufe.Path([shapeSegment, usdUtils.createUfePathSegment(n)])) mayaPaths = [] for n in ["|" + o for o in mayaNames]: mayaPaths.append(ufe.Path(mayaUtils.createUfePathSegment(n))) # Create a list of paths by alternating USD objects and Maya objects # Flatten zipped tuples using list comprehension double loop. zipped = zip(usdPaths, mayaPaths) paths = [j for i in zipped for j in i] # Create items for all paths. self.items = [ufe.Hierarchy.createItem(p) for p in paths] # Clear selection to start off cmds.select(clear=True)
def testMultiSelectMoveUSD(self): '''Move multiple USD objects, read through Transform3d interface.''' # Select multiple balls to move them. proxyShapePathSegment = mayaUtils.createUfePathSegment( "|transform1|proxyShape1") balls = ['Ball_33', 'Ball_34'] ballPaths = [ ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/' + ball) ]) for ball in balls ] ballItems = [ ufe.Hierarchy.createItem(ballPath) for ballPath in ballPaths ] for ballItem in ballItems: ufe.GlobalSelection.get().append(ballItem) # We compare the UFE translation with the USD run-time translation. To # obtain the full translation of USD scene items, we need to add the USD # translation to the Maya proxy shape translation. proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath( 0).node() proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) def usdSceneItemTranslation(item): prim = usdUtils.getPrimFromSceneItem(item) if not prim.HasAttribute('xformOp:translate'): return proxyShapeXformFn.translation(om.MSpace.kTransform) else: return addVec( proxyShapeXformFn.translation(om.MSpace.kTransform), prim.GetAttribute('xformOp:translate').Get()) def ufeSceneItemTranslation(item): return transform3dTranslation(ufe.Transform3d.transform3d(item)) # Set up the callables that will retrieve the translation. self.runTimeTranslation = usdSceneItemTranslation self.ufeTranslation = ufeSceneItemTranslation # Give the tail item in the selection an initial translation that # is different, to catch bugs where the relative translation # incorrectly squashes any existing translation. backItem = ballItems[-1] backT3d = ufe.Transform3d.transform3d(backItem) initialTranslation = [-10, -20, -30] backT3d.translate(*initialTranslation) assertVectorAlmostEqual(self, ufeSceneItemTranslation(backItem), usdSceneItemTranslation(backItem)) # Save the initial positions to the memento list. expected = [ usdSceneItemTranslation(ballItem) for ballItem in ballItems ] self.runMultiSelectTestMove(ballItems, expected)
def setUp(self): ''' Called initially to set up the maya test environment ''' # Load plugins self.assertTrue(self.pluginsLoaded) # These tests requires no additional setup. if self._testMethodName in [ 'testAddNewPrim', 'testAddNewPrimWithDelete' ]: return # Open top_layer.ma scene in testSamples mayaUtils.openTopLayerScene() # Clear selection to start off. ufe.GlobalSelection.get().clear() # Select Ball_35. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35") ]) self.ball35Item = ufe.Hierarchy.createItem(ball35Path) self.ball35Prim = usdUtils.getPrimFromSceneItem(self.ball35Item) ufe.GlobalSelection.get().append(self.ball35Item) # Create a ContextOps interface for it. self.contextOps = ufe.ContextOps.contextOps(self.ball35Item)
def testStaticUsdCamera(self): self._StartTest('TranslateRotate_vs_xform') mayaPathSegment = mayaUtils.createUfePathSegment('|stage|stageShape') #camera1 doesn't work correctly right now because of an xformOp:transform issue MAYA-110515 #cam1UsdPathSegment = usdUtils.createUfePathSegment('cameras/cam1/camera1') #cmds.lookThru('|stage|stageShape,/cameras/cam1/camera1') #self.assertSnapshotClose('%s_cam1_unselected.png' % self._testName) cmds.lookThru('|stage|stageShape,/cameras/cam2/camera2') self.assertSnapshotClose('%s_cam2_unselected.png' % self._testName) # create a Ufe transform3d and move cam2 somewhere else and do a snapshot cam2UsdPathSegment = usdUtils.createUfePathSegment( '/cameras/cam2/camera2') cam2Path = ufe.Path([mayaPathSegment, cam2UsdPathSegment]) cam2Item = ufe.Hierarchy.createItem(cam2Path) cam2Transform3d = ufe.Transform3d.transform3d(cam2Item) cam2Transform3d.translate(-1, 0, 0) self.assertSnapshotClose('%s_cam2_translated.png' % self._testName) # create a Ufe Camera and modify the near clip plane and do a snapshot # ufe.Camera is not in Ufe 2.0.0 MAYA-110675 # set the clipping range using the USD API instead usdCamera = usdUtils.getPrimFromSceneItem(cam2Item) clippingAttr = usdCamera.GetAttribute('clippingRange') clippingRange = clippingAttr.Get() clippingAttr.Set(Gf.Vec2f(10, 5000)) self.assertSnapshotClose('%s_cam2_insideNearClipPlane.png' % self._testName)
def testAttributes(self): '''Engine method to run attributes test.''' # Get a UFE scene item for one of the balls in the scene. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35") ]) ball35Item = ufe.Hierarchy.createItem(ball35Path) # Then create the attributes interface for that item. ball35Attrs = ufe.Attributes.attributes(ball35Item) self.assertIsNotNone(ball35Attrs) # Test that we get the same scene item back. self.assertEqual(ball35Item, ball35Attrs.sceneItem()) # Verify that ball35 contains the visibility attribute. self.assertTrue(ball35Attrs.hasAttribute(UsdGeom.Tokens.visibility)) # Verify the attribute type of 'visibility' which we know is a enum token. self.assertEqual(ball35Attrs.attributeType(UsdGeom.Tokens.visibility), ufe.Attribute.kEnumString) # Get all the attribute names for this item. ball35AttrNames = ball35Attrs.attributeNames # Visibility should be in this list. self.assertIn(UsdGeom.Tokens.visibility, ball35AttrNames)
def testRenameRestrictionHasSpecs(self): '''Restrict renaming USD node. Cannot rename a node that doesn't contribute to the final composed prim''' # open appleBite.ma scene in testSamples mayaUtils.openAppleBiteScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|Asset_flattened_instancing_and_class_removed_usd|Asset_flattened_instancing_and_class_removed_usdShape' ) usdPathSegment = usdUtils.createUfePathSegment('/apple/payload/geo') geoPath = ufe.Path([mayaPathSegment, usdPathSegment]) geoItem = ufe.Hierarchy.createItem(geoPath) ufe.GlobalSelection.get().append(geoItem) # get the USD stage stage = mayaUsd.ufe.getStage(str(mayaPathSegment)) # rename "/apple/payload/geo" to "/apple/payload/geo_renamed" # expect the exception happens with self.assertRaises(RuntimeError): cmds.rename("geo_renamed")
def _GetUfePath(instanceIndex=-1): mayaSegment = mayaUtils.createUfePathSegment('|UsdProxy|UsdProxyShape') usdSegmentString = mayaUsdUfe.usdPathToUfePathSegment( '/PointInstancerGrid/PointInstancer', instanceIndex) usdSegment = usdUtils.createUfePathSegment(usdSegmentString) ufePath = ufe.Path([mayaSegment, usdSegment]) return ufePath
def _testMoveMaya(self): '''Move Maya object, read through the Transform3d interface.''' # Give the sphere an initial position, and select it. expected = om.MVector(1, 2, 3) sphereObj = om.MSelectionList().add('pSphere1').getDagPath(0).node() sphereFn = om.MFnTransform(sphereObj) def setMayaTranslation(xlation): sphereFn.setTranslation(xlation, om.MSpace.kTransform) setMayaTranslation(expected) spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) sphereItem = ufe.Hierarchy.createItem(spherePath) ufe.GlobalSelection.get().append(sphereItem) # Create a Transform3d interface for it. transform3d = ufe.Transform3d.transform3d(sphereItem) # Set up the callables that will set and get the translation. self.setRunTimeTranslation = setMayaTranslation self.getRunTimeTranslation = partial(sphereFn.translation, om.MSpace.kTransform) self.getUfeTranslation = partial(transform3dTranslation, transform3d) self.runTestMove()
def testRenameRestrictionSameLayerDef(self): '''Restrict renaming USD node. Cannot rename a prim defined on another layer.''' # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|transform1|proxyShape1') usdPathSegment = usdUtils.createUfePathSegment( '/Room_set/Props/Ball_35') ball35Path = ufe.Path([mayaPathSegment, usdPathSegment]) ball35Item = ufe.Hierarchy.createItem(ball35Path) ufe.GlobalSelection.get().append(ball35Item) # get the USD stage stage = mayaUsd.ufe.getStage(str(mayaPathSegment)) # check GetLayerStack behavior self.assertEqual(stage.GetLayerStack()[0], stage.GetSessionLayer()) self.assertEqual(stage.GetEditTarget().GetLayer(), stage.GetRootLayer()) # expect the exception happens with self.assertRaises(RuntimeError): newName = 'Ball_35_Renamed' cmds.rename(newName)
def testRenameUniqueName(self): # open tree.ma scene in testSamples mayaUtils.openTreeScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment('|Tree_usd|Tree_usdShape') usdPathSegment = usdUtils.createUfePathSegment('/TreeBase/trunk') trunkPath = ufe.Path([mayaPathSegment, usdPathSegment]) trunkItem = ufe.Hierarchy.createItem(trunkPath) ufe.GlobalSelection.get().append(trunkItem) # get the USD stage stage = mayaUsd.ufe.getStage(str(mayaPathSegment)) # by default edit target is set to the Rootlayer. self.assertEqual(stage.GetEditTarget().GetLayer(), stage.GetRootLayer()) # rename `/TreeBase/trunk` to `/TreeBase/leavesXform` cmds.rename("leavesXform") # get the prim item = ufe.GlobalSelection.get().front() usdPrim = stage.GetPrimAtPath(str(item.path().segments[1])) self.assertTrue(usdPrim) # the new prim name is expected to be "leavesXform1" assert ([x for x in stage.Traverse()] == [stage.GetPrimAtPath("/TreeBase"), stage.GetPrimAtPath("/TreeBase/leavesXform"), stage.GetPrimAtPath("/TreeBase/leavesXform/leaves"), stage.GetPrimAtPath("/TreeBase/leavesXform1"),])
def testDrawModes(self): self._StartTest('DrawModes') cmds.modelEditor('modelPanel4', edit=True, grid=False) cmds.move(2, 2, 2, 'persp') cmds.rotate(-33, 45, 0, 'persp') self.assertSnapshotClose('%s_cross_all_positive.png' % self._testName) cmds.move(-2, -2, -2, 'persp') cmds.rotate(145, 45, 0, 'persp') self.assertSnapshotClose('%s_cross_all_negative.png' % self._testName) mayaPathSegment = mayaUtils.createUfePathSegment('|stage|stageShape') usdPathSegment = usdUtils.createUfePathSegment('/DrawModes') drawModesPath = ufe.Path([mayaPathSegment, usdPathSegment]) drawModesItem = ufe.Hierarchy.createItem(drawModesPath) drawModesPrim = usdUtils.getPrimFromSceneItem(drawModesItem) cardGeomAttr = drawModesPrim.GetAttribute('model:cardGeometry') cardGeomAttr.Set('box') cmds.move(2, 2, 2, 'persp') cmds.rotate(-33, 45, 0, 'persp') self.assertSnapshotClose('%s_box_all_positive.png' % self._testName) cmds.move(-2, -2, -2, 'persp') cmds.rotate(145, 45, 0, 'persp') self.assertSnapshotClose('%s_box_all_negative.png' % self._testName)
def testMoveUSD(self): '''Move USD object, read through the Transform3d interface.''' # Select Ball_35 to move it. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) ball35Item = ufe.Hierarchy.createItem(ball35Path) ufe.GlobalSelection.get().append(ball35Item) # Create a Transform3d interface for it. transform3d = ufe.Transform3d.transform3d(ball35Item) # We compare the UFE translation with the USD run-time translation. To # obtain the full translation of Ball_35, we need to add the USD # translation to the Maya proxy shape translation. proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) def ball35Translation(): ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) return addVec( proxyShapeXformFn.translation(om.MSpace.kTransform), ball35Prim.GetAttribute('xformOp:translate').Get()) # Set up the callables that will retrieve the translation. self.runTimeTranslation = ball35Translation self.ufeTranslation = partial(transform3dTranslation, transform3d) # Save the initial position to the memento list. expected = ball35Translation() self.runTestMove(expected)
def testManipulatePointInstancePosition(self): # Create a UFE path to a PointInstancer prim with an instanceIndex on # the end. This path uniquely identifies a specific point instance. # We also pick one with a non-zero initial position. instanceIndex = 7 ufePath = ufe.Path([ mayaUtils.createUfePathSegment('|UsdProxy|UsdProxyShape'), usdUtils.createUfePathSegment( '/PointInstancerGrid/PointInstancer/%d' % instanceIndex) ]) ufeItem = ufe.Hierarchy.createItem(ufePath) # Select the point instance scene item. globalSelection = ufe.GlobalSelection.get() globalSelection.append(ufeItem) # Get the PointInstancer prim for validating the values in USD. ufePathString = ufe.PathString.string(ufePath) prim = mayaUsdUfe.ufePathToPrim(ufePathString) pointInstancer = UsdGeom.PointInstancer(prim) self.assertTrue(pointInstancer) # The PointInstancer should have 14 authored positions initially. positionsAttr = pointInstancer.GetPositionsAttr() positions = positionsAttr.Get() self.assertEqual(len(positions), 14) # Validate the initial position before manipulating position = positions[instanceIndex] self.assertTrue( Gf.IsClose(position, Gf.Vec3f(-4.5, 1.5, 0.0), self.EPSILON)) # Perfom a translate manipulation via the move command. cmds.move(1.0, 2.0, 3.0, objectSpace=True, relative=True) # Re-fetch the USD positions and check for the update. position = positionsAttr.Get()[instanceIndex] self.assertTrue( Gf.IsClose(position, Gf.Vec3f(-3.5, 3.5, 3.0), self.EPSILON)) # Try another move. cmds.move(6.0, 5.0, 4.0, objectSpace=True, relative=True) # Re-fetch the USD positions and check for the update. position = positionsAttr.Get()[instanceIndex] self.assertTrue( Gf.IsClose(position, Gf.Vec3f(2.5, 8.5, 7.0), self.EPSILON)) # Now undo, and re-check. cmds.undo() position = positionsAttr.Get()[instanceIndex] self.assertTrue( Gf.IsClose(position, Gf.Vec3f(-3.5, 3.5, 3.0), self.EPSILON)) # And once more. cmds.undo() position = positionsAttr.Get()[instanceIndex] self.assertTrue( Gf.IsClose(position, Gf.Vec3f(-4.5, 1.5, 0.0), self.EPSILON))
def testRenameRestrictionVariant(self): '''Renaming prims inside a variantSet is not allowed.''' cmds.file(new=True, force=True) # open Variant.ma scene in testSamples mayaUtils.openVariantSetScene() # stage mayaPathSegment = mayaUtils.createUfePathSegment('|Variant_usd|Variant_usdShape') stage = mayaUsd.ufe.getStage(str(mayaPathSegment)) # first check that we have a VariantSets objectPrim = stage.GetPrimAtPath('/objects') self.assertTrue(objectPrim.HasVariantSets()) # Geom usdPathSegment = usdUtils.createUfePathSegment('/objects/Geom') geomPath = ufe.Path([mayaPathSegment, usdPathSegment]) geomItem = ufe.Hierarchy.createItem(geomPath) geomPrim = mayaUsd.ufe.ufePathToPrim(ufe.PathString.string(geomPath)) # Small_Potato smallPotatoUsdPathSegment = usdUtils.createUfePathSegment('/objects/Geom/Small_Potato') smallPotatoPath = ufe.Path([mayaPathSegment, smallPotatoUsdPathSegment]) smallPotatoItem = ufe.Hierarchy.createItem(smallPotatoPath) smallPotatoPrim = mayaUsd.ufe.ufePathToPrim(ufe.PathString.string(smallPotatoPath)) # add Geom to selection list ufe.GlobalSelection.get().append(geomItem) # get prim spec for Geom prim primspecGeom = stage.GetEditTarget().GetPrimSpecForScenePath(geomPrim.GetPath()); # primSpec is expected to be None self.assertIsNone(primspecGeom) # rename "/objects/Geom" to "/objects/Geom_something" # expect the exception happens with self.assertRaises(RuntimeError): cmds.rename("Geom_something") # clear selection cmds.select(clear=True) # add Small_Potato to selection list ufe.GlobalSelection.get().append(smallPotatoItem) # get prim spec for Small_Potato prim primspecSmallPotato = stage.GetEditTarget().GetPrimSpecForScenePath(smallPotatoPrim.GetPath()); # primSpec is expected to be None self.assertIsNone(primspecSmallPotato) # rename "/objects/Geom/Small_Potato" to "/objects/Geom/Small_Potato_something" # expect the exception happens with self.assertRaises(RuntimeError): cmds.rename("Small_Potato_something")
def testAlreadyChild(self): '''Parenting an object to its current parent is a no-op.''' with OpenFileCtx("simpleHierarchy.ma"): shapeSegment = mayaUtils.createUfePathSegment( "|mayaUsdProxy1|mayaUsdProxyShape1") spherePath = ufe.Path( [shapeSegment, usdUtils.createUfePathSegment("/pCylinder1/pCube1/pSphere1")]) sphereItem = ufe.Hierarchy.createItem(spherePath) cylinderShapePath = ufe.Path( [shapeSegment, usdUtils.createUfePathSegment("/pCylinder1/pCylinderShape1")]) cylinderShapeItem = ufe.Hierarchy.createItem(cylinderShapePath) parentPath = ufe.Path( [shapeSegment, usdUtils.createUfePathSegment("/pCylinder1")]) parentItem = ufe.Hierarchy.createItem(parentPath) parent = ufe.Hierarchy.hierarchy(parentItem) childrenPre = parent.children() # get the USD stage stage = mayaUsd.ufe.getStage(str(shapeSegment)) # check GetLayerStack behavior self.assertEqual(stage.GetEditTarget().GetLayer(), stage.GetRootLayer()) # The sphere is not a child of the cylinder self.assertNotIn("pSphere1", childrenNames(childrenPre)) # The cylinder shape is a child of the cylinder self.assertIn("pCylinderShape1", childrenNames(childrenPre)) # Parent the sphere and the cylinder shape to the cylinder. This # is a no-op for the cylinder shape, as it's already a child of the # cylinder, and the sphere is parented to the cylinder. cmds.parent(ufe.PathString.string(spherePath), ufe.PathString.string(cylinderShapePath), ufe.PathString.string(parentPath)) children = parent.children() self.assertEqual(len(childrenPre)+1, len(children)) self.assertIn("pSphere1", childrenNames(children)) self.assertIn("pCylinderShape1", childrenNames(children)) # Undo / redo cmds.undo() children = parent.children() self.assertEqual(len(childrenPre), len(children)) self.assertNotIn("pSphere1", childrenNames(children)) self.assertIn("pCylinderShape1", childrenNames(children)) cmds.redo() children = parent.children() self.assertEqual(len(childrenPre)+1, len(children)) self.assertIn("pSphere1", childrenNames(children)) self.assertIn("pCylinderShape1", childrenNames(children))
def testPurposeBoundingBox(self): '''Bounding box of prims with guide, proxy, and render purpose.''' # Create a scene with prims of purposes other than default: guide, # proxy, and render. All must have a valid bounding box. The bounding # box is conditional to the proxy shape on the UFE path to the prim # having that purpose enabled: if the purpose is disabled, the bounding # box is invalid. import mayaUsd_createStageWithNewLayer proxyShapePath = mayaUsd_createStageWithNewLayer.createStageWithNewLayer( ) proxyShapePathSegment = mayaUtils.createUfePathSegment(proxyShapePath) stage = mayaUsd.lib.GetPrim(proxyShapePath).GetStage() usdPaths = ['/Cube1', '/Cube2', '/Cube3'] prims = [stage.DefinePrim(path, 'Cube') for path in usdPaths] purposes = [ UsdGeom.Tokens.proxy, UsdGeom.Tokens.guide, UsdGeom.Tokens.render ] for (prim, purpose) in zip(prims, purposes): imageable = UsdGeom.Imageable(prim) imageable.CreatePurposeAttr(purpose) # Create a UFE scene item for each prim, and get the bounding box using # the Object3d interface. for (prim, usdPath) in zip(prims, usdPaths): pathSegment = usdUtils.createUfePathSegment(usdPath) path = ufe.Path([proxyShapePathSegment, pathSegment]) item = ufe.Hierarchy.createItem(path) object3d = ufe.Object3d.object3d(item) # First turn off proxy, guide, render purposes on the proxy shape. # The bounding box should be invalid. purposeAttribs = [ 'drawProxyPurpose', 'drawGuidePurpose', 'drawRenderPurpose' ] for purposeAttrib in purposeAttribs: cmds.setAttr(proxyShapePath + '.' + purposeAttrib, 0) bbox = object3d.boundingBox() self.assertTrue(bbox.empty()) # Next, turn on each purpose in turn on the proxy shape. The # bounding box should be valid only if the prim's purpose matches # the proxy shape purpose. imageable = UsdGeom.Imageable(prim) primPurpose = imageable.GetPurposeAttr().Get() for (purpose, purposeAttrib) in zip(purposes, purposeAttribs): cmds.setAttr(proxyShapePath + '.' + purposeAttrib, 1) bbox = object3d.boundingBox() if primPurpose == purpose: assertVectorAlmostEqual(self, bbox.min.vector, [-1] * 3) assertVectorAlmostEqual(self, bbox.max.vector, [1] * 3) else: self.assertTrue(bbox.empty()) cmds.setAttr(proxyShapePath + '.' + purposeAttrib, 0)
def testRotateScalePivotCompensationAfterExport(self): '''Rotate and scale pivots must match after export.''' cmds.file(new=True, force=True) mayaSphere = cmds.polySphere()[0] cmds.rotate(0, 0, -45, r=True, os=True, fo=True) cmds.scale(4, 3, 2, r=True) cmds.move(-2, -3, -4, "pSphere1.rotatePivot", r=True) cmds.move(7, 6, 5, "pSphere1.scalePivot", r=True) # Export out, reference back in using proxy shape. usdFilePath = os.path.abspath('UsdExportMayaXformStack.usda') cmds.mayaUSDExport(file=usdFilePath) # Reference it back in. proxyShape = cmds.createNode('mayaUsdProxyShape') cmds.setAttr('mayaUsdProxyShape1.filePath', usdFilePath, type='string') # MAYA-101766: awkward plug access for non-interactive stage loading. outStageData = nameToPlug('mayaUsdProxyShape1.outStageData') outStageData.asMDataHandle() proxyShapeMayaPath = cmds.ls(proxyShape, long=True)[0] proxyShapePathSegment = mayaUtils.createUfePathSegment( proxyShapeMayaPath) spherePathSegment = usdUtils.createUfePathSegment('/pSphere1') spherePath = ufe.Path([proxyShapePathSegment, spherePathSegment]) sphereItem = ufe.Hierarchy.createItem(spherePath) usdSphereT3d = ufe.Transform3d.transform3d(sphereItem) # If the Transform3d interface can't handle rotate or scale pivot # compensation, skip this test. if usdSphereT3d.translateRotatePivotCmd() is None or \ usdSphereT3d.translateScalePivotCmd() is None: raise unittest.SkipTest( "Rotate or scale pivot compensation unsupported.") # Maya object and its exported USD object twin should have the # same pivots and pivot compensations. checkPivotsAndCompensations(self, "pSphere1", usdSphereT3d) sn = ufe.GlobalSelection.get() sn.clear() sn.append(sphereItem) # Move only the rotate pivot. cmds.move(-1, -2, -3, r=True, urp=True) cmds.move(-1, -2, -3, "pSphere1.rotatePivot", r=True) checkPivotsAndCompensations(self, "pSphere1", usdSphereT3d) # Move only the scale pivot. cmds.move(-4, -3, -2, r=True, usp=True) cmds.move(-4, -3, -2, "pSphere1.scalePivot", r=True) checkPivotsAndCompensations(self, "pSphere1", usdSphereT3d)
def testRename(self): # open tree.ma scene in testSamples mayaUtils.openTreeScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment('|Tree_usd|Tree_usdShape') usdPathSegment = usdUtils.createUfePathSegment('/TreeBase') treebasePath = ufe.Path([mayaPathSegment, usdPathSegment]) treebaseItem = ufe.Hierarchy.createItem(treebasePath) ufe.GlobalSelection.get().append(treebaseItem) # get the USD stage stage = mayaUsd.ufe.getStage(str(mayaPathSegment)) # by default edit target is set to the Rootlayer. self.assertEqual(stage.GetEditTarget().GetLayer(), stage.GetRootLayer()) self.assertTrue(stage.GetRootLayer().GetPrimAtPath("/TreeBase")) # get default prim defaultPrim = stage.GetDefaultPrim() self.assertEqual(defaultPrim.GetName(), 'TreeBase') # TreeBase has two childern: leavesXform, trunk assert len(defaultPrim.GetChildren()) == 2 # get prim spec for defaultPrim primspec = stage.GetEditTarget().GetPrimSpecForScenePath(defaultPrim.GetPath()); # set primspec name primspec.name = "TreeBase_potato" # get the renamed prim renamedPrim = stage.GetPrimAtPath('/TreeBase_potato') # One must use the SdfLayer API for setting the defaultPrim when you rename the prim it identifies. stage.SetDefaultPrim(renamedPrim); # get defaultPrim again defaultPrim = stage.GetDefaultPrim() self.assertEqual(defaultPrim.GetName(), 'TreeBase_potato') # make sure we have a valid prims after the primspec rename assert stage.GetPrimAtPath('/TreeBase_potato') assert stage.GetPrimAtPath('/TreeBase_potato/leavesXform') # prim should be called TreeBase_potato potatoPrim = stage.GetPrimAtPath('/TreeBase_potato') self.assertEqual(potatoPrim.GetName(), 'TreeBase_potato') # prim should be called leaves leavesPrimSpec = stage.GetObjectAtPath('/TreeBase_potato/leavesXform/leaves') self.assertEqual(leavesPrimSpec.GetName(), 'leaves')
def getItem(path): '''Get the UFE scene item and USD prim for an item under a USD path''' fullPath = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment(path) ]) item = ufe.Hierarchy.createItem(fullPath) prim = mayaUsd.ufe.ufePathToPrim(ufe.PathString.string(fullPath)) return item, prim
def testTranslateLockedLayer(self): # create new stage cmds.file(new=True, force=True) # Open usdCylinder.ma scene in testSamples mayaUtils.openCylinderScene() # get the stage proxyShapes = cmds.ls(type="mayaUsdProxyShapeBase", long=True) proxyShapePath = proxyShapes[0] stage = mayaUsd.lib.GetPrim(proxyShapePath).GetStage() # cylinder prim cylinderPrim = stage.GetPrimAtPath('/pCylinder1') self.assertIsNotNone(cylinderPrim) # create a sub-layer. rootLayer = stage.GetRootLayer() subLayerA = cmds.mayaUsdLayerEditor(rootLayer.identifier, edit=True, addAnonymous="LayerA")[0] # check to see the if the sublayers was added addedLayers = [subLayerA] self.assertEqual(rootLayer.subLayerPaths, addedLayers) # set the edit target to LayerA. cmds.mayaUsdEditTarget(proxyShapePath, edit=True, editTarget=subLayerA) # set permission to edit to false layerA = Sdf.Find(subLayerA) layerA.SetPermissionToEdit(False) # Check that our helper function is returning the right thing self.assertFalse(mayaUsdUfe.isEditTargetLayerModifiable(stage)) # Get translate attribute and make sure its empty translateAttr = cylinderPrim.GetAttribute('xformOp:translate') self.assertIsNotNone(translateAttr) tranlateBeforeEdit = translateAttr.Get() # create a transform3d and translate cylinderPath = ufe.Path([ mayaUtils.createUfePathSegment("|mayaUsdTransform|shape"), usdUtils.createUfePathSegment("/pCylinder1") ]) cylinderItem = ufe.Hierarchy.createItem(cylinderPath) cylinderT3d = ufe.Transform3d.transform3d(cylinderItem) if cylinderT3d is not None: cylinderT3d.translate(5.0, 6.0, 7.0) # check that the translate operation didn't change anything tranlateAfterEdit = translateAttr.Get() self.assertEqual(tranlateBeforeEdit, tranlateAfterEdit)
def testRenameProxyShape(self): '''Rename proxy shape, UFE lookup should succeed.''' mayaSegment = mayaUtils.createUfePathSegment( "|transform1|proxyShape1") usdSegment = usdUtils.createUfePathSegment("/Room_set/Props/Ball_35") ball35Path = ufe.Path([mayaSegment, usdSegment]) ball35PathStr = ','.join( [str(segment) for segment in ball35Path.segments]) # Because of difference in Python binding systems (pybind11 for UFE, # Boost Python for mayaUsd and USD), need to pass in strings to # mayaUsd functions. Multi-segment UFE paths need to have # comma-separated segments. def assertStageAndPrimAccess( proxyShapeSegment, primUfePathStr, primSegment): proxyShapePathStr = str(proxyShapeSegment) stage = mayaUsd.ufe.getStage(proxyShapePathStr) prim = mayaUsd.ufe.ufePathToPrim(primUfePathStr) stagePath = mayaUsd.ufe.stagePath(stage) self.assertIsNotNone(stage) self.assertEqual(stagePath, proxyShapePathStr) self.assertTrue(prim.IsValid()) self.assertEqual(str(prim.GetPath()), str(primSegment)) assertStageAndPrimAccess(mayaSegment, ball35PathStr, usdSegment) # Rename the proxy shape node itself. Stage and prim access should # still be valid, with the new path. mayaSegment = mayaUtils.createUfePathSegment( "|transform1|potato") cmds.rename('|transform1|proxyShape1', 'potato') self.assertEqual(len(cmds.ls('potato')), 1) ball35Path = ufe.Path([mayaSegment, usdSegment]) ball35PathStr = ','.join( [str(segment) for segment in ball35Path.segments]) assertStageAndPrimAccess(mayaSegment, ball35PathStr, usdSegment)
def testUsdCamera(self): self._StartTest('TranslateRotate_vs_xform') mayaPathSegment = mayaUtils.createUfePathSegment('|stage|stageShape') cam2UsdPathSegment = usdUtils.createUfePathSegment( '/cameras/cam2/camera2') cam2Path = ufe.Path([mayaPathSegment, cam2UsdPathSegment]) cam2Item = ufe.Hierarchy.createItem(cam2Path) cam2Camera = ufe.Camera.camera(cam2Item) cameraPrim = usdUtils.getPrimFromSceneItem(cam2Item) self._TestCameraAttributes(cam2Camera, cameraPrim)
def testRenameNotifications(self): '''Rename a USD node and test for the UFE notifications.''' # open usdCylinder.ma scene in testSamples mayaUtils.openCylinderScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|mayaUsdTransform|shape') usdPathSegment = usdUtils.createUfePathSegment('/pCylinder1') cylinderPath = ufe.Path([mayaPathSegment, usdPathSegment]) cylinderItem = ufe.Hierarchy.createItem(cylinderPath) ufe.GlobalSelection.get().append(cylinderItem) # get the USD stage stage = mayaUsd.ufe.getStage(str(mayaPathSegment)) # set the edit target to the root layer stage.SetEditTarget(stage.GetRootLayer()) self.assertEqual(stage.GetEditTarget().GetLayer(), stage.GetRootLayer()) # Create our UFE notification observer ufeObs = TestObserver() if (os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') < '2021'): # We start off with no observers self.assertFalse(ufe.Scene.hasObjectAddObserver(ufeObs)) self.assertFalse(ufe.Scene.hasObjectDeleteObserver(ufeObs)) self.assertFalse(ufe.Scene.hasObjectPathChangeObserver(ufeObs)) # Add the UFE observers we want to test ufe.Scene.addObjectAddObserver(ufeObs) ufe.Scene.addObjectDeleteObserver(ufeObs) ufe.Scene.addObjectPathChangeObserver(ufeObs) else: # We start off with no observers self.assertFalse(ufe.Scene.hasObserver(ufeObs)) # Add the UFE observer we want to test ufe.Scene.addObserver(ufeObs) # rename newName = 'pCylinder1_Renamed' cmds.rename(newName) # After the rename we should have 1 rename notif and no unexepected notifs. self.assertEqual(ufeObs.notifications(), 1) self.assertFalse(ufeObs.receivedUnexpectedNotif())
def testAnimatedBoundingBox(self): '''Test the Object3d bounding box interface for animated geometry.''' # Open sphereAnimatedRadiusProxyShape.ma scene in testSamples mayaUtils.openSphereAnimatedRadiusScene() # The extents of the sphere are copied from the .usda file. expected = [[(-1.0000002, -1, -1.0000005), (1, 1, 1.0000001)], [(-1.3086424, -1.308642, -1.3086426), (1.308642, 1.308642, 1.3086421)], [(-2.135803, -2.1358025, -2.1358035), (2.1358025, 2.1358025, 2.1358027)], [(-3.333334, -3.3333333, -3.333335), (3.3333333, 3.3333333, 3.3333337)], [(-4.7530875, -4.7530866, -4.753089), (4.7530866, 4.7530866, 4.753087)], [(-6.246915, -6.2469134, -6.2469163), (6.2469134, 6.2469134, 6.2469144)], [(-7.6666684, -7.6666665, -7.6666703), (7.6666665, 7.6666665, 7.6666675)], [(-8.8642, -8.864198, -8.864202), (8.864198, 8.864198, 8.864199)], [(-9.6913595, -9.691358, -9.691362), (9.691358, 9.691358, 9.691359)], [(-10.000002, -10, -10.000005), (10, 10, 10.000001)]] # Create an Object3d interface for USD sphere. mayaPathSegment = mayaUtils.createUfePathSegment( '|transform1|proxyShape1') usdPathSegment = usdUtils.createUfePathSegment('/pSphere1') spherePath = ufe.Path([mayaPathSegment, usdPathSegment]) sphereItem = ufe.Hierarchy.createItem(spherePath) object3d = ufe.Object3d.object3d(sphereItem) # Loop over frames 1 to 10, and compare the values returned to the # expected values. for frame in range(1, 11): cmds.currentTime(frame) ufeBBox = object3d.boundingBox() # Compare it to known extents. assertVectorAlmostEqual(self, ufeBBox.min.vector, expected[frame - 1][0], places=6) assertVectorAlmostEqual(self, ufeBBox.max.vector, expected[frame - 1][1], places=6)
def testVisibility(self): '''Test the Object3d visibility methods.''' # Open top_layer.ma scene in testSamples mayaUtils.openTopLayerScene() # Get a scene item for Ball_35. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35") ]) ball35Item = ufe.Hierarchy.createItem(ball35Path) # Create an Object3d interface for it. object3d = ufe.Object3d.object3d(ball35Item) visObs = TestObserver() # We start off with no visibility observers. self.assertFalse(ufe.Object3d.hasObserver(visObs)) self.assertEqual(ufe.Object3d.nbObservers(), 0) # Set the observer for visibility changes. ufe.Object3d.addObserver(visObs) self.assertTrue(ufe.Object3d.hasObserver(visObs)) self.assertEqual(ufe.Object3d.nbObservers(), 1) # No notifications yet. self.assertEqual(visObs.notifications(), 0) # Initially it should be visible. self.assertTrue(object3d.visibility()) # Make it invisible. object3d.setVisibility(False) self.assertFalse(object3d.visibility()) # We should have got 'one' notification. self.assertEqual(visObs.notifications(), 1) # Make it visible. object3d.setVisibility(True) self.assertTrue(object3d.visibility()) # We should have got one more notification. self.assertEqual(visObs.notifications(), 2) # Remove the observer. ufe.Object3d.removeObserver(visObs) self.assertFalse(ufe.Object3d.hasObserver(visObs)) self.assertEqual(ufe.Object3d.nbObservers(), 0)
def testObservation(self): '''Test Transform3d observation interface. As of 11-Apr-2018 only implemented for USD objects. ''' # Select Ball_35 to move it. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) ball35Item = ufe.Hierarchy.createItem(ball35Path) # Create a Transform3d interface for it. transform3d = ufe.Transform3d.transform3d(ball35Item) t3dObs = TestObserver() # We start off with no observers for Ball_35. self.assertFalse(ufe.Transform3d.hasObservers(ball35Path)) self.assertFalse(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 0) # Set the observer to observe Ball_35. ufe.Transform3d.addObserver(ball35Item, t3dObs) self.assertTrue(ufe.Transform3d.hasObservers(ball35Path)) self.assertTrue(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 1) # No notifications yet. self.assertEqual(t3dObs.notifications(), 0) # We only select the ball AFTER doing our initial tests because # the MayaUSD plugin creates a transform3d observer on selection # change to update the bounding box. ufe.GlobalSelection.get().append(ball35Item) # Move the prim. Use a change block to condense USD notifications into # one. Otherwise, as of 15-Jul-2021, the implementation of # UsdStage::_SetValue() notifies once for creation of the # 'xformOp:translate' attrSpec, at the end of an SdfChangeBlock, and # once for setting the 'xformOp:translate' field (in Sdf terminology), # again at the end of a separate SdfChangeBlock. ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) with Sdf.ChangeBlock(): ball35Prim.GetAttribute('xformOp:translate').Set( Gf.Vec3d(10, 20, 30)) # Notified. self.assertEqual(t3dObs.notifications(), 1)
def testRenameSpecialCharacter(self): # open twoSpheres.ma scene in testSamples mayaUtils.openTwoSpheresScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|usdSphereParent|usdSphereParentShape') usdPathSegment = usdUtils.createUfePathSegment('/sphereXform/sphere') basePath = ufe.Path([mayaPathSegment, usdPathSegment]) usdSphereItem = ufe.Hierarchy.createItem(basePath) ufe.GlobalSelection.get().append(usdSphereItem) # get the USD stage stage = mayaUsd.ufe.getStage(str(mayaPathSegment)) # by default edit target is set to the Rootlayer. self.assertEqual(stage.GetEditTarget().GetLayer(), stage.GetRootLayer()) # rename with special chars newNameWithSpecialChars = '!@#%$@$=sph^e.re_*()<>}021|' cmds.rename(newNameWithSpecialChars) # get the prim pSphereItem = ufe.GlobalSelection.get().front() usdPrim = stage.GetPrimAtPath(str(pSphereItem.path().segments[1])) self.assertTrue(usdPrim) # prim names are not allowed to have special characters except '_' regex = re.compile('[@!#$%^&*()<>?/\|}{~:]') self.assertFalse(regex.search(usdPrim.GetName())) # rename starting with digits. newNameStartingWithDigit = '09123Potato' self.assertFalse(Tf.IsValidIdentifier(newNameStartingWithDigit)) cmds.rename(newNameStartingWithDigit) # get the prim pSphereItem = ufe.GlobalSelection.get().front() usdPrim = stage.GetPrimAtPath(str(pSphereItem.path().segments[1])) self.assertTrue(usdPrim) # prim names are not allowed to start with digits newValidName = Tf.MakeValidIdentifier(newNameStartingWithDigit) self.assertEqual(usdPrim.GetName(), newValidName)
def runTestAttribute(self, path, attrName, ufeAttrClass, ufeAttrType): '''Engine method to run attribute test.''' # Create the UFE/USD attribute for this test from the input path. # Get a UFE scene item the input path in the scene. itemPath = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment(path) ]) ufeItem = ufe.Hierarchy.createItem(itemPath) # Get the USD prim for this item. usdPrim = usdUtils.getPrimFromSceneItem(ufeItem) # Create the attributes interface for the item. ufeAttrs = ufe.Attributes.attributes(ufeItem) self.assertIsNotNone(ufeAttrs) # Get the USDAttribute for the input attribute name so we can use it to # compare to UFE. usdAttr = usdPrim.GetAttribute(attrName) self.assertIsNotNone(usdAttr) # Get the attribute that matches the input name and make sure it matches # the class type of UFE attribute class passed in. self.assertTrue(ufeAttrs.hasAttribute(attrName)) ufeAttr = ufeAttrs.attribute(attrName) self.assertIsInstance(ufeAttr, ufeAttrClass) # Verify that the attribute type matches the input UFE type. self.assertEqual(ufeAttr.type, ufeAttrType) # Verify that the scene item the attribute was created with matches # what is stored in the UFE attribute. self.assertEqual(ufeAttr.sceneItem(), ufeItem) # Verify that this attribute has a value. Note: all the attributes that # are tested by this method are assumed to have a value. self.assertTrue(ufeAttr.hasValue()) # Verify that the name matched what we created the attribute from. self.assertEqual(ufeAttr.name, attrName) # Test that the string representation of the value is not empty. self.assertTrue(str(ufeAttr)) return ufeAttr, usdAttr
def testComboMaya(self): '''Move, rotate, and scale Maya object, read through the Transform3d interface.''' # Give the sphere an initial position, rotation, scale, and select it. sphereObj = om.MSelectionList().add('pSphere1').getDagPath(0).node() sphereFn = om.MFnTransform(sphereObj) expectedTRS = None if (self.move in self.ops): expectedTRS = self.updateTRS(expectedTRS, self.move, [1, 2, 3]) t = self.extractTRS(expectedTRS, self.move) sphereFn.setTranslation(om.MVector(t[0], t[1], t[2]), om.MSpace.kTransform) if (self.rotate in self.ops): expectedTRS = self.updateTRS(expectedTRS, self.rotate, [30, 60, 90]) r = self.extractTRS(expectedTRS, self.rotate) sphereFn.setRotation( om.MEulerRotation(radians(r[0]), radians(r[1]), radians(r[2])), om.MSpace.kTransform) if (self.scale in self.ops): expectedTRS = self.updateTRS(expectedTRS, self.scale, [1, 2, 3]) s = self.extractTRS(expectedTRS, self.scale) sphereFn.setScale(om.MVector(s[0], s[1], s[2])) spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) sphereItem = ufe.Hierarchy.createItem(spherePath) ufe.GlobalSelection.get().append(sphereItem) # Create a Transform3d interface for it. transform3d = ufe.Transform3d.transform3d(sphereItem) # Set up the callables that will retrieve the translation. self.runTimes[self.move] = partial(sphereFn.translation, om.MSpace.kTransform) self.ufes[self.move] = partial(transform3dTranslation, transform3d) # Set up the callables that will retrieve the rotation. self.runTimes[self.rotate] = partial(sphereFn.rotation, om.MSpace.kTransform) self.ufes[self.rotate] = partial(transform3dRotation, transform3d) # Set up the callables that will retrieve the scale. self.runTimes[self.scale] = partial(sphereFn.scale) self.ufes[self.scale] = partial(transform3dScale, transform3d) self.runTestCombo(expectedTRS)
def testObservation(self): '''Test Transform3d observation interface. As of 11-Apr-2018 only implemented for USD objects. ''' # Select Ball_35 to move it. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35") ]) ball35Item = ufe.Hierarchy.createItem(ball35Path) # Create a Transform3d interface for it. transform3d = ufe.Transform3d.transform3d(ball35Item) t3dObs = TestObserver() # We start off with no observers for Ball_35. self.assertFalse(ufe.Transform3d.hasObservers(ball35Path)) self.assertFalse(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 0) # Set the observer to observe Ball_35. ufe.Transform3d.addObserver(ball35Item, t3dObs) self.assertTrue(ufe.Transform3d.hasObservers(ball35Path)) self.assertTrue(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 1) # No notifications yet. self.assertEqual(t3dObs.notifications(), 0) # We only select the ball AFTER doing our initial tests because # the MayaUSD plugin creates a transform3d observer on selection # change to update the bounding box. ufe.GlobalSelection.get().append(ball35Item) # Move the prim. ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) ball35Prim.GetAttribute('xformOp:translate').Set(Gf.Vec3d(10, 20, 30)) # Notified. self.assertEqual(t3dObs.notifications(), 1)