Assignment 10: Reach for your goals

In which, we use inverse kinematics to animate our characters

Due Friday, Dec 3, before midnight

The goal of this lab is to

  • Implement two-link analytical and CCD algorithms on our character

  • Implement procedural animations based on IK

Get the source

On Github, do a Fetch Upstream to synchronize your forked repository with the class repository.

Then update the source on your local machine and rebuild.

> git pull
> cd build
> cmake ..; make

1. Eye on the prize

In the file, looker.cpp, implement a character whose gaze follows a target.

Your algorithm should align the forward direction of the head with the target. The forward direction of the head is the Z axis (0,0,1) in its local coordinates.

looker

To run the demo from the build directory, type

build> ../bin/a10-looker

2. Character IK

In the file, ik_controller.cpp, implement a poseable character using different algorithms. This file implements a class which overrides Skeleton to support joints whose positions can be set using global coordinates. Inverse kinematics is used to calculate the corresponding local rotations of the interior joints.

The basecode comes with a viewer to help you test your algorithm.

User interface overview

The camera can be controlled with the mouse:

  • Left-button drag with the mouse to rotate

  • Right-button drag with the mouse to pan

  • Middle-button drag with the mouse to zoom

The left frame lets you select joints, reset the pose, and set the goal position manually. The right panel lets you select the algorithm for IK along with IK parameters. For CCD:

  • Threshold: how close to the goal do we need to be to stop iterating

  • Max iterations: max number of iterations to use before stopping the algorithm

  • Nudge: the nudge factor to use when moving towards the goal

  • Chain length: the number of ancestors to "nudge" towards the goal. If the chain size is -1, we use all ancestors up to (but excluding) the root.

  • Epsilon: threshold for analytic IK

2.1. CCD

Implement the CCD algorithm in IKController::solveIKCCD() in ik_controller.cpp.

// solveIKCCD positions the joint given by jointid so its global position
// is located at goalPos
//
// param skeleton: the character to modify
// param jointid: the ID of the joint to pose
// param goalPos: the target position for jointid (global pos)
// param chain: the list of joints to "nudge" towards the goal
// param threshold: when the given joint is within threshold of the goal, stop iterating
// param maxIters: the max number of iterations to try to reach the goal
//
// return true/false based on whether we could reach the goal
// side effect: skeleton should by posed such that jointid is located at goalPos (or in this direction of
// goalPos if the target is out of reach)
bool IKController::solveIKCCD(Skeleton& skeleton, int jointid,
    const AVector3& goalPos, std::vector<Joint*> chain, float threshold, int maxIters)

To run the demo from the build directory, type

build> ../bin/a10-ikviewer
When you change the local rotation of a joint, you must call fk() to update the global rotations and translations.

Implementation Hints

  • When implementing CCD, make the chain length 1 to start and ensure that a single joint can follow the target.

  • Test in your function that your angle/axis computation is correct by computing whether the computed rotation indeed rotates the limb towards the target.

  • Then, make sure that you can set the rotation matrix correctly in the joint’s local coordinate system.

2.2. Analytical method

Implement IKController::solveIKAnalytic() in ik_controller.cpp. Your solution should combine the techniques of the simple two-link analytic approach with CCD’s angle/axis calculation. This work will allow us to animate the legs and arms of the character such that the knees and elbows bend along their natural axis.

// solveIKAnalytic: positions the joint given by jointid so its global position
// is located at goalPos. This method computes rotations for the parent and grandparent
// of jointid.
//
// param skeleton: the character to modify
// param jointid: the ID of the end effector
// param goalPos: the target position for jointid (global pos)
//
// return true/false based on whether we could reach the goal
// side effect: skeleton should by posed such that jointid is located at goalPos (or in this direction of
// goalPos if the target is out of reach)
bool IKController::solveIKAnalytic(Skeleton& skeleton, int jointid, const vec3& goalPos)

To run the demo from the build directory, type

build> ../bin/a10-ik

Implementation hints:

  • Use the angle/axis CCD computation to solve for the grandparent joint rotation.

  • Use the law of cosines to solve for the parent joint rotation.

  • Use the follow axis formula to choose the axis of rotation for the parent joint:

vec3 limbDir = normalize(parentJoint->getLocalTranslation());
vec3 axis = cross(limbDir, vec3(0,0,-1));
if (limbDir[1] < 0) axis = cross(limbDir, vec3(0,0,1));

3. Dancer

In the file dancer.cpp, implement a procedural algorithm to make our character dance. Your solution should animate the positions of the hands and hips to move up and down (for example, using sine or cosine). Use IK to keep the feet planted on the ground. Use IK to compute the elbow and shoulder positions given the position of the hands. You can choose to use either solveIKAnalytic or solveIKCCD.

Your solution will modify the motion in idle.bvh to make the hands and hips move differently.

dancer

To run the demo from the build directory, type

build> ../bin/a10-dancer

Demo requirements

  • You should animate the hips back and forth and up and down.

  • You should animate the hands up and down.

  • The feet should not move

  • Note: You may use either sine/cosine or a spline to animate the hips and hands.

Suggested approach

1) Animate the hand targets first.

dancer1

2) Then use IKController to position the hands so that they follow the targets

dancer2

3) Then animate the position of the hips

dancer3

4) Then pin the feet to their original position using IKController

dancer4

5) Then reset the rotation of the feet to their original global rotation

dancer5

4. Unique

Personalize one the demos from this assignment. Below are some ideas:

  • Make you own unique animation based on inverse kinematics, splines, and motions. For example, make a new dance, have the character hold a cup, or wave.

  • Try your procedural dance or look on an other motions.

  • Try creating a procedural walker by using IK on the legs.

  • Create a procedural motion for an animal or insect, such as a spider, centipede, cat, ostrich, or fish.

  • Create a unique looking character or environment.

5. Hand-in your work

5.1. What to hand-in

  • Your code

  • Images, movies, gifs, as appropriate

  • Your readme

5.2. How to hand-in

Check-in your code, images, and writeup and push the changes to Github. If everything is uploaded correctly, you will see your work on Github.

> cd animation-toolkit
> git add <files>
> git commit -m "helpful message"
> git push

Best practice is to always commit changes as you work, rather than waiting until the end to commit changes. You can always revert to an old version if you need to!

Your code should download and compile without modifications. Test your assignment on a lab machine (Park 230) to ensure that it works.

5.3. Generating images, movies and gifs

Screenshots

On Ubuntu, you can take a screenshot by

  • Prt Scrn to take a screenshot of the desktop.

  • Alt + Prt Scrn to take a screenshot of a window.

Gifs

On Ubuntu, you can use Peek to create gifs.

Movies

On Ubuntu, you can use recordmydesktop to record movies in .ogv format.

By default, the whole desktop is recorded unless you give it a window id. To get the window id, call xwininfo and click on the window. Then pass the id to recordmydesktop.

> recordmydesktop --windowid <WindowId> --no-sound  --v_quality 30 -o <name>.ogv

To check the video, open it in firefox.

> firefox <name>.ogv
Files larger than 100 MB cannot be checked into git. In general, videos should be less than 5 MB.

5.4. Update your Readme.md

Update assignments/a10-ik/Readme.md to document the features in your assignment. Your readme should contain your images, gifs, and movies.

On github, you can drag and drop movies into your readme files. Images and gifs can also be added that way, or by including text such as the following

![Alternate text here](/path/to/image.png)

This Guide can help you with writing markdown.