Skip to main content

create_fk_ik_chain_switch

Already made something like this years ago for my mock auto rigging. Making this one again for a manual rigging tasks on custom game model

import maya.cmds as cmds
import pymel.core as pm

def create_joint_chain():
# Create the main joint chain
joints = []
joint_names = ["shoulder_jnt", "elbow_jnt", "hand_jnt"]
positions = [(0, 10, 0), (1, 5, 0), (0, 0, 0)]

for name, pos in zip(joint_names, positions):
jnt = pm.joint(name=name, position=pos)
joints.append(jnt)

pm.select(clear=True)
return joints

def duplicate_joint_chain(joint_chain, prefix):

new_joint_chain = pm.duplicate(joint_chain)

for joint in new_joint_chain:
new_name = prefix + joint.nodeName().split("1")[0]
pm.rename(joint, new_name)

return new_joint_chain

def setup_ik_fk_switch(main_chain, fk_chain, ik_chain):
# Create IK Handle for the IK chain
ik_handle, effector = pm.ikHandle(startJoint=ik_chain[0], endEffector=ik_chain[-1], solver="ikRPsolver", name="arm_ikHandle")
effector.rename(ik_chain[-1] + "_eff")

# Create a control for the IK handle
ik_control = pm.circle(name="ik_ctrl", normal=[0, 1, 0])[0]
pm.delete(pm.parentConstraint(ik_chain[-1], ik_control))
pm.parent(ik_handle, ik_control)

# Create FK controls
fk_controls = []
for fk_jnt in fk_chain:
fk_ctrl = pm.circle(name=fk_jnt.name().replace("_jnt", "_ctrl"), normal=[0, 1, 0])[0]
pm.delete(pm.parentConstraint(fk_jnt, fk_ctrl))
pm.parentConstraint(fk_ctrl, fk_jnt, maintainOffset=True)
fk_controls.append(fk_ctrl)

pm.parent(fk_controls[2], fk_controls[1])
pm.parent(fk_controls[1], fk_controls[0])

# Create IK/FK switch attribute
switch_ctrl = pm.circle(name="ik_fk_switch_ctrl", normal=[0, 1, 0])[0]
switch_ctrl.addAttr("IK_FK_Switch", attributeType="float", minValue=0, maxValue=1, defaultValue=0, keyable=True)

# Constrain the main joints to the FK and IK joints
for main_jnt, fk_jnt, ik_jnt in zip(main_chain, fk_chain, ik_chain):
orient_constr = pm.orientConstraint(fk_jnt, ik_jnt, main_jnt)
pm.connectAttr(switch_ctrl.IK_FK_Switch, orient_constr.attr(ik_jnt.nodeName() + "W1"))
rev_node = pm.createNode("reverse", name=main_jnt.nodeName() + "_ikFkRev")
pm.connectAttr(switch_ctrl.IK_FK_Switch, rev_node + ".inputX")
pm.connectAttr(rev_node + ".outputX", orient_constr.attr(fk_jnt.nodeName() + "W0"))




# # Organize in groups
# pm.group(main_chain[0], name="main_joints_grp")
# pm.group(fk_controls, name="fk_controls_grp")
# pm.group(ik_control, ik_chain[0], name="ik_controls_grp")
# pm.group(switch_ctrl, name="ik_fk_switch_grp")

if __name__ == "__main__":
main_joints = create_joint_chain()
fk_joints = duplicate_joint_chain(main_joints, "FK_")
#print (fk_joints[0].name())
ik_joints = duplicate_joint_chain(main_joints, "IK_")
#print (ik_joints[0].name())
setup_ik_fk_switch(main_joints, fk_joints, ik_joints)