// Copyright Digital Pictures 2003. All Rights Reserved // // Author: // Stuart Bryson global proc doModularRigHelp() { window -title "ModularRig v0.1" -iconName "ModularRig" -titleBar true -minimizeButton true -maximizeButton true -h 400 -w 310 -sizeable true; scrollLayout -verticalScrollBarThickness 16 -horizontalScrollBarThickness 16; columnLayout -adjustableColumn true; text -align left -label ( "No help has yet been writen for this script.\n" + "If it is needed urgently contact rnd@gmd.com.au.\n" ); setParent ..; showWindow; } //###################################################################################### //# FUNCTIONS FOR CONTROLS, SELECTION HANDLES ETC //###################################################################################### proc setAndLockAttrs(string $obj, string $attributes[], float $value) { string $attr; for ($attr in $attributes) { setAttr -lock true ($obj + "." + $attr) $value; } } proc removeChannels(string $objects[], string $attributes[], int $lock) { string $obj, $attr; for ($obj in $objects) { for ($attr in $attributes) { if ($lock) { setAttr -lock true ($obj + "." + $attr); } setAttr -k off ($obj + "." + $attr); } } } proc toggleSelectionHandles(string $objects[]) { string $obj; for ($obj in $objects) { toggle -selectHandle $obj; } } proc toggleSelectionHandle(string $object) { toggle -selectHandle $object; } proc toggleSelectionHandlesWithOffset(string $objects[], float $offset[]) { string $obj; float $loc; for ($obj in $objects) { toggle -selectHandle $obj; $loc = `getAttr ($obj + ".selectHandleX")`; setAttr ($obj + ".selectHandleX") ($offset[0]+$loc); $loc = `getAttr ($obj + ".selectHandleY")`; setAttr ($obj + ".selectHandleY") ($offset[1]+$loc); $loc = `getAttr ($obj + ".selectHandleZ")`; setAttr ($obj + ".selectHandleZ") ($offset[2]+$loc); } } proc toggleSelectionHandleWithOffset(string $obj, float $offset[]) { float $loc; toggle -selectHandle $obj; $loc = `getAttr ($obj + ".selectHandleX")`; setAttr ($obj + ".selectHandleX") ($offset[0]+$loc); $loc = `getAttr ($obj + ".selectHandleY")`; setAttr ($obj + ".selectHandleY") ($offset[1]+$loc); $loc = `getAttr ($obj + ".selectHandleZ")`; setAttr ($obj + ".selectHandleZ") ($offset[2]+$loc); } //NOTE The order of colouring a heirachy is important - always colour from top down so as not to override the child objects // colour an object with a user defined colour proc colourObjectWithColour(string $object, int $colour) { color -ud $colour $object; } // colour all objects with a user defined colour proc colourObjectsWithColour(string $objects[], int $colour) { color -ud $colour $objects; } // colour objects with different user defined colours proc colourObjectsWithColours(string $objects[], int $colours[]) { string $obj; int $i; // check number of objects matches number of colours if (size($objects) > size($colours)) { error "Too many objects and not enough colours when colouring objects"; } else if (size($objects) < size($colours)) { error "Too many colours and not enough objects when colouring objects"; } for ($i=0; $i= size($removeIndexes)) { return $return; } } } return $return; } // Vector (float array) functions... proc float[] vecAdd(float $a[], float $b[]) { float $result[]; $result[0] = $a[0] + $b[0]; $result[1] = $a[1] + $b[1]; $result[2] = $a[2] + $b[2]; return $result; } proc float[] vecSub(float $a[], float $b[]) { float $result[]; $result[0] = $a[0] - $b[0]; $result[1] = $a[1] - $b[1]; $result[2] = $a[2] - $b[2]; return $result; } proc float[] vecMultFloat(float $a[], float $b) { float $result[]; $result[0] = $a[0] * $b; $result[1] = $a[1] * $b; $result[2] = $a[2] * $b; return $result; } proc float[] vecDivFloat(float $a[], float $b) { float $result[]; $result[0] = $a[0] / $b; $result[1] = $a[1] / $b; $result[2] = $a[2] / $b; return $result; } // returns a subset of a float array from start to end indicies proc float[] vecIndex(float $array[], int $start, int $end) { float $result[]; int $i; for ($i=$start; $i<=$end; $i++) { $result[size($result)] = $array[$i]; } return $result; } // returns a subset of a string array from start to end indicies proc string[] vecIndexString(string $array[], int $start, int $end) { string $result[]; int $i; for ($i=$start; $i<=$end; $i++) { $result[size($result)] = $array[$i]; } return $result; } // Creates a Locator given the name, position and scale and returns the new locators name proc string createLoc(string $name, string $parent, float $pos[], float $scale) { string $parents[], $loc[]; $loc = `spaceLocator`; setAttr ($loc[0] + ".sx") $scale; setAttr ($loc[0] + ".sy") $scale; setAttr ($loc[0] + ".sz") $scale; move -a $pos[0] $pos[1] $pos[2] $loc[0]; $loc[0] = `rename $loc[0] $name`; $parents = `parent $loc[0] $parent`; return $loc[0]; } // creates a group of locators (or lodacators :) N/M) proc string createLocGroup(string $groupName, string $names[], float $locLocs[], float $scale) { int $i; string $group = `group -em -n $groupName`; // Check that the number of locators given times 3 equals the number of positions given (x,y,z for each) if (size($names)*3 > size($locLocs)) { error "When creating locator group: Too many names specified or not enough points specified"; } else if (size($names)*3 < size($locLocs)) { error "When creating locator group: Not enough names specified or too many points specified"; } // Check that the new group has the correct name.... if (strcmp($group, $groupName) != 0) { warning ("Could not create group " + $groupName + " as there is probably already a group with that name."); } // for each locator, create it, move it and parent it to the new group for ($i=0; $i size($jointLocs)) { error "Too many joint names specified or not enough joint points specified.\n"; } else if (size($jointNames) * 3 < size($jointLocs)) { error "Not enough joint names specified or too many joint points specified.\n"; } if (size($jointLocs)%3 != 0) { error "Joint Loc array not divisible by 3.\n"; } if (size($upVectors) != 3 && size($upVectors) != size($jointLocs)) { error "You must specify either one up vector for all joints or multiple up vectors, one for each joint.\n"; } if (size($upVectors) == 3) { $globalUpVector = 1; } $numOfJoints = size($jointLocs)/3; select -cl; // Create the first joint outside the loop as the loop references root // We do not want to play with the joint orients of the root joint... $joints[0] = `joint -p $jointLocs[0] $jointLocs[1] $jointLocs[2] -n ($prefix + $jointNames[0] + "#")`; // top level refers to just the node name and not the full path of the joint, this joint should be parented to world anyway $jointsTopLevel[0] = $joints[0]; // joint may not return the full path and this may create problems later so we ls -l to get the full path $lslong = `ls -l $joints[0]`; if (size($lslong) > 1) { warning ("ls -l returned more than one match for the joint: " + $joints[0]); } $joints[0] = $lslong[0]; // Create the remaining joints for ($i=1; $i<$numOfJoints; $i++) { // Create joint $joints[$i] = `joint -p $jointLocs[$i*3] $jointLocs[($i*3) + 1] $jointLocs[($i*3) + 2] -n ($prefix + $jointNames[$i] + "#")`; // joint may not return the full path and this may create problems later so we ls -l to get the full path $lslong = `ls -l $joints[$i]`; if (size($lslong) > 1) { warning ("ls -l returned more than one match for the joint: " + $joints[$i]); } $joints[$i] = $lslong[0]; // Ungroup it so we can aim constrain $temp = `parent -w $joints[$i]`; if (size($temp) > 1) { warning ("parent returned more than one value when parenting " + $joints[$i] + " to the world."); } $jointsTopLevel[$i] = $temp[0]; // get the upvector for this joint if ($globalUpVector) { $upVector[0] = $upVectors[0]; $upVector[1] = $upVectors[1]; $upVector[2] = $upVectors[2]; } else { $upVector[0] = $upVectors[$i*3]; $upVector[1] = $upVectors[$i*3 + 1]; $upVector[2] = $upVectors[$i*3 + 2]; } // create a locator at the world space position of the joint to be constrained $jointLoc = `xform -q -ws -rp $jointsTopLevel[$i - 1]`; $aimUpLoc = `spaceLocator -n ($jointsTopLevel[$i] + "_AimLoc")`; // store aim up locators so we can delete them later... for some reason it barfs if we try to delete them too soon $aimUpLocs[$i] = $aimUpLoc[0]; move -a -ws ($jointLoc[0] + $upVector[0]) ($jointLoc[1] + $upVector[1]) ($jointLoc[2] + $upVector[2]) $aimUpLoc[0]; // aim constrain the joint to the next joint with the locator as our up vector $aimConst = `aimConstraint -wut "object" -aim 1 0 0 -u 0 1 0 -wuo $aimUpLoc[0] $jointsTopLevel[$i] $jointsTopLevel[$i - 1]`; delete $aimConst[0]; // set the joint orients to the joint rotations and reset the rotations to 0 $orient = `getAttr ($jointsTopLevel[$i - 1] + ".r")`; setAttr ($jointsTopLevel[$i - 1] + ".jo") ($orient[0]) $orient[1] $orient[2]; setAttr ($jointsTopLevel[$i - 1] + ".r") 0 0 0; select -r $jointsTopLevel[$i]; } // set the last joint's orients to the same as the second last joint's orients $orient = `getAttr ($jointsTopLevel[$i-2] + ".jo")`; setAttr ($jointsTopLevel[$i-1] + ".jo") $orient[0] $orient[1] $orient[2]; for ($i=1; $i<$numOfJoints; $i++) { //print ("Parenting " + $jointsTopLevel[$i] + " to " + $jointsTopLevel[$i-1] + "\n"); $temp = `parent $jointsTopLevel[$i] $jointsTopLevel[$i-1]`; if (size($temp) > 1) { warning ("parent returned more than one value when parenting " + $jointsTopLevel[$i] + " to " + $jointsTopLevel[$i-1]); } $lslong = `ls -l $temp[0]`; if (size($lslong) > 1) { warning ("ls -l returned more than one match for the joint: " + $temp[0]); } $joints[$i] = $lslong[0]; delete $aimUpLocs[$i]; } // Parent to the $root joint if (`objExists $root`) { parent $joints[0] ("|" + $root); } // Add the root joint to the joint names array to be returned (so we have the absolute path) for ($i=0; $i<$numOfJoints; $i++) { $joints[$i] = $root + $joints[$i]; } return $joints; } // A function which reorients a joint to point at a locator and another locator as its up vector // this is different to the modRigBuild func as it doesn't assume that the X axis should point at the next joint // doesn't seem to work on last joint in the chain global proc orientToLocators(string $joint, string $aim, string $up) { string $children[], $childTopLevel, $jointTopLevel, $aimConst[], $child, $temp[], $parent; float $orient[], $rotations[]; $temp = `listRelatives -p $joint`; $parent = $temp[0]; // parent child joint to the world $temp = `parent -w $joint`; if (size($temp) > 1) { warning ("parent returned more than one value when parenting " + $joint + " to the world."); } $jointTopLevel = $temp[0]; // get the child joint object of the joint $children = `listRelatives -type joint $jointTopLevel `; // only parent the child joint if there is one! if (size($children) > 0) { $child = $children[0]; // parent child joint to the world $temp = `parent -w $child`; if (size($temp) > 1) { warning ("parent returned more than one value when parenting " + $child + " to the world."); } $childTopLevel = $temp[0]; } // set the joint orients to 0 setAttr ($jointTopLevel + ".jo") 0 0 0; // add aim constraint $aimConst = `aimConstraint -wut "object" -aim 1 0 0 -u 0 1 0 -wuo $up $aim $jointTopLevel`; // delete the aim constraint delete $aimConst[0]; // get the joint rotations $rotations = `getAttr ($jointTopLevel + ".r")`; // set the joint orients to the rotations setAttr ($jointTopLevel + ".jo") $rotations[0] $rotations[1] $rotations[2]; // set the joint rotations to 0 0 0 setAttr ($jointTopLevel + ".r") 0 0 0; parent $jointTopLevel $parent; if (size($children) > 0) { // parent the joint back to its original parent parent $childTopLevel $joint; } } // Creates a skeleton at the locator positions passed in and returns an array of joints // should use orient constraints... proc string[] skelAtLoc(string $root, string $locs[], float $upVectors[], string $prefix) { float $jointLoc[], $jointLocs[]; string $joints[], $newJointNames[], $buffer[]; int $i, $numTokens; select -cl; for ($i=0; $i 0) { for ($object in $selected) { $type = `ls -st $object`; // if it is a transform then check that the required locators are below it... if (strcmp($type[1], "transform") == 0) { $locators[size($locators)] = $object; // if it is a joint then set root = joint } else if (strcmp($type[1], "joint") == 0) { $roots[size($roots)] = $object; } } } // end selection mapping if ($jointsOrLocators == 0) { return $roots; } else { return $locators; } } // determines if the fk ik or bind skeletons 'appear' to have a conflicting name proc warnRootSelections(string $fkRoot, string $ikRoot, string $bindRoot) { string $matched; $matched = `match "ik" (tolower($fkRoot))`; if (size($matched) > 0) { warning "You may have selected the IK skeleton as the FK root!"; } $matched = `match "bind" (tolower($fkRoot))`; if (size($matched) > 0) { warning "You may have selected the Bind skeleton as the FK root!"; } $matched = `match "fk" (tolower($ikRoot))`; if (size($matched) > 0) { warning "You may have selected the FK skeleton as the IK root!"; } $matched = `match "bind" (tolower($ikRoot))`; if (size($matched) > 0) { warning "You may have selected the Bind skeleton as the IK root!"; } $matched = `match "fk" (tolower($bindRoot))`; if (size($matched) > 0) { warning "You may have selected the FK skeleton as the Bind root!"; } $matched = `match "ik" (tolower($bindRoot))`; if (size($matched) > 0) { warning "You may have selected the IK skeleton as the Bind root!"; } } // determines whether a string contains a substring with the option of case sensitivity proc int stringContains(string $string, string $contains, int $caseSensitive) { string $matched; if ($caseSensitive) { $matched = `match $contains $string`; } else { $matched = `match (tolower($contains)) (tolower($string))`; } if (size($matched) > 0) { return 1; } else { return 0; } } //###################################################################################### //# ARMS //###################################################################################### global proc string modRigLayoutArmSkeleton(int $left) { string $prefix, $missing[], $group; int $numOfArms, $i; $numOfArms = `intFieldGrp -q -v1 armNumOfArms`; if ($left) { print ("Laying out " + $numOfArms + " left arm(s)...\n"); } else { print ("Laying out " + $numOfArms + " right arm(s)...\n"); } // for each arm create a group of locators to indicate joints for ($i=1; $i<=$numOfArms; $i++) { if ($left) { $group = createLocGroup(("Arm"), {"shoulder", "elbow", "wrist", "collar", "armPoleVector"}, {2.0,17,0, 6,17,-0.5, 10,17,0, 1,16,0, 6,17,-4.5}, 0.8); } else { $group = createLocGroup(("Arm"), {"shoulder", "elbow", "wrist", "collar", "armPoleVector"}, {-2.0,17,0, -6,17,-0.5, -10,17,0, -1,16,0, -6,17,-4.5}, 0.8); } // Create a locator for the up vector of a joint... if ($left) { createLoc("elbowUpVector", ($group + "|elbow"), {6.0,18,-0.5}, 0.4); createLoc("xCollarVector", ($group + "|collar"), {1.0, 17, 0}, 0.2); createLoc("yCollarVector", ($group + "|collar"), {2.0, 16, 0}, 0.2); } else { createLoc("elbowUpVector", ($group + "|elbow"), {-6.0,18,-0.5}, 0.4); createLoc("xCollarVector", ($group + "|collar"), {-1.0, 17, 0}, 0.2); createLoc("yCollarVector", ($group + "|collar"), {-2.0, 16, 0}, 0.2); } } select -r $group; return $group; } global proc string[] modRigPreBuildArmSkeleton(string $roots[], string $locs[], int $left, string $biped) { string $locs[], $roots[], $object, $missing[], $arms[], $bindSkel[]; int $i, $numOfSkelsToCreate; // Check that if only FK, IK or only Bind is checked then ensure that only 1 root is selected... // if more than one is checked then ensure that at least 1 and no more than 3 roots are selected... $numOfSkelsToCreate = `checkBoxGrp -q -v1 armFkIkCheckBox` + `checkBoxGrp -q -v2 armFkIkCheckBox` + `checkBoxGrp -q -v3 armFkIkCheckBox`; if (size($roots) > 3) { error "Too many root joints selected. The maximum is 3."; } if ($numOfSkelsToCreate == 0) { error "No Skeletons to create..."; } else if ($numOfSkelsToCreate == 1 && size($roots) > 1) { error "Too many root joints selected"; } else if ($numOfSkelsToCreate == 3 && size($roots) == 2) { error "To create IK, FK and Bind skeletons you must have 0, 1 or 3 roots selected, not 2."; } // Check that all locators are present to create a arm if (size($locs) < 1) { error "No Locator Groups selected"; } // check that all the locators required for an arm are present for ($i=0; $i 0) { reportMissing($missing,$locs[$i],0); } else { $arms[size($arms)] = $locs[$i]; } } if (size($arms) > 0) { // create the arm $bindSkel = modRigBuildArmSkeleton($roots, $arms, $left, $biped); } return $bindSkel; } // creates the required amount of 'extra' locators for mid joints - used for the biceps and forearms on the bind arm proc string[] createMidJoints(string $startName, string $endName, int $numOfMidJoints, string $parent) { float $startLoc[], $endLoc[], $deltaJoint[]; string $midjoints[]; // determine start and end ws points $startLoc = `xform -q -ws -rp $startName`; $endLoc = `xform -q -ws -rp $endName`; // determine the distance for each bicep to be offset $deltaJoint[0] = ($endLoc[0] - $startLoc[0])/(float)($numOfMidJoints +1); $deltaJoint[1] = ($endLoc[1] - $startLoc[1])/(float)($numOfMidJoints +1); $deltaJoint[2] = ($endLoc[2] - $startLoc[2])/(float)($numOfMidJoints +1); // for num of biceps loc = (elbow loc - shoulder loc) / num biceps for ($j=0; $j<$numOfMidJoints; $j++) { $temp = `spaceLocator -n "midjoint#"`; $temp[0] = "|" + $temp[0]; move -a ($deltaJoint[0]*($j+1) +$startLoc[0]) ($deltaJoint[1]*($j+1) +$startLoc[1]) ($deltaJoint[2]*($j+1) +$startLoc[2]) $temp[0]; //print ("Parenting " + $temp[0] + " to " + $parent + "\n"); parent $temp[0] $parent; $midjoints[$j] = $parent + "|" + $temp[0]; } return $midjoints; } // Tests to see if an object has an input connnection to a particular attribute and if so then break the connection proc breakConnections(string $object, string $attribute) { string $source; if (`connectionInfo -isDestination ($object + "." + $attribute)`) { $source = `connectionInfo -sourceFromDestination ($object + "." + $attribute)`; disconnectAttr $source ($object + "." + $attribute); } } // Create expression to control the twisting of the biceps and forarms based on the shoulder x rotation and the wrist x rotation respectivley (with blending) proc createTwistExpression(string $skelFK[], string $skelIK[], string $skelBind[], string $skelBindBase[], int $numOfBiceps, int $numOfForearms) { string $bicepExp, $forearmExp; for ($j=0; $j<$numOfBiceps; $j++) { $bicepExp = $bicepExp + $skelBind[2+$j] + ".rotateX = ((" + $skelFK[1] + ".rotateX * $FKinf) + (" + $skelIK[1] + ".rotateX * $IKinf))/" + $numOfBiceps + ";\n"; } for ($j=0; $j<$numOfForearms; $j++) { $forearmExp = $forearmExp + $skelBind[2+$numOfBiceps+1+$j] + ".rotateX = ((" + $skelFK[3] + ".rotateX * $FKinf) + (" + $skelIK[3] + ".rotateX * $IKinf))/" + $numOfForearms + ";\n"; } $exp = "// calculate the fk and ik influence based on blend\nfloat $FKinf = 1-(" + $skelBindBase[0] + ".blend_fk_ik/10);\nfloat $IKinf = (" + $skelBindBase[0] + ".blend_fk_ik/10);\n// Calculate the bicep x rotation\n" + $bicepExp + "// Calculate the forearm x rotation\n" + $forearmExp; expression -s $exp -o "" -ae 1 -uc all; } // Create expression to control the twisting of the biceps and forarms based on the shoulder x rotation and the wrist x rotation respectivley (without blending) proc createTwistExpressionNoBlend(string $skel[], string $skelBind[], int $numOfBiceps, int $numOfForearms) { string $bicepExp, $forearmExp; for ($j=0; $j<$numOfBiceps; $j++) { $bicepExp = $bicepExp + $skelBind[2+$j] + ".rotateX = " + $skel[1] + ".rotateX/" + $numOfBiceps + ";\n"; } for ($j=0; $j<$numOfForearms; $j++) { $forearmExp = $forearmExp + $skelBind[2+$numOfBiceps+1+$j] + ".rotateX = " + $skel[3] + ".rotateX/" + $numOfForearms + ";\n"; } $exp = "// Calculate the bicep x rotation\n" + $bicepExp + "// Calculate the forearm x rotation\n" + $forearmExp; expression -s $exp -o "" -ae 1 -uc all; } // Create IK handles and pole vector for the arm proc createArmIKHandles(string $skelIK[], string $poleVecLoc, string $ikRoot, int $left, string $biped) { string $ikHandle[], $group, $parented[]; float $loc[], $ikSelOffset[] = {0,-2,0}; $ikHandle = `ikHandle -sj $skelIK[1] -ee $skelIK[3] -p 1 -w 1 -n "ikArmHandle#"`; // pole vector poleVectorConstraint $poleVecLoc $ikHandle[0]; // colour code the pole vec colourObjectWithColour($poleVecLoc, 2); // remove pole vector channels removeChannels({$poleVecLoc}, {"rx","ry","rz","sx","sy","sz"}, 1); // remove IK attributes removeChannels(removeElementAtIndex($skelIK, 0), {"tx","ty","tz","rx","ry","rz","sx","sy","sz"}, 0); // group the ikHandle $group = `group -em -n "ikArm#"`; // colour code the group colourObjectWithColour($group, 2); // move group pivot point to the ikHandle pivot point $loc = `xform -q -ws -rp $ikHandle[0]`; xform -ws -rp $loc[0] $loc[1] $loc[2] -sp $loc[0] $loc[1] $loc[2] $group; $parented = `parent $ikHandle[0] $group`; // rotate the group to match the wrist // make the group drive the wrist rotation //connectAttr -f ikArm1.rotate IK_L_wrist_1.rotate; //parent and freeze transform $parented = `parent $group $biped`; makeIdentity -apply true -t 1 -r 1 -s 1 $parented[0]; toggleSelectionHandleWithOffset($parented[0], $ikSelOffset); $parented = `parent $poleVecLoc $ikRoot`; makeIdentity -apply true -t 1 $parented[0]; toggleSelectionHandle($parented[0]); if ($left) { $ikSelOffset = {0,0,2}; } else { $ikSelOffset = {0,0,-2}; } toggleSelectionHandleWithOffset($skelIK[0], $ikSelOffset); } // adds an extra joint on the end (of the fk and ik arms) to help indicate the rotations of the arms by scaling the joint in one axis proc addRotIndicationJoint(string $skelFK[], int $selHandle, int $left) { float $vec[], $secLast[], $last[], $temp[]; string $joint; $secLast = `xform -q -ws -rp $skelFK[size($skelFK)-2]`; $last = `xform -q -ws -rp $skelFK[size($skelFK)-1]`; // get the vector from the second last to the last joint $vec = vecSub($last, $secLast); normalize($vec); // create our new joint offset from the last joint in the direction of vec //$joint = `joint -p ($vec[0]*0.5 + $last[0]) ($vec[1]*0.5 + $last[1]) ($vec[2]*0.5 + $last[2]) -n "RotIndication#"`; $joint = `joint -p ($vec[0]*0.5 + $last[0]) $last[1] $last[2] -n "RotIndication#"`; // scale the joint in only Z setAttr ($skelFK[size($skelFK)-1] + ".scaleZ") 4; parent $joint $skelFK[size($skelFK)-1]; // add selection handle? if ($selHandle) { if ($left == 1) { toggleSelectionHandleWithOffset($skelFK[size($skelFK)-1], {0.0,0,-0.2}); } else { toggleSelectionHandleWithOffset($skelFK[size($skelFK)-1], {0.0,0,0.2}); } } } global proc string[] modRigBuildArmSkeleton(string $roots[], string $arms[], int $left, string $biped) { // Declare some variables string $skelFK[], $skelFK2[], $skelIK[], $skelIK2[], $skelBind[], $skelBindBase[], $skelBindBase2[], $biceps[], $forearms[], $fullBindLocators[]; string $prefix, $ikHandles[], $temp[], $bicepExp, $forearmExp, $exp, $extraNaming; string $fkRoot, $ikRoot, $bindRoot, $poleVectorLoc, $ikGroup; float $upVector[], $upVectors[], $initialFKIKBlend, $upVectorLoc[], $upVectorLocRef[], $startJoint[], $endJoint[], $deltaJoint[]; int $i, $j, $numOfArms, $numOfBiceps, $numOfForearms, $createSkels[], $templateSkels[], $hideSkels[]; string $remFKAttrs[] = {"tx","ty","tz","sx","sy","sz"}; string $remAllAttrs[] = {"tx","ty","tz","rx","ry","rz","sx","sy","sz"}; float $bindSelOffset[] = {3,1,0}; //Initialise variables from the GUI $numOfBiceps = `intFieldGrp -q -v1 armNumOfBiceps`; $numOfForearms = `intFieldGrp -q -v1 armNumOfForearms`; $createSkels[0] = `checkBoxGrp -q -v1 armFkIkCheckBox`; $createSkels[1] = `checkBoxGrp -q -v2 armFkIkCheckBox`; $createSkels[2] = `checkBoxGrp -q -v3 armFkIkCheckBox`; $initialFKIKBlend = `radioButtonGrp -q -sl armFkIkInitialBlend` == 1 ? 0 : 10; // prefix contains the group name with a pipe for easy naming of locators etc... $prefix = $arms[0] + "|"; // If there is no joint selected, create root joint at first shoulder locator if (size($roots) < 1) { select -cl; warning "No root node selected. Creating a root joint at world 0...\n"; $fkRoot = $ikRoot = $bindRoot = `joint -p 0 0 0 -n "chest"`; } else if (size($roots) == 1) { $fkRoot = $ikRoot = $bindRoot = $roots[0]; } else if (size($roots) == 2) { if ($createSkels[0]) { $fkRoot = $roots[0]; if ($createSkels[1]) { $ikRoot = $roots[1]; } else { $bindRoot = $roots[1]; } } else { $ikRoot = $roots[0]; $bindRoot = $roots[1]; } } else if (size($roots) == 3) { $fkRoot = $roots[0]; $ikRoot = $roots[1]; $bindRoot = $roots[2]; } if ($left == 1) { $extraNaming = "L_"; $ikSelOffset = {0,0,2}; } else if ($left == 0) { $extraNaming = "R_"; } else { $extraNaming = ""; } // Build required skeleton and options for each arm for ($i=0; $i 3) { error "Too many root joints selected. The maximum is 3."; } if ($numOfSkelsToCreate == 0) { error "No Skeletons to create..."; } else if ($numOfSkelsToCreate == 1 && size($roots) > 1) { error "Too many root joints selected"; } else if ($numOfSkelsToCreate == 3 && size($roots) == 2) { error "To create IK, FK and Bind skeletons you must have 0, 1 or 3 roots selected, not 2."; } // Check that all locators are present to create a foot/leg if (size($locs) < 1) { error "No Locator Groups selected"; } for ($i=0; $i 0) { reportMissing($missing, $locs[$i], 0); } else { $legs[size($legs)] = $locs[$i]; } } if (size($legs) > 0) { $return = modRigBuildReverseFootSkeleton($roots, $legs, $left); } return $return; } // Creates the IK handles for the reverse foot and parent the handles to the IK leg proc createReverseFootIKHandles(string $skelIK[], string $heelSkel[], string $poleVecLoc) { string $temp[]; // create ik between hip and ankle $temp = `ikHandle -sj $skelIK[0] -ee $skelIK[2] -p 1 -w 1`; $ikHandles[0] = $temp[0]; // add pole vector to the knee poleVectorConstraint $poleVecLoc $ikHandles[0]; removeChannels({$poleVecLoc}, {"rx","ry","rz","sx","sy","sz"}, 1); // colour code the pole vec colourObjectWithColour($poleVecLoc, 2); // add ik to the foot $temp = `ikHandle -sj $skelIK[2] -ee $skelIK[4] -p 1 -w 1`; $ikHandles[1] = $temp[0]; $temp = `ikHandle -sj $skelIK[4] -ee $skelIK[5] -p 1 -w 1`; $ikHandles[2] = $temp[0]; // Parent them to the appropriate bone on the heel control skeleton parent $ikHandles[0] $heelSkel[4]; parent $ikHandles[1] $heelSkel[2]; parent $ikHandles[2] $heelSkel[1]; parent $poleVecLoc $heelSkel[0]; // freeze transforms on the pole vector and toggle selection handles... need to do this AFTER the parenting makeIdentity -apply true -t 1 ($heelSkel[0] + "|" + $poleVecLoc); toggleSelectionHandle($heelSkel[0] + "|" + $poleVecLoc); } // Create the roll attribute for the reverse foot heel proc createReverseFootRollKeys(string $heelSkel[], string $controlNode) { // Add the roll attribute to the control node addAttr -ln roll -at double -min -5 -max 5 -dv 0 $controlNode; setAttr -e -keyable true ($controlNode + ".roll"); setDrivenKeyframe -cd ($controlNode + ".roll") -dv 0 -v 0 ($heelSkel[0] + ".rotateZ"); setDrivenKeyframe -cd ($controlNode + ".roll") -dv (-5) -v (20) ($heelSkel[0] + ".rotateZ"); setDrivenKeyframe -cd ($controlNode + ".roll") -dv 0 -v 0 ($heelSkel[2] + ".rotateZ"); setDrivenKeyframe -cd ($controlNode + ".roll") -dv (5) -v (30) ($heelSkel[2] + ".rotateZ"); setDrivenKeyframe -cd ($controlNode + ".roll") -dv 0 -v 0 ($heelSkel[1] + ".rotateZ"); setDrivenKeyframe -cd ($controlNode + ".roll") -dv (5) -v (30) ($heelSkel[1] + ".rotateZ"); } global proc string modRigBuildReverseFootSkeleton(string $roots[], string $legs[], int $left) { // Declare some variables... string $skelFK[], $skelFK2[], $skelIK[], $skelIK2[], $skelBind[], $skelBind2[], $heelSkel[], $heelSkel2[]; string $prefix, $ikHandles[], $poleVecLoc, $temp[], $footGroup, $extraNaming; string $fkRoot, $ikRoot, $bindRoot; float $upVector[], $upVectors[], $reverseFootUpVectors[], $jointLoc[], $initialFKIKBlend, $upVectorLoc[], $upVectorLocRef[]; int $i, $j, $numOfLegs, $createSkels[], $templateSkels[], $hideSkels[]; string $remFKAttrs[] = {"tx","ty","tz","sx","sy","sz"}; string $remAllAttrs[] = {"tx","ty","tz","rx","ry","rz","sx","sy","sz"}; //Initialise variables from the GUI $createSkels[0] = `checkBoxGrp -q -v1 legFkIkCheckBox`; $createSkels[1] = `checkBoxGrp -q -v2 legFkIkCheckBox`; $createSkels[2] = `checkBoxGrp -q -v3 legFkIkCheckBox`; $initialFKIKBlend = `radioButtonGrp -q -sl legFkIkInitialBlend` == 1 ? 0 : 10; // prefix contains the group name with a pipe for easy naming of locators etc... $prefix = $legs[0] + "|"; // If there is no joint selected, create root joint at first hip locator if (size($roots) < 1) { select -cl; warning "No root node selected. Creating a root joint at world 0...\n"; $fkRoot = $ikRoot = $bindRoot = `joint -p 0 0 0 -n "tail"`; } else if (size($roots) == 1) { $fkRoot = $ikRoot = $bindRoot = $roots[0]; } else if (size($roots) == 2) { if ($createSkels[0]) { $fkRoot = $roots[0]; if ($createSkels[1]) { $ikRoot = $roots[1]; } else { $bindRoot = $roots[1]; } } else { $ikRoot = $roots[0]; $bindRoot = $roots[1]; } } else if (size($roots) == 3) { $fkRoot = $roots[0]; $ikRoot = $roots[1]; $bindRoot = $roots[2]; } if ($left == 1) { $extraNaming = "L_"; } else if ($left == 0) { $extraNaming = "R_"; } else { $extraNaming = ""; } // Build required skeleton and options for each leg for ($i=0; $i 0 ? $numOfFingers-1 : 1) * 2); $Y = 0; $totSpread = $deltaFinger*($numOfFingers-1); // for each finger create a locator to indicate the tip of the finger for ($i=0; $i<$numOfHands; $i++) { // position the finger tips for ($j=0; $j<$numOfFingers; $j++) { $fingerTipNames[$j] = ("fingerTip"+$j); $fingerTips[$j*3] = $left ? $X : -$X; $fingerTips[$j*3 + 1] = $Y; $fingerTips[$j*3 + 2] = (linstep(0,$numOfFingers-1,$j)-0.5)*$totSpread; } // position the main knuckles for ($j=0; $j<$numOfFingers; $j++) { $fingerKnuckleNames[$j] = ("fingerKnuckle"+$j); $fingerKnuckles[$j*3] = $left ? $X/2 : -$X/2; $fingerKnuckles[$j*3 + 1] = $Y; $fingerKnuckles[$j*3 + 2] = (linstep(0,$numOfFingers-1,$j)-0.5)*$totSpread; } if ($thumb) { //Position the thumb $fingerTipNames[$numOfFingers] = "thumbTip"; $fingerTips[$numOfFingers*3] = $left ? $X/2 : -$X/2; $fingerTips[$numOfFingers*3+1] = $Y-$deltaFinger; $fingerKnuckleNames[$numOfFingers] = "thumbKnuckle"; $fingerKnuckles[$numOfFingers*3] = $left ? $X/4 : -$X/4; $fingerKnuckles[$numOfFingers*3+1] = $Y-$deltaFinger; $fingerKnuckles[$numOfFingers*3+2] = $fingerTips[$numOfFingers*3+2] = $totSpread/2 + $deltaFinger; } $group = createLocGroupTree("Hand", $fingerKnuckleNames, $fingerTipNames, $fingerKnuckles, $fingerTips, 0.15); // Create a locator for the ridge joint... if ($numOfFingers%2==1) { if ($left) { createLoc("ridge", $group, {$X/3,$Y,0}, 0.1); } else { createLoc("ridge", $group, {-$X/3,$Y,0}, 0.1); } } else { if ($left) { createLoc("ridge", $group, {$X/3,$Y,$deltaFinger/2}, 0.1); } else { createLoc("ridge", $group, {-$X/3,$Y,$deltaFinger/2}, 0.1); } } // Create a locator for the wrist joint... createLoc("wrist", $group, {0.0,$Y,0}, 0.1); // Create a locator for the up vector of a joint... if ($left) { createLoc("fingerKnuckleUpVector", ($group+"|fingerKnuckle0"), {$X/2,$Y+0.2,$fingerKnuckles[2]}, 0.05); if ($thumb) { createLoc("thumbUpVector", ($group+"|thumbKnuckle"), {$X/4,$Y-$deltaFinger,$totSpread/2+$deltaFinger*2}, 0.05); } } else { createLoc("fingerKnuckleUpVector", ($group+"|fingerKnuckle0"), {-$X/2,$Y+0.2,$fingerKnuckles[2]}, 0.05); if ($thumb) { createLoc("thumbUpVector", ($group+"|thumbKnuckle"), {-$X/4,$Y-$deltaFinger,$totSpread/2+$deltaFinger*2}, 0.05); } } if ($left) { setAttr ($group + ".tx") 10.5; } else { setAttr ($group + ".tx") -10.5; } setAttr ($group + ".ty") 17; } select -r $group; return $group; } global proc modRigPreBuildHand(string $roots[], string $locs[]) { string $knuckles[], $tips[], $hands[], $roots[]; int $numOfSkelsToCreate, $tipExists, $i, $j, $k, $numOfFingers, $numOfRidges; // Check that if only FK, IK or only Bind is checked then ensure that only 1 root is selected... // if more than one is checked then ensure that at least 1 and no more than 3 roots are selected... $numOfSkelsToCreate += `checkBoxGrp -q -v1 handFkIkCheckBox` + `checkBoxGrp -q -v2 handFkIkCheckBox` + `checkBoxGrp -q -v3 handFkIkCheckBox`; if (size($roots) > 3) { error "Too many root joints selected. The maximum is 3."; } if ($numOfSkelsToCreate == 0) { error "No Skeletons to create..."; } else if ($numOfSkelsToCreate == 1 && size($roots) > 1) { error "Too many root joints selected"; } else if ($numOfSkelsToCreate == 3 && size($roots) == 2) { error "To create IK, FK and Bind skeletons you must have 0, 1 or 3 roots selected, not 2."; } if (`checkBoxGrp -q -v2 handFkIkCheckBox`) { error "Do not support IK hands yet..."; } // Check that all locators are present to create a hand if (size($locs) < 1) { error "No Locator Groups selected"; } for ($i=0; $i 0) { $knuckleLoc = `xform -q -ws -rp $thumb`; // create an intermediate joint 25% between root and knuckle $jointLocs[0] = ($knuckleLoc[0] - $rootLoc[0])*.25 + $rootLoc[0]; $jointLocs[1] = ($knuckleLoc[1] - $rootLoc[1])*.25 + $rootLoc[1]; $jointLocs[2] = ($knuckleLoc[2] - $rootLoc[2])*.25 + $rootLoc[2]; $jointNames[0] = "palm"; // Get the knuckle and the tip locator positions $relatives = `listRelatives -f $thumb`; for ($rel in $relatives) { // check that the name contains tip if (stringContains($rel, "tip", 0)) { $tipLocator = $rel; } else if (stringContains($rel, "upvector", 0)) { $upVectorLoc = $rel; } } $tipLoc = `xform -q -ws -rp $tipLocator`; // get the upvector locators position $upVectorLocPos = `xform -q -ws -rp $upVectorLoc`; // calculate the up vector $upVector = vecSub($upVectorLocPos, $knuckleLoc); // calculate the vector between the joints $deltaJoint = vecSub($tipLoc, $knuckleLoc); for ($i=1; $i<=$numOfKnuckles; $i++) { $step = linstep(0, $numOfKnuckles-1, $i-1); $jointLocs[size($jointLocs)] = $knuckleLoc[0] + ($step * $deltaJoint[0]); $jointLocs[size($jointLocs)] = $knuckleLoc[1] + ($step * $deltaJoint[1]); $jointLocs[size($jointLocs)] = $knuckleLoc[2] + ($step * $deltaJoint[2]); $jointNames[$i] = "knuckle"; } $newThumb = modRigBuildJoints($root, $jointLocs, $upVector, $jointNames, "FK_"); return $newThumb; } else { return {}; } } proc float[] getFingerUpVector(string $hand) { int $flag; string $relatives[], $rel, $firstFinger, $upVectorLocator; float $knuckleLoc[], $upVectorLocPos[], $upVector[]; $relatives = `listRelatives -f $hand`; for ($rel in $relatives) { // check that the name contains finger if (stringContains($rel, "finger", 0) && $flag != 1) { $firstFinger = $rel; $flag = 1; } } $flag = 0; $relatives = `listRelatives -f $firstFinger`; for ($rel in $relatives) { // check that the name contains finger if (stringContains($rel, "upvector", 0) && $flag != 1) { $upVectorLocator = $rel; $flag = 1; } } if ($flag) { $knuckleLoc = `xform -q -ws -rp $firstFinger`; $upVectorLocPos = `xform -q -ws -rp $upVectorLocator `; $upVector = vecSub($upVectorLocPos, $knuckleLoc); } else { $upVector = {0,1,0}; } normalize($upVector); return $upVector; } global proc modRigBuildHand(string $roots[], string $hands[]) { // Declare some variables... string $midFingerFK[], $midFingerFK2[], $midFingerIK[], $midFingerIK2[], $midFingerBind[]; string $ridgeLeftFK[], $ridgeLeftFK2[], $ridgeLeftIK[], $ridgeLeftIK2[], $ridgeLeftBind[]; string $ridgeRightFK[], $ridgeRightFK2[], $ridgeRightIK[], $ridgeRightIK2[], $ridgeRightBind[]; string $fullSkelFK[], $fullSkelFK2[], $fullSkelIK[], $fullSkelIK2[], $fullSkelBind[], $fullSkelBind2[]; string $prefix, $jointNames[], $midFinger, $wrist, $ridge, $ridgeFingers[], $newFinger[], $newThumb[]; string $fkRoot, $ikRoot, $bindRoot; string $remFKAttrs[] = {"tx","ty","tz","sx","sy","sz"}; string $remAllAttrs[] = {"tx","ty","tz","rx","ry","rz","sx","sy","sz"}; float $upVector[], $jointLocs[], $initialFKIKBlend, $upVectorLoc[], $upVectorLocRef[]; int $i, $j, $createSkels[], $templateSkels[], $hideSkels[], $numOfKnuckles, $numOfFingers; //Initialise variables from the GUI $numOfKnuckles = `intFieldGrp -q -v1 handNumOfKnuckles`; $createSkels[0] = `checkBoxGrp -q -v1 handFkIkCheckBox`; $createSkels[1] = `checkBoxGrp -q -v2 handFkIkCheckBox`; $createSkels[2] = `checkBoxGrp -q -v3 handFkIkCheckBox`; $initialFKIKBlend = `radioButtonGrp -q -sl handFkIkInitialBlend` == 1 ? 0 : 10; // prefix contains the group name with a pipe for easy naming of locators etc... $prefix = $hands[0] + "|"; // If there is no joint selected, create root joint at first shoulder locator if (size($roots) < 1) { select -cl; warning "No root node selected. Creating a root joint at world 0...\n"; $fkRoot = $ikRoot = $bindRoot = `joint -p 0 0 0 -n "aRoot"`; } else if (size($roots) == 1) { $fkRoot = $ikRoot = $bindRoot = $roots[0]; } else if (size($roots) == 2) { if ($createSkels[0]) { $fkRoot = $roots[0]; if ($createSkels[1]) { $ikRoot = $roots[1]; } else { $bindRoot = $roots[1]; } } else { $ikRoot = $roots[0]; $bindRoot = $roots[1]; } } else if (size($roots) == 3) { $fkRoot = $roots[0]; $ikRoot = $roots[1]; $bindRoot = $roots[2]; } // Build required skeleton and options for each hand for ($i=0; $i 0) { createCurl($midFingerFK[0], "thumb", $newThumb, 3, 1, 2); } appendStringArray($fullSkelFK, $newThumb, size($newThumb)); createCupping($midFingerFK[0], $ridgeLeftFK, $ridgeRightFK); // lock and remove FK attributes removeChannels($fullSkelFK, $remFKAttrs, 1); // add selection handles for just the wrist toggleSelectionHandle($fullSkelFK[0]); // colour code colourObjectWithColour($fullSkelFK[0], 1); // If FK is selected but not IK and size of roots is 3 then we create 2 FK skeletons... if ($createSkels[1] == 0 && size($roots) == 3) { // Create the middle finger // ************************************************************************COULD BE OPTIMISED BY NOT RECALCULATING A LOT OF THIS... trade off more conditionals $jointLocs = calculateMiddleFinger($wrist, $ridge, $midFinger, $numOfKnuckles); $jointNames = createMiddleFingerJointNames($numOfKnuckles); $midFingerFK2 = modRigBuildJoints($ikRoot, $jointLocs, $upVector, $jointNames, "FK_"); if (size($midFingerFK2) != $numOfKnuckles+3) { error ("Number of expected joints on midFingerFK2 does not equal " + ($numOfKnuckles+3) + ".\n"); } // NEED TO CREATE A VARIABLE WHICH HAS EVERY* JOINT OF THE HAND IN IT TO USE FOR THE FK IK BLENDING $fullSkelFK2 = $midFingerFK2; // Create the left Ridge $jointLocs = calculateRidge($ikRoot, $midFingerFK[1], $midFinger, $hands[$i], 1); $jointNames = createRidgeJointNames(size($jointLocs)/3); $ridgeFingers = getRidgeFingers($midFinger, $hands[$i], 1); $ridgeLeftFK2 = modRigBuildJoints($midFingerFK2[1], $jointLocs, $upVector, $jointNames, "FK_"); if (size($ridgeLeftFK2) != (size($ridgeFingers)+1)) { error ("Number of expected joints on ridgeLeftFK2 does not equal " + (size($ridgeFingers)+1) + ".\n"); } // add to full hand skeleton array appendStringArray($fullSkelFK2, $ridgeLeftFK2, size($ridgeLeftFK2)); for ($j=0; $j 0) { createCurl($midFingerFK2[0], "thumb", $newThumb, 3, 1, 2); } appendStringArray($fullSkelFK2, $newThumb, size($newThumb)); createCupping($midFingerFK2[0], $ridgeLeftFK2, $ridgeRightFK2); // lock and remove FK attributes removeChannels($fullSkelFK2, $remFKAttrs, 1); // add selection handles for just the wrist toggleSelectionHandle($fullSkelFK2[0]); // colour code colourObjectWithColour($fullSkelFK2[0], 2); } } if ($createSkels[1]) { } if ($createSkels[2]) { // Create the middle finger // ************************************************************************COULD BE OPTIMISED BY NOT RECALCULATING A LOT OF THIS... trade off more conditionals $jointLocs = calculateMiddleFinger($wrist, $ridge, $midFinger, $numOfKnuckles); $jointNames = createMiddleFingerJointNames($numOfKnuckles); $midFingerBind = modRigBuildJoints($bindRoot, $jointLocs, $upVector, $jointNames, "BIND_"); if (size($midFingerBind) != $numOfKnuckles+3) { error ("Number of expected joints on midFingerBind does not equal " + ($numOfKnuckles+3) + ".\n"); } // NEED TO CREATE A VARIABLE WHICH HAS EVERY* JOINT OF THE HAND IN IT TO USE FOR THE FK IK BLENDING $fullSkelBind = $midFingerBind; // Create the left Ridge $jointLocs = calculateRidge($bindRoot, $midFingerBind[1], $midFinger, $hands[$i], 1); $jointNames = createRidgeJointNames(size($jointLocs)/3); $ridgeFingers = getRidgeFingers($midFinger, $hands[$i], 1); $ridgeLeftBind = modRigBuildJoints($midFingerBind[1], $jointLocs, $upVector, $jointNames, "BIND_"); if (size($ridgeLeftBind) != (size($ridgeFingers)+1)) { error ("Number of expected joints on ridgeLeftBind does not equal " + (size($ridgeFingers)+1) + ".\n"); } // add to full hand skeleton array appendStringArray($fullSkelBind, $ridgeLeftBind, size($ridgeLeftBind)); for ($j=0; $j 3) { error "Too many root joints selected. The maximum is 3."; } if ($numOfSkelsToCreate == 0) { error "No Skeletons to create..."; } else if ($numOfSkelsToCreate == 1 && size($roots) > 1) { error "Too many root joints selected"; } else if ($numOfSkelsToCreate == 3 && size($roots) == 2) { error "To create Cube, IK and Bind skeletons you must have 0, 1 or 3 roots selected, not 2."; } // Check that all locators are present to create a spine if (size($locs) < 1) { error "No Locator Groups selected"; } // check that all the locators required for a spine are present (will work for curves as well as locators) for ($i=0; $i 0) { reportMissing($missing,$locs[$i],0); } else { $spines[size($spines)] = $locs[$i]; } } // create the spines if they are valid if (size($spines)) { $bindSkel = modRigBuildSpine($roots, $spines); } return $bindSkel; } // Calculates the joint locs along the spine curve... $numJoints is major and minor joints but not including the 'extra' joint proc float[] getJointLocs(string $spine, int $numJoints) { int $i; float $jointLocs[], $jointLoc[]; string $locators[], $locator, $mPath; string $curve = ($spine + "|spineCurve"); // We have to use a motion path because pointOnCurve and arcLength only work in parametric units // create a locator $locators = `spaceLocator`; $locator = $locators[0]; // attatch the locator with a motion path to the curve $mPath = `pathAnimation -c $curve -stu 1 -etu 1 -fm 1 $locator`; // move the u and sample the world space of the locator to get the jointLoc setAttr ($mPath + ".uValue") 0; $jointLoc = `xform -q -ws -rp $locator`; // Add the $jointLoc to the $jointLocs array for ($i=0; $i<3; $i++) { $jointLocs[size($jointLocs)] = $jointLoc[$i]; } // Calculate the 'extra' joint setAttr ($mPath + ".uValue") ((1.0/(float)($numJoints-1))/2.0); $jointLoc = `xform -q -ws -rp $locator`; for ($i=0; $i<3; $i++) { $jointLocs[size($jointLocs)] = $jointLoc[$i]; } // Calculate all the other joints for ($i=1; $i<$numJoints; $i++) { setAttr ($mPath + ".uValue") ((1.0/(float)($numJoints-1))*$i); $jointLoc = `xform -q -ws -rp $locator`; for ($j=0; $j<3; $j++) { $jointLocs[size($jointLocs)] = $jointLoc[$j]; } } // clean up delete $locator $mPath; return $jointLocs; } // creates the joint names... $numJoints is major and minor joints but not including the 'extra' joint proc string[] getJointNames(int $numOfMajVert, int $numOfMinVert) { int $i; string $names[]; $names = {"spineBase", "extraJoint"}; for ($j=0; $j<$numOfMinVert; $j++) { $names[size($names)] = "minVert"; } for ($i=1; $i<$numOfMajVert-1; $i++) { $names[size($names)] = "majVert"; for ($j=0; $j<$numOfMinVert; $j++) { $names[size($names)] = "minVert"; } } $names[size($names)] = "topVert"; return $names; } proc string createClusterHandle(string $curve, int $cv, string $name, float $selOffset[]) { string $cluster[]; string $remAttrs[] = {"tx","ty","tz","rx","ry","rz","sx","sy","sz"}; // add clusters to the curve $cluster = `cluster -n ($name + "Cluster") -rel -en 1 ($curve + ".cv["+$cv+"]")`; // add a selection handle to the cluster handle toggleSelectionHandleWithOffset($cluster[1], $selOffset); // colour cluster colourObjectWithColour($cluster[1], 2); return $cluster[1]; } proc string createSplineIK(string $root, string $startJoint, string $endEffector, string $curve, string $name) { string $ikHandleObjects[], $clusters[], $group; float $loc[]; $clusters[0] = createClusterHandle($curve, 1, "base", {0.0,0,-2}); $clusters[1] = createClusterHandle($curve, 2, "mid", {0.0,0,-2}); $clusters[2] = createClusterHandle($curve, 3, "top", {0.0,0,-2}); // group the clusters $group = `group -n "Clusters" $clusters[0] $clusters[1] $clusters[2]`; // move the pivot point of the cluster group to the pivot point of the root and parent it $loc = `xform -q -ws -rp $root`; xform -ws -rp $loc[0] $loc[1] $loc[2] $group; parent $group $root; // create an ikSpline $ikHandleObjects = `ikHandle -n $name -sj $startJoint -ee $endEffector -c $curve -sol "ikSplineSolver" -ccv 0 -pcv 1 -roc 0`; // add the twist attribute to the base cluster and connect it to the IK handle addAttr -ln twist -at double $clusters[0]; setAttr -e -keyable true ($clusters[0] + ".twist"); connectAttr ($clusters[0] + ".twist") ($ikHandleObjects[0] + ".twist"); // return the ikHandle return ("|" + $ikHandleObjects[0]); } proc string createCubeSetup(string $nonRootCubeJoints[], int $numOfMinVert) { string $temp[], $cube, $cubes[], $group, $groups[], $cubeGroup, $cmd, $cubeJoints[]; int $i, $currMinVert, $lastMajVert; string $remCubeGeoAttrs[] = {"tx","ty","tz","rx","ry","rz","sx","sy","sz"}; string $remCubeGroupAttrs[] = {"tx","ty","tz","sx","sy","sz"}; // some references need to be reference from the world root $cubeJoints = addRootReference($nonRootCubeJoints); $cubeGroup = ("|" + `group -n "Cubes" -em`); // create the cube at world 0 $temp = `polyCube -w 1 -h 1 -d 1 -sx 1 -sy 1 -sz 1 -ax 0 1 0 -tx 1 -ch 0`; // we store all the created cubes in the cubes array // we use index 1 here purely to help in the loops later where we ignore the extra joint // basically because the loop index starts at 2 and we need to reference the root joint cube we just set it to one // so that the inital loop will be 2 - 1 to get to the first cube (so we can skip the extra joint which sits at index 1 of cubeJoints) $cubes[1] = $temp[0]; // disable all cube rendering attributes (except double sided) setAndLockAttrs($cubes[1], {"castsShadows", "receiveShadows", "motionBlur", "primaryVisibility", "smoothShading", "visibleInReflections", "visibleInRefractions"}, 0); // orient the cube to the same axis as the joint $temp = `orientConstraint $cubeJoints[0] $cubes[1]`; delete $temp[0]; // group the cube to help with animation $group = `group -n "cube#" $cubes[1]`; $groups[1] = $group; // colour code the group colourObjectWithColour($groups[1], 1); //point constrain the group to the joint pointConstraint $cubeJoints[0] ("|" + $group); //orient constrain the point to the cube orientConstraint -n "orCon" $cubes[1] $cubeJoints[0]; // add selection handle to major cube toggleSelectionHandle($groups[1]); //parent the new cube group to the total cube group parent ("|" + $group) $cubeGroup; // do the same as above for the rest of the joints skipping the 'extra joint' for ($i=2; $i 0) { for ($i=2; $i 0) { reportMissing($missing, $locs[$i], 0); } else { // duplicate the groups duplicate ($locs[$i]+"|Arm") ($locs[$i]+"|Hand") ($locs[$i]+"|Leg"); // currently the hand groups pivot point is at the wrist not at world 0 so we must move it to world 0 to mirror move -a 0 0 0 ($locs[$i]+ "|Hand1.scalePivot") ($locs[$i]+ "|Hand1.rotatePivot"); // mirror the locators scale $sx $sy $sz ($locs[$i]+"|Arm1") ($locs[$i]+"|Hand1") ($locs[$i]+"|Leg1"); } } } proc createBipedCOGSetup(string $driver, string $cog, string $anim, string $expr) { string $animBuffer[], $exprBuffer[]; // add the extra attribute to our driver node addAttr -ln blend_anim_expr -at double -min 0 -max 10 -dv 0 $driver; setAttr -e -keyable true ($driver + ".blend_anim_expr"); // add the orient constraint $constraints = `orientConstraint -w 1 -n "orCon" $anim $expr $cog`; // As our locators are full paths we need to get just the dag node name in short form to use for the aim constraints. $numAnimTokens = `tokenize $anim "|" $animBuffer`; $numExprTokens = `tokenize $expr "|" $exprBuffer`; // *********THIS IS NAUGHTY... I should be querying the orient constraint to obtain the weights... not just assume it is W0 and W1 setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 0 -v 1 ($constraints[0] + "." + $animBuffer[$numAnimTokens-1] + "W0"); setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 0 -v 0 ($constraints[0] + "." + $exprBuffer[$numExprTokens-1] + "W1"); setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 10 -v 0 ($constraints[0] + "." + $animBuffer[$numAnimTokens-1] + "W0"); setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 10 -v 1 ($constraints[0] + "." + $exprBuffer[$numExprTokens-1] + "W1"); // add the point constraint $constraints = `pointConstraint -w 1 -n "pointCon" $anim $expr $cog`; // *********THIS IS NAUGHTY... I should be querying the orient constraint to obtain the weights... not just assume it is W0 and W1 setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 0 -v 1 ($constraints[0] + "." + $animBuffer[$numAnimTokens-1] + "W0"); setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 0 -v 0 ($constraints[0] + "." + $exprBuffer[$numExprTokens-1] + "W1"); setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 10 -v 0 ($constraints[0] + "." + $animBuffer[$numAnimTokens-1] + "W0"); setDrivenKeyframe -cd ($driver + ".blend_anim_expr") -dv 10 -v 1 ($constraints[0] + "." + $exprBuffer[$numExprTokens-1] + "W1"); } global proc modRigPreBuildBiped() { string $missing[], $locs[], $roots[], $bipeds[], $skel[], $arm[], $buffer[], $temp[], $group, $biped, $prefix, $foot, $foot1; float $loc[]; int $numTokens; // get the locator and root selections $locs = getSelected(1); $roots = getSelected(0); if (size($locs) < 1) { error "No Locator Groups selected"; } for ($i=0; $i 0) { reportMissing($missing, $locs[$i], 0); } else { $biped = `group -em -n "BIPED#"`; $skel = modRigPreBuildSpine($roots, {$locs[$i] + "|Spine"}); $foot = modRigPreBuildReverseFootSkeleton({$skel[0]}, {$locs[$i] + "|Leg"}, 1); $foot1 = modRigPreBuildReverseFootSkeleton({$skel[0]}, {$locs[$i] + "|Leg1"}, 0); $arm = modRigPreBuildArmSkeleton({$skel[size($skel)-1]}, {$locs[$i] + "|Arm"}, 1, $biped); modRigPreBuildHand({$arm[size($arm)-1]}, {$locs[$i] + "|Hand"}); $arm = modRigPreBuildArmSkeleton({$skel[size($skel)-1]}, {$locs[$i] + "|Arm1"}, 0, $biped); modRigPreBuildHand({$arm[size($arm)-1]}, {$locs[$i] + "|Hand1"}); // add extra top group nodes // first tokenize $skel[0] on | $numTokens = `tokenize $skel[0] "|" $buffer`; // group and move pivot to the spine base $group = `group -n "Offset#" $buffer[0]`; $prefix = $group; $loc = `xform -q -ws -rp $buffer[0]`; xform -ws -rp $loc[0] $loc[1] $loc[2] $group; // group and move pivot to the spine base $cog = `group -n "COG#" $group`; $prefix = $cog + "|" + $prefix; xform -ws -rp $loc[0] $loc[1] $loc[2] $cog; // group and move pivot to 0, 0, 0 parent $cog $biped; $prefix = "|" + $biped + "|" + $prefix; xform -ws -rp 0 0 0 $biped; // create the two locators to blend between expression centre of gravity and animation string $newLoc[] = `spaceLocator -n "Animation#"`; string $animLoc = $newLoc[0]; move -a $loc[0] $loc[1] $loc[2] $animLoc; makeIdentity -apply true -t 1 -r 1 -s 1 $animLoc; $newLoc = `spaceLocator -n "Expression#"`; string $expLoc = $newLoc[0]; move -a $loc[0] $loc[1] $loc[2] $expLoc; makeIdentity -apply true -t 1 -r 1 -s 1 $expLoc; $temp = `parent $animLoc $biped`; $animLoc = $temp[0]; // colour code the anim locator colourObjectWithColour($animLoc, 1); toggleSelectionHandleWithOffset($animLoc, {0,-2,0}); $temp = `parent $expLoc $biped`; $expLoc = $temp[0]; hide $expLoc; // parent feet to biped parent $foot $foot1 $biped; // add the expression to control the expression -s ($expLoc+".translateX = ("+$foot+".translateX + "+$foot1+".translateX)/2;\r"+$expLoc+".translateZ = ("+$foot+".translateZ + "+$foot1+".translateZ)/2;\r"+$expLoc+".rotateY = ("+$foot+".rotateY + "+$foot1+".rotateY)/2;\r\r") -o "" -ae 1 -uc all ; // add the point and orient constraints createBipedCOGSetup($prefix + $skel[0], $cog, $animLoc, $expLoc); // delete the locators delete $locs[$i]; select $biped; } } } //###################################################################################### //# GUI //###################################################################################### global proc toggleSpineGUI() { int $createSkels[], $templateSkels[], $hideSkels[]; //Initialise variables from the GUI $createSkels[0] = `checkBoxGrp -q -v1 spineFkIkCheckBox`; $createSkels[1] = `checkBoxGrp -q -v2 spineFkIkCheckBox`; $createSkels[2] = `checkBoxGrp -q -v3 spineFkIkCheckBox`; //legFkIkInitialBlend radioButtonGrp -e -en ($createSkels[0] && $createSkels[1] && $createSkels[2]) spineFkIkInitialBlend; } global proc toggleLegGUI() { int $createSkels[], $templateSkels[], $hideSkels[]; //Initialise variables from the GUI $createSkels[0] = `checkBoxGrp -q -v1 legFkIkCheckBox`; $createSkels[1] = `checkBoxGrp -q -v2 legFkIkCheckBox`; $createSkels[2] = `checkBoxGrp -q -v3 legFkIkCheckBox`; //legFkIkInitialBlend radioButtonGrp -e -en ($createSkels[0] && $createSkels[1] && $createSkels[2]) legFkIkInitialBlend; } global proc toggleArmGUI() { int $createSkels[], $templateSkels[], $hideSkels[]; //Initialise variables from the GUI $createSkels[0] = `checkBoxGrp -q -v1 armFkIkCheckBox`; $createSkels[1] = `checkBoxGrp -q -v2 armFkIkCheckBox`; $createSkels[2] = `checkBoxGrp -q -v3 armFkIkCheckBox`; //legFkIkInitialBlend radioButtonGrp -e -en ($createSkels[0] && $createSkels[1] && $createSkels[2]) armFkIkInitialBlend; } global proc toggleHandGUI() { int $createSkels[], $templateSkels[], $hideSkels[]; //Initialise variables from the GUI $createSkels[0] = `checkBoxGrp -q -v1 handFkIkCheckBox`; $createSkels[1] = `checkBoxGrp -q -v2 handFkIkCheckBox`; $createSkels[2] = `checkBoxGrp -q -v3 handFkIkCheckBox`; //legFkIkInitialBlend radioButtonGrp -e -en ($createSkels[0] && $createSkels[1] && $createSkels[2]) handFkIkInitialBlend; } global proc buildModularRigWindow(string $modularRigWindow) { string $winPrefix = "//aa_server3/work/maya_scripts/icons/"; string $nixPrefix = "/usr/work/maya_scripts/icons/"; string $iconPrefix; window -menuBar true -menuBarVisible true -title "ModularRig v0.1" -iconName "ModularRig" -titleBar true -minimizeButton true -maximizeButton true -h 735 -w 375 -sizeable true $modularRigWindow; menu -label "Help" -tearOff false; menuItem -label "Help on modularRig." -c "doModularRigHelp()"; string $form = `formLayout -numberOfDivisions 100`; string $scroll = `scrollLayout -verticalScrollBarThickness 16 -horizontalScrollBarThickness 0`; columnLayout -rs 5 -adjustableColumn true; rowLayout -numberOfColumns 2 -columnWidth2 50 350 -ct2 "left" "left" -co2 5 15; //text at top if ( `about -nt`) { image -w 50 -h 20 -image "//aa_server3/work/maya_scripts/gmd_logo.gif"; $iconPrefix = $winPrefix; } else { image -w 50 -h 20 -image "/usr/work/maya_scripts/gmd_logo.gif"; $iconPrefix = $nixPrefix; } text -label "(C)DP 2003. Programmed by Stuart Bryson" -align "left"; setParent ..; //################################################ BIPED ################################################ //symbolButton -image ($iconPrefix + "DPRightHandLayout.xpm") -c "modRigLayoutBiped(0)"; //symbolButton -image ($iconPrefix + "DPRightHandLayout.xpm") -c "modRigLayoutBiped(1)"; //symbolButton -image ($iconPrefix + "DPRightHandBuild.xpm") -c "modRigPreBuildBiped()"; frameLayout -label "Biped" -cl 0 -labelAlign "center" -borderStyle "etchedIn" -cll true; columnLayout -rs 5 -adjustableColumn true; rowLayout -numberOfColumns 3 -columnWidth3 34 34 282; symbolButton -image ($iconPrefix + "DPBipedHalfLayout.xpm") -c "modRigLayoutBiped(0)"; symbolButton -image ($iconPrefix + "DPBipedLayoutMirror.xpm") -c "modRigMirrorBiped()"; radioButtonGrp -nrb 3 -label "Mirror Axis:" -l1 "X" -l2 "Y" -l3 "Z" -sl 1 -cw4 120 50 50 62 mirrorBipedAxisCheckBox; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; symbolButton -image ($iconPrefix + "DPBipedLayout.xpm") -c "modRigLayoutBiped(1)"; symbolButton -image ($iconPrefix + "DPBipedBuild.xpm") -c "modRigPreBuildBiped()"; text -label ""; text -label ""; setParent ..; setParent ..; setParent ..; //################################################ HANDS ################################################ frameLayout -label "Hands" -cl 1 -labelAlign "center" -borderStyle "etchedIn" -cll true; columnLayout -rs 5 -adjustableColumn true; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; symbolButton -image ($iconPrefix + "DPRightHandLayout.xpm") -c "modRigLayoutHand(0)"; symbolButton -image ($iconPrefix + "DPLeftHandLayout.xpm") -c "modRigLayoutHand(1)"; intFieldGrp -nf 1 -v1 1 -label "# Hands:" -cw2 80 63 handNumOfHands; intFieldGrp -nf 1 -v1 4 -label "# Fingers:" -cw2 80 63 handNumOfFingers; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; text -label ""; checkBoxGrp -ncb 1 -label "" -l1 "Thumb" -v1 1 -cw2 10 133 handThumbCheckBox; text -label ""; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; symbolButton -image ($iconPrefix + "DPRightHandBuild.xpm") -c "modRigPreBuildHand(getSelected(0), getSelected(1))"; intFieldGrp -nf 1 -v1 3 -label "# Knuckles:" -cw2 80 63 handNumOfKnuckles; radioButtonGrp -label "" -nrb 2 -labelArray2 "Exp." "Even" -sl 2 -cw3 3 50 90 handDistType; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 82 200; text -label ""; text -label ""; checkBoxGrp -ncb 3 -label "Create:" -l1 "FK" -l2 "IK" -l3 "Bind" -v1 1 -v2 0 -v3 0 -cw4 80 50 50 102 -cc "toggleHandGUI()" handFkIkCheckBox; setParent ..; rowLayout -numberOfColumns 3 -columnWidth3 34 34 282; text -label ""; text -label ""; radioButtonGrp -label "Blend" -nrb 2 -labelArray2 "FK" "IK" -sl 1 -cw3 80 101 101 handFkIkInitialBlend; setParent ..; separator; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; symbolButton -image ($iconPrefix + "DPFinger.xpm") -c "modRigCalculateFinger()"; radioButtonGrp -label "" -nrb 2 -labelArray2 "Exp." "Even" -sl 2 -cw3 3 50 90 fingerDistType; intFieldGrp -nf 1 -v1 3 -label "# Knuckles:" -cw2 80 63 fingerNumOfKnuckles; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; symbolButton -image ($iconPrefix + "DPThumb.xpm") -c ""; radioButtonGrp -label "" -nrb 2 -labelArray2 "Exp." "Even" -sl 2 -cw3 3 50 90 thumbDistType; intFieldGrp -nf 1 -v1 3 -label "# Knuckles:" -cw2 80 63 thumbNumOfKnuckles; setParent ..; setParent ..; setParent ..; //################################################ SPINE ################################################ frameLayout -label "Spine" -cl 1 -labelAlign "center" -borderStyle "etchedIn" -cll true; columnLayout -rs 5 -adjustableColumn true; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; symbolButton -image ($iconPrefix + "DPSpineLayout.xpm") -c "modRigLayoutSpine()"; intFieldGrp -nf 1 -v1 1 -label "# Spines:" -cw2 80 63 spineNumOfSpines; text -label ""; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; symbolButton -image ($iconPrefix + "DPSpineBuild.xpm") -c "modRigPreBuildSpine(getSelected(0), getSelected(1))"; intFieldGrp -nf 1 -v1 1 -label "# Min Vert:" -cw2 80 63 spineNumOfMinVert; intFieldGrp -nf 1 -v1 4 -label "# Maj Vert:" -cw2 80 63 spineNumOfMajVert; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 82 200; text -label ""; text -label ""; checkBoxGrp -ncb 3 -label "Create:" -l1 "Cube" -l2 "IK" -l3 "Bind" -v1 1 -v2 1 -v3 1 -cw4 80 50 50 102 -cc "toggleSpineGUI()" spineFkIkCheckBox; setParent ..; rowLayout -numberOfColumns 3 -columnWidth3 34 34 282; text -label ""; text -label ""; radioButtonGrp -label "Blend" -nrb 2 -labelArray2 "Cube" "IK" -sl 1 -cw3 80 101 101 spineFkIkInitialBlend; setParent ..; setParent ..; setParent ..; //################################################ LEGS ################################################ frameLayout -label "Legs" -cl 1 -labelAlign "center" -borderStyle "etchedIn" -cll true; columnLayout -rs 5 -adjustableColumn true; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; symbolButton -image ($iconPrefix + "DPRightLegLayout.xpm") -c "modRigLayoutReverseFootSkeleton(0)"; symbolButton -image ($iconPrefix + "DPLeftLegLayout.xpm") -c "modRigLayoutReverseFootSkeleton(1)"; intFieldGrp -nf 1 -v1 1 -label "# Legs:" -cw2 80 61 legNumOfLegs; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; symbolButton -image ($iconPrefix + "DPLeftLegBuild.xpm") -c "modRigPreBuildReverseFootSkeleton(getSelected(0), getSelected(1), -1)"; checkBoxGrp -ncb 3 -label "Create:" -l1 "FK" -l2 "IK" -l3 "Bind" -v1 1 -v2 1 -v3 1 -cw4 80 50 50 102 -cc "toggleLegGUI()" legFkIkCheckBox; setParent ..; rowLayout -numberOfColumns 3 -columnWidth3 34 34 282; text -label ""; text -label ""; radioButtonGrp -label "Blend" -nrb 2 -labelArray2 "FK" "IK" -sl 1 -cw3 80 101 101 legFkIkInitialBlend; setParent ..; setParent ..; setParent ..; //################################################ ARMS ################################################ frameLayout -label "Arms" -cl 1 -labelAlign "center" -borderStyle "etchedIn" -cll true; columnLayout -rs 5 -adjustableColumn true; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; symbolButton -image ($iconPrefix + "DPRightArmLayout.xpm") -c "modRigLayoutArmSkeleton(0)"; symbolButton -image ($iconPrefix + "DPLeftArmLayout.xpm") -c "modRigLayoutArmSkeleton(1)"; intFieldGrp -nf 1 -v1 1 -label "# Arms:" -cw2 80 61 armNumOfArms; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 141 141; text -label ""; symbolButton -image ($iconPrefix + "DPLeftArmBuild.xpm") -c "modRigPreBuildArmSkeleton(getSelected(0), getSelected(1), -1)"; intFieldGrp -nf 1 -v1 1 -label "# Bicep:" -cw2 80 61 armNumOfBiceps; intFieldGrp -nf 1 -v1 1 -label "# Forearm:" -cw2 80 61 armNumOfForearms; setParent ..; rowLayout -numberOfColumns 4 -columnWidth4 34 34 82 200; text -label ""; text -label ""; checkBoxGrp -ncb 3 -label "Create:" -l1 "FK" -l2 "IK" -l3 "Bind" -v1 1 -v2 1 -v3 1 -cw4 80 50 50 102 -cc "toggleArmGUI()" armFkIkCheckBox; setParent ..; rowLayout -numberOfColumns 3 -columnWidth3 34 34 282; text -label ""; text -label ""; radioButtonGrp -label "Blend" -nrb 2 -labelArray2 "FK" "IK" -sl 1 -cw3 80 101 101 armFkIkInitialBlend; setParent ..; setParent ..; setParent ..; //end gui stuff setParent ..; setParent ..; formLayout -edit -attachForm $scroll "top" 0 -attachForm $scroll "left" 0 -attachForm $scroll "right" 0 -attachForm $scroll "bottom" 0 $form; } // This procedure builds the modularRig window if necessary and then shows it. global proc modularRig() { // Put the wait cursor on and build the window if it does not exist. waitCursor -state on; string $modularRigWindow = "modularRigWindow"; if (!`window -exists $modularRigWindow`) buildModularRigWindow($modularRigWindow); // Make sure the window is shown and then turn off the wait cursor. showWindow $modularRigWindow; waitCursor -state off; }