Я пытаюсь выяснить, как повернуть RotateAxisAngle, чтобы вернуть вращение вокруг этих произвольных осей (или эквивалентные вращения, которые дают одинаковое чистое вращение, не должны быть идентичными). кто нибудь знает как это сделать? Я использую MathGeoLib, но я не вижу обратного пути, чтобы вернуть углы вокруг осей, когда у вас есть только матрица.
Вот код прямого направления (RotateAxisAngle от MathGeoLib):
float4x4 matrixRotation = float4x4::RotateAxisAngle(axisX, ToRadian(rotation.x));
matrixRotation = matrixRotation * float4x4::RotateAxisAngle(axisY, ToRadian(rotation.y));
matrixRotation = matrixRotation * float4x4::RotateAxisAngle(axisZ, ToRadian(rotation.z));
Теперь я хочу вернуться к градусам, относительно этих произвольных осей, в том же порядке (ну, оттяните Z, затем Y, затем X), так что, если бы я сделал это снова, направление вперед получило бы те же чистые вращения.
Вот пример / матрица, соответствующая тому набору вращений, который я выложил выше, если это поможет, при возврате к нему:
axisX:
x 0.80878228 float
y -0.58810818 float
z 0.00000000 float
Rot about that axis:
30.000000 float
axisY:
x 0.58811820 float
y 0.80877501 float
z 0.00000000 float
Rot about that axis:
60.000000 float
axisZ:
x 0.00000000 float
y 0.00000000 float
z 1.0000000 float
Rot about that axis:
40.000000 float
Это формирует эту матрицу, которая хранится в файле и должна извлекать вращения вокруг вышеуказанных осей (без какой-либо информации о первоначально использованных вращениях)
[4][4]
[0x0] 0.65342271 float
[0x1] -0.51652151 float
[0x2] 0.55339342 float
[0x3] 0.00000000 float
[0x0] 0.69324547 float
[0x1] 0.11467478 float
[0x2] -0.71151978 float
[0x3] 0.00000000 float
[0x0] 0.30405501 float
[0x1] 0.84856069 float
[0x2] 0.43300733 float
[0x3] 0.00000000 float
[0x0] 0.00000000 float
[0x1] 0.00000000 float
[0x2] 0.00000000 float
[0x3] 1.0000000 float
Хорошо, я собираюсь сделать еще один удар в этом. Мой первый ответ был для XYZ порядка вращения. Этот ответ для заказа ZYX, теперь, когда я знаю больше о том, как работает MathGeoLib.
MathGeoLib представляет векторы положения как векторы столбцов v = [x y z 1]^T
где ^T
это оператор транспонирования, который переворачивает строки в столбцы (и наоборот). Матрицы вращения предварительно умножают векторы столбцов. Так что, если у нас есть матрица Rx(s)
представляет вращение вокруг оси х на s градусов, затем вращение Ry(t)
представляет вращение вокруг оси Y на t градусов, затем вращение Rz(u)
представляющий вращение вокруг оси z на u градусов, и мы объединяем их и умножаем на v
как Rx(s) Ry(t) Rz(u) v
мы на самом деле применяем вращение z первым. Но мы все еще можем определить углы из объединенной матрицы, просто формулы будут отличаться от более распространенного порядка XYZ.
У нас есть верхние левые блоки матриц вращения следующим образом. (Четвертая строка и столбец — все 0, за исключением диагонального элемента, который равен 1; он никогда не меняется в последующих вычислениях, поэтому мы можем спокойно его игнорировать.) MathGeoLib, похоже, использует левосторонние координаты, поэтому матрицы вращения:
[1 0 0] [ cos t 0 sin t] [ cos u -sin u 0]
Rx(s) = [0 cos s -sin s], Ry(t) = [ 0 1 0], Rz(u) = [ sin u cos u 0]
[0 sin s cos s] [-sin t 0 cos t] [ 0 0 1]
(Обратите внимание на положение — войти в Ry(t)
; это там, потому что мы думаем о координатах в циклическом порядке. Rx(s)
вращается y и z; Ry(t)
вращается z и x; Rz(u)
вращается х и у. поскольку Ry(t)
вращает z и x не в алфавитном порядке, а в циклическом порядке, вращение противоположно направлению, которое вы ожидаете для алфавитного порядка.
Теперь мы умножим матрицы в правильном порядке. Rx(s) Ry(t)
является
[1 0 0][ cos t 0 sin t] [ cos t 0 sin t]
[0 cos s -sin s][ 0 1 0] = [ sin s*sin t cos s -sin s*cos t]
[0 sin s cos s][-sin t 0 cos t] [-cos s*sin t sin s cos s*cos t]
Продукт этого с Rz(u)
является
[ cos t 0 sin t][ cos u -sin u 0]
[ sin s*sin t cos s -sin s*cos t][ sin u cos u 0] =
[-cos s*sin t sin s cos s*cos t][ 0 0 1]
[ cos t*cos u -cos t*sin u sin t]
[ sin s*sin t*cos u+cos s*sin u -sin s*sin t*sin u+cos s*cos u -sin s*cos t]
[-cos s*sin t*cos u+sin s*sin u cos s*sin t*sin u+sin s*cos u cos s*cos t]
Таким образом, мы можем выяснить углы следующим образом:
tan s = -(-sin s * cos t)/(cos s * cos t) = M23/M33 => s = -arctan2(M23,M33)
sin t = M13 => t = arcsin(M13)
tan u = -(-cos t * sin u)/(cos t * cos u) = M12/M11 => u = -arctan2(M12,M11)
Если мы хотим реализовать эти вычисления, нам нужно понять, как матрица индексируется в MathGeoLib. Индексация является основной строкой, точно так же как математическая запись, но индексация начинается с 0 (компьютерный стиль), а не с 1 (математический стиль), поэтому формулы C ++, которые вам нужны,
s = -atan2(M[1][2],M[2][2]);
t = asin(M[0][2]);
u = -atan2(M[0][1],M[0][0]);
Углы возвращаются в радианах, поэтому при желании их необходимо преобразовать в градусы. Вы должны проверить этот результат в случае, когда оси для поворотов Z, Y и X находятся в стандартном положении (001), (010) и (100).
Если мы хотим повернуть вращение вокруг нестандартных осей, как в вашем примере, проблема становится более сложной. Тем не менее, я думаю, что это может быть сделано путем «изменения координат». Так что, если наша матрица тайны вращения matrixRotation
Я полагаю, вы можете просто сформировать «сопряженную» матрицу
M = coordinateChangeMatrix*matrixRotation*coordinateChangeMatrix^{-1}
а затем используйте приведенные выше формулы. Вот coordinateChangeMatrix
будет матрица
[Xaxis0 Xaxis1 Xaxis2 0]
[Yaxis0 Yaxis1 Yaxis2 0]
[Zaxis0 Zaxis1 Zaxis2 0]
[ 0 0 0 1]
где ось X вращения (Xaxis0,Xaxis1,Xaxis2)
, В вашем примере эти цифры будут (0.808...,-0.588...,0)
, Вы должны убедиться, что матрица вращения является ортонормированной, то есть, произведение точки Xaxis с самим собой равно 1, произведение точки Xaxis с другой осью равно 0, и то же самое для любой другой оси. Если матрица изменения координат не является ортонормированной, вычисление все еще может работать, но я точно не знаю.
Обратная матрица изменения координат может быть рассчитана с помощью float4x4::inverseOrthonormal
или если это не ортонормированный вы можете использовать float4x4::inverse
но, как я уже говорил, я не знаю, насколько хорошо это будет работать.
Если вы просто хотите вращение, обращающее вращение, которое вы получили за один шаг, вы можете инвертировать матрицу вращения. float4x4::InverseOrthonormal
должно работать, и это быстро и точно. float4x4::Inverse
также будет работать, но это медленнее и менее точно.
Если вы действительно хотите восстановить углы, это происходит примерно так. (Существует множество различных соглашений, даже для X-Y-Z; я думаю, что это соответствует, но вам, возможно, придется взять транспонирование матрицы или сделать какую-то другую модификацию. Если это не сработает, я могу предложить альтернативы.) Сначала мы следуем Статья в википедии для описания преобразования углов Эйлера в матрицу. В полученной матрице имеем
A11 = cos theta cos psi
A21 = -cos theta sin psi
A31 = sin theta
A32 = -sin phi cos theta
A33 = cos phi cos theta
где phi — вращение вокруг оси x, theta — вращение вокруг оси y, а psi — вращение вокруг оси z. Чтобы восстановить углы, мы делаем
phi = -arctan2(A32,A33)
theta = arcsin(A31)
psi = -arctan2(A21,A11)
Углы могут не точно соответствовать исходным углам, но повороты должны совпадать. arctan2 — это форма с двумя аргументами функции arctan, которая учитывает квадрант точки, представленной аргументом, и правильно обрабатывает углы в 90 градусов.
Учитывая способ представления ваших вращений, я думаю, что вам, возможно, придется использовать вместо этого транспонирование. Это просто: вы просто меняете индексы в приведенных выше формулах:
phi = -arctan2(A23,A33)
theta = arcsin(A13)
psi = -arctan2(A12,A11)
Если ни одна из этих работ не работает, я мог бы ближе взглянуть на библиотеку MathGeoLib и выяснить, что они делают.
Обновить
Я не учел информацию об осях вращения в моем предыдущем ответе. Теперь я думаю, что у меня есть план борьбы с ними.
Идея состоит в том, чтобы «изменить координаты», а затем выполнить операции, как указано выше, в новых координатах. Я немного запутан в деталях, поэтому процесс немного «алхимический» в данный момент. ОП должен попробовать различные комбинации моих предложений и посмотреть, работает ли какое-либо из них … их не слишком много (всего 4 … на данный момент).
Идея состоит в том, чтобы сформировать матрица изменения координат используя координаты осей вращения. Мы делаем это так:
axisX: 0.80878228 -0.58810818 0.00000000 0.00000000
axisY: 0.58811820 0.80877501 0.00000000 0.00000000
axisZ: 0.00000000 0.00000000 1.0000000 0.00000000
and..: 0.00000000 0.00000000 0.00000000 1.0000000
Я только что взял три 3-вектора axisX, axisY, axisZ, дополнил их 0 в конце и добавил строку [0 0 0 1]
внизу.
Мне также нужна обратная сторона этой матрицы. Поскольку система координат является ортонормированной системой отсчета, обратная — это транспонирование. Вы можете использовать InverseOrthonormal
функция в библиотеке; все, что он делает, это формирует транспонирование.
Теперь возьмите свою загадочную матрицу и предварительно умножьте ее на матрицу изменения координат, а затем умножьте ее на обратную матрицу изменения координат. Затем примените одно из двух приведенных выше вычислений с использованием обратных функций триггера. Скрестив пальцы, я думаю это все …
Если это не сработает, то предварительно умножьте загадочную матрицу на обратную матрицу изменения координат и затем умножьте на матрицу изменения координат. Затем примените один или другой набор формул триггера.
Это работает?