r18 - 16 Nov 2010 - 01:44:02 - MattEstelaYou are here: TWiki >  Maya Web > WebLeftBar > MayaAnimation > MayaBatchRenderOptions > MayaCloth > MayaFluids > MayaFur > MayaJapan > MayaLightingShading > MayaLinks > MayaMelAndExpressions

MEL

Other Mel tips pages

MEL Tips 'n Nodes

Hmm, this page is getting unwieldy. Should break this up into something like Eric Pavey's excellent mel wiki, but with the stuff I constantly forget and search for near the top. Gonna stick these quick examples up here for now, will sort out properly later:

  • Convert selection to specific shapes: listRelatives -children -type "follicle"
  • Convert selection to transforms listRelatives -parents -type "transform"
  • Find other node based on connected attribute connectionInfo -destinationFromSource myFollicle.outCurve
  • listhistory example: listHistory -pruneDagObjects true -leaf false -interestLevel 1 startCurve (work on this one....)

Ls across all namespaces and references

Tell ls to be recursive:

ls -r 1 "*myShape*";

Multitude manager

Tis bril. Lets you run small snippets of mel over different kinds of selection or objects, save them as presets, great. Go get:

http://www.technolumiere.com/software/multitudeManager.html

Reorder objects in outliner via mel

Use reorder of course. This example script will take the current selection, sort it, then reorder the outliner to match:

string $sel[] = sort(`ls -sl`);
string $each;
for ($each in $sel) reorder -back $each;

Setting input components

Say you need to add more edges feeding a polyBevel node.

First you'd want to get the existing list:

getAttr polyBevel3.inputComponents;
// e[0:2] e[6:8] e[10:15] e[20:22] e[26:28] e[30:32] e[34:35] // 

by selecting an edge in the scene, I know I need to add edge 33, so I've rewritten the edge I want to this:

e[0:2] e[6:8] e[10:15] e[20:22] e[26:28] e[30:35] 

To update the polybevel node you need to tell it the number of compnents your feeding it. An array of edges counts as one, so here its 6 elements.

setAttr polyBevel3.inputComponents -type "componentList" 6 e[0:2] e[6:8] e[10:15] e[20:22] e[26:28] e[30:35] 

Not easy to remember, hence I've added it here!

Handy things for Vim, regex's

I try and maintain geek cred points by using vim for my mel hacking, I constantly forget little useful vim tricks, hence this section.

Find variables, surround in quotes (useful when constructing big strings that need escaped vars)

:s/\$\w*/"\+&\+"/g
Thats searchreplace (:s) words that start with a dollar sign ( \$\w* ) and replace with itself ( & ), but with +" "+ around it ( "\+&\+" ), and all occurrances on the line ( g ). more complex than it looks due to escaping the magic symbols. actually that'd still look complex without... Anyway, an example:
button -label "Launch foo" -c ("foo (`textFieldGrp -q -text $seqControl`)");
becomes
button -label "Launch foo" -c ("foo (`textFieldGrp -q -text "+$seqControl+"`)");

to insert vim variables like the guifont to make the vimrc while in insert mode,

C-r=&guifont
Thats ctrl-r (insert a register), = (expression register) &guifont (internal settings are preceded by an ampersand)

to insert the last typed colon-command

C-r:

to convert an unformatted chunk of XML into something useful:

:%s/></>\r</g 
:0 
=:$ 

To find span tags in some html, but leave the inner block untouched:

/<span\_.\{-}>

That means:

<span  = find the start of the span tag
\_.  = find any single character (same as . ), the \_ before it means also look search beyond linebreaks
\{-}  =  match as FEW as possible of the preceding pattern, rather than as many as possible; otherwise it'll match the entire text file.
>  = the end of the span tag.
Note that this doesn't find the matching end
</span>
tag, needs to be run seperately. I'm sure its possible....

Strip spaces and punctuation (make valid object names)

The outliner will convert spaces and punctuation to underscores when you try and rename an object, but this doesn't seem to be exposed as a mel command. There's testing functions, but no converting functions. Here's my stab. A 'while' loop is cleaner, but there's no way to stop a runaway loop in maya, which sucks, so I've gone the ugly but safer 'for' loop instead.

string $comment = "this, is a line with numbers like 0.25 and: stuff!";
string $regex = "[^a-zA-Z0-9_]";
string $replace = "_";

print ($comment+"\n");
int $i = 0;
string $match;
int $totalChars = `size($comment)`;

for ($i = 0; $i < $totalChars; $i++) {
  $match  = `match $regex $comment`;
  $comment = `substitute $regex $comment $replace`;
  if ($match == "") break;
} 

