Euler to Quaternion

Started by
17 comments, last by JoeJ 4 months, 2 weeks ago

JoeJ said:
I never understood why OpenGL used degrees for rotations

I guess that 180° or 360° and such are more ‘perfect’ than 3.14159…

Advertisement

snoken said:
My matrix indexes as col, then row so index [0][1] would read column 0, row 1. To convert a quaternion to a rotation matrix, I am using the following:

It's difficult to communicate. Math itself isn't affected, but when it comes to technical implementation, choices on semantics and memory layout bring back uncertainty no matter how hard we try to avoid it.

But i can give an example on the numbers i get from code like this:

				sQuat rot;
				rot.FromAxisAndAngle(vec(1,0,0), float(PI)/180.f * 30.f);
				SystemTools::Log("\nquat:\n%f, %f, %f, %f\n", rot[0],rot[1],rot[2],rot[3]);
				
				sMat3 matrix;
				matrix.FromQuat(rot);
				SystemTools::Log("\nmatrix:\n%f, %f, %f\n", matrix[0][0],matrix[0][1],matrix[0][2]);
				SystemTools::Log("%f, %f, %f\n", matrix[1][0],matrix[1][1],matrix[1][2]);
				SystemTools::Log("%f, %f, %f\n", matrix[2][0],matrix[2][1],matrix[2][2]);

results are:

quat:
0.258819, 0.000000, 0.000000, 0.965926

matrix:
1.000000, 0.000000, 0.000000
0.000000, 0.866025, 0.500000
0.000000, -0.500000, 0.866025

You could compare what you get for the same example.
You should get the same numbers and signs, and i assume also the same order (my library calls rows columns, but i guess that's just semantically in practice).

But i see it almost gives a symmetric matrix. Doing a second example with a non axis aligned axis to get more unique numbers:

				sQuat rot;
				rot.FromAxisAndAngle(sVec3(1,0.5f,0.2f).Unit(), float(PI)/180.f * 30.f);
				SystemTools::Log("\nquat:\n%f, %f, %f, %f\n", rot[0],rot[1],rot[2],rot[3]);
				sMat3 matrix;
				matrix.FromQuat(rot);
				SystemTools::Log("\nmatrix:\n%f, %f, %f\n", matrix[0][0],matrix[0][1],matrix[0][2]);
				SystemTools::Log("%f, %f, %f\n", matrix[1][0],matrix[1][1],matrix[1][2]);
				SystemTools::Log("%f, %f, %f\n", matrix[2][0],matrix[2][1],matrix[2][2]);
quat:
0.227877, 0.113939, 0.045575, 0.965926

matrix:
0.969882, 0.139973, -0.199341
-0.036117, 0.891989, 0.450611
0.240884, -0.429840, 0.870180

_Silence_ said:
I guess that 180° or 360° and such are more ‘perfect’ than 3.14159…

Sure, but that's a bad excuse to waste cycles. It's also an example of making it harder by trying to make it foolproof imo.

Thanks for the reply! The order I was using with rotation matrices as rX rY rZ where the rotation matrices are multiplied right to left so it's rZ first. I am using the same ordering for Quaternions

snoken said:
The order I was using with rotation matrices as rX rY rZ where the rotation matrices are multiplied right to left so it's rZ first. I am using the same ordering for Quaternions

Yeah, looking at your code, i think it should work.
But since it does not, you need to test one thing after another while minimizing what else could go wrong.
By comparing your result for a single rotation with mine, you can see if that works. Caring about Euler angle order would be the next step.

Thanks for the reply! I just compared your results to mine.

30 degree rotation on X axis:

Quaternion RotX = Quaternion(30.0f, vec3(1.0f, 0.0f, 0.0f));
Quaternion: 0.965926, 0.258819, 0, 0
Matrix: 

         1          0          0          0 

         0      0.866        0.5          0 

         0       -0.5      0.866          0 

         0          0          0          1 

I have w first for quaternions while I think you have it last.

Test 2:

Quaternion RotX = Quaternion(30.0f, vec3(1.0f, 0.5f, 0.2f).unit());
Quaternion: 0.965926, 0.227877, 0.113939, 0.0455755
Matrix: 
    0.9699   -0.03612     0.2409          0 
      0.14      0.892     0.4506          0 
    0.2409    -0.4298     0.8702          0 
         0          0          0          1 

snoken said:
I have w first for quaternions while I think you have it last.

Yes, otherwise we agree, confirming there is no bug in axis angle or quat → matrix stuff. Which is good, but actually bad : )

I have still some (probably baseless) paranoia about this:

snoken said:
where the rotation matrices are multiplied right to left so it's rZ first.

I would write each multiplication in its own line, to rule out the compiler could choose a left to right order. And i would do the change to both code paths, just to be sure.

Likely that's no success either.
After that i would log all bone matrices to file for both code paths using the same animation pose, to see when they start to diverge. Maybe the first few spine bones are right, and just the limbs go wrong or something like that, revealing more hints about the bug.

When using quaternions, the skeleton looks fine except the z axis rotation. The arms go up instead of down. If I negate only Z, the arms come down as they should but they are not aligned with the torso, they are rotated back. Other than that, the skeleton looks fine and in the correct pose.

Arms are behind instead of aligned with torso. This is the only issue when negating z. The rest of the pose seems fine

snoken said:
When using quaternions, the skeleton looks fine except the z axis rotation. The arms go up instead of down. If I negate only Z, the arms come down as they should but they are not aligned with the torso, they are rotated back. Other than that, the skeleton looks fine and in the correct pose.

I guess the observation is due to coincidence and probably misleading. An error in ‘seemingly mostly z’ likely depends on the data, but it could look very differently wrong with a different model.

But the issue does remind me on getting euler order wrong, wrong multiplication order, or a combination of both.
It's frustrating you have a working matrix path already, and now the same using quaternions does not work. But it's also luck because you can do numerical comparison with correct reference data. This should help to narrow it down to a single case (bone), to give an isolated test case for debugging.

This topic is closed to new replies.

Advertisement