Maya IK/FK Switch


#1

Just a simple question… is the 3 joint chain method (IK/FK/Bind) that is so often used in rigs even relevant anymore with Maya’s inherent IK switch? What are the reasons to continue using the 3 joint chain?


#2

I never thought the three chain method was very elegant. The only advantage I can think of is te ability to see both modes simultaneously and blend between them, but I have never known animators to actually do that. Most every animator uses a two frame seamless switch


#3

Yeah I’ve been wondering the same thing for ages… My only thoughts are that when you constrain the IK handle ( typical for a custom controller ) it basically breaks the capabilities of Maya’s inbuilt IK/FK switching system… Also if you use a pole constraint you have to snap the controllers position when you switch from FK back to IK…

I have implemented a pretty good example of using it however here… I’m parenting shapes under the IK Handle and the FK Joints as an alternative to constraints… I’m still working out some of the kinks but it works.

[video]http://www.jamietelford.com/tutorials/2015-08-24_00-36-45.mp4[/video]

Here’s my script for the switching

__author__ = 'Jamie Telford'

import maya.api.OpenMaya as om
import maya.cmds as cmds

from PySide import QtGui
from PySide import QtCore
import maya.OpenMayaUI as omui
from shiboken import wrapInstance

import maya.mel as mel

source = 'polar_helper'
polar = 'r_Polar_CTRL'

mel_command = ['ikFK(0, `ls -sl`);', '', 'SetIKFKKeyframe;',
               'NextFrame;', 'ikFK(0, `ls -sl`);', '', 'SetIKFKKeyframe;']


def main_window():
    win_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(long(win_ptr), QtGui.QWidget)

def get_polar_position(handle):
    joints = cmds.ikHandle(handle, jl=True, q=True)
    joints.append(cmds.listRelatives(joints[-1], c=1)[0])

    first = cmds.xform(joints[0], q=1, ws=1, t=1)
    second = cmds.xform(joints[1], q=1, ws=1, t=1)
    last = cmds.xform(joints[2], q=1, ws=1, t=1)

    first_vec = om.MVector(first)
    second_vec = om.MVector(second)
    last_vec = om.MVector(last)

    first_last = last_vec - first_vec
    first_second = second_vec - first_vec

    dot = first_second * first_last
    cast = float(dot)/float(first_last.length())
    first_last_normal = first_last.normal()
    cast_vec = first_last_normal * cast

    point = (first_second - cast_vec) *3
    pole_pos = point + second_vec
    pole_offset = om.MVector(cmds.xform(polar, q=1, rp=1))
    return(pole_pos-pole_offset)

class MyWindow(QtGui.QDockWidget):
    def __init__(self, parent=main_window()):
        super(MyWindow, self).__init__(parent)

        self.setWindowTitle('Switch IK/FK')
        self.setFloating(True)
        self.setAllowedAreas(QtCore.Qt.RightDockWidgetArea  )

        self.create_layout()

    def create_layout(self):
        layout = QtGui.QVBoxLayout()
        h_layout = QtGui.QHBoxLayout()

        layout.addLayout(h_layout)

        widget = QtGui.QWidget()
        widget.setLayout(layout)
        widget.setMinimumWidth(250)

        self.setWidget(widget)

        self.ikfk_button = QtGui.QToolButton()
        self.ikfk_button.setIcon(QtGui.QIcon(':/menuIconKeys.png'))
        self.ikfk_button.setIconSize(QtCore.QSize(50, 50))
        self.ikfk_button.clicked.connect(self.switch_ikfk)

        layout.addWidget(self.ikfk_button)

    def switch_ikfk(self):
        # testing for multiple IK handles.. eventually to test against connected
        selected = cmds.ls(sl=True)
        ik_handles = cmds.ls(et='ikHandle')
        for handle in ik_handles:
            if cmds.getAttr('{}.ikBlend'.format(handle)):
                cmds.setKeyframe(polar)
                mel_command[1] = 'setAttr "{}.ikBlend" 1;'.format(handle)
                mel_command[5] = 'setAttr "{}.ikBlend" 0;'.format(handle)
                mel.eval(''.join(mel_command))
                cmds.setKeyframe(polar)
            else:
                cmds.select(polar)
                cmds.setKeyframe(polar)
                cmds.xform(polar, t=get_polar_position(handle))
                mel_command[1] = 'setAttr "{}.ikBlend" 0;'.format(handle)
                mel_command[5] = 'setAttr "{}.ikBlend" 1;'.format(handle)
                mel.eval(''.join(mel_command))
                cmds.setKeyframe(polar)
                cmds.select(selected)



try:
    ui.close()
except:
    pass

ui = MyWindow()
ui.show()





#4

Quick update on this one… Got a pretty good FK/IK switch working… suffering from what appears to be a drift on the solver rotate plane for the polar constrain… Still thinking about a way to get a satisfactory unification of the IK handle translation and the wrist rotation etc…

//youtu.be/4B5ZFArN4zA


#5

Hey

I didn’t want to create another thread for this…

can anyone elaborate please? what is the real advantage of multi-chain ik/fk rig? is there a reason to rig this way?

thank you!


#6

I think if you build the rig automatically with script,

3-chain setup enable you to optionally add IK, FK functions with script, so more like a modular way of think in rig building