print $comment;
print "\n";

// returns "this__is_a_line_with_numbers_like_0_25_and__stuff_"

The regex means anything within a to z, or A to Z, or 0 to 9, or an underscore. The ^ in front inverts the test, so its anything NOT in those ranges, ie only spaces or punctuation. For bonus points you could process the string again to delete redundant underscores and camel-case the result, but this is fine for me for now.

Search and Replace Names

to rename and substitute object names
  • unsuported script by Alias: searchReplaceNames.mel
  • located at: mayaInstallationDirectory\scripts\others
  • searchReplaceNames("searchString","replaceString","flags");
    • flags: "all", "selected", "hierarchy"
    • example: searchReplaceNames("someName","myName","all");

Adding paths to the script path via userSetup

Tricker than I thought. Here I try to run zooHUD on startup:

   string $oldScriptPath = `getenv MAYA_SCRIPT_PATH`;
   string $newScriptPath = ("Z:/shared/scripts/zoo;" + $oldScriptPath);
   putenv MAYA_SCRIPT_PATH $newScriptPath;
   rehash;

   source zooHUD;

It'll complain that it can't find zooHUD, even though you can see the path added if you run 'getEnv'. Instead, you'll have to wrap the last line in an eval:

   eval("source zooHUD");

Any scripts in the new folders will need to be wrapped this way, maya doesn't register the new paths until after userSetup finishes.

Padding object names

This tip from Rob Pieké via the highend3d list:

global proc string padzero( int $num, int $maxDigits )
{
   string $result = "";
   int $i;
   for( $i = log10( $num ); $i < $maxDigits-1; $i++ )
   {
    $result += "0";
   }
   return ( $result + $num );
};

Then: print ("myObject_"+padzero(12,4)); Yields: myObject_0012

Get all verticies in an array

ls -fl "pCube1.vtx[*]";

Create particles on selected verticies

This is a quick MEL to create particles on selected vertices on a polyogn object. Quite useful, when you want to simulate some softbody stuff, off, some model. Usage : Select the required vertices on a polygon and execute the function -> AshPartsOnVerts? ();

global proc AshPartsOnVerts()
{
string $objsVertexess[]=`ls -sl -flatten`;
string $particleCreator="particle ";
for ($i=0;$i<size($objsVertexess);$i++)
{
vector $eachVertPos=`xform -q -ws -t $objsVertexess[$i]`;
$particleCreator=($particleCreator+ ("-p "+($eachVertPos.x)+" "+($eachVertPos.y) +" "+($eachVertPos.z)+" "));
}
$particleCreator=($particleCreator+"-c 1;");
eval ($particleCreator);
print ("Particles created for vertices :\n");
print ($objsVertexess);
}

- Happy MELing ! AshishDantu?

textscroll lists

A nice example by Kevin Mannens to list all lights in the scene, and give you the option to turn off the specular attribute for lights you select from the list. Source this script and run 'lightUI'.

global proc lightUI()
{
if (`window -exists lightWin`)
   deleteUI lightWin;

window lightWin;

columnLayout -adj 1 TSLColl;
textScrollList    -h 150 
-allowAutomaticSelection  on
-allowMultiSelection  on
   lightTSl;
button -l "turn off specular" -c "turnOffSpecular()"
offButton; 
populateTSL;
showWindow lightWin;
}

global proc populateTSL()
{
//get all lights
string $list[] = `ls -lt`;
//loop through the string array...
for ($eachLight in $list)
   {//...and put in TSL
   textScrollList -e -a $eachLight lightTSl;
   }
}

global proc turnOffSpecular ()   
{
string $selInTSL[] = `textScrollList -q -si lightTSl`;
for ($each in $selInTSL)
   {//...and turn of emitSpecular
   setAttr ($each + ".emitSpecular") 0;
   }      
}

attributeExists vs ls

Andy Walker posted this handy tip to the highend3d mailing list:

You should probably check the attribute exists before you set it, ls is the quickest function to use for this (attributeExists is one of the strangely slowest MEL procedures out there..):

if(size(`ls ($list[$i] + ".emitSpecular")`)) setAttr ($list[$i] + ".emitSpecular") 0;

Quickly assign random rotations to the selected objects

Select your required objects and run this script. sorry Ashish, I edited this a bit to use the cleaner each in selected loop type. -matt

* hi matt, thank you for changing it to this for loop. But i've changed the setAttr lines to use $each or else it will give error,variable $i not declared.

