Python in Maya:
maya.cmds, PyMEL


Two modules - maya.cmds, pymel.core

Python in Maya - intro, history

At first there was/is Maya Python (maya.cmds), from Autodesk. MEL calls were wrapped in Python, that's about it.

At Luma Pictures, developers began 'PyMEL' (pymel), and started a Google forum to spread the word (and did!!). pymel wraps around maya.cmds :)

Today we have PyMEL officially being bundled by Autodesk.. So there are two ways to "do Python in Maya".

Be sure to do the PyMEL samples below, in Maya 2011 or later.

What's in maya.cmds, pymel

import maya.cmds 
import maya.mel
dir(maya.cmds)
dir(maya.mel)


from pymel.core import *
dir()

maya.cmds is strings-based, pymel is object-based

for n in maya.cmds.ls():
  print type(n)
# oh no!!! maya.cmds is simply MEL in Python's clothing :(

for n in ls():
  print type(n)
# THIS is why PyMEL is WAAAAAAAAAAAAAAAAAAY BETTER!!!!!!!!!

Trying out maya.cmds

The idea is pretty simple - commands you need to run are all 'maya.cmds.something()', with extra inputs being specified inside the '()' (or 'cmds.something()' if you use the import shortcut below).


import maya.cmds as cmds
cmds.plane()

cmds.sphere(radius=4)
cmds.move(2.0, 1.0, 1.0, 'nurbsSphere1')

cmds.sphere(n='ball')

cmds.ls(type='nurbsSurface')

cmds.ls(selection=True)

cmds.getAttr('ball.translate')
cmds.getAttr('ball.translateX')
cmds.setAttr('ball.translateX', -5.0)

# something more fancy
import math
for i in range(360):
 x = math.cos(i*3.1415/180)
 y = math.sin(i*3.1415/180)
 cmds.sphere(r=0.01,p=[x,y,0])

UI creation

MEL remains a powerful, simple way (although verbose) to create UI in Maya. So we can use maya.cmds (or pymel) to create them in Python (since they call MEL anyway). FYI - a completely different, and new, way is to code your UI in PyQt (or 'QtPy') - Qt is a very popular toolkit (originally from Trolltech in Norway, since acquired by Nokia) that is used in cellphones/PDAs as well as desktops.

Here are some UI examples.

cmds.promptDialog(button=['OK'])
userText = cmds.promptDialog(query=True, text=True)
print "You entered " + userText + " in the dialog box :)"

cmds.promptDialog(
        title='Create object',
        message='Enter Object Name:',
        button=['Sphere', 'Cancel'],       
        defaultButton='Sphere',
        cancelButton='Cancel')
 
text = cmds.promptDialog(query=True, text=True)
cmds.polySphere(n=text)

cmds.promptDialog(
        title='Sphere creation',
        message='Enter sphere\'s name:',
        button=['Do it', 'Cancel'],       
        defaultButton='Create sphere',
        cancelButton='Cancel')
 
sphNm = cmds.promptDialog(query=True, text=True)
cmds.polySphere(n=sphNm)

As you can see, the commands are not bad (not complex). Here is another piece of code that shows how to create radio-buttons. This is a screenshot.

win =  cmds.window()
cmds.columnLayout()
 
cmds.radioCollection('Shapes')
cmds.radioButton('Sphere', label = 'Sphere')
cmds.radioButton('Cube', label = 'Cube')
cmds.radioButton('Cylinder', label = 'Cylinder')
cmds.radioButton('Torus', label = 'Torus')
 
cmds.button( label='OK', command="print cmds.radioCollection('Shapes', query=True, select=True)")
 
cmds.showWindow(win)

