Home
Shockwave
Lingo
    IK tutorial
    Lingo2HTML
    olesm
    ScriptExtractor
Design
About me
Archive
Elsewhere


Comments

2007-08-13




2006-11-16



Marty Plumbo
2004-03-02

Excellent tutorial!

As a follow-up, maybe you could rewrite the code from Lingo to DMX2's new Director-JavaScript?

Or, maybe you could serve us up a Shockwave3D IK example next?

Again, great tutorial - clear, conside, and very applicable!





 Inverse kinematics - Tutorial
Prolog This is my first tutorial. I hope it will be worth your time. This tutorial will only show you the basics of a 2 limbs solution. It will not handle angle-restrictions, dampening or any such features. It will not describe vectormath but you will find a trigonometry lib in the source. Basicly it will only give you the math and sourcecode for calculating the angles of a triangle.

Demo can be viewed here (opens in a new window)

Sourcecode:
  InverseKinematics.zip 197kb
  InverseKinematics.sitx 189kb

Printable version.


Basics As you can see in figure 1 the whole thing is about finding out the angles of a triangle with known lengths. The structure of the bones and ik objects can be found in the source, that is not what I will describe here. Almost all angles in the code are radians but in here they well be degrees for better understanding.


Figure 1


Get your hands dirty Here is the function that returns the radian angle x of the far side of a triangle with known lengths. The triangle does not need to be a "right triangle". The first argument c is the length of the far side of the corner you want to calculate. You can ignore the order of a and b.
-- The code is cut from trigmath v0.6 parentscript.
on GetFarAngle (me,c,a,b)
  --
  --   |\
  --   |x\
  -- a |  \ b
  --   |___\
  --     c
  --  
  --  x = a*a + b*b - c*c
  --  x = x / float(2*a*b)
  --  x = me.InvCos(x)  
  --  
  --  return x
  
  if a*b = 0 then return 0
  
  return me.InvCos((a*a+b*b-c*c)/float(2*a*b))
end

on InvCos me, X  
  y = Sqrt(-X * X + 1)
  if y = 0 then return 0--y --NAN
  return atan(-X / y) + 2 * pAtan1
end

Let's calculate the angles of our triangle from figure 1
put gTrig.GetFarAngle( 185, 225 ,104 )
-- 0.9502
put gTrig.RadToDegree(0.9502)
-- 54.4424

put gTrig.GetFarAngle( 225, 104 ,185 )
-- 1.7164
put gTrig.RadToDegree(1.7164)
-- 98.3425
Ok, so we got an 55°∠ for the first bone and 98°∠ for the second. If we try to assign those values to the bone, it will behave strangely. We need to offset the angle from the goalangle. The goalangle is the angle between the goal and the first bone's startposition. The goal is pTarget here.
a = pTarget.GetLoc()
b = pBoneChain[1].GetLoc()
vGoalVector = a-b
vGoalAngle  = gTrig.VectorToAngle(vGoalVector)
vGoalLength = gTrig.Magnitude2d(vGoalVector)
There is one thing to have in mind with the trigmath code. 0°∠ is to the right and 90°∠ is down. But sprites.rotation in director 0°∠ is up. So we will have to compensate for that -90°. This compensation should really belong in the drawing routine, but now it ain't. In this case the goalangle is about 35°∠ (starting from right 0°∠)
--First bone
-- vGoalAngle - vCorner1Angle + 90
put +35 - 55 + 90
-- 70
That seems to be correct according to figure 1 with 0°∠ up. Next bone is simple, use the angle from the first bone and add the second corner angle
--Second bone
-- vBone[1].GetTheta() + vCorner1Angle
put 70 + 76
--146
So far so good, in the source this part will be slight messed up by the fact that I have the bone gfx upside down. I know it's kinda stupid. So do better than me.

Now, if you've coded your way here, you'll have a working leg. You should now notice that the leg is bent in one direction only. This is easily fixed, I use a pDirection property in the IK object. It can be -1 or 1, use it to flip the cornerangle before calculating the final boneangle. You will need to flipH the sprite aswell.
--First bone
-- vGoalAngle - vCorner1Angle*pDirection + 90
put +35 - (55*-1 ) + 90
-- 180
--Second bone
-- vBone[1].GetTheta() + vCorner2Angle
put 180 + (76*-1)
--104

Early out First of all you should check that the "leg" can reach the target, if not, point the leg towards the target as in figure 2. There is one case when this code breaks. Try moving the target so close to the leg's startingpoint that it can't reach it, the leg flippes. I havn't tried to fix this yet.


Figure 2

That's all folks Seems like that covers the basics, so start coding your own spider or some other beast and show me the results.

/Christoffer Enedahl
www.enedahl.com