Tuesday, 30 November 2010

Customising a Maya menu

In this post I'm going to kill two birds with one stone and cover two things;

1) A script I use pretty much every day for point, orient or parent snapping one object (the source) to another (the target). The point snap also works with a vertex selection or multiple nodes as a source.

2) How to add these to the standard Maya Constrain window




Snapping script


global proc NT_snapToObject(int $mode)
{
string $nodes[] = `ls -sl -fl`;
if (`size($nodes)` > 1) {
string $target = $nodes[`size($nodes)`-1];
string $constraints[];

if ($mode == 1) {
string $locators[];
if (`gmatch $nodes[0] "*.vtx*"`) {
for ($counter = 0; $counter < `size $nodes` -1; $counter ++) {
string $thisLoc[] = `spaceLocator`;
$locators[`size $locators`] = $thisLoc[0];
vector $vtxPos = `xform -q -ws -t $nodes[$counter]`;
setAttr (($thisLoc[0])+".translate") ($vtxPos.x) ($vtxPos.y) ($vtxPos.z);
}
select -r $locators;
select -add $target;
}
$constraints = `pointConstraint`;
vector $t = `getAttr (($target)+".translate")`;
delete $constraints;
setAttr (($target)+".translate") ($t.x) ($t.y) ($t.z);
if (`size $locators` >0)
delete $locators;
}
if ($mode == 2) {
$constraints = `orientConstraint`;
vector $r = `getAttr (($target)+".rotate")`;
delete $constraints;
setAttr (($target)+".rotate") ($r.x) ($r.y) ($r.z);
}
if ($mode == 3) {
$constraints = `parentConstraint`;
vector $t = `getAttr (($target)+".translate")`;
vector $r = `getAttr (($target)+".rotate")`;
delete $constraints;
setAttr (($target)+".translate") ($t.x) ($t.y) ($t.z);
setAttr (($target)+".rotate") ($r.x) ($r.y) ($r.z);
}
}
}

You can see the procedure has a single argument which determines whether it is a point, orient or parent snap. This value is passed from a menu.
To use, select one or more source nodes (or vertices if doing a point snap), then select the node you wish to snap last.

Modifying the Maya constraint menu to include the snap options

In my scripts directory I have one called mayaMod. In here are all scripts that are modified versions of Maya's default scripts for building UI elements and various other things. When Maya starts, these scripts are sourced and in memory overwrite the default ones with my modified versions. With this structure I still have the default versions in their original location should things go wrong.


Here you can see my customised version of AniConstraintsMenu.mel, the default version of which can be found in C:\Program Files (x86)\Autodesk\Maya2008\scripts\startup depending on your install directory.
Here is an excerpt from the modified script, the modified sections are highlighted.



menuItem -label (uiRes("m_AniConstraintsMenu.kParent"))  
-annotation (uiRes("m_AniConstraintsMenu.kParentAnnot")) 
-dmc "performParentConstraint 2"
-c "ParentConstraint"
-i "parentConstraint.xpm" 
parentConstraintItem;
menuItem -optionBox true
-annotation (uiRes("m_AniConstraintsMenu.kParentOptAnnot"))
-c "ParentConstraintOptions"
-i "parentConstraint.xpm"
parentConstraintOptionItem;

menuItem -divider true;
menuItem -label "Point Snap" 
-c ("source \""+$NT_scriptRoot+"General/NT_snapToObject.mel\"; NT_snapToObject 1;")
-i "parentConstraint.xpm" 
pointConstraintSnap;
menuItem -label "Orient Snap" 
-c ("source \""+$NT_scriptRoot+"General/NT_snapToObject.mel\"; NT_snapToObject 2;")
-i "parentConstraint.xpm" 
orientConstraintSnap;
menuItem -label "Parent Snap" 
-c ("source \""+$NT_scriptRoot+"General/NT_snapToObject.mel\"; NT_snapToObject 3;")
-i "parentConstraint.xpm" 
parentConstraintSnap;
menuItem -divider true;

menuItem -label (uiRes("m_AniConstraintsMenu.kGeometry"))  
-annotation (uiRes("m_AniConstraintsMenu.kGeometryAnnot")) 
-dmc "performGeometryConstraint 2"
-c "GeometryConstraint"
-i "geometryConstraint.xpm"
geometryConstraintItem;
menuItem -optionBox true
-annotation (uiRes("m_AniConstraintsMenu.kGeometryOptAnnot")) 
-i "geometryConstraint.xpm"
-c "GeometryConstraintOptions"
geometryConstraintOptionItem;


So here are three new menu items inserted into the constrain menu. Each one, when clicked, sources and runs the snapping script and passes an integer value to the procedure to determine whether to do a point, orient or parent snap. 

Note that the path is partially constructed from the string variable $NT_scriptRoot.
The picture below shows the top of AniConstraintsMenu procedure. $NT_scriptRoot is generated by calling a simple procedure that returns the highest level directory of all my scripts. By constructing paths in this way it is very easy to move your entire scripts directory between drives/projects/work/home as you only have a single procedure to modify to ensure that all your scripts can be sourced and run.

global proc AniConstraintsMenu( string $parent )
{
string $NT_scriptRoot = NT_getScriptRoot();
setParent -menu $parent;
if( `menu -q -ni $parent` != 0 ) {
//
// Menu is built already - just return
//
return;
}

1 comment:

  1. Hi Matt,

    Thanks for starting this blog--it's a lot of great information and I will be back regularly!

    ReplyDelete