[jBullet] Problem with skinning ragdoll

Hello everyone,

I’m posting the problem here, because I couldn’t get a response from other sites, and I’m hoping that somebody could point me in the right direction.

I have the following ragdoll structure (green dots - bones, pinkish lines - bone links):

The black boxes are Bullet’s rigid bodies (boxes) constructed by creating an AABB of all mesh vertices that are influenced by the bones in a particular, let’s say, body part. So for example, if you look at the chest area, there are five bones that make up that body part - I take the vertices, calculate their AABB and construct a rigid body. (In the picture, the head is a circle, but in my code, it’s actually a box, too :))

These rigid bodies are linked to each other using six-DOF constraints. The ragdoll itself is working fine, but now, when I run the simulation, I want to somehow map a rigid body’s transformation to the corresponding bones to animate the mesh. To continue with the example of the chest area - whenever it is moved by Bullet, I want to apply its center of mass transform to all the bones that are within the chest area.

The way I figured out the mapping is divided in two parts - the initialization phase and update phase.

During initialization (for every rigid body):

a) Calculate its inverse transform matrix

Utils.transformToMatrix(vars.tempMat4x42, this.rigidBody.getCenterOfMassTransform(vars.vecmathTransform));
vars.tempMat4x42.invert();

b) For each bone assigned to the body, transform the bone’s world bind position by the inverse transform matrix and save it for later. Also, save the bone’s world bind rotation, and the inverse of rigid body’s initial rotation quaternion.

private void initializeBone(final Bone bone, final Matrix4f invRigidBodyTransform) {
    final TempVars vars = TempVars.get();
    final TransformComponents transformComponents = new TransformComponents();

    RagdollUtils.getMatrixForBone(vars.tempMat4x41, bone); // <-- this returns the bone's world bind matrix without scaling applied

    final Vector3f boneTranslation = vars.tempMat4x41.getTranslation(vars.vect3d1);
    invRigidBodyTransform.transformPosition(boneTranslation, transformComponents.getTranslation());
    vars.tempMat4x41.getNormalizedRotation(transformComponents.getRotation());

    this.initialBoneTransforms.put(bone.getIndex(), transformComponents);

    vars.release();
}

During update (for every rigid body):
a) Get the current rigid body’s transform matrix, transform the initial position by it.
b) Multiply the inverse of the rigid body’s initial rotation by the current rotation.
c) Multiply the initial bone’s rotation by the result of the previous operation.
d) Multiply the resulting transformation matrix by the inverse transformation matrix of the model (the owner of the skeleton)

// This method performs stuff described in the points a-c.
void getTransformedBone(final Bone bone, final Vector3f outVec, final Quaternionf outQuat) {
    final TempVars vars = TempVars.get();
    final TransformComponents initialTrans = this.initialBoneTransforms.get(bone.getIndex());


    Utils.transformToMatrix(vars.tempMat4x41, this.rigidBody.getCenterOfMassTransform(vars.vecmathTransform));
    Utils.convert(vars.quat1, vars.vecmathTransform.getRotation(vars.vecmathQuat));
    vars.tempMat4x41.transformPosition(initialTrans.getTranslation(), outVec);


    final Quaternionf rot = this.initialRotation.invert(vars.quat2).mul(vars.quat1, vars.quat1);
    initialTrans.getRotation().mul(rot, outQuat);


    vars.release();
}

The above works well, as you can see here:

However, when I apply the matrices computed like that to the skin, it gets messed up. Any idea what might be causing the problem? I’m guessing that the matrices are in world space, maybe that’s what causing the problem? I’ve also tried multiplying by the bone’s inverse bind matrix (as you usually do), but that didn’t help either…

Thanks,
Patryk