Maya Python API Undo/Redo callback

#Description:
#Create a undo/redo callback using maya python api
#Usage:
#Call the undoRedoCallback function with "add" to create the undo/redo callbacks. Or call the
#undoRedoCallback function with "remove" as argument to remove the created callbacks.
#
#Info:
#Reference from undoRedoMsgCmd.cpp exemple
#By Rosenio Pinto
#kenio3d@gmail.com

import maya.OpenMaya as om

def undoTest(*args):
    print 'Checking Undo callback'

def redoTest(*args):
    print 'Checking ReDo callback'

def undoRedoCallback(arg):
    global callbackIDs

    undoStr = str('Undo')
    redoStr = str('Redo')
    Null = om.MObject()

    if arg == 'add':

        undoID = om.MEventMessage.addEventCallback(undoStr, undoTest, Null)
        redoID = om.MEventMessage.addEventCallback(redoStr, redoTest, Null)

        callbackIDs = [undoID, redoID]

    elif arg == 'remove':
        try:
            for i in callbackIDs:
                om.MEventMessage.removeCallback(i)
        except:
            print 'There is no ID to delete'

    else:
        print 'The argument must be "add" or "remove"'

            

Maya Python MNodeMessage sample

This is a simple example of the MNodeMessage usage.

import maya.cmds as cmds
import maya.OpenMaya as om

#Ref http://pastebin.com/mntSGhex

cmds.polySphere()
cmds.select('polySphere1')

def changed_radius( msg, mplug, otherMplug, clientData):
    nodeName, attrName = mplug.name().split('.')
    #if msg & om.MNodeMessage.kAttributeSet:
    if msg == 2056:
        if nodeName == 'polySphere1':
            if attrName == 'radius':
                print "Radius Changed"
                rd = cmds.getAttr('polySphere1.radius')
                cmds.setAttr('polySphere1.subdivisionsAxis', rd*3)

def getNode():
    #Get the node as MObject and set the id message
    MSelectionList = om.MSelectionList()
    om.MGlobal.getActiveSelectionList(MSelectionList)
    node = om.MObject()
    MSelectionList.getDependNode(0, node)
    clientData = None
    id = om.MNodeMessage.addAttributeChangedCallback(node, changed_radius,clientData)

getNode()

            

zenno extra control

This script creates a extra control for facial rig and other specific stuff.
I’m using softmod node to do the deformation.

zennoJointReflect

Just a tool that mirror and orient the joint in time creation. It is a base for other tool I’m developing.

zennoMPath node

This is a demonstration of my multi motion path node. It consists in manage objects in a path curve at once. I still need to do some improvements. Any sugestion or question, send me a message kenio3d@gmail.com…

I also used my zennoRamp and zennoTwist node in conjunction to zennoMPath to get the behavior shown below.

zennoMPath hypergraph

Reference material:

http://ewertb.soundlinker.com/mel/mel.105.php

http://www.rtrowbridge.com/blog/2009/02/python-api-mtransformationmatrixgetrotation-bug/

Thanks my friends!

rp_sensor v1.0

Updated!
A custom python plugin for maya. I’ll use this plugins for calculate aproximation, and trigger some other nodes like corretive blendshapes, LOD calculations, etc…Now with fallOff!.

rp_sensor

A custom python plugin for maya. I’ll use this plugins for calculate aproximation, and trigger some other nodes like corretive blendshapes…

Normal Check

##
##
#Description: Help to check of the normals direction of the selected objects.
#Usage:
#from rpNormal import *
#winNormCheck()
#Any questions you can ask me on kenio3d@gmail.com

import maya.cmds as cmds

def checkNorm():
    global count
    global sel
    if count == 0:
        sel = cmds.ls(sl=True)
    else:
        pass

    if count >= len(sel):
        cmds.select(sel)
        cmds.FrameSelected()
        cmds.isolateSelect('modelPanel4', s=0)
        cmds.ToggleFaceNormalDisplay()
        cmds.deleteUI('winNormCheck')
        cmds.refresh()

    else:
        cmds.select(sel[count])
        cmds.polyNormal(nm=2, ch=False)
        cmds.ToggleFaceNormalDisplay()
        cmds.SelectIsolate()
        cmds.FrameSelected()
        count = count+1
        print '%s'%count+' of '+'%s'%len(sel)

def reverseDef():
    cmds.polyNormal(nm=0, ch=False)
    checkNorm()

