Search code examples
javamathquaternions

Invalid results when multiplying quaternions and no idea why


I am currently working on a 3D-library including quaternions. As every expert, I coded my methods based on what I found on Wikipedia and it doesn't work quite right.

This is the method for calculating the product between two quaternions:

public static Quaternion product(Quaternion a, Quaternion b) {
    return a.clone().multiply(b);
}

And here is its implementation:

public Quaternion multiply(Quaternion q) {
    float rx = q.getX(), ry = q.getY(), rz = q.getZ(), rw = q.getW();

    this.w = w*rw - x*rx - y*ry - z*rz;
    this.x = w*rx + x*rw + y*rz - z*ry;
    this.y = w*ry - x*rz + y*rw + z*rx;
    this.z = w*rz + x*ry - y*rx + z*rw;
    return this;
}

And here is a small test that I wrote:

Quaternion a = Quaternion.create(1, 1, 1, Spatium.DEG_TO_RAD *  15);
Quaternion b = Quaternion.create(1, 1, 1, Spatium.DEG_TO_RAD *  15);
Quaternion c = Quaternion.product(a, b);
System.out.println(a + " * " + b + " = " + c);

Note that the create() method initializes quaternions with x, y, z, w.

Unfortunately, the tests yields results that don't make any sense despite my amazing skills of copying and pasting Wikipedia formulas:

(0.2617994 + 1.0i + 1.0j + 1.0k) * (0.2617994 + 1.0i + 1.0j + 1.0k) = (-2.931461 + -2.6696618i + 1.0j + -6.3393235k)

For comparison, Wolfram solves it correctly and returns -2.93146 + 0.523599i + 0.523599j + 0.523599k.

Here's the formulas I so skillfully copied from Wikipedia: enter image description here

I don't really have anything to say other than please help me, Wikipedia couldn't.


Solution

  • I think you should store the current values of x, y, z and w in a temp variable before updating it with new values.

        public Quaternion multiply(Quaternion q) {
            float rx = q.getX(), ry = q.getY(), rz = q.getZ(), rw = q.getW();
    
            float cx = x; // cx = current X
            float cy = y;
            float cz = z;
            float cw = w;
    
            this.w = cw*rw - cx*rx - cy*ry - cz*rz;
            this.x = cw*rx + cx*rw + cy*rz - cz*ry;
            this.y = cw*ry - cx*rz + cy*rw + cz*rx;
            this.z = cw*rz + cx*ry - cy*rx + cz*rw;
            return this;
        }
    

    In your code, when you use this.w = w*rw - x*rx - y*ry - z*rz;, you are overridind the current value of w, and the next 3 operations will be affected by this changes.