Tuesday, January 12, 2016

Taking on Inverse Kinematics

In my previous post, I said I was not going to need Inverse Kinematics since the poses I would be working with were static and simple, like drawing frames of a 2D game.

I couldn't be so wrong.

Granted, I probably (hopefully?) won't need IK for playing animations at runtime, but creating poses for an animation that needs grounded foot, for example, proved to be a true exercise to patience. Moving the hip box, or the character pivot, would change the feet position. Getting that foot back to the former position was quite time-consuming. With the hundreds, probably thousands, of poses I will need to work on, I cannot allow such a basic feature to be difficult to do.

Before I lay out my plans to tackle on this issue, first off a little explanation about how the current system is designed.

The Character() class is nothing but a hierarchy of cubes, starting from the Hip, mimicking a human skeleton. The tree goes as follows:
  • Hip
    • Abdomen
      • Chest
        • Left Shoulder
          • Left Upper Arm
            • Left Lower Arm
              • Left Hand
        • Right Shoulder
          • Right Arm
            • Right Lower Arm
              • Right Hand
        • Neck
          • Head
    • Left Upper Leg
      • Left Lower Leg
        • Left Foot
    • Right Upper Leg
      • Right Lower Leg
        • Right Foot
Once I rotate one of the cubes above, every child will follow suit. Rotating and moving the Hip box will, obviously, move everything along. For basic moves, like throwing a punch, the first frame would be a wind-up, a preparation, that does minor movement on the Hip. 

Moving the Hip will obviously move the Feet -- and here lies the problem.

To avoid a "feet slide" effect, I have to adjust the Feet back into the previous frame position by rotating every Leg segment (upper and lower leg, three axes each) until its foot is back in place. This is just... not nice to do. It's annoying. I bet it's a nightmare for animators. 

No wonder Inverse Kinematics is a thing.

A while ago, I came across this paper that explained in good detail how Inverse Kinematics work. The following image was quite inspiring:


Emphasis on "Limbs with variable length."
So I started having ideas, and the following sketch came out:


The green diamond represents the Hip box. In the current implementation, if I move it, it's like I'm dragging the whole character around. Same happens if I rotate it.

The yellow lines represent the "bones" as they are. They follow the parenting scheme shown earlier. They don't stretch: they just rotate around their pivot points.

The blue lines are new limbs, "stretchy" limbs. They also rotate.

To achieve the IK effect I need, I am going to allow both feet and hands to be "frozen" in space. This is represented by the orange circle in the picture above, where I chose to freeze ("ground") the Right Foot. Once a part is grounded/frozen, moving the Hip will keep the Right Foot in its place, while everything else will follow the parent as normal.

For that, I will have to change the Bone Tree to the following:
  • Hip
    • Abdomen
      • Chest
        • Left Stretchy Arm
          • Left Upper Arm
            • Left Lower Arm
          • Left Hand
        • Right Stretchy Arm
          • Right Upper Arm
            • Right Lower Arm
          • Right Hand
        • Neck
          • Head
    • Left Stretchy Leg
      • Left Upper Leg
        • Left Lower Leg
      • Left Foot
    • Right Stretchy Leg
      • Right Upper Leg
        • Right Lower Leg
      • Right Foot
The above Tree may look "wonky" as there are some loose ends. Namely, the lower arms and legs. They no longer have hands and feet as children.

Without proper coding, the above tree would allow a pose where the hands/feet would be disconnected from their limbs. Since I'm not doing a Mortal Kombat game with "Fatalities" and stuff, I need hands and feet to stay connected.

If no parts are frozen, nothing changes. Once the Hip box is moved/rotated, everything moves and rotates along with it.

Let's isolate one limb to understand how it goes when a hand or foot is frozen:
  • Stretchy Leg
    • Upper Leg
      • Lower Leg
    • Foot (frozen)
Where:
  • Stretchy Leg: an instance of THREE.Object3D(). This object will be invisible, and will have two socket points, called "Upper Leg" and "Foot". The former is located at the object's pivot point, while the latter is initially located at -Y where Y = total length of the leg (upper + lower). This would position the Foot at the end of the leg.
  • Upper Leg and Lower Leg: instances of Bone(), one of the core game objects. It's basically a composition of a THREE.Mesh() with several socket points. When I attach another Bone to a socket, the attached bone becomes a child of that Mesh. In this case, the Lower Leg is the child of Upper Leg.
  • Foot: an instance of Bone that will be appended to the Stretchy Leg's socket point called "Foot". Usually, socket points are fixed, but in this particular case, the socket location will be dynamic, although restricted: it will only move along the Y axis. This will be the stretching effect taking place.
So, when I freeze "Foot", whenever I move the Hip box, I need to change the following:

1 - The location of the socket named "Foot".
This involves moving the socket point along its Y axis. To calculate world-space X, the Stretchy Leg object itself will have to be rotated around its pivot. This will create a right triangle, where the final value of Y equals its hypotenuse value. I haven't yet figured out the full formula for this, and I already see a complexity factor as of when the Hip box is moved along the Z axis. I'm not a Math guru, so this will require some study.
2 - The angles of Upper Leg and Lower Leg.
Once the leg stretches as a result of a Hip re-positioning, the Foot will be disconnected from the Lower Leg. So I need to angle the leg segments in a way that the lower end of the lower leg connects back with the foot. 
Both legs are children of the Stretchy Leg object. So I just need to find two angles, from each leg segment. This will form a triangle with three known sizes: one is Y, the distance between pivot and socket in the "Stretchy Leg" object; and the other two are fixed values representing the lengths of upper and lower legs. With those three values, I can calculate the two angles I need with this formula. It does sound complex, so I will probably do some more digging to see if I can find a simpler, faster formula.  
Once I get the two angles right, the end of the lower leg will connect back with the pivot of the foot.
There's an additional approach I need to research about which involves converting local to world coordinates. ThreeJS offers helpers for those. Basically, I save the world coordinates (converting from local to world) of the "Foot" socket before the Hip moves, then re-apply them (converting from world to local) after the Hip is moved. This would, in theory, keep the feet at its original place. Then it would just be a matter of making the leg armatures reach the newly positioned socket point.

