//////////////////////////////// // // // cMotionTrail. Cam 2006 // // // //////////////////////////////// // overview: creates updating motion trails with spacer objects. // install: copy script into local scripts folder, source the script ( or restart maya ), type "cMotionTrailUI" to launch the script. // Arguments: "cMotionTrail" int `start time` , int `end time`, float `spacer scale`, string `object to trail`, int `set template` ( 0 or 1 ). // Written by Cameron Fielding : cameron.fielding@bvg.com // Tested with Maya 7.0 // -------------------------------------------------------------------------------------------------------------------------------------------- // proc to create the UI // global proc cMotionTrailUI() { if (`window -exists cMTrailWin`) deleteUI -window cMTrailWin; if (`windowPref -exists cMTrailWin`) windowPref -remove cMTrailWin; window -t "cMotionTrail" -w 562 -h 350 cMTrailWin; formLayout cMtopForm; rowColumnLayout -nc 3 -cw 1 65 -cw 2 150 -cw 3 100 cMrow1; text -l "Time Range"; radioCollection cMraiod1; $cMradio1_1 = `radioButton -label "Start/End"`; $cMradio1_2 = `radioButton -label "Time Slider"`; radioCollection -e -select $cMradio1_2 cMraiod1; setParent cMtopForm; rowColumnLayout -nc 2 -cw 1 55 -cw 2 80 cMrow2; text -l "Start Time "; textField -text "1" cMstart; text -l " End Time "; textField -text "30" cMend; setParent cMtopForm; frameLayout -bs "out" -h 2 cMSep1; setParent cMtopForm; floatSliderGrp -pre 2 -label "Spacer display size" -field true -minValue 0.01 -maxValue 10 -v 0.5 cMslide; checkBox -l " Template the trail's group" -v 0 cMcbox; colorIndexSliderGrp -label "Trail Colour" -min 0 -max 31 -value 14 -en true cMslide2; checkBox -l " Use object's own colour for the trail" -v 0 cMcbox2; checkBox -l " Connect trail to object's visibility" -v 0 cMcbox3; checkBox -l " Use spheres as spacer objects" -v 1 cMcbox4; colorIndexSliderGrp -label "Spacer Colour" -min 0 -max 31 -value 17 -en true cMslide3; rowColumnLayout -nc 3 -cw 1 180 -cw 2 180 -cw 3 180 cMbutrow; button -l "Create cMotion Trail" -c "getcMPrefs 1" -h 27 ; button -l "Apply" -c "getcMPrefs 0"; button -l "Close" -c "deleteUI cMTrailWin"; setParent cMtopForm; formLayout -e -attachForm cMrow1 "left" 100 -attachForm cMrow1 "top" 3 -attachForm cMrow2 "left" 111 -attachForm cMrow2 "top" 20 -attachForm cMSep1 "left" 0 -attachForm cMSep1 "right" 0 -attachForm cMSep1 "top" 70 -attachForm cMslide "left" 25 -attachForm cMslide "top" 78 -attachForm cMslide2 "left" 25 -attachForm cMslide2 "top" 104 -attachForm cMslide2 "right" 140 -attachForm cMslide3 "left" 25 -attachForm cMslide3 "top" 131 -attachForm cMcbox "left" 164 -attachForm cMcbox "top" 177 -attachForm cMcbox2 "left" 164 -attachForm cMcbox2 "top" 159 -attachForm cMcbox3 "left" 164 -attachForm cMcbox3 "top" 196 -attachForm cMcbox4 "left" 164 -attachForm cMcbox4 "top" 215 -attachForm cMbutrow "left" 5 -attachForm cMbutrow "bottom" 5 cMtopForm; showWindow; window -e -h 290 cMTrailWin; } // proc to launch the main function with flags from the UI // global proc getcMPrefs( int $closecMwin ) { int $startTime, $endTime, $template; float $scale; string $trailObjects[]; if ( `radioCollection -q -sl cMraiod1` == "radioButton1" ) { $startTime = `textField -q -text cMstart`; $endTime = `textField -q -text cMend`; } else { $startTime = `playbackOptions -q -min`; $endTime = `playbackOptions -q -max`; } $template = `checkBox -q -v cMcbox`; $scale = `floatSliderGrp -q -v cMslide`; $trailObjects = `ls -sl -fl`; for ( $trailObject in $trailObjects ) { if ( `objExists ( $trailObject + "_extraNode_t" + $startTime + $endTime )` == 0 ) { cMotionTrail $startTime $endTime $scale $trailObject $template; } else { catch ( error ( "a trail already exists for " + $trailObject + " from frames " + $startTime + " to " + $endTime )); } } if ( $closecMwin == 1 ) { deleteUI cMTrailWin; } } // main trail creating proc // global proc cMotionTrail ( int $startTime, int $endTime, float $scale, string $trailObject, int $template ) { // get the name of the object thats going to be trailed, and the trail length // string $originalName = $trailObject; int $totalTime = $endTime - $startTime; $totalTime ++; // clear the array that will be used to group everything together, and create its index clock that will manage its members // string $groupArray[]; clear $groupArray; int $gAClock = 0; // create the extra node needed ( I'm not sure why this node is needed - but it seems that the `getAttr -t` function needs it to successfully evaluate the // position of the hiddenTrailObject, when the object being trailed is not a direct child of the world ) group -w -em -n ( $trailObject + "_extraNode_t" + $startTime + $endTime ); pointConstraint -offset 0 0 0 -weight 1 $trailObject ( $trailObject + "_extraNode_t" + $startTime + $endTime ); $groupArray[$gAClock] = ( $trailObject + "_extraNode_t" + $startTime + $endTime ); $gAClock ++; $trailObject = ( $trailObject + "_extraNode_t" + $startTime + $endTime ); // create the hidden trail object that will be sampled // // note: this is the actual object that the script uses to generate and alter the shape of the cMotion trail. NOT the object the user selected. group -w -em -n ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime ); connectAttr ( $originalName + "_extraNode_t" + $startTime + $endTime + ".translateX" ) ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateX" ); connectAttr ( $originalName + "_extraNode_t" + $startTime + $endTime + ".translateY" ) ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateY" ); connectAttr ( $originalName + "_extraNode_t" + $startTime + $endTime + ".translateZ" ) ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateZ" ); $groupArray[$gAClock] = ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime ); $gAClock ++; // prepare the curve data // float $tPosX[], $tPosY[], $tPosZ[]; clear $tPosX $tPosY $tPosZ; int $cMclock = $startTime; for ( $i = 0; $i < $totalTime; $i ++ ) { $tPosX[$i] = `getAttr -t $cMclock ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateX" )`; $tPosY[$i] = `getAttr -t $cMclock ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateY" )`; $tPosZ[$i] = `getAttr -t $cMclock ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateZ" )`; $cMclock ++; } // create the eval string, and evaluate it to generate the curve // string $evalMe = "curve -d 1 "; int $cMclock = $startTime; for ( $i = 0; $i < `size $tPosX`; $i ++ ) { $evalMe = ( $evalMe + "-p " + $tPosX[$i] + " " + $tPosY[$i] + " " + $tPosZ[$i] + " " ); } $evalMe = ( $evalMe + "-n " + $trailObject + "_cMotionTrail_curve" ); eval $evalMe; $groupArray[$gAClock] = ( $trailObject + "_cMotionTrail_curve" ); $gAClock ++; // lock the curve so it cant be accidently moved ( only the group as a whole can be user manipulated ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.tx" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.ty" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.tz" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.rx" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.ry" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.rz" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.sx" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.sy" ); setAttr -lock true ( $trailObject + "_cMotionTrail_curve.sz" ); // set the user colours of the curve setAttr ( $trailObject + "_cMotionTrail_curve.overrideEnabled" ) 1; setAttr ( $trailObject + "_cMotionTrail_curve.overrideColor" ) ( (`colorIndexSliderGrp -q -value cMslide2`) - 1 ); // if the user chose `use object colour` and object has override enabled - set its colour // if ( `checkBox -q -v cMcbox2` == 1 || ($originalName + ".overrideEnabled") == 1 ) { setAttr ( $trailObject + "_cMotionTrail_curve.overrideColor" ) ( `getAttr ( $originalName + ".overrideColor" )`); } // rename the curve's shape node for easy access // string $findShape[]; $findShape = `listRelatives ( $trailObject + "_cMotionTrail_curve" )`; rename $findShape[0] ( $trailObject + "_cMotionTrailShape" ); // create the eval string to make the scriptjob that will update each CV position on the curve // string $evalMeExpr = ""; int $cMclock = $startTime; for ( $i = 0; $i < `size $tPosX `; $i ++ ) { $evalMeExpr = ( $evalMeExpr + "setAttr \\\"" + $trailObject + "_cMotionTrailShape" + ".controlPoints[" + $i + "].xValue\\\" ( `getAttr -t " + $cMclock + " " + $trailObject + ".tx`);" ); $evalMeExpr = ( $evalMeExpr + "setAttr \\\"" + $trailObject + "_cMotionTrailShape" + ".controlPoints[" + $i + "].yValue\\\" ( `getAttr -t " + $cMclock + " " + $trailObject + ".ty`);" ); $evalMeExpr = ( $evalMeExpr + "setAttr \\\"" + $trailObject + "_cMotionTrailShape" + ".controlPoints[" + $i + "].zValue\\\" ( `getAttr -t " + $cMclock + " " + $trailObject + ".tz`);" ); $cMclock ++; } // create the scriptJob to connect the update to a change in the trail null's translate attributes // // note: for efficiency this scriptjob checks the current frame number and compares it with a previous stored frame number ( from a dynamically generated // global variable ). The scriptjob will only run if these 2 values are the same ( so the scriptJob will ONLY evaluate when the user physically makes a // change in the scene, rather than evaluating each time the user scrubs the timeslider, or steps through the timeSlider. ) int $randTag = `rand 999999`; $evalMeExpr = ( "$cmtsc" + $randTag + "_sJob1 = `scriptJob -kws -cu true -ac \"" + $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translate\" \"" + "global int $cmtscDG" + $randTag + "_hiddenTrailObject_t" + $startTime + $endTime + "r2; $r1 = `currentTime -q`; if ( $r1 == $cmtscDG" + $randTag + "_hiddenTrailObject_t" + $startTime + $endTime + "r2 ) {" + $evalMeExpr); $evalMeExpr = ( $evalMeExpr + " print \\\"\\\"; }else{ $cmtscDG" + $randTag + "_hiddenTrailObject_t" + $startTime + $endTime + "r2 = `currentTime -q`; } \"`" ); eval $evalMeExpr; // create the spacing locators and connect them to each point on the curve // // note: for efficiency, the spacing locators are connected directly to each CV in the curve, much faster than depending on the scriptJob // to also update all their positions. int $cMclock = $startTime; for ( $i = 0; $i < `size $tPosX `; $i ++ ) { $tPosX[$i] = `getAttr -t $startTime ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateX" )`; $tPosY[$i] = `getAttr -t $startTime ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateY" )`; $tPosZ[$i] = `getAttr -t $startTime ( $originalName + "_hiddenTrailObject_t" + $startTime + $endTime + ".translateX" )`; if ( `checkBox -q -v cMcbox4` == 0 ) { spaceLocator -n ( $trailObject + "_spacingLocator_" + $i ); } else { sphere -p 0 0 0 -ax 0 1 0 -ssw 0 -esw 360 -r 1 -d 3 -ut 0 -tol 0.01 -s 4 -nsp 2 -ch 1 -n ( $trailObject + "_spacingLocator_" + $i ); setAttr ( $trailObject + "_spacingLocator_" + $i + ".overrideShading" ) 0 ; } scale -r $scale $scale $scale; xform -ws -t $tPosX[$i] $tPosY[$i] $tPosZ[$i]; connectAttr ( $trailObject + "_cMotionTrailShape" + ".controlPoints[" + $i + "].xValue" ) ( $trailObject + "_spacingLocator_" + $i + ".tx" ); connectAttr ( $trailObject + "_cMotionTrailShape" + ".controlPoints[" + $i + "].yValue" ) ( $trailObject + "_spacingLocator_" + $i + ".ty" ); connectAttr ( $trailObject + "_cMotionTrailShape" + ".controlPoints[" + $i + "].zValue" ) ( $trailObject + "_spacingLocator_" + $i + ".tz" ); $groupArray[$gAClock] = ( $trailObject + "_spacingLocator_" + $i ); $gAClock ++; $cMclock ++; setAttr ( $trailObject + "_spacingLocator_" + $i + ".overrideEnabled" ) 1; setAttr ( $trailObject + "_spacingLocator_" + $i + ".overrideColor" ) ( (`colorIndexSliderGrp -q -value cMslide3`) - 1 ); } // create the final group of everything that was created, and set its user template value // select -r $groupArray; group -n ( $originalName + "_cMotionTrail_" + $startTime + "to" + $endTime ); setAttr ( $originalName + "_cMotionTrail_" + $startTime + "to" + $endTime + ".template") $template; select -cl; if ( `checkBox -q -v cMcbox3` == 1 ) { catch ( `connectAttr ( $originalName + ".visibility" ) ( $originalName + "_cMotionTrail_" + $startTime + "to" + $endTime + ".visibility ") `); } }