Я программирую пользовательские карты Starcraft 2 и получаю некоторые прогеммы с математикой в 3D. В настоящее время я пытаюсь создать и повернуть точку вокруг произвольной оси, заданной x, y и z (вектор xyz нормирован).
Я много пробовал и читал много вещей в Интернете, но я просто не могу понять, как он работает правильно. Мой текущий script (вы, вероятно, не знаете язык, но он ничего особенного) является результатом разрыва всего в течение нескольких часов (не работает корректно):
Я просто не могу разобраться в математике. Если вы сможете объяснить это простым языком, что было бы лучшим решением, то код был бы очень полезен (но не совсем так же полезен, потому что я планирую сделать больше 3D-материалов в будущем).
Ответ 2
Полезным методом для таких поворотов является их выполнение с помощью quaternions. На практике я нашел их более удобными в использовании и добавил дополнительный бонус, избегая Gimbal lock.
Здесь есть хорошая прогулка, объясняющая, как и почему они используются для вращения вокруг произвольной оси (это ответ на вопрос пользователя). Это немного более высокий уровень и будет хорошо для тех, кто не знаком с этой идеей, поэтому я рекомендую начинать там.
Обновить во избежание коррозии ссылок
Текст со связанного сайта:
Как вы уже не сомневались, вращение вокруг оси
проходящей через начало координат и точку (a,b,c)
на единичной сфере в
трехмерное является линейным преобразованием и, следовательно, может быть
представленный матричным умножением. Мы дадим очень гладкий
метод определения этой матрицы, но оценить компактность
формулы будет разумным начать с нескольких замечаний.
Вращения в трехмерном пространстве - довольно специальные линейные
преобразований, не в последнюю очередь потому, что они сохраняют длины
векторов, а также (при вращении двух векторов) углы между
векторы. Такие преобразования называются "ортогональными", и они
представленные ортогональными матрицами:
M M' = I
где удобно обозначить транспонирование на '. Другими словами,
транспонирование ортогональной матрицы является ее обратной.
Рассмотрим данные, необходимые для определения преобразования.
Вы уже обозначили ось вращения, ai + bj + ck
,
удобно считать единичным вектором. Единственной другой базой данных является
угол поворота, который из-за отсутствия более естественного характера я буду
обозначим через г (для вращения?) и которое мы будем называть в
радиан.
Теперь вращение на самом деле немного особенное даже среди ортогональных
преобразований, и на самом деле их также называют специальными ортогональными
преобразования (или матрицы) в силу их принадлежности быть
"сохранение ориентации". Сравните их с отражениями, которые
а также сохранение длины и угла, и вы обнаружите, что геометрический
характерной для сохранения ориентации (или "ручности", если вы
предпочитают) имеет численный аналог в определителе матрицы.
Матрица вращения имеет определитель 1, а матрица отражения имеет
определитель -1. Оказывается, что произведение (или состав) двух
повороты снова являются поворотными, что согласуется с тем, что
детерминантом произведения является произведение определителей (или 1 в
случай вращения).
Теперь мы можем описать пошаговый подход, который можно было бы выполнить для
построить желаемую матрицу (прежде чем мы сократим весь процесс и
перейдите к Ответ!). Рассмотрим сначала шаг, на котором мы поворачиваем
единичный вектор:
u = ai + bj + ck
так что он совпадает с одним из "стандартных" единичных векторов, возможно
k (положительная ось z). Теперь мы знаем, как вращаться вокруг оси z;
это вопрос обычного преобразования 2x2 на x, y
только координаты:
cos(r) sin(r) 0
M = -sin(r) cos(r) 0
0 0 1
Наконец, нам нужно "отменить" начальное вращение, которое взяло u в k,
что легко, потому что обратное этому преобразованию (мы
вспомните), представленную матрицей транспонирования. Другими словами, если
матрица R представляет собой поворот, принимающий u в k, тогда R 'переводит k в u,
и мы можем записать состав таких преобразований:
R' M R
Нетрудно проверить, что это произведение матриц при умножении
раз u, возвращает u обратно:
R' M R u = R' M k = R' k = u
Поэтому это действительно вращение вокруг оси, определяемой u.
Одним из преимуществ этого выражения является то, что он чисто отделяет
зависимость М от угла г от зависимости Q и Q 'от
вектор "оси" u. Однако, если мы должны выполнить вычисления в
подробно, мы, очевидно, будем иметь много матричного умножения.
Итак, к ярлыку. Оказывается, когда вся пыль оседает, что
умножение между вращениями изоморфно умножению единицы
кватернионы. Кватернионы, если вы их раньше не видели, являются
вид четырехмерного обобщения комплексных чисел. Они были
"изобретен" Уильямом Гамильтоном в 1843 году:
[Сэр Уильям Роуэн Гамильтон]
http://www-gap.dcs.st-and.ac.uk/~history/Mathematicians/Hamilton.html
и сегодня программисты 3D-графики сильно зависят от своего долга.
Каждый единичный кватернион q = q0 + q1*i + q2*j + q3*k
затем определяет матрицу вращения:
(q0² + q1² - q2² - q3²) 2(q1q2 - q0q3) 2(q1q3 + q0q2)
Q = 2(q2q1 + q0q3) (q0² - q1² + q2² - q3²) 2(q2q3 - q0q1)
2(q3q1 - q0q2) 2(q3q2 + q0q1) (q0² - q1² - q2² + q3²)
Чтобы проверить, что Q - ортогональная матрица, т.е. что Q Q' = I
, означает
сущность, что строки Q образуют ортонормированный базис. Таким образом, для
Например, первая строка должна иметь длину 1:
(q0² + q1² - q2² - q3²)² + 4(q1q2 - q0q3)² + 4(q1q3 + q0q2)²
= (q0² + q1² - q2² - q3²)² + 4(q1q2)² + 4(q0q3)² + 4(q1q3)² + 4(q0q2)²
= (q0² + q1² + q2² + q3²)²
= 1
а первые две строки должны иметь нулевой результат:
[ (q0² + q1² - q2² - q3²), 2(q1q2 - q0q3), 2(q1q3 + q0q2) ]
* [ 2(q2q1 + q0q3), (q0² - q1² + q2² - q3²), 2(q2q3 - q0q1) ]
= 2(q0² + q1² - q2² - q3²)(q2q1 + q0q3)
+ 2(q1q2 - q0q3)(q0² - q1² + q2² - q3²)
+ 4(q1q3 + q0q2)(q2q3 - q0q1)
= 4(q0²q1q2 + q1²q0q3 - q2²q0q3 - q3²q2q1)
+ 4(q3²q1q2 - q1²q0q3 + q2²q0q3 - q0²q2q1)
= 0
В общем случае также можно показать, что det(Q) = 1
, и, следовательно, Q
действительно поворот.
Но вокруг какой оси Q вращение? И под каким углом? Что ж,
заданный угол r и единичный вектор:
u = ai + bj + ck
как и раньше, соответствующий кватернион равен:
q = cos(r/2) + sin(r/2) * u
= cos(r/2) + sin(r/2) ai + sin(r/2) bj + sin(r/2) ck
Таким образом, с помощью
q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c,
мы можем получить искомое свойство, что умножение на Q "фиксирует" u:
Q u = u
Вместо того, чтобы перебирать длинную алгебру, сделайте простой пример.
Пусть u = 0i + 0.6j + 0.8k
- наш единичный вектор, а r = pi - наш угол поворота.
Тогда кватернион равен:
q = cos(pi/2) + sin(pi/2) * u
= 0 + 0i + 0.6j + 0.8k
и матрицы вращения:
-1 0 0
Q = 0 -0.28 0.96
0 0.96 0.28
В этом конкретном случае легко проверить, что Q Q '= я и det (Q) = 1.
Также мы вычисляем, что:
Q u = [ 0, -0.28*0.6 + 0.96*0.8, 0.96*0.6 + 0.28*0.8 ]'
= [ 0, 0.6, 0.8 ]'
= u
т. единичный вектор u определяет ось вращения, потому что он "фиксирован" Q.
Наконец, покажем, что угол поворота равен pi (или 180
градусов), рассматривая, как Q действует на единичный вектор в направлении
положительной оси х, перпендикулярной и:
i + 0j + 0k, or as a vector, [ 1, 0, 0 ]'
Тогда Q [ 1, 0, 0 ]' = [-1, 0, 0 ]'
, являющееся вращением [1, 0, 0
] 'через угол pi относительно u.
В качестве ссылки для этого представления поворотов по кватернионам и
некоторые дополнительные методы представления (и то, что они хороши
для), см. подробности здесь:
[Представление трехмерных поворотов]
http://gandalf-library.sourceforge.net/tutorial/report/node125.html
РЕЗЮМЕ
Учитывая угол r в радианах и единичный вектор u = ai + bj + ck или [a, b, c] ', определите:
q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c
и построим из этих значений матрицу вращения:
(q0² + q1² - q2² - q3²) 2(q1q2 - q0q3) 2(q1q3 + q0q2)
Q = 2(q2q1 + q0q3) (q0² - q1² + q2² - q3²) 2(q2q3 - q0q1)
2(q3q1 - q0q2) 2(q3q2 + q0q1) (q0² - q1² - q2² + q3²)
Умножение на Q затем приводит к желаемому вращению, и в частности:
Q u = u