////////////////////////////////// // // Maya script file // ////////////////////////////////// // // Author : Lluís Llobera // (lluisllobera@gmail.com) // // Creation date : 23/III/2006 // v1.1 : 24/III/2006 // v1.2 : 18/X/2006 // // Main procedure : type "llDeleteRedundantKeys" in the Command Line or Script Editor // ////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // DESCRIPTION // // This script will delete the "redundant" keys in the curves seen in the Graph Editor, or else // in the whole scene if no curves are seen in the Graph Editor. // // "Redundant" keys are those which are not useful for the changes in the animation - i.e. // consecutive flat keys with the same value, stepped keys, and so on. // // Thanks to my mentor Victor Navone for the idea .. another lifesaver ! // // // VERSION HISTORY // // UPDATE 1.1 : added new case for redundant-ness. If the angle of the tangents of three // consecutive keys that are not stepped is the same (within a tolerance limit of 0.0001), // the middle key is considered redundant and deleted // // UPDATE 1.2 : if any keyframes are selected in the Graph Editor, now the script will // clean only those. Otherwise, it will clean the visible curves in the GE, or the whole // scene's curves if none are visible in the GE. Also, upon deleting redundant keys, // now the script's output message reflects the exact number of curves that were actually // cleaned, instead of the total sum of curves it iterated through. // // // Enjoy!! // // //////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////// // llDRKNameIsChannel // ////////////////////////////////// // // Returns 0 if the input name is an object, // or 1 if it is an attribute. // // // <-- llDRKFilterChannels // ////////////////////////////////// global proc int llDRKNameIsChannel (string $NAME) { int $RETURN = 0 ; string $SUBSTRING ; for ($I = 1 ; $I <= (`size $NAME` - 1) ; $I++) { $SUBSTRING = eval ("substring " + $NAME + " " + $I + " " + $I ) ; if ($SUBSTRING == ".") $RETURN = 1 ; } ; // for return $RETURN ; } ; // global proc int llDRKNameIsChannel ////////////////////////////////// // llDRKFilterChannels // ////////////////////////////////// // // Goes through the names input by $CHANNELS and checks if they are channels or objects. // If they are objects, their keyable attributes are added to $CHANNELS, and the object's // name itself is blanked out with an empty string ("") from the list. // // // <-- llDeleteRedundantKeys // --> llDRKNameIsChannel // ////////////////////////////////// global proc string[] llDRKFilterChannels (string $CHANNELS[]) { int $SIZE = `size $CHANNELS` ; if ($SIZE > 0) { for ($I = 0 ; $I<= $SIZE-1 ; $I++) { if (!`llDRKNameIsChannel ($CHANNELS[$I])`) { string $ATTS[] = `listAttr -k $CHANNELS[$I]` ; for ($ATT in $ATTS) { string $CURVENAME[] = eval ("listConnections -type animCurve " + $CHANNELS[$I] + "." + $ATT) ; if (`size $CURVENAME` > 0) $CHANNELS[(`size $CHANNELS`)] = $CHANNELS[$I] + "." + $ATT ; } ; // for ($ATT in $ATTS) $CHANNELS[$I] = "" ; } ; // if } ; // for } ; // if ($SIZE > 0) return $CHANNELS ; } ; // global proc llDRKFilterChannels ////////////////////////////////// // llDRKCleanChannel // ////////////////////////////////// // // Gets all the useful data from the specified channel, // then loops through all its keys getting rid of the redundant ones. // // // <-- llDeleteRedundantKeys // ////////////////////////////////// global proc int llDRKCleanChannel (string $CHANNEL) { // initialize counter int $COUNT = 0 ; // get selected keys from specified channel int $MIN = 0 ; int $SELECTED[] = `keyframe -q -sl -iv $CHANNEL` ; if (`size $SELECTED` == 0) { int $MIN = 1 ; $SELECTED = `keyframe -q -iv $CHANNEL` ; } ; // get necessary data from animation curve float $VALUE[] = `keyframe -q -vc $CHANNEL` ; float $TIME[] = `keyframe -q -tc $CHANNEL` ; string $INTYPE[] = `keyTangent -q -itt $CHANNEL` ; string $OUTTYPE[] = `keyTangent -q -ott $CHANNEL` ; float $INANGLE[] = `keyTangent -q -ia $CHANNEL` ; float $OUTANGLE[] = `keyTangent -q -oa $CHANNEL` ; float $INWEIGHT[] = `keyTangent -q -iw $CHANNEL` ; float $OUTWEIGHT[] = `keyTangent -q -ow $CHANNEL` ; float $INX[] = `keyTangent -q -ix $CHANNEL` ; float $INY[] = `keyTangent -q -iy $CHANNEL` ; float $OUTX[] = `keyTangent -q -ox $CHANNEL` ; float $OUTY[] = `keyTangent -q -oy $CHANNEL` ; // change linear tolerance of Maya to get less decimals in the angle output // (tolerance get restored in the end of the proc) float $TOLERANCE = `tolerance -q -l` ; float $NEWTOLERANCE = 0.0001 ; tolerance -l $NEWTOLERANCE ; // initialize $PURGE variable float $PURGE = 0 ; // proceed only if there's more than one key if (`size $VALUE` > 1) { if ($MIN == 0) if ($SELECTED[0] == 0) $LASTVALUE = $VALUE[($SELECTED[0])] ; else $LASTVALUE = $VALUE[($SELECTED[0])-1] ; else $LASTVALUE = 0 ; for ($J = $MIN ; $J <= (`size $SELECTED` -1) ; $J++) { $I = $SELECTED[$J] ; if ($I != 0) { $PURGE = 0 ; if ($VALUE[$I] == $LASTVALUE) { // case 1 : tangents are flattened if ( ($OUTY[$I-1] == 0) && // previous out is 0 ($INY[$I] == 0) && ($OUTY[$I] == 0) && // current in-out is 0 ($INY[$I+1] == 0) && // next in is 0 ($VALUE[$I+1] == $VALUE[$I])) // next value is the same $PURGE = 1 ; else // case 2 : stepped tangents if ( ($OUTTYPE[$I-1] == "step") && // previous out is step ($OUTTYPE[$I] == "step") && // current out is step ($OUTTYPE[$I+1] != "spline")) // next out is not spline $PURGE = 2 ; } // if else // case 3 : same angle if ( ($OUTTYPE[$I-1] != "step") && // previous out is not step (`equivalent $OUTANGLE[$I-1] $INANGLE[$I]`) && // previous out is same as current in ($OUTANGLE[$I-1] != 0) && // previous out is not 0 ($OUTTYPE[$I] != "step") && // current out is not step (`equivalent $INANGLE[$I] $OUTANGLE[$I]`) && // current in is same as current out (`equivalent $OUTANGLE[$I] $INANGLE[$I+1]`)) // current out is same as next in $PURGE = 3 ; else $LASTVALUE = $VALUE[$I] ; if ($PURGE != 0) { // delete key cutKey -t $TIME[$I] $CHANNEL ; // copy values from previous key $VALUE[$I] = $VALUE[$I-1] ; $TIME[$I] = $TIME[$I-1] ; $INTYPE[$I] = $INTYPE[$I-1] ; $OUTTYPE[$I] = $OUTTYPE[$I-1] ; $INANGLE[$I] = $INANGLE[$I-1] ; $INANGLE[$I] = $OUTANGLE[$I-1] ; $INWEIGHT[$I] = $INWEIGHT[$I-1] ; $OUTWEIGHT[$I] = $OUTWEIGHT[$I-1] ; $INX[$I] = $INX[$I-1] ; $INY[$I] = $INY[$I-1] ; $OUTX[$I] = $OUTX[$I-1] ; $OUTY[$I] = $OUTY[$I-1] ; // increase counter $COUNT = $COUNT + 1 ; } ; // if ($PURGE != 0) } ; // if ($I != 0) } ; // for } ; // if // restore tolerance tolerance -l $TOLERANCE ; // return number of redundant keys found return $COUNT ; } ; // global proc int llDRKCleanChannel ////////////////////////////////// // llDeleteRedundantKeys // ////////////////////////////////// // // MAIN PROC // // Calls on the proc to clean individual channels. // If no curves are visible in the Graph Editor, // a confirm dialog will pop up asking the user // if they want to run the script on all // the animation curves in the scene. // // // --> llDRKCleanChannel // --> llDRKFilterChannels // ////////////////////////////////// global proc llDeleteRedundantKeys () { int $CHANNELS_SELECTED = 1 ; string $CHANNELS[] = `keyframe -q -n -sl` ; if (`size $CHANNELS` == 0) { $CHANNELS = `selectionConnection -q -obj graphEditor1FromOutliner` ; $CHANNELS_SELECTED = 0 ; } ; // if (`size $CHANNELS` == 0) int $COUNT = 0 ; int $CURVES = 0 ; int $ADD ; if (`size $CHANNELS` > 0) { if (!$CHANNELS_SELECTED) $CHANNELS = `llDRKFilterChannels ($CHANNELS)` ; for ($CHANNEL in $CHANNELS) if ($CHANNEL != "") { $ADD = 0 ; $ADD += eval ("llDRKCleanChannel \"" + $CHANNEL + "\"") ; $COUNT += $ADD ; if ($ADD > 0) $CURVES += 1 ; } ; // if } // if (`size $CHANNELS` > 0) else { string $ANSWER = `confirmDialog -title "Delete All Redundant Keys" -message "Delete redundant keys for all the animation curves in the scene ?" -button "Yes" -button "No" -defaultButton "Yes" -cancelButton "Cancel" -dismissString "Cancel"` ; if ($ANSWER == "Yes") { $CHANNELS = `ls -type animCurve` ; if (`size $CHANNELS` > 0) for ($CHANNEL in $CHANNELS) if (!`referenceQuery -isNodeReferenced $CHANNEL`) { $ADD = 0 ; $ADD += eval ("llDRKCleanChannel \"" + $CHANNEL + "\"") ; $COUNT += $ADD ; if ($ADD > 0) $CURVES += 1 ; } ; // if } // if else $COUNT = -1 ; } ; // else // output counting result if ($COUNT > 0) print ("// Result : cleaned " + $COUNT + " redundant keys in " + $CURVES + " animation curves //\n") ; else if ($COUNT == 0) print ("// Result : no redundant keys found //\n") ; } ; // global proc llDeleteRedundantKeys //////////////////////////////////////////////////////////////////////////////////////////////////// // // EoS llDeleteRedundantKeys // ////////////////////////////////////////////////////////////////////////////////////////////////////