Note that you specify the command for the button, in a separate 'callback' function (that Maya will call back, (only) when the user clicks the button. Here's what the callback will look like:


# note - 'self' MUST always be the first argument in a callback func definition
def createUsersObj(self):
    us = cmds.radioCollection('Shapes', query=True, select=True)
    print us
    if us=='Sphere':
     cmds.sphere()
    elif us=='Cylinder':
     cmds.cylinder()
    elif us=='Torus':
     cmds.torus()
    else:
     cmds.cube()



win =  cmds.window()
cmds.columnLayout()
 
cmds.radioCollection('Shapes')
cmds.radioButton('Sphere', label = 'Sphere')
cmds.radioButton('Cube', label = 'Cube')
cmds.radioButton('Cylinder', label = 'Cylinder')
cmds.radioButton('Torus', label = 'Torus')
 
cmds.button( label='OK', command=createUsersObj)
 
cmds.showWindow(win)

Some things are way simpler in pymel

Because pymel is object-oriented, it 'comes' with useful functionality pre-built. In the example below, you can see that its 'mel' object contains a MEL-language call "natively".

values = ['one', 'three', 'two', 'three', 'four']
# call a MEL function, via 'eval' 
maya.mel.eval( 'stringArrayRemoveDuplicates( {"'+'","'
.join(values)+'"})')

values = ['one', 'three', 'two', 'three', 'four']
# much simpler - pymel's 'mel' includes stringArrayRemoveDuplicates()
mel.stringArrayRemoveDuplicates(values) 

Running MEL procs from within pymel

There are times when you have a well-debugged,efficient piece of MEL code you like, and want to 'somehow' run that from within Python. How?

# 1. define
mel.eval( '''global proc myScript( string $stringArg, 
float $floatArray[] )
{ float $donuts = `ls -type camera`;}''')

# 2. use 
mel.myScript('test',[0.1,0.7])
mel.myScript('test',[]) # MelConversionError is thrown

pymel helps you 'string together' calls

// in MEL:
sphere();
string $sel[] = `ls -sl`;
string $shapes[] = `listRelatives -s $sel[0]`;
string $conn[] = `listConnections -s 1 -d 0 $shapes[0]`;
setAttr ($conn[0] + ".radius") 3;

# Back in Py:
sphere()
selected()[0].getShape().inputs()[0].radius.set(12) # wow

pymel's nodes - RICH functionality

camTrans, camShape = camera()  # create a new camera

camShape.setFocalLength(100)
fov = camShape.getHorizontalFieldOfView()
print fov

camShape.dolly( -3 )
camShape.track(left=10)

dir(cam) # all of cam's methods/members

Another pymel example

Again, based on a node's type, we can call appropriate methods.

s = polySphere()[0] # just shape

dir(s)

if s.visibility.isKeyable() and not s.visibility.isLocked():
    s.visibility.set(False)
    s.visibility.lock()
    print s.visibility.type()

dir(s.getChildren()) # what are we seeing?? 


dir(s.getChildren()[0])

pymel - reach deep into nodes

You can also do component-level processing, using simple-looking calls:

s = polySphere()[0] # just shape

# s.faces is a list of all faces 
for face in s.faces:
    if face.getNormal('world').y > 0.0:
       select(face, add=1)

Comparison: three eval()s

There is MEL's eval() command that is available via maya.cmds.eval() and also pymel's mel.eval(), as shown below. In addition, entirely separately, Python's native eval() call is also there(to evaluate a **Python** string).

# maya.cmds
maya.mel.eval("curve -d 3 -p 0 0 0 -p 1 0 0 -p 0 1 0 -p 0 0 1")

# pymel
mel.eval("curve -d 3 -p 0 0 0 -p 1 0 0 -p 0 1 0 -p 0 0 1")

# Python's built-in eval()
eval('camera()')

Manipulating the Maya 'optionVar' database - so simple

Maya stores ALL CUSTOMIZATIONS in a database (maintained in a MEL script).

if 'numbers' not in optionVar:
    optionVar['numbers'] = [1,24,47]
optionVar['numbers'].append(9)
numArray = optionVar.pop('numbers')

Comparable MEL commands are shown here.

Getting/setting globals

All globals are in a pymel dictionary called 'melGlobals':

melGlobals['$gMainFileMenu']
melGlobals['$gGridDisplayGridLinesDefault'] = 15

Some custom operators

pymel comes with operators for parenting nodes, and for connecting and disconnecting attrs.

# create a camera and a sphere
camXform, camShape = camera()
sphere = polySphere()[0]

sphere | camXform  # parent the camera to the sphere

camXform.tx >> camXform.ty  # connect operator

camXform.tx // camXform.ty  # disconnect operator

"Script plugins"

Interestingly, you can write 'Python script plugins', which make use of Python-wrapped C++ Maya API calls. In other words - in the past, Maya plugins *had* to be coded in C++, but now, we can use Python. Advantage - cleaner/simpler syntax, and the ability to mix in code from dozens/hundreds of other Python modules.

Here is an example: download this file (helixCmd.py) to any directory (eg. /tmp or your home dir), and load it into Maya via the plugin manager (as you would, any other '.so' plugin). Then run this in the Python script-ed win:

import maya
maya.cmds.spHelix(p=0.3, r=7)

Cool! The helix curve that shows up in the scene, via the maya.cmds.spHelix() Python call that you just made, was generated from Python code contained in helixCmd.py. For fun, you can also run the plugin code via MEL (be sure to switch to the MEL tab first!):

// we're running, via MEL, Python code in 
// our 'helixCmd.py' plugin file :)
spHelix -p 0.4 -r 10; 

Study the code in helixCmd.py, make minor modifications (eg. look for the place where CV x,y,z values are computed, and set them to random (hint: 'import random') values :) Re-load the plugin, and run again (MEL or Python) - you should be able to see the result of your changes.

Making changes to existing code and observing what that does is one good way to learn programming. Another is to have a project/pet idea that you want to try out, and use that as a means to learn (ie look up necessary calls to make the code do what you want).

After more reading up and experimentation, you should be able to write Python script plugins in these categories:

  • deformers
  • emitters
  • fields
  • solvers
  • shape generators (surfaces, curves)
  • shaders
  • constraints
  • manipulators
  • general-purpose nodes (eg. a 'Perlin noise' node)
  • 'command' plugins (such as helixCmd.py above)
  • ...

So how do you learn more? Look at C++ plugin code - you will be able to 'port' these to Python without much effort. A huge collection of C++ plugin source files can be found in the '....devkit/plug-ins' directory of Maya's installation (eg. paste this in the browser URL box: file:///rel/third_party/maya/2011.5.3_64/devkit/plug-ins).

'Porting' MEL to pymel (and vice-versa!)

When you know one language, learning additional ones becomes easier - this is because you can compare the new language(s) to your first one..

Here is a MEL to Python 'transition' guide (very barebones!)..

More on GUI-building

Outside of Maya, you can use to build GUIs for just about anything - exploring files, asset management, launching programs, sending mail..

Here is a sampling of ways by which you can construct interfaces.

Where else can you use Python?

Now that you know Python basics and understand how object-oriented (node-based) calls in pymel work, you have a VAST playground in which to exercise your Python skills:

  • Maya
  • XSI
  • Houdini
  • Blender
  • Cinema 4D
  • MotionBuilder
  • RealFlow
  • prman
  • aqsis
  • Nuke
  • ...

Remember - all functionality resides in modules, and you use them all identically, using beguilingly-simple, uniform syntax :)

Graphics (and audio) programming

You can also do your own graphics programming (to draw lines, color pixels, manipulate images and video, etc.) using Python.

Here is a sampler:

But wait, there's more! You can also audio processing in Python, ie. read-in music (eg. an mp3 file), alter it, create modified output. The pyechonest API offers an example. This and this are examples of what you can do with it :)

Upload an mp3 to this page, to try out some audio processing which runs "on the cloud". This is a processed result.