У меня есть простая реализация игрового движка сущности / компонента.
Компонент Transform имеет методы для установки локального положения, локального вращения, глобального положения и глобального вращения.
Если для преобразования устанавливается новая глобальная позиция, то локальная позиция также изменяется, чтобы обновить локальную позицию, в этом случае я просто применяю текущую локальную матрицу преобразования к матрице родительского мира преобразования.
До тех пор у меня нет проблем, я могу получить обновленную матрицу локального преобразования.
Но я борюсь за то, как обновить локальное положение и значение поворота в преобразовании. Единственное решение, которое я имею в виду, - это извлечь значения перемещения и поворота из localMatrix of transform.
Для перевода это довольно просто - я просто беру значения 4-го столбца. а как насчет вращения?
Как извлечь углы Эйлера из матрицы преобразования?
Правильно ли такое решение ?:
Чтобы найти вращение вокруг оси Z, мы можем найти разницу между вектором оси X localTransform и вектором оси X parent.localTransform и сохранить результат в Delta, затем: localRotation.z = atan2 (Delta.y, Delta .Икс);
То же самое для вращения вокруг X & Y, просто нужно поменять местами оси.
Майк Дэй написал отличную статью об этом процессе: https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2012/07/euler-angles1.pdf
Это также теперь реализовано в glm, начиная с версии 0.9.7.0, 02.08.2015. Проверьте реализацию .
Чтобы понять математику, вы должны посмотреть на значения, которые находятся в вашей матрице вращения. Кроме того, вы должны знать порядок, в котором были применены повороты для создания матрицы, чтобы правильно извлечь значения.
Матрица вращения из углов Эйлера формируется путем объединения вращений вокруг осей x, y и z. Например, вращение θ градусов вокруг Z можно сделать с помощью матрицы
Подобные матрицы существуют для вращения вокруг осей X и Y:
Мы можем умножить эти матрицы вместе, чтобы создать одну матрицу, которая является результатом всех трех вращений. Важно отметить, что порядок умножения этих матриц важен, поскольку умножение матриц не является коммутативным . Это значит что
Rx*Ry*Rz ≠ Rz*Ry*Rx
. Давайте рассмотрим один из возможных порядков вращения, zyx. Когда три матрицы объединены, это приводит к матрице, которая выглядит следующим образом:где
Cx
косинусx
угла поворота,Sx
синусx
угла поворота и т. д.Теперь задача состоит в том, чтобы извлечь оригинал
x
,y
иz
значения , которые вошли в матрицу.Давайте сначала выясним
x
угол. Если мы знаемsin(x)
иcos(x)
, мы можем использовать обратную функцию тангенса,atan2
чтобы вернуть нам наш угол. К сожалению, эти значения не появляются сами по себе в нашей матрице. Но, если мы более внимательно посмотрим на элементыM[1][2]
иM[2][2]
, мы увидим, что мы знаем,-sin(x)*cos(y)
а такжеcos(x)*cos(y)
. Поскольку касательная функция представляет собой отношение противоположных и смежных сторон треугольника, масштабирование обоих значений на одну и ту же величину (в данном случаеcos(y)
) даст одинаковый результат. Таким образом,Теперь попробуем получить
y
. Мы знаемsin(y)
изM[0][2]
. Если бы у нас было cos (y), мы могли бы использоватьatan2
снова, но у нас нет этого значения в нашей матрице. Однако из-за пифагорейской идентичности мы знаем, что:Итак, мы можем рассчитать
y
:Наконец, нам нужно рассчитать
z
. В этом подход Майка Дея отличается от предыдущего ответа. Поскольку в этот момент мы знаем величинуx
иy
вращение, мы можем построить матрицу вращения XY и найти величинуz
вращения, необходимую для соответствия целевой матрице.RxRy
Матрица выглядит следующим образом :Поскольку мы знаем, что
RxRy
*Rz
равен нашей входной матрицеM
, мы можем использовать эту матрицу, чтобы вернуться кRz
:Обратной матрицы вращения является транспонированной , поэтому мы можем расширить это:
Теперь мы можем решить для
sinZ
иcosZ
путем выполнения умножения матриц. Нам нужно только рассчитать элементы[1][0]
и[1][1]
.Вот полная реализация для справки:
источник
M[1][3]
с помощьюM[1][2]
иM[2][3]
сM[2][2]
.