Я пытаюсь позволить пользователю моего приложения вращать трехмерный объект, нарисованный в центре экрана, перетаскивая палец на экране. Горизонтальное движение на экране означает вращение вокруг фиксированной оси Y, а вертикальное движение означает вращение вокруг оси X. У меня проблема в том, что если я просто позволю вращение вокруг одной оси, объект вращается нормально, но как только я ввожу второе вращение, объект не вращается, как ожидалось.
Вот картина того, что происходит:
Синяя ось представляет мою фиксированную ось. Представьте себе экран с фиксированной синей осью. Это то, что я хочу, чтобы объект вращался относительно. То, что происходит, в красном.
Вот что я знаю:
- Первое вращение вокруг Y (0, 1, 0) заставляет модель двигаться из синего пространства (назовите это пространство A) в другое пространство (назовите это пространство B)
- Попытка повернуть снова, используя вектор (1, 0, 0), вращается вокруг оси x в пространстве B, а НЕ в пространстве A, что я не хочу делать.
Вот что я попробовал, учитывая то, что я (думаю) я знаю (опуская W координаты для краткости):
- Сначала поверните вокруг Y (0, 1, 0), используя кватернион.
- Преобразовать вращение Y Quaternion в Матрицу.
- Умножьте матрицу вращения Y на мою фиксированную ось x Vector (1, 0, 0), чтобы получить ось X относительно нового пространства.
- Поверните вокруг этого нового вектора X с помощью кватерниона.
Вот код:
private float[] rotationMatrix() {
final float[] xAxis = {1f, 0f, 0f, 1f};
final float[] yAxis = {0f, 1f, 0f, 1f};
float[] rotationY = Quaternion.fromAxisAngle(yAxis, -angleX).toMatrix();
// multiply x axis by rotationY to put it in object space
float[] xAxisObjectSpace = new float[4];
multiplyMV(xAxisObjectSpace, 0, rotationY, 0, xAxis, 0);
float[] rotationX = Quaternion.fromAxisAngle(xAxisObjectSpace, -angleY).toMatrix();
float[] rotationMatrix = new float[16];
multiplyMM(rotationMatrix, 0, rotationY, 0, rotationX, 0);
return rotationMatrix;
}
Это не работает, как я ожидаю. Вращение, кажется, работает, но в какой-то момент горизонтальное движение не вращается вокруг оси Y, а вращается вокруг оси Z.
Я не уверен, что мое понимание неверно или что-то еще вызывает проблему. У меня есть некоторые другие преобразования, которые я делаю с объектом, кроме вращения. Я перемещаю объект в центр перед применением вращения. Я поворачиваю его, используя матрицу, возвращенную из моей функции выше, затем я перевожу ее на -2 в направлении Z, чтобы я мог видеть объект. Я не думаю, что это портит мои вращения, но вот код для этого в любом случае:
private float[] getMvpMatrix() {
// translates the object to where we can see it
final float[] translationMatrix = new float[16];
setIdentityM(translationMatrix, 0);
translateM(translationMatrix, 0, translationMatrix, 0, 0f, 0f, -2);
float[] rotationMatrix = rotationMatrix();
// centers the object
final float[] centeringMatrix = new float[16];
setIdentityM(centeringMatrix, 0);
float moveX = (extents.max[0] + extents.min[0]) / 2f;
float moveY = (extents.max[1] + extents.min[1]) / 2f;
float moveZ = (extents.max[2] + extents.min[2]) / 2f;
translateM(centeringMatrix, 0, //
-moveX, //
-moveY, //
-moveZ //
);
// apply the translations/rotations
final float[] modelMatrix = new float[16];
multiplyMM(modelMatrix, 0, translationMatrix, 0, rotationMatrix, 0);
multiplyMM(modelMatrix, 0, modelMatrix, 0, centeringMatrix, 0);
final float[] mvpMatrix = new float[16];
multiplyMM(mvpMatrix, 0, projectionMatrix, 0, modelMatrix, 0);
return mvpMatrix;
}
Я застрял на этом в течение нескольких дней. Помощь очень ценится.
================================================== ================
ОБНОВИТЬ:
Заставить это работать в Unity просто. Вот некоторый код, который вращает куб с центром в начале координат:
public class CubeController : MonoBehaviour {
Vector3 xAxis = new Vector3 (1f, 0f, 0f);
Vector3 yAxis = new Vector3 (0f, 1f, 0f);
// Update is called once per frame
void FixedUpdate () {
float horizontal = Input.GetAxis ("Horizontal");
float vertical = Input.GetAxis ("Vertical");
transform.Rotate (xAxis, vertical, Space.World);
transform.Rotate (yAxis, -horizontal, Space.World);
}
}
Часть, которая заставляет повороты вести себя так, как я ожидаю, является Space.World
параметром Rotate
функции преобразования.
Если бы я мог использовать Unity, я бы, к сожалению, сам должен был написать код этого поведения.