<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=DeepCopy</id>
		<title>DGL Wiki - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=DeepCopy"/>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php/Spezial:Beitr%C3%A4ge/DeepCopy"/>
		<updated>2026-05-30T22:17:07Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23953</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23953"/>
				<updated>2009-07-25T18:05:42Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Trigonometrie am rechtwinkligen Dreieck */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen auf der x/z-Ebene), bei entfernter Betrachtung, selbst wieder einen Kreis (hier blau gezeichnet) beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-). Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]] &lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
Delphic&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23936</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23936"/>
				<updated>2009-07-23T15:25:23Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Dreh- und Angelpunkt des Geschehens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix gezeichnet. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° (gegen den Uhrzeigersinn) um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Wir rufen einfach glTranslate* und anschließend glRotate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen, verschobenen Punkt, oooh wie wunderbar... g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Rotiert Ihr zuerst euer Objekt und beginnt dann die Translation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel mit negativem Winkel zur Veranschaulichung, der schwarze Punkt stellt die Rotationsgerade dar, senkrecht zur Ebene:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23935</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23935"/>
				<updated>2009-07-23T15:19:48Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Meinen Unsinn korrigiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix gezeichnet. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° (gegen den Uhrzeigersinn) um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Wir rufen einfach glTranslate* und anschließend glRotate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen, verschobenen Punkt, oooh wie wunderbar... g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Rotiert Ihr zuerst euer Objekt und beginnt dann die Translation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel mit negativem Winkel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23932</id>
		<title>Datei:translation-vs-rotation.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23932"/>
				<updated>2009-07-23T15:11:41Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: hat eine neue Version von „Datei:translation-vs-rotation.png“ hochgeladen: Falsches Schema korrigiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23921</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23921"/>
				<updated>2009-07-23T05:56:22Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Und Cut! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und Quadrat 2 ist hier für OpenGL genau die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdet Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Nein...? Doch! Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Modellmatrix vor dem Rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mit in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt [Anmk: Die Grafikkarte speichert alle Objekte einer Displayliste in ihrem Grafikartenspeicher, um die Displayliste jetzt anzeigen zu lassen muss der Grafikkarte nur die Nummer der jeweiligen Displayliste übergeben werden und nicht nochmals alle Objekte, das spart eine Menge Bandbreite, Voraussetzung ist allerdings genügend Grafikkartenspeicher]. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht zu Hand haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang die Eigenschaften (oder besser den Aufbau) der Objekte der Displayliste verändern, z.B. die wahre Form oder die Farbe einzelner Punke innerhalb der Liste verändern wollen, so würde hier eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23920</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23920"/>
				<updated>2009-07-23T05:44:08Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Und Cut! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und Quadrat 2 ist hier für OpenGL genau die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdet Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Nein...? Doch! Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Modellmatrix vor dem Rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mit in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt [Anmk: Die Grafikkarte speichert alle Objekte einer Displayliste in ihrem Grafikartenspeicher, um die Displayliste jetzt anzeigen zu lassen muss der Grafikkarte nur die Nummer der jeweiligen Displayliste übergeben werden und nicht nochmals alle Objekte, das spart eine Menge Bandbreite, Voraussetzung ist allerdings genügend Grafikkartenspeicher]. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht zu Hand haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23919</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23919"/>
				<updated>2009-07-23T05:29:48Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Vorsicht! Aufnahme */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und Quadrat 2 ist hier für OpenGL genau die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdet Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Nein...? Doch! Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Modellmatrix vor dem Rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mit in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt [Anmk: Die Grafikkarte speichert alle Objekte einer Displayliste in ihrem Grafikartenspeicher, um die Displayliste jetzt anzeigen zu lassen muss der Grafikkarte nur die Nummer der jeweiligen Displayliste übergeben werden und nicht nochmals alle Objekte, das spart eine Menge Bandbreite, Voraussetzung ist allerdings genügend Grafikkartenspeicher]. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht hand zu haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23918</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23918"/>
				<updated>2009-07-23T05:22:33Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Rechtschreibfehler korrigiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und Quadrat 2 ist hier für OpenGL genau die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdet Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Nein...? Doch! Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Modellmatrix vor dem Rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mit in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht hand zu haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23917</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23917"/>
				<updated>2009-07-23T05:21:28Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Rechtschreibfehler korrigiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und Quadrat 2 ist hier für OpenGL genau die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdet Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Nein...? Doch! Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Modellmatrix vor dem Rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mir in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht hand zu haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23916</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23916"/>
				<updated>2009-07-23T05:17:11Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Eine abstrakte Wahrheit… */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und Quadrat 2 ist hier für OpenGL genau die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdest Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Matrix vor dem rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mir in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht hand zu haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23915</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23915"/>
				<updated>2009-07-23T05:09:03Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Besser formuliert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und Quadrat 1 ist hier für OpenGL genau die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdest Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Matrix vor dem rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mir in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht hand zu haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23914</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23914"/>
				<updated>2009-07-23T05:06:10Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Eine abstrakte Wahrheit… */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersinn, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und genau hier ist auch für OpenGL die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdest Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Matrix vor dem rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mir in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht hand zu haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23913</id>
		<title>Tutorial Lektion 5</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_5&amp;diff=23913"/>
				<updated>2009-07-23T05:05:37Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Eine abstrakte Wahrheit… */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Artenvielfalten und Ihre Folgen =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Und wieder einmal aufraffen und etwas tippen. Es ist wirklich nicht immer leicht solche Tutorials zu schreiben, vor allem wenn man mal wieder eine Null-Bock-Phase hat. Ich hoffe doch sehr, dass auch Ihr dafür Verständnis habt, den… auch ich bin ein Mensch… egal wie viele Augen und Beine ich habe *sg* Gut… genug &amp;quot;gefaxt&amp;quot;, es geht wieder um den Ernst im Leben: Delphi&lt;br /&gt;
&lt;br /&gt;
Ich habe wirklich eine zeitlang überlegt, was wir machen sollten. Einige haben sich Lichter gewünscht, aber ich konnte mich nicht dazu aufraffen… Stattdessen habe ich irgendwie Lust gehabt, mal was anderes zu machen, etwas wo man etwas kreativ sein kann und was auch mir Spaß macht! :-D Und deswegen, habe ich mir gedacht, dass wir das eine oder andere Wissen, welches zwischendurch behandelt wurde noch etwas vertiefen sollten… einfach in dem wir andere Möglichkeiten aufzeigen, elegant ein Problem zu umschiffen und auch den einen oder anderen Effekt erzielen!&lt;br /&gt;
&lt;br /&gt;
Und genau darum geht es auch diesmal! Ich denke, dass sich dieses Tutorial weitestgehend nur an die richten wird, die bereits ein solides Wissen in OpenGL und Delphi haben, ansonsten wird es wohl schwer sein mir zu folgen, ich werde einiges an Wissen woraus setzen! Wer folgen kann, wird dann mit einem Wissen belohnt werden, dass ihm das eine oder andere Probleme sehr elegant umschiffen lässt in dem man einfach seine Software entsprechend mit OpenGL optimiert! Den nur wer sein Handwerk bis ins Detail beherrscht, darf sich Meister nennen ;)&lt;br /&gt;
&lt;br /&gt;
== Unbekannte Zeichen-Arten ==&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Maxime ===&lt;br /&gt;
&lt;br /&gt;
Wer nicht gerade erst jetzt hier eingestiegen ist, wird sicherlich bereits bemerkt haben, dass OpenGL streng genommen nach einem sehr einfachen Prinzip arbeitet. Ständig wird an unserer &amp;quot;Zustand-Maschine&amp;quot; etwas manipuliert und mit Matrizen setzen wir die Positionen fest. Jedoch nur an einer einzigen Stelle kommen alle diese Werte zusammen. Nämlich dann, wenn etwas gerendert wird. Genau in diesem Moment werden alle Werte &amp;quot;zusammengerechnet&amp;quot; und erzeugen etwas Sichtbares auf dem Bildschirm. In den meisten Fällen wird dies Eben zwischen glBegin und glEnd geschehen. Und genau diese beiden Funktionen wollen wir nun näher betrachten. Interessant hierbei ist nämlich der Parameter von glBegin…&lt;br /&gt;
&lt;br /&gt;
Streng genommen definieren wir nur eine Anzahl von Punkten zwischen glBegin und glEnd, der Parameter bei glBegin bestimmt aber letztendlich wie diese Verstanden werden sollen. Nur als kleine Übersicht alle verfügbaren Parameter:&lt;br /&gt;
&lt;br /&gt;
 GL_POINTS&lt;br /&gt;
 GL_LINES&lt;br /&gt;
 GL_LINE_STRIP&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
 GL_QUAD_STRIP&lt;br /&gt;
 GL_POLYGON&lt;br /&gt;
&lt;br /&gt;
Ich denke aus ethischen Gründen werde ich nun darauf verzichten Euch erneut zu erklären wofür, die bisher für Euch bekannten Parameter (gl_Triangle und gl_Quad) gut sind… jeder wird sich denken können, dass das erste immer per 3er Punkte ein Dreieck bildet, dass zweiter aus 4 Punkten ein Quadrat erzeugt… (mist… *g*) ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Zunächst war der Strich ===&lt;br /&gt;
&lt;br /&gt;
Interessanter, da neu für uns, sind die restlichen Parameter, auch wenn diese sich weitestgehend selbst erklären. Gl_Points z.B. … könnte es vielleicht bedeuten, dass OpenGL alle mit [[glVertex3f]] definierten Punkte auch nur als Punkte zeichnet?&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_point.gif]]&lt;br /&gt;
&lt;br /&gt;
Scheint zu stimmen… ;) Es ist nun auch nicht besonders schwer herzuleiten, was OpenGL mit Vertex-Definitionen macht, die mit gl_Lines beginnen. Versuchen wir doch mal ein Dreieck damit zu zeichnen! Ergo brauchen wir 4 Punkte (der letzte muss, auf den ersten verweisen)…&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_lines.gif]]&lt;br /&gt;
&lt;br /&gt;
Doch was ist das? Dies ist kein böswilliger Trick, den ich auf Euch spielen will, sondern folgender Code, ist dafür verantwortlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht soweit alles in Ordnung aus - ist es auch! Der Fehler liegt nämlich nicht am Code, sondern an uns selbst. Gl_Lines bewirkt nämlich nicht, dass alle Punkte miteinander verbunden werden, sondern nur, dass jeweils Punkte 1 mit Punkte2, Punkte 3 mit Punkt 4 etc. verbunden werden, d.h. immer zweiter Pärchen. Um das Ergebnis zu erreichen, welches wir angestrebt haben (und zwar ohne 6 Punkte zu definieren), wäre in diesem Fall nämlich gl_Line_Strip gewesen, was nämlich bewirkt, dass der &amp;quot;Zeichenstift&amp;quot; immer von seiner letzten Position zum nächst definierten Punkte einen Strich zieht. Dementsprechend sieht dann unser Dreieck mit praktisch dem gleichen Source wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_line_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
hr merkt bereits jetzt wie viele Möglichkeiten einen OpenGL bietet mit nur wenigen Zeilen eine Menge zu verändern. Man bedenkt, dass wir hier nur sehr wenige Punkte haben, allerdings kann man eine Menge Leistung rausschlagen, wenn man statt gl_Lines, gl_Line_Strip verwendet, da einfach weniger Punkte abgearbeitet werden müssen. Logisch oder?&lt;br /&gt;
&lt;br /&gt;
 GL_LINE_LOOP&lt;br /&gt;
&lt;br /&gt;
Der Parameter entspricht praktisch gesehen GL_LINE_STRIP, nur das der letzte Punkt mit dem ersten verbunden wird. Man bräuchte mit diesem Parameter also nur 3 Punkte… das Optimum für unser Dreieck! ;)&lt;br /&gt;
&lt;br /&gt;
== Artenvielfalt ==&lt;br /&gt;
&lt;br /&gt;
Natürlich lassen sich solche Zeichenoperationen auch durch eine Menge anderer Faktoren beeinflussen. Vielleicht hat sich der eine oder andere ja bereits gefragt, wie man es schafft, dass der Rahmen des Dreiecks dicker gezeichnet wird. Sicherlich könnte man nun beginnen und ganz leicht versetzt daneben noch ein Dreieck zu zeichnen. Dies würde dann natürlich einen kleinen Tick größer wirken.&lt;br /&gt;
&lt;br /&gt;
Die Lösung liegt allerdings viel näher - den OpenGL bietet hierfür eine hauseigene Lösung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLineWidth(3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir stellen einfach ein, wie OpenGL die Linien Rastern soll. Wir nehmen in diesem Fall die dreifache Dicke von der normalen Einstellung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gllinewidth.gif]]&lt;br /&gt;
&lt;br /&gt;
Auch werden einige von Euch sicherlich die unschönen Treppchen kennen, die vor allem bei solch einfache Konstruktionen wie diesm dickeren Dreieck auftreten können. Die Lösung dagegen heißt bekanntlich &amp;quot;AntiAliasing&amp;quot; … verschlägt es Euch die Sprache, dass ich gleich mit solch derben Geschützen auffahre?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LINE_SMOOTH);&lt;br /&gt;
  glDisable(GL_LINE_SMOOTH);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da verschlägt es einem die Sprache oder? Das war es nämlich auch bereits wieder. Wir schalten einfach einen Zustand um und fertig war die Geschichte! Der Zustands-Maschine von OpenGL sei dank, müssen wir nur noch sagen, was gemacht werden soll, ein lästiges &amp;quot;Wie?&amp;quot; entfällt komplett&lt;br /&gt;
&lt;br /&gt;
Und noch ein kleines Beispiel dafür, wie einfach OpenGL nicht nur Informationen schreiben lässt, sondern diese auch wieder preisgibt. Haben wir vergessen wie Dick wir die Linien eingestellt haben? Kein Problem, den OpenGL bietet folgende Funktionen um zu ermitteln, auf welchen Wert ein &amp;quot;Zustand&amp;quot; geschaltet ist:&lt;br /&gt;
&lt;br /&gt;
[[glGetBooleanv]], [[glGetDoublev]], [[glGetFloatv]], [[glGetIntegerv]]&lt;br /&gt;
&lt;br /&gt;
Ich glaube ich brauche nicht wieder damit zu beginnen darauf hinzuweisen, dass man bei jeder Abfrage auch den richtigen Variablen-Typen verwenden sollte *g*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glGetIntegerv(gl_line_width,@myint);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon haben wir in myint die Stärke mit der OpenGL momentan alle Linien zeichnen soll. Das geht mit fast allen Zuständen, die OpenGL haben kann. Ich denke, das Grundprinzip ist recht leicht verständlich. Beachtet auch, dass OpenGL bei solchen Funktionen immer einen Pointer auf eine Variable erwartet (sprich besser: eine Adresse) und nicht die Variable selbst!&lt;br /&gt;
&lt;br /&gt;
Achso… vergaß ich zu erwähnen, dass wir auch weitere Funktionen auf Striche anwenden können? Zum Beispiel glColor, um den Strich einzufärben? Auch der Z-Buffer lasst sich darauf anwenden, eben alles, was man auch bei einem Dreieck tun könnte (wovon man aber zwingend absehen sollte eine Linie zu texturieren, um keine unnötigen Berechnungen durchzuführen)&lt;br /&gt;
&lt;br /&gt;
=== Ein Dreieck, hat drei Ecken… ===&lt;br /&gt;
&lt;br /&gt;
Nun dreht sich erstmal alles um Dreiecke. Den auch hierfür bietet OpenGL mehre Möglichkeiten, wie die Reihenfolge der Punkte verstanden wird:&lt;br /&gt;
&lt;br /&gt;
 GL_TRIANGLES&lt;br /&gt;
 GL_TRIANGLE_STRIP&lt;br /&gt;
 GL_TRIANGLE_FAN&lt;br /&gt;
&lt;br /&gt;
Zunächst widmen wir uns GL_TRIANGLES! Dieser Parameter sollte uns allen noch geläufig sein. Jeweils 3 Punkte werden zusammen zu einem eigenständigen Dreieck verbunden. Nicht neues für uns, bereits im ersten Tutorial könnt ihr den Beweis finden, dass es klappt :-D&lt;br /&gt;
&lt;br /&gt;
Sicherlich werdet ihr Euch denken können, dass dies sehr hilfreich ist, wenn man nur ein Dreieck zeichnen möchte, nicht jedoch, sobald man mehre in einem Rutsch auf dem Bildschirm bringen möchte. Hierzu bietet sich dann eher GL_TRIANGLE_STRIP an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wem das ganze zu schwer erscheint, sollte er sich die glColor3f weglassen, die habe ich reingesetzt, damit das ganze auch schön aussieht ;) (Programmierer lieben sinnlosen Spielkram der glänzt und bunt ist). Wer sich nur auf die Punkte konzentriert und sich die Position im Kopfe vorstellt, wird ein Gebilde wie folgt vorstellen können:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Streng genommen macht OpenGL nichts anderes, als die ersten drei Eckpunkte zu nehmen und ein Dreieck daraus zu rendern. Anschließend fällt der erste Punkt weg und es wird das Dreieck zwischen 2,3,4 gerendert usw. Im Anschluss dieses Kapitels werden wir nochmals hieraus zurückkommen und das Culling erklären!&lt;br /&gt;
&lt;br /&gt;
=== Ventilatoren und OpenGL ===&lt;br /&gt;
&lt;br /&gt;
Tja, und nur die wenigstens wissen, dass auch ein Ventilator ein Dreieck sein kann *hust* Okay, begnügen wir uns hier lieber mit dem englischen Begriff &amp;quot;Fan&amp;quot;. (Das ist nicht der Kerl, der vorm Fenster steht, einem gierig anstarrt und laut ruft &amp;quot;Ich will ein Kind von Dir…&amp;quot; … nein, sicher nicht ;)&lt;br /&gt;
&lt;br /&gt;
Vielmehr sollten wir uns wirklich mal bildlich einen Fahrrad-Reifen vorstellen. Von den Außenseiten verlaufen die einzelnen Speichen alle zu einem Mittelpunkt. Nach einem ähnlichen Render-Prinzip funktioniert auch GL_TRIANGLE_FAN. Der einfachheitshalber werden wir hier jedoch kein komplexes Objekt anfertigen, sondern nur eine Möglichkeit zeigen, wie man mit dieser Einstellung sinnvoll ein Objekt zeichnen kann! In unserem Fall nehmen wir einfach einen Drachen (nein… nicht das Fabelwesen), denn auch dieser ist ein Ventilator (Chaos… perfekt….) ;)&lt;br /&gt;
&lt;br /&gt;
Bevor nun jeder abdreht, schauen wir uns doch mal das Objekt an, von dem ich sprach:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_triangle_fan.gif]]&lt;br /&gt;
&lt;br /&gt;
In diesem Fall benötigen wir nur 6 (!) Punkte, um dieses Gebilde zu erzeugen. Zentraler Ausgangspunkt ist hierbei die Nummer 1. Wie man erkennen kann besteht das erste Dreieck aus 1,2,3. Das zweite aus 1,3,4… für die abstrakt denkenden Menschen lässt sich daraus folgern, dass OpenGL die Punkte wie folgt abarbeitet 1, n+1, n+2. Oder um es neudeutsch zu sagen, der erste Punkte wird immer mit zwei weiteren verbunden. Im Gegensatz zum Strip fällt allerdings nicht der erste Punkt raus, sondern immer der zweite.&lt;br /&gt;
&lt;br /&gt;
Gl_Triangle_Fans und Gl_Triangle_Strips sind wohl die besten Möglichkeiten, um die Anzahl der im Video-Speicher befindlichen Daten zu begrenzen. Allerdings lässt sich schnell erahnen, dass nicht jeder dieser Methoden wirklich komplexe Objekte zulässt. Man sollte sie jedoch nicht total ignorieren, sondern mit Verstand einsetzen. Ach so, bevor ich es vergesse, der Code dafür:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_TRIANGLE_FAN);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,-3,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(-1,0,0);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man beachte, dass Punkte 2 und Punkte 6 identisch sind, da er sonst das letzte Dreieck weglassen würde ;)&lt;br /&gt;
&lt;br /&gt;
=== Quadratisch, praktisch, gut! ===&lt;br /&gt;
&lt;br /&gt;
Das ist ne wahrer Marathon geworden. Schlimm, wenn man bedenkt, dass wir uns hier nur mit einem Parameter für eine Funktion beschäftigen. Ihr versteht, warum ich so oft geschrieben haben &amp;quot;lassen wir es lieber und klären nicht jeden Parameter&amp;quot; ;) Aber gut, ich halte es für sehr wichtig, solche Dinge zu beherrschen, weil es einfach zu den Grundlagen dazugehört! Immerhin bleiben nicht mehr sonderlich viele übrig, als ran an die letzten drei!&lt;br /&gt;
&lt;br /&gt;
 GL_QUADS&lt;br /&gt;
&lt;br /&gt;
Sollte auch niemanden von uns mehr sonderlich schockieren können. Jeweils vier übergebende Punkte werden zusammengefasst zu einem Quadrat… nichts weiter Aufregendes. Eigentlich sollten inzwischen auch die GL_QUAD_STRIP nichts wirklich erstaunliches mehr liefern. Wir übergeben zunächst vier Punkte und bei jedem Durchgang entfallen die beiden ersten und werden durch die nächsten zwei ersetzt. OpenGL erstellt dann daraus jedes Mal ein Viereck. Bitte nicht verwechseln mit der Punkt-Reihenfolge von GL_QUADS. Folgendes Beispiel sollte die Problematik verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glBegin(GL_QUAD_STRIP);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(2,0,0);&lt;br /&gt;
    glVertex3f(2,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glVertex3f(3,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_quad_strip.gif]]&lt;br /&gt;
