Example: Using Time to Animate a Cube Mesh

Example: Using Time to Animate a Cube Mesh

Filename: animCubeNode.py

Annotated Output: The dotted arrows in the image below point to the rear and bottom polygons of the cube, while the full arrows point to its forward and top polygons. The table which accompanies this image illustrates the various array parameters used in MFnMesh.create().

Program Summary: The plug-in code below is an adaptation of the animCubeNode.py example provided with the Maya API documentation. Some variable names were refactored to be more closely aligned with the class documentation and annotated output above. This MPxNode plug-in defines a typed input attribute which accepts Maya's time to determine the scale of the generated output cube mesh. Once this command is run, slide the timeline in the Maya user interface to view the animation.

NOTE:The way in which this cubic mesh is constructed is also used in Example: Voxelizer Node to create voxels.
Python API 2.0:
# pyAnimCubeNode.py

import sys
import maya.api.OpenMaya as OpenMaya

def maya_useNewAPI():
	"""
	The presence of this function tells Maya that the plugin produces, and
	expects to be passed, objects created using the Maya Python API 2.0.
	"""
	pass
	
kPluginNodeName = "spAnimCube"
kPluginNodeId = OpenMaya.MTypeId(0x8700B)

##########################################################
# Plug-in 
##########################################################
class animCube(OpenMaya.MPxNode):
    time = OpenMaya.MObject()
    outputMesh = OpenMaya.MObject()

    
    def __init__(self):
        ''' Constructor. '''
        OpenMaya.MPxNode.__init__(self)
    
    
    def createMesh(self, tempTime, outData):
        ''' 
        Create a cube mesh, and scale it given the current frame number. 
        The resulting mesh data is stored within outData.
        '''
        
        frame = int(tempTime.asUnits(OpenMaya.MTime.kFilm))
        if frame is 0:
            frame = 1

        cubeSize = 0.5 * float(frame % 10)

        numPolygons = 6
        numVertices = 8
        numPolygonConnects = 4 * numPolygons # four vertices are needed per polygon. (i.e. 24 numPolygonConnects)

        vertexArray = OpenMaya.MFloatPointArray()
        vertexArray.setLength( numVertices )
        vertexArray[0] = OpenMaya.MFloatPoint(-cubeSize, -cubeSize, -cubeSize)
        vertexArray[1] = OpenMaya.MFloatPoint( cubeSize, -cubeSize, -cubeSize)
        vertexArray[2] = OpenMaya.MFloatPoint( cubeSize, -cubeSize,  cubeSize)
        vertexArray[3] = OpenMaya.MFloatPoint(-cubeSize, -cubeSize,  cubeSize)
        vertexArray[4] = OpenMaya.MFloatPoint(-cubeSize,  cubeSize, -cubeSize)
        vertexArray[5] = OpenMaya.MFloatPoint(-cubeSize,  cubeSize,  cubeSize)
        vertexArray[6] = OpenMaya.MFloatPoint( cubeSize,  cubeSize,  cubeSize)
        vertexArray[7] = OpenMaya.MFloatPoint( cubeSize,  cubeSize, -cubeSize)
        
        polygonCounts = OpenMaya.MIntArray()
        polygonCounts.setLength( numPolygons )
        for i in range (0,numPolygons):
            polygonCounts[i] = 4

        
        polygonConnects = OpenMaya.MIntArray()
        polygonConnects.setLength( numPolygonConnects )
        polygonConnects[0] = 0
        polygonConnects[1] = 1
        polygonConnects[2] = 2
        polygonConnects[3] = 3
        polygonConnects[4] = 4
        polygonConnects[5] = 5
        polygonConnects[6] = 6
        polygonConnects[7] = 7
        polygonConnects[8] = 3
        polygonConnects[9] = 2
        polygonConnects[10] = 6
        polygonConnects[11] = 5
        polygonConnects[12] = 0
        polygonConnects[13] = 3
        polygonConnects[14] = 5
        polygonConnects[15] = 4
        polygonConnects[16] = 0
        polygonConnects[17] = 4
        polygonConnects[18] = 7
        polygonConnects[19] = 1
        polygonConnects[20] = 1
        polygonConnects[21] = 7
        polygonConnects[22] = 6
        polygonConnects[23] = 2

        meshFn = OpenMaya.MFnMesh()
        newMesh = meshFn.create(vertexArray, polygonCounts, polygonConnects, parent=outData)
        

    def compute(self, plug, data):
        if plug == animCube.outputMesh:
            timeData = data.inputValue(animCube.time)
            tempTime = timeData.asTime()

            outputHandle = data.outputValue(animCube.outputMesh)

            dataCreator = OpenMaya.MFnMeshData()
            newOutputData = dataCreator.create()

            self.createMesh(tempTime, newOutputData)

            outputHandle.setMObject(newOutputData)
            data.setClean(plug)
        else:
            return OpenMaya.kUnknownParameter
        
