I have made a simple animation in blender where the object(Bone in this case) is rotated from 0 to 360 degrees within 40 keyframes I then exported that data(Each keyframe) to glTF which stores the rotation of each keyframe as quaternion. After that i read each keyframe from the file and converted the quaternion(I also normalized the quaternion before that just in case) to XYZ euler angles, however the results are very unexpected and confusing.
This is the output:
Quat XYZW: -6.584865E-8, -6.71794E-8, -4.853328E-15, 1.0
maps to Euler(XYZ) In radians: -1.316973E-7, -1.343588E-7, -1.8554003E-14 | In degrees: -7.545699778706759E-6, -7.69819215990934E-6, -1.0630660420387862E-12
Quat XYZW: -6.584723E-8, 0.0065628546, -4.321644E-10, 0.9999785
maps to Euler(XYZ) In radians: -1.316973E-7, 0.013125804, -1.8542322E-14 | In degrees: -7.545699778706759E-6, 0.7520531864073278, -1.0623967938537065E-12
Quat XYZW: -6.5826804E-8, 0.025757458, -1.6961029E-9, 0.99966824
maps to Euler(XYZ) In radians: -1.316973E-7, 0.051520616, -1.823185E-14 | In degrees: -7.545699778706759E-6, 2.9519138441784234, -1.0446080897377453E-12
Quat XYZW: -6.5742256E-8, 0.056824293, -3.741812E-9, 0.99838424
maps to Euler(XYZ) In radians: -1.3169732E-7, 0.113709845, -1.8772983E-14 | In degrees: -7.545700592928757E-6, 6.515094187466668, -1.0756126741124562E-12
Quat XYZW: -6.5525505E-8, 0.0989473, -6.515556E-9, 0.9950927
maps to Euler(XYZ) In radians: -1.3169729E-7, 0.19821896, -2.0836097E-14 | In degrees: -7.545698964484761E-6, 11.357109632076618, -1.1938204425972884E-12
Quat XYZW: -6.5091555E-8, 0.15120457, -9.956626E-9, 0.9885025
maps to Euler(XYZ) In radians: -1.3169729E-7, 0.3035735, -1.861474E-14 | In degrees: -7.545698964484761E-6, 17.3934797025985, -1.0665460355383746E-12
Quat XYZW: -6.43445E-8, 0.21251643, -1.3993929E-8, 0.9771575
maps to Euler(XYZ) In radians: -1.3169728E-7, 0.42829898, -2.1480152E-14 | In degrees: -7.545698150262762E-6, 24.539723923622546, -1.2307220789639523E-12
Quat XYZW: -6.31839E-8, 0.2815993, -1.8542945E-8, 0.9595321
maps to Euler(XYZ) In radians: -1.3169729E-7, 0.5709209, -2.1111827E-14 | In degrees: -7.545698964484761E-6, 32.71135712398392, -1.2096185822782078E-12
Quat XYZW: -6.15112E-8, 0.35693273, -2.350355E-8, 0.9341301
maps to Euler(XYZ) In radians: -1.3169728E-7, 0.7299645, -3.3372332E-14 | In degrees: -7.545698150262762E-6, 41.823884741007696, -1.9120937992588885E-12
Quat XYZW: -5.923645E-8, 0.43674588, -2.8759136E-8, 0.89958495
maps to Euler(XYZ) In radians: -1.3169728E-7, 0.90395635, -3.4464144E-14 | In degrees: -7.545698150262762E-6, 51.79288392900523, -1.9746500140954907E-12
Quat XYZW: -5.6284716E-8, 0.51902527, -3.4177116E-8, 0.854759
maps to Euler(XYZ) In radians: -1.3169728E-7, 1.0914207, -3.0811074E-14 | In degrees: -7.545698150262762E-6, 62.533796946051744, -1.765344512671221E-12
Quat XYZW: -5.260214E-8, 0.60155135, -3.9611358E-8, 0.79883415
maps to Euler(XYZ) In radians: -1.3169719E-7, 1.2908835, -1.2859481E-13 | In degrees: -7.545693264930771E-6, 73.9621787483438, -7.367939727230888E-12
Quat XYZW: -4.8161187E-8, 0.68195695, -4.490595E-8, 0.7313923
maps to Euler(XYZ) In radians: -1.3169702E-7, 1.50087, -3.0508725E-13 | In degrees: -7.54568349426679E-6, 85.99351599018624, -1.748021205393232E-11
Quat XYZW: -4.2964448E-8, 0.7578121, -4.990091E-8, 0.6524729
maps to Euler(XYZ) In radians: 3.1415925, 1.4216864, -3.1415927 | In degrees: 179.999991348578, 81.45663113589697, -180.00000500895632
Quat XYZW: -3.704698E-8, 0.82672364, -5.4438644E-8, 0.56260824
maps to Euler(XYZ) In radians: 3.1415925, 1.1950747, -3.1415927 | In degrees: 179.999991348578, 68.47273522183704, -180.00000500895632
Quat XYZW: -3.0476517E-8, 0.8864487, -5.837146E-8, 0.46282688
maps to Euler(XYZ) In radians: 3.1415925, 0.96236306, -3.1415927 | In degrees: 179.999991348578, 55.13934194304214, -180.00000500895632
Quat XYZW: -2.335154E-8, 0.9350088, -6.156907E-8, 0.35462454
maps to Euler(XYZ) In radians: 3.1415925, 0.72502494, -3.1415927 | In degrees: 179.999991348578, 41.54086902255905, -180.00000500895632
Quat XYZW: -1.5797392E-8, 0.97079647, -6.3925626E-8, 0.23990472
maps to Euler(XYZ) In radians: 3.1415925, 0.48453543, -3.1415927 | In degrees: 179.999991348578, 27.761834928724795, -180.00000500895632
Quat XYZW: -7.960307E-9, 0.9926662, -6.5365725E-8, 0.12088809
maps to Euler(XYZ) In radians: 3.1415925, 0.24236898, -3.1415927 | In degrees: 179.999991348578, 13.886719710062323, -180.00000500895632
Quat XYZW: 7.731664E-15, 1.0, -6.584865E-8, 2.3468012E-8
maps to Euler(XYZ) In radians: 3.1415925, 4.6936023E-8, -3.1415927 | In degrees: 179.999991348578, 2.6892360289340074E-6, -180.00000500895632
Quat XYZW: -7.920893E-9, -0.9927389, 6.5370514E-8, 0.120289244
maps to Euler(XYZ) In radians: 3.1415925, -0.24116248, -3.1415927 | In degrees: 179.999991348578, -13.81759221924627, -180.00000500895632
Quat XYZW: -1.5651457E-8, -0.9713415, 6.396153E-8, 0.23768824
maps to Euler(XYZ) In radians: 3.1415925, -0.47997037, -3.1415927 | In degrees: 179.999991348578, -27.500276249553743, -180.00000500895632
Quat XYZW: -2.305319E-8, -0.9367149, 6.168141E-8, 0.3500934
maps to Euler(XYZ) In radians: 3.1415925, -0.7153417, -3.1415927 | In degrees: 179.999991348578, -40.98605958646809, -180.00000500895632
Quat XYZW: -3.0003555E-8, -0.89016205, 5.861596E-8, 0.45564413
maps to Euler(XYZ) In radians: 3.1415925, -0.94619143, -3.1415927 | In degrees: 179.999991348578, -54.21277555571114, -180.00000500895632
Quat XYZW: -3.6401097E-8, -0.83331436, 5.4872622E-8, 0.55279946
maps to Euler(XYZ) In radians: 3.1415925, -1.1714399, 3.1415927 | In degrees: 179.999991348578, -67.1185614264228, 180.00000500895632
Quat XYZW: -4.216858E-8, -0.76805305, 5.0575256E-8, 0.6403863
maps to Euler(XYZ) In radians: 3.1415925, -1.3900026, -3.1415927 | In degrees: 179.999991348578, -79.64128296772347, -180.00000500895632
Quat XYZW: -4.7255202E-8, -0.6964209, 4.5858375E-8, 0.7176336
maps to Euler(XYZ) In radians: -1.3169738E-7, -1.5407987, 0.0 | In degrees: -7.545703849816751E-6, -88.28126053192533, 0.0
Quat XYZW: -5.163706E-8, -0.62053615, 4.0861455E-8, 0.78417784
maps to Euler(XYZ) In radians: -1.3169742E-7, -1.3388525, -1.2364265E-13 | In degrees: -7.545706292482747E-6, -76.71059905903273, -7.0842017918353375E-12
Quat XYZW: -5.531615E-8, -0.5425092, 3.572349E-8, 0.84004986
maps to Euler(XYZ) In radians: -1.316973E-7, -1.1468425, -3.4545395E-14 | In degrees: -7.545699778706759E-6, -65.70923385346072, -1.979305341354779E-12
Quat XYZW: -5.8318243E-8, -0.4643712, 3.057821E-8, 0.8856407
maps to Euler(XYZ) In radians: -1.316973E-7, -0.965849, -2.4987489E-14 | In degrees: -7.545699778706759E-6, -55.33907033475165, -1.4316776537211207E-12
Quat XYZW: -6.0689615E-8, -0.38801494, 2.5550252E-8, 0.9216531
maps to Euler(XYZ) In radians: -1.3169732E-7, -0.7969536, -2.5416875E-14 | In degrees: -7.545700592928757E-6, -45.6620788092451, -1.4562796829062145E-12
Quat XYZW: -6.2493015E-8, -0.31515533, 2.0752546E-8, 0.9490401
maps to Euler(XYZ) In radians: -1.3169732E-7, -0.6412406, -1.773355E-14 | In degrees: -7.545700592928757E-6, -36.740379847442306, -1.0160575447920945E-12
Quat XYZW: -6.380327E-8, -0.24730308, 1.6284568E-8, 0.9689382
maps to Euler(XYZ) In radians: -1.3169729E-7, -0.49979177, -1.2143506E-14 | In degrees: -7.545698964484761E-6, -28.63595912360844, -6.957716214363101E-13
Quat XYZW: -6.470256E-8, -0.18575978, 1.22320225E-8, 0.9825952
maps to Euler(XYZ) In radians: -1.316973E-7, -0.3736901, -1.5264296E-14 | In degrees: -7.545699778706759E-6, -21.410865491258477, -8.745797402829878E-13
Quat XYZW: -6.5275735E-8, -0.13162617, 8.6673975E-9, 0.99129945
maps to Euler(XYZ) In radians: -1.3169732E-7, -0.2640185, -1.8401186E-14 | In degrees: -7.545700592928757E-6, -15.127146096360107, -1.0543102956962941E-12
Quat XYZW: -6.56057E-8, -0.08582368, 5.6513647E-9, 0.99631035
maps to Euler(XYZ) In radians: -1.316973E-7, -0.17185877, -1.8029164E-14 | In degrees: -7.545699778706759E-6, -9.846782344310256, -1.0329950079242779E-12
Quat XYZW: -6.5769136E-8, -0.049127325, 3.234959E-9, 0.9987925
maps to Euler(XYZ) In radians: -1.3169728E-7, -0.09829421, -1.7849729E-14 | In degrees: -7.545698150262762E-6, -5.631843579191415, -1.0227141133972815E-12
Quat XYZW: -6.583243E-8, -0.022202317, 1.4619833E-9, 0.9997535
maps to Euler(XYZ) In radians: -1.3169732E-7, -0.04440828, -1.911468E-14 | In degrees: -7.545700592928757E-6, -2.5444070424923027, -1.0951905372995666E-12
Quat XYZW: -6.58476E-8, -0.0056411726, 3.714543E-10, 0.9999841
maps to Euler(XYZ) In radians: -1.316973E-7, -0.011282405, -1.859742E-14 | In degrees: -7.545699778706759E-6, -0.6464341826508654, -1.0655536652056328E-12
Quat XYZW: -6.584865E-8, 2.0243377E-8, -1.061E-14, 1.0
maps to Euler(XYZ) In radians: -1.316973E-7, 4.0486754E-8, -1.8554003E-14 | In degrees: -7.545699778706759E-6, 2.319720102041324E-6, -1.0630660420387862E-12
As seen after it reaches 90 degrees, it goes backwards but instead of x, z staying at ≈ 0 they're set to PI and -PI (or 180 and -180) what i expected was x, z staying at ≈ 0 and y going from 0 to 360 because the keyframes i only rotated 0-360 degrees in the y axis in blender.
I am not sure why this happens, my desired result is x, z staying at ≈ 0 and y going from 0 TO 2PI for example(implying 0-360 degrees)
I also highly doubt the conversion to euler xyz is wrong because i tried both wikis implementation of it and JOML's(math library for opengl in java)
Converted code of DMGregory's answer that is producing NaN for some values
private Vector3f getEuler(Quaternionf q) {
double PI = Math.PI;
Vector3f transformedForward = new Vector3f(2 * q.x * q.z, 2 * q.y * q.z - 2 * q.w * q.x, MathUtils
.sq(q.w) + MathUtils.sq(q.z) - MathUtils.sq(q.x) - MathUtils.sq(q.y));
double yaw = PI + Math.atan2(-2 * (q.x * q.z + q.w * q.y),
q.x * q.x + q.y * q.y - q.z * q.z - q.w * q.w);
double pitch = Math.asin(2 * (q.w * q.x - q.y * q.z));
Vector3f noRollRight = new Vector3f(q.w * q.w + q.z * q.z - q.x * q.x - q.y * q.y, 0, -2 * (q.x * q.z - q.w * q.y))
.normalize();
Vector3f noRollUp = transformedForward.cross(noRollRight);
Vector3f transformedUp = new Vector3f(2 * (q.x * q.y - q.w * q.z),
q.w * q.w + q.y * q.y - q.x * q.x - q.z * q.z,
2 * (q.w * q.x + q.y * q.z));
double roll = Math.acos(transformedUp.dot(noRollUp)) * -Math.signum(transformedUp.dot(noRollRight));
return new Vector3f((float) yaw, (float) pitch, (float) roll);
}
6.283185, -0.79695374, NaN for (-3.880E-1 -6.192E-8 -2.607E-8 9.217E-1)
6.283185, -0.64124054, NaN for (-3.152E-1 -6.376E-8 -2.117E-8 9.490E-1)
First 3 values are the euler angles(yaw, pitch, roll) and the quaternion is in the paranthesis(in XYZW form)
Debugging the value of noRollUp, transformedUp for the first example above:
noRollUp: (-1.375E-7 6.989E-1 -7.152E-1),
transformedUp: ( 9.610E-8 6.989E-1 -7.152E-1)
for Quaternion (-3.880E-1 -6.192E-8 -2.607E-8 9.217E-1)
Result:
6.283185, -0.79695374, NaN for (-3.880E-1 -6.192E-8 -2.607E-8 9.217E-1)
I can't immediately see anything wrong with it.
After clamping the input of acos for roll to -1 - 1, that issue is resolved:
double roll = Math.acos(MathUtils.clamp(transformedUp.dot(noRollUp) * -Math.signum(transformedUp
.dot(noRollRight)), -1f, 1f));
noRollUp
andtransformedUp
. Likely a small rounding error has led to one or both being slightly greater than 1.0 in magnitude, so you may just want to clamp the input toacos
between -1 and 1 to avoid issues there. \$\endgroup\$acos
, and is important for representing upside-down rotations. \$\endgroup\$