&lt;br /&gt;
Unser erstes Quadrat besteht aus den Punkten 1,2,3,4, dass zweite aus 3,4,5,6 etc. Ich denke, dass das Prinzip dahinter leicht verständlich ist. Anbieten tut sich diese Lösung meist in Schleifen, wenn man längere solcher Quad-Strukturen braucht, die aneinander gereiht sind&lt;br /&gt;
&lt;br /&gt;
=== Vieleckerei ===&lt;br /&gt;
&lt;br /&gt;
Und zu guter letzt GL_POLYGON, was wohl am einfachsten nachzuvollziehen ist ;) Es wird einfach eine Liste von Punkten übergeben und daraus wird schlicht und ergreifend dann ein Vieleck gemacht. Wie variantenreich dies werden kann, könnt ihr Euch vorstellen. Vor allem komplexere und exotischere Formen lassen sich damit darstellen, auch wenn es in diesem Fall eher Leitung kostet als wirklich einbringt. Zeichnet also niemals ein Quadrat mit GL_POLYGON.&lt;br /&gt;
&lt;br /&gt;
Eine mögliche Form wäre zum Beispiel diese:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_gl_polygon.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(3,0,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(4,1,0);&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(2,2,0);&lt;br /&gt;
    glColor3f(0,1,1);&lt;br /&gt;
    glVertex3f(-2,3,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(-1,1,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke zusammen mit dem Code sollte es keine weiteren Fragen mehr dazu geben. Am besten setzt Ihr Euch nun alle einmal hin und wendet das Wissen Testweise an, denn es muss sitzen und stellt vor allem, wenn es um optimierte Programmierung geht ein absolutes Grundwissen da! Ihr werdet mit etwas praktischer Erfahrung schnell die Grenzen finden, die die einzelnen Parametern mit sich bringen z.B. bei der Texturierung von Objekten!&lt;br /&gt;
&lt;br /&gt;
Ein Quadrat besteht aus einem Face (Fläche), ein Quadrat zusammengesetzt aus zwei Triangle aus zwei. Man könnte zum Beispiel letzteres mit zwei Texturen versehen, ersteres nur mit einer!&lt;br /&gt;
&lt;br /&gt;
== Das Culling-Verfahren ==&lt;br /&gt;
&lt;br /&gt;
=== Wahrheiten und Wirklichkeiten ===&lt;br /&gt;
&lt;br /&gt;
;Dramatik:&lt;br /&gt;
Bevor wir uns mit der eigentlichen Technik des Cullings befassen, möchte ich eine radikale Aufklärung betreiben, die Euer Weltbild für immer verändern wird. Seit gewarnt, dass Ihr nach dem lesen der folgenden Zeilen, Eure Quake3-Gegner mit ganz anderen Augen sehen werdet und eventuell nie wieder zu Eurer alten Denkweise zurückkehren werden könnt!&lt;br /&gt;
&lt;br /&gt;
Habt Ihr Euch bereits gefragt wie die kommerziellen Spiele es schaffen ohne Ruckler (*hust), super Grafiken auf den Bildschirm zu bringen, die auch nach der Optimierung immer noch durch grafische Qualität überzeugen können? Nun, es gibt viele Möglichkeiten seine Szenen zu optimieren, dass wohl einfachste und auch mit am effizientesten ist das so genannte Culling-Verfahren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper1.gif]]&lt;br /&gt;
&lt;br /&gt;
So sieht unser Protagonist wie gewohnt aus. Wir sehen ihn wie er liebt und lebt. (ja…) Um es philosophisch auszudrücken, sehen wir hier jedoch nur die halbe Wahrheit… ich stelle die wage Behauptung aus, dass wir der Rückseite von ihm gar nicht sehen können und daher auch nicht sagen können, ob sie existiert! Jedes Mal, wenn wir uns um ihn herum bewegen sehen wir nie seine Rückseite. Nun… das wäre auch nicht weiter fatal, wenn ich nicht sofort eine weitere These aufstellen würde: &amp;quot;Der Kerl hat gar keine Rückseite&amp;quot; :-O&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Aber! Wenn wir um ihn herum gehen, dann sehen wir doch seine Rückseite, also ist sie da!&amp;quot;, könnte man mir nun skeptisch zurufen. Tja… beweist mir das Gegenteil und schickt einen Wetteinsatz an mich, ich werde Euch beweisen, dass er immer nur eine Seite hat und seine Rückseite erst erzeugt wird, wenn sie auch benötigt wird. Es würde dann aussage gegen Aussage stehen und ihr könntet mir nicht beweisen, dass Ihr Recht habt, denn wenn wir um ihn herum gehen, würden wir ja wieder seine Rückseite nicht sehen. Ich hingegen würde den Beweis antreten und Euch mitteilen, dass wir ja einfach mal uns die Rückseite ansehen, dann allerdings auf die Forderseite verzichten müssen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_trooper2.gif]]&lt;br /&gt;
&lt;br /&gt;
Was auf den ersten Blick wie ein verschwommendes Etwas aussieht entpuppt sich auf den zweiten Blick bereits als unser Soldat vom ersten Bild. Skeptisch wird man sich sicherlich fragen, was geschehen ist. Und wenn man genau durch ihn durch sieht, erkennen wir, dass wir hier z.B. seine Hose sehen… und seinen Kopf auch irgendwie von … hinten! Was ist geschehen? Wir betrachten Ihn von vorne und sehen, was hinten ist! (Oh Gott… eine ganze Wirklichkeit stürzt in sich ein *sg* ).&lt;br /&gt;
&lt;br /&gt;
Natürlich ist das verschwommende Ding da oben nicht ein grafisches Ziel, was wir erreichen wollen, sondern nur der Beweis dafür, dass jede Figur zwei Seiten hat (Erkenntnis, aufschreiben!) und wir in OpenGL bestimmen können, welche Seite wir von Vorne oder Hinten betrachten können.&lt;br /&gt;
&lt;br /&gt;
Ich gebe ja auch zu, dass ich ein wenig getrickst habe und im oberen Bild, die Figur zweimal genredert habe, davon einmal die Vorderseite mit Alpha Blending, weil auf einem unbewegten Bild es schwer zu erkennen wäre, welches die Vorder und welches die Rückseite ist, da wir die Texturen eben gespiegelt auf dem Modell sehen würden.&lt;br /&gt;
&lt;br /&gt;
=== Eine abstrakte Wahrheit… ===&lt;br /&gt;
&lt;br /&gt;
An sich klingt bisher doch auch noch alles recht logisch oder? Den wieso sollte OpenGL die Rückseite von Objekten rendern, wenn man sie gar nicht sehen kann. Grob würde dies eben die doppelte Arbeit sein, die sinnlos getätigt wird. Der Laie wird nun vor Freude an die Decke springen, der erfahrene Programmierer skeptisch die Falten runzeln. &amp;quot;Wie erkennt OpenGL, den das es sich um die Rückseite handelt!&amp;quot;. Gute Frage oder? Des Lösung-Rätsel sollte ein Blick auf die Uhr zeigen… (&amp;lt;== nein, er spinnt nicht (Anm. v. Flo2))&lt;br /&gt;
&lt;br /&gt;
Aber was meine ich damit? Was haben unsere Objekte mit einer Uhr gemeinsam? Was zunächst einem komisch vorkommt ist eigentlich logisch: Es ist die Laufrichtung! Unsere Uhr wird im Normalfall im Uhrzeigersinn laufen das heißt mit dem Uhrzeigersin, die Entgegengesetzte Richtung nennen wir dann entgegen des Uhrzeigersinnes. Das wird nun vielleicht den einen oder anderen dazu gebracht haben ein leises Aua von sich zu geben und sich mit der Hand an die Rübe zu schlagen. Diese Erkenntnis ist jedoch grundlegend ^__-&lt;br /&gt;
&lt;br /&gt;
Denn auch unsere Objekte haben eine gewissen Definitionsreihenfolge. Wir werden die Problematik im Weiteren an Hand eines Quadrates verfolgen ;) Folgender Code ist nicht gleich…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
    glColor3f(0,1,0);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glEnd;&lt;br /&gt;
&lt;br /&gt;
  glBegin(GL_QUADS);&lt;br /&gt;
    glColor3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,0,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(1,1,1);&lt;br /&gt;
    glVertex3f(1,1,0);&lt;br /&gt;
&lt;br /&gt;
    glColor3f(0,0,1);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
  glEnd;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer das Culling nicht verstanden hat, wird sich fragen, wo der unterschied liegt, den beide Stücke beschreiben ein und das gleiche Dreieck. Der Unterschied wird erst deutlich, wenn wir uns die Definitionsreihenfolge vor Augen führen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_order.png]]&lt;br /&gt;
&lt;br /&gt;
Und genau hier ist auch für OpenGL die Definition von &amp;quot;Rückseite&amp;quot;. Normalerweise erwartet OpenGL nämlich, dass alle Punkte gegen den Uhrzeigersinn definiert werden, also so wie beim ersten Quadrat. OpenGL würde in seinem Normalzustand dies dann als die Vorderseite ansehen. Mit einer einzigen Zeile können wir dieses Verhalten jedoch auch verändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glFrontFace(GL_CW);        //Clock-Wise&lt;br /&gt;
  glFrontFace(GL_CCW);       // Counter Clock-Wise&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist jedoch zu empfehlen diese Reihenfolge beizubehalten, da andere Programmierer, die Euren Source lesen, ebenfalls davon ausgehen werden, dass ihr die Punkte gegen den Uhrzeigersinn definieren werdet. Nur bei einigen Optimierungsverfahren macht ein umschalten wirklich Sinn.&lt;br /&gt;
&lt;br /&gt;
=== … und eine verlogene Wirklichkeit ===&lt;br /&gt;
&lt;br /&gt;
Vielleicht springt mal wieder jemand auf und wird mich beschuldigen totalen Mist erzählt zu haben… immerhin zeichnet er vielleicht bei Euch mit beiden Code-Schnipseln die Quadrate? Das liegt einfach daran, dass OpenGL das Culling standardgemäß deaktiviert hat und somit auch beide Seiten rendert. Wie man Culling aktivieren kann, ist schon fast ratbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_CULL_FACE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glDisable dementsprechend können wir es wieder deaktivieren. Sollten wir beide Quadrate nebeneinander gerendert haben und eben an den Grundeinstellungen nichts verändert haben, sollte mit der Aktivierung dieser Seite nur noch das linke Dreieck angezeigt werden, weil OpenGL es als Vorderseite ansieht. Wollen wir, dass er nur die &amp;quot;Rückseiten&amp;quot; rendert, so lässt sich dies erfolgreich mit einem weiteren Funktionsauruf realisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_FRONT);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit glCullface können wir immer die Seite angeben, die OpenGL vernachlässigen soll. In diesem Fall wäre dies dann die Vorderseite, die nicht gezeichnet werden würde (oder eben das rechte Dreieck).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCullface(GL_BACK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Würde wieder den ursprünglichen Status herstellen. Zusammengefasst : glCullFace definiert, ob Vorder oder Rückseite weggelassen werden sollen, glFrontFace definiert, wie die Vorderseite definiert ist (im oder gegen Uhrzeigersinn!) und mit glEnable müssen wir das Culling zunächst aktivieren (und das sollten wir auch immer tun, wenn es möglich ist!).&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, ich habe es halbwegsverständlich erklärt. Wenn jemand sich jetzt fragt, wie man nun die Rückseite sehen kann, wenn wir ein Quadrat haben, dass im Uhrzeigersinn definiert ist… Wenn wir von vorne drauf sehen, werden wir es nicht sehen, da die Punkte in der falschen Reihenfolge definiert sind. Bewegen wir uns durch das Dreieck hin durch und drehen uns um, so werden wir feststellen, dass die Punkte wieder in der &amp;quot;richtigen&amp;quot; Reihenfolge definiert sind und OpenGL sie rendern wird. Wir haben dies hier nur bei sehr simplen Gebilden betrachtet, aber auch bei komplexen ist das Prinzip gleich!&lt;br /&gt;
&lt;br /&gt;
Auch bei möchte ich noch einmal ein gutes Beispiel sehen, wo man bei komplexeren Objekten das Culling gut erkennen kann. Nämlich unserer Landschaft aus dem vierten Tutorial:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion5_culledland.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dies sieht zunächst nach einem schweren Grafikfehler aus… ist es jedoch nicht. Wir betrachten unsere Landschaft hier nur von einer Seite, die der Spieler nicht sehen würde, nämlich von der Unterseite. Wir sehen die Landschaft von unten bei aktivieren Culling (Anm.: Beim vierten Tutorial ist KEIN Culling von mir aktiviert worden!) und da ich die Quadrate alle richtig definiert habe sehen wir auch nur noch die, die dem Spieler zu gewannt sind. Etwas Fantasie benötigt man schon dazu, um dies wieder zu erkennen, allerdings sieht man es oben rechts doch noch recht gut. Ich hoffe, dass spätestens dieses kleine Beispiel es noch verständlicher gemacht hat, wenn nicht… schaut Euch die Samples an und fragt dann im Forum nach ;)&lt;br /&gt;
&lt;br /&gt;
BTW: Für psychische Folgen, die beim Lesen dieses Tutorials entstanden sind, übernimmt der Autor keine Haftung. Auch er hat bisher keinen glaubwürdigen Beweis dafür gefunden, dass seine Mitmenschen eine Rückseite haben. Auch die Betrachtung dieser mit Hilfe eines Spiegels kann eine zusätzlich Render-Routine der Engine sein, in der wir leben. Es ist jedoch höchst wahrscheinlich, dass sie keine haben, weil … wer sollte die ganze Rechenleistung aufbringen, um die Vorder- und Rückseite aller Menschen zu rendern! :-D&lt;br /&gt;
&lt;br /&gt;
== Für das Protokoll ==&lt;br /&gt;
&lt;br /&gt;
=== Grundgedanken zu Display-Listen ===&lt;br /&gt;
&lt;br /&gt;
Bisher sind wir sicherlich noch nicht in die Verlegenheit gekommen, komplexere Programme zu schreiben. Hat es doch jemand bereits versucht, so wird er schnell gemerkt haben, dass man ohne eine solide Organisation keine Chance hat, ein größeres Projekt zu verwirklichen. Die goldene Regel für eine gelungene Organisation ist sehr einfach! Redundanzen vermeiden um jeden Preis. Man sollte nicht wenn man z.B. ein Quad zeichnen will, diesen 20.000 Mal hintereinander erzeugt. Vielleicht tut es ja auch eine Schleife? Genauso, wie man nicht mehrfach ein Modell in den Speicher laden sollte, wenn es bereits einmal geladen wurde.&lt;br /&gt;
&lt;br /&gt;
Das klingt nun sicherlich wie eine große Verarschung meinerseits. Aber wer jetzt hier geschmunzelt hat, sollte aufpassen, dass ihm nicht gleich das Grinsen im Gesichte stecken bleibt. Würdest Ihr Euer Programm richtig aufbauen? Versuchen eben doppelte Daten zu vermeiden, wo man es nur kann? Wer halbwegs geschickt vorgeht, wird mit Prozeduren, die er immer wieder aufrufen kann eine Menge sinnlosen Code vermeiden. Zum Beispiel wenn wir einen Würfel zeichnen wollen! Wir würden diesen in einer Funktion zeichnen lassen und dann einfach diese Prozedur aufrufen, wenn er gerendert werden soll.&lt;br /&gt;
&lt;br /&gt;
Wünschen wir ihn an einer anderen Stelle in der Welt, so rufen wir einfach die entsprechende Matrix vor dem rendern auf und schon haben wir zwei Würfel in einer Welt mit nur einer Prozedur erzeugt… und die Hälfte an Code gespart. Das lässt sich doch sehen! Auch können wir nun zahlreiche andere Dinge mir in diese Funktion setzen, z.B. eine andere Farbe. Das klingt doch sehr nach einem richtige Ansatz!&lt;br /&gt;
&lt;br /&gt;
=== Vorsicht! Aufnahme ===&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet für ein solches vorgehen ein eigenes System und eine Anzahl von Funktionen, die man unter den Namen &amp;quot;Display-Listen&amp;quot; zusammenfassen kann. Dies kann man sich so vorstellen, dass man einen Namen für eine Liste vergibt (nicht irritieren lassen, ein Name ist in diesem Fall eine Nummer!) und sagt OpenGL, dass alles, was jetzt geschieht mitprotokolliert werden soll. Man kann nun anfangen Objekte zu zeichnen, Farben, Texturen, Materialen, einfach alles was einem in den Sinn kommt zu rendern und OpenGL wird dann all dies in einer Liste zusammen fassen. Es steht dann im fortan für uns auf Abruf zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technisch gesehen ließen sich wohl diese Listen auch mit Prozeduren realisieren, allerdings gibt es auch einen weiteren Vorteil (angeblich… ich konnte ihn nicht nachweisen, evtl. nur einen Sinn in seiner Frühzeit, wo es keine 3D-Karten gab oder nur bei extrem vielen Objekten spürbar…). OpenGL kann diese Befehle nämlich schneller durchführen, weil es die Operationen praktisch vormerkt. Wie auch immer man es sehen mag, Display-Listen sind unglaublich praktisch bei der Programmierung und meist weicht die anfängliche Skepsis durch Begeisterung (und wenn nicht, gehört es zum guten Ton es zu wissen, weil man es häufiger sehen wird)&lt;br /&gt;
&lt;br /&gt;
Zunächst holen wir uns von OpenGL eine Nummer ab, unter welcher wir die Display-Liste später erreichen werden. Diese wird im Idealfall von Typ Integer sein. Der Aufruf ist kinderleicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  Displaylist := glGenLists(1);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
glGenLists liefert und eben den gewünschten Wert zurück. Wir können auch stattdessen ein Array of GLUint nehmen und gleich mehre anfordern.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist dann praktisch aufgebaut wie ein glBegin und glEnd, nur dass die entsprechenden Funktionen diesmal glNewList und glEndList heißen und wie folgt verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glNewList(DisplayList,GL_COMPILE);&lt;br /&gt;
  […]&lt;br /&gt;
glEndList;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GL_COMPILE bewirkt schlicht und ergreifend, dass sich OpenGL die verwendeten Funktionen merkt. Alternativ könnten wie auch noch GL_COMPILE_AND_EXECUTE einsetzen, wenn wir wollen, dass die Liste auch gleich ausgeführt wird. Praktisch alles was zwischen diesen beiden Funktionen steht wird auch mitgeschrieben. Ausnahmen gibt es wir immer und ich werde dies Mal aufführen, ich denke, dass man erahnen kann, warum diese nicht mit unterstützt werden. Es gibt praktisch keinen Sinn diese mit aufzuzeichnen:&lt;br /&gt;
&lt;br /&gt;
[[glColorPointer]], [[glDeleteLists]], [[glDisableClientState]], [[glEdgeFlagPointer]],&lt;br /&gt;
[[glEnableClientState]], [[glFeedbackBuffer]], [[glFinish]], [[glFlush]], [[glGenLists]],&lt;br /&gt;
[[glIndexPointer]],[[glInterleavedArrays]], [[glIsEnabled]], [[glIsList]], [[glNormalPointer]],&lt;br /&gt;
[[glPopClientAttrib]],[[glPixelStore]], [[glPushClientAttrib]], [[glReadPixels]],&lt;br /&gt;
[[glRenderMode]], [[glSelectBuffer]], [[glTexCoordPointer]], [[glVertexPointer]] und&lt;br /&gt;
alle  [[glGet]] Routinen&lt;br /&gt;
&lt;br /&gt;
=== Und Cut! ===&lt;br /&gt;
&lt;br /&gt;
Idealerweise erzeugen wir diese Listen nicht bei jedem Render-Vorgang, sondern nur einmal im Init und führen diese dann nur noch beim Rendern aus. Dies geschieht mit der Funktion glCallList und sollte genauso leicht zu beherrschen sein, wie die bisherigen auch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glCallList(displaylist);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach den Namen der Liste und schon wird alles was wir drinnen aufgezeichnet haben auch ausgeführt… Perfekt, oder? Das ganze ist doch recht leicht hand zu haben und sollte niemanden vor einem großen Problem stellen.&lt;br /&gt;
&lt;br /&gt;
Im Sample haben wir ein kleines Astroiden-Feld nachgebildet, eben mit Hilfe dieser Display-Listen. Ich denke, dass dort anschaulich gezeigt wird, wie man sie sinnvoll einsetzen kann. Auch die Demo von Jan Horn &amp;quot;Biohazzard&amp;quot; zeigt eindrucksvoll, wie man es am Geschicktesten machen kann ;)&lt;br /&gt;
&lt;br /&gt;
*g* Ach ja… einen kleinen Nachteil haben die Display-Listen doch noch! (ich weiß, dass ist jetzt so, als würde ich euch ins ein tiefes Becken tauchen lassen und am Boden steht: &amp;quot;Du hast die Sauerstoff-Falsche vergessen…&amp;quot;) Sie verbrauchen relativ viel Speicher! Alle Vorgänge werden nämlich direkt im Arbeitsspeicher geschoben. Eine gesunde Mischung zwischen normalen Rendering und Display-Listen ist also anzuraten, denn wenn der Speicher voll ist, hilft keine Optimierung mehr, dass Programm vorm ruckeln zu schützen ;)&lt;br /&gt;
&lt;br /&gt;
Auch sollte man bedenken, dass ein Aufbau z.B. eines Quads sich nicht mehr sehr optimieren lässt. Richtig bringen werden Euch die Display-Listen nur dann etwas, wenn ihr mit komplexen Gebilden arbeitet, die sich immer wiederholen. Würdet ihr z.B. bei jedem Render-Durchgang ein Model verändern, also seine Form (nicht seine Farbe), so würde eine Display-Liste eher hinderlich als nützlich sein!&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Bitte nicht traurig sein, wenn hier bereits wieder Ende ist ;) Ich weiß, dass ich in diesem Tutorial mehr versprochen habe, als letztendlich drin ist, aber ich habe vermehrt zu hören bekommen, dass ich dazu neige, wahre Monster-Tutorials zu machen und wollte dem hier mal entgegen wirken, da ich noch rund das doppelte an Stoff gehabt hätte. Drum ist hier nun erstmal Schluss! Es ist nicht ganz das geworden, was zunächst geplant war, aber ich denke, dass das Ziel, nämlich das Grundwissen zu vertiefen erfüllt werden konnte!&lt;br /&gt;
&lt;br /&gt;
Das schreiben dieses Tutorials hat mir sehr viel Spaß gemacht, da ich mich teilweise auch selbst momentan damit beschäftige und es auch unglaublich interessant finde. In diesem Sinne möchte ich dann auch beim sechsten Tutorial weiter machen und mal eine kleine Exkursion unternehmen, nämlich Möglichkeiten aufzuzeigen, Daten aus einem Modellierer in unsere Software zu bekommen. Die Direct3D-Welt hat gesagt, dass sie bereit ist für einen Kampf ist - also sollen sie ihn auch bekommen ^__-&lt;br /&gt;
&lt;br /&gt;
Den mit OpenGL lässt sich weitaus mehr machen als man zunächst erahnt und da die meisten Samples immer nur Dreiecke zeigen wollen wir doch mal etwas Komplexeres machen! Ihr dürft also gespannt sein und wie immer gilt… Ideen und Vorschläge sind herzlich willkommen ;) Im Gegensatz zu D3D hat man bei OpenGL erkannt, dass eine Grafik-API keine Model- und Texture-Loader bieten sollte. Hier ist dann eine Hardcodierung notwendig, die wir allerdings nicht als Nachteil ansehen sollten, sondern vielmehr die Chancen nutzen, unsere Programme mit eigenen Routinen zu optimieren. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Have Fun!&lt;br /&gt;
&lt;br /&gt;
Euer [[Benutzer:Phobeus|Phobeus]]&lt;br /&gt;
&lt;br /&gt;
Siehe Auch: [[Displayliste]]&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_5_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 4]] | [[Tutorial Lektion 7]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion5]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23912</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23912"/>
				<updated>2009-07-23T04:58:46Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Dreh- und Angelpunkt des Geschehens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix gezeichnet. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° (gegen den Uhrzeigersinn) um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr zuerst euer Objekt und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel mit negativem Winkel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23911</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23911"/>
				<updated>2009-07-23T04:57:33Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Dreh- und Angelpunkt des Geschehens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix gezeichnet. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° (gegen den Uhrzeigersinn) um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel mit negativem Winkel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23910</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23910"/>
				<updated>2009-07-23T04:53:56Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Dreh- und Angelpunkt des Geschehens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix gezeichnet. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° (gegen den Uhrzeigersinn) um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23909</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23909"/>
				<updated>2009-07-23T04:51:16Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Dreh- und Angelpunkt des Geschehens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix gezeichnet. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° (gegen den Uhrzeigersinn) um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23908</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23908"/>
				<updated>2009-07-23T04:40:43Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* D3D-Verrat */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix gezeichnet. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23907</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23907"/>
				<updated>2009-07-23T03:23:19Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* D3D-Verrat */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Worldmatrix (besser Modellmatrix) übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23906</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23906"/>
				<updated>2009-07-23T02:52:12Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelmatrix (auch Worldmatrix), die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23905</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23905"/>
				<updated>2009-07-23T00:57:44Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Modellmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23904</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23904"/>
				<updated>2009-07-23T00:51:47Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Modellmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Worldmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23903</id>
		<title>Tutorial Lektion 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23903"/>
				<updated>2009-07-23T00:45:02Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Der erste Kontakt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Entdeckung einer neuen Welt =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Ich möchte Euch an dieser Stelle bei DGL herzlich willkommen heißen. Vermutlich wird dies eines der ersten Tutorials sein, das Ihr als Einsteiger lesen werdet. Wahrscheinlich werdet Ihr dann auch noch nicht lange bei uns sein und Euch nicht vorstellen können, dass all die Schreiber auf unserer Seite keine Gurus, sondern ganz normale Menschen sind.&lt;br /&gt;