##########################################################
# Plug-in initialization.
##########################################################
def nodeCreator():
    ''' Creates an instance of our node class and delivers it to Maya as a pointer. '''
    return animCube()

def nodeInitializer():
    ''' Defines the input and output attributes as static variables in our plug-in class. '''
    unitAttr = OpenMaya.MFnUnitAttribute()
    typedAttr = OpenMaya.MFnTypedAttribute()
    
    animCube.time = unitAttr.create("time", "tm", OpenMaya.MFnUnitAttribute.kTime, 0.0)
    animCube.outputMesh = typedAttr.create("outputMesh", "out", OpenMaya.MFnData.kMesh)

    animCube.addAttribute(animCube.time)
    animCube.addAttribute(animCube.outputMesh)

    animCube.attributeAffects(animCube.time, animCube.outputMesh)


def initializePlugin(mobject):
    ''' Initialize the plug-in '''
    mplugin = OpenMaya.MFnPlugin(mobject)
    try:
        mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer)
    except:
        sys.stderr.write( "Failed to register node: " + kPluginNodeName )
        raise

def uninitializePlugin(mobject):
    ''' Uninitializes the plug-in '''
    mplugin = OpenMaya.MFnPlugin(mobject)
    try:
        mplugin.deregisterNode( kPluginNodeId )
    except:
        sys.stderr.write( "Failed to deregister node: " + kPluginNodeName )
        raise

##########################################################
# Sample usage.
##########################################################
''' 
# Copy the following lines and run them in Maya's Python Script Editor:

import maya.cmds as cmds
cmds.loadPlugin( "pyAnimCubeNode.py" )
cmds.createNode( "transform", name="animCube1" )
cmds.createNode( "mesh", name="animCubeShape1", parent="animCube1" )
cmds.sets( "animCubeShape1", add="initialShadingGroup" )
cmds.createNode( "spAnimCube", name="animCubeNode1" )
cmds.connectAttr( "time1.outTime", "animCubeNode1.time" )
cmds.connectAttr( "animCubeNode1.outputMesh", "animCubeShape1.inMesh" )

'''
Python API 1.0:
# animCubeNode.py

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

kPluginNodeName = "spAnimCube"
kPluginNodeId = OpenMaya.MTypeId(0x8700B)

