Saturday, November 14, 2009

MEL scripting trickery Part I

MEL is frickin annoying!!! There are so many irritating things in MEL I can't even begin to start. Maya's use of Python is certainly a godsend, except for one minor detail -- the foundation is still MEL. So now we basically have to write MEL in Python, which is an entire learning adventure in itself.

Anyway, here are solutions to some problems that I personally lost sleep over when I was starting out learning MEL and Maya.

Problem 1: Resolving variable names within a script

Imagine this scenario. You are trying to create a cute MEL script to automate the creation of some objects, and you ... just ... can't! Why, why, WHY does this not work???

// attempt # 1
$mySphere = `polySphere`;
$mySphere.scaleX = 3;

The docs say to use setAttr. Fine.

// attempt # 2
$mySphere = `polySphere`;
setAttr $mySphere.scaleX = 3;

Oh! I see, setAttr actually takes two arguments, the attribute to set and the value to set it to. It doesn't take an equation with the equals sign. Okay, now it's got to work, right??

// attempt # 3
$mySphere = `polySphere`;
setAttr $mySphere.scaleX 3;

YES! No syntax error! But ... still not working. We get the mysterious, annoying, USELESS error: No attribute was specified. By now you are probably not caring why it doesn't work, you just want some hack to fix this problem and be done with it. So you turn to your trusty eval command, which allows you to evaluate a string as if it were a MEL command. Gettin ugly ....

// attempt # 4
$mySphere = `polySphere`;
$commandString = "setAttr " + $mySphere + ".scaleX 3";
eval($commandString);

Haha, now we get not one error, but two. Give up yet? Ok, so this last attempt was almost correct. The problem with MEL is that sometimes it inexplicably returns you a string array instead of a string, even though the string array has only one item in it. So technically, this works:

// attempt # 5
$mySphereStringArray = `polySphere`;
$mySphereString = $mySphereStringArray[0];
$commandString = "setAttr " + $mySphereString + ".scaleX 3";
eval($commandString);

Wow. That looks ugly as all hell. While attempt #5 works, the code shows someone who kept fiddling with code until it worked instead of trying to understand the underlying problem. First of all, find out if the attribute can be set during creation. Go to your MEL command reference and look up the attributes for polySphere. Hmm, doesn't seem like there are any flags that can help us set the scaleX before the object is created. Fine.

And that brings us to the correct, MELish way to do it. Here is where we wish and wish MEL could be more like Python, but it just isn't. MEL can resolve variables and execute commands, but it can't do both at the same time :( If you look at attempt 3 above, this was the closest to the actual solution. In the second line of code, you are trying to resolve a variable and execute a command at the same time, and Maya gets confused (and that seems to happen very often).

// attempt # 6 -- the right way

$mySphereStringArray = `polySphere`;
setAttr ($mySphereStringArray[0] + ".scaleX") 3;

We've separated the job of resolving the variable name and executing the command by using a parenthetical expression. The parenthetical expression assembles a string from the string array $mySphereStringArray that is used as the first argument for setAttr (the attribute to change). The second argument is 3, the value to change the attribute to. No eval() needed.

Hope this helps. Let me know if you have any other weird issues with MEL syntax. More on this in future posts.

I'm not an arrogant prick, really!

Ok, so I know the title of this blog sounds extremely pretentious -- who am I to assume that I am some member of a computer graphics cognoscenti? I, Jonathan King, who have worked in the computer graphics industry for less than a couple years.

So first off, let me clear up any misunderstanding -- this is not a "Look at me" blog. Far from it. The reason I'm writing this blog is to catalog my "Aha!" moments. Those moments when I discover something either on my own or with the help of other people that is not obvious and I'm sure would trip up other people who didn't know.

How many times have you tried to solve a problem in CG, and you slave over it day and night, obsessing over this stupid little thing that should work but for some reason doesn't, only to have someone casually peek over your shoulder and say, "Oh, it's not working because you didn't do this, this and this." Just like that -- if only you had known that a week ago!

This blog is for those people. My goal is to reduce some frustration and help CG artists get on with what they do best -- creating awesome work. Good luck everyone!