Wednesday, December 15, 2010

Simple HUD Buttons

hudButton is a command that kind of flies under the radar mostly, but can be useful. For example making a HUD button that hides nurbs curves in the perspective view:

global int $gCurvesHudActive;
// this procedure could be combined into a single line and put in the button command
// but wouldnt fit in the blog post :D
global proc ToggleNurbsCurves() {
int $nurbsActive = `modelEditor -q -nurbsCurves modelPanel4`;
if ($nurbsActive == 1) hudButton -e -l "Show Nurbs Curves" HUDCurvesButton;
else hudButton -e -l "Hide Nurbs Curves" HUDCurvesButton;
modelEditor -e -nurbsCurves (abs(($nurbsActive)-1)) modelPanel4;

if ($gCurvesHudActive == 0) {
hudButton -s 8 -b 1
-vis 1
-l "Hide Nurbs Curves"
-bw 150
-padding 2
-bsh "roundRectangle"
-rc "ToggleNurbsCurves()"
$gCurvesHudActive = 1;
else {
headsUpDisplay -remove "HUDCurvesButton";
$gCurvesHudActive = 0;

Wednesday, October 20, 2010

Select UV Border Edges

Selecting border edges for the most part is relatively easy, but if you have a model where an internal edge shares the same vertices as two border vertices, it will also select those edges (ex. - a square polygon subdivided diagonally across the center into triangles). This fixes that problem (as long as the object is bigger than a square, which 99% of the time it is) source

// select UV border edges and remove edges that share uvs with the borders
// thus eliminating any unwanted internal edges
string $currSelected[] = `ls -sl -o`;
string $temp[] = `ls ($currSelected[0]+".map[*]")`;
select $temp;
polySelectBorderShell 1;
PolySelectConvert 20;
string $potentialEdges[]=`filterExpand -ex 1 -sm 32`;
string $removedEdges[];
for($eachEdge in $potentialEdges)
string $uvs[] =`polyListComponentConversion -fe -tuv $eachEdge`;
$uvs = `ls -fl $uvs`;
$removedEdges[size($removedEdges)] = $eachEdge;
select -d $removedEdges;

Monday, October 11, 2010

Soft influence falloff for objects

These two procedures will take an object, and influence surrounding objects based on their distance from the object, and a falloff distance specified. Similar to how the Soft Modification Tool works for meshes, but this is for objects.


global proc jsCreateSoftSelectLoc(string $locator, string $objects[], float $falloffDistance) {

float $start[] = `xform -q -ws -piv $locator`;

for ($i=0;$i<size($objects);$i++) {
float $offsetVal[];
float $curPos[] = `xform -q -ws -piv $objects[$i]`;

// make a distance dimension node to find the distance, then find the ratio based of the input
string $dis[] = jsCreateMeasureTool($locator,$objects[$i]);
float $distance = `getAttr ($dis[0]+".distance")`;
float $disRatio = $distance / $falloffDistance;
if ($disRatio > 1) $disRatio = 1;
$disRatio = 1 - $disRatio;
delete $dis[0] $dis[1] $dis[2];

// get the original distance between them
$offsetVal[0] = $start[0] - $curPos[0];
$offsetVal[1] = $start[1] - $curPos[1];
$offsetVal[2] = $start[2] - $curPos[2];

// make it so we can just add a value to them by finding the orig pos
string $plusNode = `shadingNode -asUtility plusMinusAverage`;
connectAttr ($plusNode+".output3D") ($objects[$i]+".t");
setAttr ($plusNode+".input3D[0]") $curPos[0] $curPos[1] $curPos[2];

// add the distance minus the orignal offset
string $addNode = `shadingNode -asUtility plusMinusAverage`;
string $multNode = `shadingNode -asUtility multiplyDivide`;
connectAttr ($locator+".t") ($addNode+".input3D[0]");
setAttr ($plusNode+".input3D[1]") $offsetVal[0] $offsetVal[1] $offsetVal[2];
setAttr ($addNode+".operation") 2;
connectAttr ($addNode+".output3D") ($multNode+".input1");
setAttr ($multNode+".input2") $disRatio $disRatio $disRatio;
connectAttr ($multNode+".output") ($plusNode+".input3D[1]");


global proc string[] jsCreateMeasureTool(string $start, string $end) {
string $return[0];
float $startPos[0];
float $endPos[0];
$startPos = `xform -q -ws -rp $start`;
$endPos = `xform -q -ws -rp $end`;
$tmpLoc = `spaceLocator -name ($start + "_distanceStart")`;
$tmpLoc2 = `spaceLocator -name ($end + "_distanceEnd")`;
move -a -ws $startPos[0] $startPos[1] $startPos[2] $tmpLoc[0];
move -a -ws $endPos[0] $endPos[1] $endPos[2] $tmpLoc2[0];
$dimension = `createNode distanceDimShape `;
connectAttr ($tmpLoc[0] + ".worldPosition[0]") ($dimension + ".startPoint");
connectAttr ($tmpLoc2[0] + ".worldPosition[0]") ($dimension + ".endPoint");
$parent = `listRelatives -f -p $dimension`;
$newName = `rename $parent[0] ($start + "_distance")`;
$return[0] = $newName;
$return[1] = $tmpLoc[0];
$return[2] = $tmpLoc2[0];
return $return;

Friday, September 24, 2010

Finding the perfect pole vector postion

Simple trick to finding the perfect pole vector position, so that when you create your constraint, your joint chain wont move at all! :)

// ik chain joint list
string $ikJoints[] = {"joint1","joint2","joint3"};
// find joint positions
float $pos1[] = `xform -q -ws -piv $ikJoints[0]`;
float $pos2[] = `xform -q -ws -piv $ikJoints[1]`;
float $pos3[] = `xform -q -ws -piv $ikJoints[2]`;
// create a 3 vertex plane between the joints and add a move vertex node
string $rpPlane[] = `polyCreateFacet -ch on -tx 1 -s 1
-p $pos1[0] $pos1[1] $pos1[2]
-p $pos3[0] $pos3[1] $pos3[2]
-p $pos2[0] $pos2[1] $pos2[2]`;
string $polyMove[] = `polyMoveVertex -constructionHistory 1 -random 0 ($rpPlane[0] + ".vtx[2]")`;
// now move that vertex back or forwards or whatever direction you need
setAttr ($polyMove[0] + ".localTranslate") -type double3 0 -5 0 ;
// snap your controller to the vertex and it'll be in the perfect position!

jEdit as a Mel IDE

Everyone has opinions about what the best editor for MEL is, but for me it's jEdit. So I'm going to share my setup and how I use it.

Step 1: Syntax Highlighting
First off get jEdit ( You'll need syntax highlighter for Mel which you can get here.

Once you have them both extract the highlighter and put it in your installation directory here (C:\Program Files\jEdit\modes) but be sure not to overwrite the existing catalog file, simply open the mel on and copy the contents to the end of the existing one.

That should do it for highlighting, you can adjust the colors in your Utilities -> Global Options, under Syntax Highlighting. Mine is setup like this.

Step 2: Auto Completion
A great plugin is TextAutoComplete which you can download under Plugins -> Plugin Manager. This will auto complete commands that you previously have typed in your buffer, standard in most editors.

Step 3: Buffer Tabs
Get this plugin in the Plugin Manager as well, makes tabs similar to your web browser for open files.

Step 4: MEL Parsing
Now this is by far the most complex and in some cases most useful tool. It will parse the current buffer and find procedures, variables, whatever u want basically. What it finds can be modified using regular expressions. It uses two plugins and some 3rd party software that pipes into jEdit. So in the plugin manager download CtagsSideKick and SideKick. You will also need to download Exuberant Ctags ( Get the source and binary zip file.

Now extract those files into your .jedit folder under a new directory (C:\Documents and Settings\USERNAME\.jedit\ctags\) and copy that path to the ctags Path Field under the CtagsSideKick Plugin Options inside of jEdit, so it shoulder read: C:/Documents and Settings/jacob.schieck/.jedit/ctags/ctags.exe If you don't do this it wont work.

Next you want to navigate to your user profile directory (C:\Documents and Settings\USERNAME\) or just %USERPROFILE% will take you there and make a new text document with the following contents:


--regex-mel=/\[ \t]*([$]+[a-zA-Z0-9_$]+)/\1/var string/
--regex-mel=/\[ \t]*([$]+[a-zA-Z0-9_$]+)/\1/var integer/
--regex-mel=/\[ \t]*([$]+[a-zA-Z0-9_$]+)/\1/var float/
--regex-mel=/\[ \t]*([$]+[a-zA-Z0-9_$]+)/\1/var matrix/
--regex-mel=/\[ \t]*([$]+[a-zA-Z0-9_$]+)/\1/var vector/

--regex-mel=/^global proc([ \t]|string|int|float|matrix|vector|\[\])*([a-zA-Z0-9_]+)/\2/global procedure/
--regex-mel=/^proc([ \t]|string|int|float|matrix|vector|\[\])*([a-zA-Z0-9_]+)/\2/local procedure/

--regex-C++=/[ \t]+\b(M[A-Za-z]+)[ \t]+([a-zA-Z0-9_]+)/\1 \2/maya api/

Save it out as ctags.cnf. This will tell the ctags.exe how to parse apart you mel script into finding variables and procedures. Personally I don't use the variables and just use procedures so if you don't want them just delete those lines.

Next you need to set up an environment variable pointing to that file. Technically, it's supposed to work without this step but it was the only way I got it work with jEdit. Right click on My Computer and click Properties. Go to the Advanced tab and at the bottom open up Environment Variables. Create a new User Environment Variable with the variable name "Files" without quotes and set the value to the path of your configuration file (C:\Documents and Settings\jacob.schieck\ctags.cnf;)

Alright now that should be it! Open up jEdit, under your SideKick Plugin Options under the Parser sections find mel and set it to ctags. Now open a mel script, and under Plugins -> SideKick, click SideKick and a window should pop-up that lists all your procedures and variables. If it doesn't make sure the dropdown box at the top says ctags, if it doesn't change it and if it still doesn't work then something is wrong. Run through again and make sure you didn't miss any steps and if you still can't figure it out let me know and I'll try to help you out.

And that's basically it! Those are all the plugins I use. I no longer use SendToMaya or whatever it was called, I just save and source my scripts manually now.

Friday, September 17, 2010

Substep Matrix

Finding middle points is easy, but what if you want to find a bunch of midpoints or evenly space out objects between two points. This little proc will generate a matrix of positions that are evenly spaced between two nodes.

global proc matrix jsGenerateSubStepMatrix(string $obj1, string $obj2, int $divisions) {
string $objs[] = {$obj1, $obj2};
matrix $subStepPos[20][3];

float $position1[] = `xform -q -ws -t $objs[0]`;
float $position2[] = `xform -q -ws -t $objs[1]`;
float $divideVec[];
$divideVec[0] = ($position2[0] - $position1[0]) / ($divisions - 1);
$divideVec[1] = ($position2[1] - $position1[1]) / ($divisions - 1);
$divideVec[2] = ($position2[2] - $position1[2]) / ($divisions - 1);
for ($i=0; $i<$divisions; $i++) {
$subStepPos[$i][0] = $position1[0] + ($divideVec[0] * $i);
$subStepPos[$i][1] = $position1[1] + ($divideVec[1] * $i);
$subStepPos[$i][2] = $position1[2] + ($divideVec[2] * $i);
return $subStepPos;

Tuesday, September 7, 2010

SMTP Email Delivery

Here is some basic code that allows you to send an email using python, which of course can then be called from MEL.

def basicEmail(fromAddr,toAddr,subject,messageBody,debug=False):
import smtplib
toList = toAddr
if type(toAddr) == list:
toList = ', '.join(toAddr) # this is a single string ,separated list of the to: adresses
mail = ('From: '+fromAddr+'\r\nTo: '+toList+'\r\nSubject: '+subject+'\r\n'+messageBody)
server = smtplib.SMTP('')
server.login('pym***', 'pym***')
print "Successfully sent email"

basicEmail('','',' test','this is the msg body')