Assembly x86 quaternion to euler angles outputs wrong order

Viewed 137

I'm having some troubles converting quaternions into euler angles.

I've followed this C++ code found on Wikipedia and I think I did a pretty good job replicating it in assembly, the problem is that my code converts the WXYZ values to ZYX instead of the XYZ order.

C++ code: https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Source_Code_2

(The provided asm code only calculates the Roll axis)

//ROLL
finit
fld dword ptr [WRot]
fld dword ptr [ZRot]
fmulp st(1),st(0)
fld dword ptr [XRot]
fld dword ptr [YRot]
fmulp st(1),st(0)
faddp st(1),st(0)
mov dword ptr [Math],40000000 //2
fld dword ptr [Math]
fxch
fmulp st(1),st(0)
fstp dword ptr [sinr_cosp] //sinr_cosp

finit
fld dword ptr [YRot]
fld dword ptr [YRot]
fmulp st(1),st(0)
fld dword ptr [ZRot]
fld dword ptr [ZRot]
fmulp st(1),st(0)
faddp st(1),st(0)
mov dword ptr [Math],40000000 //2
fld dword ptr [Math]
fxch
fmulp st(1),st(0)
mov dword ptr [Math],3F800000 //1
fld dword ptr [Math]
fxch
fsubp st(1),st(0)
fstp dword ptr [cosr_cosp] //cosr_cosp

finit
fld dword ptr [sinr_cosp]
fld dword ptr [cosr_cosp]
fpatan
mov dword ptr [Math],42652EE1 //57.29577951308232
fld dword ptr [Math]
fxch
fmulp st(1),st(0)
fstp dword ptr [Roll] //Roll value

Using https://quaternions.online/ I've set the following values like this:

w:  0.549
x:  0.747
y:  0.092
z:  0.363

When applying, the XYZ order it should output:

x:  100.000
y:  40.000
z:  20.000

But my code produces:

x:  98.527
y: -26.213
z:  36.644

How could I fix that? Wher can I find a proper working C++ code as reference for converting Quat to XYZ?

I don't think it's a problem with memory allocation, every floating value is 8byte apart from one another.

I've also found this interesting reply https://stackoverflow.com/a/27496984/13741865 which shows the different possible cases, but for me it's a bit complicated to understand as it doesn't have comments and I would love to know which formula is applied to which rotation (for the XYZ case).

I'm still in my early development in assembly and I might not have a decent enough knowlege of the terminology.

I hope I've added every possible detail, I thank you in advance for your attention.

2 Answers

The problem was the formula itself, the souce code provided in Wikipedia was made for the ZYX order (it was commented on the code above and I didn't noticed it).

What I did is take my time to read the answer provided here https://stackoverflow.com/a/27496984/13741865 , analyze the code and fix the one I've made.

This gives the right output

finit
fld dword ptr [WRot]
fld dword ptr [WRot]
fmulp
fld dword ptr [XRot]
fld dword ptr [XRot]
fmulp
faddp
fld dword ptr [YRot]
fld dword ptr [YRot]
fmulp
fsubp
fld dword ptr [ZRot]
fld dword ptr [ZRot]
fmulp
fsubp
fld dword ptr [XRot]
fld dword ptr [YRot]
fmulp
fld dword ptr [WRot]
fld dword ptr [ZRot]
fmulp
fsubp
mov dword ptr [Math],0 //hex of 0
fld dword ptr [Math]
mov dword ptr [Math],40000000 //hex of 2
fld dword ptr [Math]
fsubp
fxch
fmulp
fxch
fpatan
mov dword ptr [Math],42652ee1 //hex of 57.29577951308232
fld dword ptr [Math]
fxch
fmulp
fstp dword [Roll] //Roll value

Thanks everyone

Maybe it is just the quaternion convention in the algorithm that is different from what you expected. Try feeding your algorithm the conjugate of the quaternion. I.e., reverse the signs of the Xrot, Yrot, and Zrot inputs. Unfortunately, it has been my experience that most quaternion information posted online rarely discusses the assumed quaternion convention for the algorithms posted (including the quaternions.online link you mention). It is entirely possible that the website you coded from assumes a different convention from the quaternions.online website.

Related