Я намагаюся дозволити користувачеві мого додатка обертати 3D-об’єкт, намальований в центрі екрана, перетягуючи пальцем по екрану. Горизонтальний рух на екрані означає обертання навколо нерухомої осі Y, а вертикальний рух означає обертання навколо осі X. Проблема, яка у мене виникає, полягає в тому, що якщо я просто дозволю обертання навколо однієї осі, об'єкт обертається нормально, але як тільки я ввожу друге обертання, об'єкт не обертається так, як очікувалося.
Ось картина того, що відбувається:
Синя вісь представляє мою нерухому вісь. Зобразіть екран із фіксованою синьою віссю. Це те, що я хочу, щоб об'єкт обертався по відношенню до. Те, що відбувається, - червоним кольором.
Ось що я знаю:
- Перше обертання навколо Y (0, 1, 0) змушує модель переміщатися з синього простору (називати цей простір A) в інший простір (називати цей простір B)
- Повторна спроба обертання за допомогою вектора (1, 0, 0) обертається навколо осі х у просторі B НЕ в просторі A, що я не маю на увазі робити.
Ось що я спробував, враховуючи те, що я (думаю) знаю (залишаючи W координату для стислості):
- Спочатку обертайтеся навколо Y (0, 1, 0), використовуючи кватерніон.
- Перетворіть обертання Y Кватерніона в матрицю.
- Помножте матрицю обертання 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;
}
Я затримався на цьому кілька днів. Допомога дуже цінується.
===================================================== ================
ОНОВЛЕННЯ:
Домогтися цього працювати в Єдності просто. Ось код, який обертає куб із центром у походження:
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, я б, на жаль, мав сам кодувати цю поведінку.