ATUALIZAÇÃO O erro aqui foi bastante simples. Perdi uma conversão de radiano para graus. Não é necessário ler a coisa toda se você tiver algum outro problema.
Eu olhei para vários tutoriais sobre isso e, quando pensei ter entendido, tentei implementar uma câmera baseada em quaternion. O problema é que não funciona corretamente, depois de girar por aprox. 10 graus, ele volta para -10 graus. Eu não tenho ideia do que está errado. Estou usando o openTK e ele já tem uma classe de quaternion. Eu sou um noob no opengl, estou fazendo isso apenas por diversão, e realmente não entendo quaternions, então provavelmente estou fazendo algo estúpido aqui. Aqui está um código: (Na verdade, quase todo o código, exceto os métodos que carregam e desenham um vbo (é retirado de uma amostra do OpenTK que demonstra o vbo-s))
Carrego um cubo em um vbo e inicializo o quaternion para a câmera
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);
}
Eu carrego uma projeção em perspectiva aqui. Isso é carregado no início e toda vez que redimensiono a janela.
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);
}
Aqui, obtenho o valor da última rotação e crio um novo quaternion que representa apenas a última rotação e multiplica-o pelo quaternion da câmera. Depois disso, eu o transformo em ângulo de eixo para que o opengl possa usá-lo. (Foi assim que eu entendi em vários tutoriais on-line 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();
}
Aqui estão duas imagens para explicar melhor: eu giro um pouco e a partir disso:
pula para isso
Qualquer ajuda é apreciada.
Update1 : eu os adiciono a um streamwriter que grava em um arquivo:
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);
O log está disponível aqui: http://www.pasteall.org/26133/text . Na linha 770, o cubo salta da direita para a esquerda quando camerarot.Y muda de sinal. Não sei se isso é normal.
Atualização2 Aqui está o projeto completo.
Respostas:
Embora você não tenha mostrado o código necessário para verificar minha suposição aqui, quase posso garantir que seu problema é realmente esta linha:
está retornando um valor de ângulo expresso em radianos , enquanto
quer que o ângulo seja fornecido em graus .
Para corrigi-lo, você precisa converter o valor do ângulo ao passá-lo para GL.Rotate (), assim:
fonte
Math.Pi
constante disponível, que deve ser usada preferencialmente ao valor literal de 3.141593 que eu usei no cálculo final.Não. Pode parecer menos trabalhoso ter uma câmera que possa ser manipulada como outros objetos de cena, mas, a longo prazo, é melhor ter uma câmera em que você possa definir uma posição, direção dos olhos e vetor ascendente. Especialmente quando você começa a programar modelos de movimento, é realmente difícil trabalhar com quaterniões.
fonte
Não sabe muito sobre os componentes internos do OpenTK. Na minha experiência, não vi uma biblioteca matemática com a implementação adequada de quat que mantém a precisão necessária (máquina), porque todos eles afetam os erros e ^ 2-e ^ 3. Portanto, o efeito que você vê: a precisão (e o valor épsilon) é de cerca de 10 ^ -5 e 'salta' perto de zero. Este é o meu palpite :)
fonte