ACTUALIZACIÓN El error aquí fue bastante simple. He perdido una conversión de radianes a grados. No es necesario leer todo si tienes algún otro problema.
Miré varios tutoriales sobre esto y cuando pensé que entendía, intenté implementar una cámara basada en el cuaternión. El problema es que no funciona correctamente, después de girar durante aprox. 10 grados salta de nuevo a -10 grados. No tengo idea de lo que está mal. Estoy usando openTK y ya tiene una clase quaternion. Soy un novato en opengl, estoy haciendo esto solo por diversión, y realmente no entiendo cuaterniones, así que probablemente estoy haciendo algo estúpido aquí. Aquí hay algo de código: (En realidad, casi todo el código, excepto los métodos que cargan y dibujan un vbo (se toma de una muestra de OpenTK que demuestra vbo-s))
Cargo un cubo en un vbo e inicializo el cuaternión para la cámara
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
cameraPos = new Vector3(0, 0, 7);
cameraRot = Quaternion.FromAxisAngle(new Vector3(0,0,-1), 0);
GL.ClearColor(System.Drawing.Color.MidnightBlue);
GL.Enable(EnableCap.DepthTest);
vbo = LoadVBO(CubeVertices, CubeElements);
}
Cargo una proyección en perspectiva aquí. Esto se carga al principio y cada vez que cambio el tamaño de la ventana.
protected override void OnResize(EventArgs e) {
base.OnResize(e);
GL.Viewport(0, 0, Width, Height);
float aspect_ratio = Width / (float)Height;
Matrix4 perpective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 64);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref perpective);
}
Aquí obtengo el último valor de rotación y creo un nuevo cuaternión que representa solo la última rotación y lo multiplico con el cuaternión de la cámara. Después de esto, lo transformo en ángulo de eje para que opengl pueda usarlo. (Así es como lo entendí de varios tutoriales en línea de quaternion)
protected override void OnRenderFrame(FrameEventArgs e) {
base.OnRenderFrame(e);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
double speed = 1;
double rx = 0, ry = 0;
if (Keyboard[Key.A]) {
ry = -speed * e.Time;
}
if (Keyboard[Key.D]) {
ry = +speed * e.Time;
}
if (Keyboard[Key.W]) {
rx = +speed * e.Time;
}
if (Keyboard[Key.S]) {
rx = -speed * e.Time;
}
Quaternion tmpQuat = Quaternion.FromAxisAngle(new Vector3(0,1,0), (float)ry);
cameraRot = tmpQuat * cameraRot;
cameraRot.Normalize();
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Vector3 axis;
float angle;
cameraRot.ToAxisAngle(out axis, out angle);
//////////////////////////////////////////////////////////////////////
// THIS IS WHAT I DID WRONG: I NEED TO CONVERT FROM RADIANS TO DEGREES
//////////////////////////////////////////////////////////////////////
//BEFORE
//GL.Rotate(angle, axis);
//AFTER
GL.Rotate(angle * (float)180.0/(float)Math.PI, axis);
GL.Translate(-cameraPos);
Draw(vbo);
SwapBuffers();
}
Aquí hay 2 imágenes para explicar mejor: giro un rato y de esto:
salta a esto
Cualquier ayuda es apreciada.
Actualización 1 : los agrego a una máquina de escribir que escribe en un archivo:
sw.WriteLine("camerarot: X:{0} Y:{1} Z:{2} W:{3} L:{4}", cameraRot.X, cameraRot.Y, cameraRot.Z, cameraRot.W, cameraRot.Length);
sw.WriteLine("ry: {0}", ry);
El registro está disponible aquí: http://www.pasteall.org/26133/text . En la línea 770, el cubo salta de derecha a izquierda, cuando camerarot.Y cambia de signo. No sé si esto es normal.
Update2 Aquí está el proyecto completo.