Either way, if I end up doing this "stretchy limbs" thing, defining a pose for the arms and legs would actually become quite easier:
  • Rotating the stretchy limb around the Y axis would "point the elbow/knee" into a given direction.
  • Stretching and squeezing the new limb would "bend" the knee/elbow to a relative value, where 100 would be "totally stretched out" and 0 would be "totally bent".
And the best thing is, I still get to keep the old behavior. I just don't need to freeze anything.

The whole thing however, as far as formulas go, is starting to sound a bit too complex.

When something starts getting too complex, I tend to step back and rethink about it.

I really, really like to keep things simple. Sometimes, simplicity comes from thinking outside the box. Or, being clever. Sometimes I pull some good stuff off, but I'm not usually that clever. Not in regards of Math at least. I'm okay at Math. I probably should be better in this field of work.

Or maybe it's supposed to be complex. It's Math after all.

Bottom line is, between experiencing a horrible time making poses, and figuring out a way to make IK work -- as complex as it needs to be -- I will probably stick with the latter. By the chance this project actually works down the line and I end up getting help from outside animators, they won't hate me.

Tuesday, January 5, 2016

A Fighting Game in Javascript - On Posing


I spent my holidays with gamer friends and had the chance to show them some of my work. Meanwhile, I got my first pose started... and it was a lot of work! I already need to change how it works.

The Character() class has a pivot point that originally was located inside the model hip. It is used primarily to move the entire model across the X and Y axis. The hip cube serves a similar purpose, but now I see that I need to give them very distinct responsibilities.

The pivot point will be moved to the ground, Y=0. The hip cube, as its only child, will be moved up along the Y axis enough so the feet touch the ground. That's the function of the "Drop to Ground" button in the interface above. The position of the hip cube, relative to the pivot point, will be baked into the pose record.

With the pivot fully grounded, I will now be able to create characters of varying heights. That was worrying me before. The model size will affect hitboxes, so I won't give way too much liberty to players to make really tiny characters, as it would be unbalanced. I am aiming for one head taller, one head shorter the most, just so the shortest character is two heads shorter than the tallest one. I believe it's a reasonable compromise for now. Of course things can change later if needed.

Another advantage of the grounded pivot point is inverse kinematics, which I probably won't be working with in this game. If I were doing a game where the character interacted with the scenario (example: climbing stairs), or a dynamic dancing game (where I'd need to know which foot is touching the ground), then IK would be essential. I do intend of making other games with this model, shall this become a thing.

Back on reality... the hip cube is used to move the character slightly across the X and Y axis during some attacks or stances (like crouching). A far kick would thrust the hip forward, without moving the pivot point. That could maybe yield some weird situations, for example, an hurt box extending forward as a result of the far kick that is countered with a sweep: if the reach is too far, the character would "snap back" to its pivot location with the knock-down effect. I am guessing each case will be different, some will move the hip cube, some will move the pivot point.

I've also separated body poses from hand poses.

A "body pose" contains rotations for head, neck, chest, shoulders, arms, abdomen, hips, legs, and feet. It also has two extra fields that hold the pose names for each hand. Hand poses are already solidly defined: you have the fist, the spread, one/two/three pointing, the V sign, the chop, a couple of rested poses, and that's it. Probably a couple extra more. (Tempted to do a Vulcan salute one.) If I were to blend those with the body poses, it would add quite some overhead to the pose definitions, not to mention it would be hell to animators to define hand poses with each pose. A hand has 15 cubes with rotation parameters along their three axes. It's almost as much as the body parts (19 cubes). So it makes sense to separate them, both for storage and animator sanity.

Although body and hand poses will be separate, when I load a body pose during game execution, it will automatically merge the hand poses parameters to form a complete "pose definition" object. Pose definitions are shallow objects that contain all rotation values that are different than zero. So poses that do not change much of the model will be smaller. Also, shallow objects allow tweens to work seamlessly, without the need of extra functions or blocks to parse data or call functions, decreasing code complexity.

Example of a pose definition that only tilts the head forward:

{Hx: 0.5}

The capital letter(s) represent the body part (in the example above, H means Head), while the last lowercase letter represents the axis it will be rotated around. Values are in radians. I've assigned capital letters for every bone in the skeleton. I could have given them longer names, but I will be transferring that data in Ajax/socket calls, so the less metadata the better. They're still somehow readable, so I'm good with that.

When I get the above object to animate a character with a Tween, I just need to do the following:

var character = new Character();
var pose = {Hx: 0.5};
new TWEEN.Tween(character).to(pose, 1000).start();

The character instance also responds to the same properties as the pose definitions, so the above tween would change character.Hx property from 0 (current value) to 0.5 in 1 second, effectively creating an animation. I haven't got this to work yet, but I am hoping I can keep things really that simple.