

= 3-D Вращение

_Плохая новость: 3D вращение осуществляется с помощью матричного исчисления.  +
Хорошая новость: Если вы не понимаете, исчисление, есть два простых правила, как вы запомните это._


+



*3D поворот -* это безумная, математические операции, где необходимо умножить все вершины объекта с помощью четырех чисел с плавающей точкой; умножение называется конкатенация, массив из четырех чисел {x,y,z,w} называется кватернион. Не беспокойтесь, 3D движок делает тяжелую работу за вас. Все, что вам нужно знать:


*Кватернион -* это объект, способный к глубокой заморозки и хранения вращения, которые можно применить к 3D-объектам.



== Использование Кватернионов для Вращения

Для хранения вращения в Кватернионе, необходимо указать две вещи: угол и ось вращения.


*  Угол поворота определяется как кратное числу PI. 
*  Оси вращения определяется вектором: в терминах “тангаж(pitch), “рыскание(yaw), и “крен(roll).

+



Пример:


[source,java]

----

/* Это кватернион хранится 180 градусов вращении по крену с */ 
Quaternion roll180 = new Quaternion(); 
roll180.fromAngleAxis( FastMath.PI , new Vector3f(0,0,1) ); 
/* Вращение применяется: Крен объекта 180 градусов. */ 
thingamajig.setLocalRotation( roll180 );

----

Так как же выбрать правильные цифры для Кватернионных параметров? Я дам вам мой чит-лист:


+


[cols="3", options="header"]
|===

a| *Поворот вокруг Оси?* 
a| *Использование этой оси!* 
a| *Примеры такого вращения* 

a|X axis 
a| (1,0,0) 
a| Тангаж самолета. Кивок головой. 

a|Y axis 
a| (0,1,0) 
a| Рыскание самолета. Автомобиль поворачивает. Покачивание головой. 

a|Z axis 
a| (0,0,1) 
a| Крен самолета. Склонив голову. 

|===

+

Примечание: эти три наиболее распространенные примеры - технически можно вращать вокруг любой оси, выраженной вектором.


+


[cols="3", options="header"]
|===

a| *Угол?* 
a| *Использование Радиан!* 
a| *Пример* 

<a|45 градусов  
a| FastMath.PI / 4 
a| восьмая часть круга 

<a|90 градусов  
a| FastMath.PI / 2 
a| четверть круга, 3 ч 

a|180 градусов 
a| FastMath.PI 
a| полукруг, 6 часов 

a|270 градусов 
a| FastMath.PI * 3 / 2 
a| три четверти круга, 9 часов 

a|360 градусов 
a| FastMath.PI * 2 
a| полный круг, 12 часов  emoji:wink 

a|`g` градусов 
a| FastMath.PI * g / 180 
a| любой угол `g` 

|===

+

*Важно:* Вы должны указать углы в link:https://ru.wikipedia.org/wiki/Радиан[Радианах] (или кратные доли PI). Если вы используете градусы, вы просто получите бесполезные результаты.


+

Как использовать эту таблицы, чтобы задать, некоторый поворот:


.  Выбрать соответствующую ось вектора из таблицы.
.  Выберите из таблицы соответствующий значение угла в радианах.
.  Создать Кватернион для хранения этот поворота. `… fromAngleAxis( radians , vector )`
.  Примените Кватернионов в узле, чтобы повернуть его. `… setLocalRotation(…)`

Кватернион объекты могут использоваться так часто, как вы захотите, можете дать им значимое имя, как `roll90, pitch45, yaw180`. 


link:http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation[Подробнее о Кватернионах]…



== Пример Кода

[source,java]

----

/* Мы начинаем с горизонтальной объекта */ 
Cylinder cylinder = new Cylinder("post", 10, 10, 1, 10);
cylinder.setModelBound(new BoundingBox());
/* Создать 90 градусов-тангажа Кватернионом. */
Quaternion pitch90 = new Quaternion();
pitch90.fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0));
/* Применить поворот к объекту */
cylinder.setLocalRotation(pitch90);
/* Обновление модели. Теперь она вертикальна. */
cylinder.updateModelBound();
cylinder.updateGeometry();

----


== Интерполяции Вращения

Можно указать на два оборота, а затем jme расчета (интерполяция) действия между двумя вращениями:


*  com.jme3.math.Quaternion, slerp() – хранить интерполированный шаг между двух поворотов
**  link:http://www.jmonkeyengine.com/doc/com/jme/math/Quaternion.html[com.jme.math.Quaternion]
**  link:http://www.jmonkeyengine.com/doc/com/jme/math/TransformQuaternion.html[com.jme.math.TransformQuaternion]



== "Добавление" Вращения

Вы можете сцепить (добавить) поворотов: это означает, что вы поворачиваете объект сначала вокруг одной оси, потом вокруг другого, в один шаг.


`Quaternion myRotation =  pitch90.mult(roll45); /* тангаж и крен */`



== Поиск и устранение ошибок при Поворотах

Does the object end up in an unexpected location, or at an unexpected angle? If you are getting weird results, check the following:


.  3-D преобразования некоммутативный! Это означает, что есть огромная разница то ли вы перемещаете узел, а затем поворачиваете его вокруг оси, или сначала поворачиваете узел вокруг оси, а затем перемещаете его. Убедись, что код делает то, что ты хочешь сделать.
. Вы намерены вращать относительно объекта-источника вдоль оси, или относительно другого точка опоры за пределами объекта? Если вы пытаетесь повернуть объект вокруг точки поворота, вы должны создать (невидимый) узел стержень первым, и присоединить объект к нему. Затем примените вращение на родительский узел стержень, не для потомка а для самого объекта!
.  Вы вводите угол в градусах(0 - 360°) или радианах (0 - 2*PI)? 3D движок ожидает в радианах, поэтому убедитесь в том, что вы преобразовали ваши значения! Формула: `g° = FastMath.PI * g / 180`


== Совет: Матрица Преобразования

Это как раз о повороте, но есть три типа 3-D преобразований: <<вращение#,вращение>>, <<масштабирование#,масштабирование>>, и <<перемещение#,Перемещение>>.


Вы можете делать все преобразования в отдельных этапах (а затем обновить геометрию и границы объектов), или вы можете объединить их и преобразовать объект за один шаг.Если у вас много повторяющихся движений происходящих в игре, вам стоит больше узнать об матриц преобразования, для оптимизации. JME также может помочь вам интерполировать действия между двумя фиксированными преобразованиями.


+



*  com.jme3.math.Transform, interpolateTransforms() – интерполировать шаг между двумя преобразованиями
**  link:http://www.jmonkeyengine.com/doc/com/jme/math/TransformMatrix.html[com.jme.math.TransformMatrix]

