Tuesday, July 03, 2012

IK to FK snapping

These videos are about how you might approach and execute IK to FK snapping. (For those that don't know or use different terminology, that's where you run a script and it snaps your IK limb position to your FK limb position). It's something that I had always looked at as a bit of luxury, something to get to if there was time when building a rig (hint: there rarely was time). As I mention in the video, Michael Cawood pointed out to me that it is actually a time saver when you're doing a lot of quick blocking. If you pose your characters in IK mode in blocking, you have a lot less counter animation to do when you change the body rotations, for example. You can pose away in IK, then switch to FK when it comes time to animate (if you need to switch, that is). As I was one of the lead animators on that job with Michael, not a rigger (thank god, there were 50+ characters for that one), I didn't bother to offer up my services:) But I thought it would be a good topic for a video tute, so here it is. . .
There are 3 parts. 1) covers the basic idea and some rudimentary vector math 2) covers the python scipting of those concepts in Maya and 3) introduces "message attributes" which are nifty little attrs that can be really useful to bump up functionality of your rigs/scripts.


Maya/Rigging: IK to FK snapping, part 1 from zeth willie on Vimeo.


Maya/Rigging: IK to FK snapping, part 2 from zeth willie on Vimeo.


Maya/Rigging: IK to FK snapping, part 3 from zeth willie on Vimeo.


Oh, yeah. Here is the code for the basic version of the IK/FK script in python (the script using the message attrs will depend on your specific attr names):
import maya.cmds as cmds
import maya.OpenMaya as om

#select the joints we need
sel = cmds.ls(sl=True)

#assign selection
fkWrist = sel[0]
fkShldr = sel[1]
fkElbow = sel[2]
ikWrist = sel[3]
ikPv = sel[4]

#get positions from fk
fkwRaw = cmds.xform(fkwrist, ws=True, q=True, t=True)
fkwPos = om.MVector(fkwRaw[0], fkwRaw[1], fkwRaw[2])

fkeRaw = cmds.xform(fkelbow, ws=True, q=True, t=True)
fkePos = om.MVector(fkeRaw[0], fkeRaw[1], fkeRaw[2])

fksRaw = cmds.xform(fkshldr, ws=True, q=True, t=True)
fksPos = om.MVector(fksRaw[0], fksRaw[1], fksRaw[2])

#set position of IK wrist ctrl
cmds.move(fkwPos.x, fkwPos.y, fkwPos.z, ikwrist)

#start figuring out pole vector pos

#find avg (midpoint) of shoulder and wrist
midpoint = (fkwPos + fksPos) / 2

#find pv direction
pvOrigin = fkePos - midpoint

#extend that length
pvRaw = pvOrigin * 2


#position pvRaw at midpoint
pvPos = pvRaw + midpoint

#stick pole vector at pvPos
cmds.move(pvPos.x, pvPos.y, pvPos.z, ikpv)
 

Once I get the little things hammered out in the zbw_messageMapper script that I showed in the video, I'll post that up too. . .

EDIT: One more thing! Here's the link to Ryan Trowbridge's site. http://www.rtrowbridge.com/blog/ Not sure how to access individual posts, but the post from March 09 has the video of the MasterClass on Vector Math in Maya. Good stuff. Also just bought his book on Python for Games and Film. Can't wait to read it!

