CS838 Project 2

Vuk Ercegovac
Neoklis Polyzotis

1. General Description

The goal of the project is to build a tool for visualizing and manipulating motion capture data. Screenshots of the tool are shown in the following figures.

Tree view showing the joint hierarchy GL view showing the skeleton and the bounding volume

The tool provides the user with two views of the data. The first view uses the motion data to draw and animate a simple skeleton; this gives an immediate and intuitive impression of the motion. The second view provides a more detailed presentation of the motion: the skeleton is visualized as an hierarchy of joints, and the user can examine the rotation and translation channels of any joint by selecting it. In this manner, the user is able to examine the motion in two different levels of semantic "zoom". The interface also provides controls to replay the motion interactively, to control the camera of the graphical view, and to set interpolators for any range of frames.

In general, the implemented functionality of the tool can be broken down in the following six points ('*' indicates a bonus feature):

In the sections that follow, we first present the general implementation details of the tool, and proceed to discuss in more detail each of the previous points.

2. Implementation

2.1 Overview

The tool is implemented in Java (jdk 1.1.7). Apart from the Java runtime, the following packages are required:

The implementation of the tool is based heavily on the Model-View-Controller (MVC) design pattern. Motion capture data represent the "model", which is visualized by a number of different "views". In our case two views are provided: the animated graphical view, and the more detailed joint hierarchy view. The visual controls for time and interpolators represent the "controller" that alter the state of the model, and therefore the state of the visualizations.


Figure 1. UML class diagram

Figure 1 shows a simplified class diagram of the tool. The "model" is implemented in terms of the AnimationModel class. This class controls the time of the model and acts as a mediator for the following classes:

Currently, three factories are implemented:

The "view" of this model is abstracted by the ModelView class. This class is realized in two subclasses:

Given the model, GLModelView positions its camera coordinates with Camera and contains a mapping from joints and joint pairs (segments) to Shape for drawing the skeleton. Currently, several of each are implemented. For Camera the broad distinction is manual or automatic. The automatic Camera uses one of several Director strategies that implement the decision making process.

The "glue" between the model and the view is provided by ViewFrame. This class represents an association between an instance of AnimationModel and an instance of ModelView. This association is one to many, which means that different views can share the same model. This class also provides the visual controls that are common among all views.

At this point we conclude our short overview of the implementation. In the following sections, we will focus on the different functions of the tool and we will provide more implementation details as needed. In addition, the interested reader can find more information in the generated javadoc documentation of the source code.

2.2 Input of Motion Data

The tool reads in motion capture data in the Biovision format (.bvh files). The parser for the data was implemented using the JavaCC parser generator. The tool makes no assumptions on the format of the input and can read arbitrary skeleton hierarchies. The only assumption is that translation channels will be named with Translate{X,Y,Z} and rotation channels with Rotate{X,Y,Z}. The tool honors the order of the rotation channels for each joint and the rotation matrix is calculated based on the specified order.

2.3 Display of Motion

As we mentioned in section 2.1, the tool currently supports two views of the motion data. The first view uses OpenGL to draw and animate a 3d skeleton on screen, while the second view presents visualizes the joint hierarchy and the raw motion data.

2.3.1 GLModelView

The GLModelView does the work of setting up the scene and rendering the model into the scene. For rendering the model, the task is broken down into mapping shapes onto the model and choosing where to position the eye and look at of the camera. Mapping shapes is done by the class ShapeManager. It maps joints and joint pairs(segments) to a set of shapes. Drawing some shapes but not all, as in the case of Tracers, is accomplished by having several ShapeManagers. To make shape drawing more generic, all model data whether its explicit as in the case of joints or implicit as in the case of segments is converted to a ShapeAdapter that defines a bounding volume. The task of Shape is then to fill the ShapeAdapter volume.

The camera eye and look at points are determined by Camera. Two primary types of implementation are:

