Próbuję pozwolić użytkownikowi mojej aplikacji obrócić obiekt 3D narysowany na środku ekranu, przeciągając palcem po ekranie. Ruch poziomy na ekranie oznacza obrót wokół stałej osi Y, a ruch pionowy oznacza obrót wokół osi X. Problem, jaki mam, polega na tym, że jeśli pozwolę na obrót wokół jednej osi, obiekt obraca się dobrze, ale gdy tylko wprowadzę drugi obrót, obiekt nie obraca się zgodnie z oczekiwaniami.
Oto obraz tego, co się dzieje:
Niebieska oś reprezentuje moją stałą oś. Wyobraź sobie ekran z tą stałą niebieską osią. To właśnie chcę, aby obiekt obracał się w stosunku do. To, co się dzieje, jest na czerwono.
Oto co wiem:
- Pierwszy obrót wokół Y (0, 1, 0) powoduje, że model przesuwa się z niebieskiej przestrzeni (nazwij to miejsce A) na inną przestrzeń (nazwij to miejsce B)
- Próba ponownego obrotu za pomocą wektora (1, 0, 0) obraca się wokół osi x w przestrzeni B NIE w przestrzeni A, co nie jest tym, co mam na myśli.
Oto, co próbowałem, biorąc pod uwagę to, co (myślę) wiem (pomijając zwięzłość W dla zwięzłości):
- Najpierw obróć wokół Y (0, 1, 0) za pomocą ćwiartki.
- Przekształć obrót Y kwaternion na macierz.
- Pomnóż macierz obrotu Y przez moją oś stałą x Wektor (1, 0, 0), aby uzyskać oś X względem nowej przestrzeni.
- Obracaj wokół tego nowego X wektora za pomocą ćwiartki.
Oto kod:
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;
}
To nie działa tak, jak się spodziewam. Obrót wydaje się działać, ale w pewnym momencie ruch poziomy nie obraca się wokół osi Y, wydaje się, że obraca się wokół osi Z.
Nie jestem pewien, czy moje rozumienie jest błędne lub czy coś innego powoduje problem. Mam inne transformacje, które wykonuję na obiekcie oprócz obrotu. Przed zastosowaniem obrotu przesuwam obiekt na środek. Obracam go za pomocą macierzy zwróconej z mojej powyższej funkcji, a następnie tłumaczę -2 w kierunku Z, aby zobaczyć obiekt. Nie sądzę, że to psuje moje rotacje, ale i tak oto kod tego:
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;
}
Utknąłem na tym od kilku dni. Pomoc jest bardzo ceniona.
================================================== ================
AKTUALIZACJA:
Uruchomienie tego w Jedności jest proste. Oto kod, który obraca sześcian wyśrodkowany na początku:
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);
}
}
Część, która powoduje, że obroty zachowują się tak, jak się spodziewam, to Space.World
parametr Rotate
funkcji w transformacji.
Gdybym mógł użyć Unity, zrobiłbym to, niestety, musiałbym sam zakodować to zachowanie.