Получение оси / угла поворота из двух пар трех точек (или двух пар двух векторов) - PullRequest
8 голосов
/ 12 января 2011

Обратите внимание, что, хотя это звучит похоже, это не обычный вопрос «как повернуть один вектор на другой».

Я хотел бы вывести аффинное преобразование (в матричной или кватернионной + векторной форме) из двух наборов из 3 точек. Их можно рассматривать как «точки маркеров» на твердых телах или как конечные точки векторов «вперед-вверх». Перемещение и ротация необходимы, масштабирование не требуется. Кроме того, решение «кватернион + вектор» было бы плюсом, поскольку это позволило бы мне втиснуть еще 1/3 экземпляра в пакет чертежа (8 униформ вместо 12). Намерение состоит в том, чтобы иметь систему для определения позы (сочлененных или нет) ридид тел интуитивно понятным способом, без необходимости поддерживать сложную иерархию и ходить по ней.

Первое очевидное упрощение состоит в том, чтобы исключить поступательную часть путем выбора одной из точек и вычитания «пункта назначения» из соответствующей «начальной» точки. Теперь нам нужно иметь дело только с вращением.

Существует хорошо известное вычислительно недорогое решение построения кватерниона, который вращает один вектор на другой, а именно q (cross (v1, v2); sqrt (v1.len_sq * v2.len_sq) + dot (v1, v2 )) или q (крестик (v1, v2); 1 + точка (v1, v2)) для векторов единичной длины. К сожалению, этот метод не имеет понятия «направление вверх» и поэтому всегда вращается по самой короткой дуге (что приведет к смещению объектов). Наивно было бы просто использовать этот метод для обоих векторов и умножить кватернионы вместе, но это, очевидно, не сработает так просто. Что нужно сделать, это выбрать один из двух векторов (назовем этот «вперед») и создать кватернион для этого, затем повернуть другой («вверх») вектор с помощью этого кватерниона, а затем построить второй кватернион для повернутого вектора «вверх» (и целевого вектора «вверх») и, наконец, умножьте второй на первый кватернион. Насколько я могу судить, это будет правильно, но это также ужасно сложно.

Теперь ... что касается матриц вращения, мне известен "метод триады", который я понимаю следующим образом: - ортонормировать пары векторов (начало и конец) - Это приводит к двум ортонормированным базам, которые являются соответствующими вращательными матрицами для начала и конца из «общей системы отсчета». Неважно, что это за система отсчета, важно только то, что она одинакова для обоих. - S - преобразование из «общего кадра» в начальный кадр, а D - преобразование в конечный кадр соответственно. - Следовательно, S -1 * D * v преобразует любую точку из начальной в конечную систему координат (проходя через общую систему отсчета). - S -1 == S T , поскольку это ортонормированная матрица, и S T * x = x * S - Следовательно: S T * D * v = D * S * v

Это должно сработать, но все равно кажется довольно сложным для чего-то, что на самом деле должно быть действительно очень простым.

Есть ли более простое и понятное решение?

Ответы [ 3 ]

2 голосов
/ 30 ноября 2013

Ваше «ужасно сложное» кватернионное решение обычно не будет работать.Вы должны проецировать вторую пару векторов на плоскость, ортогональную оси первого вращения, чтобы убедиться, что второе вращение ортогонально первому.Вы заинтересованы: http://robokitchen.tumblr.com/post/67060392720/finding-a-rotation-quaternion-from-two-pairs-of-vectors

До вращения: u0, v0.После поворота: u2, v2.

Quaternion q2 = Quaternion::fromTwoVectors(u0, u2);
Vector v1 = v2.rotate(q2.conjugate());
Vector v0_proj = v0.projectPlane(u0);
Vector v1_proj = v1.projectPlane(u0);
Quaternion q1 = Quaternion::fromTwoVectors(v0_proj, v1_proj);
return (q2 * q1).normalized();

Я не уверен, что это то решение, которое вам нужно, но код работает на удивление быстро.

1 голос
/ 18 сентября 2012

Мы должны решить эту же проблему. Вот как я это делаю:

Назовите точки P и W, поэтому у нас есть P1..P3 и W1..W3

Построить три вектора в каждом пространстве, вот так

A1 = P2-P1
A2 = P3-P1
A3 = A1 x A2

и

B1 = W2-W1
B2 = W3-W1
B3 = B1 x B2

Эти две пары из трех векторов составляют неортогональный базис, и вы хотите найти, как представить свои декартовы оси (x y и z) в одном пространстве, чтобы вы могли найти их в другом. Для этого создайте матрицу так, чтобы ее столбцы были тремя векторами, найденными выше. Затем инвертировать эту матрицу, если эта инверсия не удалась, то неортогональный базис не охватывает пространство, и проблема не может быть решена.

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

Если мы назовем эту матрицу R и обозначим R [строку, столбец] в качестве нашей записи, тогда строки (или столбцы, в зависимости от того, как вы используете матрицу) окончательной матрицы преобразования будут иметь вид:

B1 * R[0,0] + B2* R[1,0] + B3 * R[2,0]
B1 * R[0,1] + B2* R[1,1] + B3 * R[2,1]
B1 * R[0,2] + B2* R[1,2] + B3 * R[2,2]

Теперь, поскольку один из столбцов исходной матрицы до инверсии был пересечением двух других столбцов, возможно, возможно оптимизировать инверсию матрицы. Я не удосужился сделать это - особенно потому, что в нашем случае три точки P1..P3 не меняются, и поэтому инвертированная матрица может быть кэширована.

Этот метод имеет то преимущество, что если у вас есть полуприличная матрица / векторная библиотека, ее очень просто реализовать. И он не использует углы, что всегда хорошо.

1 голос
/ 12 января 2011

Для работы только с частью вращения ваш второй метод будет работать, и я подозреваю, что он будет работать хорошо. В качестве альтернативы вы можете использовать гибрид этих двух методов, который может быть немного проще. Предположим, две пары двух векторов, которые вы создали выше, каждая пара в своем собственном векторном пространстве. Вычислить ортормальный базис каждой пары и назвать их X 0 и X 1 в одном векторном пространстве, а также соответствующие им векторы Y 0 и Y 1 в другом векторном пространстве. Теперь вам нужно вычислить два кватернионных вращения:

1) q 0 поворачивается X 0 и X 1 до X ' 0 и X' 1 соответственно, так что X ' 0 = Y 0 . X ' 1 и Y 1 теперь должны быть в одной плоскости с нормальной плоскостью X' 0 = Y 0 .

2) q 1 поворачивает X ' 1 до X' ' 1 = Y 1 . Все, что вам нужно сделать, это вычислить угол между векторами, так как вы уже знаете, что вектор вращения будет просто X ' 1 x Y 1 = X' 0 = Y 0

Вы можете вычислить q = q 1 * q 0 , чтобы выполнить вращение за один шаг.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...