&lt;br /&gt;
Man kann uns also jeder Zeit im Forum &amp;quot;anfassen&amp;quot;, uns Fragen stellen, Vorschläge unterbreiten oder einfach nur einmal kurz mit einem Lob ermutigen weitere Texte zu verfassen ;-).&lt;br /&gt;
&lt;br /&gt;
Ich wünsche Euch an dieser Stelle viel Erfolg bei dem Einstieg in die Thematik OpenGL und ermahne Euch noch einmal, dass Ihr Eure Ziele nicht zu weit steckt. Wirklich Spaß beginnt OpenGL nämlich erst dann zu machen, wenn man stets kleinere Erfolge feiern kann.&lt;br /&gt;
== Höhere Mächte - Matrizen und ihre Folgen ==&lt;br /&gt;
=== Saubere Arbeit ===&lt;br /&gt;
Bevor wir direkt beginnen, etwas zu zeichnen, müssen wir erst einmal das Bild löschen, denn wie in der vorherigen Lektion beschrieben zeichnen wir die Szene jeden Schleifendurchlauf neu. Das Löschen der Puffer, in dem die Bildinformationen enthalten sind, übernimmt die Funktion [[glClear]]. Die Farbinformationen unser  [[Fragment|Fragmente]] (Fragmente sind vergleichbar mit den [[Pixel|Pixeln]] auf dem Bildschirm, besitzen aber weitere Informationen wie z.&amp;amp;nbsp;B. Tiefenwerte. Bei der Ausgabe des Bildes werden diese Fragmente in Pixel umgewandelt) sind in dem so genannten [[Farbpuffer]] (Colorbuffer) gespeichert. Aus diesem Grund übergeben wir an die Funktion [[glClear]] die Konstante '''GL_COLOR_BUFFER_BIT'''. Die oben bereits angesprochenen Tiefenwerte stehen im [[Tiefenpuffer]]. Diese Daten werden benutzt, um zu entscheiden, welche Pixel durch andere verdeckt werden. Deshalb sollten wir den Tiefenpuffer auch mit löschen. Die Konstante dafür heißt '''GL_DEPTH_BUFFER_BIT'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;//Farbbuffer und Tiefenpuffer entleeren&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_puffereffekt.gif|right]]&lt;br /&gt;
Mit Hilfe des Befehls [[glClearColor]] können wir festlegen, welche Farbinformationen mit dem Aufruf von glClear in den Colorbuffer geschrieben werden sollen. Wenn wir es also genau nehmen, so löscht glClear den Colorbuffer nicht, sondern es schreibt ihn mit den definierten Werten voll. Standardmäßig erhalten die Fragmente eine schwarze Farbe. (Der Vollständigkeit halber sei erwähnt, dass der Tiefenpuffer immer mit Nullen überschrieben wird.)&lt;br /&gt;
&lt;br /&gt;
Es wird also nicht bei jedem Zeichenvorgang (Rendervorgang) der Bildspeicher gelöscht, sondern der Programmierer entscheidet, wann dies geschehen soll. Theoretisch könnt Ihr auch die Szene wiedergeben und dann löschen, bevor sie ausgegeben wird... wer's mag :).&lt;br /&gt;
&lt;br /&gt;
Wer sich entscheidet, den Colorbuffer nicht zu löschen, der kann so auch einige nette Effekte erzeugen. Den Cheatern unter euch sollte der erreichte Effekt bekannt vorkommen, wenn man beispielsweise bei Counter-Strike durch die Wand gelaufen ist. Der Grund für das Verwischen ist in beiden Fällen derselbe: Das neue Bild wird gezeichnet, ohne dass das alte Bild aus dem Puffer entfernt wurde.&lt;br /&gt;
&lt;br /&gt;
=== Und die Welt ist doch keine Scheibe... ===&lt;br /&gt;
[[bild:Tutimg_lektion2_koordinatensystem.jpg|256px|right]]&lt;br /&gt;
Nachdem wir nun wieder Ordnung im Speicher geschafft haben, können wir zum interessanten Teil kommen: &amp;quot;Wie darf man sich einen 3D-Raum vorstellen?&amp;quot; Nun... warum schaut Ihr Euch nicht einmal in Eurem Zimmer um?&lt;br /&gt;
&lt;br /&gt;
Versuchen wir doch mal, ein Beispiel direkt aus dem Leben gegriffen zu nehmen und stellen uns unsere Umgebung als Koordinaten-System vor (Igitt!). Der Monitor, der hoffentlich direkt vor uns steht, ist in diesem Fall unser Ursprung, d.h. er liegt an dem Punkt (0, 0, 0).&lt;br /&gt;
&lt;br /&gt;
Blicken wir seitwärts neben den Monitor, so sehen wir eine Linie (wenn Ihr es nicht tun solltest, macht Euch keine Sorgen ... solche Anfälle hat der Autor häufiger *g*), die von links nach rechts verläuft. Es handelt sich hierbei um die X-Achse, die links vom Monitor im negativen Bereich verläuft, rechts davon in den positiven.&lt;br /&gt;
&lt;br /&gt;
Nun blicken wir einmal nach oben und einmal nach unten und schon erspähen wir die Y-Achse, die oberhalb des Monitors positiv verläuft, unterhalb negativ. Wunderbar! Wenn Ihr bereits in 2D gearbeitet habt, solltet Ihr an dieser Stelle ein dümmliches Grinsen auf Eurem Gesichte haben und das wohltuende Gefühl, dass Euch das doch alles bereits irgendwie bekannt vorkommt. Doch zu unserem Entsetzen können wir uns ja auch noch von unserem Bildschirm wegbewegen oder auch dichter heran (alle Kurzsichtigen unter uns sollten das nicht so persönlich nehmen, auch sie leben in einem 3D-Raum ^__-).&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen ist im 3D-Raum typisch, jedoch nicht unerklärlich, da wir uns auf der Z-Achse bewegen. Rollen wir mit dem Stuhl vom Monitor weg, so gelangen wir in den positiven Bereich der Z-Achse, bewegen wir uns drauf zu, gelangen wir in den negativen Bereich. Jeder, der bereits in D3D programmiert hat, sollte sich schleunigst einprägen, dass das ein großer Unterschied zwischen D3D und OpenGL ist. Das kann sonst zu einigen wirklich fiesen Fehlern führen, wenn man es nicht weiß... *fg*.&lt;br /&gt;
&lt;br /&gt;
Soweit so gut! Klingt bisher hoffentlich immer noch nicht so kompliziert. Nur keine Sorge, das Niveau versuchen wir zu halten ;).&lt;br /&gt;
&lt;br /&gt;
Speziell wenn Ihr bereits 2D-Spiele programmiert habt, solltet Ihr Euch sehr schnell von folgenden Gedanken trennen: Die Koordinaten, die Ihr seht und angebt, entsprechen in der Regel nicht den Pixeln des Bildschirmes, sondern so genannten Weltkoordinaten. Eine Definition für diese Weltkoordinaten gibt es nicht, denn wie groß diese sind, ist dem Programmierer überlassen. Ob Ihr euer Objekt eine Einheit vor Euch und 0,1 Einheit rechts von Euch oder aber 100 Einheiten vor euch und 10 Einheiten neben Euch positioniert ist egal. Die euch zur Verfügung stehende Welt ist grenzenlos ;). Ihr könnt Eure Szene theoretisch unendlich klein oder aber unendlich groß darstellen. Das Einzige, was euch wirklich daran hindert, ist die Größe und Auflösung der Euch zur Verfügung stehenden Typen wie Integer oder Single ;). Der eigentliche Größeneindruck eines Objektes entsteht durch die Geschwindigkeit mit der sich der Betrachter und andere Objekte in der Welt bewegen.&lt;br /&gt;
&lt;br /&gt;
=== Der erste Kontakt ===&lt;br /&gt;
Um nun etwas mit OpenGL rendern zu können, müssen wir uns bewusst werden, was eine Modellmatrix ist und warum wir sie benötigen. In dieser Matrix wird nämlich festgehalten, '''wie''' und '''wo''' ein Objekt gezeichnet wird. Das hört sich vielleicht zunächst recht merkwürdig an, lässt sich aber leicht veranschaulichen.&lt;br /&gt;
&lt;br /&gt;
Mann sollte sich vorstellen das eigentlich zwei Koordinatensysteme existieren, keine Angst ist ganz einfach... ;). &lt;br /&gt;
Ich erkläre es Euch an einer Beispielzeichnung: &lt;br /&gt;
&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
&lt;br /&gt;
Also in der 3D-Programmierung verschiebt man eigentlich nicht das Objekt sondern das Koordinatensystem, alles verstanden? *fg* Gut, dann weiter. Da man nun ein Objekt im Weltkoordinatensystem nicht so einfach verschieben und drehen kann (versucht mal die neuen Koordinaten eines beliebig gedrehten Würfels selber zu berechnen), also suchte man etwas, was an Stelle des Weltkoordinatensystems verschoben werden könnte, und so einfach zu Handhaben war wie eine '''unrotierte Darstellung im Ursprung des Koordinatensystems'''. Wer mitgelesen hat wird es schon wissen... richtig! Es ist das Modellkoordinatensystem, von selbst darauf gekommen? Super! &lt;br /&gt;
&lt;br /&gt;
Das Modellkoordinatensystem liegt noch vor dem ersten Aufruf parallel zum Weltkoordinatensystem, also die Basisvektoren (x,y,z-Achsen) &amp;quot;zeigen&amp;quot; in die selbe Richtung und haben den selben Ursrpung (0-Punkt). Rufen wir nun eine OpenGL Funktion zur Veränderung (z.B. glTranlate, glRotate...) unseres Objektes auf, so ändern wir eigentlich nicht das Objekt sondern nur das Modellkoordinatensystem. Und nicht vergessen! Auch beim Programmieren definieren wir ja auch zuerst die Position (also das Modellkoordinatensystem) und dann zeichnen wird das Objekt, ist eigentlich nicht schwer zu verstehen oder? *g*&lt;br /&gt;
&lt;br /&gt;
Ok, ok... ;) eine Beispielzeichnung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:wc-vs-mc-beispiel.png]]&lt;br /&gt;
&lt;br /&gt;
Der Würfel in der Darstellung oben, ist eigentlich nicht notwendig und dient nur der Veranschaulichung.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Sollte es jemand also nach der folgenden Erläuterung nicht verstanden haben, kann er mich selbstverständlich persönlich per Mail zur &amp;quot;Rechenschaft&amp;quot; ziehen oder aber er wirft einen Blick in unser OpenGLWiki :)).&lt;br /&gt;
&lt;br /&gt;
Wir setzen also zu Beginn unser Modellkoordinatensystem in den Mittelpunkt unseres Weltkoordinatensystems. Um oberes Beispiel aufzugreifen: Den Bildschirm. Dies geschieht mit dem Befehl [[glLoadIdentity]] und entspricht einem Reset der Modellmatrix. Theoretisch können wir nun an dieser Stelle etwas zeichnen. Dies würde allerdings dazu führen, dass das Objekt sehr groß oder gar nicht zu sehen ist, weil der Punkt (auch Augpunktkoordinate genannt) von dem aus wir unser Objekt betrachten  sich genau an der Stelle befindet wo sich unser Objekt befindet, nämlich im Ursprung (vorausgesetzt wir Zeichnen ein Objekt um oder and den Ursprung, und das genau in der x/y-Ebene und nicht darüber oder darunter) . Gehen wir doch einmal 6 Einheiten nach hinten und 1,5 Einheiten nach links!&lt;br /&gt;
&lt;br /&gt;
Eine kleine Beispielgrafik soll helfen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:objekt-sichtbar-verschieben.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hierfür sollte man sich bewusst werden, dass wir in OpenGL praktisch an einen Stuhl gefesselt sind, d.h. wir können uns gar nicht bewegen. Das soll uns aber nicht davon abhalten. Wir brauchen ja nur die ganze Welt so zu bewegen, dass es für uns aussieht, als ob wir uns bewegen. Denn wenn sich alles außer uns nach links bewegt, haben wir den Eindruck, wir wären nach rechts gewandert, right?&lt;br /&gt;
&lt;br /&gt;
Nun aber zu der Bewegung unseres ersten Objektes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(0, 0,-6);&lt;br /&gt;
glTranslatef(-1.5,0,0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dies hat bewirkt, dass sich unser Zeichenstift 6 Einheiten nach hinten (negativer Bereicht der Y-Achse) und anschließend 1,5 Einheiten nach links (negativer Bereich der X-Achse) bewegt hat. Ich habe diesen Fall absichtlich in zwei Schritten gefasst, um es zu verdeutlichen. Sicherlich wäre es einfacher, alles mit nur einem Aufruf von [[glTranslate|glTranslate*]] zu machen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(-1.5, 0,-6);&amp;lt;/source&amp;gt;&lt;br /&gt;
Man beachte, dass in diesem Fall die 6 Schritte nach hinten notwendig sind um ein bisschen Distanz zum Objekt zu bekommen und nicht direkt in ihm zu stehen!&lt;br /&gt;
&lt;br /&gt;
Fertig! Schon haben wir dort unseren &amp;quot;Zeichenstift&amp;quot; positioniert, der nun auf weitere Zeichenkommandos von uns wartet. Das mag sicherlich alles ein wenig verwirrend klingen... probiert es am Besten aus und spielt mit den Parametern und erkennt, was gemeint ist :).&lt;br /&gt;
&lt;br /&gt;
== Von Sichtungen... ==&lt;br /&gt;
=== Die Büchse der Pandora ===&lt;br /&gt;
Nun sind wir aber auch alle scharf darauf, endlich etwas zu rendern und auf dem Bildschirm auszugeben. Dies geschieht z.&amp;amp;nbsp;B. mit folgenden Zeilen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glVertex3f( 1,-1, 0);&lt;br /&gt;
  glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Wir erkennen hierbei eindeutig eine Art Block. Gerade wir Pascaler sollten diese ja lieben :-&amp;gt;. Wir teilen OpenGL mit Hilfe von [[glBegin]] mit, dass wir ein Objekt zeichnen wollen. In diesem Fall übergeben wir den Parameter '''GL_TRIANGLE''', der OpenGL angibt, dass folgende Punkte als ein Dreieck interpretiert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Anschließend folgt ein dreifacher Aufruf von [[glVertex|glVertex3f]]. Jeder Aufruf erzeugt nun einen Punkt (Vertex) in unserem 3D-Raum. Da wir OpenGL bei glBegin mitgeteilt haben, dass diese Punkte zu einem Dreieck zusammengefügt werden sollen, wird das auch so getan ;).&lt;br /&gt;
&lt;br /&gt;
Wie wir auf dem Bild erkennen können, wurde unser Dreieck wie erwartet nach links verschoben abgebildet und auch mit einem leichten Abstand zur Kamera, nämlich 6 Einheiten entlang der Z-Achse.&lt;br /&gt;
=== Guter Stoff! ===&lt;br /&gt;
Nun... ein wenig trostlos sieht unser Dreieck nun doch aus, oder? Ich habe übrigens damals bei D3D rund eine Woche benötigt, bis ich ein schwarzes Dreieck hatte. Wir haben immerhin schon ein weißes... aber wir gehen nun einen Schritt weiter und werden das Dreieck schön bunt einfärben.&lt;br /&gt;
&lt;br /&gt;
Bevor nun irgendjemand anfängt und Pixel für Pixel den Bildschirm nach zu pinseln oder gar sein PaintShop bereits offen hat, um die ersten Texturen zu erstellen, sei gestoppt! Es gibt für einfache Einfärbungen in OpenGL eine bessere Methode. Wir definieren einfach für jeden Eckpunkt eine Farbe und OpenGL wird dann sogar eigenständig die Farbverläufe dafür erstellen. Jeder der D3D kennt, wird diese Vorgehensweise bekannt vorkommen und er wird beginnen, verzweifelt nach dem FVF zu suchen, um es korrekt zu definieren... Wenn Ihr einen Vertex zeichnet, so rendert OpenGL diesen automatisch &amp;quot;weiß&amp;quot; (Ah huch! Deswegen ist unser Dreieck auch weiß???). Alles was wir nun machen müssen, ist OpenGL mitzuteilen, dass es eine andere Farbe einsetzen soll. Und zwar wird OpenGL diese Farbe für alle folgenden Eckpunkte nutzen, so lange bis von uns ein anderes Kommando kommt.&lt;br /&gt;
&lt;br /&gt;
Der mysteriöse Befehl, um den ich nun schon die ganze Zeit herumschwafle ist [[glColor|glColor*]]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Alle folgenden Eckpunkte werden rot gefärbt&lt;br /&gt;
glColor3f(1,0,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Wobei jeder Parameter einen Farbwert repräsentiert und zwar nach dem Muster RGB. Es wird ein Wert zwischen 1 und 0 erwartet, wobei eine Eins &amp;quot;volle Farbsättigung&amp;quot; bedeutet. Das heißt in unserem Fall haben wir als Farbe &amp;quot;rot&amp;quot; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Und weil wir schließlich die Welt ein wenig bunter machen und nicht nur das weiße Dreieck rot färben wollten, werden wir nach jedem Eckpunkt eine neue Farbe setzen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1, 0, 0); glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glColor3f(0, 0, 1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0, 1, 0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Und dies ist dann unser farbenfrohes Ergebnis. Beeindruckend, wenn man bedenkt, wie wenig Aufwand letztendlich dahinter steckt, oder?&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_dreieck.gif]]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wer meine Tutorials kennt weiß, dass zum Abschluß noch immer ein wenig Geblubber von mir kommt (man beachte diese entzückende Wortwahl von meiner einer... hoffe, der Lektor findet es auch amüsant...). (Anm. des Lektors: Und wie!) Schauen wir doch mal stolz auf das zurück, was wir heute erreicht haben! Wir haben OpenGL initialisiert, ein erstes Dreieck auf den Bildschirm gezaubert und dieses in den Farbtopf gesteckt! Das solltet Ihr als ein historisches Ereignis ansehen. Als ich damals mit D3D angefangen habe, brauchte ich, um es mir selbst zu erarbeiten, ca. eine Woche (Das ist jetzt der Moment, in dem Ihr Eure Hände heben solltest und ein lautes &amp;quot;Call me God&amp;quot; aus Euch herauskommen sollte, so dass zumindest Eure unmittelbaren Mitmenschen denken, dass Ihr einen Dachschaden habt!!! Das gehört einfach mit dazu ^__- )&lt;br /&gt;
&lt;br /&gt;
Wie immer solltet Ihr Euch nun hinsetzen und Euch ein wenig mit den Parametern vertraut machen. Speziell bei glTranslate* solltet Ihr ein wenig mit den Parametern experimentieren, damit Ihr seht, was es mit den Matrizen auf sich hat und wie diese funktionieren. Wenn Ihr dann auch denkt, dass Ihr damit vertraut seid, versucht ein wenig mit den einzelnen Vertexpositionen zu experimentieren und verändert diese. Wenn auch das klar ist, setzt Euch in die Ecke und warte sehnsüchtig auf mehr von uns :D! (Anm: Die &amp;quot;Ecke&amp;quot; ist nicht die Kneipe nebenan... :)&lt;br /&gt;
&lt;br /&gt;
Im nächsten Kapitel werden wir dann Matrizen-Hardcore machen ... legt also schon mal Euer Aspirin parat, es wird witzig werden *grunz* :).&lt;br /&gt;
&lt;br /&gt;
Und wie immer freuen wir uns sehr über Feedback. Schreibt uns doch einfach ein paar Worte in unser [http://www.delphigl.com/forum/viewforum.php?f=8 Feedback-Forum]. Sagt, was Ihr gut und was hingegen Ihr als schlecht empfunden habt! Auch freuen wir uns immer über Ideen für weitere Tutorials, teilt uns also bitte Eure Ideen mit ;)!&lt;br /&gt;
&lt;br /&gt;
Okay... ich wünsche Euch einen angenehmen Tag / Nacht!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 1]] | [[Tutorial Lektion 3]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion2]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23902</id>
		<title>Tutorial Lektion 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23902"/>
				<updated>2009-07-23T00:42:12Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Der erste Kontakt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Entdeckung einer neuen Welt =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Ich möchte Euch an dieser Stelle bei DGL herzlich willkommen heißen. Vermutlich wird dies eines der ersten Tutorials sein, das Ihr als Einsteiger lesen werdet. Wahrscheinlich werdet Ihr dann auch noch nicht lange bei uns sein und Euch nicht vorstellen können, dass all die Schreiber auf unserer Seite keine Gurus, sondern ganz normale Menschen sind.&lt;br /&gt;
&lt;br /&gt;
Man kann uns also jeder Zeit im Forum &amp;quot;anfassen&amp;quot;, uns Fragen stellen, Vorschläge unterbreiten oder einfach nur einmal kurz mit einem Lob ermutigen weitere Texte zu verfassen ;-).&lt;br /&gt;
&lt;br /&gt;
Ich wünsche Euch an dieser Stelle viel Erfolg bei dem Einstieg in die Thematik OpenGL und ermahne Euch noch einmal, dass Ihr Eure Ziele nicht zu weit steckt. Wirklich Spaß beginnt OpenGL nämlich erst dann zu machen, wenn man stets kleinere Erfolge feiern kann.&lt;br /&gt;
== Höhere Mächte - Matrizen und ihre Folgen ==&lt;br /&gt;
=== Saubere Arbeit ===&lt;br /&gt;
Bevor wir direkt beginnen, etwas zu zeichnen, müssen wir erst einmal das Bild löschen, denn wie in der vorherigen Lektion beschrieben zeichnen wir die Szene jeden Schleifendurchlauf neu. Das Löschen der Puffer, in dem die Bildinformationen enthalten sind, übernimmt die Funktion [[glClear]]. Die Farbinformationen unser  [[Fragment|Fragmente]] (Fragmente sind vergleichbar mit den [[Pixel|Pixeln]] auf dem Bildschirm, besitzen aber weitere Informationen wie z.&amp;amp;nbsp;B. Tiefenwerte. Bei der Ausgabe des Bildes werden diese Fragmente in Pixel umgewandelt) sind in dem so genannten [[Farbpuffer]] (Colorbuffer) gespeichert. Aus diesem Grund übergeben wir an die Funktion [[glClear]] die Konstante '''GL_COLOR_BUFFER_BIT'''. Die oben bereits angesprochenen Tiefenwerte stehen im [[Tiefenpuffer]]. Diese Daten werden benutzt, um zu entscheiden, welche Pixel durch andere verdeckt werden. Deshalb sollten wir den Tiefenpuffer auch mit löschen. Die Konstante dafür heißt '''GL_DEPTH_BUFFER_BIT'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;//Farbbuffer und Tiefenpuffer entleeren&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_puffereffekt.gif|right]]&lt;br /&gt;
Mit Hilfe des Befehls [[glClearColor]] können wir festlegen, welche Farbinformationen mit dem Aufruf von glClear in den Colorbuffer geschrieben werden sollen. Wenn wir es also genau nehmen, so löscht glClear den Colorbuffer nicht, sondern es schreibt ihn mit den definierten Werten voll. Standardmäßig erhalten die Fragmente eine schwarze Farbe. (Der Vollständigkeit halber sei erwähnt, dass der Tiefenpuffer immer mit Nullen überschrieben wird.)&lt;br /&gt;
&lt;br /&gt;
Es wird also nicht bei jedem Zeichenvorgang (Rendervorgang) der Bildspeicher gelöscht, sondern der Programmierer entscheidet, wann dies geschehen soll. Theoretisch könnt Ihr auch die Szene wiedergeben und dann löschen, bevor sie ausgegeben wird... wer's mag :).&lt;br /&gt;
&lt;br /&gt;
Wer sich entscheidet, den Colorbuffer nicht zu löschen, der kann so auch einige nette Effekte erzeugen. Den Cheatern unter euch sollte der erreichte Effekt bekannt vorkommen, wenn man beispielsweise bei Counter-Strike durch die Wand gelaufen ist. Der Grund für das Verwischen ist in beiden Fällen derselbe: Das neue Bild wird gezeichnet, ohne dass das alte Bild aus dem Puffer entfernt wurde.&lt;br /&gt;
&lt;br /&gt;
=== Und die Welt ist doch keine Scheibe... ===&lt;br /&gt;
[[bild:Tutimg_lektion2_koordinatensystem.jpg|256px|right]]&lt;br /&gt;
Nachdem wir nun wieder Ordnung im Speicher geschafft haben, können wir zum interessanten Teil kommen: &amp;quot;Wie darf man sich einen 3D-Raum vorstellen?&amp;quot; Nun... warum schaut Ihr Euch nicht einmal in Eurem Zimmer um?&lt;br /&gt;
&lt;br /&gt;
Versuchen wir doch mal, ein Beispiel direkt aus dem Leben gegriffen zu nehmen und stellen uns unsere Umgebung als Koordinaten-System vor (Igitt!). Der Monitor, der hoffentlich direkt vor uns steht, ist in diesem Fall unser Ursprung, d.h. er liegt an dem Punkt (0, 0, 0).&lt;br /&gt;
&lt;br /&gt;
Blicken wir seitwärts neben den Monitor, so sehen wir eine Linie (wenn Ihr es nicht tun solltest, macht Euch keine Sorgen ... solche Anfälle hat der Autor häufiger *g*), die von links nach rechts verläuft. Es handelt sich hierbei um die X-Achse, die links vom Monitor im negativen Bereich verläuft, rechts davon in den positiven.&lt;br /&gt;
&lt;br /&gt;
Nun blicken wir einmal nach oben und einmal nach unten und schon erspähen wir die Y-Achse, die oberhalb des Monitors positiv verläuft, unterhalb negativ. Wunderbar! Wenn Ihr bereits in 2D gearbeitet habt, solltet Ihr an dieser Stelle ein dümmliches Grinsen auf Eurem Gesichte haben und das wohltuende Gefühl, dass Euch das doch alles bereits irgendwie bekannt vorkommt. Doch zu unserem Entsetzen können wir uns ja auch noch von unserem Bildschirm wegbewegen oder auch dichter heran (alle Kurzsichtigen unter uns sollten das nicht so persönlich nehmen, auch sie leben in einem 3D-Raum ^__-).&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen ist im 3D-Raum typisch, jedoch nicht unerklärlich, da wir uns auf der Z-Achse bewegen. Rollen wir mit dem Stuhl vom Monitor weg, so gelangen wir in den positiven Bereich der Z-Achse, bewegen wir uns drauf zu, gelangen wir in den negativen Bereich. Jeder, der bereits in D3D programmiert hat, sollte sich schleunigst einprägen, dass das ein großer Unterschied zwischen D3D und OpenGL ist. Das kann sonst zu einigen wirklich fiesen Fehlern führen, wenn man es nicht weiß... *fg*.&lt;br /&gt;
&lt;br /&gt;
Soweit so gut! Klingt bisher hoffentlich immer noch nicht so kompliziert. Nur keine Sorge, das Niveau versuchen wir zu halten ;).&lt;br /&gt;
&lt;br /&gt;
Speziell wenn Ihr bereits 2D-Spiele programmiert habt, solltet Ihr Euch sehr schnell von folgenden Gedanken trennen: Die Koordinaten, die Ihr seht und angebt, entsprechen in der Regel nicht den Pixeln des Bildschirmes, sondern so genannten Weltkoordinaten. Eine Definition für diese Weltkoordinaten gibt es nicht, denn wie groß diese sind, ist dem Programmierer überlassen. Ob Ihr euer Objekt eine Einheit vor Euch und 0,1 Einheit rechts von Euch oder aber 100 Einheiten vor euch und 10 Einheiten neben Euch positioniert ist egal. Die euch zur Verfügung stehende Welt ist grenzenlos ;). Ihr könnt Eure Szene theoretisch unendlich klein oder aber unendlich groß darstellen. Das Einzige, was euch wirklich daran hindert, ist die Größe und Auflösung der Euch zur Verfügung stehenden Typen wie Integer oder Single ;). Der eigentliche Größeneindruck eines Objektes entsteht durch die Geschwindigkeit mit der sich der Betrachter und andere Objekte in der Welt bewegen.&lt;br /&gt;
&lt;br /&gt;
=== Der erste Kontakt ===&lt;br /&gt;
Um nun etwas mit OpenGL rendern zu können, müssen wir uns bewusst werden, was eine Modellmatrix ist und warum wir sie benötigen. In dieser Matrix wird nämlich festgehalten, '''wie''' und '''wo''' ein Objekt gezeichnet wird. Das hört sich vielleicht zunächst recht merkwürdig an, lässt sich aber leicht veranschaulichen.&lt;br /&gt;
&lt;br /&gt;
Mann sollte sich vorstellen das eigentlich zwei Koordinatensysteme existieren, keine Angst ist ganz einfach... ;). &lt;br /&gt;
Ich erkläre es Euch an einer Beispielzeichnung: &lt;br /&gt;
&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
&lt;br /&gt;
Also in der 3D-Programmierung verschiebt man eigentlich nicht das Objekt sondern das Koordinatensystem, alles verstanden? *fg* Gut, dann weiter. Da man nun ein Objekt im Weltkoordinatensystem nicht so einfach verschieben und drehen kann (versucht mal die neuen Koordinaten eines beliebig gedrehten Würfels selber zu berechnen), also suchte man etwas, was an Stelle des Weltkoordinatensystems verschoben werden könnte, und so einfach zu Handhaben war wie eine '''unrotierte Darstellung im Ursprung des Koordinatensystems'''. Wer mitgelesen hat wird es schon wissen... richtig! Es ist das Modellkoordinatensystem, von selbst darauf gekommen? Super! &lt;br /&gt;
&lt;br /&gt;
Das Modellkoordinatensystem liegt noch vor dem ersten Aufruf parallel zum Weltkoordinatensystem, also die Basisvektoren (x,y,z-Achsen) &amp;quot;zeigen&amp;quot; in die selbe Richtung und haben den selben Ursrpung (0-Punkt). Rufen wir nun eine OpenGL Funktion zur Veränderung (z.B. glTranlate, glRotate...) unseres Objektes auf, so ändern wir eigentlich nicht das Objekt sondern nur das Modellkoordinatensystem. Und nicht vergessen! Auch beim Programmieren definieren wir ja auch zuerst die Position (also das Modellkoordinatensystem) und dann zeichnen wird das Objekt, ist eigentlich nicht schwer zu verstehen oder? *g*&lt;br /&gt;
&lt;br /&gt;
Ok, ok... ;) eine Beispielzeichnung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:wc-vs-mc-beispiel.png]]&lt;br /&gt;
&lt;br /&gt;
Der Würfel in der Darstellung oben, ist eigentlich nicht notwendig und dient nur der Veranschaulichung.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Sollte es jemand also nach der folgenden Erläuterung nicht verstanden haben, kann er mich selbstverständlich persönlich per Mail zur &amp;quot;Rechenschaft&amp;quot; ziehen oder aber er wirft einen Blick in unser OpenGLWiki :)).&lt;br /&gt;
&lt;br /&gt;
Wir setzen also zu Beginn unser Modellkoordinatensystem in den Mittelpunkt unseres Weltkoordinatensystems. Um oberes Beispiel aufzugreifen: Den Bildschirm. Dies geschieht mit dem Befehl [[glLoadIdentity]] und entspricht einem Reset der Modellmatrix. Theoretisch können wir nun an dieser Stelle etwas zeichnen. Dies würde allerdings dazu führen, dass das Objekt sehr groß oder gar nicht zu sehen ist, weil der Punkt (auch Augpunktkoordinate genannt) von dem aus wir unser Objekt betrachten  sich genau an der Stelle befindet wo sich unser Objekt befindet, nämlich im Ursprung (vorausgesetzt wir Zeichnen ein Objekt um oder and den Ursprung, und das genau in der x/y-Ebene und nicht darüber oder darunter) . Gehen wir doch einmal 1,5 Einheiten nach links und 6 Einheiten nach hinten!&lt;br /&gt;
&lt;br /&gt;
Eine kleine Beispielgrafik soll helfen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:objekt-sichtbar-verschieben.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hierfür sollte man sich bewusst werden, dass wir in OpenGL praktisch an einen Stuhl gefesselt sind, d.h. wir können uns gar nicht bewegen. Das soll uns aber nicht davon abhalten. Wir brauchen ja nur die ganze Welt so zu bewegen, dass es für uns aussieht, als ob wir uns bewegen. Denn wenn sich alles außer uns nach links bewegt, haben wir den Eindruck, wir wären nach rechts gewandert, right?&lt;br /&gt;
&lt;br /&gt;
Nun aber zu der Bewegung unseres ersten Objektes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(0, 0,-6);&lt;br /&gt;
glTranslatef(-1.5,0,0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dies hat bewirkt, dass sich unser Zeichenstift 6 Einheiten nach hinten (negativer Bereicht der Y-Achse) und anschließend 1,5 Einheiten nach links (negativer Bereich der X-Achse) bewegt hat. Ich habe diesen Fall absichtlich in zwei Schritten gefasst, um es zu verdeutlichen. Sicherlich wäre es einfacher, alles mit nur einem Aufruf von [[glTranslate|glTranslate*]] zu machen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(-1.5, 0,-6);&amp;lt;/source&amp;gt;&lt;br /&gt;
Man beachte, dass in diesem Fall die 6 Schritte nach hinten notwendig sind um ein bisschen Distanz zum Objekt zu bekommen und nicht direkt in ihm zu stehen!&lt;br /&gt;
&lt;br /&gt;
Fertig! Schon haben wir dort unseren &amp;quot;Zeichenstift&amp;quot; positioniert, der nun auf weitere Zeichenkommandos von uns wartet. Das mag sicherlich alles ein wenig verwirrend klingen... probiert es am Besten aus und spielt mit den Parametern und erkennt, was gemeint ist :).&lt;br /&gt;
&lt;br /&gt;
== Von Sichtungen... ==&lt;br /&gt;
=== Die Büchse der Pandora ===&lt;br /&gt;
Nun sind wir aber auch alle scharf darauf, endlich etwas zu rendern und auf dem Bildschirm auszugeben. Dies geschieht z.&amp;amp;nbsp;B. mit folgenden Zeilen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glVertex3f( 1,-1, 0);&lt;br /&gt;
  glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Wir erkennen hierbei eindeutig eine Art Block. Gerade wir Pascaler sollten diese ja lieben :-&amp;gt;. Wir teilen OpenGL mit Hilfe von [[glBegin]] mit, dass wir ein Objekt zeichnen wollen. In diesem Fall übergeben wir den Parameter '''GL_TRIANGLE''', der OpenGL angibt, dass folgende Punkte als ein Dreieck interpretiert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Anschließend folgt ein dreifacher Aufruf von [[glVertex|glVertex3f]]. Jeder Aufruf erzeugt nun einen Punkt (Vertex) in unserem 3D-Raum. Da wir OpenGL bei glBegin mitgeteilt haben, dass diese Punkte zu einem Dreieck zusammengefügt werden sollen, wird das auch so getan ;).&lt;br /&gt;