##########################################################
# Plug-in 
##########################################################
class animCube(OpenMayaMPx.MPxNode):
    time = OpenMaya.MObject()
    outputMesh = OpenMaya.MObject()

    
    def __init__(self):
        ''' Constructor. '''
        OpenMayaMPx.MPxNode.__init__(self)
    
    
    def createMesh(self, tempTime, outData):
        ''' 
        Create a cube mesh, and scale it given the current frame number. 
        The resulting mesh data is stored within outData.
        '''
        
        frame = int(tempTime.asUnits(OpenMaya.MTime.kFilm))
        if frame is 0:
            frame = 1

        cubeSize = 0.5 * float(frame % 10)

        numPolygons = 6
        numVertices = 8
        numPolygonConnects = 4 * numPolygons # four vertices are needed per polygon. (i.e. 24 numPolygonConnects)

        vertexArray = OpenMaya.MFloatPointArray()
        vertexArray.setLength( numVertices )
        vertexArray.set( OpenMaya.MFloatPoint(-cubeSize, -cubeSize, -cubeSize), 0)
        vertexArray.set( OpenMaya.MFloatPoint( cubeSize, -cubeSize, -cubeSize), 1)
        vertexArray.set( OpenMaya.MFloatPoint( cubeSize, -cubeSize,  cubeSize), 2)
        vertexArray.set( OpenMaya.MFloatPoint(-cubeSize, -cubeSize,  cubeSize), 3)
        vertexArray.set( OpenMaya.MFloatPoint(-cubeSize,  cubeSize, -cubeSize), 4)
        vertexArray.set( OpenMaya.MFloatPoint(-cubeSize,  cubeSize,  cubeSize), 5)
        vertexArray.set( OpenMaya.MFloatPoint( cubeSize,  cubeSize,  cubeSize), 6)
        vertexArray.set( OpenMaya.MFloatPoint( cubeSize,  cubeSize, -cubeSize), 7)
        
        polygonCounts = OpenMaya.MIntArray()
        polygonCounts.setLength( numPolygons )
        polygonCounts.set(4, 0)
        polygonCounts.set(4, 1)
        polygonCounts.set(4, 2)
        polygonCounts.set(4, 3)
        polygonCounts.set(4, 4)
        polygonCounts.set(4, 5)
        
        polygonConnects = OpenMaya.MIntArray()
        polygonConnects.setLength( numPolygonConnects )
        polygonConnects.set(0, 0)
        polygonConnects.set(1, 1)
        polygonConnects.set(2, 2)
        polygonConnects.set(3, 3)
        polygonConnects.set(4, 4)
        polygonConnects.set(5, 5)
        polygonConnects.set(6, 6)
        polygonConnects.set(7, 7)
        polygonConnects.set(3, 8)
        polygonConnects.set(2, 9)
        polygonConnects.set(6, 10)
        polygonConnects.set(5, 11)
        polygonConnects.set(0, 12)
        polygonConnects.set(3, 13)
        polygonConnects.set(5, 14)
        polygonConnects.set(4, 15)
        polygonConnects.set(0, 16)
        polygonConnects.set(4, 17)
        polygonConnects.set(7, 18)
        polygonConnects.set(1, 19)
        polygonConnects.set(1, 20)
        polygonConnects.set(7, 21)
        polygonConnects.set(6, 22)
        polygonConnects.set(2, 23)

        meshFn = OpenMaya.MFnMesh()
        newMesh = meshFn.create(numVertices, numPolygons, vertexArray, polygonCounts, polygonConnects, outData)

    def compute(self, plug, data):
        if plug == animCube.outputMesh:
            timeData = data.inputValue(animCube.time)
            tempTime = timeData.asTime()

            outputHandle = data.outputValue(animCube.outputMesh)

            dataCreator = OpenMaya.MFnMeshData()
            newOutputData = dataCreator.create()

            self.createMesh(tempTime, newOutputData)

            outputHandle.setMObject(newOutputData)
            data.setClean(plug)
        else:
            return OpenMaya.kUnknownParameter
        
##########################################################
# Plug-in initialization.
##########################################################
def nodeCreator():
    ''' Creates an instance of our node class and delivers it to Maya as a pointer. '''
    return OpenMayaMPx.asMPxPtr( animCube() )

def nodeInitializer():
    ''' Defines the input and output attributes as static variables in our plug-in class. '''
    unitAttr = OpenMaya.MFnUnitAttribute()
    typedAttr = OpenMaya.MFnTypedAttribute()
    
    animCube.time = unitAttr.create("time", "tm", OpenMaya.MFnUnitAttribute.kTime, 0.0)
    animCube.outputMesh = typedAttr.create("outputMesh", "out", OpenMaya.MFnData.kMesh)

    animCube.addAttribute(animCube.time)
    animCube.addAttribute(animCube.outputMesh)

    animCube.attributeAffects(animCube.time, animCube.outputMesh)


def initializePlugin(mobject):
    ''' Initialize the plug-in '''
    mplugin = OpenMayaMPx.MFnPlugin(mobject)
    try:
        mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer)
    except:
        sys.stderr.write( "Failed to register node: " + kPluginNodeName )
        raise

def uninitializePlugin(mobject):
    ''' Uninitializes the plug-in '''
    mplugin = OpenMayaMPx.MFnPlugin(mobject)
    try:
        mplugin.deregisterNode( kPluginNodeId )
    except:
        sys.stderr.write( "Failed to deregister node: " + kPluginNodeName )
        raise

##########################################################
# Sample usage.
##########################################################
''' 
# Copy the following lines and run them in Maya's Python Script Editor:

import maya.cmds as cmds
cmds.loadPlugin( "animCubeNode.py" )
cmds.createNode( "transform", name="animCube1" )
cmds.createNode( "mesh", name="animCubeShape1", parent="animCube1" )
cmds.sets( "animCubeShape1", add="initialShadingGroup" )
cmds.createNode( "spAnimCube", name="animCubeNode1" )
cmds.connectAttr( "time1.outTime", "animCubeNode1.time" )
cmds.connectAttr( "animCubeNode1.outputMesh", "animCubeShape1.inMesh" )

'''