Topics:
Start by downloading this image module (from http://pages.central.edu/emp/johnsonm/conciseintro/), and placing it in your 'scripts' dir.
Now try this:
import image, random
dir(image)
help(image)
i = image.ImagePPM.new((256,256))
for x in range(256):
for y in range(256):
i.putpixel((y,x),(100,160,200))
i.save("C:/Users//Desktop/fun.ppm")
# now look in your desktop :)
How can we generate patterns?
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.
import maya.cmds import maya.mel dir(maya.cmds) dir(maya.mel) from pymel.core import * dir()
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!!!!!!!!!
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])
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)
Another UI example:
# select a bunch of nodes, then run the following
import maya.cmds as mc
def createMyLayout( obj, parent ):
mc.setParent(parent)
c = mc.columnLayout()
text = mc.textField(text=obj)
button1 = mc.button(label="one")
button2 = mc.button(label="two")
return c
myLayouts = []
w = mc.window("example", title="Sample UI creation")
c = mc.columnLayout()
for selectedObject in mc.ls(sl=True):
myLayouts.append(createMyLayout(selectedObject, c))
mc.showWindow(w)
Here is how to set keyframes.. Start a new scene, set fps to 50, and set the frame range from 1 to 300 (we'll need 252 frames). Then run this:
import maya.cmds as cmds
cmds.polySphere(name = "bouncing", radius = 2)
g = -0.04
v0y = 0.8
v0x = 0.1
pos0y = 2
pos0x = 0
for itr in xrange(0,6):
for tx in xrange(0,42):
posy = pos0y + v0y*(tx-1) + g*(tx-1)*(tx-1)/2
posx = pos0x + v0x*((itr*42) + tx-1)
cmds.setKeyframe("bouncing", attribute="translateY", value=posy, t=(itr*42) + tx )
cmds.setKeyframe("bouncing", attribute="translateX", value=posx, t=(itr*42) + tx )
In the above, we're calling maya.cmds.polySphere() to create a ball, and maya.cmds.setKeyframe() to set a keyframe (given a node, attribute, value, time). So straightforward!
Next, let's open a 'P3' .ppm text file (that contains image pixels), and "plot" it in Maya.. Here is the image file (as ASCII!).
import maya.cmds
# before proceeding, EDIT sgn.ppm, remove these four 'header' lines:
# P3
# # CREATOR: The GIMP's PNM Filter Version 1.0
# 99 99
# 255
f = open("c:/test/sgn.ppm")
lines = f.readlines()
lines
rx, ry = 99,99
for i in range(ry):
for j in range(rx):
pxl = []
for k in range(3):
indx = k + j*3 + 3*i*rx # ry-1-i
pxl.append(int(lines[indx].rstrip('\n')))
rd = (pxl[0]+pxl[1]+pxl[2])/(3*255.0)
maya.cmds.sphere(r=rd)
maya.cmds.move(j,i,0)
f.close()
# variation
import maya.cmds
f = open("c:/temp/sgn.ppm")
lines = f.readlines()
rx, ry = 99,99
for i in range(ry):
for j in range(rx):
pxl = []
for k in range(3):
indx = k + j*3 + 3*(ry-1-i)*rx # ry-1-i
pxl.append(int(lines[indx]))
rd = 5*(pxl[0]+pxl[1]+pxl[2])/(3*255.0)
maya.cmds.polyCube(w=1,h=1,d=rd)
maya.cmds.move(j,i,0*rd/2)
f.close()
Here's a 'chain' script:
import maya.cmds as mc
mc.polyCylinder(ax=[1,0,0])
mc.scale(4,1,1)
mc.sphere(p=[6,0,0])
mc.duplicate()
mc.move(3,0,0)
for i in range(1,11):
mc.duplicate(st=True)
mc.select(["pCylinder1","nurbsSphere1"],r=True)
mc.constrain(hinge=True, o=(0, 2.5, 0), i=0 )
mc.select("pCylinder1")
mc.setAttr("rigidBody1.active", 0)
for i in range(1,12):
mc.select("nurbsSphere"+str(i))
mc.select("nurbsSphere"+str(i+1),tgl=True)
mc.constrain(hinge=True, o=(0, 2.5, 0), i=0 )
mc.move(1,0,0,"rigidHingeConstraint1",r=True)
mc.gravity(pos=(0,0,0), m=9.8, dx=0, dy=-1, dz=0)
mc.select("nurbsSphere*")
sph = mc.ls(selection=True)
mc.connectDynamic(sph,f="gravityField1")
# set pb range to 200 frames, then play :)
Exercise - how to create 'symmography' cobweb curves??
pymel was explicitly conceived (by Chad Dombrova and others from Luma Pictures - THANK YOU!) to be object-oriented, as opposed to maya.cmd's "stringy" feel (because it is simply a Python layer/wrapper for good old MEL calls).
Calls use standard Py objects such as lists/tuples.
import pymel.core pymel.core.curve(d=1,p=[(0,0,0),(1,1,1)])
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)
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
// 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: import pymel.core as pm pm.sphere() pm.selected()[0].getShape().inputs()[0].radius.set(12) # wow
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
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])
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)
Here is how to draw straight lines (curves of degree 1):
import pymel.core as pm, random for i in range(100): p1 = (random.randint(-45,45),random.randint(-45,45),random.randint(-45,45)) p2 = (random.randint(-45,45),random.randint(-45,45),random.randint(-45,45)) pm.curve(p=[p1,p2], d=1)
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()')
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.
All globals are in a pymel dictionary called 'melGlobals':
melGlobals['$gMainFileMenu'] melGlobals['$gGridDisplayGridLinesDefault'] = 15
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
Creating pymel-based UI is easy/fun. Try this:
from pymel.core import *
win = window(title="My Window")
layout = columnLayout()
chkBox = checkBox(label = "My Checkbox", value=True, parent=layout)
btn = button(label="My Button", parent=layout)
def buttonPressed(*args):
if chkBox.getValue():
print "Check box is CHECKED!"
btn.setLabel("Uncheck")
else:
print "Check box is UNCHECKED!"
btn.setLabel("Check")
btn.setCommand(buttonPressed)
win.show()
Here are many more examples.
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!)..
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:
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.
Likewise, a growing collection of Python "scripted" plugins are being shipped as well - look in the ..../devkit/plug-ins/scripted subdirectory. Here is documentation o nhow to use the ones that are included with Maya 2012. And here are several .py script plugin sources, mixed in with C++ (".cpp" and ".h") files..
Out of necessity (not enough time, too early, etc.), these had to be left out:
If you need your Python foundation to be complete, you do need to invest some effort in learning the above on your own. Given what you know, this shouldn't be hard at all.
That's all, for now. Hope you UTILIZE, ENJOY AND PROFIT from "coding" throughout your career.. Good luck, be in touch!