Search code examples
three.jsquaternions

Quaternion product is different from the quaternion extracted from the matrix product


Yesterday I have been trying to solve the following problem: calculate the local rotation quaternion for a bone given its global rotation quaternion and the skeleton state.

I figured that the global quaternion equals to the parent bone global multiplied by the bone's local quaternion:

global = globalParent * local

After a couple of simple manipulations, I got the following:

local = (globalParent)-1 * global

I did some tests on that equation and, to my surprise, it sometimes yields the correct answer and sometimes I get the correct answer multiplied by -1. Not the local quaternion's conjugate, but the whole quaternion multiplied by -1.

So I went back to the original equation (global = globalParent * local) and tested it too. The same thing happened, sometimes the right answer and sometimes the right answer multiplied by -1.

I found that really strange and went further to make the matrix product (globalParent * local) and extract the quaternion for the result. In this situation, I always got the right answer.

Finally, my question is pretty simple. Where is the mistake in my thought process when manipulating the quaternions?

The code I used to check the things I said is the following:

{
    var p = new THREE.Vector3();
    var s = new THREE.Vector3();
    var bone = this.get_model_bone(label);

    var gm = bone.matrixWorld;
    var g = new THREE.Quaternion();
    gm.decompose(p, g, s);
    console.log(label + " - GLOBAL: (" + g.x + ", " + g.y + ", " + g.z + ", " + g.w + ")");

    var m = bone.matrix;
    var q = new THREE.Quaternion();
    m.decompose(p, q, s);
    console.log(label + " - LOCAL: (" + q.x + ", " + q.y + ", " + q.z + ", " + q.w + ")");

    if(bone.parent !== null)
    {
        var gpm = bone.parent.matrixWorld;
        var gp = new THREE.Quaternion();
        gpm.decompose(p, gp, s);
        console.log(label + " - PARENT GLOBAL: (" + gp.x + ", " + gp.y + ", " + gp.z + ", " + gp.w + ")");

        var productMatrix = new THREE.Matrix4().multiplyMatrices(gpm, m);
        var qprod = new THREE.Quaternion();
        productMatrix.decompose(p, qprod, s);
        console.log(label + " - MATRIX PROD: (" + qprod.x + ", " + qprod.y + ", " + qprod.z + ", " + qprod.w + ")");

        var gpq = new THREE.Quaternion().multiplyQuaternions(gp, q);
        console.log(label + " - QUAT PROD: (" + gpq.x + ", " + gpq.y + ", " + gpq.z + ", " + gpq.w + ")");
    }
}

In my logs, sometimes "MATRIX PROD" is different than "QUAT PROD". The model I am using can be found at:

https://raw.githubusercontent.com/poli-libras/virtual-jonah2/master/resources/model/human.js


Solution

  • I did some tests on that equation and, to my surprise, it sometimes yields the correct answer and sometimes I get the correct answer multiplied by -1.

    Quaternion and quaternion multiplied by -1 represent exact same transformation (rotation).