Estoy tratando de permitir que el usuario de mi aplicación gire un objeto 3D dibujado en el centro de la pantalla arrastrando su dedo sobre la pantalla. Un movimiento horizontal en la pantalla significa rotación alrededor de un eje Y fijo, y un movimiento vertical significa rotación alrededor del eje X. El problema que tengo es que si solo permito la rotación alrededor de un eje, el objeto gira bien, pero tan pronto como introduzco una segunda rotación, el objeto no gira como se esperaba.
Aquí hay una imagen de lo que está sucediendo:
El eje azul representa mi eje fijo. Imagen de la pantalla que tiene este eje azul fijo. Esto es a lo que quiero que rote el objeto en relación. Lo que está sucediendo está en rojo.
Esto es lo que sé:
- La primera rotación alrededor de Y (0, 1, 0) hace que el modelo se mueva del espacio azul (llame a este espacio A) a otro espacio (llame a este espacio B)
- Intentar rotar nuevamente usando el vector (1, 0, 0) gira alrededor del eje x en el espacio B NO en el espacio A, que no es lo que quiero hacer.
Esto es lo que probé, dado lo que (creo) que sé (dejando de lado la W coord por brevedad):
- Primero gire alrededor de Y (0, 1, 0) usando un Quaternion.
- Convierta la rotación Y Quaternion en una matriz.
- Multiplique la matriz de rotación Y por mi eje fijo x Vector (1, 0, 0) para obtener el eje X en relación con el nuevo espacio.
- Gire alrededor de este nuevo Vector X usando un Quaternion.
Aquí está el código:
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;
}
Esto no funciona como espero. La rotación parece funcionar, pero en algún momento el movimiento horizontal no gira sobre el eje Y, parece girar sobre el eje Z.
No estoy seguro si mi comprensión es incorrecta o si algo más está causando un problema. Tengo algunas otras transformaciones que estoy haciendo al objeto además de la rotación. Muevo el objeto al centro antes de aplicar la rotación. Lo giro usando la matriz devuelta por mi función anterior, luego lo traduzco -2 en la dirección Z para poder ver el objeto. No creo que esto esté arruinando mis rotaciones, pero de todos modos aquí está el código para eso:
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;
}
He estado atrapado en esto por unos días. La ayuda es muy apreciada.
================================================== ================
ACTUALIZAR:
Hacer que esto funcione en Unity es sencillo. Aquí hay un código que gira un cubo centrado en el origen:
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 que hace que las rotaciones se comporten como espero es el Space.World
parámetro de la Rotate
función en la transformación.
Si pudiera usar Unity lo haría, desafortunadamente tengo que codificar este comportamiento yo mismo.