Пример #1
0
    def _TestPrototypes(self, instancerName):
        """
        Tests that all of the instancer prototypes made it to USD.
        """
        self.assertTrue(self.stage)
        instancer = OMFX.MFnInstancer(self._GetDagPath(instancerName))

        # Move to the last frame so that we can ensure all of the prototypes
        # are in use.
        cmds.currentTime(self.END_TIMECODE, edit=True)
        paths = OM.MDagPathArray()
        matrices = OM.MMatrixArray()
        particlePathStartIndices = OM.MIntArray()
        pathIndices = OM.MIntArray()
        instancer.allInstances(paths, matrices, particlePathStartIndices,
                               pathIndices)

        # Check that the Maya instanced objects are what we think they are.
        pathStrings = [paths[i].fullPathName() for i in range(paths.length())]
        self.assertEqual(
            pathStrings,
            [
                # 0 (logical 0) - Cube
                "|dummyGroup|pCube1|pCubeShape1",
                "|dummyGroup|pCube1|pSphere1|pSphereShape1",
                # 1 (logical 2) - Sphere
                "|InstancerTest|%s|prototypeUnderInstancer|prototypeUnderInstancerShape"
                % instancerName,
                # 2 (logical 3) - Reference
                "|referencePrototype|NS_referencePrototype:Geom|NS_referencePrototype:Cone|NS_referencePrototype:ConeShape"
            ])

        # Check that the USD prims have correct type name, references, kinds,
        # kinds, instancerTranslate xformOps.
        instancerPrim = self.stage.GetPrimAtPath("/InstancerTest/%s" %
                                                 instancerName)
        self.assertEqual(
            Usd.ModelAPI(instancerPrim).GetKind(), Kind.Tokens.subcomponent)

        prototypesPrim = instancerPrim.GetChild("Prototypes")
        self.assertEqual(len(prototypesPrim.GetChildren()), 3)
        self.assertEqual(
            Usd.ModelAPI(prototypesPrim).GetKind(), Kind.Tokens.subcomponent)

        # Note that pCube1_0 is a special case where instancerTranslate
        # isn't the opposite of translate, so both have to be left in.
        prototype0 = prototypesPrim.GetChild("pCube1_0")
        self._AssertPrototype(prototype0, "Xform", 2, True)

        prototype1 = prototypesPrim.GetChild("prototypeUnderInstancer_1")
        self._AssertPrototype(prototype1, "Mesh", 0, False)

        prototype2 = prototypesPrim.GetChild("referencePrototype_2")
        self._AssertPrototype(prototype2, "Xform", 1, False)
        self.assertEqual(
            Usd.ModelAPI(prototype2).GetAssetName(), "ConeAssetName")
Пример #2
0
    def testTransforms(self):
        """
        Check that the point transforms are correct.
        """
        mayaInstancer = OMFX.MFnInstancer(self._GetDagPath("instancer1"))
        usdInstancer = UsdGeom.PointInstancer(
            self.stage.GetPrimAtPath("/InstancerTest/instancer1"))

        time = self.START_TIMECODE
        while time <= self.END_TIMECODE:
            cmds.currentTime(time, edit=True)

            # Need to do this because MFnInstancer will give instance matrices
            # as offsets from prototypes' original world space positions.
            worldPositions = [
                self._GetWorldSpacePosition("|dummyGroup|pCube1"),
                self._GetWorldSpacePosition(
                    "|InstancerTest|instancer1|prototypeUnderInstancer"),
                self._GetWorldSpacePosition("|referencePrototype")
            ]

            paths = OM.MDagPathArray()
            matrices = OM.MMatrixArray()
            particlePathStartIndices = OM.MIntArray()
            pathIndices = OM.MIntArray()
            mayaInstancer.allInstances(paths, matrices,
                                       particlePathStartIndices, pathIndices)

            usdInstanceTransforms = \
                    usdInstancer.ComputeInstanceTransformsAtTime(time, time)
            usdProtoIndices = usdInstancer.GetProtoIndicesAttr().Get(time)

            self.assertEqual(matrices.length(), len(usdInstanceTransforms))

            # Compute the instancer-space position of instances in Maya
            # (including the protos' transforms). By default, this is what
            # UsdGeomPointInstancer::ComputeInstanceTransformsAtTime already
            # gives us.
            mayaWorldPositions = [
                worldPositions[protoIndex] for protoIndex in usdProtoIndices
            ]
            mayaGfMatrices = [
                mayaWorldPositions[i] * self._MayaToGfMatrix(matrices[i])
                for i in xrange(matrices.length())
            ]
            usdGfMatrices = [
                usdInstanceTransforms[i]
                for i in xrange(len(usdInstanceTransforms))
            ]
            for i in xrange(len(usdGfMatrices)):
                self._AssertXformMatrices(mayaGfMatrices[i], usdGfMatrices[i])

            time += 1.0
