Bone world rotation quaternion vs absolute matrix rotation

I tried inputting a bone’s absolute matrix’s rotation quaternion into its bone.setRotationQuaternion() method with the parameter BABYLON.Space.WORLD, however the skeleton and mesh become messed up :frowning:

I thought that a bone’s (1) absolute matrix’s rotation quaternion and (2) world rotation quaternion are the same, so I expected that setting one to the other would have no effect, though it looks like I’m wrong.

Please see the Youtube video below where I uncomment lines in the PG linked below:

PG: https://playground.babylonjs.com/#BCU1XR#7552 (this PG is based on one in the official documentation)

Does anyone know the relationship between the (1) world rotation quaternion and (2) absolute matrix rotation? I’m trying to find the correct input quaternion for bone.setRotationQuaternion() with BABYLON.Space.WORLD.

Thank you for your help :slight_smile:

See how it is done in getRotationQuaternionToRef:

You are missing a multiplication of the first row by a scaling value, which is +1 or -1 depending on the bind matrix determinant. From _updateAbsoluteBindMatrices:

this._scalingDeterminant = this._absoluteBindMatrix.determinant() < 0 ? -1 : 1;

In your case, all bones have a -1 value.

1 Like

Thank you so much, @Evgeni_Popov! You’re a lifesaver :smile:

@Evgeni_Popov thank you for your tip on the scaling determinant. I’ve tried looking online to understand this term more, though haven’t found anything yet. Would you have any pointers on where I could read more on the scaling determinant’s purpose in the bone’s world rotation?

Unfortunately, I don’t really understand this part of our bone code, so I can’t really help…

From what I understand, it takes into account the fact that the matrix could be “left”/“right” handed (as we do for meshes coming from gltf files), and negate the X axis of the matrix (the first row) - we also negate scaling.x for the root bone in gltf case.

1 Like

These are great pointers :slight_smile: thank you so much!

Thank you so much again, @Evgeni_Popov, for your expertise and help here

I exported a .glb of the same model. Previously, I exported to the .babylon format. I’m trying to do the same thing in the PG for the .glb version

The boolean USE_GLTF can be changed to use either the .glb or .babylon model. The PG below works great when using .babylon, though I’m having trouble getting the same result with .glb. Would you be able to help with finding where I’m going wrong?

Thank you!!

bone._linkedTransformNode.rotationQuaternion = rotation is wrong, because rotation is in world space whereas bone._linkedTransformNode.rotationQuaternion expects a quaternion in local space.

You will have to perform the same calculation than Bone.setRotationQuaternion(rotation, BABYLON.Space.WORLD) and set the result to bone._linkedTransformNode.rotationQuaternion (see Babylon.js/packages/dev/core/src/Bones/bone.ts at master · BabylonJS/Babylon.js · GitHub).

I gave it a try, simplifying the calculation, as it seems to boil down to R.W-1, where R is the rotation matrix you want to define for the bone (in world space) and W-1 is the inverse rotation matrix of the bone’s parent:

2 Likes

Thank you so much, @Evgeni_Popov ! This looks great, and I’ll be studying this now

@Evgeni_Popov There’s just a slight issue where the shoulder and thumb bones seem to be left/right flipped:


After commenting out the rotation portion of the code below, the correct skeleton is shown in the images below:

Commented out portion of code:
if (!parent) {
    bone._linkedTransformNode.rotationQuaternion = rotation;
} else {
    BABYLON.Matrix.FromQuaternionToRef(rotation, tmpMat);

    tmpMat2.copyFrom(parent._linkedTransformNode.getWorldMatrix());
    rootInvMat.multiplyToRef(tmpMat2, tmpMat2);
    tmpMat2.invert();

    tmpMat.multiplyToRef(tmpMat2, tmpMat);

    bone._linkedTransformNode.rotationQuaternion = BABYLON.Quaternion.FromRotationMatrix(tmpMat);
}


I also commented out the BABYLON.Debug.AxesViewer in the PG so that the issue is more visible: https://playground.babylonjs.com/#BCU1XR#7973

Would you be able to help me figure out how to get these few bones in the right orientation when trying to set the rotation of their _linkedTransformNodes? Thank you so much for your help, Evgeni :smiley: I’ll be studying this too to try to also try to learn how to do this

I’m afraid I can’t help more, I’m a bit stucked… The problem is because of left-handedness. It works if you switch the scene to right handed mode (that’s a workaround at least):

In fact, we can see that in left handed mode there are more problems than just the thumb position:

Right handed mode:

Left handed mode:

I tried to account for left handedness with the rootInvMat matrix, but it seems it’s not enough / not the right fix…

1 Like

Thank you so much, @Evgeni_Popov! You’ve helped me greatly in the right direction :smiley: I’ll be studying this today and will try to solve this for left handed mode

1 Like