Archive for MEL

Script: Cartoony Wheel Rig v1

Script: Cartoony Wheel Rig v1

When rigging vehicles you’ll usually have to deal with at least two wheels, and (especially if you’re going cartoony) you’re going to waste a lot of time if you’re rigging them manually, one by one. So I decided to write a script for this, the script is supposed to do all of the work automaticly, and it should work with wheels regardless of size and position.

The requirements I set for the rig was that it had to be clean, fast and flexible. It should also be animation friendly, so the controllers have to be logical and easy to select. With this current version of the rig I’m not too happy with the flexibility in particular, it works, but it can’t be pushed as far as I want it to. I’m going back to the drawing board.

Here’s the script in action:

The current version is basicly just a lattice with some clusters, and a nurbs-circle with all of the extra-controllers connected to the circle through MotionPath-nodes. As for the main controllers, I have a contact-controller for floor contact, two controllers for the rolling of the wheel, and one main-controller for translation/rotation/scaling.

 

jh_wheelRigger (Cartoony Wheel Rig)

//*************************************************************************************************************

// Title: jh_wheelRigger.mel
// Author: Jørn-Harald Paulsen
// Created: July 20, 2012
// Last Update: July 23, 2012
// Description: Utility to rig wheels with lattice and joints.
//*************************************************************************************************************
// MAIN WINDOW
//*************************************************************************************************************
global proc jh_wheelRigger()
{
//Close window if it already exists
if (`window -q -ex jh_wheelRigger`) deleteUI jh_wheelRigger;

//Main Window
window -topEdge 30 -title “Wheelrigger”
-mxb false -s true -rtf false -mb false -mbv false -w 412 -h 268 jh_wheelRigger;

//Window content
columnLayout -adjustableColumn true;
text -label “\nMake sure your wheel is pointing in Z, so if it were to roll” -fn boldLabelFont;
text -label “it would roll forward in positive Z. Also make sure that your” -fn boldLabelFont;
text -label “wheel-geo is grouped, and has it’s pivot in the center.” -fn boldLabelFont;
separator -w 240 -h 40;
text -label “Enter the prefix for the wheel (example: car_l_front_):”;
textField prefixField;
separator -w 240 -h 40;
button -label “Load the wheel-geo group” -c jh_loadWheelGeo;
textField -en 0 wheelGeoField;
separator -w 240 -h 40;
button -label “Rig the wheel” -c jh_rigWheel;
separator -w 240 -h 40;
window -e -w 412 -h 268 jh_wheelRigger;
showWindow jh_wheelRigger;
}

global proc jh_loadWheelGeo()
{
//Get the selected object
string $selObj[] = `ls -sl`;
//Add it to the textField
textField -e -text $selObj[0] wheelGeoField;
}

