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 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 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 test-samples mayaUtils.openTopLayerScene() # Clear selection to start off. ufe.GlobalSelection.get().clear() # Select Ball_35. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|world|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 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("|world|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 testScaleUSD(self): '''Scale USD object, read through the Transform3d interface.''' # Select Ball_35 to scale it. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|world|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 scale with the USD run-time scale. To # obtain the full scale of Ball_35, we need to add the USD # scale to the Maya proxy shape scale. proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) def ball35Scale(): ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) if not ball35Prim.HasAttribute('xformOp:scale'): return proxyShapeXformFn.scale() else: return combineScales(proxyShapeXformFn.scale(), ball35Prim.GetAttribute('xformOp:scale').Get()) # Set up the callables that will retrieve the scale. self.runTimeScale = ball35Scale self.ufeScale = partial(transform3dScale, transform3d) # Save the initial position to the memento list. expected = ball35Scale() self.runTestScale(expected)
def testRenameRestrictionSameLayerDef(self): '''Restrict renaming USD node. Cannot rename a prim defined on another layer.''' # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|world|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 testRenameRestrictionOtherLayerOpinions(self): '''Restrict renaming USD node. Cannot rename a prim with definitions or opinions on other layers.''' # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|world|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)) # set the edit target to Assembly_room_set.usda stage.SetEditTarget(stage.GetLayerStack()[2]) self.assertEqual(stage.GetEditTarget().GetLayer().GetDisplayName(), "Assembly_room_set.usda") # expect the exception happens with self.assertRaises(RuntimeError): newName = 'Ball_35_Renamed' cmds.rename(newName)
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 test-samples mayaUtils.openAppleBiteScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|world|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 testMultiSelectMoveUSD(self): '''Move multiple USD objects, read through Transform3d interface.''' # Select multiple balls to move them. proxyShapePathSegment = mayaUtils.createUfePathSegment( "|world|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) # Open top_layer.ma scene in test-samples mayaUtils.openTopLayerScene() # Create a proxy shape with empty stage to start with. import mayaUsd_createStageWithNewLayer mayaUsd_createStageWithNewLayer.createStageWithNewLayer() # Clear selection to start off. ufe.GlobalSelection.get().clear() # Select Ball_35. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35") ]) self.ball35Item = ufe.Hierarchy.createItem(ball35Path) ufe.GlobalSelection.get().append(self.ball35Item) # Create a ContextOps interface for it. self.contextOps = ufe.ContextOps.contextOps(self.ball35Item)
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 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("|world|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 _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 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 testRenameUniqueName(self): # open tree.ma scene in test-samples mayaUtils.openTreeScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment('|world|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 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 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 _testMultiSelectRotateUSD(self): '''Rotate multiple USD objects, read through Transform3d interface.''' # Select multiple balls to rotate them. proxyShapePathSegment = mayaUtils.createUfePathSegment( "|world|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 rotation with the USD run-time rotation. To # obtain the full rotation of USD scene items, we need to add the USD # rotation to the Maya proxy shape rotation. proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) def usdSceneItemRotation(item): prim = usdUtils.getPrimFromSceneItem(item) if not prim.HasAttribute('xformOp:rotateXYZ'): return proxyShapeXformFn.rotation(om.MSpace.kTransform) else: x,y,z = prim.GetAttribute('xformOp:rotateXYZ').Get() return proxyShapeXformFn.rotation(om.MSpace.kTransform) + om.MEulerRotation(radians(x), radians(y), radians(z)) def ufeSceneItemRotation(item): return transform3dRotation(ufe.Transform3d.transform3d(item)) # Set up the callables that will retrieve the rotation. self.runTimeRotation = usdSceneItemRotation self.ufeRotation = ufeSceneItemRotation # Give the tail item in the selection an initial rotation that # is different, to catch bugs where the relative rotation # incorrectly squashes any existing rotation. backItem = ballItems[-1] backT3d = ufe.Transform3d.transform3d(backItem) initialRot = [-10, -20, -30] backT3d.rotate(*initialRot) assertVectorAlmostEqual(self, [radians(a) for a in initialRot], usdSceneItemRotation(backItem)) # Save the initial positions to the memento list. expected = [usdSceneItemRotation(ballItem) for ballItem in ballItems] # MAYA-96058: unfortunately, rotate command currently requires a rotate # manipulator to be created to update the UFE object. manipCtx = cmds.manipRotateContext() cmds.setToolTo(manipCtx) #Temporarily disabling undo redo until we fix it for PR 94 self.runMultiSelectTestRotate(ballItems, expected)
def testRename(self): # open tree.ma scene in test-samples mayaUtils.openTreeScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment('|world|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 testRename(self): '''Rename USD node.''' # Select a USD object. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35") ]) ball35Item = ufe.Hierarchy.createItem(ball35Path) ball35Hierarchy = ufe.Hierarchy.hierarchy(ball35Item) propsItem = ball35Hierarchy.parent() propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) propsChildrenPre = propsHierarchy.children() ufe.GlobalSelection.get().append(ball35Item) newName = 'Ball_35_Renamed' cmds.rename(newName) # The renamed item is in the selection. snIter = iter(ufe.GlobalSelection.get()) ball35RenItem = next(snIter) ball35RenName = str(ball35RenItem.path().back()) self.assertEqual(ball35RenName, newName) # MAYA-92350: should not need to re-bind hierarchy interface objects # with their item. propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) propsChildren = propsHierarchy.children() self.assertEqual(len(propsChildren), len(propsChildrenPre)) self.assertIn(ball35RenItem, propsChildren) cmds.undo() def childrenNames(children): return [str(child.path().back()) for child in children] propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) propsChildren = propsHierarchy.children() propsChildrenNames = childrenNames(propsChildren) self.assertNotIn(ball35RenName, propsChildrenNames) self.assertIn('Ball_35', propsChildrenNames) self.assertEqual(len(propsChildren), len(propsChildrenPre)) cmds.redo() propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) propsChildren = propsHierarchy.children() propsChildrenNames = childrenNames(propsChildren) self.assertIn(ball35RenName, propsChildrenNames) self.assertNotIn('Ball_35', propsChildrenNames) self.assertEqual(len(propsChildren), len(propsChildrenPre))
def testAnimatedBoundingBox(self): '''Test the Object3d bounding box interface for animated geometry.''' # Load up a scene with a sphere that has an animated radius, with # time connected to the proxy shape. filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test-samples", "sphereAnimatedRadius", "sphereAnimatedRadiusProxyShape.ma") cmds.file(filePath, force=True, open=True) # 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( '|world|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 xrange(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 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 testBoundingBox(self): '''Test the Object3d bounding box interface.''' # Create a simple USD scene. Default sphere radius is 1, so extents # are from (-1, -1, -1) to (1, 1, 1). usdFilePath = cmds.internalVar(utd=1) + '/testObject3d.usda' stage = Usd.Stage.CreateNew(usdFilePath) xform = stage.DefinePrim('/parent', 'Xform') sphere = stage.DefinePrim('/parent/sphere', 'Sphere') extentAttr = sphere.GetAttribute('extent') extent = extentAttr.Get() assertVectorAlmostEqual(self, extent[0], [-1] * 3) assertVectorAlmostEqual(self, extent[1], [1] * 3) # Move the sphere. Its UFE bounding box should not be affected by # transformation hierarchy. UsdGeom.XformCommonAPI(xform).SetTranslate((7, 8, 9)) # Save out the file, and bring it back into Maya under a proxy shape. stage.GetRootLayer().Save() proxyShape = cmds.createNode('mayaUsdProxyShape') cmds.setAttr('mayaUsdProxyShape1.filePath', usdFilePath, type='string') # MAYA-101766: loading a stage is done by the proxy shape compute. # Because we're a script, no redraw is done, so need to pull explicitly # on the outStageData (and simply discard the returned data), to get # the proxy shape compute to run, and thus the stage to load. This # should be improved. Without a loaded stage, UFE item creation # fails. PPT, 31-10-2019. outStageData = nameToPlug('mayaUsdProxyShape1.outStageData') outStageData.asMDataHandle() proxyShapeMayaPath = cmds.ls(proxyShape, long=True)[0] proxyShapePathSegment = mayaUtils.createUfePathSegment( proxyShapeMayaPath) # Create a UFE scene item from the sphere prim. spherePathSegment = usdUtils.createUfePathSegment('/parent/sphere') spherePath = ufe.Path([proxyShapePathSegment, spherePathSegment]) sphereItem = ufe.Hierarchy.createItem(spherePath) # Get its Object3d interface. object3d = ufe.Object3d.object3d(sphereItem) # Get its bounding box. ufeBBox = object3d.boundingBox() # Compare it to known extents. assertVectorAlmostEqual(self, ufeBBox.min.vector, [-1] * 3) assertVectorAlmostEqual(self, ufeBBox.max.vector, [1] * 3) # Remove the test file. os.remove(usdFilePath)
def testRenameProxyShape(self): '''Rename proxy shape, UFE lookup should succeed.''' mayaSegment = mayaUtils.createUfePathSegment( "|world|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( "|world|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 test-samples mayaUtils.openCylinderScene() # clear selection to start off cmds.select(clear=True) # select a USD object. mayaPathSegment = mayaUtils.createUfePathSegment( '|world|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 testMultiSelectScaleUSD(self): '''Scale multiple USD objects, read through Transform3d interface.''' # Select multiple balls to scale them. proxyShapePathSegment = mayaUtils.createUfePathSegment( "|world|transform1|proxyShape1") # Test passes for a single item. # balls = ['Ball_33'] 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 scale with the USD run-time scale. To # obtain the full scale of USD scene items, we need to add the USD # scale to the Maya proxy shape scale. proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) def usdSceneItemScale(item): prim = usdUtils.getPrimFromSceneItem(item) if not prim.HasAttribute('xformOp:scale'): return proxyShapeXformFn.scale() else: return combineScales(proxyShapeXformFn.scale(), prim.GetAttribute('xformOp:scale').Get()) def ufeSceneItemScale(item): return transform3dScale(ufe.Transform3d.transform3d(item)) # Set up the callables that will retrieve the scale. self.runTimeScale = usdSceneItemScale self.ufeScale = ufeSceneItemScale # Give the tail item in the selection an initial scale that # is different, to catch bugs where the relative scale # incorrectly squashes any existing scale. backItem = ballItems[-1] backT3d = ufe.Transform3d.transform3d(backItem) initialScale = [1.1, 2.2, 3.3] backT3d.scale(*initialScale) assertVectorAlmostEqual(self, initialScale, usdSceneItemScale(backItem), places=6) # Save the initial positions to the memento list. expected = [usdSceneItemScale(ballItem) for ballItem in ballItems] self.runMultiSelectTestScale(ballItems, expected, places=6)
def testVisibility(self): '''Test the Object3d visibility methods.''' # Open top_layer.ma scene in test-samples mayaUtils.openTopLayerScene() # Get a scene item for Ball_35. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|world|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)