How to implement forward kinematics?

Hello there,

I’m trying to make a utility that animates a character according to the data in a BVH file. I can’t do this by simply exporting a character animation from Blender, because (1), I have a lot of BVH animations, and I want to have BVH parsing and visualization all done within the same application, and (2) eventually, the movement data will be generated in real-time, and not from a BVH file.

I’ve gotten as far as making a character model in Blender, instantiating it in jME3, extracting pointers to the model’s bones, parsing the BVH file and finally affecting the model with the animation data. My problem is that I’m not sure how to implement forward kinematics on a series of model bones.

BVH format defines the the angles of each joint in local coordinate space (relative to the parent joint) in Euler format. When I use the most naive approach to moving the model around:

[java]

for (int i = 0; i < bones.length; i++) {

if (Float.isNaN(frame.getRotX(i)) || Float.isNaN(frame.getRotY(i)) || Float.isNaN(frame.getRotZ(i))) continue;

Quaternion q = new Quaternion();

q.fromAngles(frame.getRotX(i), frame.getRotY(i), frame.getRotZ(i));

bones.setUserTransforms(Vector3f.ZERO, q, Vector3f.UNIT_XYZ);

}

[/java]

Where I just set the rotation to the value in the BVH file, it looks like it’s using some sort of global coordinate space, or perhaps the transforms are summing and not replacing one another; in any case the model movement is definitely very wrong. I’ve included an animated gif that shows a little bit of a walking sequence:

http://i.imgur.com/DQNwi.gif



Is there a way to set the rotations of the joints that preserves forward kinematics? If people know of a tutorial or post out there that addresses it, that would be great.

Thanks!

Look at TestKinematicRagdoll, if you have the animation data in a normal jme3 AnimControl, the ragdoll will work as kinematic physics object incl. limbs etc.

Do you mean jme3test.bullet.TestRagDoll.java? I can’t find anything called TestKinematicRagdoll in my jME3 distribution.

I’ve been trying to do this i my local repo, and it’s a rotation mess.

Even if the skeleton is the same in the bvh file and in the jme model, you have to retarget rotations properly…

I didn’t find how to do it yet; best result I had was in inverting rotation of the animation, which makes no sense of course, and the result was far from good.



The problem is the bvh joint has an init rotation of identity quaternion, and I don’t know in which space BVH rotation are… There is not much documentation on BVH though.

Also Blender BVH files do not follow exactly BVH specs, because they keep Z as the up axis.



I tried a lot of things with no result…

The key might be to multiply the rotation by the inverted rotations of the target bone…but you have to find the good combination of rotations…

normen seems to think there is an easier way… But I can’t find the file he is referencing. Maybe he could give us one more clue? :slight_smile:



I found TestBoneRagdoll.java – Maybe this is a place to start?



As for rotations and quaternions, it shouldn’t be this hard. The worst case scenario should involve having to recurse down the skeleton, from the root, and apply rotations, right?



My particular BVH files are taken from a motion capture system; not made in Blender. I have my program set up as a couple threads, where a producer thread parses the BVH file, and fills up a queue that the consumer (the jMonkeyEngine main loop) reads. The queue is filled with “frames”; basically single lines of data from the BVH file. The producer produces at a speed equal to the frame rate specified in the BVH.

It’s TestBoneRagdoll indeed, but the title of the post confused Normen, you just want to retarget the animation to the jme model skeleton and play it. The ragdoll Kinematic mode means the model can interact with the physical environment.


eubarch said:
As for rotations and quaternions, it shouldn't be this hard. The worst case scenario should involve having to recurse down the skeleton, from the root, and apply rotations, right?

You don't have to do that, call the resetAndUpadte method of a skeleton it compute model space rotations for each bones.
Also...i'm afraid it's not that easy.
But experiment with it, I tried a lot of things and got confused in the process, so it's cool that a "fresh" mind look into this ;)


eubarch said:
My particular BVH files are taken from a motion capture system; not made in Blender. I have my program set up as a couple threads, where a producer thread parses the BVH file, and fills up a queue that the consumer (the jMonkeyEngine main loop) reads. The queue is filled with "frames"; basically single lines of data from the BVH file. The producer produces at a speed equal to the frame rate specified in the BVH.

Why don't you just load the data in a BoneAnimation?
nehon said:
Why don't you just load the data in a BoneAnimation?

Because I expect to have some of my movement data generated in realtime. I'm building a visualization for a movement algorithm, and replaying BVH files is just a first step in development. Eventually the rotation data should come straight from the algorithm.
As for doing the forward kinematics manually, I can give it a shot. If I get it working, I'll post.

Just an update.



Referencing this thread on quaternions: http://hub.jmonkeyengine.org/groups/general-2/forum/topic/some-specific-questions-about-quaternion-rotation/,

it looks as if the Ogre XML exported decided to make my skeleton a very different size than the mesh, and this was causing the strange movement shown above.



I fixed this by scaling the mesh in Blender and exporting. I had to iterate, but it looked like a scaling factor of 0.155 worked well enough. Calling Bone.setBindTransforms() with a scaling vector did scale the skeleton, but the mesh scaled with it. Calling Skeleton.setBindingPose() would, in almost all cases, cause all of the joints in the skeleton to collapse to the same location in space. I gave up trying to fix the scaling problem with Bind Transforms.



The movement code is virtually the same as above, but this time it’s done in recursive order:



[java]private void recurseBoneRotation(Bone bone, Frame frame) {

int index = getBoneIndex(bone.getName());



Quaternion q = new Quaternion();



if (!(Float.isNaN(frame.getRotX(index)) || Float.isNaN(frame.getRotY(index)) || Float.isNaN(frame.getRotZ(index)))) {

q.fromAngles(frame.getRotX(index), frame.getRotY(index), frame.getRotZ(index));

} else q = Quaternion.IDENTITY;



bone.setUserTransforms(Vector3f.ZERO, q, Vector3f.UNIT_XYZ);



for (Bone b : bone.getChildren()) {

recurseBoneRotation(b, frame);

}

}[/java]



…Which produces something much better, but not quite there:







This “Bow Legged” gait isn’t correct-- Notice how the thighs move along non-parallel axes. The animation that Blender produced from the BVH looks far more normal (where the thighs move in roughly parallel axes). I can tweak the Ogre XML skeleton file and influence this, so I suspect that the problem might be with the exporter.



nehon: Is this as far as you got?

yep pretty much…I got Sinbad walk like he’s retarded…



But I though about the problem actually. I think the best way to compute correct rotations is to compute them in world space (for the source and target skeleton) for each frame of the animation and then compute the local rotation for the target skeleton from it.



this implies to iterate through the anim, for each frame iterate over each bone of the source skeleton, apply the animation on it, compute the world space rotation (local rot from anim x parent’s world rot), then multiply this rotation by the inverse world rotation of the parent bone in the target skeleton.



yeah…not very clear I admit, I’m gonna try and i’ll report back.

Well, it’s not at all ideal, but I did manage to improve on the movement:









I ended up doing two things:

For the legs, I manually edited the skeleton XML file with the aid of the simple oscillating animation loop that nehon authored. If you run that animation on my skeleton, you can see that oscillating on the X axis along produces a bow-legged “kick”. Editing the skeleton XML output from the Ogre XML exporter isn’t hard at all, and you can set the axis of rotation to be axis-aligned rather than off at the odd angle that you see animated above. For some reason, all of the arm animations were rotating backwards, so I implemented another stupid hack and reversed them at runtime. Not ideal, but good enough for now.



So this leaves the question: What is producing those incorrect axis definitions in the skeleton definition?



Hope this helps.