Пример #3
0
    def testInstancePaths(self):
        """
        Checks that the proto index assigned for each point is correct.
        """
        mayaInstancer = OMFX.MFnInstancer(self._GetDagPath("instancer1"))
        usdInstancer = UsdGeom.PointInstancer(
            self.stage.GetPrimAtPath("/InstancerTest/instancer1"))

        time = self.START_TIMECODE
        while time <= self.END_TIMECODE:
            cmds.currentTime(time, edit=True)

            paths = OM.MDagPathArray()
            matrices = OM.MMatrixArray()
            particlePathStartIndices = OM.MIntArray()
            pathIndices = OM.MIntArray()
            mayaInstancer.allInstances(paths, matrices,
                                       particlePathStartIndices, pathIndices)
            usdProtoIndices = usdInstancer.GetProtoIndicesAttr().Get(time)

            # Mapping of proto index to index(es) in the paths array.
            # Note that in the Maya instancer a single point may map to multiple
            # DAG paths, which correspond to all the shapes in the instanced
            # hierarchy.
            usdIndicesToMayaIndices = {
                0: [0, 1],  # the first prototype has two shapes in hierarchy
                1: [2],  # this prototype only has one shape
                2: [3],  # the reference prototype only has one shape
            }

            for i in xrange(len(usdProtoIndices)):
                usdProtoIndex = usdProtoIndices[i]
                expectedMayaIndices = usdIndicesToMayaIndices[usdProtoIndex]

                mayaIndicesStart = particlePathStartIndices[i]
                mayaIndicesEnd = particlePathStartIndices[i + 1]

                self.assertEqual(mayaIndicesEnd - mayaIndicesStart,
                                 len(expectedMayaIndices))
                actualPathIndices = [
                    pathIndices[i]
                    for i in xrange(mayaIndicesStart, mayaIndicesEnd)
                ]
                self.assertEqual(actualPathIndices, expectedMayaIndices)

            time += 1.0
Пример #4
0
def bake(instancerName, start, end, progress=None):
    """
    Process an instancer node over the specified frame range, reading the 
    positions and objects. With this data objects are duplicated and 
    positioned to mimic the instancer. With the particle data individual 
    objects can be matched over the different frames and animated. When
    a particle "dies", the visibility is turned off.

    :param str instancerName: Name if the instancer to bake
    :param int start: Start frame
    :param int end: End frame
    :param QProgressBar progress: Update ui ( Optional )
    :return: Group that contains all of the baked information
    :rtype: str
    :raises RuntimeError: When the instancer doesn't exist
    :raises RuntimeError: When there are no particles attached
    """
    # store all particle information in data variable
    data = {}

    # get instance
    if not cmds.objExists(instancerName):
        raise RuntimeError("Instancer doesn't exist!")
        return

    # set visible
    cmds.setAttr("{0}.visibility".format(instancerName), 1)

    instancerObj = asMObject(instancerName)
    instancerDag = asMDagPath(instancerObj)
    instancer = OpenMayaFX.MFnInstancer(instancerDag)

    # get particles
    particleName = cmds.listConnections(
        "{0}.inputPoints".format(instancerName))
    if not particleName:
        raise RuntimeError("No particles connected!")
        return

    particleName = particleName[0]
    particleObj = asMObject(particleName)
    particleDag = asMDagPath(particleObj)
    particle = OpenMayaFX.MFnParticleSystem(particleDag)

    # variables
    ages = OpenMaya.MDoubleArray()
    paths = OpenMaya.MDagPathArray()
    matrices = OpenMaya.MMatrixArray()
    particleIndices = OpenMaya.MIntArray()
    pathIndices = OpenMaya.MIntArray()

    # create container group
    container = cmds.group(world=True,
                           empty=True,
                           n="{0}_bake_1".format(instancerName))

    # loop time
    for i in range(start, end + 1):
        # set time
        cmds.currentTime(i)

        # query instancer information
        instancer.allInstances(paths, matrices, particleIndices, pathIndices)

        # query particle information
        particle.age(ages)

        # loop particle instances
        num = matrices.length()
        for j in range(num):
            # get particles index
            p = particleIndices[j]

            # get parent
            parent = paths[pathIndices[j]].fullPathName()

            # get age
            age = ages[j]

            if data.get(p):
                # get path and age
                path = data[p].get("path")

                oldAge = data[p].get("age")
                oldParent = data[p].get("parent")

                # check if age is less than previous
                if age < oldAge:
                    # hide mesh and delete particle id data
                    keyVisibility(path, i, 0)
                    del (data[p])

                # check if parent is the same as previous
                elif parent != oldParent:
                    # hide mesh and delete particle id data
                    keyVisibility(path, i, 0)
                    del (data[p])

            # duplicate path if index not in data
            if not data.get(p):
                # get parent name
                parentShort = parent.split("|")[-1].split(":")[-1]

                # duplicate mesh
                name = "{0}_{1}_1".format(instancerName, parentShort)
                path = cmds.duplicate(parent, n=name)[0]
                path = cmds.parent(path, container)[0]

                # handle visibility
                keyVisibility(path, i, 1)

                # get dag
                dag = asMDagPath(asMObject(path))

                # get matrix
                transform = asMFnTransform(dag)
                matrix = transform.transformation().asMatrix()

                # store variables
                data[p] = {}
                data[p]["path"] = path
                data[p]["dag"] = dag
                data[p]["matrix"] = matrix
                data[p]["parent"] = parent

            # get variables
            path = data[p].get("path")
            dag = data[p].get("dag")
            matrix = data[p].get("matrix")

            # store age
            data[p]["age"] = age

            # set matrix
            m = matrix * matrices[j]
            m = OpenMaya.MTransformationMatrix(m)

            transform = asMFnTransform(dag)
            transform.set(m)

            # set keyframes
            keyTransform(path, i)

        # update progress
        if progress:
            progress.setValue(i + 1 - start)

    return container