&lt;br /&gt;
Wie wir auf dem Bild erkennen können, wurde unser Dreieck wie erwartet nach links verschoben abgebildet und auch mit einem leichten Abstand zur Kamera, nämlich 6 Einheiten entlang der Z-Achse.&lt;br /&gt;
=== Guter Stoff! ===&lt;br /&gt;
Nun... ein wenig trostlos sieht unser Dreieck nun doch aus, oder? Ich habe übrigens damals bei D3D rund eine Woche benötigt, bis ich ein schwarzes Dreieck hatte. Wir haben immerhin schon ein weißes... aber wir gehen nun einen Schritt weiter und werden das Dreieck schön bunt einfärben.&lt;br /&gt;
&lt;br /&gt;
Bevor nun irgendjemand anfängt und Pixel für Pixel den Bildschirm nach zu pinseln oder gar sein PaintShop bereits offen hat, um die ersten Texturen zu erstellen, sei gestoppt! Es gibt für einfache Einfärbungen in OpenGL eine bessere Methode. Wir definieren einfach für jeden Eckpunkt eine Farbe und OpenGL wird dann sogar eigenständig die Farbverläufe dafür erstellen. Jeder der D3D kennt, wird diese Vorgehensweise bekannt vorkommen und er wird beginnen, verzweifelt nach dem FVF zu suchen, um es korrekt zu definieren... Wenn Ihr einen Vertex zeichnet, so rendert OpenGL diesen automatisch &amp;quot;weiß&amp;quot; (Ah huch! Deswegen ist unser Dreieck auch weiß???). Alles was wir nun machen müssen, ist OpenGL mitzuteilen, dass es eine andere Farbe einsetzen soll. Und zwar wird OpenGL diese Farbe für alle folgenden Eckpunkte nutzen, so lange bis von uns ein anderes Kommando kommt.&lt;br /&gt;
&lt;br /&gt;
Der mysteriöse Befehl, um den ich nun schon die ganze Zeit herumschwafle ist [[glColor|glColor*]]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Alle folgenden Eckpunkte werden rot gefärbt&lt;br /&gt;
glColor3f(1,0,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Wobei jeder Parameter einen Farbwert repräsentiert und zwar nach dem Muster RGB. Es wird ein Wert zwischen 1 und 0 erwartet, wobei eine Eins &amp;quot;volle Farbsättigung&amp;quot; bedeutet. Das heißt in unserem Fall haben wir als Farbe &amp;quot;rot&amp;quot; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Und weil wir schließlich die Welt ein wenig bunter machen und nicht nur das weiße Dreieck rot färben wollten, werden wir nach jedem Eckpunkt eine neue Farbe setzen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1, 0, 0); glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glColor3f(0, 0, 1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0, 1, 0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Und dies ist dann unser farbenfrohes Ergebnis. Beeindruckend, wenn man bedenkt, wie wenig Aufwand letztendlich dahinter steckt, oder?&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_dreieck.gif]]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wer meine Tutorials kennt weiß, dass zum Abschluß noch immer ein wenig Geblubber von mir kommt (man beachte diese entzückende Wortwahl von meiner einer... hoffe, der Lektor findet es auch amüsant...). (Anm. des Lektors: Und wie!) Schauen wir doch mal stolz auf das zurück, was wir heute erreicht haben! Wir haben OpenGL initialisiert, ein erstes Dreieck auf den Bildschirm gezaubert und dieses in den Farbtopf gesteckt! Das solltet Ihr als ein historisches Ereignis ansehen. Als ich damals mit D3D angefangen habe, brauchte ich, um es mir selbst zu erarbeiten, ca. eine Woche (Das ist jetzt der Moment, in dem Ihr Eure Hände heben solltest und ein lautes &amp;quot;Call me God&amp;quot; aus Euch herauskommen sollte, so dass zumindest Eure unmittelbaren Mitmenschen denken, dass Ihr einen Dachschaden habt!!! Das gehört einfach mit dazu ^__- )&lt;br /&gt;
&lt;br /&gt;
Wie immer solltet Ihr Euch nun hinsetzen und Euch ein wenig mit den Parametern vertraut machen. Speziell bei glTranslate* solltet Ihr ein wenig mit den Parametern experimentieren, damit Ihr seht, was es mit den Matrizen auf sich hat und wie diese funktionieren. Wenn Ihr dann auch denkt, dass Ihr damit vertraut seid, versucht ein wenig mit den einzelnen Vertexpositionen zu experimentieren und verändert diese. Wenn auch das klar ist, setzt Euch in die Ecke und warte sehnsüchtig auf mehr von uns :D! (Anm: Die &amp;quot;Ecke&amp;quot; ist nicht die Kneipe nebenan... :)&lt;br /&gt;
&lt;br /&gt;
Im nächsten Kapitel werden wir dann Matrizen-Hardcore machen ... legt also schon mal Euer Aspirin parat, es wird witzig werden *grunz* :).&lt;br /&gt;
&lt;br /&gt;
Und wie immer freuen wir uns sehr über Feedback. Schreibt uns doch einfach ein paar Worte in unser [http://www.delphigl.com/forum/viewforum.php?f=8 Feedback-Forum]. Sagt, was Ihr gut und was hingegen Ihr als schlecht empfunden habt! Auch freuen wir uns immer über Ideen für weitere Tutorials, teilt uns also bitte Eure Ideen mit ;)!&lt;br /&gt;
&lt;br /&gt;
Okay... ich wünsche Euch einen angenehmen Tag / Nacht!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 1]] | [[Tutorial Lektion 3]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion2]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23901</id>
		<title>Tutorial Lektion 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23901"/>
				<updated>2009-07-23T00:22:56Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Der erste Kontakt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Entdeckung einer neuen Welt =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Ich möchte Euch an dieser Stelle bei DGL herzlich willkommen heißen. Vermutlich wird dies eines der ersten Tutorials sein, das Ihr als Einsteiger lesen werdet. Wahrscheinlich werdet Ihr dann auch noch nicht lange bei uns sein und Euch nicht vorstellen können, dass all die Schreiber auf unserer Seite keine Gurus, sondern ganz normale Menschen sind.&lt;br /&gt;
