Saturday, February 20, 2010

MEL: Remove Namespaces From A String or Object Name

Dealing with namespaces is a pain in the ass. Period.

Veteran TD's and Maya guys will tell you how easy it is and that there are so many ways to deal with them and this and that. They are correct. However, they are still a giant, giant pain in the ass.

Thankfully there's a simple trick to remove namespaces from using the tokenize MEL command.

What tokenize does is split a string into multiple parts using a character(s) as the splitting point. For example, if an object is named this_Object if you were to tokenize it and split it using the character "_" than you would end up with two tokens: "this" and "Object".

We know that if an object has a namespace, or in some cases multiple namespaces that the object name will always be prefixed with the namespace and a colon. (:)

So, let's tokenize it out using a colon.

string $objectName = "Character:r_arm_CTRL" ; // Our Object Name
string $buffer[] ; // Create Empty Array To Hold Tokens
tokenize $objectName ":" $buffer ; // Split $objectName by ":"

// Now...
string $namespace = $buffer[0] ; // "Character"
string $object = $buffer[1] ; // "r_arm_CTRL"

With this example we've done a basic namespace removal. However, this is prone to errors for multiple reasons. What if you have multiple namespaces? By hardcoding which index you're getting from $buffer you will end up potentially grabbing the wrong data. A way around this is to use a programming trick to always grab the very last item in an array. As with namespaces, we always know the last item will be the object itself so we'll end up with the correct string.

string $objectName = "Character:r_arm_CTRL" ;
string $buffer[] ;
tokenize $objectName ":" $buffer ;

string $objectWithoutNamespace = $buffer[size($buffer)-1] ;

By getting the size of the array, and subtracting one, you'll end up with the last index of a zero-based array. If it were Maxscript, arrays are one-based (they start with one, not zero) so you wouldn't need to subtract one from the size.

