Tutorial Nachsitzen: Unterschied zwischen den Versionen
(Erste veraenderungen und Markierungen zur weiteren bearbeitung eingefuegt) |
|||
Zeile 1: | Zeile 1: | ||
{{Offline}} | {{Offline}} | ||
+ | Dieses Tutorial wird momentan an eineigen Stellen deutlich Ueberarbeitet. Einige Ungereimtheiten beim Lesen sind sicherlich die Folge. Ich wuerde empfehlen in den naechsten Tagen nocheinmal vorbeizusehen, statt das Tutorial jetzt zu lesen. (N.M.) | ||
+ | |||
==Vorwort== | ==Vorwort== | ||
− | Immer wieder muss ich feststellen, dass viele die (mit OpenGl) 3D Anwendungen schreiben, nichts mit der Mathematik dahinter anfangen können. Um das ein oder andere zu verstehen oder sich selbst überlegen zu können, ist dieses Wissen aber unabdingbar. Ich möchte mit diesem Artikel helfen, diesen meiner Meinung nach unhaltbaren Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Das ein oder andere werded ihr aus der Schule bereits kennen, wenn ihr also etwas überspringen wollt, orientiert euch einfach an den Überschriften. | + | Immer wieder muss ich feststellen, dass viele, die (mit OpenGl) 3D Anwendungen schreiben, nichts mit der Mathematik dahinter anfangen können. Um das ein oder andere zu verstehen oder sich selbst überlegen zu können, ist dieses Wissen aber unabdingbar. Ich möchte mit diesem Artikel helfen, diesen meiner Meinung nach unhaltbaren Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Das ein oder andere werded ihr aus der Schule bereits kennen, wenn ihr also etwas überspringen wollt, orientiert euch einfach an den Überschriften. |
==Trigonometrie am rechtwinkligen Dreieck== | ==Trigonometrie am rechtwinkligen Dreieck== | ||
Zeile 52: | Zeile 54: | ||
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Das ist ein Trugschluss, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w). | Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Das ist ein Trugschluss, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w). | ||
− | Ich denke, zu den 3 ersten Koordinaten muss ich nichts weiter sagen, zur w-Koordinate hingegen schon: w ist normalerweise immer 1.0. Mit glVertex4 kann bei Bedarf auch ein anderer Wert zugewiesen werden. Ist w ungleich Null, so wird ein Vertex als folgender 3-Dimensionaler Punkt interpretiert: (x/w, y/w, z/w). Im Normalfall sollte der Wert für w aber auf 1.0 belassen werden, es sei denn man hat eine interessante Idee, die sich mit einem w ungleich 1.0 besonders schön realisieren lässt.Wen die w-Koordinate interessiert, sollte in der OpenGl Spezifikation unter Coordinate Transformations nachschauen. | + | Ich denke, zu den 3 ersten Koordinaten muss ich nichts weiter sagen, zur w-Koordinate hingegen schon: w ist normalerweise immer 1.0. Mit glVertex4 kann bei Bedarf auch ein anderer Wert zugewiesen werden. Ist w ungleich Null, so wird ein Vertex als folgender 3-Dimensionaler Punkt interpretiert: (x/w, y/w, z/w). Im Normalfall sollte der Wert für w aber auf 1.0 belassen werden, es sei denn man hat eine interessante Idee, die sich mit einem w ungleich 1.0 besonders schön realisieren lässt. Wen die w-Koordinate interessiert, sollte in der OpenGl Spezifikation unter Coordinate Transformations nachschauen. |
− | Ein Beispiel für die | + | Ein Beispiel für die Effekt beim Einsatz von w Koordinaten: Beim ersten Dreieck ist im oberen Punkt w = 1.0, im 2. ist w = 0.5: |
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]] | [[Bild:Tutorial_Nachsitzen_wcoord.jpg]] | ||
− | |||
− | |||
===Einstieg in Matrizen=== | ===Einstieg in Matrizen=== | ||
Zeile 74: | Zeile 74: | ||
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]] | [[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]] | ||
+ | /-- Bild austauschen --/ | ||
Bzw: | Bzw: | ||
<pascal> | <pascal> | ||
− | x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + a[1,4] | + | x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4] |
{Koeffizienten aus der ersten Zeile der Matrix} | {Koeffizienten aus der ersten Zeile der Matrix} | ||
− | y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + a[2,4] | + | y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4] |
{Koeffizienten aus der zweiten Zeile der Matrix} | {Koeffizienten aus der zweiten Zeile der Matrix} | ||
− | z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + a[3,4] | + | z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4] |
{Koeffizienten aus der dritten Zeile der Matrix} | {Koeffizienten aus der dritten Zeile der Matrix} | ||
+ | w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4] | ||
+ | {Koeffizienten aus der letzten Zeile der Matrix} | ||
</pascal> | </pascal> | ||
+ | |||
+ | /-- Mathematische Kurzschreibweise der Rechnung --/ | ||
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis: | Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis: | ||
:'''Die Spalten sind die Bilder der Einheitsvektoren''' | :'''Die Spalten sind die Bilder der Einheitsvektoren''' | ||
Die Bedeutung dürfte noch keinem hier klar sein, aber ich denke das kommt bald. | Die Bedeutung dürfte noch keinem hier klar sein, aber ich denke das kommt bald. | ||
+ | |||
+ | Ist w=1, wie das in fast allen Anwendungen der Fall sein wird, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte. | ||
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity=== | ===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity=== | ||
Zeile 97: | Zeile 104: | ||
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird: | Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird: | ||
<pascal> | <pascal> | ||
− | x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + a[1,4] | + | x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4] |
</pascal> | </pascal> | ||
Unser Ziel ist, dass x_neu gleich x ist. Das lässt sich immer erreichen, indem wir den Koeffizienten a[1,1] = 1.0 setzen und die restichen = 0. Dann steht da nämlich: | Unser Ziel ist, dass x_neu gleich x ist. Das lässt sich immer erreichen, indem wir den Koeffizienten a[1,1] = 1.0 setzen und die restichen = 0. Dann steht da nämlich: | ||
<pascal> | <pascal> | ||
− | x_neu := x*1 + y*0 + z*0 + 0 { = x } | + | x_neu := x*1 + y*0 + z*0 + w*0 { = x } |
</pascal> | </pascal> | ||
− | Die gleiche Überlegung kann man auch für die anderen | + | Die gleiche Überlegung kann man auch für die anderen 3 Elemente y,z und w machen. Jede dieser Überlegungen ergibt eine Zeile der Identitätsmatrix. Das Ergebnis: |
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]] | [[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]] | ||
Zeile 172: | Zeile 179: | ||
Eine wichtige Operation ist die Matrixmultiplikation. Sie verbindet zwei Matrizen zu einer so, dass sie nacheinander ausgeführt werden. Dabei ist zu bedenken, dass die Reihenfolge einen Unterschied macht: erst drehen und dann verschieben ist ungleich erst verschieben und dann drehen, aber das sollte eich bei der Verwendung von glRotate und glTranslate bereits aufgefallen sein. | Eine wichtige Operation ist die Matrixmultiplikation. Sie verbindet zwei Matrizen zu einer so, dass sie nacheinander ausgeführt werden. Dabei ist zu bedenken, dass die Reihenfolge einen Unterschied macht: erst drehen und dann verschieben ist ungleich erst verschieben und dann drehen, aber das sollte eich bei der Verwendung von glRotate und glTranslate bereits aufgefallen sein. | ||
+ | |||
+ | /-- Genauere beschreibung wie das geht --/ | ||
===Matrixinversion=== | ===Matrixinversion=== | ||
Zeile 178: | Zeile 187: | ||
Man hat ein Objekt, dessen Rotation durch eine Matrix beschrieben wird, was generell sinnvoll ist, wenn das Objekt voneinander abhängige Drehungen vollführen soll oder man das lokale Koordinatensystem des Objekts benötigt. Jedenfalls will man nun das Objekt nicht von aussen bestaunen, sondern sich in die Ansicht des Objekts selbst hineinversetzen, so kann man dessen Rotationsmatrix einfach invertieren und schon hat man sein Ziel erreicht. Wen ähnliches interessiert, sollte sich jetzt einmal an mein Kamera Tutorial wagen und schauen, dass er's versteht. | Man hat ein Objekt, dessen Rotation durch eine Matrix beschrieben wird, was generell sinnvoll ist, wenn das Objekt voneinander abhängige Drehungen vollführen soll oder man das lokale Koordinatensystem des Objekts benötigt. Jedenfalls will man nun das Objekt nicht von aussen bestaunen, sondern sich in die Ansicht des Objekts selbst hineinversetzen, so kann man dessen Rotationsmatrix einfach invertieren und schon hat man sein Ziel erreicht. Wen ähnliches interessiert, sollte sich jetzt einmal an mein Kamera Tutorial wagen und schauen, dass er's versteht. | ||
+ | |||
+ | /-- Genauere beschreibung wie das geht --/ | ||
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen== | ==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen== | ||
Zeile 189: | Zeile 200: | ||
==Kopfschmerzen?== | ==Kopfschmerzen?== | ||
− | Ahh, wieder eines meiner schrecklichen Tutorials überlebt. Ich hoffe, dass wenigstens ein paar Leute unter euch das ein oder andere Verstanden haben und ich das alles nicht umsonst geschrieben habe(wenns nur einer Verstanden hat, bin ich schon glücklich ;-) ). | + | Ahh, wieder eines meiner schrecklichen Tutorials überlebt. Ich hoffe, dass wenigstens ein paar Leute unter euch das ein oder andere Verstanden haben und ich das alles nicht umsonst geschrieben habe (wenns nur einer Verstanden hat, bin ich schon glücklich ;-) ). |
...have a lot of fun! | ...have a lot of fun! | ||
− | + | [Nico Michaelis] | |
Version vom 12. Mai 2006, 08:19 Uhr
Bitte haben Sie etwas Geduld und nehmen Sie keine Änderungen vor, bis der Artikel hochgeladen wurde. |
Dieses Tutorial wird momentan an eineigen Stellen deutlich Ueberarbeitet. Einige Ungereimtheiten beim Lesen sind sicherlich die Folge. Ich wuerde empfehlen in den naechsten Tagen nocheinmal vorbeizusehen, statt das Tutorial jetzt zu lesen. (N.M.)
Inhaltsverzeichnis
- 1 Vorwort
- 2 Trigonometrie am rechtwinkligen Dreieck
- 3 Die Welt der Matrizen
- 4 OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen
- 5 Kopfschmerzen?
Vorwort
Immer wieder muss ich feststellen, dass viele, die (mit OpenGl) 3D Anwendungen schreiben, nichts mit der Mathematik dahinter anfangen können. Um das ein oder andere zu verstehen oder sich selbst überlegen zu können, ist dieses Wissen aber unabdingbar. Ich möchte mit diesem Artikel helfen, diesen meiner Meinung nach unhaltbaren Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Das ein oder andere werded ihr aus der Schule bereits kennen, wenn ihr also etwas überspringen wollt, orientiert euch einfach an den Überschriften.
Trigonometrie am rechtwinkligen Dreieck
Man stelle sich vor, man hat einen Kreis, mit Radius 1. Der Mittelpunkt des Kreises befindet sich auf dem Koordinatensystem Ursprung. An der X-Achse ist ein Winkel ß angetragen:
An der x-Achse bildet sich dann ein rechter Winkel(wichtig für normale Trigonometrie). Die diesem Winkel gegenüberliegende Seite(r) nennt man Hypotenuse. Die am Winkel ß anliegende Seite(x) ist die Ankathete. Die dem Winkel gegenüberliegende Seite(y) heißt Gegenkathete. Jetzt definiert man folgende Funktionen:
sin(ß) = Gegenkathete / Hypotenuse cos(ß) = Ankathete / Hypotenuse tan(ß) = Gegenkathete / Ankathete
Im Einheitskreis(und nur dort) gilt:
sin(ß) = y cos(ß) = x
da die länge der Hypotenuse 1 ist(Kreisradius).
Die Umkehrfunktionen dazu sind(in Pascal):
ß = arcsin(sin(ß)) ß = arccos(cos(ß)) ß = arctan(tan(ß))
für ß im bereich 0° - 90°. In den anderen Quadranten des Koordinatensystems, sind die Umkehrfunktionen nicht für alle Winkel eindeutig zurückzurechnen, hier muss man also ein wenig aufpassen, z.B. gibt arcsin(sin(ß)) im Bereich 90°-180° den Winkel 180° - ß aus. Im übrigen ist auch darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:
sin(-ß) = - sin(ß) cos(-ß) = cos(ß) sin(90° - ß) = cos (ß) cos(90° - ß) = sin (ß) sin²(ß) + cos²(ß) = 1
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.
Die Welt der Matrizen
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Werkzeug, das man irgendwann nicht mehr missen mag. Vorher sollten wir aber noch einmal Vertieces in OpenGl(bei D3D dürfte es im übrigen ähnlich, wenn nicht genauso laufen) betrachten und uns erst dann auf Matrizen stürzen.
Vertices und ihr Ursprung
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Das ist ein Trugschluss, denn die meisten 3D APIs verwenden 4-Dimensionale Vertices(x/y/z/w).
Ich denke, zu den 3 ersten Koordinaten muss ich nichts weiter sagen, zur w-Koordinate hingegen schon: w ist normalerweise immer 1.0. Mit glVertex4 kann bei Bedarf auch ein anderer Wert zugewiesen werden. Ist w ungleich Null, so wird ein Vertex als folgender 3-Dimensionaler Punkt interpretiert: (x/w, y/w, z/w). Im Normalfall sollte der Wert für w aber auf 1.0 belassen werden, es sei denn man hat eine interessante Idee, die sich mit einem w ungleich 1.0 besonders schön realisieren lässt. Wen die w-Koordinate interessiert, sollte in der OpenGl Spezifikation unter Coordinate Transformations nachschauen.
Ein Beispiel für die Effekt beim Einsatz von w Koordinaten: Beim ersten Dreieck ist im oberen Punkt w = 1.0, im 2. ist w = 0.5:
Einstieg in Matrizen
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:
Definition:Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:
Anwendung der Matrix auf einen Vektor
Hat man nun ein 3-Dimensionales Vertex(w=1.0!) und möchte diesen durch die Matrix schicken, so rechnet man:
Bzw:
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4] {Koeffizienten aus der ersten Zeile der Matrix} y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4] {Koeffizienten aus der zweiten Zeile der Matrix} z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4] {Koeffizienten aus der dritten Zeile der Matrix} w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4] {Koeffizienten aus der letzten Zeile der Matrix}
/-- Mathematische Kurzschreibweise der Rechnung --/
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:
- Die Spalten sind die Bilder der Einheitsvektoren
Die Bedeutung dürfte noch keinem hier klar sein, aber ich denke das kommt bald.
Ist w=1, wie das in fast allen Anwendungen der Fall sein wird, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte.
Die Identitätsmatrix, oder der Ursprung von glLoadIdentity
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:
V * Matrix = V
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]
Unser Ziel ist, dass x_neu gleich x ist. Das lässt sich immer erreichen, indem wir den Koeffizienten a[1,1] = 1.0 setzen und die restichen = 0. Dann steht da nämlich:
x_neu := x*1 + y*0 + z*0 + w*0 { = x }
Die gleiche Überlegung kann man auch für die anderen 3 Elemente y,z und w machen. Jede dieser Überlegungen ergibt eine Zeile der Identitätsmatrix. Das Ergebnis:
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:
Welten verschieben
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben. Durch den Umstand, dass die letzte Spalte einer Matrix in OpenGl einfach zum Wert des neuen Vertex dazugezählt wird, lässt sich eine Translationsmatrix sehr einfach realisieren:
Um den Ursprung drehen
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Viel toller wird er aber, wenn man ihn auch noch aus verschiedenen Blickwinkeln anschauen und frei drehen kann. Den meisten dürfte damit schon klar sein, worauf ich hinaus will: Drehungen mithilfe von Matrizen:
Matrixoperationen
Fürs Arbeiten mit Matrizen gibt es ein paar überlebenswichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber dennoch erklären was sie tun und was man damit anstellen kann. Wer diese Operationen verwenden möchte, sollte mal auf Mike Lischkes Homepage vorbeischaun. Dort findet ihr eine Geometry.pas, die diese Funktionen und noch viele mehr beinhaltet. Eine etwas verbesserte und immer wieder aktualisierte Variante liegt dem glScene Projekt bei.
Matrixmultiplikation
Eine wichtige Operation ist die Matrixmultiplikation. Sie verbindet zwei Matrizen zu einer so, dass sie nacheinander ausgeführt werden. Dabei ist zu bedenken, dass die Reihenfolge einen Unterschied macht: erst drehen und dann verschieben ist ungleich erst verschieben und dann drehen, aber das sollte eich bei der Verwendung von glRotate und glTranslate bereits aufgefallen sein.
/-- Genauere beschreibung wie das geht --/
Matrixinversion
Eine invertierte Matrix macht genau das Gegenteil der ursprünglichen Matrix. Verschiebt die ursprüngliche ein Vertex um 3 nach rechts, so schiebt die intervtierte Matrix ein Vertex um 3 nach links(Achtung: nicht alle Matrizen sind invertierbar, Rotations- und Translationsmatrizen lassen sich jedoch immer invertieren). Dies lässt sich sinnvoll bei Kameras einsetzen:
Man hat ein Objekt, dessen Rotation durch eine Matrix beschrieben wird, was generell sinnvoll ist, wenn das Objekt voneinander abhängige Drehungen vollführen soll oder man das lokale Koordinatensystem des Objekts benötigt. Jedenfalls will man nun das Objekt nicht von aussen bestaunen, sondern sich in die Ansicht des Objekts selbst hineinversetzen, so kann man dessen Rotationsmatrix einfach invertieren und schon hat man sein Ziel erreicht. Wen ähnliches interessiert, sollte sich jetzt einmal an mein Kamera Tutorial wagen und schauen, dass er's versteht.
/-- Genauere beschreibung wie das geht --/
OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen
Wie hat man sich gefreut, als man glaubt Matrizen endlich ein wenig verstanden zu haben und dann das. Die ersten Versuche mit glLoadMatrix und glMultMatrix müssen zwingend schiefgehen. Immer, wenn man nicht vorgewarnt wird. Wer glaubt seine Matrizen einfach mit einem 2 Dimensionalen Array beschreiben zu können irrt. Die Idee ist zwar nicht schlecht, aber aus Performancegründen liegen die OpenGl Matrizen nicht zeilenweise, sondern spaltenweise im Speicher:
Ich persönlich bevorzuge meist, statt dass ich in einem 2D-Array immer mit den Zugriffsvariablen herumwurschtle, den Zugriff auf die Matrix mit einem eindimensionalen Array. Die obige Tabelle hilft dabei, die passene Zelle zu finden.
Kopfschmerzen?
Ahh, wieder eines meiner schrecklichen Tutorials überlebt. Ich hoffe, dass wenigstens ein paar Leute unter euch das ein oder andere Verstanden haben und ich das alles nicht umsonst geschrieben habe (wenns nur einer Verstanden hat, bin ich schon glücklich ;-) ).
...have a lot of fun!
[Nico Michaelis]
|
||
Vorhergehendes Tutorial: Tutorial Lineare Algebra |
Nächstes Tutorial: Tutorial Objekt gedreht und dennoch nach vorne bewegt |
|
Schreibt was ihr zu diesem Tutorial denkt ins Feedbackforum von DelphiGL.com. Lob, Verbesserungsvorschläge, Hinweise und Tutorialwünsche sind stets willkommen. |