GLM преобразование из углов Эйлера в кватернион и обратно не имеет места - PullRequest
4 голосов
/ 22 февраля 2020

Я пытаюсь преобразовать ориентацию контроллера OpenVR, который я сохранил как glm::vec3 углов Эйлера, в glm::fquat и обратно, но я получаю совершенно разные результаты, и поведение в игре просто неверно (сложно объяснить, но ориентация объекта ведет себя нормально для небольшого диапазона углов, затем переворачивается в странных осях) .

Это мой код преобразования:

// get `orientation` from OpenVR controller sensor data

const glm::vec3 eulerAnglesInDegrees{orientation[PITCH], orientation[YAW], orientation[ROLL]};
debugPrint(eulerAnglesInDegrees);

const glm::fquat quaternion{glm::radians(eulerAnglesInDegrees)};
const glm::vec3 result{glm::degrees(glm::eulerAngles(quaternion))};
debugPrint(result);

// `result` should represent the same orientation as `eulerAnglesInDegrees`

Я бы ожидал, что eulerAnglesInDegrees и result будут либо одинаковыми, либо эквивалентными представлениями одной и той же ориентации, но это, очевидно, не тот случай. Вот некоторые примеры значений, которые я распечатал:

39.3851 5.17816 3.29104 
39.3851 5.17816 3.29104 

32.7636 144.849 44.3845 
-147.236 35.1512 -135.616 

39.3851 5.17816 3.29104 
39.3851 5.17816 3.29104 

32.0103 137.415 45.1592 
-147.99 42.5846 -134.841 

Как вы можете видеть выше, для некоторых диапазонов ориентации преобразование является правильным, но для других оно совершенно другое.

Что я делаю не так?

Я посмотрел на существующие вопросы и попытался сделать несколько вещей, включая попытку каждого возможного порядка вращения, перечисленного здесь , , сопрягающего кватернион и другие случайные вещи, такие как переключение высоты тона / рыскания / крена. Ничто не дало мне ожидаемого результата.

Как преобразовать углы Эйлера в кватернионы и обратно, представляющие исходную ориентацию, используя glm?


Некоторые другие примеры расхождений:

original:      4; 175;   26; 
computed:   -175;   4; -153; 
difference:  179; 171;  179; 

original:     -6; 173;   32; 
computed:    173;   6; -147; 
difference: -179; 167;  179; 

original:      9; 268;  -46; 
computed:   -170; -88;  133; 
difference:  179; 356; -179; 

original:    -27; -73;  266; 
computed:    -27; -73;  -93; 
difference:    0;   0;  359; 

original:    -33; 111;  205; 
computed:    146;  68;   25; 
difference: -179;  43;  180; 

Я пытался найти шаблон для исправления окончательных computed результатов, но не похоже, что есть один простой для идентификации.


GIF + видео о поведении:

Video excerpt


Визуальное представление моей интуиции / текущего понимания:

Visual diagram

  • На картинке выше показана сфера, и я нахожусь в центр. Когда я нацеливаю пистолет на зеленую половину сферы, ориентация правильная. Когда я нацеливаю пистолет на красную половину сферы, это неправильно - кажется, что каждая ось перевернута, но я не уверен на 100%, что это так.

Ответы [ 3 ]

4 голосов
/ 22 февраля 2020

32,7636 144,849 44,3845 -147,236 35,1512 -135,616

Это то же самое. Слева 33 или справа 147. Вы 180 друг от друга. Теперь посмотрите на 145 - это выше 35 на горизонте, ваша спина выгнута. Теперь перевернитесь, чтобы вернуться в небо.

Если вам нужно , чтобы использовать Эйлера, попробуйте сохранить высоту в диапазоне от -90 до +90, а также от -180 до +180;

if (pitch > 90) {
   pitch -= 90;
   yaw += 180;
   roll += 180;
}
if (roll > 180) {
   roll = 360 - roll;
}

или что-то в этом роде.

2 голосов
/ 22 февраля 2020

Определение любого вида 3-х углов для представления поворота определяется не только порядком поворотов, если они являются extrinsi c или extrinsi c, но и тем, какой интервал углов вы выбираете при определите сопоставление каждого элемента 3D группы вращения с набором из 3 углов.

К сожалению, в программных библиотеках обычно не указывается, какое подмножество углов они поддерживают, поэтому обычно необходимо либо проверить их поведение, либо напрямую проверить исходный код. Для соответствующей проблемы относительно glm см. https://github.com/g-truc/glm/issues/569 и см. https://github.com/robotology/idyntree/pull/504 для соответствующего обсуждения другой библиотеки, над которой я работаю.

В glm master, из быстрой проверки кода (https://github.com/g-truc/glm/blob/6543cc9ad1476dd62fbfbe3194fcf19412f0cbc0/glm/gtc/quaternion.inl#L10) и из того факта, что в C ++ asin изображение примерно (-90,0, 90,0) и atan2 изображение примерно (-180,0, 180,0) , предполагаемый интервал в glm кажется примерно (-180,0, 180,0) x (-90,0, 90,0) x (- 180.0, 180.0), поэтому, ограничив второй угол (рыскание, используя имена, которые вы используете) до (-90.0, 90.0). Таким образом, то, что вы видите на уровне GLM, - это в основном отображение от предоставленных углов к эквивалентным углам в диапазоне (-180.0, 180.0) x (-90.0, 90.0) x (-180.0, 180.0).

Однако тот факт, что эти углы эквивалентны, зависит от того, как они используются , т. Е. Если у вас есть библиотека, которая зажимает углы Эйлера за пределами используемых диапазонов, вместо преобразования его в эквивалентные углы, вы получите странные результаты. По этой причине я думаю, что было бы интересно понять вашу проблему, чтобы узнать, как генерируются эти углы (в частности, средние углы являются частью диапазона (-90, 270), что является странным, даже если это правильный выбор) и как они интерпретируются для визуализации объекта в визуализации. Как только вы поймете, что даже если функция рендеринга отлично работает для углов в исходных диапазонах приложений, вы можете написать функцию для сопоставления «исходных углов приложения» с «углами GLM» и ее инверсией, которую вы можете использовать для своей первоначальной цели.

1 голос
/ 24 февраля 2020

Примерно следуя Тони совету и после некоторых проб и ошибок и идентификации шаблона, мне удалось найти способ восстановить исходные значения после преобразования.

  • ox, oy и oz - исходные высота , рыскание и крен в градусах, до любое преобразование;

  • fx, fy и fz - это новые высота , рыскание и крен в градусах, полученный после преобразования "Эйлер -> кватернион -> Эйлер" (через glm::degrees(glm::eulerAngles(glm::normalize(quaternion)))).

if (oy > 90.f)
{
    fx -= 180.f;
    fy -= 180.f;
    fy *= -1.f;
    fz += 180.f;

    if (ox > 0.f)
    {
        fx += 360.f;
    }
}

Приведенный выше код похоже, что исходные значения углов и значение после преобразования точно совпадают. Хотя он отвечает на первоначальный вопрос, он не решает мою настоящую проблему ... Я конвертировал в кватернион, чтобы плавно интерполировать под другим углом. Однако, похоже, что использование glm::mix на кватернионе после преобразования приводит, опять же, к очень непредсказуемым поворотам.

...