Due to the subjective nature of cinematography, it is difficult to say which automated solution will prove to be the best if at all possible. Thus we provide a framework for exploring what makes a good camera motion and ultimately the most interesting story. The heart of the framework is the Director that is responsible for providing camera positioning for a given frame. Every director knows something about a given frame of an animation and makes a decision based on this information. This knowledge is partitioned relative to the current frame in terms of prior and future knowledge. Specific to each director is what information they collect for their knowledge and how it effects the final decision. Directors for local and global are implemented. Local uses only the current frame's model information to calculate a fixed offset from a given joint. Global uses all frames to pick interesting camera positions and interpolated (linear) between them. Interesting is defined as breaking a bounding volume that serves as a threshold. Currently, only local has been plugged in.

2.3.2 TreeView

The second view presents the user with a tree visualization of the joint hierarchy. The user can select any joint or end effector in the hierarchy and view the values of the translation and rotation channels. The visualization of the rotation channels uses a text-based view that shows the actual data, and an OpenGL view that depicts an axis-angle representation. In this manner, the user can browse the raw motion data with the text-view, and at the same time get a more intuitive representation of the rotation through the OpenGL view. The latter shows the axis as a vector on the unit sphere and animates the orientation of the axis based on the rotation data.

It is important to note here that both main views share the same animation model. Apart from the obvious save in resource consumption, this also means that the two views are completely in sync: whatever change is applied to the model, it will appear in both views. Therefore, they will always display the same frame and the same interpolators will apply in both of them.

2.4 Forward Kinematics

The user can control the replay of the motion using the "video" buttons that each window contains. The tool supports replay of the motion in normal and fast speed, and also in both directions (backwards and forward). There is also a looping option, which wraps the frame number around when the end or start of frames is reached. Apart from the automated replay of frames, the user can also move manually to the next or previous frame, or directly set the value of the text field that shows the current frame. As we noted earlier, since the two main views share the same animation model, the replay of frames can be controlled from either of them and they will always be in sync.

Internally, the model is traversed in a depth first manner to produce the expected matrix stack manipulations.

2.5 Internal Representation of Rotations

The tool supports three different internal representations of rotations: Euler angles, unit quartenions and parameterized quartenions (exponential maps).

2.5.1 Euler Angles

In this representation, the rotation of the joint is represented with three rotation angles around the axes of the local coordinate system. The order that the rotations are applied is dictated by the order that the rotation channels appear in the input data. We make no assumption of a "global" rotation order, but instead store the rotation order on a per joint basis.

2.5.2 Unit Quartenions

We have used the javax.vecmath package for the implementation of unit quartenions. The package provides all the necessary code to create a unit quartenion and convert it to a rotation matrix. The quartenion for a specific joint is constructed by multiplying the individual quartenions that represent the rotation around the Cartesian axes. Again, the order of multiplication is dictated by the order that the rotation channels appear in the input file.

2.5.3 Exponential Map

We have implemented exponential maps on top of unit quartenions. More specifically, we first construct the unit quartenion that represents a specific rotation, and then use the logarithmic map to obtain the parameterized form. This is necessary, since there is no obvious manner in which we can compose the rotations of two parameterized quartenions.

2.6 Interpolation

We have implemented interpolators as a special case of rotation drivers. An interpolator is initialized with a range of frames and a rotation driver. It then uses the rotation driver to retrieve the rotations of the joints for the starting and ending frame, and calculates the rotations for the in-between frames. Interpolators need not use only the frame driver in order to access the rotation data; instead, the tool allows interpolators to be stacked in an hierarchy, where one interpolator is using the previous one as the rotation driver. This feature allows the creation of virtual "streams" of drivers, and can be used to combine filters and interpolators on the same motion. In addition, there may be an arbitrary number of such interpolator intervals defined over the total set of frames.

The interface allows the user to select a range of frames and the kind of interpolation that will be used (if there is actually a choice). The current version of the tool supports the following interpolators: linear interpolation for Euler angles, median filter for Euler angles, SLERP interpolation for quartenions and linear interpolation for exponential maps.

2.6.1 Euler Angles Interpolation

The Euler interpolator uses simple independent linear interpolation on the three angles to calculate the rotation of a joint. This of course does not always provide a smooth transition between the starting and ending frame, since the interpolation scheme does not take in account the interplay between the three axes.

