No tags yet.
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!!
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.
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.
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.
Here is the properly spaced script on my site.
http://joshgaines3d.com/downloads/
WAW!! I didn't see all the conversion till now!! thank you SO MUCH for the explanation!! I am trying this right away.
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.
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.
You must log in to post.