global proc randrots()
{
   string $selected[]=`ls -sl`; // selected objects are stored in this array 
   string $each;

   print ("objects selected : \n");
   print $selected;

   for ($each in $selected)
   {
      setAttr ($each+".rx") (rand(360)); // using setAttr to set the rotations of the object to random values between 
      setAttr ($each+".ry") (rand(360));
      setAttr ($each+".rz") (rand(360));
   }
}

Make only the selected camera renderable

  • Borrowed the first function from Bryan Ewert, cos he rocks so hard.

proc string getShape( string $xform ) {
  string $shapes[];

  $shapes[0] = $xform;

  // If given node is not a transform, assume it is a shape 
  // and pass it through.
  if ( "transform" == `nodeType $xform` ) {
    $shapes = `listRelatives -fullPath -shapes $xform`;
  }

  return $shapes[0];
}

global proc setCurrentCameraRenderable() {
   string $cameras[] = `ls -type "camera"`;
   string $selection[] = `ls -sl`;

   // check we only have one object selected, and that its a camera

   if (`size($selection)` != 1) {
        warning("please select only one camera");
       return;
   }

   string $camera = getShape($selection[0]);

   if(`objectType -isType "camera" $camera`) {
       for ($each in $cameras) {
          setAttr ($each+".renderable") 0;
       }
       setAttr ($camera+".renderable") 1;
       print ($selection[0]+" set as only renderable camera");
   } else {
       warning("selected object isn't a camera");
   }   
}

Build UIs quickly

Curve pivot to curve origin

  • Sets selected curves pivot to first/origin CV.
string $selection[] = `ls -sl`;

for($curve in $selection) {

   float $curveOrigin[3] = `pointPosition -w ($curve + ".cv[0]")`;
   move -a $curveOrigin[0] $curveOrigin[1] $curveOrigin[2] ($curve + ".scalePivot") ($curve + ".rotatePivot");
}

Get an attribute from the previous frame

  • Say you needed to sample a motionpath value at the previous frame, to work out velocity or follow-through:
getAttr -time (frame - 1) motionpath1.uValue;

Copy attributes from an object to another

  • Don't know if their is a way to do it through the Maya UI, but here is a scripted way.

// Select first the object you want to copy the attr to the second selected object

string $attrList[] = {"tx", "ty", "tz", "rx", "ry", "rz", "sx", "sy", "sz"};

string $sel[] = `ls -sl`;

string $attr;

for($attr in $attrList) {

setAttr ($sel[1] + "." + $attr) `getAttr ($sel[0] + "." + $attr)`;

}

-- NicolasdHaussy? - 06 May 2005

Return results from functions

  • Most of maya's builtin functions return a string (or strings) of the result of their operation. Can be handy to immediately assign this to a variable, in case you need it later.
// the curve function returns the name of the created curve
string $thisCurve = `curve -d 1 -p 0 0 0 -p 1 0 0 -name "myCurve"`;

// the extrude function returns an array of strings,
// the first is the surface, the second the extrude node
string $result[] = `extrude -n "mySurface" $thisCurve`;

string $surface = $result[0];
string $extrudeNode = $result[1];

Does xyz exist?

  • Use 'objExists':
if (`objExists "xyz"`) {
     // objExists, do something
}

  • So if something needs to be created once, and only once, negate the test:
if (!`objExists "xyz"`) {
     createNode xyz;
}

Sets

  • Create a set by choosing some objects, and go create -> sets -> option box, or use create -> quick select set
  • Query the members of a set:
sets -q mySet;

  • So we can select the members of a set with
select `sets -q mySet`;

  • Or just:
select mySet;

  • Use -noExpand (or -ne) to select the set itself:

select -ne mySet;

  • A handy trick is to get the intersection of 2 sets. Say you have a lattice partially deforming 2 objects, and you need to get the deformed points in one object. Create a quick select set of one objects verts, then run:

select `sets -int ffd1Set myQssSet`;

  • To create sets for particles and emiters quickly from a scene :

global proc Ashpartsset()
{
select -r `listTransforms "-type particle"`;
$createSetResult = `sets -name ParticleSet`; // Creates a set named ParrticleSet - quickly allows you to select particles shapes in your outliner

}
global proc Ashemiterset()
{
string $emiterssel[]=`ls -typ "pointEmitter"`;
for ($i=0;$i<size($emiterssel);$i++)
{
select -add $emiterssel[$i];
}
$createSetResult = `sets -name EmiterSet`; // Creates a set named emiterSet - quickly allows you to select emiters shapes in your outliner

}

Selection wrangling

  • Getting a bunch of similar values from the current selection, and return an array.