def winNormCheck():
    global count
    count = 0
    if cmds.window('winNormCheck', ex=True):
        cmds.deleteUI('winNormCheck')
    else:
        winNormCheck = cmds.window('winNormCheck', title='winNormCheck')
        cmds.rowLayout( numberOfColumns=3, columnWidth3=(80, 80, 80), adjustableColumn=2, columnAlign=(1, 'right'), columnAttach=[(1, 'both', 0), (2, 'both', 0), (3, 'both', 0)] )
        cmds.button(l='Next', command='checkNorm()')
        cmds.button(l='Reverse', command='reverseDef()')
        cmds.button(l='FaceNormals', command='cmds.ToggleFaceNormalDisplay()')
        cmds.showWindow(winNormCheck)
##
##

Get rotation from tangent information…motionPath like

I’m meking a test for a custom node thats take the tangent, normal and binormal and transform in rotation information…This code is only for analysis…
Thanks for Fernando Soares and Richard Kazuo for the suport!

##
##
import maya.cmds as cmds
import maya.OpenMaya as om
import math as math

def tanCons(upVec, frontAxis, par):
    sel = cmds.ls(sl=True)
    curveObj = sel[0]
    obj = sel[1]

    #Ensure a valid up-vector. Use Y-up as default if input is bogus.
    if upVec.length() < 0.001:
        upVec = om.MVector(0.0, 1.0, 0.0)

    #Ensure up-vector is normalized.
    upVec.normalize()

    #Query the position and tangent
    p = cmds.pointOnCurve(curveObj, ch=False, top=True, pr=par, p=True)
    t = cmds.pointOnCurve(curveObj, ch=False, top=True, pr=par, nt=True)

    tan = om.MVector(t[0], t[1], t[2])
    tan.normalize()

    #Calculate a normal using the Y-up vector as the binormal.
    norm = tan^upVec

    #Calculate the orthogonal binormal.
    bi = tan^norm

    #If the binormal is pointing the wrong way,
    #negate it and the normal.
    if upVec*bi < 0.0:
        bi = -bi
        norm = -norm

    #Normalize our vector.
    norm.normalize()
    bi.normalize()

    #Create a matrix, using normal for the X axis and
    #tangent for the Z axis.
    if frontAxis == (1,0,0):
        m = [(tan.x, tan.y, tan.z, 0.0), # X axis
            (bi.x, bi.y, bi.z, 0.0),# Y axis
            (norm.x, norm.y, norm.z, 0.0),# Z axis
            (p[0], p[1], p[2], 1.0)]
    elif frontAxis == (0,1,0):
        m = [(norm.x, norm.y, norm.z, 0.0), # X axis
            (tan.x, tan.y, tan.z, 0.0),# Y axis
            (bi.x, bi.y, bi.z, 0.0),# Z axis
            (p[0], p[1], p[2], 1.0)]
    else:
        m = [(norm.x, norm.y, norm.z, 0.0), # X axis
            (bi.x, bi.y, bi.z, 0.0),# Y axis
            (tan.x, tan.y, tan.z, 0.0),# Z axis
            (p[0], p[1], p[2], 1.0)]

    cmds.xform(obj, ws=True, m=((m[0][0], m[0][1], m[0][2], m[0][3],
                            m[1][0], m[1][1], m[1][2], m[1][3],
                            m[2][0], m[2][1], m[2][2], m[2][3],
                            m[3][0], m[3][1], m[3][2], m[3][3])),
                            p=True)
    cmds.scale(1,1,1,obj)

frontAxis = (0,1,0)
upVec = om.MVector(0,1,0)
tanCons(upVec, frontAxis, .5)
##
##

MRampAttribute solved!

Thanks Ryan Trowbridge for the help!

###
###

import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.mel as mel

kPluginNodeTypeName = "rpRampNode"

rampNodeId = OpenMaya.MTypeId(0x89010)

