Пример #1
0
    def _convert_to_usd_matrix(self, matrix):
        """Converts a glTF matrix to a Usd Matrix

        Arguments:
            matrix {[type]} -- [description]

        Returns:
            [type] -- [description]
        """

        return Gf.Matrix4d(
            matrix[0], matrix[1], matrix[2], matrix[3],
            matrix[4], matrix[5], matrix[6], matrix[7],
            matrix[8], matrix[9], matrix[10], matrix[11],
            matrix[12], matrix[13], matrix[14], matrix[15]
        )
Пример #2
0
    def test_ComputeNarrowedFrustum(self):
        f = Gf.Frustum()
        f.projectionType = f.Orthographic
        f.Transform(Gf.Matrix4d(Gf.Vec4d(3,2,1,1)))
        narrowF = f.ComputeNarrowedFrustum(Gf.Vec2d(0, 0), Gf.Vec2d(0.1, 0.1))
        self.assertTrue(Gf.IsClose(narrowF.window.min, Gf.Vec2d(-0.3, -0.2), 0.0001))
        self.assertTrue(Gf.IsClose(narrowF.window.max, Gf.Vec2d(0.3, 0.2), 0.0001))

        narrowF = f.ComputeNarrowedFrustum(Gf.Vec3d(0, 0, -1), Gf.Vec2d(0.1, 0.1))
        self.assertTrue(Gf.IsClose(narrowF.window.min, Gf.Vec2d(-0.3, -0.2), 0.0001))
        self.assertTrue(Gf.IsClose(narrowF.window.max, Gf.Vec2d(0.3, 0.2), 0.0001))

        # Given a point behind the eye should get the same frustum back
        narrowF = f.ComputeNarrowedFrustum(Gf.Vec3d(0, 0, 1), Gf.Vec2d(0.1, 0.1))
        self.assertTrue(Gf.IsClose(narrowF.window.min, Gf.Vec2d(-3.0,-2.0), 0.0001))
        self.assertTrue(Gf.IsClose(narrowF.window.max, Gf.Vec2d(3.0,2.0), 0.0001))
Пример #3
0
    def _convert_skin_to_usd(self, gltf_node, gltf_primitive, usd_node, usd_mesh):
        """Converts a glTF skin to a UsdSkel

        Arguments:
            gltf_node {dict} -- glTF node
            node_index {int} -- index of the glTF node
            usd_parent_node {UsdPrim} -- parent node of the usd node
            usd_mesh {[type]} -- [description]
        """
        skel_binding_api = UsdSkel.BindingAPI(usd_mesh)
        gltf_skin = gltf_node.get_skin()
        gltf_joint_names = [GLTF2USDUtils.convert_to_usd_friendly_node_name(joint.name) for joint in gltf_skin.get_joints()]
        usd_joint_names = [Sdf.Path(self._get_usd_joint_hierarchy_name(joint, gltf_skin.root_joints)) for joint in gltf_skin.get_joints()]
        skeleton = self._create_usd_skeleton(gltf_skin, usd_node, usd_joint_names)
        skeleton_animation = self._create_usd_skeleton_animation(gltf_skin, skeleton, usd_joint_names)

        parent_path = usd_node.GetPath()

        bind_matrices = []
        rest_matrices = []

        skeleton_root = self.stage.GetPrimAtPath(parent_path)
        skel_binding_api = UsdSkel.BindingAPI(usd_mesh)
        skel_binding_api.CreateGeomBindTransformAttr(Gf.Matrix4d(((1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1))))
        skel_binding_api.CreateSkeletonRel().AddTarget(skeleton.GetPath())
        if skeleton_animation:
            skel_binding_api.CreateAnimationSourceRel().AddTarget(skeleton_animation.GetPath())
        
        bind_matrices = self._compute_bind_transforms(gltf_skin)

        primitive_attributes = gltf_primitive.get_attributes()

        if 'WEIGHTS_0' in primitive_attributes and 'JOINTS_0' in primitive_attributes:
            total_vertex_weights = primitive_attributes['WEIGHTS_0'].get_data()
            total_vertex_joints = primitive_attributes['JOINTS_0'].get_data()
            total_joint_indices = []
            total_joint_weights = []

            for joint_indices, weights in zip(total_vertex_joints, total_vertex_weights):
                for joint_index, weight in zip(joint_indices, weights):
                    total_joint_indices.append(joint_index)
                    total_joint_weights.append(weight)

            joint_indices_attr = skel_binding_api.CreateJointIndicesPrimvar(False, 4).Set(total_joint_indices)
            total_joint_weights = Vt.FloatArray(total_joint_weights)
            UsdSkel.NormalizeWeights(total_joint_weights, 4)
            joint_weights_attr = skel_binding_api.CreateJointWeightsPrimvar(False, 4).Set(total_joint_weights)