proc float[] getPathVars() {
   string $selection[] = `ls -sl`;
   int $selectionSize = `size $selection`;
   float $pathArray[];
   for ($i = 0; $i < $selectionSize; $i++) {
      $pathArray[$i] = getAttr ($selection[$i]+".pathU");
   }
   return $pathArray;
}

  • Return the children of the current node. TODO: How do we make it not add the current node?
proc returnChildren() {
   string $children[] = `ls -dag -o -sl -tr`;
   for ($each in $children) {
      print ($each+"\n");
   }
}
returnChildren;

--Edit--
Here's how to get the entire hierarchy under the current node WITHOUT returning the node itself (solution to the TODO above)

proc returnChildren() {
   string $children[] = `listRelatives -allDescendents`;
   for ($each in $children) {
      print ($each+"\n");
   }
}
returnChildren;

-- SeanFennell? Oct 19, 2005

Size of objects/arrays

  • Use the size function.

int $asize = size($a); 

Select all poly children

Useful if you have a big parenting scheme of locators joints curves etc, but only want to set attrs on the meshes:

select -hi;
select `listRelatives -fullPath -shapes -type mesh`;

Flipping an array

  • We get the size of the array, create a temp array, then iterate through, reversing the array values as we go.

proc float[] reverseFloatArray(float $a[]) {  
        int $asize = `size($a)`; 
        float $tempArray[]; 
        for($i = 0; $i < $asize; $i++) {  
                $tempArray[$i] = $a[$asize-$i-1];  
        } 
        return $tempArray;  
}  

Defining a function

  • Slightly different from C, but not too much:

proc myFunc() {
   print("Hello World!\n");
}

  • To define a return values, put it before the name, but after proc:
proc string myFunc2() {
    return "Hello World!\n";
}

  • To make it callable from a script, name the mel the same as the function, and use

global proc myGlobalProc() {
   print("Hello World!\n");
}

A for loop

  • Again, just like in C:

int $i;
for ($i = 0, $i < 10, i++) {
    print($i);
}

  • A handy shortcut for a selection is the each in selection style loop, very python:

string $selection[] = `ls -sl`;
string $each;
for ($each in $selection) {
    print($each);
}

addAttr

  • How to add an attribute myVariable to mySphere so that it has a slider, but isn't a fixed range:
addAttr -ln myVariable -at double -smn 0 -smx 1 -dv 0.05 mySphere;

setAttr and getAttr

  • Little fiddly, but not too bad once you get the hang of it. Still not as easy as using direct assignment like you can do in expressions, but sometimes you have no other choice.

// usage: setAttr object.property variable;

string $myObject = "nurbsSphere1";
setAttr ($myObject+".scaleX") 5;

// a bit more painful for some data types, like strings

setAttr -type "string" ($myObject+".ribArchive") "/tmp/some.rib";

  • similar for getAttr:

// usage: getAttr object.property;

string $myObject = "nurbsSphere1";
print `getAttr ($myObject+".scaleX")`;

Connecting several polysmooths to a custom attribute

  • On creating a 'smooth' attribute on a model named 'myModel', this script will connect it to all the polysmooths in that models history.
proc doThis() {
   string $select[] = `ls -type "polySmoothFace"`;
   for ($each in $select) {
      connectAttr -f myModel.smooth ($each+".divisions");
   }
}
doThis;
  • A better option would be something similar to max's polysmooth; override the standard polysmooth attribute editor so that it has 2 extra attribute when created; viewport iterations, and render iterations. This'd be linked to pre/post render scripts to set the polysmooth iterations high during a render, but low any other time. Ie, subdivs without all the, ahem, issues of maya subdivs. I'm sure someone's written this on highend3d somewhere, I just haven't looked hard enough.
  • On this topic, everyone knows that polysmooths in maya 5 correctly smooth UVs too? That just rocks my world... =)

Want to know the Shading goups on an object?

  • There are a few ways, like getting the history and the looking for a shadingEngin node, but this is certainly the simplest I have found.
listSets -type 1 -o myObjectShape

-- Edit --

A shortcut which allows you to feed the object instead of the objectShape:

listSets -type 1 -ets -o myObject;

- SeanFennell? Oct 19, 2005

Expressions

Finally, an expression tip!

Force expression to evaluate

getAttr expression1.evaluateNow

can throw that into your preframe mel if things aren't behaving.


Keywords: Info, maya, expressions, mel

Edit | WYSIWYG | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r18 < r17 < r16 < r15 < r14 | More topic actions
Main.MayaMelAndExpressions moved from Main.MelAndExpressions on 31 May 2003 - 02:06 by MattEstela
 
Powered by TWiki
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback