Guest User

FK IK switch

a guest
Nov 14th, 2019
679
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #FK-IK auto rig & matching script
  2. #select your shoulder joint, the next one in the hierarchy will be the elbow and so on.
  3.  
  4. from maya import cmds
  5.  
  6. #this function makes a list from a parent object, and places items in the right order. The updated list is returned.
  7. def getRelatives(parent, lenght):
  8.     newList = cmds.listRelatives(parent, allDescendents=1)
  9.     newList.append(parent)
  10.     newList.reverse()
  11.     print newList
  12.     if len(newList)<lenght:
  13.         print "too little joints"
  14.     else:
  15.         del newList[lenght:]
  16.     return newList
  17.  
  18. #this function adds suffixes to a given list of objects
  19. def renameList(array, suffix):
  20.     for element in array:
  21.         oldName = str(element)
  22.         cmds.rename([element], oldName+"_"+suffix)
  23.  
  24. #this function duplicates a list, makes sure they have the same lenght and gives the duplicated objects a new suffix.
  25. #The duplicated list is returned.
  26. def duplicateList(array, suffix, bHide):
  27.     oldName = str(array[0])
  28.     newList = cmds.duplicate(array[0], n=oldName+"_"+suffix, renameChildren=1)
  29.     if len(newList)>len(array):
  30.         cmds.delete(newList[len(array):len(newList)])
  31.         del newList[len(array):len(newList)]
  32.     for id in range(0, len(array)):
  33.         if bHide == 1:
  34.             cmds.setAttr(str(newList[id])+".visibility", 0)
  35.         cmds.rename(newList[id], str(array[id])+"_"+suffix)
  36.     newList = getRelatives(newList[0], 3)
  37.     return newList
  38.    
  39. #this function hides and optionally locks translate, rotate, and scale attributes
  40. def lockHideAttr(array, bTranslate, bRotate, bScale, bLock):
  41.     for object in array:
  42.         if isinstance(object, list):
  43.             object=object[0]
  44.         if bTranslate == 1:
  45.             cmds.setAttr(str(object)+".tx", keyable=0, channelBox=0, lock=bLock)
  46.             cmds.setAttr(str(object)+".ty", keyable=0, channelBox=0, lock=bLock)
  47.             cmds.setAttr(str(object)+".tz", keyable=0, channelBox=0, lock=bLock)
  48.         if bRotate == 1:
  49.             cmds.setAttr(str(object)+".rx", keyable=0, channelBox=0, lock=bLock)
  50.             cmds.setAttr(str(object)+".ry", keyable=0, channelBox=0, lock=bLock)
  51.             cmds.setAttr(str(object)+".rz", keyable=0, channelBox=0, lock=bLock)
  52.         if bScale == 1:
  53.             cmds.setAttr(str(object)+".sx", keyable=0, channelBox=0, lock=bLock)
  54.             cmds.setAttr(str(object)+".sy", keyable=0, channelBox=0, lock=bLock)
  55.             cmds.setAttr(str(object)+".sz", keyable=0, channelBox=0, lock=bLock)          
  56.  
  57. #this function creates and returns FK controllers for a given list of joints.
  58. #Null objects act as buffer for rotational values, so the controllers keep the right angle at 0,0,0
  59. def makeFKCtrls(array):
  60.     nullList = []
  61.     controllerList = []
  62.     for element in array:
  63.         fkController = cmds.circle(n=str(element)+"_ctrl", sweep=360, normalX=90, radius=1.5)
  64.         cmds.delete(cmds.parentConstraint(element, fkController, maintainOffset=0))
  65.         fkNull = cmds.group(n=str(element)+"_null", empty=1)
  66.         cmds.delete(cmds.parentConstraint(element, fkNull, maintainOffset=0))
  67.         cmds.parent(fkController, fkNull)
  68.         cmds.makeIdentity(fkController, apply=1)
  69.         cmds.orientConstraint(fkController, element, maintainOffset=0)
  70.         nullList.append(fkNull)
  71.         controllerList.append(fkController)
  72.     parentGroup = cmds.group(n="fkControllers_grp", empty=1)
  73.     cmds.parent(nullList[0], parentGroup)
  74.     cmds.parent(nullList[1], controllerList[0])
  75.     cmds.parent(nullList[2], controllerList[1])
  76.     lockHideAttr([parentGroup], 1, 1, 1, 1)
  77.     lockHideAttr(nullList, 1, 1, 1, 1)
  78.     lockHideAttr(controllerList, 1, 0, 1, 1)
  79.     return controllerList
  80.    
  81. #this function calculates and returns the appropriate position of the pole vector from a list of joints.
  82. #Credits to https://bindpose.com/seamless-ik-fk-switch-maya-python/ for this one
  83. def poleVectorLocation(array):
  84.     vector1=[cmds.xform(array[1], translation=1, worldSpace=1, query=1)[id] - cmds.xform(array[0], translation=1, worldSpace=1, query=1)[id] for id in range(3)]
  85.     vector2=[cmds.xform(array[1], translation=1, worldSpace=1, query=1)[id] - cmds.xform(array[2], translation=1, worldSpace=1, query=1)[id] for id in range(3)]
  86.     middlePos=[cmds.xform(array[1], translation=1, worldSpace=1, query=1)[id] for id in range(3)]
  87.     return [middlePos[id]+(vector1[id]*.75)+(vector2[id]*.75) for id in range(3)]
  88.  
  89. #this function creates IK controllers from a list of joints. The controller is returned.
  90. def makeIKCtrl(array, poleVector):
  91.     ikController = cmds.curve (n=str(array[2])+"_ctrl", d=1, p=[(.75, .75, .75), (.75, .75, -.75), (-.75, .75, -.75), (-.75, -.75, -.75), (.75, -.75, -.75), (.75, .75, -.75), (-.75, .75, -.75), (-.75, .75, .75), (.75, .75, .75), (.75, -.75, .75), (.75, -.75, -.75), (-.75, -.75, -.75), (-.75, -.75, .75), (.75, -.75, .75), (-.75, -.75, .75), (-.75, .75, .75)])
  92.     #this is the fastest way to make a cube of curves
  93.     cmds.delete(cmds.parentConstraint(array[2], ikController, maintainOffset=0))
  94.     ikNull = cmds.group(n=str(array[2])+"_null", empty=1)
  95.     cmds.delete(cmds.parentConstraint(array[2], ikNull, maintainOffset=0))
  96.     cmds.parent(ikController, ikNull)
  97.     cmds.makeIdentity(ikController, apply=1)
  98.     ikEffector = cmds.ikHandle(n=str(array[2])+"_handle", startJoint=array[0], endEffector=array[2])
  99.     ikHandle = str(array[2])+"_handle"
  100.     cmds.pointConstraint(ikController, ikHandle)
  101.     cmds.orientConstraint(ikController, array[2])
  102.     cmds.poleVectorConstraint(poleVector, ikHandle)
  103.     cmds.setAttr(str(ikHandle)+".visibility", 0)
  104.     lockHideAttr([ikNull], 1, 1, 1, 1)
  105.     lockHideAttr([ikController], 0, 0, 1, 1)
  106.     return ikController
  107.    
  108. #this function creates and returns a controller for switching between IK and FK controllers
  109. #a "reverse" shader node is used to set FK and IK influence, as well as their visibility, as opposite to eachother
  110. def makeSwitchCtrl(skinJoints, fkJoints, ikJoints, fkCtrls, ikCtrl, poleVector):
  111.     cmds.shadingNode("reverse", asUtility=1, name="invertValue")
  112.     switchCtrl = cmds.circle(n="switch_ctrl", sweep=360, normalX=90, radius=0.7)
  113.     cmds.delete(cmds.pointConstraint(str(skinJoints[2])+"_bind", switchCtrl, maintainOffset=0))
  114.     cmds.setAttr(str(switchCtrl[0])+".translateY", 2)
  115.     cmds.makeIdentity(switchCtrl, apply=1)
  116.     cmds.pointConstraint(str(skinJoints[2])+"_bind", switchCtrl, maintainOffset=1)
  117.     lockHideAttr([switchCtrl], 1, 1, 1, 1)
  118.     cmds.addAttr(switchCtrl, longName="fkIkSwitch", niceName="FK/IK", attributeType="bool", keyable=1, exists=1)
  119.     cmds.connectAttr(str(switchCtrl[0])+".fkIkSwitch", "invertValue.inputX")
  120.     for id in range(3):
  121.         cmds.orientConstraint(fkJoints[id], ikJoints[id], str(skinJoints[id])+"_bind")
  122.         cmds.connectAttr(str(switchCtrl[0])+".fkIkSwitch", str(skinJoints[id])+"_bind_orientConstraint1."+str(skinJoints[id])+"_FKW0")
  123.         cmds.connectAttr("invertValue.outputX", str(skinJoints[id])+"_bind_orientConstraint1."+str(skinJoints[id])+"_IKW1")
  124.     for ctrl in fkCtrls:
  125.         cmds.connectAttr(str(switchCtrl[0])+".fkIkSwitch", str(ctrl[0])+".visibility" )
  126.     cmds.connectAttr("invertValue.outputX", str(ikCtrl)+".visibility")
  127.     cmds.connectAttr("invertValue.outputX", "poleVector_ctrl.visibility")
  128.     return switchCtrl
  129.  
  130. #this function matches the IK and FK controllers to current pose, depending on the value of the switch controller
  131. #this function is called in real time from the viewport using a scriptjob
  132. def matchCtrls():
  133.     #this orients to FK controllers to the IK joints
  134.     if cmds.getAttr(str(switchCtrl[0])+".fkIkSwitch") == 1:
  135.         for id in range(len(fkControllers)):
  136.             if id != 2:
  137.                 cmds.delete(cmds.aimConstraint(ikJointList[id+1], fkControllers[id]))
  138.         cmds.delete(cmds.orientConstraint(ikController, fkControllers[2]))
  139.     #this places the IK controller at the wrist, and places the pole vector at the appropriate position from the FK joints
  140.     else:
  141.         cmds.delete(cmds.pointConstraint(fkJointList[2], ikController))
  142.         cmds.delete(cmds.orientConstraint(fkControllers[2], ikController))
  143.         newPositionLocator = cmds.spaceLocator(name="newPositionLocator", position = poleVectorLocation(fkJointList))
  144.         cmds.xform(newPositionLocator, centerPivots=1)
  145.         cmds.delete(cmds.pointConstraint(newPositionLocator, poleVectorCtrl))
  146.         cmds.delete(newPositionLocator)
  147.  
  148. #this calls the functions in the right order, using the selected object as the elbow joint.
  149. #A scriptjob is created to call the matchCtrls function when the switchCtrl changes values
  150. sl = cmds.ls(sl=1)
  151. if len(sl) ==1:
  152.     jointList = getRelatives(sl[0], 3)
  153.     fkJointList = duplicateList(jointList, "FK", 1)
  154.     ikJointList = duplicateList(jointList, "IK", 1)
  155.     renameList (jointList, "bind")
  156.     poleVectorCtrl = cmds.spaceLocator(name="poleVector_ctrl", position= poleVectorLocation(ikJointList))
  157.     cmds.xform(poleVectorCtrl, centerPivots=1)
  158.     lockHideAttr(poleVectorCtrl, 0, 1, 1, 1)
  159.     fkControllers = makeFKCtrls(fkJointList)
  160.     ikController = makeIKCtrl(ikJointList, poleVectorCtrl)
  161.     switchCtrl = makeSwitchCtrl(jointList, fkJointList, ikJointList, fkControllers, ikController, poleVectorCtrl)
  162.     cmds.scriptJob(attributeChange=[str(switchCtrl[0])+".fkIkSwitch", matchCtrls])
RAW Paste Data