He pasado un par de semanas sobre este tema y parece que no puedo encontrar una solución adecuada y necesito algunos consejos.LWJGL - Problemas al implementar 'rollo' en una cámara 6DOF usando cuaterniones y una matriz de traducción
Estoy trabajando en la creación de una clase de cámara usando LWJGL/Java, y estoy usando Quaternions para manejar las rotaciones de rodamiento (cabeceo), cabeceo y balanceo. Me gustaría que esta cámara maneje los 6 grados de movimiento en el espacio tridimensional y ruede. Bearing, Pitch and Roll son cuaterniones. Los multiplico en un cuaternión de "cambio" y creo una matriz de traducción a partir de eso. Lo pongo en un buffer flotante, y multiplico la matriz modelview por mi buffer que contiene la matriz de rotación.
Puedo hacer que las rotaciones de rumbo y rodamiento funcionen correctamente, pero cuando implemento el rollo, me estoy encontrando con problemas. Principalmente, girar alrededor del eje Z (rodar) no parece funcionar. Siempre que "giro" la cámara, parece rodar alrededor del eje Z global en lugar del eje de dirección de la cámara local. Por lo general, puedo obtener 2 de los 3 para que funcionen dependiendo del orden en que multiplique los cuaterniones, pero no puedo hacer que funcionen juntos.
Dado que todas funcionan de forma independiente, supongo que hay un problema con mi método de orientación donde las combino y construyo una matriz de rotación. Tengo problemas para pegar toda la clase, así que aquí están los métodos y las declaraciones relativas a la rotación:
private final static float DEGTORAD = (float)(Math.PI/180);
//Eye - position of the camera in the 3D world.
private Vector3f eye;
//Camera axis vectors, calculated each time reorient() is called.
//Initialized to global x, y, and z axis initially.
private Vector3f up;
private Vector3f right;
private Vector3f direction;
//Angles of rotation (in degrees)
private float pitchAngle;
private float bearingAngle;
private float rollAngle;
private Quaternion pitch;
private Quaternion bearing;
private Quaternion roll;
private FloatBuffer viewMatrixBuffer = BufferUtils.createFloatBuffer(16);
private Quaternion currentOrientation;
...
/**
* Change the bearing (yaw)
* @param bearing delta in degrees
*/
public void bearing(float bearingDelta){
bearingAngle += bearingDelta;
if(bearingAngle > 360){
bearingAngle -= 360;
}else if(bearingAngle < 0){
bearingAngle += 360;
}
bearing.setFromAxisAngle(new Vector4f(0f, 1f, 0f, bearingAngle * DEGTORAD));
bearing.normalise();
}
/**
* Change the pitch
* @param pitch delta in degrees
*/
public void pitch(float pitchDelta){
pitchAngle += pitchDelta;
if(pitchAngle > 360){
pitchAngle -= 360;
}else if(pitchAngle < 0){
pitchAngle += 360;
}
pitch.setFromAxisAngle(new Vector4f(1f, 0f, 0f, pitchAngle * DEGTORAD));
pitch.normalise();
}
/**
* @param initialRoll
*/
public void roll(float initialRoll) {
rollAngle += initialRoll;
if(rollAngle > 360){
rollAngle -= 360;
}else if(rollAngle < 0){
rollAngle += 360;
}
roll.setFromAxisAngle(new Vector4f(0, 0, 1, rollAngle * DEGTORAD));
roll.normalise();
}
/**
* Change direction to focus on a certain point in the world
* @param eye
*/
public void lookThrough(){
reorient();
GL11.glMultMatrix(viewMatrixBuffer);
}
public void reorient(){
//Multiply in order: bearing, pitch, roll. Non-commutative!
Quaternion change = new Quaternion();
Quaternion.mul(bearing, pitch, change);
Quaternion.mul(roll, change, change);
// orient the camera...
Matrix4f rotationMatrix = getRotationMatrix(change);
//Get the looking direction
direction.x = rotationMatrix.m20;
direction.y = rotationMatrix.m21;
direction.z = rotationMatrix.m22;
//Set the position
rotationMatrix.m30 = eye.x;
rotationMatrix.m31 = eye.y;
rotationMatrix.m32 = eye.z;
rotationMatrix.m33 = 1;
rotationMatrix.invert();
rotationMatrix.store(viewMatrixBuffer);
viewMatrixBuffer.rewind();
Vector3f.cross(new Vector3f(0,1,0), direction, null).normalise(right);
Vector3f.cross(right, direction, null).normalise(up);
}
Vector3f, cuaternión, y Matrix4f son todas las clases lwjgl, no hecho a medida.
Así que mi pregunta es, dado 3 Quaternions que representan Teniendo, Pitch and Roll, ¿cómo modifico la matriz ModelView para representar con precisión estas rotaciones?
EDIT: Siento que esto está muy cerca. Ver el enlace Gist en el comentario de RiverC. Después de girar tantos grados, la vista salta mucho antes de volver a la normalidad al rodar. La esencia está allí, pero todavía está un poco apagado.
Gracias por la actualización. No he tocado este código por un tiempo, así que estoy volviendo a la velocidad con LWJGl. Creo que estoy cerca. Después de hacer los cambios y cambios sugeridos por gsimard, me estoy acercando. Sin embargo, cuando yaw (teniendo en la pregunta) está en 0, el tono está bien. Cuando la guiñada está en 180, el tono se invierte (el cabeceo hacia arriba mueve la cámara hacia abajo). Además, la rotación se vuelve esporádica después de girar unos 20 grados. Si sigo girando, se nivela. Entonces algo todavía no está del todo bien. Pondré el código en github y actualizaré esta pregunta más tarde esta noche. Creo que ya casi está allí. Gracias de nuevo. – framauro13
¿Por qué haces cosas en la matriz de rotación después de crearla? Deberías poder enviar un Mat4 directamente al Shader y usarlo para multiplicar los vértices de la escena sin modificarlo. Lo que quiero decir es, la parte '// establecer la dirección' del código. Parece que estás tratando de usar eso para compensar la cámara a través de la multiplicación, pero en mi experiencia esto ha sido impredecible. Prueba a soltar eso. –
I * think * la razón por la que lo hice inicialmente fue para poder sumar el vector de dirección con el vector de ojo para generar un vector para interactuar con objetos en el mundo. Un vector de 'recolección' más o menos. Además, he solucionado el problema con el lanzamiento de tono. Cambié el orden de rumbo y cabeceo, por lo que la línea dice 'Quaternion.mul (Quaternion.mul (rodar, llevar, cambiar), cabeceo, cambio);' Todavía estoy tratando de descubrir por qué el rollo se pone pesado después de rodar un cierto cantidad. – framauro13