&lt;br /&gt;
Man kann uns also jeder Zeit im Forum &amp;quot;anfassen&amp;quot;, uns Fragen stellen, Vorschläge unterbreiten oder einfach nur einmal kurz mit einem Lob ermutigen weitere Texte zu verfassen ;-).&lt;br /&gt;
&lt;br /&gt;
Ich wünsche Euch an dieser Stelle viel Erfolg bei dem Einstieg in die Thematik OpenGL und ermahne Euch noch einmal, dass Ihr Eure Ziele nicht zu weit steckt. Wirklich Spaß beginnt OpenGL nämlich erst dann zu machen, wenn man stets kleinere Erfolge feiern kann.&lt;br /&gt;
== Höhere Mächte - Matrizen und ihre Folgen ==&lt;br /&gt;
=== Saubere Arbeit ===&lt;br /&gt;
Bevor wir direkt beginnen, etwas zu zeichnen, müssen wir erst einmal das Bild löschen, denn wie in der vorherigen Lektion beschrieben zeichnen wir die Szene jeden Schleifendurchlauf neu. Das Löschen der Puffer, in dem die Bildinformationen enthalten sind, übernimmt die Funktion [[glClear]]. Die Farbinformationen unser  [[Fragment|Fragmente]] (Fragmente sind vergleichbar mit den [[Pixel|Pixeln]] auf dem Bildschirm, besitzen aber weitere Informationen wie z.&amp;amp;nbsp;B. Tiefenwerte. Bei der Ausgabe des Bildes werden diese Fragmente in Pixel umgewandelt) sind in dem so genannten [[Farbpuffer]] (Colorbuffer) gespeichert. Aus diesem Grund übergeben wir an die Funktion [[glClear]] die Konstante '''GL_COLOR_BUFFER_BIT'''. Die oben bereits angesprochenen Tiefenwerte stehen im [[Tiefenpuffer]]. Diese Daten werden benutzt, um zu entscheiden, welche Pixel durch andere verdeckt werden. Deshalb sollten wir den Tiefenpuffer auch mit löschen. Die Konstante dafür heißt '''GL_DEPTH_BUFFER_BIT'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;//Farbbuffer und Tiefenpuffer entleeren&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_puffereffekt.gif|right]]&lt;br /&gt;
Mit Hilfe des Befehls [[glClearColor]] können wir festlegen, welche Farbinformationen mit dem Aufruf von glClear in den Colorbuffer geschrieben werden sollen. Wenn wir es also genau nehmen, so löscht glClear den Colorbuffer nicht, sondern es schreibt ihn mit den definierten Werten voll. Standardmäßig erhalten die Fragmente eine schwarze Farbe. (Der Vollständigkeit halber sei erwähnt, dass der Tiefenpuffer immer mit Nullen überschrieben wird.)&lt;br /&gt;
&lt;br /&gt;
Es wird also nicht bei jedem Zeichenvorgang (Rendervorgang) der Bildspeicher gelöscht, sondern der Programmierer entscheidet, wann dies geschehen soll. Theoretisch könnt Ihr auch die Szene wiedergeben und dann löschen, bevor sie ausgegeben wird... wer's mag :).&lt;br /&gt;
&lt;br /&gt;
Wer sich entscheidet, den Colorbuffer nicht zu löschen, der kann so auch einige nette Effekte erzeugen. Den Cheatern unter euch sollte der erreichte Effekt bekannt vorkommen, wenn man beispielsweise bei Counter-Strike durch die Wand gelaufen ist. Der Grund für das Verwischen ist in beiden Fällen derselbe: Das neue Bild wird gezeichnet, ohne dass das alte Bild aus dem Puffer entfernt wurde.&lt;br /&gt;
&lt;br /&gt;
=== Und die Welt ist doch keine Scheibe... ===&lt;br /&gt;
[[bild:Tutimg_lektion2_koordinatensystem.jpg|256px|right]]&lt;br /&gt;
Nachdem wir nun wieder Ordnung im Speicher geschafft haben, können wir zum interessanten Teil kommen: &amp;quot;Wie darf man sich einen 3D-Raum vorstellen?&amp;quot; Nun... warum schaut Ihr Euch nicht einmal in Eurem Zimmer um?&lt;br /&gt;
&lt;br /&gt;
Versuchen wir doch mal, ein Beispiel direkt aus dem Leben gegriffen zu nehmen und stellen uns unsere Umgebung als Koordinaten-System vor (Igitt!). Der Monitor, der hoffentlich direkt vor uns steht, ist in diesem Fall unser Ursprung, d.h. er liegt an dem Punkt (0, 0, 0).&lt;br /&gt;
&lt;br /&gt;
Blicken wir seitwärts neben den Monitor, so sehen wir eine Linie (wenn Ihr es nicht tun solltest, macht Euch keine Sorgen ... solche Anfälle hat der Autor häufiger *g*), die von links nach rechts verläuft. Es handelt sich hierbei um die X-Achse, die links vom Monitor im negativen Bereich verläuft, rechts davon in den positiven.&lt;br /&gt;
&lt;br /&gt;
Nun blicken wir einmal nach oben und einmal nach unten und schon erspähen wir die Y-Achse, die oberhalb des Monitors positiv verläuft, unterhalb negativ. Wunderbar! Wenn Ihr bereits in 2D gearbeitet habt, solltet Ihr an dieser Stelle ein dümmliches Grinsen auf Eurem Gesichte haben und das wohltuende Gefühl, dass Euch das doch alles bereits irgendwie bekannt vorkommt. Doch zu unserem Entsetzen können wir uns ja auch noch von unserem Bildschirm wegbewegen oder auch dichter heran (alle Kurzsichtigen unter uns sollten das nicht so persönlich nehmen, auch sie leben in einem 3D-Raum ^__-).&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen ist im 3D-Raum typisch, jedoch nicht unerklärlich, da wir uns auf der Z-Achse bewegen. Rollen wir mit dem Stuhl vom Monitor weg, so gelangen wir in den positiven Bereich der Z-Achse, bewegen wir uns drauf zu, gelangen wir in den negativen Bereich. Jeder, der bereits in D3D programmiert hat, sollte sich schleunigst einprägen, dass das ein großer Unterschied zwischen D3D und OpenGL ist. Das kann sonst zu einigen wirklich fiesen Fehlern führen, wenn man es nicht weiß... *fg*.&lt;br /&gt;
&lt;br /&gt;
Soweit so gut! Klingt bisher hoffentlich immer noch nicht so kompliziert. Nur keine Sorge, das Niveau versuchen wir zu halten ;).&lt;br /&gt;
&lt;br /&gt;
Speziell wenn Ihr bereits 2D-Spiele programmiert habt, solltet Ihr Euch sehr schnell von folgenden Gedanken trennen: Die Koordinaten, die Ihr seht und angebt, entsprechen in der Regel nicht den Pixeln des Bildschirmes, sondern so genannten Weltkoordinaten. Eine Definition für diese Weltkoordinaten gibt es nicht, denn wie groß diese sind, ist dem Programmierer überlassen. Ob Ihr euer Objekt eine Einheit vor Euch und 0,1 Einheit rechts von Euch oder aber 100 Einheiten vor euch und 10 Einheiten neben Euch positioniert ist egal. Die euch zur Verfügung stehende Welt ist grenzenlos ;). Ihr könnt Eure Szene theoretisch unendlich klein oder aber unendlich groß darstellen. Das Einzige, was euch wirklich daran hindert, ist die Größe und Auflösung der Euch zur Verfügung stehenden Typen wie Integer oder Single ;). Der eigentliche Größeneindruck eines Objektes entsteht durch die Geschwindigkeit mit der sich der Betrachter und andere Objekte in der Welt bewegen.&lt;br /&gt;
&lt;br /&gt;
=== Der erste Kontakt ===&lt;br /&gt;
Um nun etwas mit OpenGL rendern zu können, müssen wir uns bewusst werden, was eine Modellmatrix ist und warum wir sie benötigen. In dieser Matrix wird nämlich festgehalten, '''wie''' und '''wo''' ein Objekt gezeichnet wird. Das hört sich vielleicht zunächst recht merkwürdig an, lässt sich aber leicht veranschaulichen.&lt;br /&gt;
&lt;br /&gt;
Mann sollte sich vorstellen das eigentlich zwei Koordinatensysteme existieren, keine Angst ist ganz einfach... ;). &lt;br /&gt;
Ich erkläre es Euch an einer Beispielzeichnung: &lt;br /&gt;
&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
&lt;br /&gt;
Also in der 3D-Programmierung verschiebt man eigentlich nicht das Objekt sondern das Koordinatensystem, alles verstanden? *fg* Gut, dann weiter. Da man nun ein Objekt im Weltkoordinatensystem nicht so einfach verschieben und drehen kann (versucht mal die die neuen Koordinaten eines beliebig gedrehten Würfels selbst zu berechnen), suchte man etwas was an Stelle des Weltkoordinatensystems verschoben werden konnte, und so einfach zu Handhaben war wie eine '''unrotierte Darstellung im Ursprung des Koordinatensystems'''. Wer mitgelesen hat wird es schon wissen... richtig! Es ist das Modellkoordinatensystem, von selbst darauf gekommen? Super! &lt;br /&gt;
&lt;br /&gt;
Das Modellkoordinatensystem liegt noch vor dem ersten Aufruf parallel zum Weltkoordinatensystem, also die Basisvektoren (x,y,z-Achsen) &amp;quot;zeigen&amp;quot; in die selbe Richtung und haben den selben Ursrpung (0-Punkt). Rufen wir nun eine OpenGL Funktion zur Veränderung (z.B. glTranlate, glRotate...) unseres Objektes auf, so ändern wir eigentlich nicht das Objekt sondern nur das Modellkoordinatensystem. Und nicht vergessen! Auch beim Programmieren definieren wir ja auch zuerst die Position (also das Modellkoordinatensystem) und dann zeichnen wird das Objekt, ist eigentlich nicht schwer zu verstehen oder? *g*&lt;br /&gt;
&lt;br /&gt;
Ok, ok... ;) eine Beispielzeichnung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:wc-vs-mc-beispiel.png]]&lt;br /&gt;
&lt;br /&gt;
Der Würfel in der Darstellung oben, ist eigentlich nicht notwendig und dient nur der Veranschaulichung.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Sollte es jemand also nach der folgenden Erläuterung nicht verstanden haben, kann er mich selbstverständlich persönlich per Mail zur &amp;quot;Rechenschaft&amp;quot; ziehen oder aber er wirft einen Blick in unser OpenGLWiki :)).&lt;br /&gt;
&lt;br /&gt;
Wir setzen also zu Beginn unser Modellkoordinatensystem in den Mittelpunkt unseres Weltkoordinatensystems. Um oberes Beispiel aufzugreifen: Den Bildschirm. Dies geschieht mit dem Befehl [[glLoadIdentity]] und entspricht einem Reset der Modellmatrix. Theoretisch können wir nun an dieser Stelle etwas zeichnen. Dies würde allerdings dazu führen, dass das Objekt sehr groß oder gar nicht zu sehen ist, weil der Punkt (auch Augpunktkoordinate genannt) von dem aus wir unser Objekt betrachten  sich genau an der Stelle befindet wo sich unser Objekt befindet, nämlich im Ursprung (vorausgesetzt wir Zeichnen ein Objekt um oder and den Ursprung, und das genau in der x/y-Ebene und nicht darüber oder darunter) . Gehen wir doch einmal 1,5 Einheiten nach links und 6 Einheiten nach hinten!&lt;br /&gt;
&lt;br /&gt;
Eine kleine Beispielgrafik soll helfen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:objekt-sichtbar-verschieben.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hierfür sollte man sich bewusst werden, dass wir in OpenGL praktisch an einen Stuhl gefesselt sind, d.h. wir können uns gar nicht bewegen. Das soll uns aber nicht davon abhalten. Wir brauchen ja nur die ganze Welt so zu bewegen, dass es für uns aussieht, als ob wir uns bewegen. Denn wenn sich alles außer uns nach links bewegt, haben wir den Eindruck, wir wären nach rechts gewandert, right?&lt;br /&gt;
&lt;br /&gt;
Nun aber zu der Bewegung unseres ersten Objektes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(0, 0,-6);&lt;br /&gt;
glTranslatef(-1.5,0,0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dies hat bewirkt, dass sich unser Zeichenstift 6 Einheiten nach hinten (negativer Bereicht der Y-Achse) und anschließend 1,5 Einheiten nach links (negativer Bereich der X-Achse) bewegt hat. Ich habe diesen Fall absichtlich in zwei Schritten gefasst, um es zu verdeutlichen. Sicherlich wäre es einfacher, alles mit nur einem Aufruf von [[glTranslate|glTranslate*]] zu machen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(-1.5, 0,-6);&amp;lt;/source&amp;gt;&lt;br /&gt;
Man beachte, dass in diesem Fall die 6 Schritte nach hinten notwendig sind um ein bisschen Distanz zum Objekt zu bekommen und nicht direkt in ihm zu stehen!&lt;br /&gt;
&lt;br /&gt;
Fertig! Schon haben wir dort unseren &amp;quot;Zeichenstift&amp;quot; positioniert, der nun auf weitere Zeichenkommandos von uns wartet. Das mag sicherlich alles ein wenig verwirrend klingen... probiert es am Besten aus und spielt mit den Parametern und erkennt, was gemeint ist :).&lt;br /&gt;
&lt;br /&gt;
== Von Sichtungen... ==&lt;br /&gt;
=== Die Büchse der Pandora ===&lt;br /&gt;
Nun sind wir aber auch alle scharf darauf, endlich etwas zu rendern und auf dem Bildschirm auszugeben. Dies geschieht z.&amp;amp;nbsp;B. mit folgenden Zeilen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glVertex3f( 1,-1, 0);&lt;br /&gt;
  glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Wir erkennen hierbei eindeutig eine Art Block. Gerade wir Pascaler sollten diese ja lieben :-&amp;gt;. Wir teilen OpenGL mit Hilfe von [[glBegin]] mit, dass wir ein Objekt zeichnen wollen. In diesem Fall übergeben wir den Parameter '''GL_TRIANGLE''', der OpenGL angibt, dass folgende Punkte als ein Dreieck interpretiert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Anschließend folgt ein dreifacher Aufruf von [[glVertex|glVertex3f]]. Jeder Aufruf erzeugt nun einen Punkt (Vertex) in unserem 3D-Raum. Da wir OpenGL bei glBegin mitgeteilt haben, dass diese Punkte zu einem Dreieck zusammengefügt werden sollen, wird das auch so getan ;).&lt;br /&gt;
&lt;br /&gt;
Wie wir auf dem Bild erkennen können, wurde unser Dreieck wie erwartet nach links verschoben abgebildet und auch mit einem leichten Abstand zur Kamera, nämlich 6 Einheiten entlang der Z-Achse.&lt;br /&gt;
=== Guter Stoff! ===&lt;br /&gt;
Nun... ein wenig trostlos sieht unser Dreieck nun doch aus, oder? Ich habe übrigens damals bei D3D rund eine Woche benötigt, bis ich ein schwarzes Dreieck hatte. Wir haben immerhin schon ein weißes... aber wir gehen nun einen Schritt weiter und werden das Dreieck schön bunt einfärben.&lt;br /&gt;
&lt;br /&gt;
Bevor nun irgendjemand anfängt und Pixel für Pixel den Bildschirm nach zu pinseln oder gar sein PaintShop bereits offen hat, um die ersten Texturen zu erstellen, sei gestoppt! Es gibt für einfache Einfärbungen in OpenGL eine bessere Methode. Wir definieren einfach für jeden Eckpunkt eine Farbe und OpenGL wird dann sogar eigenständig die Farbverläufe dafür erstellen. Jeder der D3D kennt, wird diese Vorgehensweise bekannt vorkommen und er wird beginnen, verzweifelt nach dem FVF zu suchen, um es korrekt zu definieren... Wenn Ihr einen Vertex zeichnet, so rendert OpenGL diesen automatisch &amp;quot;weiß&amp;quot; (Ah huch! Deswegen ist unser Dreieck auch weiß???). Alles was wir nun machen müssen, ist OpenGL mitzuteilen, dass es eine andere Farbe einsetzen soll. Und zwar wird OpenGL diese Farbe für alle folgenden Eckpunkte nutzen, so lange bis von uns ein anderes Kommando kommt.&lt;br /&gt;
&lt;br /&gt;
Der mysteriöse Befehl, um den ich nun schon die ganze Zeit herumschwafle ist [[glColor|glColor*]]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Alle folgenden Eckpunkte werden rot gefärbt&lt;br /&gt;
glColor3f(1,0,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Wobei jeder Parameter einen Farbwert repräsentiert und zwar nach dem Muster RGB. Es wird ein Wert zwischen 1 und 0 erwartet, wobei eine Eins &amp;quot;volle Farbsättigung&amp;quot; bedeutet. Das heißt in unserem Fall haben wir als Farbe &amp;quot;rot&amp;quot; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Und weil wir schließlich die Welt ein wenig bunter machen und nicht nur das weiße Dreieck rot färben wollten, werden wir nach jedem Eckpunkt eine neue Farbe setzen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1, 0, 0); glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glColor3f(0, 0, 1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0, 1, 0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Und dies ist dann unser farbenfrohes Ergebnis. Beeindruckend, wenn man bedenkt, wie wenig Aufwand letztendlich dahinter steckt, oder?&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_dreieck.gif]]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wer meine Tutorials kennt weiß, dass zum Abschluß noch immer ein wenig Geblubber von mir kommt (man beachte diese entzückende Wortwahl von meiner einer... hoffe, der Lektor findet es auch amüsant...). (Anm. des Lektors: Und wie!) Schauen wir doch mal stolz auf das zurück, was wir heute erreicht haben! Wir haben OpenGL initialisiert, ein erstes Dreieck auf den Bildschirm gezaubert und dieses in den Farbtopf gesteckt! Das solltet Ihr als ein historisches Ereignis ansehen. Als ich damals mit D3D angefangen habe, brauchte ich, um es mir selbst zu erarbeiten, ca. eine Woche (Das ist jetzt der Moment, in dem Ihr Eure Hände heben solltest und ein lautes &amp;quot;Call me God&amp;quot; aus Euch herauskommen sollte, so dass zumindest Eure unmittelbaren Mitmenschen denken, dass Ihr einen Dachschaden habt!!! Das gehört einfach mit dazu ^__- )&lt;br /&gt;
&lt;br /&gt;
Wie immer solltet Ihr Euch nun hinsetzen und Euch ein wenig mit den Parametern vertraut machen. Speziell bei glTranslate* solltet Ihr ein wenig mit den Parametern experimentieren, damit Ihr seht, was es mit den Matrizen auf sich hat und wie diese funktionieren. Wenn Ihr dann auch denkt, dass Ihr damit vertraut seid, versucht ein wenig mit den einzelnen Vertexpositionen zu experimentieren und verändert diese. Wenn auch das klar ist, setzt Euch in die Ecke und warte sehnsüchtig auf mehr von uns :D! (Anm: Die &amp;quot;Ecke&amp;quot; ist nicht die Kneipe nebenan... :)&lt;br /&gt;
&lt;br /&gt;
Im nächsten Kapitel werden wir dann Matrizen-Hardcore machen ... legt also schon mal Euer Aspirin parat, es wird witzig werden *grunz* :).&lt;br /&gt;
&lt;br /&gt;
Und wie immer freuen wir uns sehr über Feedback. Schreibt uns doch einfach ein paar Worte in unser [http://www.delphigl.com/forum/viewforum.php?f=8 Feedback-Forum]. Sagt, was Ihr gut und was hingegen Ihr als schlecht empfunden habt! Auch freuen wir uns immer über Ideen für weitere Tutorials, teilt uns also bitte Eure Ideen mit ;)!&lt;br /&gt;
&lt;br /&gt;
Okay... ich wünsche Euch einen angenehmen Tag / Nacht!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 1]] | [[Tutorial Lektion 3]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion2]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23900</id>
		<title>Tutorial Lektion 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23900"/>
				<updated>2009-07-23T00:18:46Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Grafik zur Objektverschiebung eingefügt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Entdeckung einer neuen Welt =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Ich möchte Euch an dieser Stelle bei DGL herzlich willkommen heißen. Vermutlich wird dies eines der ersten Tutorials sein, das Ihr als Einsteiger lesen werdet. Wahrscheinlich werdet Ihr dann auch noch nicht lange bei uns sein und Euch nicht vorstellen können, dass all die Schreiber auf unserer Seite keine Gurus, sondern ganz normale Menschen sind.&lt;br /&gt;
&lt;br /&gt;
Man kann uns also jeder Zeit im Forum &amp;quot;anfassen&amp;quot;, uns Fragen stellen, Vorschläge unterbreiten oder einfach nur einmal kurz mit einem Lob ermutigen weitere Texte zu verfassen ;-).&lt;br /&gt;
&lt;br /&gt;
Ich wünsche Euch an dieser Stelle viel Erfolg bei dem Einstieg in die Thematik OpenGL und ermahne Euch noch einmal, dass Ihr Eure Ziele nicht zu weit steckt. Wirklich Spaß beginnt OpenGL nämlich erst dann zu machen, wenn man stets kleinere Erfolge feiern kann.&lt;br /&gt;
== Höhere Mächte - Matrizen und ihre Folgen ==&lt;br /&gt;
=== Saubere Arbeit ===&lt;br /&gt;
Bevor wir direkt beginnen, etwas zu zeichnen, müssen wir erst einmal das Bild löschen, denn wie in der vorherigen Lektion beschrieben zeichnen wir die Szene jeden Schleifendurchlauf neu. Das Löschen der Puffer, in dem die Bildinformationen enthalten sind, übernimmt die Funktion [[glClear]]. Die Farbinformationen unser  [[Fragment|Fragmente]] (Fragmente sind vergleichbar mit den [[Pixel|Pixeln]] auf dem Bildschirm, besitzen aber weitere Informationen wie z.&amp;amp;nbsp;B. Tiefenwerte. Bei der Ausgabe des Bildes werden diese Fragmente in Pixel umgewandelt) sind in dem so genannten [[Farbpuffer]] (Colorbuffer) gespeichert. Aus diesem Grund übergeben wir an die Funktion [[glClear]] die Konstante '''GL_COLOR_BUFFER_BIT'''. Die oben bereits angesprochenen Tiefenwerte stehen im [[Tiefenpuffer]]. Diese Daten werden benutzt, um zu entscheiden, welche Pixel durch andere verdeckt werden. Deshalb sollten wir den Tiefenpuffer auch mit löschen. Die Konstante dafür heißt '''GL_DEPTH_BUFFER_BIT'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;//Farbbuffer und Tiefenpuffer entleeren&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_puffereffekt.gif|right]]&lt;br /&gt;
Mit Hilfe des Befehls [[glClearColor]] können wir festlegen, welche Farbinformationen mit dem Aufruf von glClear in den Colorbuffer geschrieben werden sollen. Wenn wir es also genau nehmen, so löscht glClear den Colorbuffer nicht, sondern es schreibt ihn mit den definierten Werten voll. Standardmäßig erhalten die Fragmente eine schwarze Farbe. (Der Vollständigkeit halber sei erwähnt, dass der Tiefenpuffer immer mit Nullen überschrieben wird.)&lt;br /&gt;
&lt;br /&gt;
Es wird also nicht bei jedem Zeichenvorgang (Rendervorgang) der Bildspeicher gelöscht, sondern der Programmierer entscheidet, wann dies geschehen soll. Theoretisch könnt Ihr auch die Szene wiedergeben und dann löschen, bevor sie ausgegeben wird... wer's mag :).&lt;br /&gt;
&lt;br /&gt;
Wer sich entscheidet, den Colorbuffer nicht zu löschen, der kann so auch einige nette Effekte erzeugen. Den Cheatern unter euch sollte der erreichte Effekt bekannt vorkommen, wenn man beispielsweise bei Counter-Strike durch die Wand gelaufen ist. Der Grund für das Verwischen ist in beiden Fällen derselbe: Das neue Bild wird gezeichnet, ohne dass das alte Bild aus dem Puffer entfernt wurde.&lt;br /&gt;
&lt;br /&gt;
=== Und die Welt ist doch keine Scheibe... ===&lt;br /&gt;
[[bild:Tutimg_lektion2_koordinatensystem.jpg|256px|right]]&lt;br /&gt;
Nachdem wir nun wieder Ordnung im Speicher geschafft haben, können wir zum interessanten Teil kommen: &amp;quot;Wie darf man sich einen 3D-Raum vorstellen?&amp;quot; Nun... warum schaut Ihr Euch nicht einmal in Eurem Zimmer um?&lt;br /&gt;
&lt;br /&gt;
Versuchen wir doch mal, ein Beispiel direkt aus dem Leben gegriffen zu nehmen und stellen uns unsere Umgebung als Koordinaten-System vor (Igitt!). Der Monitor, der hoffentlich direkt vor uns steht, ist in diesem Fall unser Ursprung, d.h. er liegt an dem Punkt (0, 0, 0).&lt;br /&gt;
&lt;br /&gt;
Blicken wir seitwärts neben den Monitor, so sehen wir eine Linie (wenn Ihr es nicht tun solltest, macht Euch keine Sorgen ... solche Anfälle hat der Autor häufiger *g*), die von links nach rechts verläuft. Es handelt sich hierbei um die X-Achse, die links vom Monitor im negativen Bereich verläuft, rechts davon in den positiven.&lt;br /&gt;
&lt;br /&gt;
Nun blicken wir einmal nach oben und einmal nach unten und schon erspähen wir die Y-Achse, die oberhalb des Monitors positiv verläuft, unterhalb negativ. Wunderbar! Wenn Ihr bereits in 2D gearbeitet habt, solltet Ihr an dieser Stelle ein dümmliches Grinsen auf Eurem Gesichte haben und das wohltuende Gefühl, dass Euch das doch alles bereits irgendwie bekannt vorkommt. Doch zu unserem Entsetzen können wir uns ja auch noch von unserem Bildschirm wegbewegen oder auch dichter heran (alle Kurzsichtigen unter uns sollten das nicht so persönlich nehmen, auch sie leben in einem 3D-Raum ^__-).&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen ist im 3D-Raum typisch, jedoch nicht unerklärlich, da wir uns auf der Z-Achse bewegen. Rollen wir mit dem Stuhl vom Monitor weg, so gelangen wir in den positiven Bereich der Z-Achse, bewegen wir uns drauf zu, gelangen wir in den negativen Bereich. Jeder, der bereits in D3D programmiert hat, sollte sich schleunigst einprägen, dass das ein großer Unterschied zwischen D3D und OpenGL ist. Das kann sonst zu einigen wirklich fiesen Fehlern führen, wenn man es nicht weiß... *fg*.&lt;br /&gt;
&lt;br /&gt;
Soweit so gut! Klingt bisher hoffentlich immer noch nicht so kompliziert. Nur keine Sorge, das Niveau versuchen wir zu halten ;).&lt;br /&gt;
&lt;br /&gt;
Speziell wenn Ihr bereits 2D-Spiele programmiert habt, solltet Ihr Euch sehr schnell von folgenden Gedanken trennen: Die Koordinaten, die Ihr seht und angebt, entsprechen in der Regel nicht den Pixeln des Bildschirmes, sondern so genannten Weltkoordinaten. Eine Definition für diese Weltkoordinaten gibt es nicht, denn wie groß diese sind, ist dem Programmierer überlassen. Ob Ihr euer Objekt eine Einheit vor Euch und 0,1 Einheit rechts von Euch oder aber 100 Einheiten vor euch und 10 Einheiten neben Euch positioniert ist egal. Die euch zur Verfügung stehende Welt ist grenzenlos ;). Ihr könnt Eure Szene theoretisch unendlich klein oder aber unendlich groß darstellen. Das Einzige, was euch wirklich daran hindert, ist die Größe und Auflösung der Euch zur Verfügung stehenden Typen wie Integer oder Single ;). Der eigentliche Größeneindruck eines Objektes entsteht durch die Geschwindigkeit mit der sich der Betrachter und andere Objekte in der Welt bewegen.&lt;br /&gt;
&lt;br /&gt;
=== Der erste Kontakt ===&lt;br /&gt;
Um nun etwas mit OpenGL rendern zu können, müssen wir uns bewusst werden, was eine Modellmatrix ist und warum wir sie benötigen. In dieser Matrix wird nämlich festgehalten, '''wie''' und '''wo''' ein Objekt gezeichnet wird. Das hört sich vielleicht zunächst recht merkwürdig an, lässt sich aber leicht veranschaulichen.&lt;br /&gt;
&lt;br /&gt;
Mann sollte sich vorstellen das eigentlich zwei Koordinatensysteme existieren, keine Angst ist ganz einfach... ;). &lt;br /&gt;
Ich erkläre es Euch an einer Beispielzeichnung: &lt;br /&gt;
&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
&lt;br /&gt;
Also in der 3D-Programmierung verschiebt man eigentlich nicht das Objekt sondern das Koordinatensystem, alles verstanden? *fg* Gut, dann weiter. Da man nun ein Objekt im Weltkoordinatensystem nicht so einfach verschieben und drehen kann (versucht mal die die neuen Koordinaten eines beliebig gedrehten Würfels selbst zu berechnen), suchte man etwas was an Stelle des Weltkoordinatensystems verschoben werden konnte, und so einfach zu Handhaben war wie eine '''unrotierte Darstellung im Ursprung des Koordinatensystems'''. Wer mitgelesen hat wird es schon wissen... richtig! Es ist das Modellkoordinatensystem, von selbst darauf gekommen? Super! &lt;br /&gt;
&lt;br /&gt;
Das Modellkoordinatensystem liegt noch vor dem ersten Aufruf parallel zum Weltkoordinatensystem, also die Basisvektoren (x,y,z-Achsen) &amp;quot;zeigen&amp;quot; in die selbe Richtung und haben den selben Ursrpung (0-Punkt). Rufen wir nun eine OpenGL Funktion zur Veränderung (z.B. glTranlate, glRotate...) unseres Objektes auf, so ändern wir eigentlich nicht das Objekt sondern nur das Modellkoordinatensystem. Und nicht vergessen! Auch beim Programmieren definieren wir ja auch zuerst die Position (also das Modellkoordinatensystem) und dann zeichnen wird das Objekt, ist eigentlich nicht schwer zu verstehen oder? *g*&lt;br /&gt;
&lt;br /&gt;
Ok, ok... ;) eine Beispielzeichnung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:wc-vs-mc-beispiel.png]]&lt;br /&gt;
&lt;br /&gt;
Der Würfel in der Darstellung oben, ist eigentlich nicht notwendig und dient nur der Veranschaulichung.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Sollte es jemand also nach der folgenden Erläuterung nicht verstanden haben, kann er mich selbstverständlich persönlich per Mail zur &amp;quot;Rechenschaft&amp;quot; ziehen oder aber er wirft einen Blick in unser OpenGLWiki :)).&lt;br /&gt;
&lt;br /&gt;
Wir setzen also zu Beginn unser Modellkoordinatensystem in den Mittelpunkt unseres Weltkoordinatensystems. Um oberes Beispiel aufzugreifen: Den Bildschirm. Dies geschieht mit dem Befehl [[glLoadIdentity]] und entspricht einem Reset der Modellmatrix. Theoretisch können wir nun an dieser Stelle etwas zeichnen. Dies würde allerdings dazu führen, dass das Objekt sehr groß oder gar nicht zu sehen ist, weil der Punkt (auch Augpunktkoordinate genannt) von dem aus wir unser Objekt betrachten  sich genau an der Stelle befindet wo sich unser Objekt befindet, nämlich im Ursprung (vorausgesetzt wir Zeichnen ein Objekt um oder and den Ursprung, und das genau in der x/y-Ebene und nicht darüber oder darunter) . Gehen wir doch einmal 1,5 Einheiten nach links und 6 Einheiten nach hinten!&lt;br /&gt;
&lt;br /&gt;
Eine kleine Beispielgrafik soll helfen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:objekt-sichtbar-verschieben.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hierfür sollte man sich bewusst werden, dass wir in OpenGL praktisch an einen Stuhl gefesselt sind, d.h. wir können uns gar nicht bewegen. Das soll uns aber nicht davon abhalten. Wir brauchen ja nur die ganze Welt so zu bewegen, dass es für uns aussieht, als ob wir uns bewegen. Denn wenn sich alles außer uns nach links bewegt, haben wir den Eindruck, wir wären nach rechts gewandert, right?&lt;br /&gt;
&lt;br /&gt;
Nun aber zu der Bewegung unseres ersten Objektes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(0, 0,-6);&lt;br /&gt;
glTranslatef(-1.5,0,0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dies hat bewirkt, dass sich unser Zeichenstift 1,5 Einheiten nach links (negativer Bereich der X-Achse) und anschließend 6 Einheiten nach hinten bewegt hat. Ich habe diesen Fall absichtlich in zwei Schritten gefasst, um es zu verdeutlichen. Sicherlich wäre es einfacher, alles mit nur einem Aufruf von [[glTranslate|glTranslate*]] zu machen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(-1.5, 0,-6);&amp;lt;/source&amp;gt;&lt;br /&gt;
Man beachte, dass in diesem Fall die 6 Schritte nach hinten notwendig sind um ein bisschen Distanz zum Objekt zu bekommen und nicht direkt in ihm zu stehen!&lt;br /&gt;
&lt;br /&gt;
Fertig! Schon haben wir dort unseren &amp;quot;Zeichenstift&amp;quot; positioniert, der nun auf weitere Zeichenkommandos von uns wartet. Das mag sicherlich alles ein wenig verwirrend klingen... probiert es am Besten aus und spielt mit den Parametern und erkennt, was gemeint ist :).&lt;br /&gt;
&lt;br /&gt;
== Von Sichtungen... ==&lt;br /&gt;
=== Die Büchse der Pandora ===&lt;br /&gt;
Nun sind wir aber auch alle scharf darauf, endlich etwas zu rendern und auf dem Bildschirm auszugeben. Dies geschieht z.&amp;amp;nbsp;B. mit folgenden Zeilen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glVertex3f( 1,-1, 0);&lt;br /&gt;
  glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Wir erkennen hierbei eindeutig eine Art Block. Gerade wir Pascaler sollten diese ja lieben :-&amp;gt;. Wir teilen OpenGL mit Hilfe von [[glBegin]] mit, dass wir ein Objekt zeichnen wollen. In diesem Fall übergeben wir den Parameter '''GL_TRIANGLE''', der OpenGL angibt, dass folgende Punkte als ein Dreieck interpretiert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Anschließend folgt ein dreifacher Aufruf von [[glVertex|glVertex3f]]. Jeder Aufruf erzeugt nun einen Punkt (Vertex) in unserem 3D-Raum. Da wir OpenGL bei glBegin mitgeteilt haben, dass diese Punkte zu einem Dreieck zusammengefügt werden sollen, wird das auch so getan ;).&lt;br /&gt;
