Круговое вращение вокруг произвольной оси

Я программирую пользовательские карты Starcraft 2 и получаю некоторые прогеммы с математикой в ​​3D. В настоящее время я пытаюсь создать и повернуть точку вокруг произвольной оси, заданной x, y и z (вектор xyz нормирован).

Я много пробовал и читал много вещей в Интернете, но я просто не могу понять, как он работает правильно. Мой текущий script (вы, вероятно, не знаете язык, но он ничего особенного) является результатом разрыва всего в течение нескольких часов (не работает корректно):

    point CP;
fixed AXY;
point D;
point DnoZ;
point DXY_Z;
fixed AZ;
fixed LXY;
missile[Missile].Angle = (missile[Missile].Angle + missile[Missile].Acceleration) % 360.0;
missile[Missile].Acceleration += missile[Missile].AirResistance;
if (missile[Missile].Parent > -1) {
    D = missile[missile[Missile].Parent].Direction;
    DnoZ = Point(PointGetX(D),0.0);
    DXY_Z = Normalize(Point(SquareRoot(PointDot(DnoZ,DnoZ)),PointGetHeight(D)));
    AZ = MaxF(ACos(PointGetX(DXY_Z)),ASin(PointGetY(DXY_Z)))+missile[Missile].Angle;
    DnoZ = Normalize(DnoZ);
    AXY = MaxF(ACos(PointGetX(DnoZ)),ASin(PointGetY(DnoZ)));
    CP = Point(Cos(AXY+90),Sin(AXY+90));
    LXY = SquareRoot(PointDot(CP,CP));
    if (LXY > 0) {
        CP = PointMult(CP,Cos(AZ)/LXY);
        PointSetHeight(CP,Sin(AZ));
    } else {
        CP = Point3(0.0,0.0,1.0);
    }
} else {
    CP = Point(Cos(missile[Missile].Angle),Sin(missile[Missile].Angle));
}
missile[Missile].Direction = Normalize(CP);
missile[Missile].Position = PointAdd(missile[Missile].Position,PointMult(missile[Missile].Direction,missile[Missile].Distance));

Я просто не могу разобраться в математике. Если вы сможете объяснить это простым языком, что было бы лучшим решением, то код был бы очень полезен (но не совсем так же полезен, потому что я планирую сделать больше 3D-материалов в будущем).

Ответ 1

http://en.wikipedia.org/wiki/Rotation_matrix. Посмотрите раздел матрица вращения от оси и угла. Для вашего удобства здесь нужна матрица. Это немного волосатое. theta - угол, а uux, uy и uz - компоненты x, y и z нормированного вектора оси

Here's the rotation matrix

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

Ответ 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

Ответ 3

Чтобы выполнить 3D-поворот, вам просто нужно смещать точку поворота в начало координат и последовательно поворачивать вокруг каждой оси, сохраняя результаты между каждым поворотом оси для использования со следующей операцией вращения. Алгоритм выглядит следующим образом:

Сдвиньте точку в начало координат.

Point of Rotation = (X1, Y1, Z1)
Point Location    = (X1+A, Y1+B, Z1+C)

(Point Location - Point of Rotation) = (A, B, C).

Выполните поворот вокруг оси Z.

    A' = A*cos ZAngle - B*sin ZAngle
    B' = A*sin ZAngle + B*cos ZAngle
    C' = C.

Затем выполните поворот вокруг оси Y.

    C'' = C'*cos YAngle - A'*sin YAngle
    A'' = C'*sin YAngle + A'*cos YAngle
    B'' = B'   

Теперь выполните последнее вращение вокруг оси X.

    B''' = B''*cos XAngle - C''*sin XAngle
    C''' = B''*sin XAngle + C''*cos XAngle
    A''' = A''

Наконец, добавьте эти значения обратно к исходной точке вращения.

Rotated Point = (X1+A''', Y1+B''', Z1+C''');

Я нашел эту ссылку чтобы быть очень полезной. Он определяет, как выполнять отдельные вращения вокруг осей X, Y и Z.

Математически вы можете определить набор операций следующим образом:

enter image description here

Ответ 4

Вот что вы можете использовать для вращения вокруг любой оси, будь то x, y или z. Rx, Ry и Rz обозначают вращение вокруг асов x, y, z соответственно.

enter image description here

Ответ 5

Для поворота вокруг любой оси в трех измерениях с матрицами у меня есть страница здесь. Связанное объяснение и вывод матриц (здесь) включает в себя следующую матрицу поворота/перевода. Это матрица, которая дает результат вращения точки (x, y, z) по линии через (a, b, c) с вектором направления ⟨u, v, w⟩ на угол tta.

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

Результатом является эта точка в трех измерениях:

повернутая точка

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

Twist and Shout!

Ответ 6

Реализация Python, работала для меня.

cos180=-1
sin180=0

rotmatrix=np.zeros((3,3))
rotmatrix[0][0]=cos180 + rotaxis[0]**2 * (1-cos180)
rotmatrix[0][1]=rotaxis[0]*rotaxis[1] * (1-cos180) - rotaxis[2] * sin180
rotmatrix[0][2]=rotaxis[0]*rotaxis[2] * (1-cos180) + rotaxis[1] * sin180

rotmatrix[1][0]=rotaxis[1]*rotaxis[0] * (1-cos180) + rotaxis[2] * sin180
rotmatrix[1][1]=cos180 + rotaxis[1]**2 * (1-cos180)
rotmatrix[1][2]=rotaxis[1]*rotaxis[2] * (1-cos180) - rotaxis[0] * sin180

rotmatrix[2][0]=rotaxis[2]*rotaxis[0] * (1-cos180) - rotaxis[1] * sin180
rotmatrix[2][1]=rotaxis[2]*rotaxis[1] * (1-cos180) + rotaxis[0] * sin180
rotmatrix[2][2]=cos180 + rotaxis[2] ** 2 * (1-cos180)