Maya Python vs MEL: Overloading Part 1 Matrices in Maya Python
Oct 25

I wanted to give another example that is even closer to how C++ overloading functions work. With python you can create functions that use keywords which are basically predefined variables. The good thing about this is a keyword does not have to have a variable passed to it because it already has a valid value. You can use this in a way to make a function work much like a maya command. For example these three lines are valid:

import maya.cmds as cmds

cmds.polySphere ( r=1 )
cmds.polySphere ( sx=10, sy=15, r=1 )
cmds.polySphere ( sy=15, r=1)

You could write your own maya command with Python API, which would be more complicated but completely possible. The good part of using the Python API to write a command is it includes other nice features that Maya does for you, but I wont get into that now. For now I will give an example how a basic function can imitate this. Example:

import maya.cmds as cmds

# define a function with three keywords that are predefined, shader is default to True
def createSphere( extrude = None, shader = True, squash = None ):

	# Create a poly sphere
	sphere = cmds.polySphere()

	# If extrude == True all faces will be extruded on the sphere
	if(extrude == 1):
		print 'extrude == True'
		faceNum = cmds.polyEvaluate( sphere[0], face=1 )

		faces = (sphere[0] + '.f[0:' + str(faceNum) + ']')
		cmds.polyExtrudeFacet( faces, ltz = .4, constructionHistory=1, keepFacesTogether=0, pvx = 0, pvy=0, pvz = 0, divisions=1, twist=0, taper=1, off=0, smoothingAngle=30)

	# If shader == True then create a lambert shader and change it to blue then assign it to the sphere
	if(shader == 1):
		print 'shader == True'

		lambert = cmds.shadingNode( 'lambert', asShader=True )
		cmds.setAttr ( (lambert + '.color'), 0, 0.0241732, 0.98, type = 'double3' )

		cmds.select( sphere )
		cmds.hyperShade( assign=lambert )

	# If squash == True a lattice deformer will be added to the sphere
	# The lattic has its top and bottom points translated toward the center of the sphere
	if(squash == 1):
		print 'squash == True'
		lattice = cmds.lattice( sphere[0], divisions =[2, 2, 2], objectCentered=True, ldv=[2, 2, 2], exclusive=1 )

		# Translate top of lattice down
		cmds.select ( (lattice[1] + '.pt[0:1][1][0]'), (lattice[1] + '.pt[0:1][1][1]'), replace=True )
		cmds.move( 0, -0.8, 0, relative = True, localSpace=True, worldSpaceDistance=1)

		# Trnaslate bottom of lattice up
		cmds.select ( (lattice[1] + '.pt[0:1][0][0]'), (lattice[1] + '.pt[0:1][0][1]'), replace=True )
		cmds.move( 0, 0.8, 0, relative = True, localSpace=True, worldSpaceDistance=1)

	# Clear selection
	cmds.select( clear=True)

In the script editor make sure you are on a Python tab and execute the above script. Then you can execute these commands below and see what they do:

# Creates a polysphere and adds a blue shader
createSphere()

# Creates a polysphere, extrudes the faces, squashes it with a lattice, and doesn't add a blue shader
createSphere( extrude = True, squash = True, shader=False)

# Creates a polysphere extrudes the faces and squashes it with a lattice, and adds a blue shader
createSphere( extrude = True, squash = True )

# Creates a polysphere and extrudes the faces, and adds a blue shader
createSphere( extrude = True )

# Creates a polysphere and squashes it with a lattice, and adds a blue shader
createSphere( squash = True )

# Creates a polysphere and squashes it with a lattice, and adds a blue shader
createSphere( extrude = False, squash = True )

Hopefully the above example will help you with writing more flexible Maya python code. Also it might give you a reason to look at using it over MEL.

-RyanT

4 Responses to “Maya Python vs MEL: Overloading Part 2”

  1. Jordan Says:

    That was extremely helpful, thanks! I just figured out how to get Python working in place of MEL- and your tutorial was very helpful.

    I find it interesting that we can assign a createSphere command to a variable- then use that variable to later substitute the name.

  2. Lyno Says:

    Hi,master Ryan,Greetings~!
    Sorry about my disturb again,plz give me some suggestions when you are free…
    I tried to tap an object to a point of another object via a script to avoid any maya constraints.(Before, maybe i would use the nCloth constraint to approach,but that always makes trouble.)So i wrote a script as below:

    —————————————————————————————
    # i created a pCube and a pCone.pCube will be the leader,and the pCone as the follower.

    import maya.cmds as mc
    # Select the follower first,then one of the vertexes of the leader.Define them.
    SL = mc.ls(selection = True)
    vertex = SL[1]
    print SL
    print vertex

    start = mc.playbackOptions(q = True,min = True)
    end = mc.playbackOptions(q = True,max = True)
    current = start

    lead = vertex
    follow = SL[0]

    #Get the vertex’s attr per frame,then bake to the follower.
    while (current<=end):
    # Get the point’s position.
    vPos = mc.xform(vertex,q = True,ws = True,t = True)
    # Get the normal infomation that could be used to define the follower’s rotate.
    vNor = mc.polyNormalPerVertex(vertex,q = True,xyz = True)
    print vPos
    print vNor
    mc.setKeyframe(follow,at=”translateX”,v=vPos[0])
    mc.setKeyframe(follow,at=”translateY”,v=vPos[1])
    mc.setKeyframe(follow,at=”translateZ”,v=vPos[2])
    mc.setKeyframe(follow,at=”rotateX”, <———- Questions appeared here
    mc.currentTime(current)
    current += 1
    —————————————————————————————

    The “vNor = mc.polyNormalPerVertex(vertex,q = True,xyz = True)” returned me a list as [1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,-1.0].
    what this group means?Is that a 3*3 matrix defining the normal’s orientation?
    How can i use the informations to define the follower’s rotation? Or maybe my thinking,my method is wrong?
    Thanks a lo~~~~t. : ]

  3. admin Says:

    This is a bit more complicated than you might think.

    The polyNormalPerVertex is returning one vector per vertex. Select your cube and turn on show vertex normals if you rotate the face on the cube the vertex normals change and will no longer line up to look like a matrix. Each vertex represents a face being drawn to represent the shape of the object. There is not one vertex being drawn but several. There is one vertex vector per face connected to it. Also if you rotate the cube the vertex vectors will still return the same value because they are returning the vector which is offset from its parents matrix.

    So really selecting one vertex is giving you several vectors. The array of numbers that polyNormalPerVertex is giving you is a vector per vertex. Therefor if you split the face on one of the cubes faces and split it from the selected vertex to another edge and then rerun the polyNormalPerVertex it will return 12 numbers instead of 9. You can not drive your other nodes rotation based on this vector alone.

    You could do something like get the world matrix of the cube then use a specific vector as the up vector. Then you would need to use that information to calculate how your node would be rotated. And that is where I will stop.

    The other way…

    I suggest you look up the rivet.mel script where someone setup a way to constrain a transform of an object to a vertex.

    http://www.creativecrash.com/maya/downloads/scripts-plugins/animation/c/rivet-button–2

  4. Lyno Says:

    thank you very much master Ryan, for your kindly help again~!

Leave a Reply