AKTUALIZACJA Błąd tutaj był dość prosty. Przegapiłem konwersję radianów na stopnie. Nie musisz czytać wszystkiego, jeśli masz jakiś inny problem.
Przejrzałem kilka samouczków na ten temat i kiedy pomyślałem, że rozumiem, próbowałem wdrożyć kamerę opartą na czwartorzędu. Problem polega na tym, że nie działa poprawnie po obróceniu o ok. 10 stopni przeskakuje z powrotem do -10 stopni. Nie mam pojęcia, co jest nie tak. Używam openTK i ma już klasę czwartorzędu. Jestem noobem w Opengl, robię to dla zabawy i tak naprawdę nie rozumiem czwartorzędów, więc prawdopodobnie robię tutaj coś głupiego. Oto trochę kodu: (Właściwie prawie cały kod z wyjątkiem metod, które ładują i rysują vbo (pochodzi z próbki OpenTK, która demonstruje vbo-s))
Ładuję sześcian do vbo i inicjuję kwaternion dla kamery
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);
}
Ładuję tutaj rzut perspektywiczny. Jest to ładowane na początku i za każdym razem, gdy zmieniam rozmiar okna.
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);
}
Tutaj otrzymuję ostatnią wartość obrotu i tworzę nową ćwiartkę, która reprezentuje tylko ostatni obrót i mnożę ją przez ćwiartkę kamery. Następnie przekształcam to w kąt osi, aby OpenGL mógł z niego korzystać. (Tak to zrozumiałem z kilku samouczków czwartorzędu online)
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();
}
Oto 2 obrazy, aby lepiej wyjaśnić: Obracam chwilę i od tego:
wskakuje w to
Każda pomoc jest mile widziana.
Aktualizacja 1 : Dodaję do streamwriter, który zapisuje do pliku:
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);
Dziennik jest dostępny tutaj: http://www.pasteall.org/26133/text . W linii 770 sześcian przeskakuje od prawej do lewej, gdy kamera zmienia znaki. Nie wiem czy to normalne.
Update2 Oto kompletny projekt.
Odpowiedzi:
Chociaż nie pokazałeś tutaj kodu niezbędnego do zweryfikowania mojego założenia, prawie mogę zagwarantować, że twoim problemem jest to, że ten wiersz:
zwraca wartość kąta wyrażoną w radianach , natomiast
chce, aby kąt był podawany w stopniach .
Aby to naprawić, musisz przekonwertować wartość kąta podczas przekazywania jej do GL.Rotate (), w następujący sposób:
źródło
Math.Pi
stała, która powinna być używana zamiast dosłownej wartości 3,141593, której użyłem w tym ostatecznym obliczeniu.Nie rób Może się wydawać, że mniej pracy byłoby mieć kamerę, którą można manipulować jak inne obiekty sceny, ale na dłuższą metę lepiej jest mieć kamerę, w której można określić pozycję, kierunek oczu i wektor w górę. Zwłaszcza, gdy zaczynasz programować modele ruchu, praca z czwartorzędami jest naprawdę trudna.
źródło
Nie wiem wiele o wewnętrznych elementach OpenTK. Z mojego doświadczenia nie widziałem biblioteki matematycznej z prawidłową implementacją quat, która zachowuje wymaganą precyzję (maszynę), ponieważ wszystkie one mają wpływ na błędy e ^ 2-e ^ 3. Efekt, który widzisz: precyzja (i wartość epsilon) wynosi około 10 ^ -5 i „skacze” w pobliżu zera. Tak sądzę :)
źródło