Преобразование кватерниона обратно в Эйлера

Я пытаюсь понять, как преобразовать кватернионы Collada (от Assimp) для вращения анимации обратно в вращения Эйлера для FBX. Я уверен, что это простой алгоритм, я просто не могу найти правильный... все те, которые я пробовал, неверны, и обычно их называют ToEulerXYZ. Возможно, это потому, что эти вращения происходят по оси X, затем по Y, затем по Z, а не одновременно? Кто-то из знающих, вероятно, может легко помочь.

Вот мои тестовые образцы - я ввожу углы Эйлера, а затем экспортирую колладу и получаю эквивалентный кватернион. Я хотел бы сделать наоборот (и из кватерниона получить Эйлера). Обратите внимание, что я знаю, что не всегда будет получать одинаковое значение, а просто нужны значения, которые дают одинаковое вращение.

Примеры значений: Эйлер X, Y, Z Кватернион X, Y, Z, W

0,0,0-> 0,0,0,1

0.000000,0.000000,45.000000-> 0,0,0.38268346,0.92387956

45,0,45-> 0.35355338, 0.14644660, 0.35355338,0.85355341

45,45,0 0.35355338,0.35355338,-0.14644660,0.85355341

45,45,45-> 0.19134171,0.46193978,0.19134171,0.84462321

30,45,60-> 0.022260016,0.43967974,0.36042345,0.82236314

Если это поможет, Assimp генерирует кватернион таким образом (под лицензией Assimp):

                    angle = 60 * float( AI_MATH_PI) / 180.0f;
                    axis = aiVector3D( 0.0f, 0.0f, 1.0f);
                    aiMatrix4x4::Rotation( angle, axis, rot);
                    res *= rot;

                    angle = 45 * float( AI_MATH_PI) / 180.0f;
                    axis = aiVector3D( 0.0f, 1.0f, 0.0f);
                    aiMatrix4x4::Rotation( angle, axis, rot);
                    res *= rot;

                    angle = 30 * float( AI_MATH_PI) / 180.0f;
                    axis = aiVector3D( 1.0f, 0.0f, 0.0f);
                    aiMatrix4x4::Rotation( angle, axis, rot);
                    res *= rot;



                    aiVector3D scale;
                    aiQuaternion rotation;
                    aiVector3D translation;
                    res.Decompose(scale, rotation, translation);

person Mary Ellen Bench    schedule 10.05.2014    source источник


Ответы (2)


Согласно документам, порядок вращения Эйлера FBX по умолчанию действительно XYZ. В классе Quat FBX SDK есть метод для преобразования quat в euler следующим образом: DecomposeSphericalXYZ в http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html.?url=files/GUID-3E0DCCD0-5F9A-44D0-8D5E-423237D49DB6.htm,topicNumber=d30e9965

Так что, учитывая, что ваш ToEulerXYZ правильный, он должен работать. Убедитесь, что вы не смешиваете градусы и радианы.

person antont    schedule 10.05.2014
comment
В нашем проекте мы используем библиотеку mathgeo с открытым исходным кодом, которая выглядит следующим образом: float3x3 float3x3::FromEulerXYZ(float x, float y, float z) github.com/juj/MathGeoLib/blob/master/src/Math/ . Вызывается для Quats из github.com/juj/MathGeoLib /blob/master/src/Math/Quat.cpp#L611 . Там немного сложно отследить из-за того, что вся операция разбита на множество частей / с использованием более мелких строительных блоков. - person antont; 11.05.2014
comment
Это работало для 45,0,45, но не работает для 30,45,60. Это кватернион 0.022260016,0.43967974,0.36042345,0.82236314 и я получаю 3,51,44 (что не равно в моделлере). - person Mary Ellen Bench; 11.05.2014
comment
Я попробовал MathGeoLib, и он получает {x=-24,597227 y=47,663212 z=58,334499} для кватерниона, используя ToEulerXYZ из 30,45,60, так что с этим тоже что-то не так. - person Mary Ellen Bench; 11.05.2014
comment
Еще одна библиотека, которую мы используем, это three.js, где Euler имеет setFromQuaternion по адресу github.com/mrdoob/three.js/blob/master/src/math/Euler.js#L227 - person antont; 11.05.2014
comment
Я думаю, что в вашей выборке есть радианы, тогда как MathGeoLib дает градусы. Однако это все еще не соответствует: math.степени(0,43967974) => 25,191793439409363 - person antont; 11.05.2014
comment
Я получаю то же значение во второй ссылке, которую вы показали (mrdoob), {x = -24,597229 y = 47,663212 z = 58,334499 ...}, поэтому я подозреваю, что это не эквивалентно тому, что использует FBX? Для кватерниона 0.022260016,0.43967974,0.36042345,0.82236314, что должно быть 30,45,60 углов от FBX. - person Mary Ellen Bench; 11.05.2014
comment
Помимо градусов и радианов, единственная разница, которую я могу себе представить, - это рукоятка coordsys - FBX праворукий в соответствии с stackoverflow.com/questions/14484887/ - person antont; 11.05.2014

Разобрался и благодарю Антона за помощь. Это был нюанс Ассимпа. По-видимому, по какой-то странной причине (ошибка?) вращение читается в обратном порядке, поэтому вам нужно сделать ToEulerZYX, но затем изменить использование xyz на zyx.

                    float3 keyValueOrig = quat.ToEulerZYX();
                    float3 keyValue;

                    keyValue.z = RadToDeg(keyValueOrig.x);
                    keyValue.y = RadToDeg(keyValueOrig.y);
                    keyValue.x = RadToDeg(keyValueOrig.z);
person Mary Ellen Bench    schedule 11.05.2014
comment
Отлично, вы придумали способ - мне все еще интересно, связано ли это с ручностью или что-то еще, было бы неплохо знать для протокола. - person antont; 11.05.2014