예제 #1
0
    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")
예제 #2
0
    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))
예제 #3
0
    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)
예제 #4
0
    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")
예제 #5
0
    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)
예제 #6
0
    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))
예제 #7
0
    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)
예제 #8
0
 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
예제 #9
0
    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)
예제 #10
0
    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 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)
예제 #12
0
        def checkParentDone():
            # The xform now has the capsule as its child.
            xformChildren = xformHier.children()
            self.assertEqual(len(xformChildren), 1)
            self.assertIn('Capsule1', childrenNames(xformChildren))

            # Confirm that the capsule has not moved in world space.  Must
            # re-create the prim and its scene item, as its path has changed.
            capsulePath = ufe.Path([
                proxyShapePathSegment,
                usdUtils.createUfePathSegment('/Xform1/Capsule1')
            ])
            capsulePrim = mayaUsd.ufe.ufePathToPrim(
                ufe.PathString.string(capsulePath))
            capsuleXformable = UsdGeom.Xformable(capsulePrim)
            capsuleItem = ufe.Hierarchy.createItem(capsulePath)
            capsuleT3d = ufe.Transform3d.transform3d(capsuleItem)
            capsuleWorld = capsuleT3d.inclusiveMatrix()
            assertVectorAlmostEqual(self, capsuleWorldPre,
                                    matrixToList(capsuleWorld))

            # The capsule's transform ops now have Maya fallback stack ops.  A
            # scale fallback op is added, even though it's uniform unit.
            self.assertEqual(
                capsuleXformable.GetXformOpOrderAttr().Get(),
                Vt.TokenArray(
                    ("xformOp:translate", "xformOp:rotateXYZ",
                     "xformOp:rotateX", "xformOp:translate:maya_fallback",
                     "xformOp:rotateXYZ:maya_fallback",
                     "xformOp:scale:maya_fallback")))
    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)
예제 #14
0
    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)
예제 #15
0
    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)
예제 #16
0
        def checkParentDone():
            # The xform now has the capsule as its child.
            xformChildren = xformHier.children()
            self.assertEqual(len(xformChildren), 1)
            self.assertIn('Capsule1', childrenNames(xformChildren))

            # Confirm that the capsule has not moved in world space.  Must
            # re-create the prim and its scene item, as its path has changed.
            capsulePath = ufe.Path([
                proxyShapePathSegment,
                usdUtils.createUfePathSegment('/Xform1/Capsule1')
            ])
            capsulePrim = mayaUsd.ufe.ufePathToPrim(
                ufe.PathString.string(capsulePath))
            capsuleXformable = UsdGeom.Xformable(capsulePrim)
            capsuleItem = ufe.Hierarchy.createItem(capsulePath)
            capsuleT3d = ufe.Transform3d.transform3d(capsuleItem)
            capsuleWorld = capsuleT3d.inclusiveMatrix()
            assertVectorAlmostEqual(self,
                                    capsuleWorldPre,
                                    matrixToList(capsuleWorld),
                                    places=6)
            # Using setMatrixCmd() on a common transform API prim will set
            # translate, rotate, and scale.
            self.assertEqual(
                capsuleXformable.GetXformOpOrderAttr().Get(),
                Vt.TokenArray(("xformOp:translate", "xformOp:translate:pivot",
                               "xformOp:rotateXYZ", "xformOp:scale",
                               "!invert!xformOp:translate:pivot")))
예제 #17
0
    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)
예제 #18
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)
예제 #19
0
    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')
예제 #20
0
 def hierarchyBefore():
     aPath = ufe.Path(
         [psPathSegment,
          usdUtils.createUfePathSegment('/A')])
     a = ufe.Hierarchy.createItem(aPath)
     bPath = aPath + ufe.PathComponent('B')
     b = ufe.Hierarchy.createItem(bPath)
     cPath = bPath + ufe.PathComponent('C')
     c = ufe.Hierarchy.createItem(cPath)
     ePath = dPath + ufe.PathComponent('E')
     e = ufe.Hierarchy.createItem(ePath)
     fPath = ePath + ufe.PathComponent('F')
     f = ufe.Hierarchy.createItem(fPath)
     gPath = ufe.Path(
         [psPathSegment,
          usdUtils.createUfePathSegment('/G')])
     g = ufe.Hierarchy.createItem(gPath)
     return [a, b, c, e, f, g]
예제 #21
0
 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
예제 #22
0
    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)
예제 #23
0
 def hierarchyBefore():
     retVal = []
     aPath = ufe.Path(
         [psPathSegment,
          usdUtils.createUfePathSegment('/A')])
     retVal.append(ufe.Hierarchy.createItem(aPath))
     for i in range(4):
         aPath = aPath + ufe.PathComponent('A')
         retVal.append(ufe.Hierarchy.createItem(aPath))
     return retVal
예제 #24
0
    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)
예제 #25
0
    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())
예제 #26
0
    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)
예제 #27
0
    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)
예제 #28
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)
예제 #29
0
    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)
예제 #30
0
    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