We have also used the interpolator framework to implement a median cut filter, suitable for smoothing out the high frequency components of the motion. This filter acts much like an interpolator, but calculates the value for each rotation channel by examining the values in the previous and next frames.

Since the framework allows interpolators to be stacked, one can imagine layering the median cut filter on top of the original motion data, and then applying linear interpolation on top of that; as a result, interpolation will be applied after the filter has smoothed out the high frequency "noisy" components. In this manner, users "mix & match" these simple interpolators and filters until they arrive at the desired visual result. Although we could potentially include the filtering mechanism in the interpolator, we believe that the direct manipulation of the interpolation stack provides a more intuitive and flexible interaction paradigm.

2.6.2 Quartenion Interpolation

The quartenion interpolator uses the javax.vecmath package which already provides for SLERP interpolation. Overall, quartenion interpolation has produced the best results compared to interpolation for the other two representations.

2.6.3 Map Interpolation

The map interpolator implements linear interpolation between the starting and ending parameterized quartenion. It uses linear interpolation independently on each coordinate of the quartenion, and produces aesthetically pleasing results, as longs as the two quartenions are close in Euclidean space. We noticed, however, that in some cases, the interpolation would produce spurious results even though the start and end keys represented similar rotations.

To illustrate this, imagine a starting rotation of -(pi-epsilon) around the positive y-axis, and an ending rotation of (pi-epsilon) around the positive y-axis. Although the two rotations are actually 2*epsilon radians apart, linear interpolation will travel counter clockwise around the circle in order to move between the keys.

We were able, however, to discover the source of the problem by examining the axis-angle view of the rotation. Since parameterized quartenions are constructed with the logarithmic map, this causes all angles to lie in [0,2*pi]; therefore, the negative rotation around the positive y-axis is transformed to a positive rotation around the negative y-axis. This means that interpolation has to work its way from a starting negative axis to an ending positive axis, thus causing the trip around the circle.

In order to remedy this, we have implemented a second version of the linear interpolator that aligns the start and end keys. More specifically, the interpolator computes the inner product of the keys, and if negative it reverses axis and angle of the start key. This has the effect of bringing the two keys closer together in Euclidean space, and decreases the chances of producing spurious rotations.

Comparison

In this section, we present one characteristic example that illustrates the operation of the different interpolation schemes. More specifically, we use the Thief data set and focus on the rotation of the hips joints. The starting rotation of the hips is approximately -3*PI around the y axis, and the ending rotation is close to 3*PI, again around the y axis (note the change of sign). These two rotations are actually very close in rotation space, and this is why we have chosen our example. In the following figures, we show the hips rotation that each algorithm calculates using screenshots of the axis-angle representation. The screenshots refer to frames 100,110,120,130,140,150.

Euler Linear Interpolation

Linear interpolation in Euler space results in a trip in the wrong direction. Not only that, but the rotation is not smooth: it accelerates in the middle, and decelerates close to the start and the end.

'

Quartenion SLERP Interpolation

SLERP interpolation provides a very smooth rotation, since it masks out the change of sign.

'

Map Linear Interpolation

Plain linear interpolation in the exponential map gives poor results, since the two rotations are far apart in Euclidean space. We basically get the same results as the Euler angles interpolation, with an increased acceleration in the middle.

'

Map Aligned Interpolation

Aligned map interpolation applies a simple heuristic to bring the start and end rotation close in Euclidean space. This simple heuristic produces very good results in our case, since the initial rotation is "mirrored" and the axis reversed. Essentially, we get results that look similar to SLERP interpolation.

'

2.7 Marker Export

Marker export is implemented in the model-view framework that we have used for the visual manipulation of motion data. More specifically, we have implemented marker export as a special type of view that simply outputs the marker positions in a file.

Resources

Running

  1. Get all resources and unpack
  2. Set your LD_LIBRARY_PATH to ${magician_home}/lib
  3. Edit the runtest script to reflect local JVM and class files.
  4. Running the motion capture: execute runtest
  5. Running marker export: execute Java ExportMarkers

Last modified: Tue Apr 18 13:46:37 XXX 2000