View Full Version : FK to IK...calculating the IK twist?

 MSmith01 January 2011, 02:39 AMHey guys, I'm still on the new side of figuring all this character setup stuff out...but I think I'm pretty close to being on my way. I just wanted to run this by people and see if there's a better more efficient way to go about it. Snapping FK to IK bones seems rather straightforward and easy. The problem is going the other way...from FK to IK bones. So when snapping back from FK bones to IK bones I wasn't sure if there was an easy (Maxscript) way to figure out the IK twist value if you're not using Pole Vectors (IK Solver Plane Targets) to control the twisting of a leg in an animation. This is the setup I'm currently thinking about using... I created an IK chain an used the twist to rotate it 45 degrees. Point01 has a lookat (aim) constraint with Bone01 as the upnode. Point02 has a lookat (aim) constraint with Bone03 as the upnode. http://www.themichaelsmith.com/TwistCalculation.jpg As you can see Point02 has the same x rotation value as the twist. A couple issues I have with this method.... I'm curious if there's any way to calculate the twist value without the addition of the two lookat (aim) constrained nodes by some cool vector math (magic) solution based on the bone positions or something. Basically I looking for a "cleaner" way so I don't have more point helpers than I need lying around. I can't seem to get the gimbal coordsys x rotation value of the lookat (aim) constrained rotation of the Point02 node. It shows up in "Rotate Transform Type-In" window but I can't find it via MaxScript. I can add yet another point helper parented to Point01 with a regular Euler controller and align it to Point02 to get the x rotation value....but it seems like I shouldn't have to do that. Any suggestions?
Duncs
01 January 2011, 09:33 AM
Hey Michael,

Apologies if I'm not understanding the problem fully but do you actually need to know the twist value? When snapping from FK to IK I normally just do:

fkUpArmBone.transform = ikUpArmBone.transform
fkLowArmBone.transform = ikLowArmBone.transform

Good luck

Duncs

MSmith
02 February 2011, 08:35 PM
Hey Duncs!

Thanks for the reply man. Yeah, you are right. Going from IK to FK is easy and rather straightforward. Unfortunately I got the title of this thread exactly backwards. The title SHOULD be FK to IK...calculating the twist.

So you pose with the FK bones and then match the IK bones to the pose, without using an IKTarget (Pole Vector).

MSmith
02 February 2011, 08:40 PM
K...I figured this out a while ago and haven't gotten around to posting it till now. I still think there's GOT to be cleaner way to figure out if your twist value is positive of negative depending on where the end bone is relevant to the start bone. So let me know if you have suggestions.

All you have to do to get this script to work is create a 4 bone chain like I had in the picture. Then make a copy of it....so you have two bone chains (8 bones all together), like an FK/IK bone blend setup. Create an IK chain between Bone02 and Bone 04. That'll be the IK bone chain. The script uses the default name of the bones and IK chain.

Rotate the FK bones around, then use this script to align the IK chain bones to the FK bones.... Make sure you only rotate Bone03 (the "knee" or "elbow" bone) on the one axis

/*
Geometrical calculations : points, lines, planes : intersections, distances, angles

Point-Line Distance : the distance between the line AB and the point C:
fn pointLineDist2 pA pB pC = (
local vAB=pB-pA
local vAC=pC-pA
(length (cross vAB vAC))/(length vAB)
)

and

Point-Line Projection : find the point on the line AB which is the projection of the point C:
fn pointLineProj pA pB pC = (
local vAB=pB-pA
local vAC=pC-pA
local d=dot (normalize vAB) (normalize vAC)
(pA+(vAB*(d*(length vAC/length vAB))))
)
*/

fn pointLineDist2 IKStart IKEnd IKBend =
(
local vAB=IKStart-IKEnd
local vAC=IKBend-IKEnd
(length (cross vAB vAC))/(length vAB)

)

fn pointLineProj IKStart IKEnd IKBend =
(
local vAB=IKEnd-IKStart
local vAC=IKBend-IKStart
local d=dot (normalize vAB) (normalize vAC)
(IKStart+(vAB*(d*(length vAC/length vAB))))
)

--match the IK Goal position with the FK end bone and set the IK Twist to 0
\$'IK Chain01'.pos = \$Bone08.pos
\$'IK Chain01'.transform.controller.swivelAngle = 0

--You now have a triangle between the two different knee positions and a point on the line that runs through
--the start and end bones of both the bone systems. You can define the lengths of all three sides of that
--triangle with the pointLineDist2 function. ( I think the lengths of both the IK and FK bend bones will
--always be equal)

--Define the triangle side lengths of all three sides using the function
IKDist = pointLineDist2 \$Bone02.pos \$Bone04.pos \$Bone03.pos
FKDist = pointLineDist2 \$Bone06.pos \$Bone08.pos \$Bone07.pos
--Define the length of the side opposite the angle I need for the twist
--i.e. the distance between the two bend bones
B2BDist = distance \$Bone07.pos \$Bone03.pos

--Know that I know the lengths of all three sides I can use the "Cosine Rule" to calculate the twist angle
TwistValue = acos(-(B2BDist^2 - FKDist^2 - IKDist^2)/(2*FKDist*IKDist))

--But the twist value from this method is always positive. Depending on which quadrant the end of the chain is
--relevant to the start bone of the chain. Sometimes the twist will be a negative value.
--I used the following vector math to figure this out....If there's a "cleaner" way to do it let me know.

PointA = pointLineProj \$Bone02.pos \$Bone04.pos \$Bone03.pos
theVector1 = \$Bone03.pos - PointA
theVector2 =PointA - \$Bone07.pos
PosOrNeg = cross theVector1 theVector2

PosOrNeg2 = \$Bone06.pos - \$Bone08.pos
j = PosOrNeg[3]*PosOrNeg2[3]

if j >0 then \$'IK Chain01'.transform.controller.swivelAngle = TwistValue
if j < 0 then \$'IK Chain01'.transform.controller.swivelAngle = -TwistValue

VIOLA...no extra point helpers, Pole Vectors or anything needed....just a FK and an IK bone chain and the twist angle is calculated for the IK bone chain so that it matches the FK pose.

Special thanks to the stick thread I found here on CGTalk