// =========================================================================== // 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. // =========================================================================== // // hikSkeletonUtils.mel // // Description: // Utility methods for HIK Skeleton Generation. Should not contain // any UI code. All code that references UI or triggers UI // updates should live in hikSkeletonUI.mel or // hikSkeletonOperations.mel // //////////////////////////////////////////////////////////////////////// // Local methods... //////////////////////////////////////////////////////////////////////// proc string CreateState2SK() { string $state2sk = `createNode "HIKState2SK"`; setAttr ($state2sk+".isHistoricallyInteresting") 0; return $state2sk; } proc string CreateSK2State() { string $sk2state = `createNode "HIKSK2State"`; setAttr ($sk2state+".isHistoricallyInteresting") 0; return $sk2state; } proc connectStateFromSk(string $pState, string $pCharacter) { // Ensure that the bones arent already connected before calling this proc hikConnectCharacterDefinition($pCharacter, $pState); int $LastNodeId = hikGetNodeCount(); for($i = 0; $i < $LastNodeId; $i++) { $hiknodename = GetHIKNodeName($i); $AttrName = $pCharacter + "." + $hiknodename; string $SkNode[] = `listConnections $AttrName`; if(size($SkNode) > 0) { string $node = $SkNode[0]; hikConnectAttribute($node, "worldMatrix", $pState, $hiknodename + "GX"); } } } proc connectSource( string $pTransform, string $pSrcT, string $pSrcR, string $pSrcS ) { if( $pSrcT != "" ) { connectAttr -f ($pSrcT+"x") ($pTransform+".translateX"); connectAttr -f ($pSrcT+"y") ($pTransform+".translateY"); connectAttr -f ($pSrcT+"z") ($pTransform+".translateZ"); } if( $pSrcR != "" ) { connectAttr -f ($pSrcR+"x") ($pTransform+".rotateX"); connectAttr -f ($pSrcR+"y") ($pTransform+".rotateY"); connectAttr -f ($pSrcR+"z") ($pTransform+".rotateZ"); } if( $pSrcS != "" ) { connectAttr -f ($pSrcS+"x") ($pTransform+".scaleX"); connectAttr -f ($pSrcS+"y") ($pTransform+".scaleY"); connectAttr -f ($pSrcS+"z") ($pTransform+".scaleZ"); } } proc connectSourceAndSaveAnim( string $pTransform, string $pSrcT, string $pSrcR, string $pSrcS, int $forcePairBlendCreation ) { // If nodes already has sources, create a pairblend to preserve the animation // Note: pairBlends are just supportign T and R, not S, anim on S will be lost if $pSrcS is set int $nbSrc; int $nbScaleSrc; string $pairBlendNode; if( !$forcePairBlendCreation ) { $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".translate" )`); $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".translateX" )`); $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".translateY" )`); $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".translateZ" )`); $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".rotate" )`); $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".rotateX" )`); $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".rotateY" )`); $nbSrc += size( `listConnections -d 0 -s 1 ($pTransform+".rotateZ" )`); } $nbScaleSrc += size( `listConnections -d 0 -s 1 ($pTransform+".scale" )`); $nbScaleSrc += size( `listConnections -d 0 -s 1 ($pTransform+".scaleX" )`); $nbScaleSrc += size( `listConnections -d 0 -s 1 ($pTransform+".scaleY" )`); $nbScaleSrc += size( `listConnections -d 0 -s 1 ($pTransform+".scaleZ" )`); if( $forcePairBlendCreation || $nbSrc ) { $pairBlend = `pairBlend -node $pTransform -at "tx" -at "ty" -at "tz" -at "rx" -at "ry" -at "rz"`; if( $pSrcT != "" ) { connectAttr $pSrcT ($pairBlend+".inTranslate2"); } if( $pSrcR != "" ) { connectAttr $pSrcR ($pairBlend+".inRotate2"); } setAttr ($pairBlend+".weight") 1; setAttr ($pairBlend+".currentDriver") 1; } else { if( $pSrcT != "" ) { connectAttr ($pSrcT+"x") ($pTransform+".translateX"); connectAttr ($pSrcT+"y") ($pTransform+".translateY"); connectAttr ($pSrcT+"z") ($pTransform+".translateZ"); } if( $pSrcR != "" ) { connectAttr ($pSrcR+"x") ($pTransform+".rotateX"); connectAttr ($pSrcR+"y") ($pTransform+".rotateY"); connectAttr ($pSrcR+"z") ($pTransform+".rotateZ"); } } if( $nbScaleSrc == 0 && $pSrcS != "" ) { connectAttr ($pSrcS+"x") ($pTransform+".scaleX"); connectAttr ($pSrcS+"y") ($pTransform+".scaleY"); connectAttr ($pSrcS+"z") ($pTransform+".scaleZ"); } } proc removePairBlend( string $pairBlend ) { string $attrIn[] = { "inTranslateX1", "inTranslateY1", "inTranslateZ1", "inRotateX1", "inRotateY1", "inRotateZ1" }; string $attrOut[] = { "outTranslateX", "outTranslateY", "outTranslateZ", "outRotateX", "outRotateY", "outRotateZ" }; for( $i = 0; $i<6; $i++ ) { string $sources[] = `listConnections -s 1 -d 0 -p 1 ($pairBlend+"."+$attrIn[$i] )`; string $destinations[] = `listConnections -s 0 -d 1 -p 1 ($pairBlend+"."+$attrOut[$i] )`; for( $dst in $destinations ) { disconnectAttr ($pairBlend+"."+$attrOut[$i]) $dst; for( $src in $sources ) { connectAttr $src $dst; break; // there should be only one source } } } delete $pairBlend; } proc disconnectSourceAndRestoreAnim( string $pTransform, string $pSrcNode, int $dirtyPlugs ) { // Disconnect any TRS input from pSrcNode to pTransform // and remove any present pairblend string $attrs[] = { "translate", "translateX", "translateY", "translateZ", "rotate", "rotateX", "rotateY", "rotateZ", "scale", "scaleX", "scaleY", "scaleZ" }; // Will destroy any upstream pairBlend and disconnect for( $attr in $attrs ) { string $srcNodes[] = `listConnections -d 0 -s 1 ($pTransform+"."+$attr )`; if( size( $srcNodes ) > 0 ) { if( `objectType -isType "pairBlend" $srcNodes[0]` ) { delete $srcNodes[0]; } else if( isSameObject( $srcNodes[0], $pSrcNode )) { string $connections[] = `listConnections -connections true -plugs 1 -d 0 -s 1 ($pTransform+"."+$attr )`; disconnectAttr $connections[1] $connections[0]; } if( !$dirtyPlugs ) { // Preserve current position when disconnecting dgdirty -clean ($pTransform+"."+$attr); } } } } proc float[] getSkelTranslateArray( string $characterObjectName ) { float $t[]; $t[0] = `getAttr ($characterObjectName + "Tx")`; $t[1] = `getAttr ($characterObjectName + "Ty")`; $t[2] = `getAttr ($characterObjectName + "Tz")`; return $t; } proc int[] setWantedFingerJointsCount(int $pWantedJoints[], string $pFingerName, int $pFingerJointsCount) { int $i, $lNodeId; for($i = 1; $i < 5; $i++) { $lNodeId = hikGetNodeIdFromName($pFingerName + $i); if( $i <= ($pFingerJointsCount + 1) ) $pWantedJoints[$lNodeId] = 1; else $pWantedJoints[$lNodeId] = 0; } return $pWantedJoints; } proc int[] setWantedJointsFromSkeletonGeneratorNode(string $skeletonGeneratorNode) { int $ltmpCheckVal; int $wantedJoints[]; int $i; int $lNodeId; for($i = 0; $i < hikGetNodeCount(); $i++) $wantedJoints[$i] = $i < 16 ? 1 : 0; // Shoulders string $plug; $plug = $skeletonGeneratorNode + ".ShoulderCount"; int $lShouldersVal = `getAttr $plug`; int $ShoulderBone = 0; int $ShoulderExtra = 0; if($lShouldersVal == 2) { $ShoulderBone = 1; $ShoulderExtra = 1; } else if($lShouldersVal == 1) { $ShoulderBone = 1; $ShoulderExtra = 0; } $lNodeId = hikGetNodeIdFromName("LeftShoulder"); $wantedJoints[$lNodeId] = $ShoulderBone; $lNodeId = hikGetNodeIdFromName("RightShoulder"); $wantedJoints[$lNodeId] = $ShoulderBone; $lNodeId = hikGetNodeIdFromName("LeftShoulderExtra"); $wantedJoints[$lNodeId] = $ShoulderExtra; $lNodeId = hikGetNodeIdFromName("RightShoulderExtra"); $wantedJoints[$lNodeId] = $ShoulderExtra; // Roll-Bones $plug = $skeletonGeneratorNode + ".WantUpperArmRollBone"; $ltmpCheckVal = `getAttr $plug`; $lNodeId = hikGetNodeIdFromName("LeftArmRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightArmRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $plug = $skeletonGeneratorNode + ".WantLowerArmRollBone"; $ltmpCheckVal = `getAttr $plug`; $lNodeId = hikGetNodeIdFromName("LeftForeArmRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightForeArmRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $plug = $skeletonGeneratorNode + ".WantUpperLegRollBone"; $ltmpCheckVal = `getAttr $plug`; $lNodeId = hikGetNodeIdFromName("LeftUpLegRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightUpLegRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $plug = $skeletonGeneratorNode + ".WantLowerLegRollBone"; $ltmpCheckVal = `getAttr $plug`; $lNodeId = hikGetNodeIdFromName("LeftLegRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightLegRoll"); $wantedJoints[$lNodeId] = $ltmpCheckVal; // New HIK 2016.5 Leaf Roll Bones int $nbRollBones = `getAttr ($skeletonGeneratorNode + ".NbUpperArmRollBones")`; for($i=1; $i<($nbRollBones+1); $i++) { $lNodeId = hikGetNodeIdFromName("LeafLeftArmRoll" + $i); $wantedJoints[$lNodeId] = 1; $lNodeId = hikGetNodeIdFromName("LeafRightArmRoll" + $i); $wantedJoints[$lNodeId] = 1; } $nbRollBones = `getAttr ($skeletonGeneratorNode + ".NbLowerArmRollBones")`; for($i=1; $i<($nbRollBones+1); $i++) { $lNodeId = hikGetNodeIdFromName("LeafLeftForeArmRoll" + $i); $wantedJoints[$lNodeId] = 1; $lNodeId = hikGetNodeIdFromName("LeafRightForeArmRoll" + $i); $wantedJoints[$lNodeId] = 1; } $nbRollBones = `getAttr ($skeletonGeneratorNode + ".NbUpperLegRollBones")`; for($i=1; $i<($nbRollBones+1); $i++) { $lNodeId = hikGetNodeIdFromName("LeafLeftUpLegRoll" + $i); $wantedJoints[$lNodeId] = 1; $lNodeId = hikGetNodeIdFromName("LeafRightUpLegRoll" + $i); $wantedJoints[$lNodeId] = 1; } $nbRollBones = `getAttr ($skeletonGeneratorNode + ".NbLowerLegRollBones")`; for($i=1; $i<($nbRollBones+1); $i++) { $lNodeId = hikGetNodeIdFromName("LeafLeftLegRoll" + $i); $wantedJoints[$lNodeId] = 1; $lNodeId = hikGetNodeIdFromName("LeafRightLegRoll" + $i); $wantedJoints[$lNodeId] = 1; } // Spine $plug = $skeletonGeneratorNode + ".SpineCount"; int $lSpineVal = `getAttr $plug`; for($i = 1; $i < 10; $i++) { $lNodeId = hikGetNodeIdFromName("Spine" + $i); if( $i < $lSpineVal ) $wantedJoints[$lNodeId] = 1; else $wantedJoints[$lNodeId] = 0; } // Neck $plug = $skeletonGeneratorNode + ".NeckCount"; int $lNeckVal = `getAttr $plug`; for($i = 0; $i < 10; $i++) { if( $i == 0 ) $lNodeId = hikGetNodeIdFromName("Neck"); else $lNodeId = hikGetNodeIdFromName("Neck" + $i); if( $i < $lNeckVal ) $wantedJoints[$lNodeId] = 1; else $wantedJoints[$lNodeId] = 0; } // FINGERS $plug = $skeletonGeneratorNode + ".FingerJointCount"; int $lFingerJointsCountVal = `getAttr $plug`; $plug = $skeletonGeneratorNode + ".WantInHandJoint"; $ltmpCheckVal = `getAttr $plug`; $plug = $skeletonGeneratorNode + ".WantMiddleFinger"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftHandMiddle", $lFingerJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightHandMiddle", $lFingerJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInHandMiddle"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInHandMiddle"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantIndexFinger"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftHandIndex", $lFingerJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightHandIndex", $lFingerJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInHandIndex"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInHandIndex"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantRingFinger"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftHandRing", $lFingerJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightHandRing", $lFingerJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInHandRing"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInHandRing"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantPinkyFinger"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftHandPinky", $lFingerJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightHandPinky", $lFingerJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInHandPinky"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInHandPinky"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantThumb"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftHandThumb", $lFingerJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightHandThumb", $lFingerJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInHandThumb"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInHandThumb"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantExtraFinger"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftHandExtraFinger", $lFingerJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightHandExtraFinger", $lFingerJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInHandExtraFinger"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInHandExtraFinger"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } // TOES $plug = $skeletonGeneratorNode + ".ToeJointCount"; int $lToeJointsCountVal = `getAttr $plug`; $plug = $skeletonGeneratorNode + ".WantInFootJoint"; $ltmpCheckVal = `getAttr $plug`; $plug = $skeletonGeneratorNode + ".WantIndexToe"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftFootIndex", $lToeJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightFootIndex", $lToeJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInFootIndex"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInFootIndex"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantMiddleToe"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftFootMiddle", $lToeJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightFootMiddle", $lToeJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInFootMiddle"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInFootMiddle"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantRingToe"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftFootRing", $lToeJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightFootRing", $lToeJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInFootRing"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInFootRing"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantPinkyToe"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftFootPinky", $lToeJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightFootPinky", $lToeJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInFootPinky"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInFootPinky"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantBigToe"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftFootExtraFinger", $lToeJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightFootExtraFinger", $lToeJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInFootExtraFinger"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInFootExtraFinger"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } $plug = $skeletonGeneratorNode + ".WantFootThumb"; if( `getAttr $plug` ) { $wantedJoints = setWantedFingerJointsCount($wantedJoints, "LeftFootThumb", $lToeJointsCountVal); $wantedJoints = setWantedFingerJointsCount($wantedJoints, "RightFootThumb", $lToeJointsCountVal); $lNodeId = hikGetNodeIdFromName("LeftInFootThumb"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightInFootThumb"); $wantedJoints[$lNodeId] = $ltmpCheckVal; } // Finger and Toe Base $plug = $skeletonGeneratorNode + ".WantFingerBase"; $ltmpCheckVal = `getAttr $plug`; $lNodeId = hikGetNodeIdFromName("LeftFingerBase"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightFingerBase"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $plug = $skeletonGeneratorNode + ".WantToeBase"; $ltmpCheckVal = `getAttr $plug`; $lNodeId = hikGetNodeIdFromName("LeftToeBase"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $lNodeId = hikGetNodeIdFromName("RightToeBase"); $wantedJoints[$lNodeId] = $ltmpCheckVal; $plug = $skeletonGeneratorNode + ".WantHipsTranslation"; int $WantHipsTranslation = `getAttr $plug`; $lNodeId = hikGetNodeIdFromName("HipsTranslation"); $wantedJoints[$lNodeId] = $WantHipsTranslation; return $wantedJoints; } proc SetDOFonCharacter(string $pCharacter, int $pNodeId, string $sknode) { string $NodeName = GetHIKNodeName($pNodeId); setAttr ($pCharacter + "." + $NodeName + "MinRLimitx") `getAttr ($sknode + ".minRotXLimit")`; setAttr ($pCharacter + "." + $NodeName + "MinRLimity") `getAttr ($sknode + ".minRotYLimit")`; setAttr ($pCharacter + "." + $NodeName + "MinRLimitz") `getAttr ($sknode + ".minRotZLimit")`; setAttr ($pCharacter + "." + $NodeName + "MaxRLimitx") `getAttr ($sknode + ".maxRotXLimit")`; setAttr ($pCharacter + "." + $NodeName + "MaxRLimity") `getAttr ($sknode + ".maxRotYLimit")`; setAttr ($pCharacter + "." + $NodeName + "MaxRLimitz") `getAttr ($sknode + ".maxRotZLimit")`; setAttr ($pCharacter + "." + $NodeName + "MinRLimitEnablex") `getAttr ($sknode + ".minRotXLimitEnable")`; setAttr ($pCharacter + "." + $NodeName + "MinRLimitEnabley") `getAttr ($sknode + ".minRotYLimitEnable")`; setAttr ($pCharacter + "." + $NodeName + "MinRLimitEnablez") `getAttr ($sknode + ".minRotZLimitEnable")`; setAttr ($pCharacter + "." + $NodeName + "MaxRLimitEnablex") `getAttr ($sknode + ".maxRotXLimitEnable")`; setAttr ($pCharacter + "." + $NodeName + "MaxRLimitEnabley") `getAttr ($sknode + ".maxRotYLimitEnable")`; setAttr ($pCharacter + "." + $NodeName + "MaxRLimitEnablez") `getAttr ($sknode + ".maxRotZLimitEnable")`; string $jo = ($sknode + ".jointOrient"); if(`objExists $jo`) { setAttr ($pCharacter + "." + $NodeName + "JointOrientx") `getAttr ($sknode + ".jointOrientX")`; setAttr ($pCharacter + "." + $NodeName + "JointOrienty") `getAttr ($sknode + ".jointOrientY")`; setAttr ($pCharacter + "." + $NodeName + "JointOrientz") `getAttr ($sknode + ".jointOrientZ")`; } setAttr ($pCharacter + "." + $NodeName + "RotateAxisx") `getAttr ($sknode + ".rotateAxisX")`; setAttr ($pCharacter + "." + $NodeName + "RotateAxisy") `getAttr ($sknode + ".rotateAxisY")`; setAttr ($pCharacter + "." + $NodeName + "RotateAxisz") `getAttr ($sknode + ".rotateAxisZ")`; setAttr ($pCharacter + "." + $NodeName + "RotateOrder") `getAttr ($sknode + ".rotateOrder")`; } proc int isInStanceInput( string $pCharacter ) { string $solver = hikGetSolverNodeFromCharacter( $pCharacter ); if( $solver != "" ) { if(hikIsCharacterEnabled($pCharacter)) { return `getAttr ($solver+".InputStance" )`; } } return 0; } // Get SKReader from Character (HIKSK2State) proc string getSKReaderFromCharacter(string $pCharacter) { string $lSKReaderAttr = $pCharacter + ".OutputCharacterDefinition"; string $list[] = `listConnections -type HIKSK2State $lSKReaderAttr`; if( size( $list ) > 0 ) { return $list[0]; } else { return ""; } } //////////////////////////////////////////////////////////////////////// // Global methods... //////////////////////////////////////////////////////////////////////// global proc hikReadStancePoseTRSOffsetsForNode( string $pCharacter, int $nodeId ) { string $nodeName = GetHIKNodeName($nodeId); string $tmpCharObjectName = $pCharacter + "." + $nodeName; string $tmpNode[] = `listConnections $tmpCharObjectName`; if (size($tmpNode)>0) { float $lMat[] = `xform -q -ws -m $tmpNode[0]`; // $lMat will have translate/rotate in internal units. The // GetHIKMatrixDecomposition() function will convert the // TRS to UI units for use with setAttr float $lTRS[] = `GetHIKMatrixDecomposition($lMat)`; hikSetSkTOffsetOnCharacter($pCharacter, $nodeId, $lTRS[0],$lTRS[1],$lTRS[2]); hikSetSkROffsetOnCharacter($pCharacter, $nodeId, $lTRS[3],$lTRS[4],$lTRS[5]); hikSetSkSOffsetOnCharacter($pCharacter, $nodeId, $lTRS[6],$lTRS[7],$lTRS[8]); SetDOFonCharacter($pCharacter, $nodeId, $tmpNode[0]); } } global proc string[] hikGetSkeletonNodes(string $pCharacter) // Description: // Get all the skeleton ndoes from the specified character // { string $lSKNodes[]; if( size( $pCharacter ) > 0 && objExists( $pCharacter ) ) { int $i; string $curSKNode = ""; int $lMatched = 0; for($i = 0; $i < hikGetNodeCount(); $i++) { $curSKNode = hikGetSkNode($pCharacter, $i); if( $curSKNode != "" ) $lSKNodes[$lMatched++] = $curSKNode; } } return $lSKNodes; } global proc hikSelectSkeletonNodes(string $character) { string $lSKNodes[] = hikGetSkeletonNodes($character); for($lElement in $lSKNodes) { if( $lElement != "" ) select -add $lElement; } } global proc string hikGetSkeletonGeneratorNode(string $pCharacter) // Description: // Get the skeleton generator node from the specified character // { if( $pCharacter == "" || objExists( $pCharacter ) == false ) return ""; string $conns[] = `listConnections -s 1 -d 0 -type "HIKSkeletonGeneratorNode" $pCharacter`; if(size($conns) > 0) return $conns[0]; else return ""; } global proc hikSetSkeletonGeneratorDefaults(string $skeletonGeneratorNode) // Description: // Set the specified skeleton generator node's values to the defaults // { string $plug; $plug = $skeletonGeneratorNode + ".ShoulderCount"; setAttr $plug 1; // Roll-Bones $plug = $skeletonGeneratorNode + ".WantUpperArmRollBone"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantLowerArmRollBone"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantUpperLegRollBone"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantLowerLegRollBone"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".SpineCount"; setAttr $plug 3; $plug = $skeletonGeneratorNode + ".NeckCount"; setAttr $plug 1; // FINGERS $plug = $skeletonGeneratorNode + ".FingerJointCount"; setAttr $plug 3; $plug = $skeletonGeneratorNode + ".WantMiddleFinger"; setAttr $plug 1; $plug = $skeletonGeneratorNode + ".WantIndexFinger"; setAttr $plug 1; $plug = $skeletonGeneratorNode + ".WantRingFinger"; setAttr $plug 1; $plug = $skeletonGeneratorNode + ".WantPinkyFinger"; setAttr $plug 1; $plug = $skeletonGeneratorNode + ".WantThumb"; setAttr $plug 1; $plug = $skeletonGeneratorNode + ".WantExtraFinger"; setAttr $plug 0; // TOES $plug = $skeletonGeneratorNode + ".ToeJointCount"; setAttr $plug 3; $plug = $skeletonGeneratorNode + ".WantIndexToe"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantMiddleToe"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantRingToe"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantPinkyToe"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantBigToe"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantFootThumb"; setAttr $plug 0; // Finger and Toe Base $plug = $skeletonGeneratorNode + ".WantFingerBase"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantToeBase"; setAttr $plug 1; // In-Hand and In-Foot Joints $plug = $skeletonGeneratorNode + ".WantInHandJoint"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantInFootJoint"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantHipsTranslation"; setAttr $plug 0; } global proc hikReadCharPoseFromSkeletonGeneratorNode(string $pCharacter, string $skeletonGeneratorNode, float $characterScale) { string $curNode; float $lT[]; float $lR[]; float $lS[]; int $i; for($i = 0; $i < hikGetNodeCount(); $i++) { string $nodeName = GetHIKNodeName($i); string $tmpCharObjectName = $skeletonGeneratorNode + "." + $nodeName; // Get the children of T so that we can proper units $lT = getSkelTranslateArray( $tmpCharObjectName ); $lT[0] *= $characterScale; $lT[1] *= $characterScale; $lT[2] *= $characterScale; $lR = `getAttr ($tmpCharObjectName + "R")`; $lS = `getAttr ($tmpCharObjectName + "S")`; hikSetSkTOffsetOnCharacter($pCharacter, $i, $lT[0], $lT[1], $lT[2] ); hikSetSkROffsetOnCharacter($pCharacter, $i, $lR[0],$lR[1],$lR[2]); hikSetSkSOffsetOnCharacter($pCharacter, $i, $lS[0],$lS[1],$lS[2]); hikSetSkTOffsetOnSkeletonGeneratorNode($skeletonGeneratorNode,$nodeName, $lT[0], $lT[1], $lT[2] ); } } global proc hikReadStancePoseTRSOffsets(string $pCharacter) // Description: // Captures the current character pose to the character node { if( size($pCharacter) <= 0 ) error( (uiRes("m_hikSkeletonUtils.kNoCharacter")) ); int $i; for($i = 0; $i < hikGetNodeCount(); $i++) { hikReadStancePoseTRSOffsetsForNode( $pCharacter, $i ); } } global proc hikWriteSkeletonPoseFile(string $skeletonGeneratorNode,string $filePath) // Description: // Write a skeleton's pose and other joint settings, to an ASCII file // { int $fileId = `fopen $filePath "w"`; float $lT[]; int $i; for($i = 0; $i < hikGetNodeCount(); $i++) { string $nodeName = GetHIKNodeName($i); string $tmpCharObjectName = $skeletonGeneratorNode + "." + $nodeName; $lT = `getAttr ($tmpCharObjectName + "T")`; string $oneLine = $nodeName + " " + $lT[0] + " " + $lT[1] + " " + $lT[2] + " " + 0 + " " + 0 + " " + 0 + " " + 1 + " " + 1 + " " + 1 + "\n"; fprint ( $fileId, $oneLine); } fclose $fileId; } global proc int hikIsSkeletonVisible(string $pCharacter) // Description: // Return 1 if the character's skeleton objects are visible // { int $lShowOrHide = 0; if( size( $pCharacter ) > 0 && objExists( $pCharacter ) ) { string $curSKNode = hikGetSkNode($pCharacter, 1); if( $curSKNode != "" ) { if( attributeExists( "drawStyle", $curSKNode ) ) $lShowOrHide = `getAttr ( $curSKNode + ".drawStyle" )` != 2; // != None look else $lShowOrHide = `getAttr ( $curSKNode + ".visibility" )`; } } return $lShowOrHide; } global proc int hikIsSkeletonLabelVisible(string $character) // Description: // Return 1 if the skeleton's labels are visible // { string $skelNodes[] = hikGetSkeletonNodes($character); if (size($skelNodes) > 1) { // Note: we use skelNodes[1] because that's the first joint. // The first node returned by hikGetSkeletonNodes is the character // reference node, which is a locator. // MAYA-18178: include the attributeExists check in case the 'joint' // is actually just a transform. // if ( `attributeExists "drawLabel" $skelNodes[1]` ) { return `getAttr ($skelNodes[1]+".drawLabel")`; } } return 0; } // Return the roll bone position based on the number of roll bones used and the length // between the 2 joints where the roll bone is placed proc float[] getRollBonePosition(float $start[], float $end[], float $splitFactor) { float $lTXform[]; $lTXform[0] = ($start[0] * (1 - $splitFactor)) + ($end[0] * $splitFactor); $lTXform[1] = ($start[1] * (1 - $splitFactor)) + ($end[1] * $splitFactor); $lTXform[2] = ($start[2] * (1 - $splitFactor)) + ($end[2] * $splitFactor); return $lTXform; } proc int isRollBone(string $name) { // To validate that we are dealing with a roll bone we look for // "ArmRoll" and "LegRoll" at the end of string name // (this will also cover "ForeArmRoll" and "UpLegRoll" string $res1 = `match "ArmRoll[1-5]*$" $name`; string $res2 = `match "LegRoll[1-5]*$" $name`; return ($res1 != "") || ($res2 != ""); } global proc int isLeafRollBone(string $name) { // Leaf must be at the beginning of the name string return isRollBone($name) && size(`match "^Leaf" $name`); } global proc int isOldRollBone( string $name ) { return( isRollBone( $name ) && (!isLeafRollBone( $name )) ); } proc string getRollBoneSide(string $name) { // check for "Left" or "Right" side string $side = ""; if (isRollBone($name)) { // take into account the case for "Leaf" too string $leftMatch = (isLeafRollBone($name)) ? "^LeafLeft" : "^Left"; string $rightMatch = (isLeafRollBone($name)) ? "^LeafRight" : "^Right"; $side = (`match $leftMatch $name` != "") ? "Left" : ((`match $rightMatch $name` != "") ? "Right" : ""); } return $side; } proc string getRollBoneLimbName(string $name) { // get the limb name. This is the part stripped of "Left/Right", "Leaf" and "Roll" string $limb = ""; if (isRollBone($name)) { if ($limb == "") $limb = `match "ForeArmRoll[1-5]*$" $name`; if ($limb == "") $limb = `match "UpLegRoll[1-5]*$" $name`; if ($limb == "") $limb = `match "ArmRoll[1-5]*$" $name`; if ($limb == "") $limb = `match "LegRoll[1-5]*$" $name`; $limb = substitute("Roll[1-5]*", $limb, ""); } return $limb; } proc int getRollBoneIndex(string $name) { // return a 1 based index (0 means no index found) int $index=0; if (isRollBone($name)) { string $num = `match "[1-5]$" $name`; $index = (size($num)) ? $num : 0; } return $index; } proc string getRollBoneType(string $name) { // check for "Upper" or "Lower" limb. Upper limbs are the Arm and UpLeg while the // lower limbs are the ForeArm and Leg string $type = ""; if (isRollBone($name)) { if ($type == "" && (`match "ForeArmRoll[1-5]*$" $name` != "")) $type = "Lower"; else if ($type == "" && (`match "UpLegRoll[1-5]*$" $name` != "")) $type = "Upper"; else if ($type == "" && (`match "ArmRoll[1-5]*$" $name` != "")) $type = "Upper"; else if ($type == "" && (`match "LegRoll[1-5]*$" $name` != "")) $type = "Lower"; } return $type; } proc float[] computeRollBoneTXform(string $nodeName, string $pCharacter,string $skeletonGeneratorNode) { float $lT1[], $lT2[], $lTXform[]; string $partLimb; // decompose the roll bone name into its parts string $side = getRollBoneSide($nodeName); // "Left" or "Right" string $type = getRollBoneType($nodeName); // "Upper" or "Lower" string $limb = getRollBoneLimbName($nodeName); // "Arm", "ForeArm", "UpLeg" or "Leg" int $rollId = getRollBoneIndex($nodeName); // 1 to 5 or 0 int $leaf = isLeafRollBone($nodeName); // 1 if name starts with "Leaf" // initial positions for calculating roll bones position if (`match "Arm" $limb` == "Arm") { $partLimb = "Arm"; $lT1 = `xform -q -ws -t (hikGetSkNode($pCharacter,hikGetNodeIdFromName($side+"Arm")))`; $lT2 = `xform -q -ws -t (hikGetSkNode($pCharacter,hikGetNodeIdFromName($side+"ForeArm")))`; if ($limb == "ForeArm") { $lT1 = $lT2; $lT2 = `xform -q -ws -t (hikGetSkNode($pCharacter,hikGetNodeIdFromName($side+"Hand")))`; } } else if (`match "Leg" $limb` == "Leg") { $partLimb = "Leg"; $lT1 = `xform -q -ws -t (hikGetSkNode($pCharacter,hikGetNodeIdFromName($side+"Leg")))`; $lT2 = `xform -q -ws -t (hikGetSkNode($pCharacter,hikGetNodeIdFromName($side+"Foot")))`; if ($limb == "UpLeg") { $lT2 = $lT1; $lT1 = `xform -q -ws -t (hikGetSkNode($pCharacter,hikGetNodeIdFromName($side+"UpLeg")))`; } } int $nbRollBones = `getAttr ($skeletonGeneratorNode + ".Nb" + $type + $partLimb + "RollBones")`; float $factor = 0.5; if (!$leaf) { // compute for old roll bones $lTXform = getRollBonePosition($lT1, $lT2, $factor); } else if($rollId > 0) // REMEMBER: $rollId is 1 based!!!! This is a sanity check { // compute the appropriate factor based on the count of roll bones and the roll bone index float $factors[], $factors1[], $factors2[], $factors3[], $factors4[], $factors5[]; if ($type == "Upper") { $factors1 = {0.10, 0.00, 0.00, 0.00, 0.00}; $factors2 = {0.10, 0.50, 0.00, 0.00, 0.00}; $factors3 = {0.10, 0.50, 0.90, 0.00, 0.00}; $factors4 = {0.10, 0.30, 0.60, 0.90, 0.00}; $factors5 = {0.10, 0.22, 0.44, 0.66, 0.90}; } else { $factors1 = {0.90, 0.00, 0.00, 0.00, 0.00}; $factors2 = {0.45, 0.90, 0.00, 0.00, 0.00}; $factors3 = {0.30, 0.60, 0.90, 0.00, 0.00}; $factors4 = {0.22, 0.44, 0.66, 0.90, 0.00}; $factors5 = {0.18, 0.36, 0.54, 0.72, 0.90}; } switch ($nbRollBones) { case 1: $factors = $factors1; break; case 2: $factors = $factors2; break; case 3: $factors = $factors3; break; case 4: $factors = $factors4; break; case 5: $factors = $factors5; break; } $factor = $factors[ $rollId-1 ]; if ($nbRollBones > $rollId-1) $lTXform = getRollBonePosition($lT1, $lT2, $factor); } return $lTXform; } // Check if the specified character is using "inline" roll bones. global proc int hikIsUsingInlineRollBones(string $pCharacter) { int $isUsingInlineRollBones = 0; for($i = 0; $isUsingInlineRollBones==0 && $i < hikGetNodeCount(); $i++) { string $nodeName = GetHIKNodeName($i); if (isRollBone($nodeName)) { if (!isLeafRollBone($nodeName)) { // Okay we are on one of the "legacy" roll bones. Now recompose the // the full name so we can check the state. string $name = $pCharacter + "." + $nodeName; string $tmpConnections[] = `listConnections $name`; $isUsingInlineRollBones = size($tmpConnections) > 0; } } } return $isUsingInlineRollBones; } // Disconnect the legacy "inline" roll bones from the skeleton definition // REMARK: a call to update the Character UI is also required to keep the // UI sync with the skeleton definition. This call is made in the // hikOperations.mel after the users answers the prompting dialog. global proc hikDisconnectInlineRollBones(string $pCharacter) { hikSetCharacterObject("", $pCharacter, 41, 0); // LeftUpLegRoll (41) hikSetCharacterObject("", $pCharacter, 42, 0); // LeftLegRoll (42) hikSetCharacterObject("", $pCharacter, 43, 0); // RightUpLegRoll (43) hikSetCharacterObject("", $pCharacter, 44, 0); // RightLegRoll (44) hikSetCharacterObject("", $pCharacter, 45, 0); // LeftArmRoll (45) hikSetCharacterObject("", $pCharacter, 46, 0); // LeftForeArmRoll (46) hikSetCharacterObject("", $pCharacter, 47, 0); // RightArmRoll (47) hikSetCharacterObject("", $pCharacter, 48, 0); // RightForeArmRoll (48) // Make sure we don't try to add inline rollbones again during the // hikUpdateSkeletonNodes calls string $plug; string $skeletonGeneratorNode = hikGetSkeletonGeneratorNode($pCharacter); if (size($skeletonGeneratorNode) > 0) { $plug = $skeletonGeneratorNode + ".WantUpperLegRollBone"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantLowerLegRollBone"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantUpperArmRollBone"; setAttr $plug 0; $plug = $skeletonGeneratorNode + ".WantLowerArmRollBone"; setAttr $plug 0; } } // Regenerate the skeleton from the skeleton generator node, all we care about // is the global positions of the joints, as the process is going to unparent everything. // If the HIK bone is not characterized, currently, there is no connection to it. // In this case, we need to extrapolate from the known data about where to put this bone. // TODO: The position of a roll bones depends of the number of roll bones. // At the moment we are always repositionning the roll bones but if required we could // add some logic to only regenerate them if one joint has been added or removed, if not we just // update the roll bones position. global proc hikSyncCurrentPoseToSkeletonGenerator(string $pCharacter,string $skeletonGeneratorNode) { float $lT[], $lTXform[]; for($i = 0; $i < hikGetNodeCount(); $i++) { clear($lTXform); clear($lT); string $skNode = hikGetSkNode($pCharacter,$i); string $nodeName = GetHIKNodeName($i); if (isRollBone($nodeName)) { $lTXform = computeRollBoneTXform($nodeName, $pCharacter, $skeletonGeneratorNode); $lT = HikConvertXformTranslateToUIUnits( $lTXform ); } else { // Get position for all other created nodes if ($skNode != ""){ $lTXform = `xform -q -ws -t $skNode`; } else { // TODO: do the same for the fingers and toes that aren't present (OLD COMMENT) continue; } } $lT = HikConvertXformTranslateToUIUnits( $lTXform ); hikSetSkTOffsetOnSkeletonGeneratorNode($skeletonGeneratorNode,$nodeName, $lT[0],$lT[1],$lT[2]); hikSetSkROffsetOnSkeletonGeneratorNode($skeletonGeneratorNode,$nodeName, 0,0,0); hikSetSkSOffsetOnSkeletonGeneratorNode($skeletonGeneratorNode,$nodeName, 1,1,1); } } global proc hikSetSkTOffsetOnSkeletonGeneratorNode(string $skeletonGeneratorNode,string $nodeName, float $tx, float $ty,float $tz) { string $txPlug = $skeletonGeneratorNode + "." + $nodeName + "Tx"; string $tyPlug = $skeletonGeneratorNode + "." + $nodeName + "Ty"; string $tzPlug = $skeletonGeneratorNode + "." + $nodeName + "Tz"; setAttr $txPlug $tx; setAttr $tyPlug $ty; setAttr $tzPlug $tz; } global proc hikSetSkROffsetOnSkeletonGeneratorNode(string $skeletonGeneratorNode,string $nodeName, float $rx, float $ry,float $rz) { string $rxPlug = $skeletonGeneratorNode + "." + $nodeName + "Rx"; string $ryPlug = $skeletonGeneratorNode + "." + $nodeName + "Ry"; string $rzPlug = $skeletonGeneratorNode + "." + $nodeName + "Rz"; setAttr $rxPlug $rx; setAttr $ryPlug $ry; setAttr $rzPlug $rz; } global proc hikSetSkSOffsetOnSkeletonGeneratorNode(string $skeletonGeneratorNode,string $nodeName, float $sx, float $sy,float $sz) { string $sxPlug = $skeletonGeneratorNode + "." + $nodeName + "Sx"; string $syPlug = $skeletonGeneratorNode + "." + $nodeName + "Sy"; string $szPlug = $skeletonGeneratorNode + "." + $nodeName + "Sz"; setAttr $sxPlug $sx; setAttr $syPlug $sy; setAttr $szPlug $sz; } // Read a Character Nodes Pose and other Joint settings, from an ASCII file global proc hikReadDefaultCharPoseFileOntoSkeletonGeneratorNode(string $skeletonGeneratorNode) { string $scriptPath = substitute( "Mel procedure found in: ", (string)`whatIs "hikReadCharPoseFileOntoSkeletonGeneratorNode"`, ""); string $dirname = `dirname $scriptPath`; string $poseFileName = $dirname + "/Biped_Template.hik"; hikReadCharPoseFileOntoSkeletonGeneratorNode($skeletonGeneratorNode,$poseFileName); } // Read a Character Nodes Pose and other Joint settings, from an ASCII file global proc hikReadCharPoseFileOntoSkeletonGeneratorNode(string $skeletonGeneratorNode,string $poseFileName) { string $errorMessageInvalidCharacterTemplate = (uiRes("m_hikSkeletonUtils.kInvalidTemplate")); int $fileId = `fopen $poseFileName "r"`; float $lT[]; float $lR[]; float $lS[]; int $lNodeId; string $s, $nodeName; if($fileId == 0) { string $fmt = (uiRes("m_hikSkeletonUtils.kFileNotFound")); string $errorString = `format -s $poseFileName $fmt`; error $errorString; } // Parse the input file by ... while ( !`feof $fileId` ) { // ... reading each line $s = `fgetline $fileId`; // ... and making sure to skip blank lines. if (size($s) == 0) continue; // If the line is not blank extract TRS values string $lTokenizedList[]; tokenizeList( $s, $lTokenizedList); if (size($lTokenizedList) != 10) error $errorMessageInvalidCharacterTemplate; $nodeName = $lTokenizedList[0]; float $t[]; $t[0] = $lTokenizedList[1]; $t[1] = $lTokenizedList[2]; $t[2] = $lTokenizedList[3]; $lT = HikConvertXformTranslateToUIUnits( $t ); if ( size( $lT ) != 3 ) return; float $r[]; $r[0] = $lTokenizedList[4]; $r[1] = $lTokenizedList[5]; $r[2] = $lTokenizedList[6]; $lR = HikConvertDegreesToUIUnits( $r ); if ( size( $lR ) != 3 ) return; $lS[0] = $lTokenizedList[7]; $lS[1] = $lTokenizedList[8]; $lS[2] = $lTokenizedList[9]; hikSetSkTOffsetOnSkeletonGeneratorNode($skeletonGeneratorNode, $nodeName, $lT[0],$lT[1],$lT[2]); hikSetSkROffsetOnSkeletonGeneratorNode($skeletonGeneratorNode, $nodeName, $lR[0],$lR[1],$lR[2]); hikSetSkSOffsetOnSkeletonGeneratorNode($skeletonGeneratorNode, $nodeName, $lS[0],$lS[1],$lS[2]); } fclose $fileId; } // Unparent Characterized Nodes global proc hikUnparentCharNodes(string $pCharacter) { string $curNode; string $reparentedNode[]; int $i; for($i = 0; $i < hikGetNodeCount(); $i++) { $curNode = hikGetSkNode($pCharacter, $i); // the node is empty or it is child of the world if( $curNode == "" || firstParentOf( $curNode ) == "" ) continue; // Use the returned name of the node after reparenting MAYA-58502 $reparentedNode = `parent -w -r $curNode`; string $src[] = `listConnections -s 1 -d 0 -p 1 ($reparentedNode[0] +".inverseScale")`; if( size( $src ) == 1 ) { disconnectAttr $src[0] ($reparentedNode[0] +".inverseScale"); } } } // Make sure a skeleton exists and that the 15 base bones are there. global proc int hikValidateSkeleton(string $pCharacter) { for($i = 1; $i <= 15; $i++) { $curNode = hikGetSkNode($pCharacter, $i); if($curNode == "") return false; } return true; } // Update skel nodes for a given defined Character global proc hikUpdateSkeletonNodes(string $pCharacter,string $skeletonGeneratorNode) { int $lWantedJoints[] = setWantedJointsFromSkeletonGeneratorNode($skeletonGeneratorNode); int $i; for($i = 0; $i < hikGetNodeCount(); $i++) { string $nodeName = GetHIKNodeName($i); string $curNode = hikGetSkNode($pCharacter, $i); if ( ($lWantedJoints[$i]) == 1 ) { if( $curNode == "" ) { string $skellName = $pCharacter + "_" + $nodeName; if ( $i == 0 ) // Create a locator for the reference { string $name[] = `spaceLocator -n $skellName`; $skellName = $name[0]; } else // and joints otherwise { $skellName = `createNode "joint" -n $skellName`; } hikAddSkToCharacter($pCharacter, $skellName, $i, 1 /*select */ ); } } else { if( $curNode != "" ) { hikRemoveSkFromCharacter($pCharacter, $i); delete $curNode; } } } } // Set Skel Nodes Global Transforms global proc hikSetSkeletonGlobalTRS(string $pCharacter) { if ( objExists( $pCharacter ) == false ) return; string $curNode; float $lT[]; float $lR[]; float $lS[]; int $i; for($i = 0; $i < hikGetNodeCount(); $i++) { $curNode = hikGetSkNode($pCharacter, $i); if ( $curNode == "" ) continue; string $nodeName = GetHIKNodeName($i); string $tmpCharObjectName = $pCharacter + "." + $nodeName; $lT = getSkelTranslateArray( $tmpCharObjectName ); $lR = `getAttr ($tmpCharObjectName + "R")`; $lS = `getAttr ($tmpCharObjectName + "S")`; setAttr ($curNode + ".translate") $lT[0] $lT[1] $lT[2]; setAttr ($curNode + ".rotate") $lR[0] $lR[1] $lR[2]; setAttr ($curNode + ".scale") $lS[0] $lS[1] $lS[2]; } } // Set Spine or Neck Global Transforms global proc hikSetSpineOrNeckGlobalTRS(string $pCharacter,string $skeletonGeneratorNode, string $pSpineOrNeck) { if ( objExists( $pCharacter ) == false ) return; string $tmpCharObjectName; int $lNodeId; float $lT[]; int $i; int $lSpineVal; float $lFirstJointT[]; float $lLastJointT[]; string $plug; if($pSpineOrNeck == "Spine") { $plug = $skeletonGeneratorNode + ".SpineCount"; $lSpineVal = `getAttr $plug`; $tmpCharObjectName = $pCharacter + "." + "Neck"; $lLastJointT = getSkelTranslateArray( $tmpCharObjectName ); } else { $plug = $skeletonGeneratorNode + ".NeckCount"; $lSpineVal = `getAttr $plug`; $tmpCharObjectName = $pCharacter + "." + "Head"; $lLastJointT = getSkelTranslateArray( $tmpCharObjectName ); } if($lSpineVal == 0) return; $tmpCharObjectName = $pCharacter + "." + $pSpineOrNeck; $lFirstJointT = getSkelTranslateArray( $tmpCharObjectName ); float $lJointDistY = ($lLastJointT[1] - $lFirstJointT[1]); float $lEachJointDistY = ($lJointDistY / $lSpineVal); for($i = 0; $i < $lSpineVal; $i++) { if( $i == 0 ) { $lNodeId = hikGetNodeIdFromName($pSpineOrNeck); $tmpCharObjectName = $pCharacter + "." + $pSpineOrNeck; } else { $lNodeId = hikGetNodeIdFromName($pSpineOrNeck + $i); $tmpCharObjectName = $pCharacter + "." + $pSpineOrNeck + $i; } $curNode = hikGetSkNode($pCharacter, $lNodeId); if( $curNode != "" ) { $lT = `getAttr ($tmpCharObjectName + "T")`; if( $i < $lSpineVal ) { $lT[1] = $lFirstJointT[1] + ($lEachJointDistY * $i); setAttr ($curNode + ".translate") $lT[0] $lT[1] $lT[2]; } } } } // Recursive Parent FK Hierarchy global proc hikRecursiveParentSkeleton(string $pCharacter, int $nodeId) { if ( objExists( $pCharacter ) == false ) return; int $i; string $tmpNode[]; string $skChild; int $childId; string $skParent; string $nodeName = GetHIKNodeName($nodeId); string $tmpCharObjectName = $pCharacter + "." + $nodeName; // Get Parent node string $pconns[] = `listConnections $tmpCharObjectName`; if (size($pconns) > 0) { $skParent = $pconns[0]; } // Get childs and parent them to Parent int $lChildCount = `GetHIKChildCount -nid $nodeId $pCharacter`; for($i = 0; $i < $lChildCount; $i++) { $childId = `GetHIKChildId -nid $nodeId -cid $i $pCharacter`; $nodeName = GetHIKNodeName($childId); $tmpCharObjectName = $pCharacter + "." + $nodeName; string $conns[] = `listConnections $tmpCharObjectName`; if (size($conns) > 0) { $skChild = $conns[0]; parent $skChild $skParent; hikRecursiveParentSkeleton($pCharacter, $childId); } } } global proc float hikGetCharacterScale(string $pCharacter) { if ( objExists( $pCharacter ) == false ) return 1.; string $plug; $plug = $pCharacter + ".HeadT"; float $headT[] = `getAttr $plug`; $plug = $pCharacter + ".HipsT"; float $hipsT[] = `getAttr $plug`; //Measure the height of the character and adjust the scale accordingly. //65 is a magic number that through trial and error shows to give a good //radius. float $scale = ($headT[1] - $hipsT[1]) / 65.0; return $scale; } global proc hikSetSkeletonRadius(string $pCharacter) { int $lastBigJoint = hikGetNodeIdFromName("RightForeArmRoll"); int $lShoulderExtra = hikGetNodeIdFromName("LeftShoulderExtra"); float $characterScale = hikGetCharacterScale($pCharacter); for($i = 1; $i < hikGetNodeCount(); $i++) { $nodeName = GetHIKNodeName($i); $curNode = hikGetSkNode($pCharacter, $i); if( $curNode != "" ) { float $scaleFact = (isRollBone($nodeName)) ? 3.0 : 1.5; string $jointRadiusAttr = $curNode + ".radius"; if( $i <= $lastBigJoint || $i >= $lShoulderExtra) setAttr $jointRadiusAttr ($scaleFact*$characterScale); else setAttr $jointRadiusAttr $characterScale; } } } global proc hikSetSkTOffsetOnCharacter(string $pCharacter, int $pNodeId, float $Tx,float $Ty,float $Tz) { string $NodeName = GetHIKNodeName($pNodeId); $attrTx = $pCharacter + "." + $NodeName + "Tx"; $attrTy = $pCharacter + "." + $NodeName + "Ty"; $attrTz = $pCharacter + "." + $NodeName + "Tz"; setAttr $attrTx $Tx; setAttr $attrTy $Ty; setAttr $attrTz $Tz; } global proc hikSetSkROffsetOnCharacter(string $pCharacter, int $pNodeId, float $Rx,float $Ry,float $Rz) { string $NodeName = GetHIKNodeName($pNodeId); $attrRx = $pCharacter + "." + $NodeName + "Rx"; $attrRy = $pCharacter + "." + $NodeName + "Ry"; $attrRz = $pCharacter + "." + $NodeName + "Rz"; setAttr $attrRx $Rx; setAttr $attrRy $Ry; setAttr $attrRz $Rz; } global proc hikSetSkSOffsetOnCharacter(string $pCharacter, int $pNodeId, float $Sx,float $Sy,float $Sz) { string $NodeName = GetHIKNodeName($pNodeId); $attrSx = $pCharacter + "." + $NodeName + "Sx"; $attrSy = $pCharacter + "." + $NodeName + "Sy"; $attrSz = $pCharacter + "." + $NodeName + "Sz"; setAttr $attrSx $Sx; setAttr $attrSy $Sy; setAttr $attrSz $Sz; } // // Unit conversion utilities // global proc float[] HikConvertXformTranslateToUIUnits( float $translate[] ) { float $ft[]; string $st[]; int $i; string $currUnit = `currentUnit -query -linear`; if ( $currUnit == "cm" ) { return $translate; } for ( $i = 0; $i < size($translate); $i++ ) { string $f = $translate[$i]; $st[$i] = `convertUnit -fromUnit "cm" -toUnit $currUnit $f`; if ( endsWith( $st[$i], $currUnit ) ) { string $s = `substitute $currUnit $st[$i] ""`; $ft[$i] = $s; } else { $ft[$i] = $st[$i]; } } return $ft; } global proc float[] HikConvertDegreesToUIUnits( float $rotate[] ) { string $currUnit = `currentUnit -query -angle`; if ( $currUnit == "deg" ) return $rotate; float $fr[]; string $sr[]; int $i; for ( $i = 0; $i < size($rotate); $i++ ) { string $f = $rotate[$i]; $sr[$i] = `convertUnit -fromUnit "deg" -toUnit $currUnit $f`; if ( endsWith( $sr[$i], $currUnit ) ) { string $s = `substitute $currUnit $sr[$i] ""`; $ft[$i] = $s; } else { $fr[$i] = $sr[$i]; } } return $fr; } // This function is used to either get a SkNode on a character or an FkNode on a Rig global proc string hikGetSkNode(string $pCharacterOrRig, int $nodeId) { string $curNode = ""; if ( objExists( $pCharacterOrRig ) ) { string $nodeName = GetHIKNodeName($nodeId); string $tmpCharObjectName = $pCharacterOrRig + "." + $nodeName; string $conns[] = `listConnections $tmpCharObjectName`; if (size($conns) > 0) { $curNode = $conns[0]; } } return $curNode; } global proc hikConnectSkFromCharacterState(string $pState, string $pCharacter, int $bakeMode ) { // Note: ensure SK is not connected prior to call this proc int $LastNodeId = hikGetNodeCount(); for($i = 0; $i < $LastNodeId; $i++) { $hiknodename = GetHIKNodeName($i); $AttrName = $pCharacter + "." + $hiknodename; string $SkNode[] = `listConnections -s 1 -d 0 $AttrName`; // Should never write in reference if($hiknodename != "Reference") { if(size($SkNode) > 0) { string $node = $SkNode[0]; // Feed the SkState node with any information that may be required from the Sk side if( !`isConnected ($node+".parentMatrix") ($pState+"."+$hiknodename + "PGX")` ) { connectAttr -f ($node+".parentMatrix") ($pState+"."+$hiknodename + "PGX"); // If we are retargeting to non-joint transforms, they may not have the jointOrient attribute // This is ok, since the state2Bone node will just use a pre-rotation of 0 if there is // no connection to that attribute. int $isJoint = `objectType -isAType "joint" $node`; if( $isJoint ) { // jointOrient connectAttr -f ($node+".jointOrient") ($pState+"."+$hiknodename + "PreR"); // segmentScaleCompensate ( boolean ) connectAttr -f ($node+".segmentScaleCompensate") ($pState+"."+$hiknodename + "SC"); // inverseScale ( 3 doubles ) used if segmentScaleCompensate is true connectAttr -f ($node+".inverseScale") ($pState+"."+$hiknodename + "IS"); } connectAttr -f ($node+".rotateOrder") ($pState+"."+$hiknodename + "ROrder"); connectAttr -f ($node+".rotateAxis") ($pState+"."+$hiknodename + "PostR"); } // Activate the bone by feeding it with the state string $srcT = ""; string $srcR = ($pState+"."+$hiknodename+"R"); string $srcS = ""; int $isRotateOnly = hikIsRotateOnlyFK( $i ); if( !$bakeMode || !$isRotateOnly ) { $srcT = ($pState+"."+$hiknodename+"T"); } if( !$bakeMode ) { $srcS = ($pState+"."+$hiknodename+"S"); } connectSourceAndSaveAnim( $node, $srcT, $srcR, $srcS, $bakeMode ); } } } } global proc hikDisconnectSkByDeletingPairBlends(string $character ) { // disconnect any pairBlend that could remain string $state2sk[] = hikGetState2SKFromCharacter( $character ); if( size($state2sk)>0 ) { string $pairBlends[] = `listConnections -s 0 -d 1 -type pairBlend $state2sk`; string $pairBlendsCleaned[] = stringArrayRemoveDuplicates( $pairBlends ); for( $pairBlend in $pairBlendsCleaned ) { // Because the defald delete passthrough behavior is not // acceptable in this case, we isntead use a custom version removePairBlend( $pairBlend ); // catchQuiet( `delete $pairBlend` ); } } } global proc hikDisconnectSkFromCharacterState(string $pState2Sk, string $pCharacter, int $dirtyPlugs ) { // Disconnect skeleton bones from SkFromState // Should be used to put character in an inactive state // Call ConnectSkFromState to reactivate the input if( $pCharacter != "" ) { // Here the Character can be place everywhere in the space // hips are usually parent to a reference bone that is read by HIK at Rig creation time but is ignored at solve time // if we disconnect SK as it is the offeset between sk & hips will be different to the characterized T pose, which is bad because it mess the skeleton // What we do here is simply put the sk reference at the FK reference position but we make sure to convert into proper transformation space using ComputeReference // that compute what is a sk reference TRS given a FK reference TRS // After the SK is properly set, everything will be disconnect, the offset between hips & ref will be good, then we restore sk reference current position (backuped here) string $skref = hikGetSkNode($pCharacter, 0); //getRef float $refrot[3]; float $refT[3]; if($skref != "") { $refrot = `getAttr ($skref + ".rotate")`; // backup the rotation & translation $refT = `getAttr ($skref + ".translate")`; string $controlset = hikGetControlRig($pCharacter); if($controlset != "") { string $fkref = hikGetSkNode($controlset, 0); //getRef if($fkref != "") { if(isInStanceInput($pCharacter)) // fkref is not use to compute the Stance input position so reset the sk to characterization { HIKComputeReference -ch $pCharacter -sk $skref -rsk; } else { HIKComputeReference -ch $pCharacter -cr $fkref -sk $skref -ssk; } } } } int $LastNodeId = hikGetNodeCount( $pCharacter ); // We disconnect the leaf nodes first and then work our way up the heirarchy. // The organization of the hik ids is not sufficient for finding parent/child // relationships. So we must rely on Maya's listRelatives command below. // 1. Collect the list of connected skeleton/joint nodes string $connectedSkeletonNodes[]; for($i = $LastNodeId-1; $i >= 0 ; $i-- ) { $hiknodename = GetHIKNodeName($i); $AttrName = $pCharacter + "." + $hiknodename; string $SkNode[] = `listConnections -s 1 -d 0 $AttrName`; if(size($SkNode) > 0) { $connectedSkeletonNodes[ size($connectedSkeletonNodes) ] = $SkNode[0]; } } // 2. Loop until we have disconnected the full count int $count = size( $connectedSkeletonNodes ); while ( $count > 0 ) { // For all skeleton/joints in the list int $i; for ( $i = 0; $i < size( $connectedSkeletonNodes ) ; $i++ ) { string $sk = $connectedSkeletonNodes[$i]; // Continue if the joint name has been reset if ( size($sk) < 1 ) continue; // Find all the nodes below this child and make sure that // they are not in the connected list before we disconnect string $children[] = `listRelatives -children -path -allDescendents $sk`; // Process this list to see if any of the children // are on the connected joint list int $noConnectedChildren = true; for ( $c in $children ) { if ( stringArrayFind( $c, 0, $connectedSkeletonNodes ) >= 0 ) { $noConnectedChildren = false; break; } } // No children are present in the connected joint list so we can disconnect this leaf if ( $noConnectedChildren ) { // Call the disconnect routine that does the work disconnectSourceAndRestoreAnim( $sk, $pState2Sk, $dirtyPlugs ); // We must NULL out the skeleton/joint name in our connected list. // We also decrease the count at the same time $connectedSkeletonNodes[$i] = ""; $count--; } } } // Error checking for ( $sk in $connectedSkeletonNodes ) { if ( size( $sk ) > 0 ) { string $processingError = (uiRes("m_hikSkeletonUtils.kProcessingError")); error $processingError; } } // replace the character in his world! restore sk original position if($skref != "") { string $lSK2State = getSKReaderFromCharacter( $pCharacter ); if($lSK2State != "") { getAttr -silent ($lSK2State + ".OutputCharacterState"); // make sure evaluation get triggered everything gets upto date } setAttr ($skref + ".rotateX") $refrot[0]; setAttr ($skref + ".rotateY") $refrot[1]; setAttr ($skref + ".rotateZ") $refrot[2]; setAttr ($skref + ".translateX") $refT[0]; setAttr ($skref + ".translateY") $refT[1]; setAttr ($skref + ".translateZ") $refT[2]; } } } global proc string hikBuildSkFromState(string $pCharacter) { string $lState2SK = CreateState2SK(); hikConnectCharacterDefinition($pCharacter, $lState2SK ); return $lState2SK; } global proc string hikGetOrBuildStateFromSk( string $pCharacter ) { // Will either create and retrieve the existing StateFromSk node string $lSK2State = getSKReaderFromCharacter( $pCharacter ); if( $lSK2State == "" ) { $lSK2State = CreateSK2State(); connectStateFromSk($lSK2State, $pCharacter); } return $lSK2State; }