// // Copyright © 2007 Kiaran Ritchie All rights reserved // www.kiaran.net // // - AUTO-DYNAMIC JOINT CHAIN v2.0 - // This script will automate the task of making a joint chain dynamic. // The joint chain will flop around dynamically using the Maya Hair engine. // // Directions: // Select base joint, shift select tip joint and click 'Make Dynamic'. // PLEASE NOTE: This script uses Maya Hair to generate the dynamic secondary // motion. You must have Maya Unlimited v6.0 or greater to use this script. // // Basic Procedure: // -A CV curve is created through the joint chain. // -The curve is attached to a spline ik handle that runs through the chain. // -The curve is made dynamic using Maya Hair. // // -Additional procedures used to bake animation, add collisions, and remove dynamics. // // // ///////////////////////////////////////////////////////////////////////////////////////// // dynJointChain procedure ///////////////////////////////////////////////////////////////////////////////////////// global proc int krDynChain_dynJointChain () { //Store the current selection into an string array. string $sel[] = `ls -sl`; //Store the name of the base and end joints into strings. string $baseJoint = $sel[0]; string $endJoint = $sel[1]; //Create a vector array to store the world space coordinates of the joints. vector $jointPos[]; //String variable to house current joint being queried in the while loop. string $currentJoint; //Counter integer used in the while loop to determine the proper index in the vector array. int $counter = 0; //Check to ensure proper selection if (!((`objectType -isType "joint" $baseJoint`) && (`objectType -isType "joint" $endJoint`))) error "Please select a base and tip joint to make dynamic."; //Initial selection going into the while loop select -r $baseJoint; //Will loop through all the joints between the base and end by pickwalking through them. //The loop stores the world space of each joint into $jointPos as it iterates over them. do { $currentJoint = $sel[0]; //Check to make sure object is a joint, //if not, skip it and keep pickwalking. if (`objectType -isType "joint" $currentJoint`) { $jointPos[$counter] = `joint -q -p -a $currentJoint`; $counter++; } pickWalk -d down; $sel = `ls -sl`; } while($currentJoint != $endJoint); /* //Theses 3 lines store the position of the end joint that the loop will miss. $sel = `ls -sl`; $currentJoint = $sel[0]; $jointPos[$counter] = `joint -q -p -a $currentJoint`; */ //Now that $jointPos[] holds the world space coords of our joints, we need to build a cv curve //with points at each XYZ coord. //This string will house the command to create our curve. string $buildCurve = "curve -d 1 "; //Another counter integer for the for loop int $cvCounter = 0; //Loops over and adds the position of each joint to the buildCurve string. while ($cvCounter < $counter) { $buildCurve = ($buildCurve + " -p " + $jointPos[$cvCounter]); $cvCounter++; } //Adds the end terminator to the build curve command $buildCurve = $buildCurve + ";"; //Evaluates the $buildCurve string as a Maya command. (creates the curve running through the joints) string $nameOfCurve = `eval ($buildCurve)`; //Make curve dynamic. select $nameOfCurve; makeCurvesDynamicHairs 0 0 1; //Determine what the name of the dynamic curve is string $nameOfDynCurve; int $sizeOfString = `size($nameOfCurve)`; $sizeOfString++; $nameOfDynCurve = `substring $nameOfCurve 6 $sizeOfString` ; $sizeOfString = $nameOfDynCurve; $sizeOfString++; $nameOfDynCurve = ("curve" + $sizeOfString); //Create Tip Constraint string $nameOfHairConstraint[]; if (`checkBoxGrp -q -value1 tipConstraintCheckbox`) { select -r ($nameOfDynCurve + ".cv[" + $cvCounter + "]"); createHairConstraint 0; string $selection[] = `pickWalk -d up`; $nameOfHairConstraint[0] = $selection[0]; $nameOfHairConstraint[0] = `rename $nameOfHairConstraint[0] ($baseJoint + "TipConstraint")`; } //Make Joint Chain Stretchy string $curveInfoNode; string $nameOfUtilityNode; if (`checkBoxGrp -q -value1 stretchCheckbox`) { //Create curve info node $curveInfoNode = `arclen -ch 1 $nameOfDynCurve`; $curveInfoNode = `rename $curveInfoNode ($baseJoint + "CurveInfoNode")`; //Create mult/div node $nameOfUtilityNode = `shadingNode -asUtility multiplyDivide`; $nameOfUtilityNode = `rename $nameOfUtilityNode ($baseJoint + "MultiDivNode")`; //Create condition node $nameOfConditionNode = `shadingNode -asUtility condition`; $nameOfConditionNode = `rename $nameOfConditionNode ($baseJoint + "ConditionNode")`; //Setup multi/div node setAttr ($nameOfUtilityNode + ".operation") 2; connectAttr -force ($curveInfoNode + ".arcLength") ($nameOfUtilityNode + ".input1X"); setAttr ($nameOfUtilityNode + ".input2X") (`getAttr ($curveInfoNode + ".arcLength")`); //Setup condition node connectAttr -force ($nameOfUtilityNode + ".outputX") ($nameOfConditionNode + ".firstTerm"); connectAttr -force ($nameOfUtilityNode + ".outputX") ($nameOfConditionNode + ".colorIfFalseR"); setAttr ($nameOfConditionNode + ".operation") 4; setAttr ($nameOfConditionNode + ".secondTerm") 1.0; setAttr ($nameOfConditionNode + ".colorIfTrueR") 1.0; //Initial selection going into the while loop select $baseJoint; $currentJoint = $baseJoint; //Will loop through all the joints between the base and end by pickwalking through them. //The loop connects the scaleX of each joint to the output of the multi/div node. while ($currentJoint != $endJoint) { connectAttr -f ($nameOfConditionNode + ".outColorR") ($currentJoint + ".scaleX"); pickWalk -d down; $sel = `ls -sl`; $currentJoint = $sel[0]; } } //Display Current Position of Hair select $nameOfDynCurve; displayHairCurves "current" 1; //Determine name of follicle node select $nameOfCurve; string $nameOfFollicle[] = `pickWalk -d up`; //Create Joint Chain Controller Object string $jointCtrlObjArray[]; $jointCtrlObjArray[0] = `createNode implicitSphere`; $jointCtrlObjArray = `pickWalk -d up`; string $jointCtrlObj = $jointCtrlObjArray[0]; //Point Constrain Control Object to the end joint pointConstraint $endJoint $jointCtrlObj; //Add attributes to controller for the dynamics addAttr -ln stiffness -at double -min 0 -max 1 -dv 0.3 -keyable true $jointCtrlObj; addAttr -ln baseStiffness -at double -min 0 -max 1 -dv 1 -keyable true $jointCtrlObj; addAttr -ln tipStiffness -at double -min 0 -max 1 -dv 1 -keyable true $jointCtrlObj; addAttr -ln damping -at double -min 0 -max 100 -dv 0 -keyable true $jointCtrlObj; addAttr -ln "drag" -at double -min 0 -max 1 -dv .05 -keyable true $jointCtrlObj; addAttr -ln friction -at double -min 0 -max 1 -dv 0.5 -keyable true $jointCtrlObj; addAttr -ln "gravity" -at double -min 0 -max 10 -dv 1 -keyable true $jointCtrlObj; addAttr -ln "controllerSize" -at double -min 0 -max 100 -dv 0.5 -keyable true $jointCtrlObj; addAttr -ln "turbulenceCtrl" -at bool -keyable true $jointCtrlObj; setAttr -lock on ($jointCtrlObj + ".turbulenceCtrl"); addAttr -ln "strength" -at double -min 0 -max 1 -dv 0 -keyable true $jointCtrlObj; addAttr -ln "frequency" -at double -min 0 -max 2 -dv 0.2 -keyable true $jointCtrlObj; addAttr -ln "speed" -at double -min 0 -max 2 -dv 0.2 -keyable true $jointCtrlObj; //Determine what the name of the hair system is string $nameOfHairSystem; int $sizeOfString = `size($nameOfFollicle[0])`; $sizeOfString++; $nameOfHairSystem = `substring $nameOfFollicle[0] 9 $sizeOfString` ; $sizeOfString = $nameOfHairSystem; $nameOfHairSystem = ("hairSystemShape" + $sizeOfString); //Add message attribute to house name of hairSystem addAttr -ln nameOfHairShapeNode -at message -multi -im false $jointCtrlObj; connectAttr -f -na ($nameOfHairSystem+".message") ($jointCtrlObj+".nameOfHairShapeNode"); //Add message attribute to house name of follicle addAttr -ln nameOfFollicleNode -at message -multi -im false $jointCtrlObj; connectAttr -f -na ($nameOfFollicle[0]+".message") ($jointCtrlObj+".nameOfFollicleNode"); //Add message attribute to house name of dynamic curve addAttr -ln nameOfDynCurve -at message -multi -im false $jointCtrlObj; connectAttr -f -na ($nameOfDynCurve+".message") ($jointCtrlObj+".nameOfDynCurve"); //Add message attribute to house name of tip constraint addAttr -ln nameOfTipConstraint -at message -multi -im false $jointCtrlObj; connectAttr -f -na ($nameOfHairConstraint[0]+".message") ($jointCtrlObj+".nameOfTipConstraint"); //Add message attribute to house name of multi/div node addAttr -ln nameOfMultiDivNode -at message -multi -im false $jointCtrlObj; connectAttr -f -na ($nameOfUtilityNode+".message") ($jointCtrlObj+".nameOfMultiDivNode"); //Add message attribute to base and end joint names addAttr -ln baseJoint -at message -multi -im false $jointCtrlObj; connectAttr -f -na ($baseJoint+".message") ($jointCtrlObj+".baseJoint"); addAttr -ln endJoint -at message -multi -im false $jointCtrlObj; connectAttr -f -na ($endJoint+".message") ($jointCtrlObj+".endJoint"); //Add special attribute to house baking state addAttr -ln bakingState -at bool $jointCtrlObj; //Add special attribute to house stretchy state addAttr -ln isStretchy -at bool $jointCtrlObj; if (`checkBoxGrp -q -value1 stretchCheckbox`) setAttr ($jointCtrlObj + ".isStretchy") 1; /* //Overide the Hair dynamics so that the follicle controls the curve dynamics select $nameOfFollicle; $nameOfFollicle = `pickWalk -d down`; setAttr ($nameOfFollicle[0] + ".overrideDynamics") 1; */ //Set the dynamic chain to hang from the base joint (not both ends) setAttr ($nameOfFollicle[0] + ".pointLock") 1; //Turn stiffness off setAttr ($nameOfHairSystem + ".stiffness") 0; //Setup stiffness scale setAttr ($nameOfHairSystem + ".stiffnessScale[1].stiffnessScale_Position") 1; setAttr ($nameOfHairSystem + ".stiffnessScale[1].stiffnessScale_FloatValue") 1; setAttr ($nameOfHairSystem + ".stiffnessScale[0].stiffnessScale_Position") 0; setAttr ($nameOfHairSystem + ".stiffnessScale[0].stiffnessScale_FloatValue") 1; //Connect attribute on the controller sphere to the hair system node connectAttr -f ($jointCtrlObj +".tipStiffness") ($nameOfHairSystem + ".stiffnessScale[1].stiffnessScale_FloatValue"); connectAttr -f ($jointCtrlObj +".baseStiffness") ($nameOfHairSystem + ".stiffnessScale[0].stiffnessScale_FloatValue"); connectAttr -f ($jointCtrlObj +".damping") ($nameOfHairSystem + ".damp"); connectAttr -f ($jointCtrlObj +".stiffness") ($nameOfHairSystem + ".startCurveAttract"); connectAttr -f ($jointCtrlObj +".drag") ($nameOfHairSystem + ".drag"); connectAttr -f ($jointCtrlObj +".friction") ($nameOfHairSystem + ".friction"); connectAttr -f ($jointCtrlObj +".gravity") ($nameOfHairSystem + ".gravity"); connectAttr -f ($jointCtrlObj +".strength") ($nameOfHairSystem + ".turbulenceStrength"); connectAttr -f ($jointCtrlObj +".frequency") ($nameOfHairSystem + ".turbulenceFrequency"); connectAttr -f ($jointCtrlObj +".speed") ($nameOfHairSystem + ".turbulenceSpeed"); //Connect scale of controller to the size attr connectAttr -f ($jointCtrlObj +".controllerSize") ($jointCtrlObj +".scaleX"); connectAttr -f ($jointCtrlObj +".controllerSize") ($jointCtrlObj +".scaleY"); connectAttr -f ($jointCtrlObj +".controllerSize") ($jointCtrlObj +".scaleZ"); //Lock And Hide Attributes on Control Object. setAttr -lock true -keyable false ($jointCtrlObj + ".tx"); setAttr -lock true -keyable false ($jointCtrlObj + ".ty"); setAttr -lock true -keyable false ($jointCtrlObj + ".tz"); setAttr -lock true -keyable false ($jointCtrlObj + ".rx"); setAttr -lock true -keyable false ($jointCtrlObj + ".ry"); setAttr -lock true -keyable false ($jointCtrlObj + ".rz"); setAttr -lock false -keyable false ($jointCtrlObj + ".sx"); setAttr -lock false -keyable false ($jointCtrlObj + ".sy"); setAttr -lock false -keyable false ($jointCtrlObj + ".sz"); //Build the splineIK handle using the dynamic curve. select $baseJoint $endJoint $nameOfDynCurve; string $nameOfIKHandle[]; catchQuiet ($nameOfIKHandle = `ikHandle -sol ikSplineSolver -ccv false`); catchQuiet ($nameOfIKHandle[0] = `rename $nameOfIKHandle[0] ($baseJoint + "ikHandle")`); //Rename Ctrl Obj $jointCtrlObj = `rename $jointCtrlObj ($baseJoint + "DynChainControl")`; //Parent follicle node to the parent of the base joint //This will attach the joint chain to the rest of the heirarchy if there is one. select $nameOfFollicle[0]; pickWalk -d up; string $follicleGrpNode[] = `pickWalk -d up`; //Determine parent of base joint select $baseJoint; string $parentOfBaseJoint[] = `pickWalk -d up`; if ($parentOfBaseJoint[0] == $baseJoint) { warning "No parent hierarchy was found for the dynamic chain.\n"; }else { //Parent the follicle into heirarchy parent $follicleGrpNode $parentOfBaseJoint; parent -w $nameOfDynCurve; } //Set dynamic chain attributes according to creation options float $sliderStiffness = `floatSliderGrp -query -value sliderStiffness`; float $sliderDamping = `floatSliderGrp -query -value sliderDamping`; float $sliderDrag = `floatSliderGrp -query -value sliderDrag`; setAttr ($baseJoint + "DynChainControl.stiffness") $sliderStiffness; setAttr ($baseJoint + "DynChainControl.damping") $sliderDamping; setAttr ($baseJoint + "DynChainControl.drag") $sliderDrag; //Group the dynamic chain nodes string $nameOfGroup = `group -name ($baseJoint + "DynChainGroup") $jointCtrlObj $nameOfDynCurve $nameOfIKHandle[0] $nameOfHairSystem`; //If the chain has a tip constraint, then parent this under the main group to keep things tidy. if (`checkBoxGrp -q -value1 tipConstraintCheckbox`) { parent $nameOfHairConstraint[0] $nameOfGroup; } //Turn the visibility of everything off to reduce viewport clutter. setAttr ($nameOfDynCurve + ".visibility") 0; setAttr ($nameOfIKHandle[0] + ".visibility") 0; setAttr ($nameOfDynCurve + ".visibility") 0; setAttr ($follicleGrpNode[0] + ".visibility") 0; setAttr ($nameOfHairSystem + ".visibility") 0; //Delete useless 'hairsystemoutputcurves' group node select $nameOfHairSystem; string $nameOfGarbageGrp[] = `pickWalk -d up`; delete ($nameOfGarbageGrp[0] + "OutputCurves"); //Select dynamic chain controller for user select ($baseJoint + "DynChainControl"); //Print feedback for user print ("Dynamic chain created from " + $baseJoint + " to " + $endJoint + "."); return 1; } ///////////////////////////////////////////////////////////////////////////////////////// // Collisions Procedure ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain_collideWithChain () { string $sel[] = `ls -sl`; string $controllers[]; string $colliders[]; //Progress Window Amount int $amount; int $numberOfObjects = size($sel); int $i = 0; progressWindow -title "Factor 5's Dyn Chain Collisions:" -progress $amount -status "Preparing: 0%" -minValue 0 -maxValue 100 -isInterruptable true; //Loop through the whole selection and split up //into $controllers or $colliders for ($obj in $sel) { $i++; // Check if the dialog has been cancelled if ( `progressWindow -query -isCancelled` ) break; // Check if end condition has been reached if ( `progressWindow -query -progress` >= 100 ) break; $amount = ((100/$numberOfObjects) * $i); progressWindow -edit -progress $amount; //Find the current index in controllers array int $pos = size($controllers); //If obj is a controller if (`attributeExists "nameOfHairShapeNode" $obj`) { $controllers[$pos] = $obj; //Add to controller list }else { //Get the shape node of obj string $shapeNode[] = `listRelatives -s -path $obj`; //Find current index in collider array $pos = size($colliders); //Check if shape node is a mesh, or a nurbs surface if ((`objectType -isType "mesh" $shapeNode[0]`) || (`objectType -isType "nurbsSurface" $shapeNode[0]`)) { $colliders[$pos] = $obj; } } } progressWindow -edit -status "Connecting Colliders: 0%"; $numberOfObjects = size($controllers); if ((!$numberOfObjects) || (!`size($colliders)`)) { progressWindow -endProgress; error "Incorrect selection. Must select controller(s) and surface(s). Nothing done.\n"; } $i = 0; //For every controller that was selected... for ($chainCtrl in $controllers) { $i++; $amount = ((100/$numberOfObjects) * $i); progressWindow -edit -progress $amount; //Get the name of the hair shape node string $connections[] = `listConnections -p false -s true ($chainCtrl + ".nameOfHairShapeNode")`; string $hairShape = $connections[0]; print $hairShape; //For every NURBS or polygon surface that was selected... for ($collider in $colliders) { //Create geoConnector node and store it's name into a variable string $nameofGeoConnector = `createNode geoConnector`; //Get the shape node of collider string $objShape[] = `listRelatives -s -path $collider`; //Connect all the necessary attributes to make the surface collide connectAttr ($objShape[0] +".message") ($nameofGeoConnector + ".owner"); connectAttr ($objShape[0] +".worldMatrix[0]") ($nameofGeoConnector + ".worldMatrix"); connectAttr ($objShape[0] +".outMesh") ($nameofGeoConnector + ".localGeometry"); connectAttr -na ($nameofGeoConnector + ".resilience") ($hairShape + ".collisionResilience"); connectAttr -na ($nameofGeoConnector + ".friction") ($hairShape + ".collisionFriction"); connectAttr -na ($nameofGeoConnector + ".sweptGeometry") ($hairShape + ".collisionGeometry"); connectAttr time1.outTime ($nameofGeoConnector + ".currentTime"); //Print output to the user for each connected collider. print ($obj + " has been set to collide with " + $chainCtrl + "\n"); } } progressWindow -endProgress; } ///////////////////////////////////////////////////////////////////////////////////////// // BAKING PROCEDURE ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain_bakeDynChain () { //Declare necessary variables string $initialSel[] = `ls -sl`; string $allCtrls[]; int $i; int $amount; //Filter selection to contain only dynamic chain controllers. for ($obj in $initialSel) { if (`attributeExists "nameOfHairShapeNode" $obj`) { $allCtrls[$i] = $obj; $i++; } } //Create a progress window progressWindow -title "Factor 5's Dynamic Joint Chain:" -progress $amount -status "Baking Joint Chains:" -minValue 0 -maxValue 100 -isInterruptable true; //Construct frame range variable string $frameRangeToBake; float $startFrame = `intField -query -value startFrame`; float $endFrame = `intField -query -value endFrame`; $frameRangeToBake = ("\"" + $startFrame + ":" + $endFrame + "\""); int $j = 1; //For all of the selected chain controllers. for ($obj in $allCtrls) { // Check if the dialog has been cancelled if ( `progressWindow -query -isCancelled` ) break; // Check if end condition has been reached if ( `progressWindow -query -progress` >= 100 ) break; $amount = ((100/$i) * $j); progressWindow -edit -progress $amount; progressWindow -edit -status ("Baking chain " + $j + " of " + $i + " :"); $j++; string $chainCtrl = $obj; string $connections[] = `listConnections -p false -s true ($chainCtrl + ".baseJoint")`; string $baseJoint = $connections[0]; $connections = `listConnections -p false -s true ($chainCtrl + ".endJoint")`; string $endJoint = $connections[0]; string $bakingJoints = "{\"" ; string $currentJoint[]; $currentJoint[0] = $endJoint; //Determine joints to be baked while ($currentJoint[0] != $baseJoint) { $bakingJoints = ($bakingJoints +$currentJoint[0] + "\", \""); select $currentJoint[0]; $currentJoint = `pickWalk -d up`; } //Add the base joint that the while loop will miss $bakingJoints = ($bakingJoints + $baseJoint + "\"}"); //Concatenate the bake simulation command with the necessary joint names. $bakingJoints = ("bakeResults -simulation true -t " + $frameRangeToBake + " -sampleBy 1 -disableImplicitControl true -preserveOutsideKeys true -sparseAnimCurveBake false -controlPoints false -shape true" + $bakingJoints); //Evaluate the $bakingJoints string to bake the simulation. eval $bakingJoints; //Tell control object that joints are baked. setAttr ($chainCtrl + ".bakingState") 1; //Print feedback to user print ("All joints controlled by " + $chainCtrl + " have now been baked!\n"); } progressWindow -endProgress; } ///////////////////////////////////////////////////////////////////////////////////////// // DELETE DYNAMICS PROCEDURE ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain_deleteDynChain () { //Declare necessary variables string $initialSel[] = `ls -sl`; for ($chainCtrl in $initialSel) { int $error = 0; //Check that controller is selected. if (!`attributeExists "bakingState" $chainCtrl`) { $error = 1; warning ("Not a chain controller. Skipping:" + $chainCtrl + " .\n") ; }else { //Check if joints have been baked. if(((`getAttr ($chainCtrl + ".bakingState")`) == 0) && ((`getAttr ($chainCtrl + ".isStretchy")`) == 1)) { string $result = `confirmDialog -title "Delete Dynamics Warning" -message "Deleting the dynamics on a stretchy chain may cause it to collapse. Please bake the joint chain before deleting." -button "Continue Anyway" -button "Cancel" -defaultButton "Cancel" -cancelButton "Cancel" -dismissString "Cancel"`; if ($result == "Cancel") { $error = 1; warning ("Dynamics were not deleted for: " + $chainCtrl + ".\n"); } } } if ($error == 0) { string $connections[]; //Delete Follicle Node $connections = `listConnections -p false -s true ($chainCtrl + ".nameOfFollicleNode")`; string $follicleNode[]; $follicleNode[0] = $connections[0]; select $follicleNode[0]; $follicleNode = `pickWalk -d up`; delete $follicleNode; //Delete Hair System Node $connections = `listConnections -p false -s true ($chainCtrl + ".nameOfHairShapeNode")`; delete $connections[0]; //Delete Dynamic Hair Curve $connections = `listConnections -p false -s true ($chainCtrl + ".nameOfDynCurve")`; delete $connections[0]; //Delete Multi/Div Node $connections = `listConnections -p false -s true ($chainCtrl + ".nameOfMultiDivNode")`; if ($connections[0] != $chainCtrl) delete $connections[0]; //Delete Tip Constraint $connections = `listConnections -p false -s true ($chainCtrl + ".nameOfTipConstraint")`; if ($connections[0] != $chainCtrl) delete $connections[0]; //Delete IK Handle $connections = `listConnections -p false -s true ($chainCtrl + ".baseJoint")`; $connections = `listConnections -p false -s true $connections[0]`; for ($connection in $connections) if (`objectType -isType ikHandle $connection`) delete $connection; //Delete control object select $chainCtrl; $connections = `pickWalk -d up`; delete $connections; //Print feedback to the user. print ("Dynamics have been deleted from the chain: " + $chainCtrl +"\n"); } } select -cl; } ///////////////////////////////////////////////////////////////////////////////////////// // SETUP SINGLE JOINT PROCEDURE ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain_dynSingleJoint() { string $sel[] = `ls -sl`; if (!`objectType -isType joint $sel[0]`) error "Please select a single joint and try again.\n"; if ($sel[0] == "") error "Please select a single joint and try again.\n"; $nameOfJoint = $sel[0]; //Get position of joint float $jointPos[] = `xform -q -rp -ws $nameOfJoint`; //Create particle at joint string $particleNode[] = `particle -position $jointPos[0] $jointPos[1] $jointPos[2] -c 0.9`; //Create NURBS curve cube at position of joint string $curveCtrl = `curve -d 1 -p 0.5 0.5 0.5 -p 0.5 0.5 -0.5 -p -0.5 0.5 -0.5 -p -0.5 -0.5 -0.5 -p 0.5 -0.5 -0.5 -p 0.5 0.5 -0.5 -p -0.5 0.5 -0.5 -p -0.5 0.5 0.5 -p 0.5 0.5 0.5 -p 0.5 -0.5 0.5 -p 0.5 -0.5 -0.5 -p -0.5 -0.5 -0.5 -p -0.5 -0.5 0.5 -p 0.5 -0.5 0.5 -p -0.5 -0.5 0.5 -p -0.5 0.5 0.5 -k 0 -k 1 -k 2 -k 3 -k 4 -k 5 -k 6 -k 7 -k 8 -k 9 -k 10 -k 11 -k 12 -k 13 -k 14 -k 15`; //Move ctrl curve to joint position. move -ws $jointPos[0] $jointPos[1] $jointPos[2] $curveCtrl; //Freeze Xforms on Controller makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $curveCtrl; //Rename Controller $curveCtrl = `rename $curveCtrl ($nameOfJoint + "dynCtrl")`; //Create spring node select ($curveCtrl + ".cv[1]") $particleNode[0]; string $springNode[] = `spring -noDuplicate false -all true -useRestLengthPS false -rl 0 -s 20 -d 4.0 -sfw 1 -efw 1`; //Add springs between cube verts and particle //CVs to connect are: 1 2 7 0 9 4 3 12 select ($curveCtrl + ".cv[2]") $particleNode[0]; krDynChain_addSpring($springNode[0]); select ($curveCtrl + ".cv[7]") $particleNode[0]; krDynChain_addSpring($springNode[0]); select ($curveCtrl + ".cv[0]") $particleNode[0]; krDynChain_addSpring($springNode[0]); select ($curveCtrl + ".cv[9]") $particleNode[0]; krDynChain_addSpring($springNode[0]); select ($curveCtrl + ".cv[4]") $particleNode[0]; krDynChain_addSpring($springNode[0]); select ($curveCtrl + ".cv[3]") $particleNode[0]; krDynChain_addSpring($springNode[0]); select ($curveCtrl + ".cv[12]") $particleNode[0]; krDynChain_addSpring($springNode[0]); //Create locator to attach to particle string $nameOfLocator[] = `spaceLocator -p 0 0 0`; //Connect world position of particle to translation of locator connectAttr ($particleNode[1] + ".worldCentroid") ($nameOfLocator[0] + ".translate"); //Connect joint to locator string $nameOfConstraint[] = `parentConstraint -mo -weight 1 $nameOfLocator[0] $nameOfJoint`; //Group nodes to keep graph tidy string $groupName = `group -em`; $groupName = `rename $groupName ($curveCtrl + "_extrasGrp")`; parent $particleNode[0] $springNode[0] $nameOfLocator[0] $groupName; //Create message connections to controller to brand nodes for deletion addAttr -ln isDynamicSingleJointCtrl -at bool $curveCtrl; addAttr -ln deleteList -at message -multi -im false $curveCtrl; connectAttr -na ($particleNode[0] + ".message") ($curveCtrl + ".deleteList"); connectAttr -na ($springNode[0] + ".message") ($curveCtrl + ".deleteList"); connectAttr -na ($nameOfLocator[0] + ".message") ($curveCtrl + ".deleteList"); connectAttr -na ($groupName + ".message") ($curveCtrl + ".deleteList"); //Attach stiffness and damping to controller addAttr -ln stiffness -at double $curveCtrl; addAttr -ln damping -at double $curveCtrl; connectAttr ($curveCtrl + ".stiffness") ($springNode[0] + ".stiffness"); connectAttr ($curveCtrl + ".damping") ($springNode[0] + ".damping"); //Set stiffness and damping default values setAttr -e -keyable true ($curveCtrl + ".damping"); setAttr -e -keyable true ($curveCtrl + ".stiffness"); setAttr ($curveCtrl + ".damping") 2.0; setAttr ($curveCtrl + ".stiffness") 10.0; /* //Store initial translation vector on joint itself addAttr -ln stiffness -at double $curveCtrl; addAttr -ln damping -at double $curveCtrl; */ //Hide clutter nodes setAttr ($particleNode[0] + ".visibility") 0; setAttr ($springNode[0] + ".visibility") 0; setAttr ($nameOfLocator[0] + ".visibility") 0; //Lock And Hide Attributes on Control Object. setAttr -lock true -keyable false ($curveCtrl + ".rx"); setAttr -lock true -keyable false ($curveCtrl + ".ry"); setAttr -lock true -keyable false ($curveCtrl + ".rz"); setAttr -lock false -keyable false ($curveCtrl + ".sx"); setAttr -lock false -keyable false ($curveCtrl + ".sy"); setAttr -lock false -keyable false ($curveCtrl + ".sz"); select -r $curveCtrl; } ///////////////////////////////////////////////////////////////////////////////////////// // ADD SPRING (FOR SINGLE JOINT SETUP) PROCEDURE ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain_addSpring(string $nameOfSpring) { select -tgl $nameOfSpring; spring -name $nameOfSpring -add -noDuplicate false -all true ; } ///////////////////////////////////////////////////////////////////////////////////////// // DELETE DYNAMICS (SINGLE JOINT) PROCEDURE ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain_singleJointCleanUp() { string $sel[] = `ls -sl`; string $toDelete[] = `listConnections ($sel[0] + ".deleteList")`; delete $toDelete; delete $sel; } ///////////////////////////////////////////////////////////////////////////////////////// // DELETE DYNAMICS CALL FROM GUI (FOR SINGLE OR BOTH) ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain_deleteDynamics() { string $sel[] = `ls -sl`; for ($obj in $sel) { if (`attributeExists "isDynamicSingleJointCtrl" $obj`) { select -r $obj; krDynChain_singleJointCleanUp; }else if (`attributeExists "bakingState" $obj`) { select -r $obj; krDynChain_deleteDynChain; } } } ///////////////////////////////////////////////////////////////////////////////////////// // MAIN WINDOW ///////////////////////////////////////////////////////////////////////////////////////// global proc krDynChain() { if (`window -q -ex dynChainWindow`) deleteUI dynChainWindow; //Main Window window -title "Kiaran's - Auto Dynamic Joint Chain v2.0" -w 360 -h 170 dynChainWindow; scrollLayout -hst 0; columnLayout dynChainColumn; //Dynamic Chain Creation Options Layout frameLayout -w 320 -h 130 -borderStyle etchedOut -collapsable true -label "Dynamic Chain Creation Options:" creationOptions; frameLayout -e -cl true creationOptions; columnLayout -cw 300; //Stiffness floatSliderGrp -label "Stiffness:" -cw3 60 60 60 -cal 1 left -cal 2 left -cal 3 left -field true -precision 3 -min 0 -max 1 -value 0.01 sliderStiffness; //Damping floatSliderGrp -label "Damping:" -cw3 60 60 60 -cal 1 left -cal 2 left -cal 3 left -field true -precision 3 -min 0 -max 100 -value 0.05 sliderDamping; //Drag floatSliderGrp -label "Drag:" -cw3 60 60 60 -cal 1 left -cal 2 left -cal 3 left -field true -precision 3 -min 0 -max 1 -value 0.0 sliderDrag; //Tip Constraint Checkbox separator -h 20 -w 330; checkBoxGrp -label "Create Tip Constraint : " -cw 1 150 tipConstraintCheckbox; checkBoxGrp -label "Allow Joint Chain to Stretch: " -cw 1 150 stretchCheckbox; //separator -h 20 -w 330; setParent..; setParent..; //Button Layouts rowColumnLayout -nc 2 -cw 1 175 -cw 2 150; text "Select base joint, shift select tip: "; button -label "Create Dynamic Chain" -c "krDynChain_dynJointChain"; text "Select single joint: "; button -label "Create Dynamic Joint" -c "krDynChain_dynSingleJoint"; text "Select control, shift select collider(s): "; button -label "Make Collide" -c "krDynChain_collideWithChain"; text "Select control: "; button -label "Delete Dynamics" -c "krDynChain_deleteDynamics"; setParent..; //Bake Animation Layouts separator -w 330 -h 20; text " -Bake Joint Animation-"; rowColumnLayout -nc 3 -cw 1 100 -cw 2 100 -cw 3 120 bakeRowColumn; text "Start Frame: "; text "End Frame:"; text "Select Control:"; intField startFrame; intField -value 24 endFrame; button -label "Bake Dynamic Chain" -c "krDynChain_bakeDynChain"; //Show Main Window Command showWindow dynChainWindow; frameLayout -e -cl true creationOptions; }