(If you're curious, the equivalent of tokenize in Maxscript is filterString)

So there you are, a quick, easy, non-dirty way of getting rid of namespaces in an object's name.

Friday, February 19, 2010

MEL: Source A Script With A Variable

Maya's MEL script command "source" will not let you source a path through a variable. Example, the following will NOT work.

string $myScriptPath = "C:/myScript.mel" ;
source $myScriptPath ;

It will produce a syntax error. So, how do we do it then? One method is by using the "eval" command and putting the source command into the string itself and slashing out the quotes.

string $command = "source \"C:/script.mel\" ;" ;
eval $command ;

"eval" will run the string as a command, thus sourcing it and your script/variable.

Another option here is to create your own proc, let's call it betterSource() ;

global proc betterSource (string $script) {

string $command = "source \""+$script+"\"";
eval $command ;


// Now you can run:

string $path = "C:/script.mel" ;
betterSource $path ;

Either way works and one is not necessarily better than the other.

Thursday, February 11, 2010

MEL: Snap / Move An Object To The Position and Orientation of Another Object

There's a super easy trick for snapping an object to the position and orientation of another object in your scene.

All you need to do is constrain your object with maintain offset turned off, and then delete the constraint. So, a quick and easy way to do this with point and orient constraints.

delete `pointConstraint $obj $targetObj` ;
delete `orientConstraint $obj $targetObj` ;

This deletes the return (the name of the constraint) after running the constraint itself.

Similarly you could just use a parent constraint.

delete `parentConstraint $obj $targetObj` ;

Credit to John Riggs for showing me this trick.

Tuesday, February 9, 2010

MEL: Split A Joint / Bone Chain To A Specified Number Of Joints

Here's a procedure you can use in Maya to split a joint chain into multiple joints.

This proc requires jgArrToStr which you may recognize from yesterday's post. :)

Source them both first and then run it by typing:

jgSplitJointChain joint1 joint2 4 ;

(joint1 being the parent of the two.)
(4 being an example of how many joints you want to add.)

One note, currently it assumes y-up as your secondary axis orient. Maya doesn't let you query SAO so there's no way I know of to dynamically check what to use. Change it in the proc if it's not y-up in you're setup.

// **********************************************************
// Adds A Specified Number Of Joints Into A Chain
global proc jgSplitJointChain (string $parent, string $child, int $numJnts) {

// Adjustment For Math Purposes
$numJnts++ ;

// Checks
select -cl ;
if(!`joint -ex $parent`) error ($parent+" doesn't exist in scene or is not a joint.") ; // Does Parent Exist
if(!`joint -ex $child`) error ($child+" doesn't exist in scene or is not a joint.") ; // Does Child Exist
if(jgArrToStr(`listRelatives -p $child`, 0) != $parent) error ($parent+" is not the parent of "+$child+".") ; // Check Parent/Child Relationship

// Joint Positions
float $pPos[] = `joint -q -p $parent` ;
float $cPos[] = `joint -q -p $child` ;

// Parent Orientation
string $ro = `joint -q -roo $parent` ;
string $sao = "yup" ;

// Unparent Child
parent -w $child ;

// Vector
float $jointVector[] ;
$jointVector[0] = ($cPos[0]-$pPos[0])/$numJnts;
$jointVector[1] = ($cPos[1]-$pPos[1])/$numJnts;
$jointVector[2] = ($cPos[2]-$pPos[2])/$numJnts;

// Deselect All
select -cl ;

// Loop And Setup Joints
string $lastJntCreated = $parent ;
string $newJnts[] ;
for($i = 1; $i < $numJnts; $i++) {

// Create Joint
string $jnt = `joint -p ($pPos[0]+($i*$jointVector[0])) ($pPos[1]+($i*$jointVector[1])) ($pPos[2]+($i*$jointVector[2]))` ;

if($i == 1) parent $jnt $parent ;

// Set Last Created For Reference (Updates Until Last Iteration)
$lastJntCreated = $jnt ;


// Reparent End Joint
parent $child $lastJntCreated ;

// Orient Joints
joint -e -oj $ro -secondaryAxisOrient yup -ch -zso $parent ;


If you have any trouble using this or have questions/comments, send me a note!

Monday, February 8, 2010

MEL: Trick To Pass An Array Into A String Argument

I wrote a quick proc this morning that will let me pass an array (specified index) into a string argument since Maya won't let you do it any way by default in MEL.


// Looking For This Object's Shape Node
string $object = "myObject" ;
string $shapeArr[] = `listRelatives -shape $object` ;
string $shapeNode = $shapeArr[0] ;

// The above returns an array, which is annoying. To me at least...

I'm aware you can use $shapeArr[0] as your shape node without redeclaring it into the second variable, but I've always felt it was sloppy to do it that way.

Here's a simple MEL procedure that makes it easier.

// **********************************************************
// Returns An Index From A String Array
global proc string jgArrToStr (string $array[], int $index) {

// Get Index From Array
string $obj = $array[$index] ;

// Return
return $obj ;


// Now you can do...

string $object = "myObject" ;
string $shape = jgArrToStr(`listRelatives -shape $object`, 0) ;

This will only work if you know the index you're looking for in the array, but a lot of times MEL returns string arrays when it doesn't need to and you know what it will be.

Wednesday, February 3, 2010

MEL: Working With Multiple Level Namespaces

I learned a great trick today concerning Maya scenes with objects that have multiple levels of namespaces.

Namespaces in general are a bit difficult to work with as they tend to break scripts if you don't constantly check for them, so this trick is a simple and very useful way to check for them and prevent errors.

Let's say you have an object you want to select called, "r_hand_CTRL". You want to select it, but you need to test for namespaces because it might actually be named "Char:r_hand_CTRL" in your Maya scene. Or for more fun let's say it's named, "Post:Char:r_hand_CTRL".

Selecting r_hand_CTRL isn't going to work as it doesn't exist if it's prefixed with namespaces, so we have to search for what the namespaces are. Maya's namespace MEL commands are annoying and difficult to use. So here is a trick.

// Define Control
string $ctrl = "r_hand_CTRL" ;

// This int is used below to prevent an infinite loop
int $i = 0 ;

// Loop until it finds all the namespaces
// Stop at ten if it still can't find it
// Hopefully you don't have more than ten recursive namespaces
// May the Gods help you if you do.

// Check forever until the object exists, or $i = 10
while(!`objExists $ctrl` || $i == 10) {

// Append *: until it can find the object
$ctrl = ("*:"+$ctrl) ;

// Increment $i so we don't do this infinitely
$i++ ;


// Note: You could also use a FOR loop. But I didn't here.

// Now that we know $ctrl exists, we can do whatever we want with it
select -r $ctrl ;

I've already used this trick like forty times, it's awesome. Enjoy!

Edit: Since learning this, people have mentioned that you can just use the following command to find your object:

ls -recursive 1 "myObject" ;

Quite handy, and much more useful than what we worked on above! I wish I had the entire MEL docs memorized.... :)

Scripting Topics

MEL (41) Maya (39) Scripting (32) Scripts (21) programming (14) Free Mel Scripts (8) MaxScript (7) Coding (6) Rigging (5) tutorial (5) 3ds Max (4) Python (4) Tricks (4) faceware (4) image metrics (4) Learn (3) Namespace (3) Namespacing (3) animation (3) facial (3) webinar (3) Code (2) GDC (2) Game Developers Conference (2) Multiple Namespaces (2) Print Selected Objects (2) Recursive (2) Removing Namespace (2) Return (2) Set Driven Keys (2) TOkenize (2) Tips (2) Toggle Background Color with MEL (2) animation tools (2) animators resource (2) deformers (2) learning (2) maya tools (2) mesh (2) modeling (2) nodes (2) procedure (2) script swell (2) transforms (2) Animschool (1) Attribute (1) Background Color (1) Beer (1) Blur (1) Character Setup (1) Check if an object exists (1) Class (1) Command Line (1) Constraints (1) Create SDK (1) Create a directory with mel (1) Data (1) Export (1) FilterString (1) Fix (1) Floating Slider Time (1) Functions (1) Get Maya Version MEL (1) Get Parent (1) Google (1) Holiday (1) How To Write To A Text File (1) Import (1) Incremental Save (1) Index (1) Joint Chain (1) Make Set Driven Keys (1) Maya Version (1) Modules (1) Objects (1) Orient Constraint (1) PYMEL (1) Parent (1) Parent Constraint (1) Point Constraint (1) Position (1) Print (1) Print Current Selection (1) Print Random Quotes (1) Print Selection (1) Print Vertices (1) Progress Bar (1) Progress Window (1) PyQT (1) Removing Spaces From Names (1) Scene File Name (1) Select Connections (1) Select Outgoing Nodes (1) Split Bones (1) Split Joints (1) St. Patrick's Day (1) String Array (1) System (1) Transfer UVs (1) Viewport (1) White Space (1) Windows Username (1) Zero Out Attributes (1) animButtonState (1) arrays (1) articles (1) auto key (1) better (1) blendshapes (1) break (1) confirm dialog (1) continue (1) convention (1) e3 (1) efficiency (1) error (1) eval (1) executable (1) fclose (1) fopen (1) fprint (1) games (1) improving (1) infinite loop (1) joints (1) listHistory (1) listRelatives (1) logic (1) loops (1) milestone (1) nodeType (1) objExists (1) recursion (1) rotates (1) rotations (1) schools (1) sculpting (1) setAttr (1) shout outs (1) source (1) source a script with a variable (1) speed (1) (1) translates (1) video (1) warning (1) world matrix (1) worldMatrix (1)
Script Swell - Blogged