Recently, I have been reading stuff about maths, mainly solving non linear equations with rotations and I have stumbled about a method to multiply vector by quaternion with 15 multiplications and 15 additions. This obviously got me curious so I’ve checked the jme Quaternion.mult(Vector3f, Vector3f) implementation.
To my suprise, it uses 60 multiplications and 21 additions! Below I post the method along with a comparison test. The result shows no significant difference in precision.
After testing this method yourself, could one of you put it on git. I would also propose to change the quaternion’s x, y, z, w from protected to public, just as a Vector3f has its x, y, z public, but that’s for another topic.
Comparison Test
The following test compares results of Quaternion multiplication between the jme’s Quaternion.mult, the 15 mult 15 add method and one other method that i found on internet.
From the tests it seems that the 15 mult 15 add method would be the optimal candidate for quaternion vector multiplication.
public static void quatMult(Quaternion q, Vector3f v, Vector3f s) {
//15 mult, 15 add
float x = q.getX();
float y = q.getY();
float z = q.getZ();
float w = q.getW();
float vx = y*v.z-z*v.y;
float vy = z*v.x-x*v.z;
float vz = x*v.y-y*v.x;
vx += vx; vy += vy; vz += vz;
s.x = v.x + w*vx + y*vz-z*vy;
s.y = v.y + w*vy + z*vx-x*vz;
s.z = v.z + w*vz + x*vy-y*vx;
}
public static void quatMult2(Quaternion q, Vector3f vec, Vector3f result){
float x = q.getX();
float y = q.getY();
float z = q.getZ();
float w = q.getW();
float num = x * 2f;
float num2 = y * 2f;
float num3 = z * 2f;
float num4 = x * num;
float num5 = y * num2;
float num6 = z * num3;
float num7 = x * num2;
float num8 = x * num3;
float num9 = y * num3;
float num10 = w * num;
float num11 = w * num2;
float num12 = w * num3;
result.x = (1f - (num5 + num6)) * vec.x + (num7 - num12) * vec.y + (num8 + num11) * vec.z;
result.y = (num7 + num12) * vec.x + (1f - (num4 + num6)) * vec.y + (num9 - num10) * vec.z;
result.z = (num8 - num11) * vec.x + (num9 + num10) * vec.y + (1f - (num4 + num5)) * vec.z;
}
public static void main(String[] args) {
Quaternion q = new Quaternion();
q.fromAngleNormalAxis(0.4547f, new Vector3f(0.5454f,0.21f,0.12f).normalizeLocal());
//For the following quaternion 0 difference
//q.fromAngleNormalAxis(FastMath.PI, Vector3f.UNIT_Z);
Vector3f res1 = new Vector3f();
Vector3f res2 = new Vector3f();
Vector3f res3 = new Vector3f();
Vector3f v = new Vector3f(0.55f,0.48f,0.54f);
for(int i = 0; i < 10; i++) {
q.mult(v, res1);
quatMult(q, v, res2);
quatMult2(q, v, res3);
System.out.println("v " + v);
// System.out.println("r1 " + res1);
// System.out.println("r2 " + res2);
System.out.println("quatMult " + res1.subtract(res2));
System.out.println("quatMult2 " + res1.subtract(res3));
v.set(FastMath.nextRandomFloat(),
FastMath.nextRandomFloat(),
FastMath.nextRandomFloat());
}
}