Registriert: Mo Jun 12, 2006 14:47 Beiträge: 75
Programmiersprache: Object FPC
Hallo miteinander,
ich bin gerade dabei einen kleinen Drohnensimulator zu schreiben (Acro Modus).
Eine Drohne im Acro modus fliegt sich wie folgt: Drehung um alle Achsen(Yaw, Roll, Pitch), und Throttle (Bewegung nach Oben, aus sicht der Kamera)
Nun habe ich folgenden Code zum Rendern:
Code:
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
fCam.Move();
fCam.CamToOpenGL();
RenderScene();
OpenGLControl1.SwapBuffers;
Da ich die Kamera ständig drehen muss habe ich die Rotation und Translation in 2 Separate Schritte aufgeteilt (das erstpart bei jeder Rotation das subtrahieren der Position und danach wieder addieren)
Code:
Procedure TCam.Roll(Angle: Single); // Rotation um die Achse die in den Monitor hinein zeigt
Begin
glPushMatrix;
glLoadIdentity();
glRotatef(-Angle, 0, 0, 1); // Yaw, und Pitch sind analog haben nur diesen Vector anders
glMultMatrixf(@fMatrix);
glGetFloatv(GL_MODELVIEW_MATRIX, @fMatrix);
glPopMatrix;
End;
Gerendert wird das ganze dann via:
Code:
Procedure TCam.CamToOpenGL();
Begin
glMultMatrixf(@fMatrix);
glTranslatef(-Fposition.x, -Fposition.y, -Fposition.z); // Die Camera Bewegung ist ja Relativ zur Scene und deswegen Negativ
End;
Mein Problem ist nun Throttle (Bewegung aus sicht der Kamera nach Oben):
Code:
Procedure TCam.StrafeUpWay(delta: Single);
Var
v: TVector4;
Begin
v := v4(0, delta, 0, 0);
v := fMatrix * v;
Fposition.x := Fposition.x + v.x;
Fposition.y := Fposition.y + v.y;
Fposition.z := Fposition.z + v.z;
End;
Der oben gezeigt Code funktioniert ganz gut wenn ich "Waagrecht" fliege, sobald ich aber die Kamera Kippe z.b 90° Roll, dann sollte ich ja, wenn ich beschleunige immer noch Relativ nach oben und Absolut nach Rechts/Links fliegen. Je Länger ich fliege (also je mehr Rotationen ich gemacht habe) desto wilder wird das Ergebnis => Sprich die Kamera bewegt sich z.B. nach Links obwohl sie nach oben sollte. Manchmal sogar in mehrere Achsen.
Die Blickrichtung wird dabei aber immer Korrekt und meinen Erwartungen entsprechend gerendert, daher gehe ich davon aus, dass meine Rotationsmatrix korrekt ist.
Wie also kann ich StrafeUpWay korrekt implementieren ? Nochmal: Wenn ich meine Kamera an einer Bestimmten Position habe und in eine Bestimmte Richtung Blicke, wie berechne ich die Absolute Positionsänderung, wenn ich Relativ zur Kamera nach Oben möchte ?
Diese Frage habe ich ebenfalls auf MathePlanet gestellt.
Registriert: Sa Jan 01, 2005 17:11 Beiträge: 2067
Programmiersprache: C++
Du verrechnest die Matrix zweimal: In CamToOpenGL() passt du erst die Matrix an und führst dann deine Translation durch. Dadurch erfolgt die Translation schon im System der Kamera und nicht mehr absolut. Bei StrafeUpWay() hast du deine Translation ja schon mit der Matrix "korrigiert".
Meine Empfehlung an der Stelle ist es Rotation und Translation nicht zu trennen sondern immer in der kombinierten 4x4 Matrix zu arbeiten. Dann kannst du entscheiden ob die nächste Änderung (als 4x4 Matrix, z.B. eine einfache Translation oder auch Rotationen) auf die aktuelle Matrix draufgerechnet werden soll (Multiplikation von Rechts) oder ob sie vor der aktuellen Matrix statt finden soll (Multiplikation von Links).
Und etwas OT: Wenn du das Matrixhandling im Griff hast, kannst du dann auch direkt auf OpenGL 3.0 und größer wechseln. Dort ist (aus meiner Sicht) nur der Ort wo die Matrix berechnet wird geändert. Und zwar aus OpenGL raus in die Hand des Benutzers.
Registriert: Mo Jun 12, 2006 14:47 Beiträge: 75
Programmiersprache: Object FPC
Hallo i0n0s,
Danke für deine Hinweise ich habe meinen Code nun wie folgt umgeschrieben:
Code:
Procedure TCam.CamToOpenGL();
Begin
glMultMatrixf(@fMatrix);
End;
Procedure TCam.StrafeUpWay(delta: Single);
Begin
glPushMatrix;
glLoadIdentity();
glTranslatef(0, -delta, 0);
glMultMatrixf(@fMatrix);
glGetFloatv(GL_MODELVIEW_MATRIX, @fMatrix);
glPopMatrix;
End;
Damit kann ich nun 1a die Kamera bewegen, was nun aber nicht mehr geht ist - Setzen der Position Absolut (außer die Rotatsionsmatrix ist = Einheitsmatrix) - Gravitation durch Verschiebung Absolut => Also alles was nicht Relativ zu meinem Kamerasystem ist.
Code:
Procedure TCam.Translate(x, y, z: Single);
Begin
fMatrix[3, 0] := fMatrix[3, 0] - x;
fMatrix[3, 1] := fMatrix[3, 1] - y;
fMatrix[3, 2] := fMatrix[3, 2] - z;
End;
Procedure TCam.SetPosition(x, y, z: Single);
Begin
fMatrix[3, 0] := -x;
fMatrix[3, 1] := -y;
fMatrix[3, 2] := -z;
End;
Function TCam.GetPosition: TVector3;
Begin
result := v3(-fMatrix[3, 0], -fMatrix[3, 1], -fMatrix[3, 2]);
End;
Wie mache ich das nun ? Nochmal: Wenn ich eine Matrix Habe die mein Kamerasystem dreht und Verschiebt, wie kann ich daraus die Absolut Position Ermitteln / verändern ? Und ich brauche auch die Absolute Position, damit ich sie später gegen meine Welt "Kollidieren" kann.
Deinen Hinweis auf das OT verstehe ich nicht, ich nutze DGLOpenGL.pas für "OpenGL 4.6"
Registriert: Mo Jun 12, 2006 14:47 Beiträge: 75
Programmiersprache: Object FPC
Ok ich habe Translate ersetzt durch:
Code:
Procedure TCam.Translate(x, y, z: Single);
Begin
glPushMatrix();
glLoadIdentity();
glMultMatrixf(@fMatrix);
glTranslatef(-x, -y, -z);
glGetFloatv(GL_MODELVIEW_MATRIX, @fMatrix);
glPopMatrix();
End;
Und nun scheint die Schwerkraft zu funktionieren, auch wenn ich nicht genau verstehe, was der Unterschied zwischen dem "Händischen" und dem Rechnen via OpenGL ist.
Damit Bleibt nur noch die Frage, wie Bekomme ich die Position meiner Kamera Heraus, wenn diese wild Verdreht ist ?
Registriert: Sa Jan 01, 2005 17:11 Beiträge: 2067
Programmiersprache: C++
Die glTranslate ist eine Multiplikation der aktuellen Matrix mit:
Code:
1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 1
Wenn wir uns jetzt das Ergebnis für x betrachten ist das:
Code:
a_{11} * x + a_{12} * y + a_{13} * z + x' * 1
x' ist die vorherige X-Position. Und die a_{ij} hat du bei deinem Translate einfach ignoriert.
Les dir bitte mal im Tutorial Matrix den Abschnitt "Auswirkungen von Matrixmanipulationen - oder "Wie positioniere ich meine Objekte richtig?"" und dann das Kombinieren der Operationen an. Wenn du auf Matrizen arbeitest, kannst du sie nur noch über Matrizenmultiplikationen verändern.
Und es mag erstmal etwas kompliziert klingen, aber dahinter steht die bisherige Logik von glTranslate. Ein Beispiel: glTranslate(1, 0, 0); glRotate(90, 0, 0, 1); glTranslate(1, 0, 0);
Jetzt stehe ich ja nicht bei (2, 0, 0) sondern bei (1, 1, 0) [Vorzeichenfehler bitte ignorieren *hust*]. Mit dem glRotate werden Werte außerhalb der Diagonalen gesetzt und die nächste Translation kombiniert Werte.
Registriert: Mo Jun 12, 2006 14:47 Beiträge: 75
Programmiersprache: Object FPC
Intuitiv war mir das ja schon klar deswegen hab ich das Translate ja durch die OpenGL variante ersetzt. Danke für den Hinweis, werde mir den Artikel noch genauers ansehen.
Offen Bleibt die Frage wie ich die Absolut Koordinaten meiner Kamera herausbekomme.
Ich dachte daran die Achsen Einheitsvektoren durch die Rotationsmatrix zu jagen (jeden Einzeln), dann müsste ich nur noch die Linearkombination finden welche dann die Position der fMatrix [3,0] -- [3,2] ergibt, gibts da nen "Eleganten" Trick dafür oder ist mein Ansatz unsinn ?
Alternativ dachte ich auch schon daran fMatrix zu invertieren dann könnte man ja ebenfalls [3,0] -- [3,2] zurück transformieren. Aber eine Matrizen invertierung zu Rechnen wird wahrscheinlich komplizierter sein wie die erste Variante ..
Registriert: Mo Jun 12, 2006 14:47 Beiträge: 75
Programmiersprache: Object FPC
Wenn man mal weiß wie es geht ist es einfach hier die Auflösung:
Notwendig ist die Inverse Matrix von fmatrix um die Weltkoordinaten zu Berechnen. Da meine Fmatrix eine sogenannte Orthogonalmatrix ist reicht es hier diese zu transponieren um sie zu invertieren (das spart richtig viel Rechenzeit).
Code:
Function TCam.GetPosition: TVector3;
Var
m: TMatrix4x4;
v, p: TVector4;
Begin
v := v4(fMatrix[3, 0], fMatrix[3, 1], fMatrix[3, 2], 0); // Die Position in Kamera-Space
m := TransposeMatrix(fMatrix); // Da es sich um eine Ortohonalmatrix Handelt ist die Inverse die Transponierte
p := m * v;// Rückprojektion der Kamera Position in das Absolute Koordinatensystem
result := v3(-p.x, -p.y, -p.z);
End;
Und die Kollision mit dem Boden ist dann auch ein Kinderspiel:
Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.