Archive for the ‘Python’ Category

Protected: Labyrinth for Maya

Saturday, June 5th, 2010

This content is password protected. To view it please enter your password below:

Maya Scripting – Working with vectors in Python

Tuesday, May 4th, 2010

I avoided writing anything model-related in python for ages because I thought it didn’t have a native vector data type like MEL does. It doesn’t as it happens, but OpenMaya comes with one that is really simple to use and understand called: MVector.

Ryan Trowbridge has already gone over the basics of this on his blog, but I thought I’d cover it in a bit more detail, especially with some real-world examples.

The first thing you have to do is import the MVector class from the OpenMaya module:

from maya.OpenMaya import MVector

Once this is done you can start creating vectors like so:

X = MVector(1.0, 0.2, 0.3)
Y = MVector(0, 1, 0)

The MVector simply takes 3 floats which represent the x, y and z components of the vector. You can’t, unfortunately, print out the MVector values by refering directly to it:

print X
<maya.OpenMaya.MVector; proxy of <Swig Object of type 'MVector *' at 0x18b95ad0> >

but you can refer to the individual components:

print X.x
# 1.0
print X.y
# 0.2
print X.z
# 0.3
print X.x, X.y, X.z    # in one line
# 1.0 0.2 0.3
mc.setAttr('pCube1.tx', X.x)    # use as you would ordinary float variables

You can also do cool and useful stuff with the vectors very easily:

mag = X.length()    # gets the vector magnitude(length)
print mag
# 1.06301458127
X = X.normal()    # normalises the Vector

Z = X^Y    # the ^ character is a shortcut for the CrossProduct function
d = X*Y    # the * returns the dotProduct if both items are vectors
Yb = Y*5.0    # but if one item is a single number it simply multiplies the vector
print Yb.x,Yb.y,Yb.z
# 0.0 5.0 0.0

If you want to capture command output into an MVector it’s just as easy as with MEL, you just have to add one minor addition, the * character:

V = MVector(*mc.pointPosition('pCube1.vtx[0]'))

The * character, in front of a list in python is kind of like shorthand for “unpack”. Because MVector expects 3 individual floats (doubles actually, but that’s splitting hairs!) you cannot legally pass it a list, even if the list is 3 elements long. The * tells the list to “unpack” itself into it’s constituent elements, so the MVector accepts it. This also holds true for anywhere in python where you need to pass a list in as individual params.

There’s a lot more you can do with MVectors, but I hope this basic stuff is enough to help you replicate what you can do with vectors in MEL. If you want to check out the more complex MVector methods and uses have a look in the Maya API – MVector docs

Code Syntax Highlighting – part II

Saturday, April 17th, 2010

Seeing as how this is supposed to be (partially at least) a MEL and Python code blog I thought it only proper that I set up some kind of code syntax highlighting.
However, if I’d known what utter hell it was going to be I may have reconsidered. It’s taken me basically the whole day to get this much working and that’s only due to the help of a WordPress/PHP savvy mate (cheers John).

The first thing I tried was Code-Snippet, which seems pretty good and allowed me to easily write and impliment a new MEL syntax file. But I couldn’t get the colours to change from the defaults, it used the wrong kind of quotes (not good for MEL/py code!) and I couldn’t get word-wrapping to turn off either..! so I ditched that and tried SuperHighlighter Evolved.

SuperHighlighter Evolved seemed great but I couldn’t make that work like the site said it would either. Additionally, creating a new colour theme or Syntax file required a degree in scripting this kind of crap as well as a full understanding of WordPress’s underlying PHP gobbledegook. Goodbye SuperHighlighter Evolved…
 
Finally I plumped for Syntax Highlighter and Code Prettifier (by Vijesh Mehta) which seems to almost work so far.. once I’ve hacked around with the settings a bit! ­čśŤ

like so:

MEL Script :

// this proc returns the id number(s) of the scriptjob(s) using the given command (if existing)
// this can be used not only to simply query the scriptjob Id so you can edit or kill it, but
// also as a true/false exists check as it returns false if the scriptjob is not found.
global proc int[] getScriptJobID(string $command)
{
	string $sjs[] = `scriptJob -lj`;	// list ALL jobs
	int $jobs[] = {};
	for ($sj in $sjs)
	{	// loop through each job description looking for our command string
		if (`gmatch $sj ("*"+$command+"*")`)
		{
			string $token[];
			tokenize $sj ":" $token;
			$jobs[size($jobs)] = $token[0];
		}
	}
	return $jobs;
}

