// =========================================================================== // Copyright 2018 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form. // =========================================================================== // // hikControlRigOperations.mel // // Description: // Contains methods that perform control rig operations. // These methods could trigger UI updates in any part of the // unified character context. // /////////////////////////////////////////////////////////////////////// // Local methodes... /////////////////////////////////////////////////////////////////////// // Safe delete node function proc safeDeleteNode( string $nodeName ) { if ( size($nodeName) < 1 ) return; if ( `objExists $nodeName` ) { delete $nodeName; } } proc updateHIKCharacterToolConfig( string $configFilename ) { if( catch( `hikCharacterToolWidget -edit -configFilename $configFilename` ) ) hikControlRigSetDefaultUIConfig( ); hikOnSwitchControlRig( ); hikUpdateContextualUI( ); hikCharacterToolWidget -e -refreshScale; } // Deletes a Control Rig // If successful this method will return 0 // Otherwise the following error code is returned: // 1 => Invalid character parameter. (ie: empty string) // 2 => Invalid control set for character. // 3 => Rig is referenced and cannot be deleted. proc int doDeleteControlRig(string $pCharacter) { if( size( $pCharacter ) == 0 ) { return 1; } string $lControlRig = hikGetControlRig( $pCharacter ); if( size( $lControlRig ) == 0 ) { return 2; } if( `referenceQuery -isNodeReferenced $lControlRig` ) { warning (uiRes("m_hikControlRigOperations.kNoRefDelete")); return 3; } // Set source input to inactive stance mode // // before setting to stance input we have to set the the FK to its characterized position to preserve offset from hips to reference. string $fkref = hikGetSkNode($lControlRig, 0); if($fkref != "") { HIKComputeReference -ch $pCharacter -cr $fkref -rcr; } hikSetStanceInput( $pCharacter ); hikEnableCharacter( $pCharacter, false ); // Delete IK and Aux nodes linked to rig // string $lIKNodes[ ] = hikGetIkNodesFromControlRig( $lControlRig, 1 ); for( $lIKNode in $lIKNodes ) { safeDeleteNode $lIKNode; } // Delete FK nodes linked to rig // string $lFKNodes[ ] = hikGetFkNodesFromControlRig( $lControlRig ); if( size( $lFKNodes ) ) { // Delete FK2State nodes ( should only be one ) // string $lFK2States[ ] = `listConnections -type HIKFK2State -s 0 -d 1 ( $lFKNodes[ 0 ] + ".worldMatrix[ 0 ]" )`; if( size( $lFK2States ) ) safeDeleteNode $lFK2States[ 0 ]; for( $lFKNode in $lFKNodes ) { safeDeleteNode $lFKNode; } } // Delete extra nodes from solver // string $lSolverNodes[ ] = hikGetSolverFromCharacter( $pCharacter ); if( size( $lSolverNodes ) ) { string $lOutputCharacterStatePlug = $lSolverNodes[ 0 ] + ".OutputCharacterState"; // Delete HIKEffectorFromCharacter nodes ( should only be one ) // string $lEffectorFromCharacterNodes[ ] = `listConnections -type HIKEffectorFromCharacter -s 0 -d 1 $lOutputCharacterStatePlug`; if( size( $lEffectorFromCharacterNodes ) ) safeDeleteNode $lEffectorFromCharacterNodes[ 0 ]; // Delete HIKState2FK nodes ( should only be one ) // string $lState2FKNodes[ ] = `listConnections -type HIKState2FK -s 0 -d 1 $lOutputCharacterStatePlug`; if( size( $lState2FKNodes ) ) safeDeleteNode $lState2FKNodes[ 0 ]; // Delete HIKEfector2State node if still exist // (normally gets automatically deleted but can remain if there are other node connected to it - MAYA-18902) // string $lEff2State = hikGetEff2StateFromCharacter( $pCharacter ); if( $lEff2State != "" ) safeDeleteNode $lEff2State; } // Delete this characters rig // safeDeleteNode $lControlRig; return 0; } /////////////////////////////////////////////////////////////////////// // Global methodes... /////////////////////////////////////////////////////////////////////// global proc hikCreateControlRig() { // check if we already have a control rig. If so, don't create one?? string $character = hikGetCurrentCharacter(); if( hikHasControlRig($character) ) { warning( (uiRes("m_hikControlRigOperations.kAlreadyHaveControlRig")) ); return; } // If we don't have a skeleton definition, prompt the user to create one if( !hikHasDefinition($character) ) { string $create = (uiRes("m_hikGlobalUtils.kCreate")); string $define = (uiRes("m_hikGlobalUtils.kDefine")); string $cancel = (uiRes("m_hikGlobalUtils.kCancel")); string $result = `confirmDialog -title (uiRes("m_hikControlRigOperations.kCreateControlRig")) -message (uiRes("m_hikControlRigOperations.kNoDefinition")) -button $create -button $define -button $cancel -defaultButton $create -cancelButton $cancel -dismissString $cancel`; if( $result == $create ) { hikCreateSkeleton(); } else if( $result == $define ) { hikCreateDefinition(); } return; } // Attempt to lock the defintion automatically. If we can't, default // to definition tab. Lower-level methods will raise confirmDialog if( !hikCheckDefinitionLocked($character) ) { // select the Definition tab hikSetCurrentSource(""); // set source to "None" hikSelectDefinitionTab(); return; } // Turn on the wait cursor. waitCursor -state 1; hikCreateControlRigWithScale( ); hikSetRigLookAndFeel( $character, hikGetLastSelectedRigStyle( ) ); hikSetCurrentSourceFromCharacter($character); hikUpdateSourceList(); hikSelectControlRigTab(); hikUpdateContextualUI(); // Turn off the wait cursor. waitCursor -state 0; } global proc int hikDeleteControlRig() { // Note: A return of 0 from doDeleteControlRig indicates success // if (0 == doDeleteControlRig( hikGetCurrentCharacter() )) { hikSetCurrentSource(""); // set source to "None" hikUpdateSourceList(); hikUpdateContextualUI(); return 1; } return 0; } global proc hikSetRigLook(string $look) // Description: // Set the Rig Look to "Wire", "Stick" or "Box" // { int $inx = -1; if( tolower($look) == "wire" ) $inx = 0; else if( tolower($look) == "stick" ) $inx = 1; else if( tolower($look) == "box") $inx = 2; else return; string $style = hikGetRigStyleName( $inx ); string $character = hikGetCurrentCharacter(); hikSetRigIkLookAndFeel( $character, $style ); hikSetRigFkLookAndFeel( $character, $style ); hikSetLastSelectedRigStyle( $inx ); } proc string getFilters() { string $xml = (uiRes("m_hikControlRigOperations.kXml")); string $all = (uiRes("m_hikControlRigOperations.kAll")); return ( $xml + " (*.xml);;" + $all + " (*.*)" ); } global proc hikLoadControlRigUIConfiguration() { string $filters = getFilters(); string $filename[]; if( `optionVar -exists hikControlRigUIPath` ) { string $dir = `optionVar -q hikControlRigUIPath`; $filename = `fileDialog2 -dir $dir -fileMode 1 -dialogStyle 2 -fileFilter $filters -caption (uiRes("m_hikControlRigOperations.kImportUIConfiguration"))`; } else { $filename = `fileDialog2 -fileMode 1 -dialogStyle 2 -fileFilter $filters -caption (uiRes("m_hikControlRigOperations.kImportUIConfiguration"))`; } if ( size($filename) != 1 ) return; optionVar -stringValue hikControlRigUIPath $filename[0]; updateHIKCharacterToolConfig( $filename[0] ); } global proc hikUpdateControlRigConfig() { string $configFile = `optionVar -q hikControlRigUIPath`; if ( $configFile == "" ) return; updateHIKCharacterToolConfig( $configFile ); } global proc hikStancePose() // Description: // Set the Stance Pose for the current character { // TODO: rename this method hikGoToStancePose( hikGetCurrentCharacter( ) ); } global proc hikFKIKSync(string $pControlSet, string $FKWriter, string $pSolverNode, string $IKWriter, int $pStance) { // This precedure applies the current solver output state back on the Rig elements (IkFk) // Its purpose is to align both IK and FK solution. resulting solver output should not be affected by this // The function can also be used to set the Rig in stance pose. To do that, the solver is instructed // not to take Rig input into accont but to rather output a stance pose // The pStance parameter can use one of thes values // 0, Normal operation mode, we just realign IK and FK on the same solution // 1, We do a full character stance pose // 2, We do a special alignement that affects distingt rig elements based on the current character // manipulation mode and rig element selection if(`pluginInfo -q -l cacheEvaluator`){ cacheEvaluator -pauseInvalidation; } int $autoKey = `autoKeyframe -q -state`; if( $autoKey ) { autoKeyframe -state 0 -noReset; } string $Solver; if ( size($pSolverNode) > 0 ) { $Solver = $pSolverNode; } else { $Solver = hikGetSolverFromNode($FKWriter); } string $ActiveAttrName = $Solver + ".InputActive"; string $StanceAttrName = $Solver + ".InputStance"; string $StanceMaskAttrName = $Solver + ".InputStanceMask"; int $lActive = `getAttr $ActiveAttrName`; int $lStance = `getAttr $StanceAttrName`; if($pStance) { setAttr $ActiveAttrName false; setAttr $StanceAttrName true; } else { setAttr $ActiveAttrName true; } int $mask; if( $pStance != 1 /* != GoToStance full body al elements */) { // Compute the affected bodybart mash based on selection // this mask is used when doing a goToStance for Body part $mask = hikGetBodyPartSelectionMask( $pControlSet, $pStance != 0 ); setAttr $StanceMaskAttrName $mask ; } else { // if we ask for Full body T-Stance make sure to reset the FK reference to it characterized value // otherwise offset between FK ref & FK hips will be skrewed. string $fkref = hikGetSkNode($pControlSet, 0); if($fkref != "") { string $character = hikGetCharacterDefinition($pControlSet); HIKComputeReference -ch $character -cr $fkref -rcr; } } // Disable solving to prevent output state refresh while // updating the rig position. The state to apply will remain on // the writer nodes outputs and will be converted to local // by the ComputeLocal nodes // Before we disable the server we force an update of the state on the input of the IKFK writers // in order to synch to the current character state getAttr -silent ($IKWriter+".InputEffectorState"); getAttr -silent ($FKWriter+".InputCharacterState"); int $lSolverNodeState = `getAttr ($Solver+".nodeState")`; setAttr ($Solver+".nodeState") 2; if(`pluginInfo -q -l cacheEvaluator`){ cacheEvaluator -resumeInvalidation; } int $LastNodeId = hikGetNodeCount(); int $foundIter = 0; for($i = 1; $i < $LastNodeId; $i++) { $hiknodename = GetHIKNodeName($i); $AttrName = $pControlSet + "." + $hiknodename; string $FkNode[] = `listConnections $AttrName`; if(size($FkNode) > 0) { string $node = $FkNode[0]; if($pStance == 1 ) { if( hikIsRotateOnlyFK( $i ) ) { // Set T even if locked when going in stance pose // This is required for initial rig positionning // and it can be usefull if the user messed up with his rig and wanted to fix it // Silent catches were added in order to continue processing when translate attribute // is part of a reference file. See bug #350194 catchQuiet( `setAttr -lock false ($node+".translate")` ); hikRigSync $node; catchQuiet( `setAttr -lock true ($node+".translate")` ); } else { hikRigSync $node; } } else { if( !`hikBodyPart -inMask $mask -forNode $i` ) { // not active body part continue; } hikRigSync $node; } } } int $LastEffId = GetHIKEffectorCount(); $foundIter = 0; for($i = 0; $i < $LastEffId; $i++) { if( $pStance != 1 ) { if( !`hikBodyPart -inMask $mask -forEffector $i` ) { // not active body part continue; } } $hikeffname = GetHIKEffectorName($i); $AttrName = $pControlSet + "." + $hikeffname; string $IkNode[] = `listConnections -s 1 -d 0 -type "hikIKEffector" $AttrName`; if(size($IkNode) > 0) { int $index = 0; for ( $eff in $IkNode ) { // Skip auxiliaries because they do not have the // node network needed to compute the synced position. if ( !hikIsAuxiliary( $eff ) ) { hikRigSync $eff; $index++; } } } } if(`pluginInfo -q -l cacheEvaluator`){ cacheEvaluator -pauseInvalidation; } setAttr $ActiveAttrName $lActive; setAttr $StanceAttrName $lStance; if( $pStance != 1 ) { setAttr $StanceMaskAttrName 0 ; } // Reenable the Ik and Fk Writers setAttr ($Solver+".nodeState") $lSolverNodeState; if( $autoKey ) { autoKeyframe -state 1 -noReset; } if(`pluginInfo -q -l cacheEvaluator`){ cacheEvaluator -resumeInvalidation; } } global proc string hikCreatePinningNode() { string $lPinningState = `createNode "HIKPinning2State"`; setAttr ($lPinningState+".isHistoricallyInteresting") 0; // Setting default pinning value setAttr ($lPinningState+".LeftAnkleEffectorPinT") true; setAttr ($lPinningState+".LeftAnkleEffectorPinR") true; setAttr ($lPinningState+".RightAnkleEffectorPinT") true; setAttr ($lPinningState+".RightAnkleEffectorPinR") true; setAttr ($lPinningState+".LeftWristEffectorPinT") true; setAttr ($lPinningState+".RightWristEffectorPinT") true; return $lPinningState; } // // // Procedure Name: // hikConnectEffectorsToPinningState // // Description Name; // This function connects the effector to the pinning state so we can find the pinning state // object from the effector // // Input Value: // pPinningState // pControlSet // // Output Value: // None // global proc hikConnectEffectorsToPinningState(string $pPinningState, string $pControlSet) { int $LastEffectorId = GetHIKEffectorCount(); for($i = 0; $i < $LastEffectorId; $i++) { string $hikeffectorname = GetHIKEffectorName($i); string $AttrName = $pControlSet + "." + $hikeffectorname; string $IkNode[] = `listConnections $AttrName`; // Connect main effector pin attributes (auxiliaries/pivots pin and pulls are always ignored if(size($IkNode) > 0) { string $effector = $IkNode[0]; string $plug; hikConnectAttribute( $effector, "pinT",$pPinningState, $hikeffectorname + "PinT"); hikConnectAttribute( $effector, "pinR",$pPinningState, $hikeffectorname + "PinR"); } } } // Characterize : Set Stance Pose for a Character with a Rig // Works on an input argument of an HIKCharacterNode, an HIK FK joint // or an HIK IK effector. If the input is an empty string, it will // look for selected characters, FK joints and IK effectors. // global proc hikGoToStancePose(string $pCharacterOrRigElem ) { string $rigs[]; if( size($pCharacterOrRigElem) == 0) { string $hikChars[] = `ls -sl -type HIKCharacterNode`; for ($hikChar in $hikChars) { string $rig = hikGetControlRig($hikChar); if( $rig && !stringArrayContains( $rig, $rigs ) ) { $rigs[ size($rigs ) ] = $rig; } } string $hikFKs[] = `ls -sl -type hikFKJoint`; for ($hikFK in $hikFKs) { string $rig = hikGetControlRigFromRigElement($hikFK); if( $rig && !stringArrayContains( $rig, $rigs ) ) { $rigs[ size($rigs ) ] = $rig; } } string $hikIKs[] = `ls -sl -type hikIKEffector`; for ($hikIK in $hikIKs) { string $rig = hikGetControlRigFromRigElement($hikIK); if( $rig && !stringArrayContains( $rig, $rigs ) ) { $rigs[ size($rigs ) ] = $rig; } } } else { string $rig; if (`objectType -isa HIKCharacterNode $pCharacterOrRigElem`) { $rig = hikGetControlRig($pCharacterOrRigElem); } else { $rig = hikGetControlRigFromRigElement($pCharacterOrRigElem); } if( $rig != "" ) { $rigs[0] = $rig; } } for( $rig in $rigs) { string $lFKWriterAndSolverNode[]; $lFKWriterAndSolverNode = hikGetFKWriterAndSolverNode($rig); string $lIKWriter = hikGetIKWriter($rig); if( size($lFKWriterAndSolverNode) && size($lIKWriter) ) { hikFKIKSync( $rig, $lFKWriterAndSolverNode[0], $lFKWriterAndSolverNode[1], $lIKWriter, 2 ); } } if ( size( $rigs ) == 0 ) { error((uiRes("m_hikControlRigOperations.kSelectHIK"))); } } global proc hikDoHIKCharacterToolEffectorPinTState( string $character, int $isOn ) { if( size( $character ) ) { string $effectors[ ] = hikGetSelectedEffectorsFromCharacter( $character, 1 ); for( $effector in $effectors ) { int $isRPinned = `getAttr ( $effector + ".pinR" )`; if( $isOn ) setAttr ( $effector + ".pinning" ) ( $isRPinned == 1 ? 3 : 1 ); else setAttr ( $effector + ".pinning" ) ( $isRPinned == 1 ? 2 : 0 ); } } } global proc hikDoHIKCharacterToolEffectorPinRState( string $character, int $isOn ) { if( size( $character ) ) { string $effectors[ ] = hikGetSelectedEffectorsFromCharacter( $character, 1 ); for( $effector in $effectors ) { int $isTPinned = `getAttr ( $effector + ".pinT" )`; if( $isOn ) setAttr ( $effector + ".pinning" ) ( $isTPinned == 1 ? 3 : 2 ); else setAttr ( $effector + ".pinning" ) ( $isTPinned == 1 ? 1 : 0 ); } } } global proc hikControlRigWidgetFatalError( string $filename ) { string $err = `format -s $filename (uiRes("m_hikControlRigOperations.kWidgetFatalErr"))`; catch( `error $err` ); } global proc hikControlRigSetDefaultUIConfig() { string $defConfigFilename = hikGetDefaultResourcesDir(); $defConfigFilename = $defConfigFilename + "CharacterControlsConfig.xml"; string $customConfigFilename = `optionVar -q hikControlRigUIPath`; warning `format -s $customConfigFilename (uiRes("m_hikControlRigOperations.kUIConfFileError"))`; optionVar -stringValue hikControlRigUIPath $defConfigFilename; if( catch( `hikCharacterToolWidget -e -configFilename $defConfigFilename` ) ) hikControlRigWidgetFatalError( $defConfigFilename ); }