20 comments:

  1. Great Stuff! :-)

    Can I vote for a SapceSwitching demo while I'm here?

    ReplyDelete
  2. Hi
    thanks for very good tutorial.
    can you comment or post for fstretch plugin and download??!
    I think very useful.
    thank you very much for special tutorial

    ReplyDelete
  3. @Craig:
    Consider your secret vote counted!

    @Saman:
    Haven't used it myself. Seen the video, looks a lot like Stretchmesh, a plug in Rob O'Neil(a TD I know) helped create. But as I said, don't know how it works.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. I can't seem to get the pole vector to snap.
    Do you have any suggestions for why this may occur?

    ReplyDelete
  6. hey zeth - i've been following your vids for about a year and have enjoyed them all - very helpful stuff. i recently tried setting up the switch system outlined here, but for the life of me can't get the elbow to line up. if you have a minute or two to help, i have scripted the whole process (arm setup with the msg attrs and then the code to switch). is there a way i can get these scripts to you for checking out my math?

    ReplyDelete
    Replies
    1. You can email it to me. . . I'll take a look when I get a sec.

      Delete
    2. hey zeth,
      thanks for the quick re:. i can't find your email address on this site, google+ or the vimeo site. could you IM or email your contact info. on gmail\gchat i am beautifulrobot.
      thx!

      Delete
    3. If this hasn't been resolved yet, I may have found the solution.
      Double check the name of the variable where we assigned it from the selection (line 12 - ikPv = sel[4] from the code Zeth posted for us) and make sure that exact name is being referenced in the line where it's supposed to be moved, line 43 of this code.

      If you straight up copy/pasted from this, there is a small error between those lines. the variable is called ikPv while the "object" to be moved is called ikpv. The missing capital letter is throwing this code off.

      Delete
  7. Thanks for the tutorials. All of them are awesome.

    ReplyDelete
  8. Hey Zeth ! How can I get transformations with rotations from IK-joints to set them FK-joints with python to make feedback for IK to FK switch ? and can I put this script to attribute in control to easy snaping in the animation process?

    ReplyDelete
    Replies
    1. Hey Daria-
      Yeah, I didnt' get into that too much, cuz a lot of it depends on how you set things up with the controls. But IK to FK is pretty easy assuming you have identical joints on the Fk/IK chains. Just get the rotation from the world space of the IK joints and apply them to the world space of the FK controls (cause the controls should match the joints).
      FK to IK can be harder because the ankle joint MAY not line up with the IK control (the IK control may be left at the default world space which won't correspond to the joint orientation). So the gist is to just get the difference between the zeroed out IK control and the zeroed out ankle joint. Does that make sense? So the IK control at zero rots will be in world space (in many setups). The FK (or IK) ankle joint will be at zero rotation, but might oriented differently (i.e. bent at 20 deg to create the foot angle). So you can get the rotation of that by using some matrix code from the api or, more conveniently, the "xform" command using the "ws" (worldspace) flag. Or you can get it manually by looking at the "joint Orient" box in the attr editor of the joint. Then you use that value to OFFSET the rotation of the IK control.
      So in the example I gave above, to orient the IK control to the FK ankle you'd subtract 20 deg from the correct axis when you use the "ws" flags in the "xform" command. The ankle at rot values (0,0,0) would yield (20, 0, 0) in the xform and the IK handle would yield (0,0,0). So to line then up you'd make sure to subtract (20, 0, 0) from whatever the FK gives you. Got it? It gets more complicated depending on the how you set up the joint orientations initially, so it'd be different for joints oriented in y than for joints oriented in x.
      I often make it easier for myself by figuring it out the rotation difference and then putting that on the IK control (or something else) as an extra hidden attribute. Then I can just tell controls to generically use the "orientOffset" attr or whatever when doing the conversion.
      That help at all?

      Delete
  9. hai zeth i tried your script in my ctrls but when i run the script i got this message
    # Error: line 1: NameError: file line 15: name 'fkwrist' is not defined #
    how can i solve it ,i will be very much thank full for your help

    ReplyDelete
    Replies
    1. I'm getting the same problem? any ideas out there please?

      Delete
  10. could use some feedback. The script works snapping ikwrist to fkwrist, but ik elbow doesnt move as in tutorial on 1st attempt at snapping wrist . almost like its locked in place . Then executing entire script ikwrist doesnt snap but ikPv moves . So in parts it seems to work but as a whole its not working correctly ...Any ideas

    ReplyDelete
  11. So instead of picking actual ikwrist joint I select ikhandle, which will be ikCtrl eventually and that worked in moving elbow . Now the ikPv is not snapping into place, its close but not an exact match . I noticed if i changed pvRaw = pvOrigin * 2 to a higher number it would get closer, but thats not the correct way either is it ?

    ReplyDelete
  12. also how difficult would it be to setup an ik/fk snap with a mechanical arm ?? consisting of 4 joints, 2 of those being elbow joints . For the most part your tutorial works great with 3 joints , but 4 i got lost and also had trouble matching ik to fk rotations .....any help would be appreciated . thanks so much

    ReplyDelete
  13. first off thanks,
    really clear explanation of what turned out to not be very difficult math.

    This works for me if my arm is on the origin.
    if its not i had to add the fk elbows position to the cooridinates in the move command.

    like this
    cmds.move(pv_pos.x + fk_elbow_pos.x, pv_pos.y + fk_elbow_pos.y, pv_pos.z + fk_elbow_pos.z, ik_pv)

    ReplyDelete
  14. There are errors in your script. All your variables are case sensitive and your script calls lower case letters, so all the people saying it cannot work, are correct.
    #assign selection

    #the below var
    #fkWrist = sel[0]
    #should be
    fkwrist = sel[0]

    So the below script will now work:

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

    #select the joints we need
    sel = cmds.ls(sl=True)

    #assign selection
    fkwrist = sel[0]
    fkshldr = sel[1]
    fkelbow = sel[2]
    ikwrist = sel[3]
    ikPv = sel[4]

    #get positions from fk
    fkwRaw = cmds.xform(fkwrist, ws=True, q=True, t=True)
    fkwPos = om.MVector(fkwRaw[0], fkwRaw[1], fkwRaw[2])

    fkeRaw = cmds.xform(fkelbow, ws=True, q=True, t=True)
    fkePos = om.MVector(fkeRaw[0], fkeRaw[1], fkeRaw[2])

    fksRaw = cmds.xform(fkshldr, ws=True, q=True, t=True)
    fksPos = om.MVector(fksRaw[0], fksRaw[1], fksRaw[2])

    #set position of IK wrist ctrl
    cmds.move(fkwPos.x, fkwPos.y, fkwPos.z, ikwrist)

    #start figuring out pole vector pos

    #find avg (midpoint) of shoulder and wrist
    midpoint = (fkwPos + fksPos) / 2

    #find pv direction
    pvOrigin = fkePos - midpoint

    #extend that length
    pvRaw = pvOrigin * 2


    #position pvRaw at midpoint
    pvPos = pvRaw + midpoint

    #stick pole vector at pvPos
    cmds.move(pvPos.x, pvPos.y, pvPos.z, ikpv)

    ReplyDelete
  15. Hi Zeth and all,
    Ryan trowbridges class is now here.
    https://area.autodesk.com/learning/class3_q1_2012/

    ReplyDelete