Estou tentando permitir que o usuário do meu aplicativo gire um objeto 3D desenhado no centro da tela, arrastando o dedo na tela. Um movimento horizontal na tela significa rotação em torno de um eixo Y fixo, e um movimento vertical significa rotação em torno do eixo X. O problema que estou tendo é que, se eu permitir a rotação em torno de um eixo, o objeto gira bem, mas assim que introduzo uma segunda rotação, o objeto não gira conforme o esperado.
Aqui está uma imagem do que está acontecendo:
O eixo azul representa meu eixo fixo. Imagine a tela com este eixo azul fixo. É para isso que eu quero que o objeto gire em relação a. O que está acontecendo está em vermelho.
Aqui está o que eu sei:
- A primeira rotação em torno de Y (0, 1, 0) faz com que o modelo se mova do espaço azul (chame este espaço A) para outro espaço (chame este espaço B)
- Tentar girar novamente usando o vetor (1, 0, 0) gira em torno do eixo x no espaço B NÃO no espaço A, o que não é o que pretendo fazer.
Aqui está o que eu tentei, considerando o que eu (acho) eu sei (deixando de fora o W coord por brevidade):
- Primeiro gire em torno de Y (0, 1, 0) usando um Quaternion.
- Converta a rotação Y Quaternion em uma matriz.
- Multiplique a matriz de rotação Y pelo meu eixo fixo x Vetor (1, 0, 0) para obter o eixo X em relação ao novo espaço.
- Gire em torno deste novo vetor X usando um Quaternion.
Aqui está o 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;
}
Isso não está funcionando como eu espero. A rotação parece funcionar, mas em algum momento o movimento horizontal não gira em torno do eixo Y, ele parece girar em torno do eixo Z.
Não tenho certeza se meu entendimento está errado ou se alguma outra coisa está causando um problema. Eu tenho algumas outras transformações que estou fazendo no objeto além da rotação. Movo o objeto para o centro antes de aplicar a rotação. Giro-o usando a matriz retornada da minha função acima e depois o traduzo -2 na direção Z para que eu possa ver o objeto. Eu não acho que isso está atrapalhando minhas rotações, mas aqui está o código para isso de qualquer maneira:
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;
}
Estou preso nisso há alguns dias. A ajuda é muito apreciada.
==================================================== ================
ATUALIZAR:
Fazer isso funcionar no Unity é simples. Aqui está um código que gira um cubo centrado na origem:
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);
}
}
A parte que faz as rotações se comportarem como eu espero é o Space.World
parâmetro para a Rotate
função na transformação.
Se eu pudesse usar o Unity, infelizmente, tenho que codificar esse comportamento.