Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
@Shaddow: sieh es mal so wie ich: ein Quaternion ist ein mathematisches Konstrukt (dessen Innereien ich auch nicht verstehe), welches das Gleiche macht wie eine Rotations-Matrix, aber ein wenig schneller (mit weniger Operationen) und brauchen weniger Speicherplatz.. Punkt. Das hab ich akzeptiert.
Es ist also vom Prinzip her egal, ob Du Deinen Vertex mit einer Matrix oder mit einem Quaternion multiplizierst, das Ergebnis sollte das Gleiche sein, nämlich ein transformierter Vertex. Mit dieser Erklärung habe ich mich zufrieden gegeben.
Quaternionen haben den großen Vorteil, dass man sie interpolieren kann. Aber sie haben im Unterschied zu Matrizen die Position des Vertex nicht mit dabei. Also können sie nicht verschieben sondern nur rotieren und man muss die Verschiebung noch extra dazufrickeln. Daher habe ich persönlich die Matrizen lieber, da ist eigentlich alles mit dabei.
Das Problem besteht momentan auch noch nicht in den Quaternationen, das könnte ich ja googlen, wenn ich da ankomme^^ Eher daran, dass ich schon einige Zeit davor nichts mehr verstanden habe. Ich habe mir besagte Tutorials incl des DGL Kamera tuts mal angesehen und irgendwas versucht hinzufriemeln. Es passiert was, aber nach einer absolut irrsinnigen drehung ist alles schwarz und es passiert gar nichts mehr. Da ich aber nicht versteh, was ich da geschrieben hab, kann ich auch nihct nachvollziehen, wo der fehler liegt^^ Da fehlt mir halt die Vorstellunsgkraft der Matrizen...
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
quaternions sind 4d zahlen, so wie komplexe zahlen 2d sind. Wichtig ist, dass sie besondere Rechengesetze haben für Operationen wie +,-,*,/ etc. Nebenbei haben Quaternions die lustige Eigenschaft, dass man mit ihnen die Rotation eines Punktes um eine frei definierte Achse berechnen kann, in dem man das Quaternion, das sich aus Achse und Winkel zusammensetzt, mit dem Punkt multipliziert und das anschließend wieder mit dem konjugat des Quaternions. Die Multiplikation hats dafür aber in sich. Die besteht nähmlich aus 16 multiplikationen und 12 Additionen. Das lässt sich dafür aber alles in einige Funktionen packen und ist dann recht handlich durchzuführen. Auf diese weiße drehe ich die Achsen meiner Camera, wobei ich finde, dass ich da wohl noch ein kleines bischn optimieren kann. Das kommt aber später, wenn es einwandfrei läuft.
Das mit dem Überschlag habe ich höchstwahrscheinlich scheiße erklärt. Also man nehme sich einen Egoshooter. In diesen schlechten Grafikdemos dreht man sich meist um die Y-Achse und den Right-Vektor. Das heißt, wenn ich leicht nach oben gucke und mich nach links, oder rechts drehe, dann drehe ich mich immer noch um (0,1,0), obwohl der Up-Vektor evtl. norm3(0,1,1) ist, weil wir ja etwas nach oben schauen. Das heißt, wenn ich um den Up-Vektor drehen würde, dann würde ich bei einer 180° drehung den Fußboden sehen, obwohl ich aber auf der anderen Seite noch in den Himmel geguckt habe. Also muss ich egal wie hoch ich gucke um die Y-Achse drehen um tatsächlich immer gleich hoch zu schauen. Nun gibts da aber ein Gedankenspiel, dass eigentlich vernachlässigbar ist in den meisten Einsatzgebieten. Dieses MEISTENS ist was mich stört, denn meistens ist nicht immer und dafür muss man dann eine Lösung haben falls einmal nicht meistens ist. Damit meine ich den Fall, das der Camera-Benutzer die Freiheit hat unbegrenzt nach oben oder unten schauen zu dürfen, aber trotzdem an die EgoShooterCam gebunden ist. Das heißt, dass der Benutzer ab einem gewissen Punkt einen Überschlag macht. Das merkt man daran, dass wenn man den Überschlagspunkt überschritten hat ( der Front-Vektor wandert nach oben über (0,1,0) hinaus, oder nach unten über (0,-1,0) ), dass plötzlich die seitwärtsrotation um die Y-Achse negiert ist. Dem wollte ich entgegen wirken, denn nur, weil der Benutzer sich die Welt umkopf anschauen will, soll er sich nicht an die vertauschten Seiten gewöhnen müssen. Um dem entgegenzuwirken stand für mich fest, dass ich den rotationswinkel dann einfach negiere, so, das er sich also doppelt negiert und wieder richtigherum ist. Allerdings kam ich nicht auf die Bedingung für dieses "auf dem Kopf stehen" und stellte daraufhin fest, dass man ab dem moment auf dem Kopf steht, ab dem die Y-Koordinate des Up-Vektors negativ wird. Direkt ausprobiert und es läuft. Es ist zwar trotzdem noch etwas merkwürdig, aber sehr viel besser als vorher.
Eine andere Idee, die mir kam ist, dass man den Rotationsbereich für eine EgoShooterCam bgrenzen könnte. Damit meine ich, dass man einen Winkel angeben kann, der nicht unter/überschritten werden kann. Das würde dafür sorgen, dass man sich nicht überschlagen kann.
Weiterhin habe ich mir gedacht, dass man die Objektstruktur evtl. noch einwenig verfeinern müsste, denn viele andere Objekte brauchen ein ähnliches Orientierungsverhalten im 3d-Raum und da wäre es praktisch, wenn man sich das Verhalten dann einfach von einer Klasse klauen kann. Die Camera wäre dann eine dieser Diebinnen. Weiter Anwendungsbeispiele wären InGameObjekte, 3d-Modelle, Nodes auf Pfaden/Curves usw. . Man hätte so die Möglichkeit viele Dinge mit einander kombinieren zu können, da sie den selben Funktionsumfang haben um sich im Raum zu Orientieren, oder ausgerichtet zu werden. Das Produkt einer solchen Orientierung wäre in jedem Fall eine 4x4Matrix und ein vereinfachter Zugriff auf die einzelnen Vektoren.
Das Camera-Objekt würde sich dann von dieser Orientierung ableiten und zustzlich nötige Funktionen mitbringen die für das Typische bewegungsverhalten des Nutzers stehen sollen. Diese kann man dann Situationsabhängig an die Interfacebuffer koppeln... Ich bin irre, ich schweife schon wieder völlig aus.
Ich lass es ersteinmal dabei und kümmer mich nach umsetzen des "look_at" um die Tutorial-Geschichte. Weiterhin würde mich interessieren, was in der oben geposteten glulookat();, nach dem neu errechnen der Vektoren über das Kreuzprodukt, genau passiert. Also, warum die Matrix transponiert multipliziert wird mit der Identität und anschließend negativ verschoben wird.
Zeile1: Du erzeugst eine Rotationsmatrix, Input ist die Kamera-Achse X und ein Winkel, das ist OK
Zeile2+3: Du rotierst die beiden anderen Achsen (Y und Z) um die in Zeile 1 erzeugte Matrix, das ist OK
Zeile 4: Du erzeugst eine neue Kameramatrix aus der alten Kameramatrix und der Matrix aus Zeile 1.
Hm ich habe das eigentlich anderes gemeint. Zeile 4 sollte eigentlich lauten:
localx = Crossproduct(localY,LocalZ). Wir brauchen ja noch die neue X-Achse, die haben wir ja noch nicht.
Und weiter(ich lass das ganze normalisieren jetzt mal weg):
Das brauchen wir hier ganz sicher nicht. LocalY und LocalZ sind oben im ersten Block bereits schon fertig.
Was wir noch brauchen, ist die Kamera-Rotations-Matrix. Und die kann man jetzt ganz einfach so erzeugen:
1. Die erste Spalte der Matrix ist localX
2. Die zweite Spalte der Matrix ist localY
3. Die dritte Spalte der Matrix ist localZ
Die vierte Spalte muss vorerst noch frei bleiben. Am besten vorher mit einer Einheitsmatrix initialisieren.
Das ist aber noch nicht die ganze Wahrheit. Bei mir muss ich die Matrix noch invertieren (bzw. Transponieren, also Zeilen und Spalten vertauschen, so eine Funktion hast Du ganz sicher), weil die Kamera ja immer genau das Gegenteil von dem machen muss, was ein Acteur machen würde (Du weißt schon: wenn die man sich nach links drehen will, muss sich die Kamera nach rechts drehen etc.)
Und dann muss ich noch eine Translationsmatrix erzeugen, wo die invertierte Kameraposition drin gespeichert ist (wenn man nach vorne gehen will, muss die Kamera nach hinten gehen etc.), und mit der Kamera-Rotations-Matrix multiplizieren. Man kann imho nicht einfach die Kameraposition in die letzte Spalte eintragen.
Das Ergebnis dieser letzten Multiplikation ist dann fertig fürs glLoadMatrix.
Also kurz nochmal:
1. Zwei Achsen um die andere rotieren, Input des Users ist der Winkel und die Rotationsachse, also z.B. X und Z um die Y-Achse rotieren
2. Die Rotationsachse Y selber ist noch nicht transformiert worden, daher muss sie neu mittels Kreuzprodukt aus den anderen beiden (bereits transformierten) Achsen erzeugt werden
3. JETZT haben wir drei nagelneue fertige Achsen, die wir in die Spalten der Kameramatrix eintragen können. Aber zuerst sollte die Matrix mit einer Einheitsmatrix initialisiert werden
4. diese neue Rotationsmatrix muss jetzt transponiert werden (Zeilen/Spalten vertauschen)
5. Und zum Schluß müssen wir noch eine Verschiebungsmatrix mit der invertierten Kameraposition erzeugen und mit der Rotationsmatrix multiplizieren.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Sellmann hat geschrieben:
Weiterhin würde mich interessieren, was in der oben geposteten glulookat();, nach dem neu errechnen der Vektoren über das Kreuzprodukt, genau passiert. Also, warum die Matrix transponiert multipliziert wird mit der Identität und anschließend negativ verschoben wird.
Das habe ich in meinem Post an Shaddow beschrieben, ab dem Satz: "Das ist aber noch nicht die ganze Wahrheit."
Sorry wegen des Doppelposts, aber sonst wird es zu unübersichtlich.
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
Gut dann hab ich das auch verstanden und werde das mal einbauen, aaaaaber ... nicht mehr heute. Jetzt wird nur noch abgespackt und Sellmann.Use(Bett); ausgeführt.
So hab ich das bisher umgesetzt. Ich hab die Translation noch nicht drin, weil es auch so schon nicht funktioniert ^^ Alle Werte werden bei einer Drehung auf NAN gesetzt.
Falls irgendwas an meinen Matrixmultiplikationen nicht stimmt, hier mal dafuer die Methoden:
Zumindest hab ich das ganze von der Theorie nun etwas verstanden, nur in der Praxis scheint das nicht ganz so zu wollen, wie ich will..
Sellmann hat geschrieben:
Gut dann hab ich das auch verstanden und werde das mal einbauen, aaaaaber ... nicht mehr heute. Jetzt wird nur noch abgespackt und Sellmann.Use(Bett); ausgeführt.
Vergiss nicht, die DamnIOversleptException abzufangen
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Da hilft nix, man muss ins Detail gehen.
Du kannst doch debuggen, oder?
Wie wäre es mit einem "Parallel Debugging"?
Ich füttere in meinen Code hier (der ganz genauso aussieht wie Deiner) die folgenden Anfangsvektoren hinein:
localX = (-1/0/0); Das ist der normale Rechts-Vektor für Objekte
localY = (0/+1/0); Das ist der normale Aufwärts-Vektor für Objekte
localZ = (0/0/+1); Das ist der normale Vorwärts-Vektor für Objekte
Winkel = 30 Grad, Drehung um die X-Achse nach links (CCW)
Mein Code lautet:
Code:
If ARotationType = CCW
Then RotMat:= MatrixRotate(+Angle,CurRight)
Else RotMat:= MatrixRotate(-Angle,CurRight);
CurForward:= VectorRotate(RotMat,CurForward);
CurUp:= VectorRotate(RotMat,CurUp);
CurRight:= VectorCrossProduct(CurForward,CurUp);
Für diese Rotation kommen mir die folgenden Werte heraus
RotationsMatrix ("RotMat")= [(+1,0,0,0),(0,+0.867,-0.5,0),(0,+0.5,+0.867,0),(0,0,0,1)];
Nach dem Rotieren und Kreuzverprodukten sehen die Vektoren so aus:
localX = (-1/0/0);
localY = (0/+0.867/-0.5);
localZ = (0/+0.5/+0.867);
Mein Code, um es in die Kamera Matrix einzufüllen, sieht so aus:
Wenn ich obige Ergebnisvektoren jetzt in die Kameramatrix wie oben gezeigt einfülle, dann sieht sie folgendermaßen aus:
KameraMatrix = [(-1,0,0,0),(0,+0.867,+0.5,0),(0,-0.5,+0.867,0),(0,0,0,1)];
ist praktisch genauso wie oben die Rotationsmatrix, nur haben sich ein paar Vorzeichen geändert.
Ich hab mich sehr bemüht, es von den Debugger-Ausgaben richtig abzuschreiben, aber ich kann nicht garantieren, dass ich nicht irgendwo ein Minus übersehen habe. Deine Prozedur "CreateRotationMatrix" habe ich überprüft, und sie sieht richtig aus.
Bei mir funktioniert es. Ich kann den Utah-Teapot von allen Seiten ganz genau inspizieren.
EDIT: Was mir noch aufgefallen ist (ein blöder Fehler von mir): das Kreuzprodukt kann man sich eigentlich sparen, die Rotationsache wird praktisch nicht verändert. Sieht man auch: LocalX verändert sich durch das Kreuzprodukt überhaupt nicht. Wird vermutlich genügen, wenn man alle paar hundert Frames überprüft, ob die Achsen noch normal zueinander stehen.
Also das ist doch schonmal ein guter Ansatz. Erster Punkt, der mir aufgefallen ist, die Rotationsmatrix sieht partiell anders aus als deine:
[[NaN, -0.0, 0.0, 0.0], [0.0, 0.8660254, 0.5, 0.0], [-0.0, 0.8660254, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
NAN is schonmal schlecht und ansonsten stimmen zwei werte nicht überein.
Den fehler in meiner createRotationMatrix find ich aber nich..
Denke mal, dass daran schon ein erheblicher Teil des Fehlers liegen wird.
EDIT: Nochmal nachgesehen, das NAN wird wohl an der sqrt in der berechnung liegen
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ach Du lieber Himmel. Ich habe Deine Prozedur offenbar sehr oberflächlich überprüft. Dort sollte keine Wurzel stehen, sondern ein Quadrat. Ich stell Dir meine eigene Funktion MatrixRotation hier rein, die ist andauernd in Betrieb und daher sicher richtig, ich hoffe die Typen sind selbsterklärend:
Code:
Function MatrixRotate(Angle: TFloat32;
Axis: TStdVector4D): TStdMatrix;
Var
MatRotation: TStdMatrix; Sinus,Cosinus: TFloat32;
Begin
Cosinus:=Cos(Angle*PiDiv180);
Sinus:=Sin(Angle*PiDiv180);
MatRotation:= MatIdentity;
With Axis DoBegin
MatRotation[0].X:= X*X*(1-Cosinus)+ Cosinus;
MatRotation[0].Y:= X*Y*(1-Cosinus)+ Z*Sinus;
MatRotation[0].Z:= X*Z*(1-Cosinus)- Y*Sinus;
MatRotation[1].X:= Y*X*(1-Cosinus)- Z*Sinus;
MatRotation[1].Y:= Y*Y*(1-Cosinus)+ Cosinus;
MatRotation[1].Z:= Y*Z*(1-Cosinus)+ X*Sinus;
MatRotation[2].X:= Z*X*(1-Cosinus)+ Y*Sinus;
MatRotation[2].Y:= Z*Y*(1-Cosinus)- X*Sinus;
MatRotation[2].Z:= Z*Z*(1-Cosinus)+ Cosinus;
End;
Result:= MatRotation;
End;
Noch etwas: bitte füll die Werte nicht in die Kameramatrix ein und lass sie nachher invertieren, sondern füll sie gleich richtig ein, so wie ich das oben mache. Das ist eine performance kritische Prozedur, weil sie auch dafür benutzt werden kann, die Matrizen von Objekten zu erzeugen. Wenn wir damit fertig sein, muss sie noch von der Schnelligkeit her optimiert werden.
Ich muss mich jetzt aber ausklinken, bin erst an Abend wieder hier.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ähem. Du musst die GANZE Funktion "CreateRotationMatrix" überprüfen, Die ist ja total kaputt. Da stecken immer noch Fehler drin. Läuse suchen in Deiner Rotationsmatrix tu ich nicht. Ich habe Dir schon eine richtige Funktion unter die Nase gehalten. Berichtigen muss Du Deinen Kram schon selber.
Also zuerstmal Danke für deine Geduld, ich bin zuweilen etwas sehr betriebsblind und manchmal begriffsstuzig
Der Fehler lag in einer falschen Konstanten zur Addressierung eines Arrayfeldes. Ich komme inzwischen auf genau die gleichen Werte, wie du auch gepostet hast, bis zum Ende. Die rotation funktioniert inzwischen auch, allerdings offenbaren sich noch zwei Probleme.
Es scheint, als würde kategorisch um einen Punkt und nicht um die Camera selbst gedreht werden. Ich stelle einmal die wagemutige Behauptung auf, dass es daran liegt, dass ich die Translation noch nicht mit in die Matrix einberechne, sondern noch per glTranslate ausführe und danach die rotationsmatrix per glMultMatrix draufrechne. Das würde sich also hoffentlich beheben, sobald ich das mit reingenommen habe.
Das aber etwas gravierendere Problem ist, dass ich mich eine weile drehen kann dann werden alle Werte NaN. Die einzige Regelmaessigkeit, die sich erkennen lässt, ist, dass die Werte kurz vor NaN unglaublich anwachsen. Nachdem ich doch nach der Neuberechnnung der Achsen alle nocheinmal habe normalisieren lassen, war auch dieses Problem beseitigt.
Allerdings scheint die Y-Achse als Upvektor nicht fest zu stehen, ich kann mich praktisch seitlich in die Szene kippen, also in diese eine Dimension drehen, die bei dem 4DOF System nicht gehen sollte.
Ich habe die Achsendrehungen in seperate Methoden aufgeteilt:
In AppyToMatrix werden die Vectoren der Matrix invers zugeordnet und vorher nocheinmal normalisiert.
Wenn ich nur rotateX aufrufe kann ich mich um die X Achse drehen, also gewissermaßen nach vorne oder hinten kippen.
Wenn ich nur rotateY aufrufe kann ich mich um die Y Achse drehen also nach links und rechts gucken.
Wenn ich beide aufrufe kann ich durch ein wenig hin und her drehen, gewissermaßen aus jeder position in jede richtung schauen und liege nach kurzem Gedrehe vollkommen schief in der Szene. Woran kann das liegen?
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
völlig schief in der Szene? Völlig schief kommt daher, dass du beim "links/rechts" drehen gewohnt bist um die Y-Achse der Welt und nicht der Camera zu drehen. Wenn du nähmlich ein Stück nch oben guckst und anschließend eine rechts Drehung durchführst, dann drehst du dich um den Up-Vektor, der j jetzt schief steht, dadurch, das du vorher nch oben geguckt hast. It also der richtige Effekt. Für den gewünschten Effekt musst du aber immer um (0,1,0) drehen, wenn du eine links/rechts-Drehung haben willst. Hab ich aber auch schon weiter oben in meinem riesen Post beschrieben ab dem Part mit der "Ego-Shooter-Cam".
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo Shaddow,
Dass die Funktion CreateRotationMatrix noch Fehler drin hat, war nicht eine Vermutung von mir, sondern ich hab es nochmals überprüft:
1. Es gab nicht nur eine Wurzel in dieser Funktion, sondern gleich drei, nämlich in jedem Block eine. Hast Du die alle drei beseitigt? In dieser ganzen Routine darf es gar keine Wurzeln geben.
2. Die meisten meiner Vorzeichen stimmen nicht mit Deinen überein. Das fängt schon in der zweiten Zeile an, wo Du die Werte in die Matrix einfüllst. Wir haben beide die gleiche Reihenfolge bei den Matrixzeilen, daher finde ich das ziemlich merkwürdig. Ich habe sie mir jetzt ganz genau angesehen, und ich finde praktisch Differenzen zwischen Deiner und meiner Matrix in fast jeder Zeile.
Irgendwie sieht mir das danach aus, als ob jemand statt Spalten Zeilen abgeschrieben hat. Ich empfehle Dir jedenfalls dringend, die Funktion richtigzustellen. Dass schon wieder irgendwelche Werte Nan werden, weist ja auch darauf hin, dass irgend eine Matrixfunktion Fehler produziert.
Ich habe bei meiner Implementierung bisher noch nicht feststellen können, dass die Matrizen ungültige Werte ausgeben. Und dabei lasse ich das Objekt auch rotieren (nicht nur die Kamera) und schätz jetzt mal, die längste TestSession bisher war sicher mindestens drei Minuten.
Zitat:
Es scheint, als würde kategorisch um einen Punkt und nicht um die Camera selbst gedreht werden. Ich stelle einmal die wagemutige Behauptung auf, dass es daran liegt, dass ich die Translation noch nicht mit in die Matrix einberechne, sondern noch per glTranslate ausführe und danach die rotationsmatrix per glMultMatrix draufrechne. Das würde sich also hoffentlich beheben, sobald ich das mit reingenommen habe.
Ja. Aber Du solltest es jetzt auch schon auf eine ganz simple Weise umstellen können: mach einfach das glMultMatrix (bzw. ein glLoadMatrix) VOR dem Translate.
Das, was Sellmann gesagt hat, kann ich bestätigen. Man kann mit einer 4Dof Kamera jede mögliche Orientierung im Raum erreichen (beinah hätt ich gesagt "Stellung", aber ich verkneifs mir lieber ).
Mitglieder in diesem Forum: 0 Mitglieder und 7 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.