global proc jh_rigWheel()
{
//Get the group with the wheel
string $wheelGeo = `textField -q -text wheelGeoField`;
//Get the prefix
string $prefix = `textField -q -text prefixField`;
//*************************************************************************************************************
// CREATE THE GROUPS NEEDED
//*************************************************************************************************************
string $wheelGrp = `group -em -n ($prefix + “wheel_grp”)`;
string $wheelGeoGrp = `group -em -n ($prefix + “wheel_geo_grp”)`;
string $clusterGrp = `group -em -n ($prefix + “wheel_cluster_grp”)`;
string $latticeGrp = `group -em -n ($prefix + “wheel_lattice_grp”)`;
string $controlGrp = `group -em -n ($prefix + “wheel_ctrl_grp”)`;
//*************************************************************************************************************
// CREATE/POSITION THE CONTACT-CONTROLLER
//*************************************************************************************************************
//Get the boundingBox of the wheel
float $boundingBox[] = `xform -q -bb $wheelGeo`;
//Create a contact-controller
string $contactCtrl = `curve -d 1 -p -1 0 -4 -p 1 0 -4 -p 1 0 -3 -p -1 0 -3 -p -1 0 -2 -p 1 0 -2 -p 1 0 -1 -p -1 0 -1 -p -1 0 0 -p 1 0 0 -p 1 0 1 -p -1 0 1 -p -1 0 2 -p 1 0 2 -p 1 0 3 -p -1 0 3 -p -1 0 4 -p 1 0 4 -p 1 0 3 -p -1 0 3 -p -1 0 2 -p 1 0 2 -p 1 0 1 -p -1 0 1 -p -1 0 0 -p 1 0 0 -p 1 0 -1 -p -1 0 -1 -p -1 0 -2 -p 1 0 -2 -p 1 0 -3 -p -1 0 -3 -p -1 0 -4 -p 0 0 -4 -p 0 0 4`;
//Create a lattice for the control
string $ctrlLattice[] = `lattice -divisions 2 2 2 -objectCentered true -ldv 2 2 2 $contactCtrl`;
//Position the control with the lattice
move -a -ws $boundingBox[3] $boundingBox[1] $boundingBox[2] ($ctrlLattice[1] + “.pt[1][0:1][0]”);
move -a -ws $boundingBox[0] $boundingBox[1] $boundingBox[2] ($ctrlLattice[1] + “.pt[0][0:1][0]”);
move -a -ws $boundingBox[3] $boundingBox[1] $boundingBox[5] ($ctrlLattice[1] + “.pt[1][0:1][1]”);
move -a -ws $boundingBox[0] $boundingBox[1] $boundingBox[5] ($ctrlLattice[1] + “.pt[0][0:1][1]”);
//Delete history and center pivot of the controller
delete -ch $contactCtrl;
xform -cp $contactCtrl;
//Create and position the group for the contact-controller
string $contactCtrlGrp = `group -em -n ($prefix + “wheel_contact_ctrl_grp”)`;
delete `pointConstraint $contactCtrl $contactCtrlGrp`;
//Parent the controller to the group and freeze the transforms
parent $contactCtrl $contactCtrlGrp;
makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $contactCtrlGrp;
//*************************************************************************************************************
// CREATE THE LATTICE AND SET UP THE CLUSTERS
//*************************************************************************************************************
//Create a lattice on the wheel
string $wheelLattice[] = `lattice -divisions 5 5 5 -objectCentered true -ldv 5 5 5 $wheelGeo`;
//Set the lattice to affect outside of the boundingBox
setAttr ($wheelLattice[0] + “.outsideLattice”) 1;
//Position the lattice-group to the lattice
delete `pointConstraint $wheelLattice[1] $latticeGrp`;
//Parent it to it’s respective group
parent $wheelLattice[1] $wheelLattice[2] $latticeGrp;
//Create a cluster for the contact of the wheel
string $contactCls[] = `cluster -n ($prefix + “wheel_contact_cluster”) ($wheelLattice[1] + “.pt[0:4][0:1][0:4]”)`;
percent -v 0.25 $contactCls[0] ($wheelLattice[1] + “.pt[0:4][1][0:4]”);
//Create a clusters for the extra control of the wheel
string $upFrontCls[] = `cluster -n ($prefix + “wheel_1_cluster”) ($wheelLattice[1] + “.pt[0:4][3:4][3:4]”)`;
percent -v 0.5 $upFrontCls[0] ($wheelLattice[1] + “.pt[0:4][3:4][3]”) ($wheelLattice[1] + “.pt[0:4][3][4]”);
string $sideFrontCls[] = `cluster -n ($prefix + “wheel_2_cluster”) ($wheelLattice[1] + “.pt[0:4][1:3][4]”)`;
percent -v 0.5 $sideFrontCls[0] ($wheelLattice[1] + “.pt[0:4][3][4]”) ($wheelLattice[1] + “.pt[0:4][1][4]”);
string $lowFrontCls[] = `cluster -n ($prefix + “wheel_3_cluster”) ($wheelLattice[1] + “.pt[0:4][0:1][3:4]”)`;
percent -v 0.5 $lowFrontCls[0] ($wheelLattice[1] + “.pt[0:4][0:1][3]”) ($wheelLattice[1] + “.pt[0:4][1][4]”);
string $lowMidCls[] = `cluster -n ($prefix + “wheel_4_cluster”) ($wheelLattice[1] + “.pt[0:4][0][1:3]”)`;
percent -v 0.5 $lowMidCls[0] ($wheelLattice[1] + “.pt[0:4][0][1]”) ($wheelLattice[1] + “.pt[0:4][0][3]”);
string $lowBackCls[] = `cluster -n ($prefix + “wheel_5_cluster”) ($wheelLattice[1] + “.pt[0:4][0:1][0:1]”)`;
percent -v 0.5 $lowBackCls[0] ($wheelLattice[1] + “.pt[0:4][1][0:1]”) ($wheelLattice[1] + “.pt[0:4][0][1]”);
string $sideBackCls[] = `cluster -n ($prefix + “wheel_6_cluster”) ($wheelLattice[1] + “.pt[0:4][1:3][0]”)`;
percent -v 0.5 $sideBackCls[0] ($wheelLattice[1] + “.pt[0:4][1][0]”) ($wheelLattice[1] + “.pt[0:4][3][0]”);
string $upBackCls[] = `cluster -n ($prefix + “wheel_7_cluster”) ($wheelLattice[1] + “.pt[0:4][3:4][0:1]”)`;
percent -v 0.5 $upBackCls[0] ($wheelLattice[1] + “.pt[0:4][3][0]”) ($wheelLattice[1] + “.pt[0:4][3:4][1]”);
string $upMidCls[] = `cluster -n ($prefix + “wheel_8_cluster”) ($wheelLattice[1] + “.pt[0:4][4][1:3]”)`;
percent -v 0.5 $upMidCls[0] ($wheelLattice[1] + “.pt[0:4][4][1]”) ($wheelLattice[1] + “.pt[0:4][4][3]”);
//Parent the clusters to the cluster-group
parent $contactCls[1] $upFrontCls[1] $sideFrontCls[1] $lowFrontCls[1] $lowMidCls[1] $lowBackCls[1] $sideBackCls[1] $upBackCls[1] $upMidCls[1] $clusterGrp;
//*************************************************************************************************************
// CREATE/POSITION AND CONNECT THE EXTRA WHEEL-CONTROLLERS
//*************************************************************************************************************
//Create string-arrays to store the joints and controllers in
string $ctrlGrp[];
string $ctrl[];
string $clsGrp[];
//Get the radius of the wheel
float $wheelRadius = `abs(($boundingBox[2] – $boundingBox[5]) / 2)`;
//Create a nurbs-circle as reference for positioning the controllers
string $ctrlCircle[] = `circle -c 0 0 0 -nr 1 0 0 -sw 360 -r $wheelRadius -d 3 -ut 0 -s 32 -ch 0`;
//Get the shape of the curve
string $ctrlCircleShape[] = `listRelatives -s $ctrlCircle[0]`;
//Position the circle at the wheel
delete `pointConstraint $wheelGeo $ctrlCircle[0]`;
//Create and position a group for the circle
string $ctrlCircleGrp = `group -em -n ($prefix + “wheel_ctrlCurve_crv_grp”)`;
delete `pointConstraint $ctrlCircle[0] $ctrlCircleGrp`;
//Parent the circle to the group
parent $ctrlCircle[0] $ctrlCircleGrp;

//Create a variable to define the U-value of the curve for where to place the joints
float $uVal = 1.000000 / 8;
float $incrementVar = $uVal;

//For each joint
for($a = 0; $a < 8; $a++)
{
//Create a motionPath-node
string $mpNode = `shadingNode -asUtility motionPath -n ($prefix + “wheel_” + ($a + 1) + “_mPath”)`;
//Create a controller and a group
string $mpCtrl[] = `circle -c 0 0 0 -nr 1 0 0 -sw 360 -r ($wheelRadius / 6) -d 3 -ut 0 -s 8 -ch 0 -n ($prefix + “wheel_” + ($a + 1) + “_ctrl”)`;
string $mpCtrlGrp = `group -n ($prefix + “wheel_” + ($a + 1) + “_ctrl_grp”) $mpCtrl[0]`;
//Connect the ctrl to the curve through the motionPath-node
connectAttr -f ($ctrlCircleShape[0] + “.worldSpace[0]”) ($mpNode + “.geometryPath”);
connectAttr -f ($mpNode + “.allCoordinates”) ($mpCtrlGrp + “.translate”);
connectAttr -f ($mpNode + “.rotate”) ($mpCtrlGrp + “.rotate”);
//Position the ctrl at it’s correct U-value along the curve
setAttr ($mpNode + “.fractionMode”) 1;
setAttr ($mpNode + “.uValue”) $uVal;
setAttr ($mpNode + “.worldUpType”) 1;
setAttr ($mpNode + “.frontAxis”) 2;
setAttr ($mpNode + “.upAxis”) 1;
setAttr ($mpNode + “.inverseUp”) 1;
connectAttr ($ctrlCircle[0] + “.worldMatrix[0]”) ($mpNode + “.worldUpMatrix”);
//Add the objects into the pre-defined arrays
$ctrlGrp[$a] = $mpCtrlGrp;
$ctrl[$a] = $mpCtrl[0];
//Add the object to it’s respective groups
parent $ctrlGrp[$a] $controlGrp;

//Create groups for the cluster
string $tmpGrp1 = `group -em -n ($prefix + “wheel_” + ($a + 1) + “_cluster_offset_grp”)`;
string $tmpGrp2 = `group -em -n ($prefix + “wheel_” + ($a + 1) + “_cluster_grp”)`;
string $tmpGrp3 = `group -em -n ($prefix + “wheel_” + ($a + 1) + “_cluster_norm_grp”)`;
//Parent the clusterGrp to the offsetGrp
parent $tmpGrp2 $tmpGrp1;
//Position and orient the group to the controller
delete `pointConstraint $ctrl[$a] $tmpGrp1`;
delete `orientConstraint $ctrl[$a] $tmpGrp1`;
//Place the cluster in the group
parent $tmpGrp1 $clusterGrp;
parent $tmpGrp3 $tmpGrp2;
parent ($prefix + “wheel_” + ($a + 1) + “_clusterHandle”) $tmpGrp3;

//Connect the controller to the cluster-group
connectAttr -f ($ctrl[$a] + “.translate”) ($tmpGrp2 + “.translate”);
connectAttr -f ($ctrl[$a] + “.rotate”) ($tmpGrp2 + “.rotate”);
connectAttr -f ($ctrl[$a] + “.scale”) ($tmpGrp2 + “.scale”);

//Increment the $uVal-variable
$uVal += $incrementVar;
}
//*************************************************************************************************************
// CREATE/POSITION THE MAIN WHEEL-CONTROLLERS
//*************************************************************************************************************
//Create a the controller for the wheel rotation/position
string $rotCtrl[] = `circle -c 0 0 0 -nr 1 0 0 -sw 360 -r ($wheelRadius / 1.7) -d 3 -ut 0 -s 32 -ch 0`;
string $minRotCtrl[] = `circle -c 0 0 0 -nr 1 0 0 -sw 360 -r ($wheelRadius / 6) -d 3 -ut 0 -s 32 -ch 0`;
string $posCtrl[] = `circle -c 0 0 0 -nr 1 0 0 -sw 360 -r ($wheelRadius / 1.2) -d 3 -ut 0 -s 32 -ch 0`;
string $minPosCtrl[] = `circle -c 0 0 0 -nr 1 0 0 -sw 360 -r ($wheelRadius / 1.5) -d 3 -ut 0 -s 32 -ch 0`;
//Shape the rotation-controllers
scale -r 0.5 0.5 0.5 ($rotCtrl[0] + “.cv[1]”) ($rotCtrl[0] + “.cv[9]”) ($rotCtrl[0] + “.cv[17]”) ($rotCtrl[0] + “.cv[25]”);
scale -r 0.3 0.3 0.3 ($minRotCtrl[0] + “.cv[1]”) ($minRotCtrl[0] + “.cv[9]”) ($minRotCtrl[0] + “.cv[17]”) ($minRotCtrl[0] + “.cv[25]”);
//Shape the position-controller
for($a=1; $a < 32; $a=$a + 2) scale -r -p 0cm 0cm 0cm 0.85 0.85 0.85 ($posCtrl[0] + “.cv[” + $a + “]”);
//Create groups for the controllers
string $rotCtrlGrp = `group -em -n ($prefix + “wheel_rotate_ctrl_grp”)`;
string $posCtrlGrp = `group -em -n ($prefix + “wheel_position_ctrl_grp”)`;
//Parent the controllers to their groups
parent $rotCtrl[0] $rotCtrlGrp;
parent $posCtrl[0] $posCtrlGrp;
parent $minPosCtrl[0] $posCtrl[0];
parent $minRotCtrl[0] $rotCtrl[0];
//Position the control-groups
delete `pointConstraint $wheelGeo $rotCtrlGrp`;
delete `orientConstraint $wheelGeo $rotCtrlGrp`;
delete `pointConstraint $wheelGeo $posCtrlGrp`;
delete `orientConstraint $wheelGeo $posCtrlGrp`;
//Get the worldSpace position of the rotate-group
float $wheelPivot[] = `xform -q -ws -t $rotCtrlGrp`;
//Find the position of where to offset the controllers
float $offsetCtrl = ($boundingBox[3] / 10);
//Offset the controllers
setAttr ($rotCtrlGrp + “.tx”) ($boundingBox[3] + $offsetCtrl);
setAttr ($posCtrlGrp + “.tx”) ($boundingBox[3] + $offsetCtrl);
//Freeze the transforms of the controllers
makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $rotCtrlGrp $posCtrlGrp;
//Set the pivot of the controllers to the center of the wheel
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($rotCtrlGrp + “.scalePivot”) ($rotCtrlGrp + “.rotatePivot”);
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($rotCtrl[0] + “.scalePivot”) ($rotCtrl[0] + “.rotatePivot”);
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($posCtrlGrp + “.scalePivot”) ($posCtrlGrp + “.rotatePivot”);
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($posCtrl[0] + “.scalePivot”) ($posCtrl[0] + “.rotatePivot”);
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($minPosCtrl[0] + “.scalePivot”) ($minPosCtrl[0] + “.rotatePivot”);
//Set the rotation order of the objects and controllers
setAttr ($ctrlCircle[0] + “.rotateOrder”) 3;
setAttr ($wheelGeo + “.rotateOrder”) 3;
setAttr ($wheelLattice[1] + “.rotateOrder”) 3;
setAttr ($wheelLattice[2] + “.rotateOrder”) 3;
setAttr ($rotCtrlGrp + “.rotateOrder”) 3;
setAttr ($posCtrlGrp + “.rotateOrder”) 3;
setAttr ($rotCtrl[0] + “.rotateOrder”) 3;
setAttr ($posCtrl[0] + “.rotateOrder”) 3;
setAttr ($minPosCtrl[0] + “.rotateOrder”) 3;
setAttr ($minRotCtrl[0] + “.rotateOrder”) 3;
//*************************************************************************************************************
// RIG THE MAIN WHEEL-CONTROLLERS
//*************************************************************************************************************
//Create a plusMinAvgNode so that we can sum the rotate-group and the rotate-controllers values to the wheel
string $rotAvgPma = `shadingNode -asUtility plusMinusAverage -n ($prefix + “wheel_rotate_sum_pma”)`;
//Connect the rotate-group and the rotate-controller to the plusMinAvgNode
connectAttr -f ($rotCtrlGrp + “.rotate”) ($rotAvgPma + “.input3D[0]”);
connectAttr -f ($rotCtrl[0] + “.rotate”) ($rotAvgPma + “.input3D[1]”);
connectAttr -f ($minRotCtrl[0] + “.rotate”) ($rotAvgPma + “.input3D[2]”);
//Connect the output of the plusMinAvgNode to the rotate of the wheel components
connectAttr -f ($rotAvgPma + “.output3Dx”) ($wheelGeo + “.rotateX”);

//Orient-Constraint the main position-controller to the lattice
orientConstraint -mo $posCtrl[0] $ctrlLattice[1];
//Point/Scale-Constraint the minPosCtrl to the lattice
pointConstraint -mo $minPosCtrl[0] $ctrlLattice[1];
scaleConstraint -mo $minPosCtrl[0] $ctrlLattice[1];
//Parent/Scale-Constraint the minPosCtrl to the extra control-curve
parentConstraint -mo $minPosCtrl[0] $ctrlCircle[0];
scaleConstraint -mo $minPosCtrl[0] $ctrlCircle[0];
//Parent/Scale-Constraint the minPosCtrl to the group of the rotation-controllers
parentConstraint -mo $minPosCtrl[0] $rotCtrlGrp;
scaleConstraint -mo $minPosCtrl[0] $rotCtrlGrp;
//Scale-Constraint the posCtrl to the group of the extra-controllers
for($each in $ctrlGrp) scaleConstraint -mo $posCtrl[0] $each;
//*************************************************************************************************************
// RIG THE CONTACT-CONTROLLER
//*************************************************************************************************************
//Move the pivot of the contact-cluster
float $contactPivot[] = `xform -q -piv $contactCtrl`;
move -a $contactPivot[0] $contactPivot[1] $contactPivot[2] ($contactCls[1] + “.scalePivot”) ($contactCls[1] + “.rotatePivot”);

//Create a multiplyDivideNode so that we can subtract the micro-pos-controller from the contact-controller
string $posSubMpd = `shadingNode -asUtility multiplyDivide -n ($prefix + “wheel_contact_pos_subtract_mpd”)`;
connectAttr -f ($minPosCtrl[0] + “.translate”) ($posSubMpd + “.input1”);
setAttr ($posSubMpd + “.input2”) -1 -1 -1;

//Create a plusMinAvgNode so that we can sum all of the components to the contact-cluster
string $contactClsPosAvgPma = `shadingNode -asUtility plusMinusAverage -n ($prefix + “wheel_contact_cls_pos_sum_pma”)`;
connectAttr -f ($contactCtrl + “.translate”) ($contactClsPosAvgPma + “.input3D[0]”);
connectAttr -f ($posSubMpd + “.output”) ($contactClsPosAvgPma + “.input3D[1]”);
//Connect the output of the plusMinAvgNode to the translate of the contact-cluster
connectAttr -f ($contactClsPosAvgPma + “.output3D”) ($contactCls[1] + “.translate”);
//Connect the contact-controller to the contact-cluster
connectAttr -f ($contactCtrl + “.rotate”) ($contactCls[1] + “.rotate”);
connectAttr -f ($contactCtrl + “.scale”) ($contactCls[1] + “.scale”);

//Parent the contact-ctrl group to the main position controller
parent $contactCtrlGrp $posCtrl[0];
//*************************************************************************************************************
// SET THE CONTROL COLOURS
//*************************************************************************************************************
//Get the shape of the controllers
string $contactCtrlShape[] = `listRelatives -s $contactCtrl`;
string $rotCtrlShape[] = `listRelatives -s $rotCtrl[0]`;
string $posCtrlShape[] = `listRelatives -s $posCtrl[0]`;
string $minRotCtrlShape[] = `listRelatives -s $minRotCtrl[0]`;
string $minPosCtrlShape[] = `listRelatives -s $minPosCtrl[0]`;
//Turn on overrideEnable of the controllers
setAttr ($contactCtrlShape[0] + “.overrideEnabled”) 1;
setAttr ($rotCtrlShape[0] + “.overrideEnabled”) 1;
setAttr ($posCtrlShape[0] + “.overrideEnabled”) 1;
setAttr ($minRotCtrlShape[0] + “.overrideEnabled”) 1;
setAttr ($minPosCtrlShape[0] + “.overrideEnabled”) 1;
//Set the color of the controllers
setAttr ($contactCtrlShape[0] + “.overrideColor”) 4;
setAttr ($rotCtrlShape[0] + “.overrideColor”) 31;
setAttr ($posCtrlShape[0] + “.overrideColor”) 19;
setAttr ($minRotCtrlShape[0] + “.overrideColor”) 9;
setAttr ($minPosCtrlShape[0] + “.overrideColor”) 17;
//For each of the extra controllers
for($each in $ctrl)
{
//Get the shape of the current control
string $extraCtrl[] = `listRelatives -s $each`;
//Turn on overrideEnable of the current controller
setAttr ($each + “.overrideEnabled”) 1;
//Set the color of the current controller
setAttr ($each + “.overrideColor”) 6;
}
//*************************************************************************************************************
// CLEANUP
//*************************************************************************************************************
//Rename the objects
$wheelGeo = `rename $wheelGeo ($prefix + “wheel_geo”)`;
$contactCtrl = `rename $contactCtrl ($prefix + “wheel_contact_ctrl”)`;
$ctrlCircle[0] = `rename $ctrlCircle[0] ($prefix + “wheel_ctrlCurve_crv”)`;
$rotCtrl[0] = `rename $rotCtrl[0] ($prefix + “wheel_rotate_ctrl”)`;
$posCtrl[0] = `rename $posCtrl[0] ($prefix + “wheel_position_ctrl”)`;
$minRotCtrl[0] = `rename $minRotCtrl[0] ($prefix + “wheel_micro_rotate_ctrl”)`;
$minPosCtrl[0] = `rename $minPosCtrl[0] ($prefix + “wheel_micro_position_ctrl”)`;
$wheelLattice[0] = `rename $wheelLattice[0] ($wheelGeo + “_latticeShape”)`;
$wheelLattice[1] = `rename $wheelLattice[1] ($wheelGeo + “_lattice”)`;
$wheelLattice[2] = `rename $wheelLattice[2] ($wheelGeo + “_lattice_base”)`;

//Set the pivot to the center of the wheel of the main groups
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($wheelGrp + “.scalePivot”) ($wheelGrp + “.rotatePivot”);
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($controlGrp + “.scalePivot”) ($controlGrp + “.rotatePivot”);
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($clusterGrp + “.scalePivot”) ($clusterGrp + “.rotatePivot”);
move -a $wheelPivot[0] $wheelPivot[1] $wheelPivot[2] ($wheelGeoGrp + “.scalePivot”) ($wheelGeoGrp + “.rotatePivot”);

//Clean the hierarchy
parent $wheelGeo $wheelGeoGrp;
parent $rotCtrlGrp $posCtrlGrp $ctrlCircleGrp $clusterGrp $latticeGrp $controlGrp $wheelGeoGrp $wheelGrp;

//Turn of inherit transform so that scaling works
setAttr ($controlGrp + “.inheritsTransform”) 0;
setAttr ($clusterGrp + “.inheritsTransform”) 0;
setAttr ($latticeGrp + “.inheritsTransform”) 0;
setAttr ($wheelGeoGrp + “.inheritsTransform”) 0;
setAttr ($ctrlCircleGrp + “.inheritsTransform”) 0;

//Hide objects/groups we don’t need to see
setAttr ($clusterGrp + “.visibility”) 0;
setAttr ($latticeGrp + “.visibility”) 0;
setAttr ($ctrlCircleGrp + “.visibility”) 0;

//Lock attributes that shouln’t be used
setAttr -lock 1 -keyable 0 -channelBox 0 ($minPosCtrl[0] + “.rotate”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($minPosCtrl[0] + “.scale”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($rotCtrl[0] + “.translate”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($rotCtrl[0] + “.scale”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($rotCtrl[0] + “.rotateY”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($rotCtrl[0] + “.rotateZ”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($minRotCtrl[0] + “.translate”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($minRotCtrl[0] + “.scale”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($minRotCtrl[0] + “.rotateY”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($minRotCtrl[0] + “.rotateZ”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($clusterGrp + “.translate”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($clusterGrp + “.rotate”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($clusterGrp + “.scale”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($latticeGrp + “.translate”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($latticeGrp + “.rotate”);
setAttr -lock 1 -keyable 0 -channelBox 0 ($latticeGrp + “.scale”);
}

jh_wheelRigger;

Download Script

Script: Delete Flat Keys

Script: Delete Flat Keys

When you’re working with animation you eventually end up with a lot of extra keys, by that I mean flat keys, keys we don’t need.

See the image below, I’ve marked the flat keys with red dots:

 

With the script you just select all of the objects that you want to clean the keyframes on, then you define the angle threshold, and the script will go through and delete all of the keys with a lower angle threshold than defined.

When run on the example above, we end up with this:

 

jh_delFlatKeys (Delete Flat Keys)

//*************************************************************************************************************
// Title: jh_delFlatKeys.mel
// Author: Jørn-Harald Paulsen
// Created: September 08, 2010
// Last Update: May 28, 2011
// Description: Utility to remove key’s with a lower value-difference than specified.
//*************************************************************************************************************
// MAIN WINDOW
//*************************************************************************************************************
global proc jh_delFlatKeys()
{
//Close window if it already exists
if (`window -q -ex jh_delFlatKeys`) deleteUI jh_delFlatKeys;

//Main Window
window -topEdge 30 -title “Keyframe cleanup”
-mxb false -s true -rtf false -mb false -mbv false -w 412 -h 268 jh_delFlatKeys;

//Window content
columnLayout -adjustableColumn true;
text -label “\nUtility to remove key’s with a lower value-difference than specified.\n” -fn boldLabelFont;
separator -w 240 -h 40;
text -label “- Select the object(s) that you want to clean keyframes on”;
text -label “- Define the angle/value tolerance (keys with values lower than these will be deleted)\n”;
floatSliderGrp -label “Angle tolerance” -f true -min 0.001 -max 5.000 -fmn 0.001 -fmx 100.000 -v 0.001 -s 0.001 sliderAngleTol;
floatSliderGrp -label “Value tolerance” -f true -min 0.001 -max 5.000 -fmn 0.001 -fmx 100.000 -v 0.001 -s 0.001 sliderValueTol;
separator -w 240 -h 40;
button -label “Clean keyframes” -c jh_deleteKeys;
separator -w 240 -h 40;
window -e -w 412 -h 268 jh_delFlatKeys;
showWindow jh_delFlatKeys;
}

global proc jh_deleteKeys()
{
//Get the selected object(s)
string $selObj[] = `ls -sl`;
//Create a variable to store the number of keys deleted
int $keysDeleted = 0;
//For each selected object
for($object in $selObj)
{
//Get the animation curves
string $animCurve[] = `keyframe -query -name $object`;
//If the object have animation curves
if (size($animCurve) > 0)
{
//Tangents with angles below this value will be considered flat
float $angleTol = `floatSliderGrp -q -v sliderAngleTol`;
//Neighboring values that fall within this tolerance will be considered matching
float $valueTol = `floatSliderGrp -q -v sliderValueTol`;

//Define the variables
string $keyedAttrs[], $outTanType[], $evalStr, $plural;
float $keyedValues[], $inAngle[], $outAngle[], $keyedFrames[], $prevValDif, $nextValDif;
int $deleteIndex[], $stepped, $i;
int $counter = 0;

//For each animation curve
for ($curve in $animCurve)
{
clear($inAngle);
clear($outAngle);
clear($deleteIndex);
clear($keyedValues);

//Get all of the keyed attributes
$keyedAttrs = `listConnections -plugs yes -source no $curve`;

//Go through the keyframes on the current animation-curve and get inAngle and outAngle
float $inAngle[] = `keyTangent -query -inAngle $curve`;
float $outAngle[] = `keyTangent -query -outAngle $curve`;
string $outTanType[] = `keyTangent -query -outTangentType $curve`;

//Make $inAngle and $outAngle absolute values, for less work on the comparison
for ($i=0;$ifor ($i=0;$i

//Get each keyed frame, and get the value of each keyed frame
$keyedFrames = `keyframe -query -timeChange $curve`;
$keyedValues = `keyframe -query -valueChange $curve`;

//For each keyeframe on the current animation-curve, find deleteable keys
for ($i=0;$i {
//As long as the current keyeframe is between 0, and less than the number of keyframes, continue
if ($i == 0 || $i == (`size $keyedFrames`-1)) continue;

//Get the outTangentType of the previus frame, the current frame, and the next frame.
//The result of this command will go to $stepped. If true, $stepped = 1, if false, $stepped = 0
$stepped = ($outTanType[$i] == “step” && $outTanType[$i-1] == “step” && $outTanType[$i+1] == “step”);

//If one of the following conditions (1 or 2) is true, rund the script inside of the if-brackets:
// 1) $stepped is true (1)
// 2) outAngle of the previous frame is less than angleTol
// & inAngle of the current frame is less than angleTol
// & outAngle of the current frame is less than angleTol
// & inAngle of the next frame is less than angleTol
if ($stepped || ($outAngle[$i-1] < $angleTol && $inAngle[$i] < $angleTol && $outAngle[$i] < $angleTol && $inAngle[$i+1] < $angleTol))
{
//Get the difference of the value of the current attribute between the previous frame and the current frame
$prevValDif = abs($keyedValues[$i-1] – $keyedValues[$i]);
//Get the difference of the value of the current attribute between the current frame and the next frame
$nextValDif = abs($keyedValues[$i+1] – $keyedValues[$i]);

//If one of the following (1 or 2) conditions is true, set $deleteIndex:
// 1) $stepped is true (1)
// & $prevValDif is less than valueTol
// 2) $stepped is false (0)
// & $prevValDif is larger than valueTol
// & $nextValDif is larger than $valueTol
if ($stepped && $prevValDif < $valueTol || !$stepped && $prevValDif < $valueTol && $nextValDif < $valueTol) $deleteIndex = $i; } } //Make the string to delete the keys if (size($deleteIndex) > 0)
{
//The first command of the delete -string
$evalStr = “cutKey -clear”;
//Add the indexes to the string
for ($i in $deleteIndex) $evalStr += ” -index ” + $i;
//Add the animation-curve to the string
$evalStr += ” ” + $curve;
//Execute the generated cutKey -string
eval($evalStr);
//Get the number of keys deleted
$counter += size($deleteIndex);
}
}

//If more than one key has been deleted, set the $plural to true
$plural = ($counter > 1 || $counter == 0) ? “s” : “”;
//Put the number of deleted keys on the current attribute to the total deleted keys -variable
$keysDeleted = $keysDeleted + $counter;
//Print information
print ($counter + ” keyframe” + $plural + ” removed from ” + $object + “.\n”);
}
}
//Print number of keys deleted in total
print (“Deleted keyframes in total: ” + $keysDeleted + “.\n”);
}

jh_delFlatKeys;

Download Script

 

Script: Hide/Display Local Axis

Script: Hide/Display Local Axis

It can be a hassle to turn on/off the local axis of multiple objects simultaneously, the reason for this is that by default there’s no on and off option on “Display > Local Rotation Axis“, it’s just a toggle. This means that if you select a bunch of objects and toggle the local axis, the objects that already have the local axis visible will be hidden, while the rest of the selection’s local handles will be visible. This can be frustrating at times, especially if you have joints/objects that have the same position and orientation.

 

This is a really simple script, it basicly just adds the flag that defines on/off to the command that toggle’s the local axis. I’ve also added an option for it to go through the entire hierarchy, definitely a timesaver.

jh_dispLocalAxis (Hide/Display the local axis on multiple objects simultaneously)

//*************************************************************************************************************
// Title: jh_dispLocalAxis.mel
// Author: Jørn-Harald Paulsen
// Created: January 27, 2012
// Last Update: January 27, 2012
// Description: Utility to display or hide the local rotation axis of the selected object(s)
//*************************************************************************************************************
// MAIN WINDOW
//*************************************************************************************************************
global proc jh_dispLocalAxis()
{
//Delete window if it already exists
if (`window -q -ex jh_dispLocalAxis`) deleteUI jh_dispLocalAxis;

//Main Window
window -topEdge 30 -title “Display/Hide Local Axis”
-mxb false -s true -rtf false -mb false -mbv false -w 300 -h 440 jh_dispLocalAxis;

//Window content
columnLayout -adjustableColumn true;
separator -w 240 -h 20;
text -label “Utility to display or hide the local rotation axis of the selected object(s)” -fn boldLabelFont;
separator -w 240 -h 25;
button -label “Display Local Axis on selected object(s)” -c “jh_dispAxis 1 0”;
button -label “Hide Local Axis on selected object(s)” -c “jh_dispAxis 0 0” -bgc 0.23 0.23 0.23;
separator -w 240 -h 25;
button -label “Display Local Axis on selected object(s) (with hierarchy)” -c “jh_dispAxis 1 1”;
button -label “Hide Local Axis on selected object(s) (with hierarchy)” -c “jh_dispAxis 0 1” -bgc 0.23 0.23 0.23;
separator -w 240 -h 25;
window -e -w 300 -h 500 jh_dispLocalAxis;
showWindow jh_dispLocalAxis;
}

global proc jh_dispAxis(int $state, int $hierarchy)
{
//If (with hierarchy) was selected, select the hierarchy
if($hierarchy == 1) select -hi;
//Get the selected object(s)
string $selObj[] = `ls -sl`;
//For each object
for($sel in $selObj)
{
//If the attribute “displayLocalAxis” exist on the current object
if(`attributeExists “displayLocalAxis” $sel`)
{
//Sel the state of the local axis
setAttr ($sel + “.displayLocalAxis”) $state;
}
}
}

jh_dispLocalAxis;

Download Script

 

Script: Find Duplicate Names

Script: Find Duplicate Names

When dealing with rigs you often end up having a ton of nodes, and it’s easy to end up having several objects with the same name. You may think that Maya automaticly renames those objects for you, and it does, but only if the objects are in the same hierarchy. However, if you have the objects in separate hierarchies they can share the same name.

This isn’t really a problem in it self because Maya will just use longnames to distinguish them apart, but you may run into problems if you’re using scripts that doesn’t take longnames into consideration.

Example:

In the image above we have two objects named “pCube”. So what Maya does to distinguish them apart is to look at their parent, if the parent’s name is unique it will use that in the longname when dealing the objects. So if I were to select the pCube in root2, Maya would read it as “grp2|pcube”, and if both of the mid-groups was named “grp2” then maya would read the pCube as “root2|grp2|pCube”.

 

I’ve made a script that finds (and renames) all of the objects in the scene sharing the same name, the download link is at the bottom :)

jh_findDuplicateNames (Find and rename duplicate objects in the scene)

//*************************************************************************************************************
// Title: jh_findDuplicateNames.mel
// Author: Jørn-Harald Paulsen
// Created: May 24, 2012
// Last Update: May 24, 2012
// Description: Utility to find and rename objects with duplicate names in the scene
//*************************************************************************************************************
// MAIN WINDOW
//*************************************************************************************************************
global proc jh_findDuplicateNames()
{
//Delete window if it already exists
if (`window -q -ex jh_findDuplicateNames`) deleteUI jh_findDuplicateNames;

//Main Window
window -topEdge 30 -title “Find Duplicate Names”
-mxb false -s true -rtf false -mb false -mbv false -w 284 -h 194 jh_findDuplicateNames;

//Window content
columnLayout -adjustableColumn true;
text -label “\nUtility to find and rename duplicate names in the scene.”;
separator -w 240 -h 40;
button -label “Just select the objects with duplicate names” -c jh_findDuplicates;
separator -w 240 -h 30;
button -label “Select and rename objects with duplicate names” -c jh_renameDuplicates;
separator -w 240 -h 30;
window -e -w 284 -h 194 jh_findDuplicateNames;
showWindow jh_findDuplicateNames;
}

global proc jh_findDuplicates()
{
//Create a string-array to store the duplicates in
string $duplicateNames[];
//Get all of the transform-nodes in the scene
string $transformNodes[] = `ls -type transform`;

//Create a counter
int $counter = 0;
//For each object
for($node in $transformNodes)
{
//If it’s a duplicate object, put it in the variable for duplicates
if(`match “|” $node` == “|”)
{
$duplicateNames[$counter] = $node;
$counter = $counter + 1;
}
}

//Get the number of duplicate objects
int $numDuplicates = `size $duplicateNames`;
//Print information
print $duplicateNames;
print (“\nThere’s a total of ” + $numDuplicates + ” transform-nodes with the same name in the scene:\n”);
//Select the duplicate names
select -r $duplicateNames;
}

global proc jh_renameDuplicates()
{
//Create a string-array to store the duplicates in
string $duplicateNames[];
//Get all of the transform-nodes in the scene
string $transformNodes[] = `ls -type transform`;

//Create a counter
int $counter = 0;
//For each object
for($node in $transformNodes)
{
//If it’s a duplicate object, put it in the variable for duplicates
if(`match “|” $node` == “|”)
{
$duplicateNames[$counter] = $node;
$counter = $counter + 1;
}
}

//Reset the counter
$counter = 0;
//For each of the duplicate objects
for($duplicate in $duplicateNames)
{
//Tokenize the strings
string $nameBuffer[];
int $numTokens = `tokenize $duplicate “|” $nameBuffer`;
//For each of the tokens
for($a=0; $a < `size $nameBuffer`; $a++) { //Get the duplicates of the current token string $dupToken[] = `ls (“*” + $nameBuffer[$a])`; //Get the number of duplicates with the same name as tokenized int $sizeToken = `size $dupToken`; //If there’s more than one object if($sizeToken > 1)
{
//For each duplicate name
for($i=1; $i < $sizeToken; $i++)
{
$dupToken[$i] = `rename $dupToken[$i] ($nameBuffer[$a] + “_dup_” + $i)`;
$counter = $counter + 1;
}
}
}
}

//Print information
print (“\nA total of ” + $counter + ” transform-nodes was renamed\n”);
}

jh_findDuplicateNames;

Download Script

 

All Posts

1,233 total views, 1 views today