Rigging

Rigging101 » Rigging128

non flipping switch IK-FK (8 posts)

About This Topic

Tags

No tags yet.

  1. pataz

    offline
    Member
    Posted 5 years ago
    #

    Hi everyone

    I am knowing now how to do a simple switch IK-FK, but is there a well known technic for doing the switch maintaining the arms position? What are the principles? is it coded? do you have several chains of joints or just one? I just don't know how to start, and I am looking for a hint, and good references. Thank you!!

  2. jgaines

    offline
    Member
    Posted 5 years ago
    #

    Hi Pataz,

    To match IK with pole vector control elbow to FK and vice versa, you should duplicate your FK controls and parent them under the IK joints (except for the FK wrist control. It should be parented under the IK wrist control). Then duplicate your IK wrist control and parent under the FK wrist control. The reason why you do this is because usually your FK controls may have a different rotation order then what your IK controls have.

    So now that you have this done, here is the next step. For this scenario, let's say you want to match IK controls to your current FK controls positioning. Your IK wrist has been duplicated and parented under your FK wrist control. So this is what you do in your script editor under a python tab:

    import maya.cmds as cmds

    #IK_to_FK

    cmds.parentConstraint('wrist_dup_IK', 'wrist_IK_Ctrl', n='wristMatch_parentConstraint')
    cmds.delete('wristMatch_parentConstraint')
    cmds.pointConstraint('elbow_FK_Ctrl', 'elbow_IK_Ctrl', n='elbowMatch_parentConstraint')
    cmds.delete('elbowMatch_parentConstraint')

    If you wanted to match FK controls to your IK positioning, do the following:

    #FK_to_IK
    cmds.orientConstraint('shldr_dup_FK', 'shldr_FK_Ctrl', n='shldrMatch_orientConstraint')
    cmds.delete('shldrMatch_orientConstraint')
    cmds.orientConstraint('elbow_dup_FK', 'elbow_FK_Ctrl', n='elbowMatch_orientConstraint')
    cmds.delete('elbowMatch_orientConstraint')
    cmds.orientConstraint('wrist_dup_FK', 'wrist_FK_Ctrl', n='wristMatch_orientConstraint')
    cmds.delete('wristMatch_orientConstraint')

    Note: Your control names need to match what the names are of the controls in the constraint commands.

    If you want to match an elbow that is no-flip, you have to script some math. If you would like to know, tell me and I'll do my best to explain. Just duplicate this same process for legs.

  3. erinfdean

    offline
    Member
    Posted 5 years ago
    #

    I just popped in on this thread, and I want to say... @jgaines, thanks for explaining it like that! Made a lot of sense! If you have time in the next little while, could you explain the elbow part? I can't speak for @pataz, but I know I'd really like to know how to approach that part, too, and would appreciate you taking the time to explain it!

    Thanks
    E.

  4. jgaines

    offline
    Member
    Posted 5 years ago
    #

    Hi erinfdean,

    Sorry for the relate response. But here is the answer for matching a no-flip elbow/knee.

    To solve the elbow position with a no flip elbow/knee, you have to do a guess and
    check process. First, what is a no flip elbow/knee? A no flip elbow/knee uses a
    rotation plane (RP) IK system on a joint chain consisting of 3 joints
    (shldr, elbow, wrist, or hip, knee, ankle). Next, you will need to create a locator
    and do a polevector constraint by selecting the locator then toggle the IK handle.
    Now vert snap that locator to the shldr joint, if on an arm, or gridsnap, about
    10 units in front of the foot, if on a knee. Parent the locator under the shldr joint
    for no flip elbow and under your foot_Ik_Ctrl for no flip knee. From here out, the
    example I'm sticking with is a no flip elbow. Copy this process for a no flip knee.

    On the IK handle, one of the attributes (attr) is called "twist". On your wrist_Ik_Ctrl,
    you will need a custom float attr called "elbow_twist". Connect this attr to the "twist"
    attr of the IK handle. Now when you change the value of the elbow_twist, your RP IK
    should rotate the elbow.

    Now let's dissect what we want to do. So we have our FK arm in a pose and would like
    to match our IK arm with no flip elbow to our FK arm pose. Well if I match it using
    the method I described above in my previous post, your wrist_Ik_Ctrl will go to the
    correct position. However, the elbow will not align now. What do we know about
    an IK of type RP? If you click on the IK handle, you will see that by the shldr joint,
    there will appear a circle with a white triangle pointing to a position on the
    circle. So IK RP rotates around a circle, which is 360 degrees. Now we are getting
    somewhere. This next part is tricky to understand and I will explain as best as I can.

    Basically, we want to find the distance between the elbow_Fk_Ctrl and the elbow_Ik_Jnt.
    The elbow_Fk_Ctrl will not move, but we will change the value on the
    wrist_Ik_Ctrl.elbow_twist to move our elbow_Ik_Jnt closer to its elbow_Fk_Ctrl target.

    ---Questions---
    1) "How do we find the distance and use that information to update our elbow_twist?"
    2) "Then, how do we know how many times to do this process before it aligns properly?"

    Good Questions!

    Answer to Q 1) You need to think what are the minimum and maximum distances that your
    elbow can travel. Well, remember that circle on our RP IK? Ans: min = 0, max = 360.
    Now we have rotation distance range. But what about the distance between the
    elbow_Fk_Ctrl position and the elbow_Ik_Jnt position? After all, that distance is
    what will tell us if we have matched the Ik_Jnt to the Fk_Ctrl. In order to find this
    out, we have to use a geometrical math term (maybe pre calculus) called "magnitude".
    See here for a more detailed explanation:
    http://www.icoachmath.com/math_dictionary/Magnitude_of_a_Vector.html

    Above, I said we are looking for the distance between the elbow_Fk_Ctrl.position
    and the elbow_Ik_Ctrl.position. Well "position" consists of an (X, Y, Z) or
    vector value. Mangnitude = sqrt(X**2 + Y**2 + Z**2). In our case, we need to find the
    magnitude of the difference between the elbow_Fk_Ctrl vector and elbow_Ik_Jnt vector.

    So to combine everything together...
    The wrist_Ik_Ctrl.elbow_twist will be set to our min value
    Run mag math to give us minDist length.

    The wrist_Ik_Ctrl.elbow_twist will be set to our max value
    Run mag math to give us maxDist length.

    Now we have the minDist and maxDist our elbow_twist can travel.

    ----
    NOTE: In MEL, mag is magnitude. In Python, there is not a command that directly does this.
    However, in the python script I made below, I show you the individual steps that give the
    same answer as MEL's mag, but in Python. If you want to do further research on having a
    command for python, you will need to download and install NumPy. Get it here:

    http://new.scipy.org/download.html

    I'm still not sure if it has a one command solution either.
    If you're real good with Python, you can create your own class.
    ----

    Let's re-phrase Q 2:
    2) Is minDist or maxDist closer to positioning the elbow_Ik_Jnt to the elbow_Fk_Ctrl?

    Ans to Q 2) In order to figure this out, you need to get an average of the data.

    avg = ((max - min)/2 + min)

    This takes our distance of 360 and starts dividing by half each time to get closer to
    where the elbow_twist is matching (eg. 360, 180, 90, 45, 22.5, etc.).

    Now we need to update the min or max value based on if the minDist is less, greater,
    or equal to the maxDist.

    if (minDist > maxDist):
    min = avg
    elif (minDist < maxDist):
    max = avg
    else: #min == max
    min = min + .00001

    The reason why we add .00001 to min if equal to max is because, if we didn't, the
    calculation will get hung up. So we add a very, very, very small amount for the
    calcuation to progress.

    All of this is thrown into a loop and you have it do this calculation
    somewhere between 25-50 times.

    At the end, the wrist_Ik_Ctrl.elbow_twist will be set with the value that matches to
    your elbow_Fk_Ctrl position. However, if the final amount is greater than + 180 or less
    than -180, we need to do a "clean up values" to make sure the final elbow_twist value
    resides between -180 and +180.

    elbowTwist = getAttr('wrist_Ik_Ctrl.elbow_twist')
    if (elbowTwist > 180):
    setAttr('wrist_Ik_Ctrl.elbow_twist', elbowTwist - 360)
    elif (elbowTwist < -180):
    setAttr('wrist_Ik_Ctrl.elbow_twist', elbowTwist + 360)

    Here is the code:
    --------------------------------------------------------------------------------
    import maya.cmds as cmds
    import math

    #--- No-Flip PV ---
    min = 0
    max = 360
    fkPos = cmds.xform('L_elbow_FKCTRL', q=True, ws=True, rp=True)

    for i in xrange(0, 50, 1):
    #Set min and max on elbow_twist to find correct value:
    cmds.setAttr('L_wrist_IKCTRL.elbow_twist', min)
    ikPos = cmds.xform('L_elbow_IKJNT', q=True, ws=True, rp=True)

    ikVecX = ikPos[0]
    ikVecY = ikPos[1]
    ikVecZ = ikPos[2]

    fkVecX = fkPos[0]
    fkVecY = fkPos[1]
    fkVecZ = fkPos[2]

    vecX = ikVecX - fkVecX
    vecY = ikVecY - fkVecY
    vecZ = ikVecZ - fkVecZ

    minDist = math.sqrt(vecX**2 + vecY**2 + vecZ**2)
    print minDist

    cmds.setAttr('L_wrist_IKCTRL.elbow_twist', max)
    ikPos = cmds.xform('L_elbow_IKJNT', q=True, ws=True, rp=True)

    ikVecX = ikPos[0]
    ikVecY = ikPos[1]
    ikVecZ = ikPos[2]

    fkVecX = fkPos[0]
    fkVecY = fkPos[1]
    fkVecZ = fkPos[2]

    vecX = ikVecX - fkVecX
    vecY = ikVecY - fkVecY
    vecZ = ikVecZ - fkVecZ

    maxDist = math.sqrt(vecX**2 + vecY**2 + vecZ**2)
    print maxDist

    avg = ((max - min)/2 + min)
    print avg

    if (minDist > maxDist):
    min = avg
    elif (minDist < maxDist):
    max = avg
    else: #min == max
    min = min + .00001

    #Check elbow_twist value:
    twistVal = cmds.getAttr('L_wrist_IKCTRL.elbow_twist')

    if (twistVal > 180):
    cmds.setAttr('L_wrist_IKCTRL.elbow_twist', twistVal - 360)

    elif (twistVal < -180):
    cmds.setAttr('L_wrist_IKCTRL.elbow_twist', twistVal + 360)

    ------

    Spacing note - Everything under the for loop until "#Check elbow_twist value", needs to be indented. I will try to post it up on my website with the proper spacing. I'll add my website link here as soon as I do.

  5. jgaines

    offline
    Member
    Posted 5 years ago
    #

    Here is the properly spaced script on my site.
    http://joshgaines3d.com/downloads/

  6. pataz

    offline
    Member
    Posted 5 years ago
    #

    WAW!! I didn't see all the conversion till now!! thank you SO MUCH for the explanation!! I am trying this right away.

  7. pataz

    offline
    Member
    Posted 5 years ago
    #

    Can't say thank you enough, jgaines, for taking that time to explain us your method and sharing your script. It is very understandable and has helped me a LOT. Thank you again.

  8. erinfdean

    offline
    Member
    Posted 4 years ago
    #

    jgaines, thanks so much for this information. I apologise for not getting back to you sooner, but the forum sort of slipped my mind as other projects and things got crazier. Your explanation was a big help and I'm going to try this as soon as I have some free time to myself!

    Thanks again!
    E.

Reply

You must log in to post.

Rigging101 » Rigging128
1,099 posts in 307 topics over 103 months by 188 of 8,226 members. Latest: fashionpvp, d2q4p5z2j, gasheldonl