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.
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.
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.
2) Then use IKController to position the hands so that they follow the targets
3) Then animate the position of the hips
4) Then pin the feet to their original position using IKController
5) Then reset the rotation of the feet to their original global rotation
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.