// =========================================================================== // 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. // =========================================================================== // // hikSkeletonOperations.mel // // Description: // Contains methods that perform skeleton generator operations. // These methods could trigger UI updates in any part of the // unified character context. // //////////////////////////////////////////////////////////////////////// // Local methods... //////////////////////////////////////////////////////////////////////// proc string getFilter() { string $type = (uiRes("m_hikSkeletonOperations.kHikSkeletonTemplate")); return ( $type + " (*.hik)"); } // Return the roll bones weight based on the number of roll bones created // and the limb (upper or lower) proc float hikGetRollBonesDefaultWeight(string $limbType, int $nbRollBones, int $rollBoneNumber) { // $limbType specifies if we are dealing with an Upper or Lower limb (the weights values are // are different for upper limbs and lower limbs) // $nbRollBones specifies how many roll bones are defined for the limb. The weight values // vary depending on this number. // $rollBoneNumber specifies which leaf rollBone we are currently processing and it is // used to chose the correct array of weights. // // If we had a 2D array definition, $rollBoneNumber would be used to access the first // dimension and $boneId the second one. // // For example, the Upper limbs table looks like: // // The design (MAYA-62753) states: // nbRollBones 1 2 3 4 5 // rollBoneNumber // 1 0 0 0 0 0 // 2 50 45 30 22 // 3 90 60 44 // 4 90 66 // 5 90 // float $rollBone1W[], $rollBone2W[], $rollBone3W[], $rollBone4W[], $rollBone5W[]; int $boneId = $nbRollBones - 1; // 0 based access to the "tables" if ($boneId < 0 || $boneId > 4) return 0.0; if ($limbType=="Upper") { $rollBone1W = { 0.0, 0.0, 0.00, 0.0, 0.00}; $rollBone2W = { 0.0, 0.5, 0.45, 0.3, 0.22}; $rollBone3W = { 0.0, 0.0, 0.90, 0.6, 0.44}; $rollBone4W = { 0.0, 0.0, 0.00, 0.9, 0.66}; $rollBone5W = { 0.0, 0.0, 0.00, 0.0, 0.90}; } else if ($limbType=="Lower") { $rollBone1W = { 1.0, 0.5, 0.33, 0.25, 0.2}; $rollBone2W = { 0.0, 1.0, 0.66, 0.50, 0.4}; $rollBone3W = { 0.0, 0.0, 1.00, 0.75, 0.6}; $rollBone4W = { 0.0, 0.0, 0.00, 1.00, 0.8}; $rollBone5W = { 0.0, 0.0, 0.00, 0.00, 1.0}; } switch($rollBoneNumber) { case 1: return $rollBone1W[$boneId]; case 2: return $rollBone2W[$boneId]; case 3: return $rollBone3W[$boneId]; case 4: return $rollBone4W[$boneId]; case 5: return $rollBone5W[$boneId]; default: return 0.0; } } // Based on the number of roll bones set the default weight properties proc hikSetRollBonesDefaultProperties(string $pCharacter) { string $propertyNode = hikGetProperty2StateFromCharacter($pCharacter); string $skeletonGeneratorNode = hikGetSkeletonGeneratorNode( $pCharacter ); int $nbUpperArmRollBones = `getAttr ($skeletonGeneratorNode + ".NbUpperArmRollBones")`; int $nbLowerArmRollBones = `getAttr ($skeletonGeneratorNode + ".NbLowerArmRollBones")`; int $nbUpperLegRollBones = `getAttr ($skeletonGeneratorNode + ".NbUpperLegRollBones")`; int $nbLowerLegRollBones = `getAttr ($skeletonGeneratorNode + ".NbLowerLegRollBones")`; if(size($propertyNode)) { for($i = 1; $i < 6; $i++) { float $weight = hikGetRollBonesDefaultWeight("Upper", $nbUpperArmRollBones, $i); int $state = ($nbUpperArmRollBones >= $i); setAttr ($propertyNode + ".ParamLeafLeftArmRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafLeftArmRoll" + $i) $weight; setAttr ($propertyNode + ".ParamLeafRightArmRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafRightArmRoll" + $i) $weight; $weight = hikGetRollBonesDefaultWeight("Lower", $nbLowerArmRollBones, $i); $state = ($nbLowerArmRollBones >= $i); setAttr ($propertyNode + ".ParamLeafLeftForeArmRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafLeftForeArmRoll" + $i) $weight; setAttr ($propertyNode + ".ParamLeafRightForeArmRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafRightForeArmRoll" + $i) $weight; $weight = hikGetRollBonesDefaultWeight("Upper", $nbUpperLegRollBones, $i); $state = ($nbUpperLegRollBones >= $i); setAttr ($propertyNode + ".ParamLeafLeftUpLegRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafLeftUpLegRoll" + $i) $weight; setAttr ($propertyNode + ".ParamLeafRightUpLegRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafRightUpLegRoll" + $i) $weight; $weight = hikGetRollBonesDefaultWeight("Lower", $nbLowerLegRollBones, $i); $state = ($nbLowerLegRollBones >= $i); setAttr ($propertyNode + ".ParamLeafLeftLegRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafLeftLegRoll" + $i) $weight; setAttr ($propertyNode + ".ParamLeafRightLegRoll" + $i + "Mode") $state; setAttr ($propertyNode + ".ParamLeafRightLegRoll" + $i) $weight; } } } //////////////////////////////////////////////////////////////////////// // Global methods... //////////////////////////////////////////////////////////////////////// global proc hikSetRollBonesDefaultsOnPropertyState(string $pProperty2State) { // This function is (AND MUST BE) only called inside hikCreatePropertyState() // to overwrite the default values the HIKProperty node inherits from the HIK3 library // If/when the library updates its default values, this function will become // obsolete and can be removed if (size($pProperty2State)) { for($i = 1; $i < 6; $i++) { float $weight = hikGetRollBonesDefaultWeight("Upper", 5, $i); setAttr ($pProperty2State + ".ParamLeafLeftArmRoll" + $i) $weight; setAttr ($pProperty2State + ".ParamLeafRightArmRoll" + $i) $weight; $weight = hikGetRollBonesDefaultWeight("Lower", 5, $i); setAttr ($pProperty2State + ".ParamLeafLeftForeArmRoll" + $i) $weight; setAttr ($pProperty2State + ".ParamLeafRightForeArmRoll" + $i) $weight; $weight = hikGetRollBonesDefaultWeight("Upper", 5, $i); setAttr ($pProperty2State + ".ParamLeafLeftUpLegRoll" + $i) $weight; setAttr ($pProperty2State + ".ParamLeafRightUpLegRoll" + $i) $weight; $weight = hikGetRollBonesDefaultWeight("Lower", 5, $i); setAttr ($pProperty2State + ".ParamLeafLeftLegRoll" + $i) $weight; setAttr ($pProperty2State + ".ParamLeafRightLegRoll" + $i) $weight; } } } global proc hikUpdateSkeletonFromSkeletonGeneratorNode(string $pCharacter, float $characterScale) // // Description: // Updates the character's skeleton based on the values in the associated // skeleton generator node. // { string $errorMessageNoCharacterSelected = (uiRes("m_hikSkeletonOperations.kNoCharSel")); if( $pCharacter != "" ) { string $controlSet = hikGetControlRig( $pCharacter ); if($controlSet == "") { //We must not update the skeleton once there is a control rig for the character. string $skeletonGeneratorNode = hikGetSkeletonGeneratorNode( $pCharacter ); if($skeletonGeneratorNode != "") { hikUnparentCharNodes( $pCharacter ); hikUpdateSkeletonNodes( $pCharacter, $skeletonGeneratorNode); hikReadCharPoseFromSkeletonGeneratorNode( $pCharacter, $skeletonGeneratorNode,$characterScale); hikSetSkeletonGlobalTRS( $pCharacter ); hikSetSpineOrNeckGlobalTRS( $pCharacter, $skeletonGeneratorNode, "Spine"); hikSetSpineOrNeckGlobalTRS( $pCharacter, $skeletonGeneratorNode, "Neck"); hikRecursiveParentSkeleton( $pCharacter , 0); hikReadStancePoseTRSOffsets( hikGetCurrentCharacter() ); hikSetSkeletonRadius( $pCharacter ); hikSetRollBonesDefaultProperties($pCharacter); } } } else print ($errorMessageNoCharacterSelected ); } global proc hikCreateSkeleton() // Description: // Creates a new skeleton // { //save the state from the current character before going to create a new one. hikSyncSkeletonGeneratorFromUI(); hikCreateCharacter( "Character1" ); string $currentName = hikGetCurrentCharacter(); if($currentName != "") { string $skeletonGeneratorNode = `createNode HIKSkeletonGeneratorNode`; setAttr ($skeletonGeneratorNode+".isHistoricallyInteresting") 0; string $outPlug = $skeletonGeneratorNode + ".CharacterNode"; string $inPlug = $currentName + ".SkeletonGenerator"; connectAttr $outPlug $inPlug; hikReadDefaultCharPoseFileOntoSkeletonGeneratorNode($skeletonGeneratorNode); hikSetSkeletonGeneratorDefaults($skeletonGeneratorNode); select -r $currentName; hikSetCurrentSource(hikNoneString()); // set the current source to "None" // If we have no characters yet, select the newly // created character. This will refresh both the // character and source lists... hikUpdateCurrentCharacterFromScene(); // Update the definition information if the plug-in is loaded hikUpdateDefinitionUI(); // Select and refresh the skeleton generator tab hikSelectSkeletonTab(); } } global proc hikResetSkeleton() { string $skeletonGeneratorNode = hikGetSkeletonGeneratorNode( hikGetCurrentCharacter() ); if($skeletonGeneratorNode == "") return; hikReadDefaultCharPoseFileOntoSkeletonGeneratorNode($skeletonGeneratorNode); hikSetSkeletonGeneratorDefaults($skeletonGeneratorNode); hikUpdateSkeletonUI(); hikUpdateCurrentSkeleton(); } global proc hikDeleteSkeleton() { string $character = hikGetCurrentCharacter(); if (size($character) == 0) { error((uiRes("m_hikSkeletonOperations.kNoCharacterFound"))); return; } if( `referenceQuery -isNodeReferenced $character` ) { warning (uiRes("m_hikSkeletonOperations.kReferencedCharacterDeleteWarning")); return; } string $ok = (uiRes("m_hikSkeletonOperations.kOK")); string $cancel = (uiRes("m_hikSkeletonOperations.kCancel")); string $result = `confirmDialog -title (uiRes("m_hikSkeletonOperations.kDeleteHikSkeleton")) -message (uiRes("m_hikSkeletonOperations.kAreYouSureMsg")) -button $ok -button $cancel -defaultButton $ok -cancelButton $cancel -dismissString $cancel`; // If the result was not "OK", then cancel // if ( $result != $ok ) { return; } hikDeleteSkeleton_noPrompt(); } global proc hikDeleteSkeleton_noPrompt() { string $character = hikGetCurrentCharacter(); if (size($character) == 0) { error((uiRes("m_hikSkeletonOperations.kNoCharacterFoundNoPrompt"))); return; } if( `referenceQuery -isNodeReferenced $character` ) { warning (uiRes("m_hikSkeletonOperations.kReferencedCharacterDeleteWarningNoPrompt")); return; } // If a retargeter has been created for the current character ... string $name = RetargeterGetName( $character ); if ( RetargeterExists( $name ) ) RetargeterDelete( $name ); // ... delete it string $lSKNodes[] = hikGetSkeletonNodes($character); hikDeleteCharacter($character); // delete character befor to avoid cycle check error if (size($lSKNodes)) { delete $lSKNodes; } // If we deleted a character, the call to hikUpdateCurrentCharacterFromScene // will select the next character in the scene hikUpdateCharacterControlsUI(false); // we are also changing the current tab hikOnSwitchContextualTabs( ); } global proc hikSaveSkeleton() // Description: // Saves Edits on the current skeleton // { hikSyncSkeletonGeneratorFromUI(); } global proc hikMirrorSkeleton() { string $currentName = hikGetCurrentCharacter(); string $skeletonGeneratorNode = hikGetSkeletonGeneratorNode($currentName); if($skeletonGeneratorNode == "") { return; } hikSyncSkeletonGeneratorFromUI(); string $hipsTPlug = $skeletonGeneratorNode + ".HipsT"; float $hipsT[] = `getAttr $hipsTPlug`; float $lT[]; for($i = 0; $i < hikGetNodeCount(); $i++) { string $nodeName = GetHIKNodeName($i); string $tmpCharObjectName = $skeletonGeneratorNode + "." + $nodeName; $lT = `getAttr ($tmpCharObjectName + "T")`; string $rightNodeName = ""; if(startsWith($nodeName,"Left")) { string $partialName = endString($nodeName,(size($nodeName) - 4)); $rightNodeName = "Right" + $partialName; } if($rightNodeName != "") { $lT[0] = $hipsT[0] - ($lT[0] - $hipsT[0]); //string $str = "setting " + $rightNodeName + " to " + $lT[0] + "," + $lT[1] + "," + $lT[2] + "\n"; //print($str); hikSetSkTOffsetOnSkeletonGeneratorNode($skeletonGeneratorNode,$rightNodeName, $lT[0],$lT[1],$lT[2]); } } hikUpdateSkeletonFromSkeletonGeneratorNode( $currentName, 1.0 ); } global proc hikExportSkeleton() // Description: // Export the Skeleton Template to file { string $currentName = hikGetCurrentCharacter(); string $skeletonGeneratorNode = hikGetSkeletonGeneratorNode($currentName); if($skeletonGeneratorNode == "") { string $noSkeletonGeneratorNodeError = (uiRes("m_hikSkeletonOperations.kNoSkeletonGeneratorNode")); error($noSkeletonGeneratorNodeError); return; } hikSyncSkeletonGeneratorFromUI(); string $exportTitle = (uiRes("m_hikSkeletonOperations.kTemplateExportTo")); string $singleFilter = getFilter(); string $result[] = `fileDialog2 -fileFilter $singleFilter -dialogStyle 2 -cap $exportTitle -fileMode 0`; if(size($result) > 0) { hikWriteSkeletonPoseFile($skeletonGeneratorNode,$result[0]); } } global proc hikImportSkeleton() // Description: // Import a Skeleton Template from file // { string $currentName = hikGetCurrentCharacter(); string $skeletonGeneratorNode = hikGetSkeletonGeneratorNode($currentName); if($skeletonGeneratorNode == "") { string $noSkeletonGeneratorNodeError = (uiRes("m_hikSkeletonOperations.kImportNoSkeletonGeneratorNode")); error($noSkeletonGeneratorNodeError); return; } string $importTitle = (uiRes("m_hikSkeletonOperations.kTemplateImportTo")); string $singleFilter = getFilter(); string $result[] = `fileDialog2 -fileFilter $singleFilter -dialogStyle 2 -cap $importTitle -fileMode 1`; if(size($result) > 0) { hikReadCharPoseFileOntoSkeletonGeneratorNode($skeletonGeneratorNode,$result[0]); hikUpdateSkeletonFromSkeletonGeneratorNode( $currentName, 1.0 ); } }