Python Script:

def typecastString(inputStr):
	"""Given an input STRING this returns it cast into the correct type;
	int, float, or string depending on what it contains."""

	inputStr = str(inputStr)	# just in case the input is not a string

	output = inputStr

	if inputStr.isdigit():
		output = int(inputStr)
	elif inputStr.replace('.','',1).isdigit():
		output = float(inputStr)

	return output

Breaking infinite loops in MEL

Friday, August 22nd, 2008

Quite often, especially when you are writing and testing a new MEL script, you’ll inadvertently create a for or while loop that never exits. Usually due to a testing condition that never becomes true, 99% of times it’s probably due to a dumb oversight that is (hopefully) picked up during initial testing/debugging, but infinite loops can still sometimes occur in production scripts. Even if you haven’t got stuck in an infinite loop you may suddenly realise that you’ve started a script with the wrong type of, or too many, components selected and the script will be churning away for a good 2-3 hours if not interrupted!

Once a bit of MEL enters such a loop there is no way of breaking out of it other than killing Maya’s process from the Windows Task Manager. Obviously this is a bit of a tedious job at the best of times, especially if it’s a script that needs thorough testing, but what if your loop-locked script was running on a scene you’d not saved for a couple of hours?

Here’s an excellent and, so far, bulletproof (touch wood) method of protecting yourself and your scripts. Because Maya has locked up at this point we can’t issue any kind of command or process from Maya. We can however issue a command from outside Maya, say from DOS…

If you create a batch file somewhere on your PC with the following content:

@echo off
echo This file breaks infinite loops in MEL scripts > c:\breakMel
pause Maya halted - Press any key to continue
del c:\breakMel

call it HALTMAYA.bat or STOPLOOP.bat or whatever name works best for you so you don’t forget what it’s for. If you have no idea what a batch file is, simply copy and paste the above code into a text file and save it as one of the names suggested above (make sure you don’t have file extensions hidden in windows!).

Now, when you run this batch file it should open a DOS shell window and prompt you to press a key to continue. Pressing a key dismisses the DOS box…

So? what exactly did this do and how does it help us stop an infinite loop??

Well if we take a look at the batch code it should be relatively self explanatory, even if you don’t know any DOS batch commands. The first line simply hides the echoing of commands (kinda like Maya script Editor “Echo All Commands” set to “off”). The second line echos the specified sentence, but the important bit is the > at the end. This > symbol tells the echo commad to redirect the echoed words into a file instead of onto┬áthe screen. That’s why you never see these words printed in the DOS window, they are sitting in a file called “breakMel” on the root of your C: drive. Of course you can change these words and the name of the file, as they are entirely irrelevant and no-one will ever see either of them. All that’s important here is that a detectable file has been created.┬áThe third line simply pauses DOS and prompts you to press a key. This is vitally important because we’ve no idea how long the┬árogue MEL script will take to get once through the loop it’s stuck in, and we need to ensure that it detects the breakMel file we’ve just created. The pause allows us to sit and wait for the loop to detect the file before we proceed to the fourth and final line which deletes┬áit. If we don’t delete the break file your MEL script will find it again next time it is run and halt immediately!

So, the final piece of the puzzle.. how does your MEL script detect the creation of this file? It’s quite straightforward; you just put a single line inside the loop in your MEL script:

if (`filetest -f "c:/breakMel"`) break;

Every iteration through your loop will look for the existence of a file called “c:\breakMel” and if it exists it will break out of the loop. If you have more than one nested loop though, you will either need to put the same line in each nested level of the loop or change the break command into an error, which is a lot simpler:

if (`filetest -f "c:/breakMel"`) error "User broke out of infinite loop!";

Believe it or not, adding this command doesn’t appear to have any noticeable effect on the performance speed of a script. I initially thought checking for a file would take MEL ages but surprisingly it doesn’t, at least not in this context. I’ve run timing tests with and without this line and there’s no significant difference, so you don’t need to worry about adding this feature to all your scripts. Of course, once you’re convinced your script is fully robust enough that it can’t get stuck in an infinite loop you can always remove this line, but it won’t hurt if you do decide to leave it in.

The other good thing about this trick is that it has no dependencies, so you can safely distribute the script to anyone without worrying that the line will cause any kind of problems at their end, as it’s unlikely anyone will ever have a file called “breakMel” on their C:\ drive!

You can do a similar thing in Python:

import os
if os.path.exists("c:/break"): break