I am writing a simple BVH parser in C# using the XNA framework. At the moment I have managed to parse in all the data and my goal is to find out the global coordinates of all the joints in the skeleton.
The problem I am encountering is that the bones don't seem to take into account the rotation of its parents. For instance, if I move my lower leg, I would expect my foot to change orientation as well and keep the same angles between the foot and the lower leg. What I am noticing is that the translation of the bone joints is correct, but the global rotation of a bone is the same as the local rotation of the bone. The picture below might help you understand what the problem is:
note: there is a mistake in the pic captions, it should read "the left upper leg is rotated around the z-axis" not the x-axis.
I would have expected the lower leg portion to also be rotated by 1 radian as a result of its parents' change in orientation.
So the code is as below (I am using XNA and C#):
foreach (Bone b in bones)
{
//Calculate the local transform matrix
b.localTransform = Matrix.CreateTranslation(b.Offset) * Matrix.CreateRotationZ(MathHelper.ToRadians(b.z)) * Matrix.CreateRotationY(MathHelper.ToRadians(b.y)) * Matrix.CreateRotationX(MathHelper.ToRadians(b.x));
Bone parent = b.parent;
if (parent != null)
{
//Calculate global transform matrix
b.globalTransform = parent.globalTransform * b.localTransform;
b.location = b.globalTransform.Translation;
lines.Add(new Tuple<Vector3, Vector3>(parent.location, b.location));
}
}
Each bone assumes its parents global transformation is correct as the list is ordered so the parents always come before the children. The root bone has no rotations and no offset and has its global transform already set based on this. I am wondering what I am doing wrong here?
I have done a simple example using only 2D:
Matrix bone1 = Matrix.CreateTranslation(new Vector3(3, 0, 0)) * Matrix.CreateRotationZ(1);
Matrix bone2 = Matrix.CreateTranslation(new Vector3(3, 0, 0)) * Matrix.CreateRotationZ(1);
lines.Add(new Tuple<Vector3, Vector3>(Vector3.Zero, bone1.Translation));
lines.Add(new Tuple<Vector3, Vector3>(bone1.Translation, (bone1 *bone2).Translation));
Drawing this onto the screen shows what I expect. The 1st bone is rotated 1 radian around the origin, 2nd bone is rotated 2 radians around the origin.
I am using the below as a reference for parsing and interpreting the BVH data: http://www.dcs.shef.ac.uk/intranet/research/resmes/CS0111.pdf