Sto cercando di consentire all'utente della mia app di ruotare un oggetto 3D disegnato al centro dello schermo trascinando il dito sullo schermo. Un movimento orizzontale sullo schermo significa rotazione attorno ad un asse Y fisso, mentre un movimento verticale significa rotazione attorno all'asse X. Il problema che sto riscontrando è che se consento solo la rotazione attorno ad un asse l'oggetto ruota bene, ma non appena introduco una seconda rotazione l'oggetto non ruota come previsto.
Ecco una foto di ciò che sta accadendo:
L'asse blu rappresenta il mio asse fisso. Immagina lo schermo con questo asse blu fisso. Questo è ciò a cui voglio ruotare l'oggetto in relazione. Quello che sta succedendo è in rosso.
Ecco quello che so:
- La prima rotazione intorno a Y (0, 1, 0) fa spostare il modello dallo spazio blu (chiama questo spazio A) in un altro spazio (chiama questo spazio B)
- Cercare di ruotare di nuovo usando il vettore (1, 0, 0) ruota attorno all'asse x nello spazio B NON nello spazio A che non è ciò che intendo fare.
Ecco cosa ho provato, dato quello che (penso) lo so (tralasciando il W coord per brevità):
- Per prima cosa ruota attorno a Y (0, 1, 0) usando un Quaternione.
- Converti la rotazione Y Quaternion in una matrice.
- Moltiplica la matrice di rotazione Y per il mio asse fisso x Vector (1, 0, 0) per ottenere l'asse X in relazione al nuovo spazio.
- Ruota attorno a questo nuovo X Vector usando un Quaternion.
Ecco il codice:
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;
}
Questo non funziona come mi aspetto. La rotazione sembra funzionare, ma a un certo punto il movimento orizzontale non ruota attorno all'asse Y, sembra ruotare attorno all'asse Z.
Non sono sicuro se la mia comprensione sia sbagliata o se qualcos'altro sta causando un problema. Ho alcune altre trasformazioni che sto facendo all'oggetto oltre alla rotazione. Sposto l'oggetto al centro prima di applicare la rotazione. Lo ruoto usando la matrice restituita dalla mia funzione sopra, quindi lo traduco -2 nella direzione Z in modo da poter vedere l'oggetto. Non penso che questo stia rovinando le mie rotazioni, ma ecco comunque il codice per quello:
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;
}
Sono stato bloccato su questo per alcuni giorni. L'aiuto è molto apprezzato.
================================================== ================
AGGIORNARE:
Far funzionare questo in Unity è semplice. Ecco del codice che ruota un cubo centrato sull'origine:
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);
}
}
La parte che fa funzionare le rotazioni come mi aspetto è il Space.World
parametro per la Rotate
funzione sulla trasformazione.
Se potessi usare Unity, purtroppo dovrei codificare questo comportamento da solo.