Использование кватернионов для представления вращения не является сложным с алгебраической точки зрения.Лично мне трудно рассуждать визуально о кватернионах, но формулы, используемые при их использовании для вращений, довольно просты.Я приведу здесь базовый набор справочных функций. 1 (см. Также этот прекрасный ответ hosolmaz , в котором он упаковывает их вместе, чтобы создать удобный класс Quaternion.)
Вы можете думать о кватернионах (для наших целей) как о скаляре плюс трехмерный вектор - абстрактно, w + xi + yj + zk
, здесь представленный простым кортежем (w, x, y, z)
.Пространство трехмерных вращений полностью представлено подпространством кватернионов, пространством единица кватернионов, поэтому вы хотите убедиться, что ваши кватернионы нормализованы.Вы можете сделать это так же, как вы бы нормализовали любой 4-вектор (т.е. величина должна быть близка к 1; если это не так, уменьшите значения на величину):
def normalize(v, tolerance=0.00001):
mag2 = sum(n * n for n in v)
if abs(mag2 - 1.0) > tolerance:
mag = sqrt(mag2)
v = tuple(n / mag for n in v)
return v
Обратите вниманиечто для простоты следующие функции предполагают, что значения кватернионов уже нормализованы .На практике вам нужно время от времени перенормировать их, но лучший способ справиться с этим будет зависеть от проблемной области.Эти функции обеспечивают только самые основы, только для справочных целей.
Каждый поворот представлен единичным кватернионом, а конкатенации вращений соответствуют умножениям единичных кватернионов.Формула 2 для этого выглядит следующим образом:
def q_mult(q1, q2):
w1, x1, y1, z1 = q1
w2, x2, y2, z2 = q2
w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
y = w1 * y2 + y1 * w2 + z1 * x2 - x1 * z2
z = w1 * z2 + z1 * w2 + x1 * y2 - y1 * x2
return w, x, y, z
Чтобы повернуть вектор на кватернион, вам также потребуется сопряжение кватерниона.Это просто:
def q_conjugate(q):
w, x, y, z = q
return (w, -x, -y, -z)
Теперь умножение кватерниона на вектор так же просто, как преобразование вектора в кватернион (установив w = 0
и оставив x
, y
и z
одинаковыми)а затем умножить q * v * q_conjugate(q)
:
def qv_mult(q1, v1):
q2 = (0.0,) + v1
return q_mult(q_mult(q1, q2), q_conjugate(q1))[1:]
Наконец, вам нужно знать, как преобразовать вращение вокруг оси в кватернионы.Также легко!Здесь имеет смысл «санировать» ввод и вывод, вызывая normalize
.
def axisangle_to_q(v, theta):
v = normalize(v)
x, y, z = v
theta /= 2
w = cos(theta)
x = x * sin(theta)
y = y * sin(theta)
z = z * sin(theta)
return w, x, y, z
И обратно:
def q_to_axisangle(q):
w, v = q[0], q[1:]
theta = acos(w) * 2.0
return normalize(v), theta
Вот краткий пример использования.Последовательность поворотов на 90 градусов вокруг осей x, y и z вернет вектор на оси y в исходное положение.Этот код выполняет эти вращения:
x_axis_unit = (1, 0, 0)
y_axis_unit = (0, 1, 0)
z_axis_unit = (0, 0, 1)
r1 = axisangle_to_q(x_axis_unit, numpy.pi / 2)
r2 = axisangle_to_q(y_axis_unit, numpy.pi / 2)
r3 = axisangle_to_q(z_axis_unit, numpy.pi / 2)
v = qv_mult(r1, y_axis_unit)
v = qv_mult(r2, v)
v = qv_mult(r3, v)
print v
# output: (0.0, 1.0, 2.220446049250313e-16)
Имейте в виду, что эта последовательность вращений не вернет все векторов в одну и ту же позицию;например, для вектора на оси x он будет соответствовать повороту на 90 градусов вокруг оси y.(Имейте в виду правило правой руки; положительное вращение вокруг оси y толкает вектор на оси x в отрицательную z область.)
v = qv_mult(r1, x_axis_unit)
v = qv_mult(r2, v)
v = qv_mult(r3, v)
print v
# output: (4.930380657631324e-32, 2.220446049250313e-16, -1.0)
Как всегдаПожалуйста, дайте мне знать, если вы обнаружите какие-либо проблемы здесь.
1.Они адаптированы из учебника OpenGL , заархивированного здесь .
2.Формула умножения кватернионов выглядит как гнездо сумасшедшей крысы, но вывод прост (если утомителен).Просто отметьте сначала, что ii = jj = kk = -1
;тогда это ij = k
, jk = i
, ki = j
;и, наконец, ji = -k
, kj = -i
, ik = -j
.Затем умножьте два кватерниона, распределяя слагаемые и переставляя их на основе результатов каждого из 16 умножений.Это также помогает проиллюстрировать , почему вы можете использовать кватернионы для представления вращения;последние шесть тождеств следуют правилу правой руки, создавая биекции между поворотами от i
до j
и поворотами вокруг k
и т. д.