&lt;br /&gt;
Wie wir auf dem Bild erkennen können, wurde unser Dreieck wie erwartet nach links verschoben abgebildet und auch mit einem leichten Abstand zur Kamera, nämlich 6 Einheiten entlang der Z-Achse.&lt;br /&gt;
=== Guter Stoff! ===&lt;br /&gt;
Nun... ein wenig trostlos sieht unser Dreieck nun doch aus, oder? Ich habe übrigens damals bei D3D rund eine Woche benötigt, bis ich ein schwarzes Dreieck hatte. Wir haben immerhin schon ein weißes... aber wir gehen nun einen Schritt weiter und werden das Dreieck schön bunt einfärben.&lt;br /&gt;
&lt;br /&gt;
Bevor nun irgendjemand anfängt und Pixel für Pixel den Bildschirm nach zu pinseln oder gar sein PaintShop bereits offen hat, um die ersten Texturen zu erstellen, sei gestoppt! Es gibt für einfache Einfärbungen in OpenGL eine bessere Methode. Wir definieren einfach für jeden Eckpunkt eine Farbe und OpenGL wird dann sogar eigenständig die Farbverläufe dafür erstellen. Jeder der D3D kennt, wird diese Vorgehensweise bekannt vorkommen und er wird beginnen, verzweifelt nach dem FVF zu suchen, um es korrekt zu definieren... Wenn Ihr einen Vertex zeichnet, so rendert OpenGL diesen automatisch &amp;quot;weiß&amp;quot; (Ah huch! Deswegen ist unser Dreieck auch weiß???). Alles was wir nun machen müssen, ist OpenGL mitzuteilen, dass es eine andere Farbe einsetzen soll. Und zwar wird OpenGL diese Farbe für alle folgenden Eckpunkte nutzen, so lange bis von uns ein anderes Kommando kommt.&lt;br /&gt;
&lt;br /&gt;
Der mysteriöse Befehl, um den ich nun schon die ganze Zeit herumschwafle ist [[glColor|glColor*]]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Alle folgenden Eckpunkte werden rot gefärbt&lt;br /&gt;
glColor3f(1,0,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Wobei jeder Parameter einen Farbwert repräsentiert und zwar nach dem Muster RGB. Es wird ein Wert zwischen 1 und 0 erwartet, wobei eine Eins &amp;quot;volle Farbsättigung&amp;quot; bedeutet. Das heißt in unserem Fall haben wir als Farbe &amp;quot;rot&amp;quot; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Und weil wir schließlich die Welt ein wenig bunter machen und nicht nur das weiße Dreieck rot färben wollten, werden wir nach jedem Eckpunkt eine neue Farbe setzen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1, 0, 0); glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glColor3f(0, 0, 1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0, 1, 0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Und dies ist dann unser farbenfrohes Ergebnis. Beeindruckend, wenn man bedenkt, wie wenig Aufwand letztendlich dahinter steckt, oder?&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_dreieck.gif]]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wer meine Tutorials kennt weiß, dass zum Abschluß noch immer ein wenig Geblubber von mir kommt (man beachte diese entzückende Wortwahl von meiner einer... hoffe, der Lektor findet es auch amüsant...). (Anm. des Lektors: Und wie!) Schauen wir doch mal stolz auf das zurück, was wir heute erreicht haben! Wir haben OpenGL initialisiert, ein erstes Dreieck auf den Bildschirm gezaubert und dieses in den Farbtopf gesteckt! Das solltet Ihr als ein historisches Ereignis ansehen. Als ich damals mit D3D angefangen habe, brauchte ich, um es mir selbst zu erarbeiten, ca. eine Woche (Das ist jetzt der Moment, in dem Ihr Eure Hände heben solltest und ein lautes &amp;quot;Call me God&amp;quot; aus Euch herauskommen sollte, so dass zumindest Eure unmittelbaren Mitmenschen denken, dass Ihr einen Dachschaden habt!!! Das gehört einfach mit dazu ^__- )&lt;br /&gt;
&lt;br /&gt;
Wie immer solltet Ihr Euch nun hinsetzen und Euch ein wenig mit den Parametern vertraut machen. Speziell bei glTranslate* solltet Ihr ein wenig mit den Parametern experimentieren, damit Ihr seht, was es mit den Matrizen auf sich hat und wie diese funktionieren. Wenn Ihr dann auch denkt, dass Ihr damit vertraut seid, versucht ein wenig mit den einzelnen Vertexpositionen zu experimentieren und verändert diese. Wenn auch das klar ist, setzt Euch in die Ecke und warte sehnsüchtig auf mehr von uns :D! (Anm: Die &amp;quot;Ecke&amp;quot; ist nicht die Kneipe nebenan... :)&lt;br /&gt;
&lt;br /&gt;
Im nächsten Kapitel werden wir dann Matrizen-Hardcore machen ... legt also schon mal Euer Aspirin parat, es wird witzig werden *grunz* :).&lt;br /&gt;
&lt;br /&gt;
Und wie immer freuen wir uns sehr über Feedback. Schreibt uns doch einfach ein paar Worte in unser [http://www.delphigl.com/forum/viewforum.php?f=8 Feedback-Forum]. Sagt, was Ihr gut und was hingegen Ihr als schlecht empfunden habt! Auch freuen wir uns immer über Ideen für weitere Tutorials, teilt uns also bitte Eure Ideen mit ;)!&lt;br /&gt;
&lt;br /&gt;
Okay... ich wünsche Euch einen angenehmen Tag / Nacht!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 1]] | [[Tutorial Lektion 3]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion2]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:objekt-sichtbar-verschieben.png&amp;diff=23899</id>
		<title>Datei:objekt-sichtbar-verschieben.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:objekt-sichtbar-verschieben.png&amp;diff=23899"/>
				<updated>2009-07-23T00:14:59Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Selbst gemacht mit Inkscape&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbst gemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23898</id>
		<title>Tutorial Lektion 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_2&amp;diff=23898"/>
				<updated>2009-07-22T22:18:04Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Es gibt keine Worldmatrix!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Entdeckung einer neuen Welt =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Ich möchte Euch an dieser Stelle bei DGL herzlich willkommen heißen. Vermutlich wird dies eines der ersten Tutorials sein, das Ihr als Einsteiger lesen werdet. Wahrscheinlich werdet Ihr dann auch noch nicht lange bei uns sein und Euch nicht vorstellen können, dass all die Schreiber auf unserer Seite keine Gurus, sondern ganz normale Menschen sind.&lt;br /&gt;
