$35
CMPT466-985 Computer Animation
Programming Assignment 1: Forward Kinematics
In this lab, you are going to apply Forward Kinematic method with motion data obtained
from a BVH file. The default coding environment is Visual Studio 2017 Community
(workload: Desktop development with C++). Please ensure that your submission is runnable
on the desktops with VS2017 (x64 compiler) and Windows 10 in ABS9840.
Introduction to BVH file
A BVH file contains two parts:
1) Hierarchy part describe the skeleton tree.
2) Motion data part stores all joints’ transformations, frame by frame.
2
Where to code?
The template is given as CMPT466-985 Programm Assignment 1.zip. Extract it. You can
play with the result demo by executing the .exe file in the folder ResultDemo first. Open
build/CMPT466_Program_Assignment_1.sln with Visual Studio 2017.
1) Vectors.h Do not edit this file.
Support file contains many vector manipulation
features (e.g., dot product). Feel free to use
them in main.cpp: main entry, contains opengl
initial operations.
2) ForwardKinematic.h Do not edit this file.
Contains default declarations of functions and
variables.
3) ForwardKinematic.cpp The only file you need
to modify.
Contains the implementation of functions in ForwardKinematic.h.
There are three sub-functions needed to be completed within the recursive function in
ForwardKinematic.cpp.
calculateJointPosRecursivelyWithQuaternion(Joint* joint)
|-- computeLocalQuaternion(Joint* joint)
|-- computeGlobalQuaternion(Joint* joint, Vector4 localQuat)
|-- computeGlobalPosition(Joint* joint)
This function would access every joint in preorder traversal of the skeleton tree and
calculates every joint’s global position for one frame.
1) FrameData is a float** type pointer (2D array) to all the motion data within
running.bvh.
2) pFrame is pointing to one row (one frame’s motion data) of frameData indexed by
currentFrame.
3
You may need to:
1) use Vector4 class to represent quaternions. check more details in Vectors.h.
2) use quaternionMultiplication(Vector4, Vector4) to calculate quaternion
multiplication
3) use the default skeleton tree’s root joint (root) and pFrame to calculate every joint’s
global position (in quaternions).
4
Introduction to the project
By default, the skeleton tree structure and motion data of the bvh file are loaded into an
instance of the ForwardKinematic class (by loadFile(const char* pfile)), which
contains a pointer (Joint* root) to the root joint of the skeleton tree, a pointer (float**
frameData) to all frames’ data, a pointer (float* pFrame) to one to-be-displayed frame
data, etc. The overall workflow is as follows in the main function:
1) Initialize OpenGL: OpenGLinit(argc, argv)
2) Load BVH file, generate a skeleton tree with a pointer to the root (Joint* root) and, store
all motion data to ‘Float** frameData’: FK_model.load_BVH(“../data/running.bvh”)
3) Print the skeleton tree: FK_Model.print().
4) Loopinng: While (true)
a. Response to Keyboard event: press ‘w’, load next frame’s data
(glutMainLoopEvent(): pFrame=frameData[currentFrame+1]);
b. recalculate every joint’s global position of the skeleton with ‘root’ and ‘pFrame’
(FK_model.calculateJointPos(): call
calculateJointPosRecursivelyWithQuaternion (root));
c. Re-display the newly calculated skeleton: glutPostRedisplay().
By default, the template display the animation like the followings (run the project in Visual
Studio 2017 and 64-bit compiler): print Skeleton structure in output window (left) and
display skeleton animation in GLUT window (right). Each time ‘w’ on the keyboard is
pressed, one more frame is displayed.
5
By keeping pressing ‘w’, you will see one purple square point (the root joint) moving around
while the rest stayed the same. The purple square points indicate joints. Tiny red, green, blue
lines indicate local coordinate axises of each joint (by default, all of them are set to the same
as the world coordinate system).
Note:
If you meet with following error:
Error MSB8036 The Windows SDK version 10.0.16299.0 was not found.
Go to Project-Property Open the window, change
Configuration_Properties-General-Windows SDK Version to change the SDK
version to your VS2017
6
Coding Part
Part 1) ComputeLocalQuaternion(Joint* joint) (5 /15 points)
Input:
Joint* joint
Output:
Vector4 Joint’s local rotation in quaternion
Every three adjacent elements within pFrame indicate three rotation angles
along local x, y, z axis, respectively, with a specific rotation order in Euler angle
(opposite to fixed-angle rotation order).
Examples:
Joint(Hips):
Rotation_order: joint-rotationOrder (e.g., XYZ=7).
Rotation_angles:
X: pFrame[0] rotation angle along X axis,
Y: pFrame[1] rotation angle along Y axis,
Z: pFrame[2] rotation angle along Z axis.
Joint(LeftUpLeg):
Rotation_order: joint-rotationOrder (e.g., ZYX=1).
Rotation_angles:
Z: pFrame[3] rotation angle along Z axis,
Y: pFrame[4] rotation angle along Y axis,
X: pFrame[5] rotation angle along X axis …
1) You can get current joint’s rotation order by joiont-rotationOrder. The rotation
order is stored in an enum structure:
Note that when rotation order is NONE, you shouldn’t move pFrame forward.
2) You can get current rotation angle from float* pFrame[0, 1, 2], which is global
variable within scope of ForwardKinematic. (Note: don’t forget to update pFrame after
getting current rotation angle, or you will get root rotation angle for all joints)
3) You need to transform angle from degree to rad by multiply 3.14f/180.f
4) Vector4 class is provided to represent the quaternion with the first three elements
representing x, y, z values and the last element representing w value: Vector4
quaternion=Vector4(x,y,z,w).
5) You need to calculate the quaternion from the Euler angles, using function
quaternionMultiplication(Vector4, Vector4) .
If you complete part I correctly you would see each joint’s local coordinate system is
rotating by pressing ‘w’.
7
Part 2) computeGlobalQuaternion(Joint* joint, Vector4
localQuat) (5 /15 points)
Input:
Joint* joint, Vector4 localQuat
Output:
Vector4 joint’s global rotation in quaternion
The local rotation for each joint is respect to its parent. So the global rotation for one joint is
actually accumulated from the root.
You need to accumulate all the quaternions along one specific path in the tree from root to
current accessed joint (composite the quaternions!).
(Note: Remember you are coding in a recursive function, so you just need to deal with current
joint’s local quaternion and parent joint’s global quaternion).
(Note: Be careful with root)
If part 2 is completed, you would see something similar after completing the Part1 (the local
coordinate systems would be slightly different). But you know the rotation is accumulated!
8
Part 3) computeGlobalPosition(BVHJoint* joint) (5 /15 points)
Based on part 1 and part 2, you now
get the accumulated rotation from the
root for each joint. The global position
is calculated by parent’s global
position + rotated current joint’s local
position.
Again, it becomes easy as you are
coding in a recursive function.
If you complete part 3, the result
animation would be like a running
skeleton by keeping pressing ‘w’ on
keyboard.
(Note: You may need to use global quaternion of its parent rather itself to
compute relative positions)
9
Submittion
Please submit a zip file with student number and your name (i.e.,
300000001_TerryFox.zip). The zip file will only contain your final modified
ForwardKinematic.cpp file. Please make sure that the code is runnable in VS2017
community under Windows 10 environment before you submit it.
TA will test your code on the desktops in ASB9840 with VS2017