Programming Project #1: Skeleton

CSE 169: Computer Animation

 

Due: Tuesday, Jan 20, 6:00pm

Assignment

Write a program that loads a character skeleton from a .skel file (described below) and display it in 3D. All joints in the skeleton will be 3-DOF rotational joints (ball-and-socket joints) that rotate in x first, then y, then z. The program should perform the forward kinematics computations to generate world space matrices for the joints.

 

The program should be able to load any skel file given to it, and should accept a .skel file name as a command line argument. If no file name is given, it should default to ‘test.skel’.

 

You can use the sample code in project0 to start with if you want. Either way, you must do the matrix computations in C++ code rather than through OpenGL. The only OpenGL matrix routine you should need to draw the skeleton is glLoadMatrixf(). In other words, do not use glPushMatrix(), glPopMatrix(), glRotatef(), glTranslatef(), or similar commands for rendering the skeleton. You can use the Matrix34 class provided in the sample code.

 

To render the actual ‘bones’ of the skeleton, you can use the drawWireBox() command provided in core.cpp or you can use another method of your choice.

 

To make loading the data file easier, a class called Tokenizer is provided in the sample code which opens a file and reads individual strings, ints or floats. Also, please see the lecture notes from Lecture 2: Skeletons for more info.

 

If you want to add extra features, feel free. Some possible ideas include:

- The ability to select a current DOF and adjust its value interactively

- Rendering solid boxes with shading

- Create your own creature skeleton (make your own .skel file)

- Load several different skeletons and display them together

Skel File Description

The .skel file is a simple indented hierarchy of joints. Each joint also lists some relevant data about its configuration. For a sample .skel file, see test.skel.

 

The .skel data file has 8 keyword tokens which are then followed by data (usually floats). These specify properties of a particular joint. Not all joints will specify all properties, so reasonable default values should be used. Here is a list of the keywords and their associated data.

 

offset                x y z                 (joint offset vector)

boxmin             x y z                 (min corner of box to draw)

boxmax            x y z                 (max corner of box to draw)

rotxlimit            min max            (x rotation DOF limits)

rotylimit            min max            (y rotation DOF limits)

rotzlimit            min max            (z rotation DOF limits)

pose                 x y z                 (values to pose DOFs)

balljoint            name { }          (child joint)

 

The ‘offset’ is the constant positional offset to add to the local joint transformation. It represents the location of a joint’s pivot point described relative to the parent joint’s space. This will almost always be specified for a joint, but if not, it should default to (0,0,0).

 

The ‘boxmin’ and ‘boxmax’ parameters describe the min and max corners of a box representing the bone to render for the particular joint. If these are not specified for a joint, they should still have a reasonable default, say (-0.1,-0.1,-0.1) and (0.1,0.1,0.1).

 

The ‘rotlimit’ tokens describe the rotational joint DOF limits. Note that all angles are in radians. These should default to an essentially unlimited state if they are not specified in the file (i.e., -100000 to 100000 would be fine).

 

The ‘pose’ token specifies values to pose the DOFs at. Normally, data like this would not be needed in a skeleton file, as the skeleton is usually posed by a higher level animation system. For the purposes of this project, however, we will include optional pose data in the .skel file. By default, these should be 0. If the pose specifies values outside of the range of the DOF limits, then it should get properly clamped before displaying. Again, remember that these values are in radians.

 

The ‘balljoint’ token specifies a child balljoint which will have its own data and possibly its own children. There should not be any limit to the number of children allowed. Every balljoint has a name in the file, but you don’t have to do anything with this string if you don’t want to. Optionally, you could draw bone names as labels in the 3D view though…

 

In theory, one could extend this file format to include other joint types (hingejoint, prismaticjoint, freejoint, etc.). Each one of these joint types could have additional data tokens if needed.

Sample

Here is a sample rendering of how test.skel should look:

 

This is from a more or less straight view with the x-axis pointing to the right, y-axis pointing up, and z-axis coming out of the screen towards the viewer. Also notice that by default, the character is aligned with the viewer, therefore looking ahead, and facing away from us.

 

Note that the right knee is bent. This is because the right knee has values specified in the ‘pose’ field within the .skel file. Also note that these values are being clamped to within the DOF limits for the knee. The knee is able to rotate about the x-axis from –2 radians to 0 radians, but y and z are constrained to be locked at 0, effectively deactivating those DOFs, and making the knee a 1-DOF hinge joint. This is all controlled in the .skel file by specifying the DOF limits.

Grading

This project is worth 15 points:

 

3:         All boxes drawing (but not necessarily in the right place)

3:         All joints connected at correct pivot points

3:         Joint pose rotations working properly

2:         DOF limits working properly

2:         Loads any skel file specified as a command line argument

2:         Reasonable use of object oriented design in code

15:       Total

 

Extra Credit:

1:         Design your own .skel file with at least 10 joints that uses joint limits, different sized boxes, and a non-trivial tree (i.e., no snakes!), then pose it.

 

2:         Add a simple GUI to the program (try glui, tcl…?) that lists all of the DOFs by name (i.e. “knee_r X”) and allows the user to adjust the value within the DOF limits. Display the active DOF name and value on the screen.

Solution

Here is some solution code that implements project 1. It requires the sample project0 code as well. The project 1 code replaces the tester.cpp & tester.h from project 0.