&lt;br /&gt;
Man kann uns also jeder Zeit im Forum &amp;quot;anfassen&amp;quot;, uns Fragen stellen, Vorschläge unterbreiten oder einfach nur einmal kurz mit einem Lob ermutigen weitere Texte zu verfassen ;-).&lt;br /&gt;
&lt;br /&gt;
Ich wünsche Euch an dieser Stelle viel Erfolg bei dem Einstieg in die Thematik OpenGL und ermahne Euch noch einmal, dass Ihr Eure Ziele nicht zu weit steckt. Wirklich Spaß beginnt OpenGL nämlich erst dann zu machen, wenn man stets kleinere Erfolge feiern kann.&lt;br /&gt;
== Höhere Mächte - Matrizen und ihre Folgen ==&lt;br /&gt;
=== Saubere Arbeit ===&lt;br /&gt;
Bevor wir direkt beginnen, etwas zu zeichnen, müssen wir erst einmal das Bild löschen, denn wie in der vorherigen Lektion beschrieben zeichnen wir die Szene jeden Schleifendurchlauf neu. Das Löschen der Puffer, in dem die Bildinformationen enthalten sind, übernimmt die Funktion [[glClear]]. Die Farbinformationen unser  [[Fragment|Fragmente]] (Fragmente sind vergleichbar mit den [[Pixel|Pixeln]] auf dem Bildschirm, besitzen aber weitere Informationen wie z.&amp;amp;nbsp;B. Tiefenwerte. Bei der Ausgabe des Bildes werden diese Fragmente in Pixel umgewandelt) sind in dem so genannten [[Farbpuffer]] (Colorbuffer) gespeichert. Aus diesem Grund übergeben wir an die Funktion [[glClear]] die Konstante '''GL_COLOR_BUFFER_BIT'''. Die oben bereits angesprochenen Tiefenwerte stehen im [[Tiefenpuffer]]. Diese Daten werden benutzt, um zu entscheiden, welche Pixel durch andere verdeckt werden. Deshalb sollten wir den Tiefenpuffer auch mit löschen. Die Konstante dafür heißt '''GL_DEPTH_BUFFER_BIT'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;//Farbbuffer und Tiefenpuffer entleeren&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_puffereffekt.gif|right]]&lt;br /&gt;
Mit Hilfe des Befehls [[glClearColor]] können wir festlegen, welche Farbinformationen mit dem Aufruf von glClear in den Colorbuffer geschrieben werden sollen. Wenn wir es also genau nehmen, so löscht glClear den Colorbuffer nicht, sondern es schreibt ihn mit den definierten Werten voll. Standardmäßig erhalten die Fragmente eine schwarze Farbe. (Der Vollständigkeit halber sei erwähnt, dass der Tiefenpuffer immer mit Nullen überschrieben wird.)&lt;br /&gt;
&lt;br /&gt;
Es wird also nicht bei jedem Zeichenvorgang (Rendervorgang) der Bildspeicher gelöscht, sondern der Programmierer entscheidet, wann dies geschehen soll. Theoretisch könnt Ihr auch die Szene wiedergeben und dann löschen, bevor sie ausgegeben wird... wer's mag :).&lt;br /&gt;
&lt;br /&gt;
Wer sich entscheidet, den Colorbuffer nicht zu löschen, der kann so auch einige nette Effekte erzeugen. Den Cheatern unter euch sollte der erreichte Effekt bekannt vorkommen, wenn man beispielsweise bei Counter-Strike durch die Wand gelaufen ist. Der Grund für das Verwischen ist in beiden Fällen derselbe: Das neue Bild wird gezeichnet, ohne dass das alte Bild aus dem Puffer entfernt wurde.&lt;br /&gt;
&lt;br /&gt;
=== Und die Welt ist doch keine Scheibe... ===&lt;br /&gt;
[[bild:Tutimg_lektion2_koordinatensystem.jpg|256px|right]]&lt;br /&gt;
Nachdem wir nun wieder Ordnung im Speicher geschafft haben, können wir zum interessanten Teil kommen: &amp;quot;Wie darf man sich einen 3D-Raum vorstellen?&amp;quot; Nun... warum schaut Ihr Euch nicht einmal in Eurem Zimmer um?&lt;br /&gt;
&lt;br /&gt;
Versuchen wir doch mal, ein Beispiel direkt aus dem Leben gegriffen zu nehmen und stellen uns unsere Umgebung als Koordinaten-System vor (Igitt!). Der Monitor, der hoffentlich direkt vor uns steht, ist in diesem Fall unser Ursprung, d.h. er liegt an dem Punkt (0, 0, 0).&lt;br /&gt;
&lt;br /&gt;
Blicken wir seitwärts neben den Monitor, so sehen wir eine Linie (wenn Ihr es nicht tun solltest, macht Euch keine Sorgen ... solche Anfälle hat der Autor häufiger *g*), die von links nach rechts verläuft. Es handelt sich hierbei um die X-Achse, die links vom Monitor im negativen Bereich verläuft, rechts davon in den positiven.&lt;br /&gt;
&lt;br /&gt;
Nun blicken wir einmal nach oben und einmal nach unten und schon erspähen wir die Y-Achse, die oberhalb des Monitors positiv verläuft, unterhalb negativ. Wunderbar! Wenn Ihr bereits in 2D gearbeitet habt, solltet Ihr an dieser Stelle ein dümmliches Grinsen auf Eurem Gesichte haben und das wohltuende Gefühl, dass Euch das doch alles bereits irgendwie bekannt vorkommt. Doch zu unserem Entsetzen können wir uns ja auch noch von unserem Bildschirm wegbewegen oder auch dichter heran (alle Kurzsichtigen unter uns sollten das nicht so persönlich nehmen, auch sie leben in einem 3D-Raum ^__-).&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen ist im 3D-Raum typisch, jedoch nicht unerklärlich, da wir uns auf der Z-Achse bewegen. Rollen wir mit dem Stuhl vom Monitor weg, so gelangen wir in den positiven Bereich der Z-Achse, bewegen wir uns drauf zu, gelangen wir in den negativen Bereich. Jeder, der bereits in D3D programmiert hat, sollte sich schleunigst einprägen, dass das ein großer Unterschied zwischen D3D und OpenGL ist. Das kann sonst zu einigen wirklich fiesen Fehlern führen, wenn man es nicht weiß... *fg*.&lt;br /&gt;
&lt;br /&gt;
Soweit so gut! Klingt bisher hoffentlich immer noch nicht so kompliziert. Nur keine Sorge, das Niveau versuchen wir zu halten ;).&lt;br /&gt;
&lt;br /&gt;
Speziell wenn Ihr bereits 2D-Spiele programmiert habt, solltet Ihr Euch sehr schnell von folgenden Gedanken trennen: Die Koordinaten, die Ihr seht und angebt, entsprechen in der Regel nicht den Pixeln des Bildschirmes, sondern so genannten Weltkoordinaten. Eine Definition für diese Weltkoordinaten gibt es nicht, denn wie groß diese sind, ist dem Programmierer überlassen. Ob Ihr euer Objekt eine Einheit vor Euch und 0,1 Einheit rechts von Euch oder aber 100 Einheiten vor euch und 10 Einheiten neben Euch positioniert ist egal. Die euch zur Verfügung stehende Welt ist grenzenlos ;). Ihr könnt Eure Szene theoretisch unendlich klein oder aber unendlich groß darstellen. Das Einzige, was euch wirklich daran hindert, ist die Größe und Auflösung der Euch zur Verfügung stehenden Typen wie Integer oder Single ;). Der eigentliche Größeneindruck eines Objektes entsteht durch die Geschwindigkeit mit der sich der Betrachter und andere Objekte in der Welt bewegen.&lt;br /&gt;
&lt;br /&gt;
=== Der erste Kontakt ===&lt;br /&gt;
Um nun etwas mit OpenGL rendern zu können, müssen wir uns bewusst werden, was eine Modellmatrix ist und warum wir sie benötigen. In dieser Matrix wird nämlich festgehalten, '''wie''' und '''wo''' ein Objekt gezeichnet wird. Das hört sich vielleicht zunächst recht merkwürdig an, lässt sich aber leicht veranschaulichen.&lt;br /&gt;
&lt;br /&gt;
Mann sollte sich vorstellen das eigentlich zwei Koordinatensysteme existieren, keine Angst ist ganz einfach... ;). &lt;br /&gt;
Ich erkläre es Euch an einer Beispielzeichnung: &lt;br /&gt;
&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
&lt;br /&gt;
Also in der 3D-Programmierung verschiebt man eigentlich nicht das Objekt sondern das Koordinatensystem, alles verstanden? *fg* Gut, dann weiter. Da man nun das Weltkoordinatensystem nicht so einfach verschieben kann, brauchte man etwas was das an der Stelle des Weltkoordinatensystems verschoben werden konnte, wer mitgelesen hat wird es schon wissen, richtig es ist das Modellkoordinatensystem, super! &lt;br /&gt;
&lt;br /&gt;
Das Modellkoordinatensystem liegt noch vor dem ersten Aufruf parallel zum Weltkoordinatensystem, also die Basisvektoren (x,y,z-Achsen) &amp;quot;zeigen&amp;quot; in die selbe Richtung und haben den selben Ursrpung (0-Punkt). Rufen nun eine OpenGL Funktion zur Veränderung (z.B. glTranlate, glRotate...) unseres Objektes auf, so ändern wir eigentlich nicht das Objekt sondern das Modellkoordinatensystem. Und nicht vergessen! Auch beim Programmieren definieren wir ja auch zuerst die Position (also das Modellkoordinatensystem) und dann zeichnen wird das Objekt, ist eigentlich nicht schwer zu verstehen oder? *g*&lt;br /&gt;
&lt;br /&gt;
Ok, ok... eine Beispielzeichnung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:wc-vs-mc-beispiel.png]]&lt;br /&gt;
&lt;br /&gt;
Der Würfel in der Darstellung oben, ist eigentlich nicht notwendig und dient nur der Veranschaulichung.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Sollte es jemand also nach der folgenden Erläuterung nicht verstanden haben, kann er mich selbstverständlich persönlich per Mail zur &amp;quot;Rechenschaft&amp;quot; ziehen oder aber er wirft einen Blick in unser OpenGLWiki :)).&lt;br /&gt;
&lt;br /&gt;
Wir setzen also zu Beginn unser Modellkoordinatensystem in den Mittelpunkt unseres Weltkoordinatensystems. Um oberes Beispiel aufzugreifen: Den Bildschirm. Dies geschieht mit dem Befehl [[glLoadIdentity]] und entspricht einem Reset der Modellmatrix. Theoretisch können wir nun an dieser Stelle etwas zeichnen. Dies würde allerdings dazu führen, dass das Objekt sehr groß oder gar nicht zu sehen ist, weil der Punkt von dem aus wir unser Objekt betrachten  sich auch an dieser Stelle befindet, nämlich im Ursprung. Gehen wir doch einmal 1,5 Einheiten nach links und 6 Einheiten nach hinten!&lt;br /&gt;
&lt;br /&gt;
Hierfür sollte man sich bewusst werden, dass wir in OpenGL praktisch an einen Stuhl gefesselt sind, d.h. wir können uns gar nicht bewegen. Das soll uns aber nicht davon abhalten. Wir brauchen ja nur die ganze Welt so zu bewegen, dass es für uns aussieht, als ob wir uns bewegen. Denn wenn sich alles außer uns nach links bewegt, haben wir den Eindruck, wir wären nach rechts gewandert, right?&lt;br /&gt;
&lt;br /&gt;
Nun aber zu der Bewegung unseres ersten Objektes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(-1.5,0,0);&lt;br /&gt;
glTranslatef(0, 0,-6);&amp;lt;/source&amp;gt;&lt;br /&gt;
Dies hat bewirkt, dass sich unser Zeichenstift 1,5 Einheiten nach links (negativer Bereich der X-Achse) und anschließend 6 Einheiten nach hinten bewegt hat. Ich habe diesen Fall absichtlich in zwei Schritten gefasst, um es zu verdeutlichen. Sicherlich wäre es einfacher, alles mit nur einem Aufruf von [[glTranslate|glTranslate*]] zu machen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(-1.5, 0,-6);&amp;lt;/source&amp;gt;&lt;br /&gt;
Man beachte, dass in diesem Fall die 6 Schritte nach hinten notwendig sind um ein bisschen Distanz zum Objekt zu bekommen und nicht direkt in ihm zu stehen!&lt;br /&gt;
&lt;br /&gt;
Fertig! Schon haben wir dort unseren &amp;quot;Zeichenstift&amp;quot; positioniert, der nun auf weitere Zeichenkommandos von uns wartet. Das mag sicherlich alles ein wenig verwirrend klingen... probiert es am Besten aus und spielt mit den Parametern und erkennt, was gemeint ist :).&lt;br /&gt;
&lt;br /&gt;
== Von Sichtungen... ==&lt;br /&gt;
=== Die Büchse der Pandora ===&lt;br /&gt;
Nun sind wir aber auch alle scharf darauf, endlich etwas zu rendern und auf dem Bildschirm auszugeben. Dies geschieht z.&amp;amp;nbsp;B. mit folgenden Zeilen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glVertex3f( 1,-1, 0);&lt;br /&gt;
  glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Wir erkennen hierbei eindeutig eine Art Block. Gerade wir Pascaler sollten diese ja lieben :-&amp;gt;. Wir teilen OpenGL mit Hilfe von [[glBegin]] mit, dass wir ein Objekt zeichnen wollen. In diesem Fall übergeben wir den Parameter '''GL_TRIANGLE''', der OpenGL angibt, dass folgende Punkte als ein Dreieck interpretiert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Anschließend folgt ein dreifacher Aufruf von [[glVertex|glVertex3f]]. Jeder Aufruf erzeugt nun einen Punkt (Vertex) in unserem 3D-Raum. Da wir OpenGL bei glBegin mitgeteilt haben, dass diese Punkte zu einem Dreieck zusammengefügt werden sollen, wird das auch so getan ;).&lt;br /&gt;
&lt;br /&gt;
Wie wir auf dem Bild erkennen können, wurde unser Dreieck wie erwartet nach links verschoben abgebildet und auch mit einem leichten Abstand zur Kamera, nämlich 6 Einheiten entlang der Z-Achse.&lt;br /&gt;
=== Guter Stoff! ===&lt;br /&gt;
Nun... ein wenig trostlos sieht unser Dreieck nun doch aus, oder? Ich habe übrigens damals bei D3D rund eine Woche benötigt, bis ich ein schwarzes Dreieck hatte. Wir haben immerhin schon ein weißes... aber wir gehen nun einen Schritt weiter und werden das Dreieck schön bunt einfärben.&lt;br /&gt;
&lt;br /&gt;
Bevor nun irgendjemand anfängt und Pixel für Pixel den Bildschirm nach zu pinseln oder gar sein PaintShop bereits offen hat, um die ersten Texturen zu erstellen, sei gestoppt! Es gibt für einfache Einfärbungen in OpenGL eine bessere Methode. Wir definieren einfach für jeden Eckpunkt eine Farbe und OpenGL wird dann sogar eigenständig die Farbverläufe dafür erstellen. Jeder der D3D kennt, wird diese Vorgehensweise bekannt vorkommen und er wird beginnen, verzweifelt nach dem FVF zu suchen, um es korrekt zu definieren... Wenn Ihr einen Vertex zeichnet, so rendert OpenGL diesen automatisch &amp;quot;weiß&amp;quot; (Ah huch! Deswegen ist unser Dreieck auch weiß???). Alles was wir nun machen müssen, ist OpenGL mitzuteilen, dass es eine andere Farbe einsetzen soll. Und zwar wird OpenGL diese Farbe für alle folgenden Eckpunkte nutzen, so lange bis von uns ein anderes Kommando kommt.&lt;br /&gt;
&lt;br /&gt;
Der mysteriöse Befehl, um den ich nun schon die ganze Zeit herumschwafle ist [[glColor|glColor*]]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Alle folgenden Eckpunkte werden rot gefärbt&lt;br /&gt;
glColor3f(1,0,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Wobei jeder Parameter einen Farbwert repräsentiert und zwar nach dem Muster RGB. Es wird ein Wert zwischen 1 und 0 erwartet, wobei eine Eins &amp;quot;volle Farbsättigung&amp;quot; bedeutet. Das heißt in unserem Fall haben wir als Farbe &amp;quot;rot&amp;quot; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Und weil wir schließlich die Welt ein wenig bunter machen und nicht nur das weiße Dreieck rot färben wollten, werden wir nach jedem Eckpunkt eine neue Farbe setzen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1, 0, 0); glVertex3f(-1,-1, 0);  &lt;br /&gt;
  glColor3f(0, 0, 1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0, 1, 0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
Und dies ist dann unser farbenfrohes Ergebnis. Beeindruckend, wenn man bedenkt, wie wenig Aufwand letztendlich dahinter steckt, oder?&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_lektion2_dreieck.gif]]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wer meine Tutorials kennt weiß, dass zum Abschluß noch immer ein wenig Geblubber von mir kommt (man beachte diese entzückende Wortwahl von meiner einer... hoffe, der Lektor findet es auch amüsant...). (Anm. des Lektors: Und wie!) Schauen wir doch mal stolz auf das zurück, was wir heute erreicht haben! Wir haben OpenGL initialisiert, ein erstes Dreieck auf den Bildschirm gezaubert und dieses in den Farbtopf gesteckt! Das solltet Ihr als ein historisches Ereignis ansehen. Als ich damals mit D3D angefangen habe, brauchte ich, um es mir selbst zu erarbeiten, ca. eine Woche (Das ist jetzt der Moment, in dem Ihr Eure Hände heben solltest und ein lautes &amp;quot;Call me God&amp;quot; aus Euch herauskommen sollte, so dass zumindest Eure unmittelbaren Mitmenschen denken, dass Ihr einen Dachschaden habt!!! Das gehört einfach mit dazu ^__- )&lt;br /&gt;
&lt;br /&gt;
Wie immer solltet Ihr Euch nun hinsetzen und Euch ein wenig mit den Parametern vertraut machen. Speziell bei glTranslate* solltet Ihr ein wenig mit den Parametern experimentieren, damit Ihr seht, was es mit den Matrizen auf sich hat und wie diese funktionieren. Wenn Ihr dann auch denkt, dass Ihr damit vertraut seid, versucht ein wenig mit den einzelnen Vertexpositionen zu experimentieren und verändert diese. Wenn auch das klar ist, setzt Euch in die Ecke und warte sehnsüchtig auf mehr von uns :D! (Anm: Die &amp;quot;Ecke&amp;quot; ist nicht die Kneipe nebenan... :)&lt;br /&gt;
&lt;br /&gt;
Im nächsten Kapitel werden wir dann Matrizen-Hardcore machen ... legt also schon mal Euer Aspirin parat, es wird witzig werden *grunz* :).&lt;br /&gt;
&lt;br /&gt;
Und wie immer freuen wir uns sehr über Feedback. Schreibt uns doch einfach ein paar Worte in unser [http://www.delphigl.com/forum/viewforum.php?f=8 Feedback-Forum]. Sagt, was Ihr gut und was hingegen Ihr als schlecht empfunden habt! Auch freuen wir uns immer über Ideen für weitere Tutorials, teilt uns also bitte Eure Ideen mit ;)!&lt;br /&gt;
&lt;br /&gt;
Okay... ich wünsche Euch einen angenehmen Tag / Nacht!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien == &lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_2_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 1]] | [[Tutorial Lektion 3]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion2]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23897</id>
		<title>Datei:wc-vs-mc-beispiel.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23897"/>
				<updated>2009-07-22T18:40:21Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: hat eine neue Version von „Datei:wc-vs-mc-beispiel.png“ hochgeladen: Entgültige Fassung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23896</id>
		<title>Datei:wc-vs-mc-beispiel.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23896"/>
				<updated>2009-07-22T18:38:04Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: hat eine neue Version von „Datei:wc-vs-mc-beispiel.png“ hochgeladen: Zurückgesetzt auf die Version vom 22. Juli 2009, 18:28 Uhr&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23895</id>
		<title>Datei:wc-vs-mc-beispiel.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23895"/>
				<updated>2009-07-22T18:31:44Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: hat eine neue Version von „Datei:wc-vs-mc-beispiel.png“ hochgeladen: Nochmals verbessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23894</id>
		<title>Datei:wc-vs-mc-beispiel.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23894"/>
				<updated>2009-07-22T18:28:42Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: hat eine neue Version von „Datei:wc-vs-mc-beispiel.png“ hochgeladen: Sinn verbessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23893</id>
		<title>Datei:wc-vs-mc-beispiel.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wc-vs-mc-beispiel.png&amp;diff=23893"/>
				<updated>2009-07-22T18:26:53Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Selbstgemacht mit Inkscape&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:weltkoordinatensystem-vs-modellkoordinatensystem.png&amp;diff=23892</id>
		<title>Datei:weltkoordinatensystem-vs-modellkoordinatensystem.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:weltkoordinatensystem-vs-modellkoordinatensystem.png&amp;diff=23892"/>
				<updated>2009-07-22T18:10:01Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Sebstgemacht mit Inkscape&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sebstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23891</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23891"/>
				<updated>2009-07-22T09:12:24Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Verständnisfehler verbessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte World- oder Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Worldmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Worldmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse und das am neuen (verschobenen) Punkt, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23890</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23890"/>
				<updated>2009-07-22T09:10:10Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Fehler in der Rotationsbeschreibung korrigiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte World- oder Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Worldmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Worldmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene y-Achse (0,1,0) gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter die Vektor-Komponenten X,Y,Z beschreiben um den die Rotation durchgeführt werden soll. &lt;br /&gt;
&lt;br /&gt;
Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach für einen Anfänger in der 3D-Programmierung sich vorzustellen wie ein Objekt um die eigene Achse zu rotieren ist.&lt;br /&gt;
&lt;br /&gt;
Doch die Lösung ist ganz einfach, ehrlich! =) .Ruft einfach glRotate* und anschließend glTranslate* auf, so rotiert das Objekt jetzt tatsächlich um die eigene Achse, oooh wie wunderbar... *g*.&lt;br /&gt;
&lt;br /&gt;
ABER! Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so unterscheidet sich das erzielte Ergebnis von dem Vorherigen! Jetzt rotiert das Objekt nämlich nicht um die eigene Achse, sondern auf einer Bahn (einfach gesprochen: &amp;quot;im Kreis halt&amp;quot;) mit der Verschiebung als Radius.&lt;br /&gt;
&lt;br /&gt;
Ein schematisches Beispiel zur Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesem möglichen Problem aus dem Weg zu gehen solltet Ihr Euch vorstellen, dass wenn Ihr das Objekt um seine Rotationsgerade (Achse) rotieren lassen wollt (also das Objekt an seinem Platz drehen lassen), dass Ihr die Rotationgerade im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr euer Objekt jetzt, so verschiebt Ihr die Rotationsgerade auch MIT an den neuen Punkt. Im allgemeinen gilt: Die Rotation um die eigene Achse ist ein Ausnahmefall, denn die Rotationsgerade liegt in diesem Fall direkt im, oder sehr nahe an dem, zu rotierenden Objekt.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23889</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23889"/>
				<updated>2009-07-22T06:55:42Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Dreh- und Angelpunkt des Geschehens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte World- oder Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Worldmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Worldmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene Achse gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter den Vektor beschreiben um den die Rotation durchgeführt werden soll. Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach ein Objekt um die Eigene Achse zu rotieren. Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so rotiert das Objekt um die eigene Achse.&lt;br /&gt;
&lt;br /&gt;
Ruft Ihr jedoch zuerst glRotate* und anschließend glTranslate* auf, so unterscheidet sich erzielte Ergebnis von dem vorherigen, ein schematisches Beispiel:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesen Problemen aus dem Weg zu gehen so müsst Ihr Euch vorstellen, dass Ihr den Rotationspunkt im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr Euer Objekt anschließend so bleibt der Rotationspunkt derselbe und das Objekt beginnt den Rotationspunkt auf einer Bahn zu umkreisen. So gesehen gibt es keinen wirklichen Unterschied und die Rotation um die eigene Achse ist ein Ausnahmefall, denn der Rotationspunkt liegt dann in dem von uns erwarteten Mittelpunkt des Objektes.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23888</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23888"/>
				<updated>2009-07-22T06:53:19Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Bild zum Vergleich Translation/Rotation zugefügt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte World- oder Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Worldmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Worldmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene Achse gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter den Vektor beschreiben um den die Rotation durchgeführt werden soll. Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach ein Objekt um die Eigene Achse zu rotieren. Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so rotiert das Objekt um die eigene Achse.&lt;br /&gt;
&lt;br /&gt;
Ruft Ihr jedoch zuerst glRotate* und anschließend glTranslate* auf, so unterscheidet sich erzielte Ergebnis von dem vorherigen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Um diesen Problemen aus dem Weg zu gehen so müsst Ihr Euch vorstellen, dass Ihr den Rotationspunkt im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr Euer Objekt anschließend so bleibt der Rotationspunkt derselbe und das Objekt beginnt den Rotationspunkt auf einer Bahn zu umkreisen. So gesehen gibt es keinen wirklichen Unterschied und die Rotation um die eigene Achse ist ein Ausnahmefall, denn der Rotationspunkt liegt dann in dem von uns erwarteten Mittelpunkt des Objektes.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23887</id>
		<title>Datei:translation-vs-rotation.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23887"/>
				<updated>2009-07-22T06:51:35Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: hat eine neue Version von „Datei:translation-vs-rotation.png“ hochgeladen: schärfer gemacht&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23886</id>
		<title>Datei:translation-vs-rotation.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23886"/>
				<updated>2009-07-22T06:48:53Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: hat eine neue Version von „Datei:translation-vs-rotation.png“ hochgeladen: kleiner gemacht&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23885</id>
		<title>Datei:translation-vs-rotation.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:translation-vs-rotation.png&amp;diff=23885"/>
				<updated>2009-07-22T06:47:29Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Selbstgemacht mit Inkscape&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selbstgemacht mit Inkscape&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23883</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23883"/>
				<updated>2009-07-22T05:07:39Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* D3D-Verrat */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte World- oder Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Worldmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Worldmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modellmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modellmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene Achse gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter den Vektor beschreiben um den die Rotation durchgeführt werden soll. Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach ein Objekt um die Eigene Achse zu rotieren. Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so rotiert das Objekt um die eigene Achse.&lt;br /&gt;
&lt;br /&gt;
Ruft Ihr jedoch zuerst glRotate* und anschließend glTranslate* auf, so unterscheidet sich erzielte Ergebnis von dem vorherigen.&lt;br /&gt;
&lt;br /&gt;
Um diesen Problemen aus dem Weg zu gehen so müsst Ihr Euch vorstellen, dass Ihr den Rotationspunkt im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr Euer Objekt anschließend so bleibt der Rotationspunkt derselbe und das Objekt beginnt den Rotationspunkt auf einer Bahn zu umkreisen. So gesehen gibt es keinen wirklichen Unterschied und die Rotation um die eigene Achse ist ein Ausnahmefall, denn der Rotationspunkt liegt dann in dem von uns erwarteten Mittelpunkt des Objektes.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23882</id>
		<title>Tutorial Lektion 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_3&amp;diff=23882"/>
				<updated>2009-07-22T05:05:21Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: Es gibt keine Worldmatrix nur ein Worldkoordinatensystem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eine Welt des Grauens =&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Liebe Leser,&lt;br /&gt;
nachdem Ihr hoffentlich den kleinen Schock des letzten Tutorials alle gut überstanden habt, freue ich mich, Euch hier wieder begrüßen zu können. Wer dachte, dass die letzte Lektion bereits schwer war, der sollte dringend Urlaub nehmen. Seid gewarnt! Bevor ich jetzt richtig loslege, solltet Ihr einigermaßen entspannt sein. Wenn dies einer der Tage ist, an denen Ihr nur noch durch eine Kippe oder die Flasche Coke am Leben gehalten werdet, ordne ich erstmal eine kleine Zwangspause an ;).&lt;br /&gt;
&lt;br /&gt;
Der Stoff der jetzt kommt ist sicherlich nicht gerade die leichteste Lektüre. Wer Mathematik studiert, hat Vorteile, wer einigermaßen logisch denken kann auch. Ein Fachidiot, wie ich, hat nur eine Chance... probieren, testen und lernen :). Und weil ich weiß, wie schwer es eventuell sein kann, werde ich nun einfach mal versuchen, ganz simpel anzufangen und das Ganze mit vielen Bildern so gut wie nur irgend möglich zu illustrieren. &lt;br /&gt;
&lt;br /&gt;
Und wenn Ihr nun Angst habt, dass Ihr das nicht packt, weil ich hier so eine Panik verbreite, dann solltet Ihr mich sehen, wie ich hier verzweifelt vor meinen Tasten hänge und mich frage, wie ich das alles bloß in Worte fassen soll :). Aber was soll es? Ran an den Kram!!! Heulen könnt Ihr anschließend im Forum ;).&lt;br /&gt;
&lt;br /&gt;
== Das Grauen hat einen Namen ==&lt;br /&gt;
=== &amp;quot;Kinofilm&amp;quot; vs. &amp;quot;Bahnhof&amp;quot; ===&lt;br /&gt;
Wer kennt nicht &amp;quot;Matrix&amp;quot; und hätte gedacht, dass es davon nicht nur eine, sondern unendlich viele gibt die so genannten &amp;quot;Matrizen&amp;quot;. Vor allem am Anfang werden diese Dinger Euch das Leben erschweren und Ihr werdet leichte Neigungen tief in Euch verspüren, dass am besten Euer ganzes Projekt sich nur im Zentrum Eurer Welt abspielt (und dies ist nicht im wahrsten Sinne des Wortes gemeint).&lt;br /&gt;
&lt;br /&gt;
Wer mit Matrizen umgehen kann, beherrscht das Wichtigste an der 3D-Programmierung. Wer nicht zu den Genies zählt, sollte nicht sofort aufgeben, sondern sich viele Beispiele ansehen und viel mit diesen herumspielen.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer... Ihr solltest wissen, dass es bei jedem Rendervorgang mehrere Matrizen gibt, die ganz drastisch das Aussehen der Szene bestimmen. Es gibt in OpenGL drei Bereiche, in denen Matrizen eingesetzt werden. Die so genannte World- oder Modelviewmatrix, die Texturenmatrix und die Perspektivenmatrix. Die zweifellos wichtigste dieser Matrizen ist die Worldmatrix, da sie die Position Eures &amp;quot;Zeichenstiftes&amp;quot; beschreibt und somit Objekte positioniert. Die Texturenmatrix funktioniert fast genauso wie die Worldmatrix nur definiert sie die Ausrichtung der Texturen. Wir werden später auf sie zurückkommen. Die Perspektivenmatrix definiert wesentliche Eigenschaften des Blickfeldes des Betrachters.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMatrixMode]] erlaubt eine Änderung der aktuellen Matrix. Mit Hilfe der Konstanten GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION kann man die Matrix bestimmen. Die Namen der Konstanten sind soweit hoffentlich selbst erklärend. Von nun an bewirken alle Matrixoperationen wie beispielsweise [[glLoadIdentity]] oder [[glTranslate|glTranslate*]] eine Veränderung der aktuell gesetzten Matrix.&lt;br /&gt;
&lt;br /&gt;
=== Die Perspektivenmatrix ===&lt;br /&gt;
Wie bereits erwähnt beschreibt die Perspektivenmatrix das aktuelle Sichtfeld. Zum Setzen der Perspektivenmatrix verwendet man in der Regel Befehle wie [[glFrustum]], [[gluPerspective]], [[glOrtho]] oder [[gluOrtho2D]].&lt;br /&gt;
&lt;br /&gt;
gluPerspective lässt den Raum beispielsweise dreidimensional erscheinen, indem sich die Größe von Objekten mit zunehmender Entfernung vom Betrachter verringert. Diese Verringerung ist abhängig von dem im ersten Parameter übergebenen Winkel. &lt;br /&gt;
&lt;br /&gt;
glOrtho hingegen ist phantastisch für ein 2D-Blickfeld geeignet, denn diese Art der Projektion enthält keine Tiefe mehr.&lt;br /&gt;
&lt;br /&gt;
Genauere Informationen zu den einzelnen Funktionen könnt ihr unserem OpenGL-Wiki entnehmen.&lt;br /&gt;
&lt;br /&gt;
Auf eine Sache möchte ich jedoch noch eingehen: Einige dieser Funktionen verlangen die Parameter &amp;quot;znear&amp;quot; und &amp;quot;zfar&amp;quot;. Diese Parameter beschreiben die zwei Schnittflächen, die das Blickfeld vor dem Betrachter begrenzen. &amp;quot;znear&amp;quot; definiert die Entfernung der Nearclippingplane vom Betrachter. Alle Objekte, die sich vor dieser Ebene befinden sind nicht sichtbar. &amp;quot;zfar&amp;quot; beschreibt die Entfernung der Farclippingplane vom Betrachter. Alle Objekte, die sich hinter dieser befinden werden weggeschnitten. Wenn also wieder einmal nur die Hälfte Eurer Szene auf dem Bildschirm sichtbar ist, versucht die Schnittflächen entsprechend anzupassen!&lt;br /&gt;
&lt;br /&gt;
== Die Worldmatrix ==&lt;br /&gt;
=== D3D-Verrat ===&lt;br /&gt;
Wenn Ihr ebenfalls zu den D3D-Verrätern gehört (wie z.&amp;amp;nbsp;B. ich *g*), dann solltet Ihr Euch möglichst von eurer Denkweise trennen: Jede Positionierung der Kamera erfolgt über ein Drehen und Bewegen der Szene. Das ist vor allem am Anfang ein wenig gewöhnungsbedürftig (&amp;quot;Die Welt dreht sich! Nicht Du!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Vielmehr wird jede Manipulation direkt an die Modelmatrix übergeben. Das heißt, wenn Ihr glTranslate* aufruft, so ist diese Manipulation bereits bei Euch in die Modelmatrix eingetragen, alle weiteren Objekte werden mit dieser Matrix transformiert. Wer zweimal glTranslate*(2, 0, 0) aufruft wird feststellen, dass glTranslate* nicht zwei Matrizen zurückliefert, sondern nur eine, die dann auf (4, 0, 0) verweist. Am Anfang solltet Ihr also sehr darauf achten, es wird eine Weile dauern bis Ihr dies fest in Eurem Herzen tragt. Nicht sofort aufgeben :)!&lt;br /&gt;
&lt;br /&gt;
== Einfach, Kompakt und Funktional ==&lt;br /&gt;
Neben dem Befehl glTranslate*, den wir im letzten Tutorial lieben gelernt haben, gibt es noch weitere Befehle, die sich auf die einzelnen Matrizen auswirken und auf die ich in dem folgenden Abschnitt eingehen möchte.&lt;br /&gt;
&lt;br /&gt;
=== Dreh- und Angelpunkt des Geschehens ===&lt;br /&gt;
Zunächst beschäftigen wir uns mit der Rotation. Wir versuchen ein Objekt zu erzeugen, welches um 90° um seine eigene Achse gedreht wurde. Das ist nicht sonderlich schwer: &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(90,0,1,0);&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein Objekt auf das wir diese Matrix anwenden, wird um 90° um seine Y-Achse gedreht sein. Daraus schließen wir, dass der erste Parameter den Winkel im Gradmaß um den wir rotieren möchten definiert und die 3 folgenden Parameter den Vektor beschreiben um den die Rotation durchgeführt werden soll. Rotationen bergen tatsächlich eine Schwierigkeit, denn es ist nicht immer einfach ein Objekt um die Eigene Achse zu rotieren. Verschiebt Ihr euer Objekt zuerst und beginnt dann die Rotation, so rotiert das Objekt um die eigene Achse.&lt;br /&gt;
&lt;br /&gt;
Ruft Ihr jedoch zuerst glRotate* und anschließend glTranslate* auf, so unterscheidet sich erzielte Ergebnis von dem vorherigen.&lt;br /&gt;
&lt;br /&gt;
Um diesen Problemen aus dem Weg zu gehen so müsst Ihr Euch vorstellen, dass Ihr den Rotationspunkt im Moment des Aufrufs von glRotate* setzt. Verschiebt Ihr Euer Objekt anschließend so bleibt der Rotationspunkt derselbe und das Objekt beginnt den Rotationspunkt auf einer Bahn zu umkreisen. So gesehen gibt es keinen wirklichen Unterschied und die Rotation um die eigene Achse ist ein Ausnahmefall, denn der Rotationspunkt liegt dann in dem von uns erwarteten Mittelpunkt des Objektes.&lt;br /&gt;
&lt;br /&gt;
=== Eine Frage der Größe ===&lt;br /&gt;
Nun ja... was kann man denn noch alles in einer 3D-Welt machen? Ihr habt gelernt, wie man Objekte bewegt und diese durch Rotationen ausrichten kann. Das ist doch schon eine Menge zum Spielen oder? Nun, bei einer Transformation kann für uns noch eine Sache sehr wichtig werden, nämlich die Möglichkeit, zu bestimmen in welcher Größe ein Objekt dargestellt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sicher würde es Sinn machen ein benötigtes Objekt gleich in der richtigen Größe in die Anwendung zu laden. Manchmal ist es aber von Vorteil, wenn man die Größe eines Objektes ohne großen Aufwand verändern kann oder aber mehrere Objekte desselben Typs mit unterschiedlicher Größe darzustellen.&lt;br /&gt;
&lt;br /&gt;
Eine Größenveränderung ist mit Hilfe des Befehls [[glScale|glScale*]] möglich.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(1,1,1);&amp;lt;/source&amp;gt;&lt;br /&gt;
In diesem Fall würden wir das Objekt so zeichnen, wie wir es auch angegeben haben. Das heißt in seiner Originalgröße. Sicherlich ahnst Du bereits, was die Parameter aussagen... sie stehen für das Verhältnis der einzelnen Seiten nach dem Muster X, Y und Z. Würden wir als ersten Parameter statt einer 1 eine 2 einsetzen, würde unser Objekt in seiner räumlichen Ausdehnung bezogen auf der X-Achse doppelt so groß sein. Würden wir stattdessen 0.5 angeben, wäre es nur noch halb so groß.&lt;br /&gt;
&lt;br /&gt;
In Wirklichkeit bewirkt glScale* jedoch keine Veränderung der Größe sondern eine Verzerrung unseres Koordinatensystems. Daher wirkt jeder Aufruf von glScale* auch auf Befehle wie glTranslate*. Aus Sicht der Matrizen lässt sich dieses Phänomen auch recht leicht erklären. In Wirklichkeit erzeugt jeder Aufruf von glRotate*, glTranslate* oder glScale* eine eigene Matrix, die dann mit der aktuellen Matrix (z.B. der Modelviewmatrix) multipliziert wird. Wurde in der Modelviewmatrix bereits ein glScale* verewigt, so wirkt sich dieses bei der Multiplikation der Matrizen auf die Transformationsmatrix aus.&lt;br /&gt;
&lt;br /&gt;
Ich denke ich muss nicht näher darauf eingehen, dass es keine gute Idee ist das Koordinatensystem mit einem Aufruf von glScalef(0, 0, 0) zu zerstören. Was würde es auch für einen Sinn ergeben, das Koordinatensystem in einem Punkt unterzubringen? &amp;lt;br&amp;gt;&lt;br /&gt;
'''''Hinweis''': Es ist bereits gefährlich nur eine Achse auf 0 zu skalieren, denn dadurch wird die aktuelle Matrix beschädigt ([http://www.math.unizh.ch/fachverein/forum/detail.jsp?FORUM=120 singulär]) und Befehle wie [[gluProject]] und [[gluUnProject]] funktionieren nicht mehr.''&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ich habe Euch nun nicht den letzten Funken Hoffnung OpenGL zu verstehen geraubt. Ich kann Euch versichern, dass dieses Verständnis mit der Zeit heranreifen wird.&lt;br /&gt;
[[bild:Tutimg_lektion3_skalierung.gif|256px|right]]&lt;br /&gt;
glScale* ist aber aufgrund seiner phantastischen Eigenschaften nicht nur in der Lage die Größe von Objekten zu verändern sondern es ist auch möglich Objekte zu spiegeln indem man negative Werte an glScale* übergibt. Somit kann sich z.&amp;amp;nbsp;B. ein D3D-Umsteiger das leben vereinfachen indem er mit einem Aufruf von glScalef(1, 1, -1) sicherstellt, dass die Z-Achse in den Bildschirm hinein positiv verläuft.&lt;br /&gt;
&lt;br /&gt;
Jeder, der die Funktion der Modelviewmatrix begreifen möchte, dem möchte ich das Programm Matrixcontrol von Lithander (siehe Anhang) ans Herz legen. Es erlaubt Euch bestimmte Änderungen an der Matrix direkt nachzuvollziehen und wenn man mit dem Programm ein wenig umherspielt wird selbst dem letzten ziemlich schnell ein Licht aufgehen. Wenn nicht, dann hilft nur fleißiges Programmieren und Anwenden und irgendwann klatscht es dann laut, wenn die eigene Handfläche auf der Stirn zum stehen kommt ;).&lt;br /&gt;
&lt;br /&gt;
== Virtuelle Gedächtnisse ==&lt;br /&gt;
=== Vom Pushen und Poppen ===&lt;br /&gt;
Wer diesen Titel ließt und sich nun zwangsläufig daran erinnert, was er bereits alles in seinem Leben konsumiert hat oder neben wem er am nächsten Morgen aufgewacht ist, sei entwarnt! Wir reden hier von etwas ganz anderem...&lt;br /&gt;
&lt;br /&gt;
Wie wir bereits gelernt haben, verändert jeder Aufruf von glTranslate*, glRotate* oder glScale* die Worldmatrix und wirkt sich unmittelbar auf andere Objekte aus. Dies kann durchaus sehr erwünscht sein. Wenn wir allerdings in einer großen Welt verschiedene Objekte positionieren, kann dies schnell zum Fluch werden. Natürlich können wir dem entgegenwirken und zum Beispiel jedes Mal glLoadIdentity aufrufen. Dies hat jedoch den Nachteil, dass die World- Matrix dann eben wieder leer ist und wir z.B. die Camera erst wieder setzen müssen, damit die Objekte an die richtige Stelle transformiert werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitaus elegantere Lösung ist die Verwendung des &amp;quot;Matrixstacks&amp;quot;! Jeder Aufruf von [[glPushMatrix]] bewirkt, dass die momentane Matrix auf den [[Stack]] geschrieben wird. Alle Manipulationen, die wir dann durchführen, werden wie gewohnt vollzogen. Ist alles gezeichnet, rufen wir mit [[glPopMatrix]], die letzte Matrix vom Stack wieder herunter und haben im Prinzip den letzten Zustand vor unseren Veränderungen rekonstruiert und können dann wieder anfangen, auf dieser Matrix aufzubauen. Natürlich lassen sich auch mehre Matrizen auf den Stack pushen! Dies kann reichlich Zeit sparen, wenn man bedenkt, dass man ansonsten andauernd die Matrix der Szene neu setzen muss.&lt;br /&gt;
&lt;br /&gt;
Um das ganze etwas anschaulicher zu machen, verwenden wir ein einfaches Beispiel. Wir werden zwei Dreiecke jeweils rechts und links vom Ursprung zeichnen. Nachdem wir das linke Objekt gezeichnet haben, werden wir nicht glLoadIdentity einsetzen oder das zweite Objekt entsprechend nach rechts transformieren, sondern eben den Matrixstack zu Hilfe nehmen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glLoadIdentity();&lt;br /&gt;
glTranslatef(0,0,-10);&lt;br /&gt;
glPushMatrix();&lt;br /&gt;
  glTranslatef(-2,0,0);&lt;br /&gt;
  glBegin(GL_TRIANGLES);&lt;br /&gt;
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
  glEnd();&lt;br /&gt;
glPopMatrix();&lt;br /&gt;
&lt;br /&gt;
glTranslatef(2,0,0);&lt;br /&gt;
glBegin(GL_TRIANGLES);&lt;br /&gt;
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);&lt;br /&gt;
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);&lt;br /&gt;
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);&lt;br /&gt;
glEnd();&amp;lt;/source&amp;gt;&lt;br /&gt;
Wie Ihr seht, setzen wir am Anfang praktisch die Distanz zum Objekt, speichern die Matrix und zeichnen das erste Objekt. Wir setzen dann die Matrix wieder zurück, so dass sie nur noch den Aufruf von glTranslatef(0, 0, -10) beschreibt und transformieren das zweite Objekt... fertig. Man kann auch ohne diese Matrixstacks leben sie können einem aber das Leben auch sehr erleichtern.&lt;br /&gt;
&lt;br /&gt;
== I wanna all! ==&lt;br /&gt;
Wer glaubt, dass es das bereits war der irrt. Es gibt noch weitere Möglichkeiten auf die Matrix Einfluss zu nehmen. Der Befehl [[glLoadMatrix|glLoadMatrix*]] erlaubt es eine beliebige 4x4 Matrix zu laden und die aktuelle Matrix durch die geladene komplett zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glMultMatrix|glMultMatrix*]] multipliziert die übergebene 4x4-Matrix mit der aktuellen Matrix. Mit diesem Befehl könnte man beispielsweise eigene glScale*- und glRotate*-Befehle schreiben, obgleich sich auch hier über den Sinn streiten lässt. Eine sinnvollere Anwendungsmöglichkeit wird in einem späteren Tutorial vorgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Der Befehl [[glGet|glGet*]] mit den Tokens GL_MODELVIEW_MATRIX, GL_TEXTURE_MATRIX und GL_PROJECTION_MATRIX ermöglicht euch die einzelnen Matrizen anzufordern.&lt;br /&gt;
&lt;br /&gt;
== Weltenformeln ==&lt;br /&gt;
=== Hier kommt die Sonne... ===&lt;br /&gt;
Genug der Theorie! Es wird langsam Zeit für etwas Praxis...&lt;br /&gt;
&lt;br /&gt;
Nun, um ehrlich zu sein, habe ich an der folgenden Idee ein wenig Zeit benötigt, um ein einigermaßen gut anschauliches Beispiel zu finden... ich will hier nicht weiter darauf eingehen, was ich gerade gehört habe, als mir die Sonne aufging :-D.&lt;br /&gt;
&lt;br /&gt;
Wie auch immer, man kann komplexere Matrixtransformationen sehr leicht mit unseren Sonnensystem beschreiben (Hey, wenn jetzt jemand denkt, dass ich spinne...). Um das Ganze etwas übersichtlicher zu gestalten, werden wir unser Prinzip auf Sonne, Mond und Erde beschränken.&lt;br /&gt;
&lt;br /&gt;
Wie funktioniert unser Sonnensystem? (Warnung, der Autor betritt mal wieder seine ausgeprägte Fantasywelt! [Anm. d. Lektors: Die richtige Sprache dafür hat er ja schon]).&lt;br /&gt;
&lt;br /&gt;
Die Sonne steht im Mittelpunkt und sollte sich in unserem Beispiel nicht selbst bewegen. Sie ist einfach nur im Mittelpunkt und vegetiert dort vor sich hin! Nun gibt es einen kleinen blauen Planeten, namens Erde (wieso er im Sample ein Dreieck ist, sei Eurer Kreativität überlassen...), der zum einen um seine eigene Achse rotiert, viel wichtiger jedoch, sich auch noch um die Sonne dreht. Nun werden sich vor allem die Neulinge unter Euch sadistisch freuen, das Fenster schließen, ihr Delphi starten und drauf los proggen! Das ist doch alles kein Ding, der gerade mal frisch aufgeschnappte Sinus-Satz lässt sich prima mit einbringen! Und schon berechnet man mit Hilfe von Sinus, die Position auf der Kreisbahn und positioniert den Planeten mit glTranslate* an seine Position. Und oh Wunder es klappt. HALT! Wer es nicht gemerkt hat, da war ne Portion Ironie dabei. Bitte Weiterlesen ^__^!&lt;br /&gt;
&lt;br /&gt;
Denn spätestens wenn wir folgende Ergänzung zum Besten geben, werden die ersten Augen wässrig werden, weil die meisten Hirne einem Informationskoller unterliegen. Meines stieg ja schon beim einfachen Sinus aus :-D. Ab und an kann man nämlich nachts weißgräuliche Flecken am Himmel beobachten! Wer annimmt, dass es sich hierbei um eine geschickt platzierte, in Echtzeit berechnete, Textur handelt, ist schief gewickelt! Es handelt sich dabei nämlich um ein Decal, namens Mond. Oha... so schlimm war es schon lange nicht mehr. Dieser bewegt sich in unserem Beispiel auch nicht entlang der Erdachse, sondern auf einer schiefen Bahn, damit man auf der unteren Hemissphäre den Mond auch am Tage noch sehen kann ^___^ (*selbstgefälliges, göttliches Grinsen*). Dies lässt sich nur sehr schwer mit Sinus beschreiben. Bevor wir uns nun jedoch mit einem Block bewaffnen oder den nächsten Mathematik-Professor entführen, damit er die Mathematik für uns übernimmt, greifen wir lieber zu den Sternen und nehmen ein einfacheres Verfahren! Les Matrices!&lt;br /&gt;
&lt;br /&gt;
=== Und es dreht sich doch! ===&lt;br /&gt;
Die Vorgehensweise ist eigentlich relativ simpel. Wir Zeichnen unsere Sonne im Mittelpunkt unseres Universums. Mit dem Aufruf von glRotate* setzen wir den Rotationspunkt an die Position unseres &amp;quot;Zeichenstiftes&amp;quot;. In unserem Fall ist das noch immer die Position der Sonne. &lt;br /&gt;
&lt;br /&gt;
Nun verschieben wir die Erde nach links und die erste Hürde ist genommen. Jetzt müssen wir nur noch den Mond setzen und das funktioniert genauso einfach wie zuvor mit der Erde.&lt;br /&gt;
&lt;br /&gt;
Unser Zeichenstift befindet sich nun an der Position der Erde und daher rufen wir glRotate* auf. Nun müssen wir den Zeichenstift nur noch ein kleines Stück neben der Erde positionieren und den Mond zeichnen. Voila! Es ist vollbracht!&lt;br /&gt;
&lt;br /&gt;
Wenn man genauer darüber nachdenkt erkennt man sehr schnell wie elegant man dieses verhältnismäßig komplizierte Problem gelöst hat.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf Wolke Sieben schwebt und glaubt er könnte sich nun an den nächsten DOOMTitel werfen, der sollte das Programm zuvor noch so erweitern, dass die Sonne, die Erde und auch der Mond sich zusätzlich um die eigene Achse drehen.&lt;br /&gt;
&lt;br /&gt;
== [[Timebased Movement]] ==&lt;br /&gt;
Wer bereits versucht hat eines der ersten selbst geschriebenen OpenGL-Programme voller Stolz seinem Kumpel vorzuführen wird festgestellt haben, dass die Bewegungen auf dem anderen Rechner schneller oder langsamer abgelaufen sind als es auf dem eigenen Rechner der Fall war.&lt;br /&gt;
&lt;br /&gt;
Dieses Phänomen lässt sich sehr einfach erklären. Nehmen wir an wir bewegen ein Dreieck von links nach rechts um den Wert 1 über den Bildschirm. Eine alte Krücke wie mein PC schafft vielleicht 50 FPS. Das bedeutet das Objekt wird in einer Sekunde genau 50mal um eine Einheit nach rechts verschoben. Das bedeutet insgesamt also um 50 Einheiten in einer Sekunde. Wenn das Programm nun aber auf einem High-End-System läuft werden wir die Szene... sagen wir... 500mal aktualisieren können. Folglich bewegt sich auf diesem Rechner das Dreieck in einer Sekunde um 500 Einheiten.&lt;br /&gt;
&lt;br /&gt;
Das einzige was wir von unserem Dreieck erhaschen können ist ein blitzartiges Zucken auf dem Bildschirm, welches wir schnell als optische Täuschung abtun würden. Wie kann man diesem Problem nun aber entgegen wirken?&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir kennen die Zeit, die wir zum Zeichnen eines Frames benötigen und ermitteln anhand dieses Wertes einen Zeitfaktor, den wir in die Bewegung mit einfließen lassen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;NewPosition := OldPosition + Movement * TimeFactor;&amp;lt;/source&amp;gt;&lt;br /&gt;
Handelt es sich um einen schnellen Rechner so ist der Zeitfaktor entsprechend niedrig und die Bewegung pro Frame verringert sich. Ist der Rechner hingegen langsam so besitzen wir einen hohen Zeitfaktor. Folglich legt das Dreieck auf dem schnelleren Rechner pro Frame weniger Weg zurück als auf dem langsamen. Insgesamt jedoch legen die beiden Dreiecke im gleichen Zeitabstand (z.&amp;amp;nbsp;B. in einer Sekunde) denselben Weg zurück.&lt;br /&gt;
&lt;br /&gt;
Um den Zeitfaktor zu ermitteln muss man lediglich die Zeit für einen Schleifendurchlauf ermitteln. Um eine möglichst hohe Genauigkeit zu erhalten sollte man die Zeit für den letzten Schleifendurchlauf ermitteln und im aktuellen Schleifendurchlauf verwenden.&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Wow... und wieder ein wenig Zeit zum Ausspannen und ein paar persönlichen Worten. Ich kann getrost nur eines sagen: Wenn Ihr nun denkt &amp;quot;das war alles ja sehr leicht&amp;quot; habt Ihr irgendetwas falsch gemacht und solltet das Tutorial noch einmal von Vorn durcharbeiten ;). Wenn Ihr jedoch leichte Kopfschmerzen verspürt (ob es nun die Matrizen sind oder der fiese Elementarbereich *sg*...) so habt Ihr alles richtig gemacht ;).&lt;br /&gt;
&lt;br /&gt;
Matrizen sind vor allem vielen Einsteigern sehr fremd. &amp;quot;Übung macht den Meister&amp;quot;. Versucht Euch doch einfach mal die eine oder andere Aufgabe selbst zu stellen oder unser &amp;quot;Sonnensystem&amp;quot; selbst einmal nachzuschreiben. Wenn Ihr glaubt, dass das Ganze ganz nett geworden ist, dann schickt es mir doch einfach mal zu. Ich freue mich immer darüber zu sehen, was für Früchte meine Tutorials tragen. *lach* Und wenn sich plötzlich alles um die Erde dreht, dann habe ich a) das Gefühl, dass die Kenntnisse über das Sonnensystem nicht mehr ganz up to date sind oder b) ich einen ziemlich fatalen Fehler beim Erklären gemacht habe :-&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Schreckt auch bitte nicht davor zurück, eine Frage diesbezüglich im Forum zu stellen. Es ist keine Schande, mit einer Matrix Probleme zu haben und vor allem die Erfahrenen unter uns, sollten nur zu gut wissen, was alles die Ursache dafür sein kann, wenn man plötzlich gar nichts mehr auf dem Screen sieht :). &lt;br /&gt;
&lt;br /&gt;
Das [[Tutorial Matrix2]] behandelt das Thema Matrizen, und vor allem wie man Sachen in OpenGL positioniert, noch genauer.&lt;br /&gt;
&lt;br /&gt;
Wir selbst werden uns in den folgenden Kapiteln noch etwas intensiver mit den Matrizen beschäftigen und unter anderem die eine oder andere interessante Spielerei zeigen!&lt;br /&gt;
&lt;br /&gt;
'''Euer'''&amp;lt;br&amp;gt;&lt;br /&gt;
'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* Der aktuellste Beispiel-Quelltext befindet sich im DGLSDK 2006.1 für {{ArchivLink|file=dglsdk_win32_2006_1‎‎|text=Windows}} und {{ArchivLink|file=dglsdk_linux_2006_1|text=Linux}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_api|text=Alter Delphi-API-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_delphi_vcl|text=Alter Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_lektion_3_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
* [http://www.pixelpracht.net Pixelpracht] -  Hier könnt Ihr das Programm &amp;quot;Matrix Control&amp;quot; finden&lt;br /&gt;
* [http://www.phobeus.de/hosting/shared/pixelpracht/downloads/mc_v02.zip Matrix Control]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 2]] | [[Tutorial Lektion 4]]}}&lt;br /&gt;
[[Kategorie:Tutorial|Lektion3]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23881</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23881"/>
				<updated>2009-07-22T04:49:42Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Um den Ursprung drehen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen auf der x/y-Ebene), bei entfernter Betrachtung, selbst wieder einen Kreis (hier blau gezeichnet) beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-). Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]] &lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
[Nico Michaelis]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23880</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23880"/>
				<updated>2009-07-22T04:31:12Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Trigonometrie am rechtwinkligen Dreieck */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen auf der x/y-Ebene), bei entfernter Betrachtung, selbst wieder einen Kreis (hier blau gezeichnet) beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-). Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]] &lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
[Nico Michaelis]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23879</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23879"/>
				<updated>2009-07-22T04:30:09Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Trigonometrie am rechtwinkligen Dreieck */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen auf der x/y-Ebene), bei entfernter Betrachtung, selbst wieder einen Kreis beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-). Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]] &lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
[Nico Michaelis]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23855</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23855"/>
				<updated>2009-07-17T01:53:55Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Drehen um die Z-Achse */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen um die x- oder y-Achse), bei entfernter Betrachtung, selbst wieder einen Kreis beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-). Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]] &lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
[Nico Michaelis]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23854</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23854"/>
				<updated>2009-07-16T20:17:26Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Welten verschieben */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen um die x- oder y-Achse), bei entfernter Betrachtung, selbst wieder einen Kreis beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung, wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-) Es folgt die vorletze Spalte der Matrix (sie entspricht dem gerade bestimmten Vektor): (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem zu bewältigem haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist die X-Achse:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]] &lt;br /&gt;
| &lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
[Nico Michaelis]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23853</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23853"/>
				<updated>2009-07-16T20:14:33Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Anwendung der Matrix auf einen Vektor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen um die x- oder y-Achse), bei entfernter Betrachtung, selbst wieder einen Kreis beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix antstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung, wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-) Es folgt die vorletze Spalte der Matrix (sie entspricht dem gerade bestimmten Vektor): (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem zu bewältigem haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist die X-Achse:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]] &lt;br /&gt;
| &lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
[Nico Michaelis]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23852</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23852"/>
				<updated>2009-07-16T20:14:05Z</updated>
		
		<summary type="html">&lt;p&gt;DeepCopy: /* Anwendung der Matrix auf einen Vektor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
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 Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
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. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen um die x- oder y-Achse), bei entfernter Betrachtung, selbst wieder einen Kreis beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu entsprechend&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix antstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, 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:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung, wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-) Es folgt die vorletze Spalte der Matrix (sie entspricht dem gerade bestimmten Vektor): (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem zu bewältigem haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist die X-Achse:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]] &lt;br /&gt;
| &lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber 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. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
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 solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
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 [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
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, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
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 ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
[Nico Michaelis]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>DeepCopy</name></author>	</entry>

	</feed>