Wednesday, May 23, 2012
Prior to starting any of these lessons be sure to import the PyMEL library. See here for why and how.
In a previous tutorial, we talked about built in Maya commands. Here we'll talk about user created Maya commands.
Often times in programming, we need to break large problems down into smaller ones. We also like to encapsulate behavior. Functions give us this ability. Let's write a few small examples.
def Hello(): print "Hello world!" Hello()
This basic function prints out the infamous "Hello World" line. I know, it’s not very flashy. But there are some things to note here. First, the code is indented. If you need a refresher on the perils of indentation in Python, check this out. Also note on line 3, how we execute the function. Lines 1 and 2 define the behavior. And line 3 actually tells Maya to run our code. Now let's add a parameter:
def Hello(name): print "Hello " + name Hello("Chuks")
Here we add a parameter, also known as an argument. We can no longer simply call Hello() Maya will complain that it expected 1 argument and it got none. But with this new definition, we can do:
Hello("John") #prints Hello John Hello("Sally") #prints Hello Sally Hello("Bob") #prints Hello Bob Hello("Newman") #prints Hello Newman (like Seinfeld would say it)
We can have more than one parameter:
def Hello(firstName, lastName): print "Hello " + firstName + " " + lastName Hello("Babe", "Ruth") #prints Hello Babe Ruth Hello("Abe", "Lincoln") #prints Hello Abe Lincoln Hello("Bugs", "Bunny") #prints Hello Bugs Bunny Hello("Yogi", "Bear") #prints Hello Yogi Bear (like Seinfeld would say it)
Additional parameters can be added as needed. And you can add as many as you want. Just make sure that they're separated by commas. Oh and if you don't get string concatenation, check out the variables tutorial.
So if parameters are inputs, what about outputs? Surely we're not only limited to only inputs?! The answer, as you may have guess is no, we're not just limited to inputs. Not only can we have inputs by way of parameters, we can create and send return values:
def Square(num): numSquared = num * num return numSquared myResult = Square(5) #result is 25 print myResult #prints myResult
This way, you can store the results of functions into variables. And from there, you can use these variables to do whatever it is you need to do.
I like to think of functions as factories that work best when they perform a singular task. You pass information through the front door as arguments and then the factory does its work. When it's done, the function passes the result out the back door as a return value.
So let's put everything together and write a script that creates a random combination of poly spheres, tori, and cylinders. And then the script will move each object's vertices to random locations.
def MoveObjVertices(curObj): numVertex = len(curObj.vtx) for i in range(0, numVertex): xVal = random.uniform(-0.03, 0.03) yVal = random.uniform(-0.03, 0.03) zVal = random.uniform(-0.03, 0.03) randVector = dt.Vector(xVal, yVal, zVal) polyMoveVtxObj = polyMoveVertex(curObj.vtx[i])[0] polyMoveVtxObj.setTranslate(randVector) def MakeObj(objType): if(objType == 1): curObj = polySphere()[0] elif(objType == 2): curObj = polyTorus()[0] else: curObj = polyCylinder()[0] MoveObjVertices(curObj) return curObj def PolyRandomization(numObj): for i in range(0, numObj): objType = random.randint(0,2) #make sure you imported random xVal = random.uniform(-30, 30) yVal = random.uniform(-30, 30) zVal = random.uniform(-30, 30) curObj = MakeObj(objType) curObj.translate.set(xVal, yVal, zVal) delete(curObj, ch=True)
See the tutorial on random numbers if you need to. Also see the tutorial for PyMEL objects to understand how polyMoveVtxObj works on line 8. So let's step through this. The entry point to this script is on line 21. We need to supply the number of object we wish to create. So we would write something like this:
PolyRandomization(5)
Lines 23-26 create random numbers we need to choose which object to create as well as where to move the object. Line 27 we call MakeObj(). Control jumps to line 11. This is where we choose which object to create based on the random integer generated on line 23. On line 18, we call MoveObjVertices(). Control jumps to line 1. And this is where we actually move the object's vertices. We loop through each vertex, making use of the PolyMoveVertex object, and we move them to a random location. Finally control returns back to line 28 and 29 where we move the newly created object and delete its construction history.
Without separating the functionality into separate functions, the code would look like this:
def PolyRandomization(numObj): for i in range(0, numObj): objType = random.randint(0,2) #make sure you imported random xValObj = random.uniform(-30, 30) yValObj = random.uniform(-30, 30) zValObj = random.uniform(-30, 30) if(objType == 1): curObj = polySphere()[0] elif(objType == 2): curObj = polyTorus()[0] else: curObj = polyCylinder()[0] numVertex = len(curObj.vtx) for i in range(0, numVertex): xValVtx = random.uniform(-0.03, 0.03) yValVtx = random.uniform(-0.03, 0.03) zValVtx = random.uniform(-0.03, 0.03) randVector = dt.Vector(xValVtx, yValVtx, zValVtx) polyMoveVtxObj = polyMoveVertex(curObj.vtx[i])[0] polyMoveVtxObj.setTranslate(randVector) curObj.translate.set(xValObj, yValObj, zValObj) delete(curObj, ch=True)
Indentation nightmare! Very hard to read. It's not very clear what's doing what. I'll leave it to you if you want to follow the flow. It hurts my eyes just looking at it.
So in conclusion, use functions whenever you have functionality that can be grouped. As an added benefit, you may be able to reuse code; you won't have to write the same lines over and over. Plus it will make your code more readable. Any questions? Let me know!
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