;

Pymel Blog Rss Feed

Sunday, April 8, 2012


In these tutorials, I won’t be using Default Maya Python (DMP). I’ll be using PyMEL. PyMEL is a Python library written to make development easier. DMP has a more procedural feel. While PyMEL takes advantage of the fact that Python is an object oriented programming language. This bit of information may or may not be of any immediate importance to you. So rather than talk about the paradigm differences between procedural and OO programming, I think it's best to show an example of why PyMEL rocks and DMP doesn't:

 

Let's say we wanted to take a bunch of objects that are at the origin and we want to move them to random locations between -50 and 50 on X, Y, and, Z. Oh and we also want to point constrain a newly created locator to each objects position.

 

DMP way:

import maya.cmds as cmds
import random
objSel = cmds.ls(sl=True) #store the selected objects
listSize = len(objSel) #store the length of the list
for i in range(0, listSize):
	curObj = objSel[i] #grab the current object from the list
	curLocator = cmds.spaceLocator()[0]#create and store locator
	xVal = random.uniform(-50, 50) #generate random x value
	yVal = random.uniform(-50, 50) #generate random y value
	zVal = random.uniform(-50, 50) #generate random z value
	cmds.connectAttr(  curObj + '.translate', curLocator + '.translate' ) # Connect the translations together
	cmds.xform(curObj, ws=True, t=[xVal, yVal, zVal]) #place the object

PyMEL way:

import random
objSel = selected() #store the selected objects
listSize = len(objSel) #store the length of the list
for i in range(0, listSize):
	curObj = objSel[i] #grab the current object from the list
	curLocator = spaceLocator()#create and store locator
	xVal = random.uniform(-50, 50) #generate random x value
	yVal = random.uniform(-50, 50) #generate random y value
	zVal = random.uniform(-50, 50) #generate random z value
	curObj.translate >> curLocator.translate # Connect the translations together
	curObj.translate.set(xVal, yVal, zVal) #place the object

Note that in the DMP way, on line 3, I use the 'ls' command. While using PyMEL, on line 2, I can use the selected() procedure. Also look at the last two lines of code for each command. The PyMEL code is much easier. Much cleaner.

 

Now let's say you have a bunch of objects that are scattered about your scene but whose tranforms have been frozen to the origin. We want to get them back to world space. If, for example, we were going to use these objects for particle instancing, we would need to do this.

 

DMP way:

import maya.cmds as cmds
objSel = cmds.ls(sl=True) #store the selected objects
listSize = len(objSel) #store the length of the list
for i in range(0, listSize):
	curObj = objSel[i]
	cmds.select( curObj)
	#get the boundingbox center
	xVal = cmds.getAttr( curObj + ".boundingBoxCenterX")
	yVal = cmds.getAttr( curObj + ".boundingBoxCenterY")
	zVal = cmds.getAttr( curObj + ".boundingBoxCenterZ")
	cmds.xform(curObj, ws=True, t=[-xVal, -yVal, -zVal]) #place the object at the origin
	cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=2 ) #freeze tranformations
	cmds.xform(curObj, ws=True, t=[-xVal, -yVal, -zVal], piv=[0,0,0]) #replace the object and center it's pivot

PyMEL way:

objSel = selected() #store the selected objects
listSize = len(objSel) #store the length of the list
for i in range(0, listSize):
	curObj = objSel[i]
	select(curObj)
	centerPoint = curObj.getBoundingBox().center() #get the bounding box center
	curObj.translate.set(-1 * centerPoint) #place the object at the origin
	cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=2 ) #freeze tranformations
	curObj.centerPivots() #center the pivot
	curObj.translate.set(centerPoint) #replace the object

I don't know about you, but I like the PyMEL way. So that's what you'll find on this site.

 

Now, in order to use the PyMEL versions of the previous examples, first we need to import the PyMEL library. Importing PyMEL is easy:

from pymel.core import *

Boom. Done. We have PyMEL. Keep in mind that it's been imported into the main namespace. This means that I don't have to prefix my commands with a namespace. For example we can say:

polyCube()

 

You can also import PyMEL into a namespace of your choosing:

import pymel.core as mc
mc.polyCube()
# Result: [nt.Transform(u'pCube2'), nt.PolyCube(u'polyCube2')] # 

So you see we had to prefix the PyMEL command with 'mc'. By importing into the root namespace, we don't need prefixes. The only caveat when you do this, is that you have to be careful not to go and overwrite a built in Maya command.

polyCube() #create and store a poly cube like usual
# Result: [nt.Transform(u'pCube1'), nt.PolyCube(u'polyCube1')] #
polyCube = 10  #oh no! here we overwrite the polyCube command with the number 10!
polyCube()
# Error: TypeError: 'int' object is not callable #

In order to use the 'polyCube' command, we'd have to restart Maya or reimport PyMEL into another namespace. Yet despite this ever present danger I routinely import PyMEL into the root namespace because I like living dangerously! Plus the more practice you get, the less likely you are to break stuff.

 

Python has become somewhat of a standard in the visual effects community. So it's only proper to have access to a flavor of Python that looks more like the industry's version. PyMEL is that flavor. And it tastes great! Much love to the kind folks at Luma Pictures for making it happen!

My comment system is powered by Disqus. And they require you to put in a name and an email. But I'd love to hear what you think. So if you want to comment anonymously, just put any name and test@test.com for your email.

blog comments powered by Disqus