Как я могу сравнить два кватерниона для логического равенства?


9

Я пытаюсь написать несколько юнит-тестов и понимаю, что не знаю, как сравнивать кватернионы. Мне нужно знать, представляют ли два кватерниона одинаковую ориентацию (объект будет смотреть одинаково). С векторной позицией я бы просто сравнил детали и проверил, что они достаточно близки, но для кватернионов значения могут сильно отличаться.

Как я могу сравнить два кватерниона?


Я не уверен, что это стандартная практика, но в Java и Unity кватернионы хранятся в виде четырех значений с плавающей запятой. Просто сравните их друг с другом, как указано в этих сообщениях: answers.unity3d.com/questions/288338/… stackoverflow.com/questions/5803627/quaternion-comparision
Tholle

1
@ Говорят, что пользователь также обеспокоен влиянием применения кватерниона для преобразования / поворота трехмерного объекта (то есть по позе). Два разных кватерниона могут достигать одинакового вращения (например, qи -q). Наивным (в вычислительном отношении) способом было бы применить оба кватерниона к одному и тому же вектору и посмотреть, отличаются ли их векторные результаты ..
Теодрон

Ответы:


7

Если ваши два кватерниона равны q1и q2, они представляют один и тот же поворот, если выполняется любое из этих двух условий:

  1. q1компонентный примерно равен q2ИЛИ
  2. q1 компонентный примерно равен -q2

Зная это, вы можете написать довольно упрощенный тестер равенства, который соответствует вашей цели.


9
+1, хотя один придира qи -qпредставляет ту же ориентацию (о которой просили), но не одно и то же вращение. Это очень важно при интерполяции.
Фальстро

@falstro, я думаю, я понимаю, что вы имеете в виду: оси вращения инвертированы, но угол аргумента также отрицается между qи -qкогда представлен как оператор вращения угловой оси. Так что, действительно, технически эффект этих вращений одинаков, хотя операторы - нет. И, да, при СЛЕРПИНГЕ необходимо убедиться, что он лежит на одном q1и q2том же полушарии гиперсферы S3, чтобы спеллер выбрал кратчайший путь.
Теодрон

1
Точно, когда вы выполняете любое вращение, вы в конечном итоге получаете ту же ориентацию, но интерполируете ее (независимо от того, используете ли вы lerp или slerp, или какую-то другую необычную интерполяцию), вы увидите, что она поворачивается по-разному. И да, аргумент угла отрицается, но это так же, как 2pi-angle, поэтому он поворачивает длинный путь вокруг отрицательных осей. Иногда это то, что вы хотите, хотя; это просто что-то, о чем нужно знать, q1 dot q2 > 0результаты в короткий поворот, q1 dot q2 < 0долгий поворот.
Фальстро

12

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

abs(q1.dot(q2)) > 1-EPS

где EPS - некоторый коэффициент выдумки, чтобы учесть небольшие ошибки из-за ограниченной точности с плавающей запятой. Если (и только если) оба кватерниона представляют одну и ту же ориентацию, то q1 = +- q2и так q1.dot(q2) = +- 1. Если вы хотите убедиться, что они имеют одинаковое вращение (а не просто ориентацию), то удалите abs.


@bogglez правда. Был спрятан в тексте. :)
фальстро

+1, довольно элегантно и, возможно, даже более эффективно, чем мой ответ (при условии использования операций SIMD :)).
Теодрон

Какое математическое обоснование для этого?
fabian789

«Математическое» (в кавычках я не математик :)) обоснование: два вектора длины единицы имеют точечное произведение (или внутреннее произведение), которое равно 0, если они расположены вертикально друг к другу, 1 * 1 = 1, если они указывают точно на в том же направлении, и 1 * 1 * cos (phi) в общем случае с phi их углом ...
нтг

2

Кватернионы хранятся как 4 числа с плавающей точкой или двойные, часто называемые x, y, z и w, где первые три представляют ось, а w - степень вращения вокруг этой оси.

Наивным подходом было бы просто сравнить эти числа двух кватернионов на равенство. Однако, поскольку вычисления с плавающей запятой связаны с ошибкой, вы должны по крайней мере использовать ошибку, часто называемую eps (для epsilon), и сравнивать каждый компонент следующим образом.

    double const eps = 1e-12; // some error threshold
    abs(quat1_x - quat2_x) < eps // similar enough?
    // repeat for other values..

Лучшим тестом было бы рассчитать скалярное произведение двух кватернионов и проверить, близко ли оно к 1,0. Вы должны посмотреть на уравнение кватернионов с sin и cos и просто поставить два кватерниона, тогда вы должны легко понять, почему это работает.


0

Основываясь на всех предложениях использовать Dot и EPS, я обнаружил, что используя (в единстве):

Mathf.Approximately(Mathf.Abs(Quaternion.Dot(transform.rotation, to)), 1.0f)

работал хорошо без меня, чтобы принять решение о размере EPS.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.