- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Examples

# rockingTransform.py

    #-
    # ==========================================================================
    # Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All
    # rights reserved.
    #
    # The coded instructions, statements, computer programs, and/or related
    # material (collectively the "Data") in these files contain unpublished
    # information proprietary to Autodesk, Inc. ("Autodesk") and/or its
    # licensors, which is protected by U.S. and Canadian federal copyright
    # law and by international treaties.
    #
    # The Data is provided for use exclusively by You. You have the right
    # to use, modify, and incorporate this Data into other products for
    # purposes authorized by the Autodesk software license agreement,
    # without fee.
    #
    # The copyright notices in the Software and this entire statement,
    # including the above license grant, this restriction and the
    # following disclaimer, must be included in all copies of the
    # Software, in whole or in part, and all derivative works of
    # the Software, unless such copies or derivative works are solely
    # in the form of machine-executable object code generated by a
    # source language processor.
    #
    # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
    # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
    # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
    # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
    # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
    # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
    # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
    # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
    # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
    # OR PROBABILITY OF SUCH DAMAGES.
    #
    # ==========================================================================
    #+

    # This plug-in implements an example custom transform that
    # can be used to perform a rocking motion around the X axix.
    # Geometry of any rotation can be made a child of this transform
    # to demonstrate the effect.
    # The plug-in contains two pieces:
    # 1. The custom transform node -- rockingTransformNode
    # 2. The custom transformation matrix -- rockingTransformMatrix
    # These classes are used together in order to implement the
    # rocking motion.  Note that the rock attribute is stored outside
    # of the regular transform attributes.

    # Usage:
    # import maya.cmds
    # maya.cmds.loadPlugin("rockingTransform.py")
    # maya.cmds.file(f=True,new=True)
    # maya.cmds.polyPlane()
    # maya.cmds.select("pPlane1",r=True)
    # maya.cmds.rotate(-15,-15,-15,r=True,ws=True)
    # maya.cmds.createNode("spRockingTransform")
    # maya.cmds.parent("pPlane1","spRockingTransform1")
    # maya.cmds.setAttr("spRockingTransform1.rockx",55)
    #

    import maya.OpenMaya as OpenMaya
    import maya.OpenMayaMPx as OpenMayaMPx
    import math
    import sys

    kRockingTransformPluginName = "spRockingTransform"
    kRockingTransformNodeName = "spRockingTransformNode"
    kRockingTransformNodeID = OpenMaya.MTypeId(0x87014)
    kRockingTransformMatrixID = OpenMaya.MTypeId(0x87015)

    # keep track of instances of rockingTransformMatrix to get around script limitation
    # with proxy classes of base pointers that actually point to derived
    # classes
    kTrackingDictionary = {}

    class rockingTransformMatrix(OpenMayaMPx.MPxTransformationMatrix):

        def __init__(self):
            OpenMayaMPx.MPxTransformationMatrix.__init__(self)
            kTrackingDictionary[OpenMayaMPx.asHashable(self)] = self
            self.rockXValue = 0.0

        def __del__(self):
            del kTrackingDictionary[OpenMayaMPx.asHashable(self)]

        def setRockInX(self,rockingValue):
            self.rockXValue = rockingValue

        def getRockInX(self):
            return self.rockXValue

        def asMatrix(self,percent=None):
            """
            Find the new matrix and return it
            """
            if percent == None:
                matrix = OpenMayaMPx.MPxTransformationMatrix.asMatrix(self)
                tm = OpenMaya.MTransformationMatrix(matrix)
                quat = self.rotation()
                rockingValue = self.getRockInX()
                newTheta = math.radians( rockingValue )
                quat.setToXAxis( newTheta )
                tm.addRotationQuaternion( quat.x, quat.y, quat.z, quat.w, OpenMaya.MSpace.kTransform )
                return tm.asMatrix()
            else:
                m = OpenMayaMPx.MPxTransformationMatrix(self)
                #
                trans = m.translation()
                rotatePivotTrans = m.rotatePivot()
                scalePivotTrans = m.scalePivotTranslation()
                trans = trans * percent
                rotatePivotTrans = rotatePivotTrans * percent
                scalePivotTrans = scalePivotTrans * percent
                m.translateTo(trans)
                m.setRotatePivot( rotatePivotTrans )
                m.setScalePivotTranslation( scalePivotTrans )
                #
                quat = self.rotation()
                rockingValue = self.getRockInX()
                newTheta = math.radians( rockingValue )

                quat.setToXAxis( newTheta )
                m.rotateBy( quat )
                eulerRotate = m.eulerRotation()
                m.rotateTo( eulerRotate * percent, OpenMaya.MSpace.kTransform )
                #
                s = self.scale( OpenMaya.MSpace.kTransform )
                s.x = 1.0 + ( s.x - 1.0 ) * percent
                s.y = 1.0 + ( s.y - 1.0 ) * percent
                s.z = 1.0 + ( s.z - 1.0 ) * percent
                m.scaleTo( s, OpenMaya.MSpace.kTransform )
                #
                return m.asMatrix()

    class rockingTransformNode(OpenMayaMPx.MPxTransform):
        aRockInX = OpenMaya.MObject()

        def __init__(self, transform=None):
            if transform is None:
                OpenMayaMPx.MPxTransform.__init__(self)
            else:
                OpenMayaMPx.MPxTransform.__init__(self, transform)
            self.rockXValue = 0.0

        def createTransformationMatrix(self):
            return OpenMayaMPx.asMPxPtr( rockingTransformMatrix() )

        def className(self):
            return kRockingTransformNodeName

        #
        def validateAndSetValue(self, plug, handle, context):
            if not plug.isNull():
                block = self._forceCache(context)
                blockHandle = block.outputValue(plug)

                if plug == self.aRockInX:
                    # Update our new rock in x value
                    rockInX = handle.asDouble()
                    blockHandle.setDouble(rockInX)

                    # Update the custom transformation matrix to the
                    # right value.
                    ltm = self.getRockingTransformationMatrix()
                    if ltm is not None:
                        ltm.setRockInX(rockInX)

                    blockHandle.setClean()

                    # Mark the matrix as dirty so that DG information
                    # will update.
                    self._dirtyMatrix()

            OpenMayaMPx.MPxTransform.validateAndSetValue(self, plug, handle, context)

        def getRockingTransformationMatrix(self):
            baseXform = self.transformationMatrixPtr()
            return kTrackingDictionary[OpenMayaMPx.asHashable(baseXform)]

    # create/initialize node and matrix
    def matrixCreator():
        return OpenMayaMPx.asMPxPtr( rockingTransformMatrix() )

    def nodeCreator():
        return OpenMayaMPx.asMPxPtr( rockingTransformNode() )

    def nodeInitializer():
        numFn = OpenMaya.MFnNumericAttribute()

        rockingTransformNode.aRockInX = numFn.create("RockInX", "rockx", OpenMaya.MFnNumericData.kDouble, 0.0)

        numFn.setKeyable(True)
        numFn.setAffectsWorldSpace(True)

        rockingTransformNode.addAttribute(rockingTransformNode.aRockInX)
        rockingTransformNode.mustCallValidateAndSet(rockingTransformNode.aRockInX)
        return

    # initialize the script plug-in
    def initializePlugin(mobject):
        mplugin = OpenMayaMPx.MFnPlugin(mobject)

        try:
            mplugin.registerTransform( kRockingTransformPluginName, kRockingTransformNodeID, \
                                    nodeCreator, nodeInitializer, matrixCreator, kRockingTransformMatrixID )
        except:
            sys.stderr.write( "Failed to register transform: %s\n" % kRockingTransformPluginName )
            raise

    # uninitialize the script plug-in
    def uninitializePlugin(mobject):
        mplugin = OpenMayaMPx.MFnPlugin(mobject)

        try:
            mplugin.deregisterNode( kRockingTransformNodeID )
        except:
            sys.stderr.write( "Failed to unregister node: %s\n" % kRockingTransformPluginName )
            raise