# Node definition
class rampNode(OpenMayaMPx.MPxNode):

        # class variables
        ramp01    = OpenMaya.MRampAttribute()
        numSegs =        OpenMaya.MObject()
        outTwisty =        OpenMaya.MObject()

        ##AEtemplate proc for the MRampAtributes
        mel.eval('''
                    global proc AErpRampNodeTemplate( string $nodeName )
{
	AEswatchDisplay  $nodeName;
	editorTemplate -beginScrollLayout;
		editorTemplate -beginLayout "ramp Node Template" -collapse 0;

			AEaddRampControl ($nodeName+".ramp01");

		editorTemplate -endLayout;

		AEdependNodeTemplate $nodeName;

	editorTemplate -addExtraControls;
	editorTemplate -endScrollLayout;
}

                    ''')

        def __init__(self):
                OpenMayaMPx.MPxNode.__init__(self)

        def compute(self, plug, dataBlock):
                #Set the attribute ramp01 to the plug
                thisNode = self.thisMObject()
                rampPlug = OpenMaya.MPlug( thisNode, rampNode.ramp01 )
                rampPlug.setAttribute(rampNode.ramp01)
                RampPlug01 = OpenMaya.MPlug(rampPlug.node(), rampPlug.attribute())

                #Get the atrributes as MRampAttribute
                myRamp = OpenMaya.MRampAttribute(RampPlug01.node(), RampPlug01.attribute())

                # Get the input handle
                dataHandle = dataBlock.inputValue(rampNode.numSegs)
                result = dataHandle.asInt()

                #Get output handle and its array data builder
                outputHandle = dataBlock.outputArrayValue(rampNode.outTwisty)
                outputBuilder = outputHandle.builder()
                numElements = outputHandle.elementCount()

                # Some variables
                myValAtPos = []
                dels = []

                #Get the float for get the average values
                for i in range(result):
                    quo = 1.0/(result - 1.0)

                    myFloat = quo*i

                    #Def to get value at position
                    def getValAtPos():

                        valAt_util = OpenMaya.MScriptUtil()

                        #Get the value as pointer
                        valAt_util.createFromDouble(1.0)
                        valAtPtr = valAt_util.asFloatPtr()

                        #Get the value at position
                        myRamp.getValueAtPosition(myFloat, valAtPtr)

                        #Get the value at pointer as float
                        valAtPos = valAt_util.getFloat(valAtPtr)

                        return (valAtPos)

                    myValAtPos.append(getValAtPos())

                    #Set the myValAtPos in the output attributes array
                    try:
                        outputHandle.jumpToArrayElement(i)
                        outdatahandle = outputHandle.outputValue()
                    except:
                        pass

                    outdatahandle.setDouble(myValAtPos[i])

                #Remove the unused elements in the attribute array.
                for w in range(numElements):
                    try:
                        outputHandle.jumpToArrayElement(w)
                        myIndex = outputHandle.elementIndex()
                    except:
                        pass

                    if (myIndex >= result):
                        try:
                            outputBuilder.removeElement(myIndex)
                        except:
                            pass

                return OpenMaya.kUnknownParameter                

# creator
def nodeCreator():
        return OpenMayaMPx.asMPxPtr( rampNode() )

# initializer
def nodeInitializer():

        #ramp01
        rampNode.ramp01= OpenMaya.MRampAttribute.createCurveRamp('ramp01', 'rmp01')

        #NumSegs
        nAttr = OpenMaya.MFnNumericAttribute()
        rampNode.numSegs = nAttr.create ( "numSegs", "nseg", OpenMaya.MFnNumericData.kInt, 0 )
        nAttr.setWritable(1)
        nAttr.setStorable(1)

        #outTwisty
        nAttr = OpenMaya.MFnNumericAttribute()
        rampNode.outTwisty = nAttr.create( "outTwisty", "ot", OpenMaya.MFnNumericData.kDouble, 0.0 )
        nAttr.setArray(1)
        nAttr.setStorable(1)
        nAttr.setUsesArrayDataBuilder(1)

        #Add Attributes
        rampNode.addAttribute( rampNode.ramp01 )
        rampNode.addAttribute ( rampNode.numSegs )
        rampNode.addAttribute( rampNode.outTwisty )

        #Attribute affects
        rampNode.attributeAffects( rampNode.ramp01 , rampNode.outTwisty )
        rampNode.attributeAffects( rampNode.numSegs , rampNode.outTwisty )

# initialize the script plug-in
def initializePlugin(mobject):
        mplugin = OpenMayaMPx.MFnPlugin(mobject, "Rosenio Pinto", "1.0", "Any")
        try:
                mplugin.registerNode( kPluginNodeTypeName, rampNodeId, nodeCreator, nodeInitializer )

        except:
                sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName )
                raise

# uninitialize the script plug-in
def uninitializePlugin(mobject):
        mplugin = OpenMayaMPx.MFnPlugin(mobject)
        try:
                mplugin.deregisterNode( rampNodeId )
        except:
                sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName )
                raise

###
###

            
Return top