Пример #4
0
    def _processCameraData(self, jsonData, cameraStage):
        # type: (dict, pxr.Usd.Stage) -> None
        """
        Create a USD Camera in the given USD Stage from the given JSON camera
        definition.
        """
        cameraFOV = jsonData.get('fov', )
        cameraName = jsonData.get('name')
        cameraEyePosition = jsonData.get('eye')
        cameraFocalLength = jsonData.get('focalLength')
        # cameraCenterOfInterest = jsonData.get('centerOfInterest')
        # cameraLensRadius = jsonData.get('lensRadius')
        cameraUpVector = normalize(jsonData.get('up'))
        # cameraScreenWindow = jsonData.get('screenwindow')
        cameraRatio = jsonData.get('ratio')
        cameraLook = normalize(jsonData.get('look'))

        # Look at conversion:
        forwardVector = normalize([
            cameraEyePosition[0] - cameraLook[0],
            cameraEyePosition[1] - cameraLook[1],
            cameraEyePosition[2] - cameraLook[2]
        ])
        sideVector = crossProduct(cameraUpVector, forwardVector)
        transformMatrix = [
            sideVector[0], sideVector[1], sideVector[2], 0, cameraUpVector[0],
            cameraUpVector[1], cameraUpVector[2], 0, forwardVector[0],
            forwardVector[1], forwardVector[2], 0, cameraEyePosition[0],
            cameraEyePosition[1], cameraEyePosition[2], 1
        ]

        cameraPrimPath = cameraStage.GetDefaultPrim().GetPath().AppendChild(
            cameraName)
        usdCamera = UsdGeom.Camera.Define(cameraStage, cameraPrimPath)
        usdCamera.MakeMatrixXform().Set(Gf.Matrix4d(*transformMatrix))
        usdCamera.GetProjectionAttr().Set(UsdGeom.Tokens.perspective)
        if cameraFocalLength is not None:
            usdCamera.GetFocalLengthAttr().Set(cameraFocalLength)

        if cameraRatio is not None and cameraFOV is not None:
            camera = usdCamera.GetCamera(cameraStage.GetStartTimeCode())
            camera.SetPerspectiveFromAspectRatioAndFieldOfView(
                aspectRatio=cameraRatio,
                fieldOfView=cameraFOV,
                direction=Gf.Camera.FOVHorizontal)
            usdCamera.SetFromCamera(camera)
    def testSkelRestXformsWithNoDagPose(self):
        """
        Tests export of rest xforms when there is no dagPose node at all.
        """
        mayaFile = os.path.join(self.inputPath, "UsdExportSkeletonTest",
            "UsdExportSkeletonNoDagPose.ma")
        cmds.file(mayaFile, force=True, open=True)

        usdFile = os.path.abspath('UsdExportSkeletonRestXformsWithNoDagPose.usda')
        cmds.select('skel_root')
        cmds.mayaUSDExport(mergeTransformAndShape=True, file=usdFile,
                           shadingMode='none', exportSkels='auto', selection=True)

        stage = Usd.Stage.Open(usdFile)

        skeleton = UsdSkel.Skeleton.Get(stage, '/skel_root/joint1')

        self.assertEqual(skeleton.GetJointsAttr().Get(),
            Vt.TokenArray(['joint1',
                           'joint1/joint2',
                           'joint1/joint2/joint3',
                           'joint1/joint2/joint3/joint4']))

        self.assertEqual(
            skeleton.GetBindTransformsAttr().Get(),
            Vt.Matrix4dArray([
                Gf.Matrix4d( (-1, 0, 0, 0), (0, 1, 0, 0), (0, 0, -1, 0), (0, 0, 0, 1) ),
                Gf.Matrix4d( (0, -1, 0, 0), (-1, 0, 0, 0), (0, 0, -1, 0), (3, 0, 0, 1) ),
                Gf.Matrix4d( (0, -1, 0, 0), (0, 0, -1, 0), (1, 0, 0, 0), (3, 0, -2, 1) ),
                Gf.Matrix4d( (0, -1, 0, 0), (1, 0, 0, 0), (0, 0, 1, 0), (3, 0, -4, 1) ),
            ])
        )

        self.assertEqual(
            skeleton.GetRestTransformsAttr().Get(),
            Vt.Matrix4dArray([
                Gf.Matrix4d( (-1, 0, 0, 0), (0, 1, 0, 0), (0, 0, -1, 0), (0, 0, 0, 1) ),
                Gf.Matrix4d( (0, -1, 0, 0), (1, 0, 0, 0), (0, 0, 1, 0), (-3, 0, 0, 1) ),
                Gf.Matrix4d( (1, 0, 0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (0, 0, 2, 1) ),
                Gf.Matrix4d( (1, 0, 0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (0, 2, 0, 1) ),
            ])
        )        
Пример #6
0
    def test_Cube(self):
        stage = Usd.Stage.CreateInMemory()
        cube = UsdGeom.Cube.Define(stage, "/Foo")
        cube.CreateSizeAttr(4.0)

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(cube, [(-2, -2, -2), (2, 2, 2)])

        # Apply the identity matrix. This should be identical to the extent
        # computed with no transform.
        self.verifyExtent(cube, [(-2, -2, -2), (2, 2, 2)], Gf.Matrix4d(1.0))

        # Apply an arbitrary transform matrix.
        self.verifyExtent(
            cube,
            [(-2.242468870104182, -1.2424688701041822, -0.12123443505209108),
             (4.242468870104182, 5.242468870104181, 3.121234435052091)],
            STRANGE_TRANSFORM)
Пример #7
0
    def test_Constructors(self):
        self.assertIsInstance(Gf.Transform(), Gf.Transform), err("constructor")
        self.assertIsInstance(
            Gf.Transform(Gf.Vec3d(), Gf.Rotation(), Gf.Vec3d(), Gf.Vec3d(),
                         Gf.Rotation()), Gf.Transform), err("constructor")

        # test GfMatrix4d constructor
        rotation = Gf.Rotation(Gf.Vec3d(0.5, 0.6, 0.7), 123)
        m = Gf.Matrix4d(1.0)
        m.SetRotate(rotation)
        t = Gf.Transform(m)
        tm = t.GetMatrix()
        tol = 0.001
        self.assertTrue(Gf.IsClose(tm[0],m[0],tol) and \
            Gf.IsClose(tm[1],m[1],tol) and \
            Gf.IsClose(tm[2],m[2],tol) and \
            Gf.IsClose(tm[3],m[3],tol),    \
            err("GfTransform(GfMatrix4d) constructor"))
Пример #8
0
def set_translate(prim, new_loc):
    properties = prim.GetPropertyNames()
    if "xformOp:translate" in properties:
        translate_attr = prim.GetAttribute("xformOp:translate")
        translate_attr.Set(new_loc)
    elif "xformOp:translation" in properties:
        translation_attr = prim.GetAttribute("xformOp:translate")
        translation_attr.Set(new_loc)
    elif "xformOp:transform" in properties:
        transform_attr = prim.GetAttribute("xformOp:transform")
        matrix = prim.GetAttribute("xformOp:transform").Get()
        matrix.SetTranslateOnly(new_loc)
        transform_attr.Set(matrix)
    else:
        xform = UsdGeom.Xformable(prim)
        xform_op = xform.AddXformOp(UsdGeom.XformOp.TypeTransform,
                                    UsdGeom.XformOp.PrecisionDouble, "")
        xform_op.Set(Gf.Matrix4d().SetTranslate(new_loc))
    def compute(self, **kwargs):
        if not self.object:
            return None

        input_stage = self.get_input_link('Input', **kwargs)

        if not input_stage:
            return None

        if not input_stage.GetPseudoRoot().GetAllChildren():
            return None

        depsgraph = bpy.context.evaluated_depsgraph_get()
        obj = self.object.evaluated_get(depsgraph)
        distribute_items = obj.data.vertices if self.method == 'VERTICES' else obj.data.polygons
        if not distribute_items:
            return None

        stage = self.cached_stage.create()
        UsdGeom.SetStageMetersPerUnit(stage, 1)
        UsdGeom.SetStageUpAxis(stage, UsdGeom.Tokens.z)

        for i, item in enumerate(distribute_items):
            root_xform = UsdGeom.Xform.Define(
                stage, f'/{Tf.MakeValidIdentifier(f"{self.name}_{i}")}')
            for prim in input_stage.GetPseudoRoot().GetAllChildren():
                override_prim = stage.OverridePrim(
                    root_xform.GetPath().AppendChild(prim.GetName()))
                override_prim.GetReferences().AddReference(
                    input_stage.GetRootLayer().realPath, prim.GetPath())

            trans = Matrix.Translation(item.co if self.method ==
                                       'VERTICES' else item.center)
            rot = item.normal.to_track_quat().to_matrix().to_4x4()

            transform = trans @ rot
            if self.object_transform:
                transform = obj.matrix_world @ transform

            UsdGeom.Xform.Get(stage, root_xform.GetPath()).MakeMatrixXform()
            root_xform.GetPrim().GetAttribute('xformOp:transform').Set(
                Gf.Matrix4d(transform.transposed()))

        return stage
Пример #10
0
    def test_DecomposeRotation3(self):
        '''Test DecomposeRotation3, should be identical to zero Sw except it returns
        a 3-tuple.  Minimally tested with and without hints as the functionality
        is more thoroughly tested in the zero Sw case above.'''

        rot = Gf.Matrix4d(-0.77657773110174733, 0.41334436580878597,
                          -0.47547183177449759, 0.0, 0.53325734733674601,
                          0.029348545343396093, -0.8454438268729656, 0.0,
                          -0.33550503583141722, -0.91010169659239692,
                          -0.24321034680169412, 0.0, 0.0, 0.0, 0.0, 1.0)

        # No hints
        thetaTw, thetaFB, thetaLR = \
            Gf.Rotation.DecomposeRotation3(rot,
                                           twAxis = Gf.Vec3d(0, 0, 1),
                                           fbAxis = Gf.Vec3d(1, 0, 0),
                                           lrAxis = Gf.Vec3d(0, 1, 0),
                                           handedness = 1)

        self.assertAlmostEqual(thetaTw, -1.641680, places=5)
        self.assertAlmostEqual(thetaFB, 1.998063, places=5)
        self.assertAlmostEqual(thetaLR, 0.943548, places=5)
        self.assertTrue(
            IsMatrixClose(
                ComposeRotation('XYZ', (thetaTw, thetaFB, thetaLR, 0.0)), rot))

        # Hints variation 1
        thetaTw, thetaFB, thetaLR = \
            Gf.Rotation.DecomposeRotation3(rot,
                                           twAxis = Gf.Vec3d(0, 0, 1),
                                           fbAxis = Gf.Vec3d(1, 0, 0),
                                           lrAxis = Gf.Vec3d(0, 1, 0),
                                           handedness = 1,
                                           thetaTwHint = -2.0,
                                           thetaFBHint = 2,
                                           thetaLRHint = 1.0,
                                           useHint = True)

        self.assertAlmostEqual(thetaTw, -1.641680, places=5)
        self.assertAlmostEqual(thetaFB, 1.998063, places=5)
        self.assertAlmostEqual(thetaLR, 0.943548, places=5)
        self.assertTrue(
            IsMatrixClose(
                ComposeRotation('XYZ', (thetaTw, thetaFB, thetaLR, 0.0)), rot))
Пример #11
0
    def test_ConstructFromMatrix(self):
        m = Gf.Matrix4d(0.9987016645043332, -0.035803686178599, -0.036236464677155, 0.0,
                        0.0362364646771555,  0.999278702502407,  0.011357524061459, 0.0,
                        0.0358036861785999, -0.012655859557126,  0.999278702502407, 0.0,
                        3.0               , -6.0              ,  5.0              , 1.0)

        f = Gf.Frustum(m,
                    Gf.Range2d(Gf.Vec2d(-0.22,-0.2), Gf.Vec2d(0.2, 0.33)),
                    Gf.Range1d(20, 90),
                    Gf.Frustum.Perspective)

        f = Gf.Frustum(m,
                    Gf.Range2d(Gf.Vec2d(-0.22,-0.2), Gf.Vec2d(0.2, 0.33)),
                    Gf.Range1d(20, 90),
                    Gf.Frustum.Perspective)

        corners = f.ComputeCorners()
        results = (Gf.Vec3d( -2.255306906099,  -9.58646139968125, -14.8715637017144),
                   Gf.Vec3d(  6.133787075736,  -9.88721236358150, -15.1759500050026),
                   Gf.Vec3d( -1.871200380521,   1.00589284684426, -14.7511739466630),
                   Gf.Vec3d(  6.517893601314,   0.70514188294401, -15.0555602499511),
                   Gf.Vec3d(-20.648881077448, -22.13907629856565, -84.4220366577152),
                   Gf.Vec3d( 17.102041840815, -23.49245563611677, -85.7917750225117),
                   Gf.Vec3d(-18.920401712348,  25.52651781079917, -83.8802827599836),
                   Gf.Vec3d( 18.830521205915,  24.17313847324806, -85.2500211247801))

        self.assertEqual(len(corners), len(results))
        for i in range(len(results)):
            self.assertTrue(Gf.IsClose(corners[i], results[i], 0.0001))
            
        corners = f.ComputeCornersAtDistance(20)
        for i in range(len(corners)):
            self.assertTrue(Gf.IsClose(corners[i], results[i], 0.0001))

        corners = f.ComputeCornersAtDistance(90)
        for i in range(len(corners)):
            self.assertTrue(Gf.IsClose(corners[i], results[i+4], 0.0001))

        corners = f.ComputeCornersAtDistance((20 + 90) / 2.0)
        for i in range(len(corners)):
            self.assertTrue(
                Gf.IsClose(corners[i], (results[i] + results[i+4]) / 2.0,
                           0.0001))
Пример #12
0
def sync(root_prim, world: bpy.types.World, **kwargs):
    is_gl_mode = kwargs.get('is_gl_delegate', False)

    if is_gl_mode:
        # TODO export correct Dome light with texture for GL mode
        return

    # get the World IBL image
    data = WorldData.init_from_world(world)

    stage = root_prim.GetStage()

    if not data.cycles_ibl.image:
        # TODO create image from environment color data if no image used
        return

    # create Dome light
    xform = UsdGeom.Xform.Define(stage,
                                 root_prim.GetPath().AppendChild("_world"))
    obj_prim = xform.GetPrim()

    usd_light = UsdLux.DomeLight.Define(
        stage,
        obj_prim.GetPath().AppendChild(sdf_path(world.name)))
    usd_light.ClearXformOpOrder()
    usd_light.OrientToStageUpAxis()

    p = Sdf.AssetPath(data.cycles_ibl.image)
    usd_light.CreateTextureFileAttr(p)

    # set correct Dome light rotation
    matrix = np.identity(4)
    rotation = data.cycles_ibl.rotation
    euler = mathutils.Euler(
        (-rotation[0], -rotation[1] + np.pi, -rotation[2] - np.pi / 2))

    rotation_matrix = np.array(euler.to_matrix(), dtype=np.float32)

    matrix[:3, :3] = rotation_matrix[:, :]

    xform.ClearXformOpOrder()
    xform.AddTransformOp().Set(Gf.Matrix4d(matrix))
Пример #13
0
    def test_OneInstanceUnalignedData(self):
        stage = Usd.Stage.Open("test.usda")
        pi = UsdGeom.PointInstancer(
            stage.GetPrimAtPath("/OneInstanceUnalignedData"))

        # Test that unaligned positions/orientations are handled properly.
        baseTime = 3
        tr = timeRange(baseTime)
        xformsArray = self.computeInstanceTransforms(pi, tr, baseTime)
        compares = []
        for time, delta in tr:
            rotationTime = time - 2
            velocityTime = time - 1
            compares.append([
                Gf.Matrix4d(
                    Gf.Rotation(Gf.Vec3d(0, 0, 1), rotationTime * 36),
                    Gf.Vec3d(velocityTime * 5, velocityTime * 10,
                             velocityTime * 20))
            ])
        self.assertAllMatrixListsEqual(xformsArray, compares)
Пример #14
0
def build_transform(obj, frame=None):
    tfm_matrix = obj.Kinematics.Local.Transform.Matrix4 if frame is None else obj.Kinematics.Local.GetTransform2(
        frame).Matrix4
    return Gf.Matrix4d(
        tfm_matrix.Value(0, 0),
        tfm_matrix.Value(0, 1),
        tfm_matrix.Value(0, 2),
        tfm_matrix.Value(0, 3),
        tfm_matrix.Value(1, 0),
        tfm_matrix.Value(1, 1),
        tfm_matrix.Value(1, 2),
        tfm_matrix.Value(1, 3),
        tfm_matrix.Value(2, 0),
        tfm_matrix.Value(2, 1),
        tfm_matrix.Value(2, 2),
        tfm_matrix.Value(2, 3),
        tfm_matrix.Value(3, 0),
        tfm_matrix.Value(3, 1),
        tfm_matrix.Value(3, 2),
        tfm_matrix.Value(3, 3),
    )
Пример #15
0
    def test_PrestoRotatePivot(self):
        """ Test that simulates how the pivot position is taken into account in the 
            presto transformable prim with transformType=Vectors.
        """
        s = Usd.Stage.CreateInMemory()

        x = UsdGeom.Xform.Define(s, '/World')

        x.AddTranslateOp().Set(Gf.Vec3d(10., 0., 0.))

        # Use token for 'pivot'
        x.AddTranslateOp(opSuffix='pivot',
                         isInverseOp=False).Set(Gf.Vec3d(0, 10, 0))

        x.AddRotateXYZOp().Set(Gf.Vec3f(60, 0, 30))

        x.AddScaleOp().Set(Gf.Vec3f(2, 2, 2))

        # Insert the inverse pivot.
        inverseTranslateOp = x.AddTranslateOp(opSuffix='pivot',
                                              isInverseOp=True)

        # Calling set on an inverseOp results in a coding error.

        self.assertEqual(
            x.GetXformOpOrderAttr().Get(),
            Vt.TokenArray(('xformOp:translate', 'xformOp:translate:pivot',
                           'xformOp:rotateXYZ', 'xformOp:scale',
                           '!invert!xformOp:translate:pivot')))

        xform = x.GetLocalTransformation(Usd.TimeCode.Default())

        self._AssertCloseXf(
            xform,
            Gf.Matrix4d(1.7320508075688774, 1.0, 0.0, 0.0, -0.5,
                        0.8660254037844389, 1.7320508075688772, 0.0,
                        0.8660254037844385, -1.5, 1.0, 0.0, 15.0,
                        1.339745962155611, -17.32050807568877, 1.0))
Пример #16
0
    def test_GetCamera(self):
        usdStage = Usd.Stage.CreateInMemory()
        usdCamera = UsdGeom.Camera.Define(usdStage, '/camera')

        # test fall-back values
        self._CheckValues(Gf.Camera(), usdCamera, 1.0)

        usdCamera.MakeMatrixXform().Set(Gf.Matrix4d(3.0))
        usdCamera.GetProjectionAttr().Set(UsdGeom.Tokens.orthographic)
        usdCamera.GetHorizontalApertureAttr().Set(5.1)
        usdCamera.GetVerticalApertureAttr().Set(2.0)
        usdCamera.GetHorizontalApertureOffsetAttr().Set(-0.11)
        usdCamera.GetVerticalApertureOffsetAttr().Set(0.12)
        usdCamera.GetFocalLengthAttr().Set(28)
        usdCamera.GetClippingRangeAttr().Set(Gf.Vec2f(5, 15))
        usdCamera.GetClippingPlanesAttr().Set([(1,2,3,4), (8,7,6,5)])
        usdCamera.GetFStopAttr().Set(1.2)
        usdCamera.GetFocusDistanceAttr().Set(300)

        camera = usdCamera.GetCamera(1.0)

        # test assigned values
        self._CheckValues(camera, usdCamera, 1.0)
Пример #17
0
    def test_PointInstancer(self):
        stage = Usd.Stage.Open("testPointInstancer.usda")

        pi = UsdGeom.PointInstancer(stage.GetPrimAtPath("/Instancer"))

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(pi, [(-1, -1, -1), (3.5, 3.5, 3.5)])

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(pi, [(-1, -1, -1), (3.5, 3.5, 3.5)],
                          Gf.Matrix4d(1.0))

        # Apply an arbitrary transform matrix. Note that this is different from
        # the extent displayed in Usdview. If you open testPointInstancer.usda
        # and select /StrangeInstancer, you will see the box is larger than it
        # needs to be (it transforms the bounding box around the entire
        # PointInstancer, not the boxes for each instance like
        # ComputeExtentFromPlugins). If you select
        # /StrangeInstancerComputedExtent, it will display the (tighter)
        # computed extent used below.
        self.verifyExtent(
            pi, [(-1.3977774381637573, 0.3787655532360077, 0.689382791519165),
                 (5.12123441696167, 6.12123441696167, 3.560617208480835)],
            STRANGE_TRANSFORM)
Пример #18
0
    def test_PointBased(self):
        stage = Usd.Stage.Open("testPointBased.usda")

        pointBased = UsdGeom.PointBased(stage.GetPrimAtPath("/Points"))

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(pointBased, [(0, 0, 0), (3.0, 2.0, 2.0)])

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(pointBased, [(0, 0, 0), (3.0, 2.0, 2.0)],
                          Gf.Matrix4d(1.0))

        # Apply an arbitrary transform matrix. Note that this is different from
        # the extent displayed in Usdview. If you open testPoints.usda and
        # select /StrangePoints, you will see the box is larger than it needs to
        # be (it transforms the bounding box around the points, not the points
        # themselves like ComputeExtentFromPlugins). If you select
        # /StrangePointsComputedExtent, it will display the (much tighter)
        # computed extent used below.
        self.verifyExtent(
            pointBased,
            [(0.3787655532360077, 2.0, 1.5),
             (4.4259724617004395, 3.609475612640381, 2.0058794021606445)],
            STRANGE_TRANSFORM)
Пример #19
0
    def test_Points(self):
        stage = Usd.Stage.Open("testPoints.usda")

        points = UsdGeom.Points(stage.GetPrimAtPath("/Points"))

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(points, [(-0.5, -0.5, -0.5), (3.25, 2.0, 2.25)])

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(points, [(-0.5, -0.5, -0.5), (3.25, 2.0, 2.25)],
                          Gf.Matrix4d(1.0))

        # Apply an arbitrary transform matrix. Note that this is different from
        # the extent displayed in Usdview. If you open testPoints.usda and
        # select /StrangePoints, you will see the box is larger than it needs to
        # be (it transforms the bounding box around the points, not the points
        # themselves like ComputeExtentFromPlugins). If you select
        # /StrangePointsComputedExtent, it will display the (much tighter)
        # computed extent used below.
        self.verifyExtent(
            points,
            [(0.18938279151916504, 1.189382791519165, 1.0946913957595825),
             (4.8312811851501465, 3.609475612640381, 2.041466236114502)],
            STRANGE_TRANSFORM)
Пример #20
0
def _write_influence_data(binding, mesh, cluster, binding_joints,
                          maximum_influences, weights_getter):
    matrix = cmds.xform(mesh, matrix=True, worldSpace=True, q=True)
    binding.CreateGeomBindTransformAttr().Set(Gf.Matrix4d(*matrix))

    indices, weights = _calculate_influences(mesh, cluster, binding_joints,
                                             maximum_influences,
                                             weights_getter)
    indices = Vt.IntArray(indices)
    weights = Vt.FloatArray(weights)

    # Reference: https://graphics.pixar.com/usd/docs/api/_usd_skel__schemas.html#UsdSkel_BindingAPI_StoringInfluences
    # Keep weights sorted and normalized for best performance
    #
    UsdSkel.NormalizeWeights(weights, len(binding_joints))
    UsdSkel.SortInfluences(indices, weights, maximum_influences)

    indices_attribute = binding.CreateJointIndicesPrimvar(
        constant=False, elementSize=maximum_influences)
    indices_attribute.Set(indices)

    weights_attribute = binding.CreateJointWeightsPrimvar(
        constant=False, elementSize=maximum_influences)
    weights_attribute.Set(weights)
Пример #21
0
    def test_Curves(self):
        stage = Usd.Stage.Open("testCurves.usda")

        curves = UsdGeom.Curves(stage.GetPrimAtPath("/Curves"))

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(curves, [(-0.5, -0.5, -0.5), (3.5, 2.5, 2.5)])

        # Verify the extent computation when no transform matrix is given.
        self.verifyExtent(curves, [(-0.5, -0.5, -0.5), (3.5, 2.5, 2.5)],
                          Gf.Matrix4d(1.0))

        # Apply an arbitrary transform matrix. Note that this is different from
        # the extent displayed in Usdview. If you open testPoints.usda and
        # select /StrangePoints, you will see the box is larger than it needs to
        # be (it transforms the bounding box around the curves, not the curves
        # themselves like ComputeExtentFromPlugins). If you select
        # /StrangePointsComputedExtent, it will display the (much tighter)
        # computed extent used below.
        self.verifyExtent(
            curves,
            [(-0.43185165524482727, 1.189382791519165, 1.0946913957595825),
             (5.236589431762695, 4.420092582702637, 2.4111881256103516)],
            STRANGE_TRANSFORM)
Пример #22
0
    def testPivot(self):
        """
        Tests that pivotPosition attribute doesn't interfere with the matrix
        that we get in maya when importing a usd file.
        """
        def _usdToMayaPath(usdPath):
            return str(usdPath).replace('/', '|')

        from maya import cmds
        cmds.loadPlugin('pxrUsd')
        usdFile = './pivotTests.usda'
        from pxr import Usd, UsdGeom
        stage = Usd.Stage.Open(usdFile)
        xformCache = UsdGeom.XformCache()

        cmds.usdImport(file=os.path.abspath(usdFile), primPath='/World')

        usdPaths = [
            '/World/anim/chars/SomeCharacter/Geom/Face/Eyes/LEye',
            '/World/anim/chars/SomeCharacter/Geom/Face/Eyes/LEye/Sclera_sbdv',
            '/World/anim/chars/SomeCharacter/Geom/Face/Eyes/REye/Sclera_sbdv',
            '/World/anim/chars/SomeCharacter/Geom/Hair/HairStandin/Hair/Hair_sbdv',
            '/World/anim/chars/SomeCharacter/Geom/Hair/HairStandin/Hair/HairFrontPiece_sbdv',
        ]

        for usdPath in usdPaths:
            usdMatrix = xformCache.GetLocalToWorldTransform(
                stage.GetPrimAtPath(usdPath))
            mayaPath = _usdToMayaPath(usdPath)
            mayaMatrix = Gf.Matrix4d(*cmds.xform(
                mayaPath, query=True, matrix=True, worldSpace=True))

            print 'testing matrix at', usdPath
            self.assertTrue(
                Gf.IsClose(usdMatrix.ExtractTranslation(),
                           mayaMatrix.ExtractTranslation(), self.EPSILON))
Пример #23
0
    def test_Methods(self):
        t1 = Gf.Transform()
        t2 = Gf.Transform()
        t1.SetMatrix(Gf.Matrix4d().SetRotate(Gf.Rotation(
            Gf.Vec3d(1, 1, 1), 60)))
        t2.SetMatrix(Gf.Matrix4d().SetRotate(Gf.Rotation(
            Gf.Vec3d(1, 1, 1), 60)))
        self.assertEqual(eval(repr(t1)), t1)
        self.assertEqual(t1, t2, err("equality"))

        t2.SetMatrix(Gf.Matrix4d().SetRotate(Gf.Rotation(Gf.Vec3d.ZAxis(),
                                                         60)))
        self.assertNotEqual(t1, t2, err("inequality"))

        t1 = Gf.Transform()
        t2 = Gf.Transform()
        t1.SetMatrix(Gf.Matrix4d().SetRotate(Gf.Rotation(
            Gf.Vec3d(1, 1, 1), 60)))
        t2.rotation = Gf.Rotation(Gf.Vec3d.YAxis(), 60)
        t1 *= t2
        self.assertEqual(eval(repr(t1)), t1)
        self.assertTrue(
            Gf.IsClose(t1.rotation.axis, Gf.Vec3d(0.495572, 0.858356,
                                                  0.132788), 0.0001)
            and Gf.IsClose(t1.rotation.angle, 105.447, 0.0001), err("*="))

        t1 = Gf.Transform()
        t2 = Gf.Transform()
        t1.SetMatrix(Gf.Matrix4d().SetRotate(Gf.Rotation(
            Gf.Vec3d(1, 1, 1), 60)))
        t2.rotation = Gf.Rotation(Gf.Vec3d.YAxis(), 60)
        t3 = t1 * t2
        self.assertEqual(eval(repr(t3)), t3)
        self.assertTrue(Gf.IsClose(t3.rotation.axis, Gf.Vec3d(0.495572, 0.858356, 0.132788), 0.0001) and \
            Gf.IsClose(t3.rotation.angle, 105.447, 0.0001), err("*="))

        t1 = Gf.Transform()
        m = Gf.Matrix4d().SetScale(Gf.Vec3d(0, 1, 1))
        t1.SetMatrix(m)
        self.assertTrue(Gf.IsClose(t1.scale, Gf.Vec3d(0.0, 1, 1), 1e-4),
                        err("SetMatrix"))
Пример #24
0
    def testSkelTransforms(self):
        """
        Tests that the computed joint transforms in USD, when tarnsformed into
        world space, match the world space transforms of the Maya joints.
        """

        mayaFile = os.path.join(self.inputPath, "UsdExportSkeletonTest",
                                "UsdExportSkeleton.ma")
        cmds.file(mayaFile, force=True, open=True)

        # frameRange = [1, 30]
        frameRange = [1, 3]

        # TODO: The joint hierarchy intentionally includes non-joint nodes,
        # which are expected to be ignored. However, when we try to extract
        # restTransforms from the dagPose, the intermediate transforms cause
        # problems, since they are not members of the dagPose. As a result,
        # no dag pose is exported. Need to come up with a way to handle this
        # correctly in export.
        print("Expect warnings about invalid restTransforms")
        usdFile = os.path.abspath('UsdExportSkeleton.usda')
        cmds.usdExport(mergeTransformAndShape=True,
                       file=usdFile,
                       shadingMode='none',
                       frameRange=frameRange,
                       exportSkels='auto')
        stage = Usd.Stage.Open(usdFile)

        root = UsdSkel.Root.Get(stage, '/SkelChar')
        self.assertTrue(root)

        skelCache = UsdSkel.Cache()

        if Usd.GetVersion() > (0, 20, 8):
            skelCache.Populate(root, Usd.PrimDefaultPredicate)
        else:
            skelCache.Populate(root)

        skel = UsdSkel.Skeleton.Get(stage, '/SkelChar/Hips')
        self.assertTrue(skel)

        skelQuery = skelCache.GetSkelQuery(skel)
        self.assertTrue(skelQuery)

        xfCache = UsdGeom.XformCache()

        for frame in range(*frameRange):
            cmds.currentTime(frame, edit=True)
            xfCache.SetTime(frame)

            skelLocalToWorld = xfCache.GetLocalToWorldTransform(
                skelQuery.GetPrim())

            usdJointXforms = skelQuery.ComputeJointSkelTransforms(frame)

            for joint, usdJointXf in zip(skelQuery.GetJointOrder(),
                                         usdJointXforms):

                usdJointWorldXf = usdJointXf * skelLocalToWorld

                selList = OM.MSelectionList()
                selList.add(Sdf.Path(joint).name)

                dagPath = selList.getDagPath(0)
                mayaJointWorldXf = Gf.Matrix4d(*dagPath.inclusiveMatrix())

                self.assertTrue(
                    Gf.IsClose(mayaJointWorldXf, usdJointWorldXf, 1e-5))
Пример #25
0
def _MMatrixToGf(mx):
    gfmx = Gf.Matrix4d()
    for i in range(4):
        for j in range(4):
            gfmx[i][j] = mx[i * 4 + j]
    return gfmx
Пример #26
0
    def test_ScalarRotateOps(self):
        s = Usd.Stage.CreateInMemory()
        x = UsdGeom.Xform.Define(s, '/X')
        x.AddRotateXOp().Set(45.)
        xformX = x.GetLocalTransformation(Usd.TimeCode.Default())
        self._AssertCloseXf(xformX, 
            Gf.Matrix4d(1.0, 0.0, 0.0, 0.0,
                        0.0, 0.7071067811865475, 0.7071067811865476, 0.0,
                        0.0, -0.7071067811865476, 0.7071067811865475, 0.0,
                        0.0, 0.0, 0.0, 1.0))
        self.assertEqual(x.GetXformOpOrderAttr().Get(), 
                    Vt.TokenArray(('xformOp:rotateX', )))

        y = UsdGeom.Xform.Define(s, '/Y')
        y.AddRotateYOp().Set(90.)
        xformY = y.GetLocalTransformation(Usd.TimeCode.Default())
        self._AssertCloseXf(xformY, 
            Gf.Matrix4d(0, 0.0, -1.0, 0.0,
                    0.0, 1.0, 0.0, 0.0,
                    1.0, 0.0, 0, 0.0,
                    0.0, 0.0, 0.0, 1.0))
        self.assertEqual(y.GetXformOpOrderAttr().Get(), 
                    Vt.TokenArray(('xformOp:rotateY', )))

        z = UsdGeom.Xform.Define(s, '/Z')
        z.AddRotateZOp().Set(30.)
        xformZ = z.GetLocalTransformation(Usd.TimeCode.Default())
        self._AssertCloseXf(xformZ, 
            Gf.Matrix4d(0.866025403784439, 0.5, 0, 0, 
                        -0.5, 0.866025403784439, 0, 0, 
                        0, 0, 1, 0, 
                        0, 0, 0, 1))
        self.assertEqual(z.GetXformOpOrderAttr().Get(), 
                    Vt.TokenArray(('xformOp:rotateZ', )))

        xy = UsdGeom.Xform.Define(s, '/XY')
        xy.AddRotateYOp().Set(90.)
        xy.AddRotateXOp().Set(45.)
        xformXY = xy.GetLocalTransformation(Usd.TimeCode.Default())
        self._AssertCloseXf(xformXY, 
            Gf.Matrix4d(0.0, 0.0, -1.0, 0.0,
                        0.7071067811865476, 0.7071067811865475, 0.0, 0.0,
                        0.7071067811865475, -0.7071067811865476, 0.0, 0.0,
                        0.0, 0.0, 0.0, 1.0))
        self.assertEqual(xy.GetXformOpOrderAttr().Get(),
                    Vt.TokenArray(('xformOp:rotateY', 'xformOp:rotateX')))

        yz = UsdGeom.Xform.Define(s, '/YZ')
        yz.AddRotateZOp().Set(30.)
        yz.AddRotateYOp().Set(90.)
        xformYZ = yz.GetLocalTransformation(Usd.TimeCode.Default())
        self._AssertCloseXf(xformYZ, 
            Gf.Matrix4d(0.0, 0.0, -1.0, 0.0,
                        -0.5, 0.8660254037844387, 0.0, 0.0,
                        0.8660254037844387, 0.5, 0.0, 0.0,
                        0.0, 0.0, 0.0, 1.0))
        self.assertEqual(yz.GetXformOpOrderAttr().Get(),
                    Vt.TokenArray(('xformOp:rotateZ', 'xformOp:rotateY')))

        zx = UsdGeom.Xform.Define(s, '/ZX')
        zx.AddRotateXOp().Set(45.)
        zx.AddRotateZOp().Set(30.)
        xformZX = zx.GetLocalTransformation(Usd.TimeCode.Default())
        self._AssertCloseXf(xformZX, 
            Gf.Matrix4d(0.8660254037844387, 0.3535533905932737, 0.35355339059327373, 0.0,
                        -0.5, 0.6123724356957945, 0.6123724356957946, 0.0,
                        0.0, -0.7071067811865476, 0.7071067811865475, 0.0,
                        0.0, 0.0, 0.0, 1.0))
        self.assertEqual(zx.GetXformOpOrderAttr().Get(), 
                    Vt.TokenArray(('xformOp:rotateX', 'xformOp:rotateZ')))
Пример #27
0
    def test_VaryingPrecisionOps(self):
        s = Usd.Stage.CreateInMemory()
        x1 = UsdGeom.Xform.Define(s, '/World')

        halfRotOp = x1.AddRotateXYZOp(precision=UsdGeom.XformOp.PrecisionHalf,
                                        opSuffix='Half')
        self.assertEqual(halfRotOp.GetPrecision(), UsdGeom.XformOp.PrecisionHalf)
        halfRotOp.Set(Gf.Vec3h(0.0, 0.0, 60.0))

        doubleRotOp = x1.AddRotateXYZOp(precision=UsdGeom.XformOp.PrecisionDouble,
                                        opSuffix='Double')
        self.assertEqual(doubleRotOp.GetPrecision(), UsdGeom.XformOp.PrecisionDouble)
        doubleRotOp.Set(Gf.Vec3d(0.0, 45.123456789, 0.0))

        floatRotOp = x1.AddRotateXYZOp(opSuffix='Float')
        self.assertEqual(floatRotOp.GetPrecision(), UsdGeom.XformOp.PrecisionFloat)
        floatRotOp.Set(Gf.Vec3f(30.0, 0.0, 0.0))

        self.assertEqual(x1.GetXformOpOrderAttr().Get(),
            Vt.TokenArray(('xformOp:rotateXYZ:Half',
                           'xformOp:rotateXYZ:Double', 
                           'xformOp:rotateXYZ:Float')))

        xform1 = x1.GetLocalTransformation(Usd.TimeCode.Default())

        x2 = UsdGeom.Xform.Define(s, '/World2')
        rotOp = x2.AddRotateXYZOp(precision=UsdGeom.XformOp.PrecisionDouble).Set(Gf.Vec3d(30.0, 45.123456789, 60.0))
        xform2 = x2.GetLocalTransformation(Usd.TimeCode.Default())

        # Everything gets converted to double internally, so the xforms computed 
        # must be equal.
        self.assertEqual(xform1, xform2)

        x3 = UsdGeom.Xform.Define(s, '/World3')
        quatd = Gf.Quatd(1., Gf.Vec3d(2., 3., 4.)).GetNormalized()
        quatf = Gf.Quatf(2., Gf.Vec3f(3., 4., 5.)).GetNormalized()
        quath = Gf.Quath(3., Gf.Vec3h(4., 5., 6.)).GetNormalized()

        defaultOrientOp = x3.AddOrientOp().Set(quatf)

        floatOrientOp = x3.AddOrientOp(precision=UsdGeom.XformOp.PrecisionFloat,
                                       opSuffix='Float')
        floatOrientOp.Set(quatf)

        doubleOrientOp = x3.AddOrientOp(precision=UsdGeom.XformOp.PrecisionDouble,
                                        opSuffix='Double')
        doubleOrientOp.Set(quatd)

        halfOrientOp = x3.AddOrientOp(precision=UsdGeom.XformOp.PrecisionHalf,
                                        opSuffix='Half')
        halfOrientOp.Set(quath)

        # Cannot set a quatd on an op that is of precision float.
        with self.assertRaises(RuntimeError):
            floatOrientOp.Set(quatd)

        xform3 = x3.GetLocalTransformation(Usd.TimeCode.Default())
        self._AssertCloseXf(xform3,
            Gf.Matrix4d(-0.27080552040616, -0.120257027227524, 0.955092988938746, 0,
                         0.95202181574436,  0.113459757051953, 0.284220593688289, 0,
                        -0.14254414216081,  0.986237867318078, 0.0837617848635551, 0,
                         0, 0, 0, 1))
Пример #28
0
 def RotMatrix(vec, angle):
     return Gf.Matrix4d(1.0).SetRotate(Gf.Rotation(vec, angle))
Пример #29
0
    def test_AliasedTypes(self):
        # A list of value, type and the corresponding basic type.
        validAliasValues = [
            # Color types
            (Gf.Vec3d(1, 2, 3), 'color3d', 'double3'),
            (Gf.Vec3f(1, 2, 3), 'color3f', 'float3'),
            (Gf.Vec3h(1, 2, 3), 'color3h', 'half3'),
            (Gf.Vec4d(1, 2, 3, 4), 'color4d', 'double4'),
            (Gf.Vec4f(1, 2, 3, 4), 'color4f', 'float4'),
            (Gf.Vec4h(1, 2, 3, 4), 'color4h', 'half4'),
            (Vt.Vec3dArray(), 'color3d[]', 'double3[]'),
            (Vt.Vec3fArray(), 'color3f[]', 'float3[]'),
            (Vt.Vec3hArray(), 'color3h[]', 'half3[]'),
            (Vt.Vec4dArray(), 'color4d[]', 'double4[]'),
            (Vt.Vec4fArray(), 'color4f[]', 'float4[]'),
            (Vt.Vec4hArray(), 'color4h[]', 'half4[]'),

            # Point types
            (Gf.Vec3d(1, 2, 3), 'point3d', 'double3'),
            (Gf.Vec3f(1, 2, 3), 'point3f', 'float3'),
            (Gf.Vec3h(1, 2, 3), 'point3h', 'half3'),
            (Vt.Vec3dArray(), 'point3d[]', 'double3[]'),
            (Vt.Vec3fArray(), 'point3f[]', 'float3[]'),
            (Vt.Vec3hArray(), 'point3h[]', 'half3[]'),

            # Normal types
            (Gf.Vec3d(1, 2, 3), 'normal3d', 'double3'),
            (Gf.Vec3f(1, 2, 3), 'normal3f', 'float3'),
            (Gf.Vec3h(1, 2, 3), 'normal3h', 'half3'),
            (Vt.Vec3dArray(), 'normal3d[]', 'double3[]'),
            (Vt.Vec3fArray(), 'normal3f[]', 'float3[]'),
            (Vt.Vec3hArray(), 'normal3h[]', 'half3[]'),

            # Vector types
            (Gf.Vec3d(1, 2, 3), 'vector3d', 'double3'),
            (Gf.Vec3f(1, 2, 3), 'vector3f', 'float3'),
            (Gf.Vec3h(1, 2, 3), 'vector3h', 'half3'),
            (Vt.Vec3dArray(), 'vector3d[]', 'double3[]'),
            (Vt.Vec3fArray(), 'vector3f[]', 'float3[]'),
            (Vt.Vec3hArray(), 'vector3h[]', 'half3[]'),

            # Frame type
            (Gf.Matrix4d(3), 'frame4d', 'matrix4d'),

            #Texture Coordinate type
            (Gf.Vec2d(1, 2), 'texCoord2d', 'double2'),
            (Gf.Vec2f(1, 2), 'texCoord2f', 'float2'),
            (Gf.Vec2h(1, 2), 'texCoord2h', 'half2'),
            (Gf.Vec3d(1, 2, 3), 'texCoord3d', 'double3'),
            (Gf.Vec3f(1, 2, 3), 'texCoord3f', 'float3'),
            (Gf.Vec3h(1, 2, 3), 'texCoord3h', 'half3'),
            (Vt.Vec2dArray(), 'texCoord2d[]', 'double2[]'),
            (Vt.Vec2fArray(), 'texCoord2f[]', 'float2[]'),
            (Vt.Vec2hArray(), 'texCoord2h[]', 'half2[]'),
            (Vt.Vec3dArray(), 'texCoord3d[]', 'double3[]'),
            (Vt.Vec3fArray(), 'texCoord3f[]', 'float3[]'),
            (Vt.Vec3hArray(), 'texCoord3h[]', 'half3[]')
        ]

        for value, typeName, baseTypeName in validAliasValues:
            self.assertTrue(Sdf.ValueHasValidType(value))
            self.assertEqual(Sdf.GetValueTypeNameForValue(value), baseTypeName)
            self._TestRoundTrippingValue(typeName, value)
Пример #30
0
    def test_TransformCompositionAndDecomposition(self):
        """
        Tests UsdSkelMakeTransform(), UsdSkelDecomposeTransform()
        and their array forms.
        """
        random.seed(0)

        count = 100

        # Make some random transforms.
        
        translations = RandomTranslations(count)
        rotations = RandomRotations(count)
        scales = RandomScales(count)

        xforms = UsdSkel.MakeTransforms(translations, rotations, scales)
        assert xforms

        xformsBuiltIndividually = Vt.Matrix4dArray(
            [UsdSkel.MakeTransform(translations[i], rotations[i], scales[i])
             for i in range(count)])

        self.assertArrayIsClose(xforms, xformsBuiltIndividually)

        # Decompose back into components.
        decomposedComponents = UsdSkel.DecomposeTransforms(xforms)
        assert decomposedComponents

        decomposedTranslations,_,_ = decomposedComponents

        self.assertArrayIsClose(translations, decomposedTranslations)
        
        # Make sure the non-array decomposition matches.
        for i,xf in enumerate(xforms):
            t,_,_ = UsdSkel.DecomposeTransform(xf)
            self.assertTrue(Gf.IsClose(t, translations[i],1e-5))

        # We can't really directly compare the decomposed rotations and scales
        # against the original components used to build our matrices:
        # Decomposition might produce different scales and rotations, but
        # which still give the same composed matrix result.
        # Instead, we rebuild xforms and validate that they give us the
        # xforms that the components were decomposed from.
        rebuiltXforms = UsdSkel.MakeTransforms(*decomposedComponents)
        assert rebuiltXforms

        self.assertArrayIsClose(xforms, rebuiltXforms)

        # And rebuilding each matrix individually...
        rebuiltXforms = Vt.Matrix4dArray(
            [UsdSkel.MakeTransform(*UsdSkel.DecomposeTransform(xf))
             for xf in xforms])

        self.assertArrayIsClose(xforms, rebuiltXforms)

        # Decomposing singular matrices should fail!
        with self.assertRaises(Tf.ErrorException):
            print("expect a warning about decomposing a singular matrix")
            UsdSkel.DecomposeTransform(Gf.Matrix4d(0))
        with self.assertRaises(Tf.ErrorException):
            UsdSkel.DecomposeTransforms(
                Vt.Matrix4dArray([Gf.Matrix4d(1), Gf.Matrix4d(0)]))