<?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=Wilson</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=Wilson"/>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php/Spezial:Beitr%C3%A4ge/Wilson"/>
		<updated>2026-05-13T20:40:57Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL-Chat&amp;diff=24693</id>
		<title>DGL-Chat</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL-Chat&amp;diff=24693"/>
				<updated>2010-02-09T19:07:58Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Änderung 24692 von Wilson (Diskussion) wurde rückgängig gemacht.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DelphiGL-Chat =&lt;br /&gt;
&lt;br /&gt;
Die DGL Community bietet neben der Website, dem Forum und dem Wiki auch ein interaktiven Chat über IRC an.&lt;br /&gt;
Den Chat findet man im [http://www.euirc.net/de/ euIRCnet] unter '''#delphigl'''.&lt;br /&gt;
In diesen Artikel erfahren Sie, welche Clients es gibt und wie man in diesen Chatroom hinein kommt.&lt;br /&gt;
&lt;br /&gt;
== IRC Chat Client ==&lt;br /&gt;
IRC Clients gibt es wie Sand am Meer aber dementsprechend sind auch die Unterschiede.&lt;br /&gt;
Da es sich um einen einfachen Zugang handeln soll, ist ein IRC Chatprogram am geeignesten.&lt;br /&gt;
Ein Java Applet (wie es z.B. DelphiGL.com unter [http://chat.delphigl.com/ http://chat.delphigl.com/] zur Verfügung stellt) oder ein Webserver basierter Chat sind langsamer und bieten nicht den Funktionsumfang.&lt;br /&gt;
&lt;br /&gt;
Unter Windows:&lt;br /&gt;
*[http://www.xchat.org/ XChat]&lt;br /&gt;
*[http://www.trillian-messenger.de/ Trillian]&lt;br /&gt;
*[http://www.mirc.de/default.php mIRC]&lt;br /&gt;
*[http://www.miranda-im.org/ Miranda]&lt;br /&gt;
*[http://www.hydrairc.com/ HydraIRC]&lt;br /&gt;
*[http://www.pidgin.im/ Pidgin]&lt;br /&gt;
&lt;br /&gt;
Unter Linux:&lt;br /&gt;
*[http://www.xchat.org/ XChat]&lt;br /&gt;
*[http://www.pidgin.im/ Pidgin]&lt;br /&gt;
&lt;br /&gt;
Ratsam ist XChat zu verwenden, da dieser nicht nur unter Windows,Linux und Mac funktioniert, sondern auch OpenSource und auf dem neusten Stand ist. X-Chat kann unter Windows auch als Precompiled Version geladen werden aber oft sind diese dann kostenpflichtig. Darum ist eine selber compilieren oft praktischer, da es stabiler, kostenlos und oft auch schneller ist. Dies liegt daran, dass das Compilat auf das eigene System vorher angepasst wird.&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Im Channel solltet Ihr eine der folgenden Personen sehen: [[Benutzer:TAK2004|TAK2004]], [[Benutzer:Frase|Frase]], [[Benutzer:Lord Horazont|Horazont]] oder [[Benutzer:I0n0s|i0n0s]].&lt;br /&gt;
Diese Personen sind Inventar und im Normalfall ist immer einer dieser Personen da.}}&lt;br /&gt;
&lt;br /&gt;
== XChat ==&lt;br /&gt;
&lt;br /&gt;
=== Installation von XChat ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Compilieren ====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Die Source lässt sich unter dem obengenannten Link laden.&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#cd /...Ordner wo das Sourcepackage liegt.&lt;br /&gt;
#Archive entpacken:&amp;lt;br&amp;gt; tar -xzvf xchat-versionsnummer.tar.gz &amp;lt;br&amp;gt; oder &amp;lt;br&amp;gt; tar -xjvf xchat-versionsnummer.tar.bz2&lt;br /&gt;
#cd /...Ordner wo die Source entpackt wurde.../&lt;br /&gt;
#Konfigurationsscript ausführen: &amp;lt;br&amp;gt; ./configure&lt;br /&gt;
#das Programm compilieren lassen &amp;lt;br&amp;gt; make&lt;br /&gt;
#zu root wechseln für eine systemweite Installation &amp;lt;br&amp;gt; su&lt;br /&gt;
#sichergehen das man im Sourceordner ist&lt;br /&gt;
#xchat installieren &amp;lt;br&amp;gt; make install &lt;br /&gt;
&lt;br /&gt;
==== Binary ====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Die binär Datei lässt sich unter dem oben genannten Link laden und mit simplen Klicks unter Windows installieren.&lt;br /&gt;
Die Linux Variante kann man als RPM-Datei laden, diese ist eine Linux Installationsdatei und muss mit dem Programm rpm installiert werden.&lt;br /&gt;
&lt;br /&gt;
==== rpm ====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#den Ordner mit der rpm öffnen &amp;lt;br&amp;gt; cd /...ordner wo die rpm liegt.../&lt;br /&gt;
#das rpm installieren &amp;lt;br&amp;gt; rpm -i xchat-versionsnummer&lt;br /&gt;
&lt;br /&gt;
Es gibt noch eine bequemere Variante, und zwar über ein Packagemanger X-Chat zu beziehen.&lt;br /&gt;
&lt;br /&gt;
===== apt-get =====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#zu Root wechseln &amp;lt;br&amp;gt; su -&lt;br /&gt;
#apt-get aktualisieren &amp;lt;br&amp;gt; apt-get update&lt;br /&gt;
#xchat suchen &amp;lt;br&amp;gt; apt-cache search xchat &amp;lt;br&amp;gt; xchat - A popular and easy to use graphical IRC (chat) client &amp;lt;br&amp;gt;&lt;br /&gt;
#das Ergebnis was gefunden wurde installieren &amp;lt;br&amp;gt; apt-get install xchat&lt;br /&gt;
&lt;br /&gt;
===== yum =====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#zu Root wechseln &amp;lt;br&amp;gt; su -&lt;br /&gt;
#xchat suchen &amp;lt;br&amp;gt; yum search xchat &amp;lt;br&amp;gt; &amp;lt;b&amp;gt;xchat&amp;lt;/b&amp;gt;.x86_64 : A popular and easy to use graphical IRC (chat) client &amp;lt;br&amp;gt;&lt;br /&gt;
#das Ergebnis was gefunden wurde installieren &amp;lt;br&amp;gt; yum install xchat&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration von XChat ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#X-Chat starten&lt;br /&gt;
#oben im Menü X-Chat-&amp;gt;Serverliste auswählen&lt;br /&gt;
#die einzelnen Nicks eintragen falls die vorigen schon belegt sind&lt;br /&gt;
#Hinzufügen drücken und ein Namen auswählen wie &amp;quot;dglchat_server&amp;quot;&lt;br /&gt;
#Editieren&lt;br /&gt;
#in der Liste ganz oben alle bis auf einen Eintrag &amp;quot;Entfernen&amp;quot; &lt;br /&gt;
#den letzten Eintrag &amp;quot;Editieren&amp;quot; und &amp;quot;#irc.euirc.net&amp;quot; eintragen&lt;br /&gt;
#ein Häkchen bei &amp;quot;Automatisches Verbinden mit diesem Netzwerk beim Start&amp;quot;&lt;br /&gt;
#bei &amp;quot;Zu betretende Channels:&amp;quot; &amp;quot;#delphigl&amp;quot; eintragen&lt;br /&gt;
#bei &amp;quot;Zeichensatz:&amp;quot; &amp;quot;UTF-8&amp;quot;&lt;br /&gt;
#fenster schließen&lt;br /&gt;
#bei &amp;quot;Keine Serverliste beim Start&amp;quot; ein Häkchen machen,&amp;quot;Verbinde&amp;quot; drücken und schließen&lt;br /&gt;
&lt;br /&gt;
== Miranda ==&lt;br /&gt;
&lt;br /&gt;
=== Installation von Miranda ===&lt;br /&gt;
----&lt;br /&gt;
Die Installation sollte ansich selbsterklärend sein.&lt;br /&gt;
Wichtig ist es nur das IRC-PlugIn mitzuinstallieren.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration von Miranda ===&lt;br /&gt;
----&lt;br /&gt;
In Miranda-Optionen unter Network sollten folgende Einträge vorhanden sein:&lt;br /&gt;
*IRC&lt;br /&gt;
*IRC Advanced&lt;br /&gt;
*IRC DCC'n CTCP&lt;br /&gt;
Wenn nicht sollte unter Plugins kontrolliert werden ob irc.dll ausgewählt ist und läuft.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Gehen wir nun in den Tab IRC:&lt;br /&gt;
Unter '''Default network''' wählt ihr euIRCnet: Random server.&lt;br /&gt;
{{Hinweis|Wenn man mehrere Netzwerke besuchen will reicht es aus die irc.dll und irc_servers.ini zu kopieren}}&lt;br /&gt;
Nick ist euere Nickname. Alternative nick ein alternativer Nick falls der erste schon verwendet wird.&lt;br /&gt;
Unter '''Other''' sollte noch 'Rejoin channel if kicked' deaktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um einen Channel zu joinen klickt man auf das Miranda Icon in der Menuleiste, wählt 'IRC-&amp;gt;Join a Channel' aus.&lt;br /&gt;
Dort gibt ihr dann #delphigl ein.&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL-Chat&amp;diff=24692</id>
		<title>DGL-Chat</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL-Chat&amp;diff=24692"/>
				<updated>2010-02-09T19:05:44Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: /* Konfiguration von XChat */  Zeichensatzdings raus&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DelphiGL-Chat =&lt;br /&gt;
&lt;br /&gt;
Die DGL Community bietet neben der Website, dem Forum und dem Wiki auch ein interaktiven Chat über IRC an.&lt;br /&gt;
Den Chat findet man im [http://www.euirc.net/de/ euIRCnet] unter '''#delphigl'''.&lt;br /&gt;
In diesen Artikel erfahren Sie, welche Clients es gibt und wie man in diesen Chatroom hinein kommt.&lt;br /&gt;
&lt;br /&gt;
== IRC Chat Client ==&lt;br /&gt;
IRC Clients gibt es wie Sand am Meer aber dementsprechend sind auch die Unterschiede.&lt;br /&gt;
Da es sich um einen einfachen Zugang handeln soll, ist ein IRC Chatprogram am geeignesten.&lt;br /&gt;
Ein Java Applet (wie es z.B. DelphiGL.com unter [http://chat.delphigl.com/ http://chat.delphigl.com/] zur Verfügung stellt) oder ein Webserver basierter Chat sind langsamer und bieten nicht den Funktionsumfang.&lt;br /&gt;
&lt;br /&gt;
Unter Windows:&lt;br /&gt;
*[http://www.xchat.org/ XChat]&lt;br /&gt;
*[http://www.trillian-messenger.de/ Trillian]&lt;br /&gt;
*[http://www.mirc.de/default.php mIRC]&lt;br /&gt;
*[http://www.miranda-im.org/ Miranda]&lt;br /&gt;
*[http://www.hydrairc.com/ HydraIRC]&lt;br /&gt;
*[http://www.pidgin.im/ Pidgin]&lt;br /&gt;
&lt;br /&gt;
Unter Linux:&lt;br /&gt;
*[http://www.xchat.org/ XChat]&lt;br /&gt;
*[http://www.pidgin.im/ Pidgin]&lt;br /&gt;
&lt;br /&gt;
Ratsam ist XChat zu verwenden, da dieser nicht nur unter Windows,Linux und Mac funktioniert, sondern auch OpenSource und auf dem neusten Stand ist. X-Chat kann unter Windows auch als Precompiled Version geladen werden aber oft sind diese dann kostenpflichtig. Darum ist eine selber compilieren oft praktischer, da es stabiler, kostenlos und oft auch schneller ist. Dies liegt daran, dass das Compilat auf das eigene System vorher angepasst wird.&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Im Channel solltet Ihr eine der folgenden Personen sehen: [[Benutzer:TAK2004|TAK2004]], [[Benutzer:Frase|Frase]], [[Benutzer:Lord Horazont|Horazont]] oder [[Benutzer:I0n0s|i0n0s]].&lt;br /&gt;
Diese Personen sind Inventar und im Normalfall ist immer einer dieser Personen da.}}&lt;br /&gt;
&lt;br /&gt;
== XChat ==&lt;br /&gt;
&lt;br /&gt;
=== Installation von XChat ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Compilieren ====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Die Source lässt sich unter dem obengenannten Link laden.&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#cd /...Ordner wo das Sourcepackage liegt.&lt;br /&gt;
#Archive entpacken:&amp;lt;br&amp;gt; tar -xzvf xchat-versionsnummer.tar.gz &amp;lt;br&amp;gt; oder &amp;lt;br&amp;gt; tar -xjvf xchat-versionsnummer.tar.bz2&lt;br /&gt;
#cd /...Ordner wo die Source entpackt wurde.../&lt;br /&gt;
#Konfigurationsscript ausführen: &amp;lt;br&amp;gt; ./configure&lt;br /&gt;
#das Programm compilieren lassen &amp;lt;br&amp;gt; make&lt;br /&gt;
#zu root wechseln für eine systemweite Installation &amp;lt;br&amp;gt; su&lt;br /&gt;
#sichergehen das man im Sourceordner ist&lt;br /&gt;
#xchat installieren &amp;lt;br&amp;gt; make install &lt;br /&gt;
&lt;br /&gt;
==== Binary ====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Die binär Datei lässt sich unter dem oben genannten Link laden und mit simplen Klicks unter Windows installieren.&lt;br /&gt;
Die Linux Variante kann man als RPM-Datei laden, diese ist eine Linux Installationsdatei und muss mit dem Programm rpm installiert werden.&lt;br /&gt;
&lt;br /&gt;
==== rpm ====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#den Ordner mit der rpm öffnen &amp;lt;br&amp;gt; cd /...ordner wo die rpm liegt.../&lt;br /&gt;
#das rpm installieren &amp;lt;br&amp;gt; rpm -i xchat-versionsnummer&lt;br /&gt;
&lt;br /&gt;
Es gibt noch eine bequemere Variante, und zwar über ein Packagemanger X-Chat zu beziehen.&lt;br /&gt;
&lt;br /&gt;
===== apt-get =====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#zu Root wechseln &amp;lt;br&amp;gt; su -&lt;br /&gt;
#apt-get aktualisieren &amp;lt;br&amp;gt; apt-get update&lt;br /&gt;
#xchat suchen &amp;lt;br&amp;gt; apt-cache search xchat &amp;lt;br&amp;gt; xchat - A popular and easy to use graphical IRC (chat) client &amp;lt;br&amp;gt;&lt;br /&gt;
#das Ergebnis was gefunden wurde installieren &amp;lt;br&amp;gt; apt-get install xchat&lt;br /&gt;
&lt;br /&gt;
===== yum =====&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#Shell öffnen&lt;br /&gt;
#zu Root wechseln &amp;lt;br&amp;gt; su -&lt;br /&gt;
#xchat suchen &amp;lt;br&amp;gt; yum search xchat &amp;lt;br&amp;gt; &amp;lt;b&amp;gt;xchat&amp;lt;/b&amp;gt;.x86_64 : A popular and easy to use graphical IRC (chat) client &amp;lt;br&amp;gt;&lt;br /&gt;
#das Ergebnis was gefunden wurde installieren &amp;lt;br&amp;gt; yum install xchat&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration von XChat ===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
#X-Chat starten&lt;br /&gt;
#oben im Menü X-Chat-&amp;gt;Serverliste auswählen&lt;br /&gt;
#die einzelnen Nicks eintragen falls die vorigen schon belegt sind&lt;br /&gt;
#Hinzufügen drücken und ein Namen auswählen wie &amp;quot;dglchat_server&amp;quot;&lt;br /&gt;
#Editieren&lt;br /&gt;
#in der Liste ganz oben alle bis auf einen Eintrag &amp;quot;Entfernen&amp;quot; &lt;br /&gt;
#den letzten Eintrag &amp;quot;Editieren&amp;quot; und &amp;quot;#irc.euirc.net&amp;quot; eintragen&lt;br /&gt;
#ein Häkchen bei &amp;quot;Automatisches Verbinden mit diesem Netzwerk beim Start&amp;quot;&lt;br /&gt;
#bei &amp;quot;Zu betretende Channels:&amp;quot; &amp;quot;#delphigl&amp;quot; eintragen&lt;br /&gt;
#fenster schließen&lt;br /&gt;
#bei &amp;quot;Keine Serverliste beim Start&amp;quot; ein Häkchen machen,&amp;quot;Verbinde&amp;quot; drücken und schließen&lt;br /&gt;
&lt;br /&gt;
== Miranda ==&lt;br /&gt;
&lt;br /&gt;
=== Installation von Miranda ===&lt;br /&gt;
----&lt;br /&gt;
Die Installation sollte ansich selbsterklärend sein.&lt;br /&gt;
Wichtig ist es nur das IRC-PlugIn mitzuinstallieren.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration von Miranda ===&lt;br /&gt;
----&lt;br /&gt;
In Miranda-Optionen unter Network sollten folgende Einträge vorhanden sein:&lt;br /&gt;
*IRC&lt;br /&gt;
*IRC Advanced&lt;br /&gt;
*IRC DCC'n CTCP&lt;br /&gt;
Wenn nicht sollte unter Plugins kontrolliert werden ob irc.dll ausgewählt ist und läuft.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Gehen wir nun in den Tab IRC:&lt;br /&gt;
Unter '''Default network''' wählt ihr euIRCnet: Random server.&lt;br /&gt;
{{Hinweis|Wenn man mehrere Netzwerke besuchen will reicht es aus die irc.dll und irc_servers.ini zu kopieren}}&lt;br /&gt;
Nick ist euere Nickname. Alternative nick ein alternativer Nick falls der erste schon verwendet wird.&lt;br /&gt;
Unter '''Other''' sollte noch 'Rejoin channel if kicked' deaktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um einen Channel zu joinen klickt man auf das Miranda Icon in der Menuleiste, wählt 'IRC-&amp;gt;Join a Channel' aus.&lt;br /&gt;
Dort gibt ihr dann #delphigl ein.&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=OpenGL_Smooth&amp;diff=24461</id>
		<title>OpenGL Smooth</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=OpenGL_Smooth&amp;diff=24461"/>
				<updated>2010-01-05T19:51:10Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Rechtschreibung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[OpenGL]] besitzt, neben den unter [[Antialiasing]] vorgestellten Methoden, eine weitere Möglichkeit Kanten-Antialiasing zu realisieren. Diese können mit [[glEnable]] mit den Parametern GL_POINT_SMOOTH, GL_LINE_SMOOTH bzw. GL_POLYGON_SMOOTH aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
=Technik=&lt;br /&gt;
Wenn der Smooth-Wert für ein [[Primitive]] aktiviert ist, so werden im Fall von Punkten und Linien bereits andere Pixel vom [[Rasterisierung|Rasterizer]] generiert. Zusätzlich wird für jedes generierte [[Fragment]] noch ein Deckungs-Wert berechnet, welcher angibt wie viel Prozent des Fragmentes von dem entsprechenden [[Primitive]] bedeckt werden.&lt;br /&gt;
&lt;br /&gt;
Dieser Deckungs-Wert wird nach allen anderen Berechnungen mit dem Alpha-Wert des Fragmentes multipliziert. Aus diesem Grund hängt diese Art von Antialiasing auch mit [[Blending]] zusammen, wodurch das Zeichnen üblicherweise mit Tiefensortierung erfolgen muss (was gleichzeitig der größte Nachteil an dieser Methode ist).&lt;br /&gt;
&lt;br /&gt;
==Punkte==&lt;br /&gt;
Werden (größere) Punkte mit aktiviertem GL_POINT_SMOOTH gerendert, so wird offensichtlich aus dem Quadrat ein richtiger Kreis. Auch ohne aktiviertem [[Blending]] (mittels [[glEnable]]( GL_BLEND ) ) hätte man hier also bereits ein Kreisform, aber natürlich ohne geglätteten Rand.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GL_POINT_SMOOTH_deaktiviert.png]] [[Bild:GL_POINT_SMOOTH_aktiviert.png]]&lt;br /&gt;
&lt;br /&gt;
''4-Fach vergrößerter Punkt links ohne und recht mit GL_POINT_SMOOTH.''&lt;br /&gt;
&lt;br /&gt;
==Linien==&lt;br /&gt;
Werden Linien mit aktiviertem GL_LINE_SMOOTH gerendert, so wird offensichtlich aus dem Trapez (mehrere 1-Pixel Linien entweder nebeneinander oder übereinander) ein Quader. Dies hat (vor allem bei breiteren Linien) ebenfalls auch Auswirkungen wenn [[Blending]] deaktiviert ist.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GL_LINE_SMOOTH_deaktiviert.png]] [[Bild:GL_LINE_SMOOTH_aktiviert.png]]&lt;br /&gt;
&lt;br /&gt;
''4-Fach vergrößerte Linie links ohne und recht mit GL_LINE_SMOOTH.''&lt;br /&gt;
&lt;br /&gt;
==Polygone==&lt;br /&gt;
Polygone (also Triangles, Quads, Triangle-Strips, Triangle-Fans und Polygone) verändern ihr Erscheinungsbild mit deaktivierten [[Blending]] kaum. Mit aktiviertem [[Blending]] werden aber natürlich die Kanten geglättet.&lt;br /&gt;
&lt;br /&gt;
=Probleme=&lt;br /&gt;
Bei Polygonen tauchen die größten Problem auf, und zwar so große, dass es von vielen Grafikkarten gar nicht unterstützt wird. Vor allem bei aktiviertem GL_POLYGON_SMOOTH kommt es also des öfteren vor, dass in den Softwaremodus umgeschaltet wird, und nicht einmal dann kann man sicher sein dass es funktioniert. Und wenn es doch funktioniert so erwartet einem häufig bereits die nächste Überraschung.&lt;br /&gt;
&lt;br /&gt;
Das Problem ist, dass zwei aneinanderliegende Dreiecke häufig einen Spalt aufweisen. Da die [[Primitive]]n GL_QUADS, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN und GL_POLYGON üblicherweise ebenfalls in Dreiecke aufgeteilt werden, entsteht dieser Spalt auch dort. Und wäre dies nicht schon genug so kann ein einzelnes Dreieck an einer [[Clipping Plane]] oder dem [[Frustum]] ebenfalls noch in 4 kleiner Dreiecke aufgesplittet werden, wo wir wiederum diesen Spalt antreffen.&lt;br /&gt;
&lt;br /&gt;
Also GL_POLYGON_SMOOTH ist mit äußerster Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
=OpenGL Funktionen=&lt;br /&gt;
*[[glEnable]] um GL_POINT_SMOOTH, GL_LINE_SMOOTH bzw. GL_POLYGON_SMOOTH zu aktivieren.&lt;br /&gt;
*[[glHint]] um den [[OpenGL]]-Treiber zu bitten eine schnellere oder eine schönere Berechnungsmethode zu verwenden.&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Matrix&amp;diff=22250</id>
		<title>Diskussion:Matrix</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Matrix&amp;diff=22250"/>
				<updated>2008-12-05T15:26:54Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Die Seite wurde neu angelegt: Bei der mxn-nxr-Matrix-Matrix Multiplikation ist ein Fehler: Bei dem Element unten links muss es nicht heißen &amp;quot;3*7+0+1*4&amp;quot; sondern &amp;quot;3*5+0+4*7&amp;quot;. Deshalb ist dann auch da...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bei der mxn-nxr-Matrix-Matrix Multiplikation ist ein Fehler: Bei dem Element unten links muss es nicht heißen &amp;quot;3*7+0+1*4&amp;quot; sondern &amp;quot;3*5+0+4*7&amp;quot;. Deshalb ist dann auch das Ergebnis 43 und nicht 25.&lt;br /&gt;
Am besten wäre es sowieso, die gescannten Sachen durch schöne LaTeX-Formeln zu ersetzen. --[[Benutzer:Wilson|Wilson]] 15:26, 5. Dez. 2008 (UTC)&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Heightmap&amp;diff=22132</id>
		<title>Heightmap</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Heightmap&amp;diff=22132"/>
				<updated>2008-09-05T19:30:15Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Ressourcenliste durch Kommas getrennt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Konzept==&lt;br /&gt;
Eine Heightmap ist ein 2-dimensionales Array, dass Informationen über eine Landschaft enthält. Dazu wird einfach an jedem Knoten der entsprechende Höhenwert gespeichert. Zum Beispiel eine zufällige Landschaft:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  i,j: integer;&lt;br /&gt;
  heightmap: array[0..width, 0..depth] of single;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to width do &lt;br /&gt;
    for j := 0 to depth do&lt;br /&gt;
      heightmap[i,j] := PerlinNoise2D(i,j, octaves, persistence);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
{{Hinweis|Es kann auch aus einem Graustufenbitmap geladen werden, z.B. je heller ein Punkt, desto höher die Landschaft an dieser Stelle}}&lt;br /&gt;
&lt;br /&gt;
==Bewertung==&lt;br /&gt;
Der Vorteil von Heightmaps ist, dass sie sehr leicht zu implementieren sind. Ein Nachteil ist jedoch, dass immer nur ein Höhenwert pro Knoten gespeichert werden kann und man so keine Felsvorsprünge oder Höhlen realisieren kann.&lt;br /&gt;
Eine interessante Möglichkeit ist, Heightmaps mit Algorithmen wie [[Perlin Noise]] zur Laufzeit zur erstellen. Desweiteren kann man [[LOD]] benutzen um das Rendern von Heightmaps zu beschleunigen.&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
[[Tutorial Terrain1]], [[Tutorial Terrain2]], [[Tutorial Terrain3]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Shaderlimitiert&amp;diff=22119</id>
		<title>Shaderlimitiert</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Shaderlimitiert&amp;diff=22119"/>
				<updated>2008-08-17T19:51:15Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Kommas&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Obwohl Shader eine der neuesten Errungenschaften bei Grafikkarten sind, besitzen sie natürlich auch Nachteile. Bevor es Shader gab, wurden alle Daten, die an die Grafikkarte geschickt wurden, nach fix vorgegebenen, einfachen Algorithmen (siehe [[Feste Funktionspipeline]]) behandelt, welche nur durch verhältnismäßig wenige Schalter oder Parameter beeinflusst werden konnten. Diese Spezialisierung bringt erst den großen Vorteil einer Grafikkarte gegenüber einer (oder sogar gegenüber einer 2ten) CPU, da diese Berechnungen nicht als Programm, sondern fast ausschließlich elektronisch realisiert wurden und großteils immer noch werden.&lt;br /&gt;
&lt;br /&gt;
Durch Shader (oder wie die OpenGL-Extensionnamen Vertex- und Fragment-program besser verdeutlichen) hat sich dies nun geändert. Ein Teil der [[Feste Funktionspipeline|festen Funktionspipeline]] wird durch einen programmierbaren Prozessor ersetzt, welcher es erlaubt die vorgegebenen Algorithmen zu verändern. Diese Freiheit geht jedoch auf Kosten der Geschwindigkeit. Hinzu kommt noch, dass der Programmierer beliebige Instruktionen geben kann, also in schlimmen Fällen auch viele, langsame und vielleicht sogar unnötige Befehle, welche natürlich die Geschwindigkeit der Grafikkarte beeinflussen. Im Endeffekt sind jedoch Shader nur als Erhöhung der Laufzeitkomplexität für Vertices bzw. Fragmente zu sehen, wodurch Shader einen (jedoch einen verhältnismäßig wichtigen) Beitrag zur [[Vertexlimitiert|Vertexlimitierung]] bzw. zur [[Füllrate|Füllratenlimitierung]] darstellen.&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=F%C3%BCllrate&amp;diff=22118</id>
		<title>Füllrate</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=F%C3%BCllrate&amp;diff=22118"/>
				<updated>2008-08-17T19:48:53Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Füllrate einer Grafikkarte beschreibt die [[Fragment]]e, die je Sekunde berechnet werden können. Da der Aufwand für diese Berechnungen jedoch sehr unterschiedlich sein kann, sind diese Angaben mit Vorsicht zu geniesen, denn meistens werden die Angaben für sehr primitive Rendereinstellungen gemacht (untexturiert, kein [[Fragment]] [[Shader]], ...).&lt;br /&gt;
&lt;br /&gt;
Der Begriff Füllratengebunden bezieht sich darauf, dass die Anzahl der [[Fragment]]e, die berechnet werden können, im Normalfall der ausschlaggebende Punkt für die Framerate ist. Dies ist natürlich nicht auf allen Grafikkarten gleich, jedoch sind die Verhältnisse zwischen [[Vertex]]anzahl und [[Fragment]]anzahl, die je Sekunde gezeichnet werden können, meistens doch recht ähnlich.&lt;br /&gt;
&lt;br /&gt;
Um zu testen, ob eine Applikation füllratengebunden ist, reicht es aus, die Applikation mit niedrigerer Auflösung laufen zu lassen und zu schauen, ob sich an der Geschwindigkeit Unterschiede bemerkbar machen.&lt;br /&gt;
&lt;br /&gt;
Einige Möglichkeiten, um die Füllrate zu schonen (und somit füllratengebundene Applikationen zu beschleunigen), sind:&lt;br /&gt;
*Auflösung verringern&lt;br /&gt;
*Objekte von vorne nach hinten zeichnen, um Gebrauch vom [[glDepthFunc|Tiefentest]] zu machen, welcher Fragmente recht früh verwirft&lt;br /&gt;
*Gebrauch vom [[glAlphaFunc|Alphatest]] machen, um [[Fragment]]e mit einem sehr niedrigem Alpha-Wert sehr früh zu verwerfen&lt;br /&gt;
*Die Rendereinstellungen je [[Fragment]] herabsetzen, also weniger Texturen, kürzerer [[Fragment]] [[Shader]], ...&lt;br /&gt;
*Die Szene weniger oft rendern (weniger Rendering Passes)&lt;br /&gt;
*[[Occlusion Culling]]&lt;br /&gt;
*[[MipMaps|Mipmapping]] bei Texturen, um die Lokalität der Texturzugriffe zu erhöhen&lt;br /&gt;
*[[Bilineare Filterung]] (anstatt linear, trilinear oder [[Anisotropes Filtern|anisotropes Filtern]])&lt;br /&gt;
Wenn viele Rendering Passes, die recht komplex sind, notwendig sind, so kann man auch im ersten Rendering Pass die gesamte Szene nur in den Tiefenbuffer zeichnen (diese Technik wird beispielsweise in Quake 3 verwendet). Bei den nächsten Passes werden dadurch alle nicht sichtbaren Fragmente sofort durch den Tiefentest verworfen.&lt;br /&gt;
&lt;br /&gt;
Einige Dinge, die '''keinen''' oder nur wenig Einfluss auf die Füllrate nehmen:&lt;br /&gt;
*[[LOD|Level of Detail]]&lt;br /&gt;
*[[Vertex]] [[Shader]]&lt;br /&gt;
*[[Frustum Culling]]&lt;br /&gt;
*Texturgröße, sofern genug Videospeicher vorhanden ist und [[MipMaps]] verwendet wird.&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=BlueBook&amp;diff=21615</id>
		<title>BlueBook</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=BlueBook&amp;diff=21615"/>
				<updated>2008-04-29T18:32:32Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Purple-Book-Satz verständlicher gemacht&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Was ist das? ==&lt;br /&gt;
Das OpenGL Bluebook ist das Referenzhandbuch zu den GL, GLU und GLX Befehlen. Hier werden alle Befehle mit&lt;br /&gt;
:Name&lt;br /&gt;
:Spezifikation&lt;br /&gt;
:Paramter&lt;br /&gt;
:Beschreibung&lt;br /&gt;
aufgelistet.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Entspricht also quasi der [[OpenGL-Funktionsübersicht]] dieses Wikis.&lt;br /&gt;
&lt;br /&gt;
Bildet zusammen mit dem [[RedBook]] die [[PurpleBook]] genannte &amp;quot;Official OpenGL Library&amp;quot;  des &amp;quot;OpenGL Architecture Review Board&amp;quot;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Siehe Auch==&lt;br /&gt;
[[RedBook]], [[OrangeBook]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=RedBook&amp;diff=21614</id>
		<title>RedBook</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=RedBook&amp;diff=21614"/>
				<updated>2008-04-29T18:32:04Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Purple-Book-Satz verständlicher gemacht&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Was ist das? ==&lt;br /&gt;
Das OpenGL Redbook ist die Dokumentation welche Ursprünglich von SGI zu [[OpenGL]] geschrieben wurde. &amp;lt;br&amp;gt;&lt;br /&gt;
Im Redbook werden alle Techniken von OpenGL, unter anderem mit Beispielen (in C) und Bildern, erklärt. &amp;lt;br&amp;gt;&lt;br /&gt;
Bildet zusammen mit dem [[BlueBook]] die [[PurpleBook]] genannte &amp;quot;Official OpenGL Library&amp;quot; des &amp;quot;OpenGL Architecture Review Board&amp;quot;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bezugsquellen ==&lt;br /&gt;
Mittlerweile wird das Redbook vom Addison-Wesley Verlag vertrieben. Eine deutsche Version ist im Buchhandel verfügbar.&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hin und wieder taucht eine englische Version des Redbooks auch im Internet auf. Eine deutsche Übersetzung samt Aktualisierung dieser Version wurde ursprünglich von der DelphiGL-Comunity angestrebt. Da aber alle Versuche der Absprache mit dem Copyrightinhaber Addison-Wesley scheiterten, wurde das DGL-Wiki als Ersatz ins Leben gerufen.&lt;br /&gt;
&lt;br /&gt;
==Siehe Auch==&lt;br /&gt;
[[BlueBook]], [[OrangeBook]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Tutorial_Frustum_Culling&amp;diff=21551</id>
		<title>Diskussion:Tutorial Frustum Culling</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Tutorial_Frustum_Culling&amp;diff=21551"/>
				<updated>2008-04-17T18:17:04Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Die Seite wurde geleert.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Tutorial_Frustum_Culling&amp;diff=21550</id>
		<title>Diskussion:Tutorial Frustum Culling</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Tutorial_Frustum_Culling&amp;diff=21550"/>
				<updated>2008-04-17T18:15:54Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Die Seite wurde neu angelegt: == Große Objekte == Was dem ganzen fehlt, ist die Betrachtung von Kugeln/Quadern (ganz allgemein: von Objekten aus min. 2 Punkten), die so groß sind, dass zwar die Ec...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Große Objekte ==&lt;br /&gt;
Was dem ganzen fehlt, ist die Betrachtung von Kugeln/Quadern (ganz allgemein: von Objekten aus min. 2 Punkten), die so groß sind, dass zwar die Eckpunkte allesamt außerhalb des Bildschirms liegen, der Teil dazwischen aber innerhalb.&lt;br /&gt;
Gut - das dürfte nicht häufig der Fall sein, aber es ist ein Fehlverhalten. [[Benutzer:Wilson|Wilson]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Matrix2&amp;diff=21495</id>
		<title>Tutorial Matrix2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Matrix2&amp;diff=21495"/>
				<updated>2008-04-12T22:02:44Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: /* Nachwort */ URL zu Matrix Control angepasst&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Matrizen und Matrixmanipulationen= &lt;br /&gt;
&lt;br /&gt;
== Vorwort == &lt;br /&gt;
Willkommen bei meinem 2. Tutorial.&amp;lt;br&amp;gt; &lt;br /&gt;
In letzter Zeit traten im Forum verstärkt fragen wie ''&amp;quot;Wie positioniere ich Objekte richtig?&amp;quot;'' und ''&amp;quot;Ich komm mit den Matrizen net klar. Könnt ihr helfen?&amp;quot;'' auf. Dies war Anlass für mich ein weiteres Tutorial zum Thema Matrizen zu schreiben. Ich werde versuchen viel mit Bildern und Gleichnissen zu arbeiten. Wer aber das ganze Angebot zum Thema &amp;quot;Matrix&amp;quot; nutzen will sollte ruhig auch einen Blick auf Phobeus Matrixtutorial ([[Tutorial_lektion3]]) und auf den Wikiartikel zum Thema [[Matrix]] werfen. &lt;br /&gt;
&lt;br /&gt;
== Matrizen in OpenGL == &lt;br /&gt;
&lt;br /&gt;
OpenGL kennt 3 Matrizen. Wer OpenGL programmieren will sollte diese auch kennen: &lt;br /&gt;
* '''GL_MODELVIEW''' - Die Modelviewmatrix &lt;br /&gt;
: Die Modelviewmatrix sollte immer dann aktiviert sein, wenn ihr an die Grafikkarte [[Vertex]]daten senden wollt. Diese Matrix wird auf die Position der Vertices, die mit [[glVertex]] gesendet werden angewandt. Ebenso beeinflusst sie die Ausrichtung der [[Normalen]], die mit Hilfe von [[glNormal]] gesetzt werden. Kurz, alles was mit den Objekten eurer Welt zu tun hat, erfordert die Aktivierung dieser Matrix.&lt;br /&gt;
* '''GL_PROJECTION''' - Die Projektionsmatrix &lt;br /&gt;
: Diese Matrix wird selten gebraucht. Sie bestimmt, wie am Ende alles angezeigt wird. Sie bestimmt quasi die Eigenschaften der &amp;quot;Kamera&amp;quot;. &lt;br /&gt;
* '''GL_TEXTURE''' - Die Texturmatrix &lt;br /&gt;
: Diese Matrix wird auf die Texturkoordinaten angewandt, mit der Folge, dass sich die Texturen auf den Oberflächen bewegen.&lt;br /&gt;
&lt;br /&gt;
Diese 3 Matrizen können per [[glMatrixMode]] aktiviert werden. Dabei kann immer nur eine Matrix aktiv sein. Wenn ihr z.B. {{INLINE_CODE|glMatrixMode(GL_MODELVIEW)}} aufgerufen habt, dann sagt man &amp;quot;Die Modelviewmatrix ist die '''''aktuelle Matrix'''''&amp;quot;. Alle Matrixmanipulationen (wir kommen gleich dazu was das ist) wirken sich ''nur'' auf die ''aktuelle Matrix'' aus.&lt;br /&gt;
&lt;br /&gt;
== Kurze Matrixtheorie == &lt;br /&gt;
''Was sind Matrizen?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Matrizen sind aufgebaut wie Tabellen. Das tolle daran ist - man kann damit rechnen. &amp;lt;br&amp;gt; &lt;br /&gt;
''&amp;quot;Gaaaaanz toll! Jetzt rechnen die schon mit Tabellen...&amp;quot;''&amp;lt;br&amp;gt; &lt;br /&gt;
So schlimm ist das gar nicht. Denn das Rechnen übernimmt OpenGL für uns. Ihr müsst nur wissen, dass wann immer ihr einen Befehl wie [[glTranslate]], [[glRotate]] oder [[glScale]] verwendet, ihr eine Matrix mit der ''aktuellen Matrix'' multipliziert. &lt;br /&gt;
{{Hinweis|Wenn ihr wissen wollt, wie man Matrizen miteinander multipliziert, dann lest euch einmal den Artikel &amp;quot;[[Matrix]]&amp;quot; durch und auch das dort verlinkte PDF &amp;quot;CompGeoScript&amp;quot;.}} &lt;br /&gt;
&lt;br /&gt;
== Wie sehen Matrizen aus? == &lt;br /&gt;
In &amp;quot;echt&amp;quot; sehen Matrizen wie Tabellen voller Zahlen aus. &amp;lt;br&amp;gt; &lt;br /&gt;
Will man sich eine Matrix grafisch vorstellen, sollte man sich ein 3 dimensionales Gitter vorstellen. Dieses Gitter ist das Koordinatensystem der Matrix. Wenn ihr mit [[glTranslate]], [[glRotate]] oder [[glScale]] die Matrix manipuliert, dann verändert ihr die Position des Koordinatenursprungs (glTranslate), die Ausrichtung der Achsen (glRotate) oder die Maße (glScale). Im dritten Teil des Tutorials gehe ich auf die Auswirkungen dieser Befehle noch einmal genauer ein. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Die drei OpenGL Matrizen = &lt;br /&gt;
&lt;br /&gt;
== GL_PROJECTION == &lt;br /&gt;
Ich möchte zuerst einmal die Projektionsmatrix vorstellen. Diese Matrix wird meist nur am Rande erwähnt, macht aber einen verdammt wichtigen Job: Sie projeziert den Inhalt der Welt auf den Bildschirm. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr der Projektionsmatrix per [[glLoadMatrix]] eine Matrix zuweist, die nur Nullen enthält, werdet ihr feststellen, dass ihr nichts seht. Ihr habt damit nämlich die Projektionsmatrix ausgeschaltet und da wir ja was sehen wollen, unterlassen wir das in Zukunft lieber ;). &lt;br /&gt;
&lt;br /&gt;
''Aber was kann man dann mit der Projektionsmatrix machen (,außer sie nicht auszuschalten ;-) )?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Bei der Vorstellung der einzelnen Matrizen erwähnte ich bereits die &amp;quot;Kamera&amp;quot;. Um gleich mal eins festzustellen: Ein Objekt &amp;quot;Kamera&amp;quot; existiert nicht. Das einzigste was man von der &amp;quot;Kamera&amp;quot; mitbekommt ist die Ausgabe. Und wie wir gerade gelernt haben ist welcher Teil für die Ausgabe zuständig? Richtig! Die Projektionsmatrix. Sie ist unsere &amp;quot;Kamera&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Kommt jetzt aber bitte nicht auf die Idee, eure Projektionsmatrix per '''glTranslate''' und '''glRotate''' irgendwohin zu bewegen... Das ist nämlich gar nicht die Aufgabe der Projektionsmatrix. Ihre Aufgabe ist &amp;quot;das Abbild für die Ausgabe zu manipulieren&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Im Ausgangszustand ([[glLoadIdentity]] wurde für die Projektionsmatrix aufgerufen), gibt die Projektionsmatrix das Bild der Welt unverändert aus. Wenn man '''glTranslate''' auf die Projektionsmatrix anwendet, dann verschiebt man nicht die Welt, sondern sagt der  Projektionsmatrix, dass sie das gesehene Bild verschieben soll. &lt;br /&gt;
&lt;br /&gt;
Befehle wie [[gluPerspective]] und [[glOrtho]] sind typische Befehle zum einstellen der Projektionsmatrix. Diese Befehle bestimmen nämlich in welcher Form die Ausgabe gemacht wird. Entweder perspektivisch verzerrt (gluPerspective) oder durch Parallelprojektion (glOrtho).&lt;br /&gt;
&lt;br /&gt;
Wenn man die Projektionsmatrix manipuliert, ist das vergleichbar mit dem Austauschen des Objektivs bei einer Kamera. Man könnt sogar über die Projektionsmatrix einen &amp;quot;Fischauge&amp;quot; Effekt erzeugen... (Aber fragt mich bitte nicht, wie die Matrix dazu aussieht... ;-) Falls ihrs wißt, einfach im Forum posten. Ich wäre interessiert.)&lt;br /&gt;
&lt;br /&gt;
== GL_MODELVIEW == &lt;br /&gt;
Wie bereits erwähnt ist die Modelviewmatrix die wichtigste Matrix in der OpenGL Welt, denn sie wirkt sich auf Ausrichtung und Position aller Primitive und damit Objekte in der OpenGL Welt aus. Ohne Daten in der Modelviewmatrix, kann die Projektionsmatrix auch nichts ausgeben. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr [[Vertex]]daten  an die Grafikkarte übermittelt solltet ihr die Modelviewmatrix aktiviert haben. Positionsangaben wie z.B. {{INLINE_CODE|glVertex3f(1,0,1);}} beziehen sich auf das aktuelle Koordinatensystem. Das Koordinatensystem ist quasi der Teil der Matrix mit dem ihr arbeitet, und den ihr euch vorstellen könnt (/müßt.).&amp;lt;br&amp;gt;&lt;br /&gt;
Wie ihr bereits wisst kann man mit den Befehlen [[glTranslate]], [[glRotate]] und [[glScale]] das Koordinatensystem manipulieren. Dadurch seit ihr in der Lage beim &amp;quot;bauen&amp;quot; von Objekten mit &amp;quot;lokalen Koordinaten&amp;quot; zu arbeiten. &lt;br /&gt;
&lt;br /&gt;
=== lokale und globale Koordinaten === &lt;br /&gt;
''Worin unterscheiden sich lokale und globale Koordinaten?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Um diese Frage zu klären bedarf es eines kleinen Beispiels: &lt;br /&gt;
&lt;br /&gt;
Stellt euch vor, ihr wollt zwei Würfel zeichnen. Der eine soll um den Punkt (3,4,5)  mit einer Kantenlänge von 1 erstellt werden, der andere soll um den Punkt (1,2,3) mit Kantenlänge 2 und dazu 30° um die Y-Achse gedreht werden. &lt;br /&gt;
&lt;br /&gt;
Wenn man mit '''globalen''' Koordinaten arbeitet lässt man die Matrix so wie sie ist (verzichtet also auf die 3 genannten Befehle) und schreibt die Koordinaten der Eckpunkte per Hand hin: &lt;br /&gt;
&amp;lt;pascal&amp;gt;glBegin(GL_QUADS); &lt;br /&gt;
  //Vorderseite erster Würfel &lt;br /&gt;
  glVertex3f(2,5,6); &lt;br /&gt;
  glVertex3f(2,3,6); &lt;br /&gt;
  glVertex3f(4,3,6); &lt;br /&gt;
  glVertex3f(4,5,6); &lt;br /&gt;
  //Nächste Seite &lt;br /&gt;
  [...] &lt;br /&gt;
&lt;br /&gt;
  //Vorderseite zweiter Würfel &lt;br /&gt;
  glVertex3f(0,3,4); &lt;br /&gt;
  glVertex3f(0,1,4); &lt;br /&gt;
  glVertex3f(2,1,4); &lt;br /&gt;
  glVertex3f(2,3,4); &lt;br /&gt;
  [...] &lt;br /&gt;
&lt;br /&gt;
glEnd; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Bei '''lokalen''' Koordinaten bewegt man zuerst den Koordinatenursprung an die Stelle an die der Würfel entstehen soll, richtet dann wenn nötig die Achsen entsprechend aus, und kann dann '''lokale''' Koordinaten übergeben. Lokal bedeutet hier relativ zum aktuellen Koordinatensystem. &lt;br /&gt;
&lt;br /&gt;
''Aber was soll das für einen Vorteil haben?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Dem ein oder anderen ist vielleicht aufgefallen, dass wir 2x das selbe Objekt zeichnen sollen. Der einzigste Unterschied besteht in der Position, Ausrichtung und Größe/Scalierung. Um Arbeit zu sparen erstellt man deshalb ein Unterprogramm welches einen Einheitswürfel (Kantenlänge 1) rendert, und ruft vor dem zeichnen einfach die passende Kombination aus glTranslate, glRotate und glScale auf: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure zeichneWuerfel; &lt;br /&gt;
begin &lt;br /&gt;
  glBegin(GL_QUADS); &lt;br /&gt;
    glVertex3f(-0.5, 0.5, 0.5); &lt;br /&gt;
    glVertex3f(-0.5,-0.5, 0.5); &lt;br /&gt;
    glVertex3f( 0.5,-0.5, 0.5); &lt;br /&gt;
    glVertex3f( 0.5, 0.5, 0.5); &lt;br /&gt;
    [...] &lt;br /&gt;
  glEnd; &lt;br /&gt;
end; &lt;br /&gt;
&lt;br /&gt;
begin &lt;br /&gt;
  glPushMatrix; &lt;br /&gt;
    glTranslatef(3,4,5); &lt;br /&gt;
    zeichneWuerfel; &lt;br /&gt;
  glPopMatrix; &lt;br /&gt;
  glPushMatrix; &lt;br /&gt;
    glTranslatef(1,2,3); &lt;br /&gt;
    glRotatef(30,0,1,0); &lt;br /&gt;
    glScalef(2,2,2); &lt;br /&gt;
    zeichneWuerfel; &lt;br /&gt;
  glPopMatrix; &lt;br /&gt;
end; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Wie ihr seht, haben lokale Koordinaten den Vorteil, dass man wiederverwendbaren Code schreiben kann. Bei globalen Koordinaten muss für jedes Objekt eigener Code geschrieben werden (und wenn sich das Objekt bewegt dann wieder...).&lt;br /&gt;
&lt;br /&gt;
Dreimal dürft ihr raten, welche Methode häufiger verwendet wird. ;-) &lt;br /&gt;
{{Hinweis|Modeller wie 3D Studio Max benutzen globale Koordinaten beim exportieren der Modelle. Dies hat den Vorteil, dass beim importieren einer ganzen 3DS Szene, die Objekte gleich an der richtigen Position stehen, und nicht erst ausgerichtet werden müssen.}} &lt;br /&gt;
&lt;br /&gt;
== GL_TEXTURE == &lt;br /&gt;
Dieser Matrix sollte endlich mehr Aufmerksamkeit geschenkt werden. Sie kann nämlich mit den Texturen in der Szene einiges anfangen... &lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach: &lt;br /&gt;
&lt;br /&gt;
Wie ihr vielleicht schon im [[Tutorial_lektion4|Einsteigertutorial 4 - Texturen]] gelesen habt, sind Texturkoordinaten immer so, dass {{INLINE_CODE|[[glTexCoord2f]](0,0)}} die obere linke Ecke und {{INLINE_CODE|glTexCoord2f(1,1)}} die untere Rechte Ecke der Textur betrifft. Wie die Textur außerhalb dieses Bereichs aussieht bestimmt ihr mittels [[glTexParameter]] und dem Parametern '''GL_TEXTURE_WRAP_S''' und '''GL_TEXTURE_WRAP_T'''. &lt;br /&gt;
&lt;br /&gt;
Nun stellt euch einmal vor, ihr habt 2 Quads die beide die selbe Textur bekommen sollen. Einziger Unterschied ist, dass bei dem einen Quad der Inhalt der Textur um 20° in Uhrzeigerrichtung gedreht ist. Blöd, oder? Das heißt ja jetzt, dass ihr in eurem Zeichenprogramm eine weitere Textur erstellen müßt, um das zweite Quad zu texturieren oder die Texturkoordinaten per Hand ändern müsst. &amp;lt;br&amp;gt; &lt;br /&gt;
'''STOP!''' Ihr hab es sicherlich schon mitbekommen: Dieses Szenario kann leicht mit der Texturmatrix gelößt werden. Und zwar so... &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure drawTexturedQuad; &lt;br /&gt;
begin &lt;br /&gt;
  glBegin(GL_QUADS); &lt;br /&gt;
    glTexCoord(0,0); glVertex3f(-1, 1,0); &lt;br /&gt;
    glTexCoord(0,1); glVertex3f(-1,-1,0); &lt;br /&gt;
    glTexCoord(1,1); glVertex3f( 1,-1,0); &lt;br /&gt;
    glTexCoord(1,0); glVertex3f( 1, 1,0); &lt;br /&gt;
  glEnd; &lt;br /&gt;
end; &lt;br /&gt;
&lt;br /&gt;
begin &lt;br /&gt;
  glMatrixMode(GL_MODELVIEW); &lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, texID); &lt;br /&gt;
  glTranslatef(-2,0,0); &lt;br /&gt;
  drawTexturedQuad; &lt;br /&gt;
&lt;br /&gt;
  glMatrixMode(GL_TEXTURE); &lt;br /&gt;
  glRotatef(20,0,0,1); &lt;br /&gt;
&lt;br /&gt;
  glMatrixMode(GL_MODELVIEW); &lt;br /&gt;
  glTranslatef(4,0,0); &lt;br /&gt;
  drawTexturedQuad; &lt;br /&gt;
end;&amp;lt;/pascal&amp;gt; &lt;br /&gt;
''Was ist hier geschehn? ''&amp;lt;br&amp;gt;&lt;br /&gt;
Durch die vorherige Aktivierung der Texturmatrix wirkt sich das nachfolgende glRotate nicht auf die Modelle der Szene sondern auf die Texturkoordinaten aus. Auf gut deutsch: OpenGL dreht vor dem rendern des zweiten Quads die Textur um 20°. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr beim rotieren der Texturmatrix, bei jedem Renderdurchlauf den Winkel um ein Stück erhöht passiert was?... Richtig! Eure Textur dreht sich auf eurem Quad... Das is dann quasi eure erste Animation... Und das ohne ein Objekt zu bewegen... Cool, oder?&lt;br /&gt;
&lt;br /&gt;
= Auswirkungen von Matrixmanipulationen - oder &amp;quot;Wie positioniere ich meine Objekte richtig?&amp;quot;= &lt;br /&gt;
In diesem Teil des Tutorials möchte ich euch zeigen wie die 3 Befehle '''glTranslate, glRotate''' und '''glScale''' eure aktuelle Matrix verändern. Ich bleibe hierbei im 2 dimensionalen Raum, da sonst die Skizzen zu unübersichtlich werden. (Die Befehle sind dabei natürlich die selben wie für 3D Manipulationen. Ich ignoriere nur einfach immer die Y-Angaben.) &lt;br /&gt;
&lt;br /&gt;
Zuersteinmal zum warm werden: &amp;lt;br&amp;gt; &lt;br /&gt;
[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|So stelle ich mir eine 2D-Matrix vor.]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==glTranslate== &lt;br /&gt;
{{INLINE_CODE|[[glTranslate]](a,b,c)}} verschiebt den Koordinatenursprung des aktuellen Koordinatensystems um ''a'' Einheiten in die Richtung der X-Achse, um ''b'' Einheiten in die Richtung der Y-Achse und um ''c'' Einheiten in die Richtung der Z-Achse. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Matrix2 Translate.png|framed|center|Das passiert bei einer Translation um 3.5 Einheiten in X und -3 Einheiten in Z-Richtung.]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==glRotate== &lt;br /&gt;
{{INLINE_CODE|[[glRotate]](w,x,y,z)}} rotiert das Koordinatensystem um ''w'' Grad um die Rotationsachse welche durch (0,0,0) und (''x,y,z'') verläuft. '''glScale richtet also die Achsen neu aus.''' (Die Richtung der Achsen ist z.B. wichtig für glTranslate) &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Matrix2 Rotate.png|framed|center|Das passiert bei einer Rotation um 45° mit der Y-Achse als Rotationsachse.]] &lt;br /&gt;
&lt;br /&gt;
==glScale== &lt;br /&gt;
{{INLINE_CODE|[[glScale]](x,y,z)}} skaliert die Maße der Koordinatenachsen (Bestimmt also wie lange &amp;quot;eine Einheit&amp;quot; wirklich ist). Wenn ''x,y'' oder ''z'' größer als 1 ist, werden die Maßeinheiten der entsprechenden Achse gestreckt, wenn die Werte kleiner 1 sind gestaucht. (Wenn die Werte gleich 0 sind verschwindet die Szene auf nimmer wieder sehn(, da hilft dann nur noch glLoadIdentity um die Matrix wieder nutzbar zu machen), sind die Werte gleich 1 verändert sich nichts.) &lt;br /&gt;
&lt;br /&gt;
''x,y'' und ''z'' muss man sich als Prozentangaben vorstellen. Will man die Szene in X-Richtung um das doppelte (also 200%) vergrößern/strecken muss ''x'' gleich 2 sein. Will man die Y-Richtung auf ein Zehntel (also 10%) verkürzen/stauchen muss ''y'' gleich 0.1 sein. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Matrix2 Scale.png|framed|center|Das passiert bei einer Skalierung. Wie ihr seht, sind die Seiten unterschiedlich skaliert worden (X-Achse: 80%, Z-Achse: 60%).]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Kombination - Translate vor Rotate== &lt;br /&gt;
Wird Translate vor Rotate aufgerufen, bewegt sich der Koordinatenursprung zuerst an den Zielpunkt (über glTranslate angegeben). Anschließend werden die Achsen neu ausgerichtet (durch glRotate). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glTranslatef(3.5,0,-3); &lt;br /&gt;
  glRotatef(45, 0, 1, 0); &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glTranslate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Translate.png|framed|center|Nachdem glTranslate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 TranslateRot.png|framed|center|Nachdem glRotate aufgerufen wurde. Man sieht, dass die jeweils vorhergehende Veränderung bestehend bleibt, und die Basis für die nachfolgende Änderung bildet.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird der Winkel von glRotate bei jedem Renderdurchlauf erhöht, dreht sich ein anschließend gezeichnetes Objekt um die durch glTranslate angegeben Position. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Kombination - Rotate vor Translate== &lt;br /&gt;
Wird Rotate vor Translate aufgerufen, werden zuerst die Achsen neu ausgerichtet und dann der Koordinatenursprung bezüglich dieser neuen Achsen verschoben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glRotatef(45, 0, 1, 0); &lt;br /&gt;
  glTranslatef(3.5,0,-3);   &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glRotate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Rotate.png|framed|center|Nachdem glRotate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 RotateTrans.png|framed|center|Nachdem glTranslate aufgerufen wurde. Man sieht, dass die vorhergehende Rotation die Verschieberichtung beeinflusst.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Wird der Winkel von glRotate bei jedem Renderdurchlauf erhöht, bewegt sich ein nach glTranslate gezeichnetes Objekt auf einer Kreisbahn um den Koordinatenursprung wie er beim Aufruf von glRotate aktuell war. Der Radius der Kreisbahn wird durch glTranslate bestimmt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn man die beiden Ergebnisse direkt vergleicht sieht man, dass die Reihenfolge von Bedeutung für das Ergebniss ist. Das die Unterschiede so &amp;quot;klein&amp;quot; ausfallen liegt nur daran, dass bei rotate nicht mit größeren Winkeln rotiert wurde. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 RotateTrans.png|framed|center|Erst Rotiert]] &lt;br /&gt;
|- &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 TranslateRot.png|framed|center|Erst Verschoben]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Kombination - Scale vor Rotate== &lt;br /&gt;
Die Rotation wird nur von der Richung, nicht aber der Länge der Achsen beeinflusst. Der Winkel um den gedreht wird, bleibt von der Skalierung unberührt (45° bleiben 45°. Die Achsen zeigen anschließend jeweils in die gleiche Richtung) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glScalef(0.8, 1, 0.6); &lt;br /&gt;
  glRotatef(45, 0, 1, 0); &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Scale.png|framed|center|Nachdem glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 ScaleRot.png|framed|center|Nachdem glRotate aufgerufen wurde. Man sieht, dass die Skalierung den Winkel nicht beeinflusst. Das Koordinatensystem wurde korrekt um 45° gedreht.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Der direkte Vergleich zeigt, dass die Skalierung keinen Effekt auf den Winkel hatte. Beide Koordinatensysteme sind gleich ausgerichtet: &lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 Rotate.png|framed|center|Unskaliert]] &lt;br /&gt;
|- &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 ScaleRot.png|framed|center|Skaliert]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Kombination - Scale vor Translate== &lt;br /&gt;
Die Verschiebung ist Abhängig von der Ausrichtung der Achsen (glRotate) und der Maße der Achsen (glScale). Aus diesem Grunde beeinflusst glScale die nachfolgenden Translationen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glScalef(0.8, 1, 0.6); &lt;br /&gt;
  glTranslatef(3.5,0,-3); &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Scale.png|framed|center|Nachdem glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 ScaleTrans.png|framed|center|Nachdem glTranslate aufgerufen wurde.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Der direkte Vergleich zeigt, dass sich die Skalierung auf die Verschiebung auswirkt. Denn obwohl der Verschiebung in die gleiche Richtung und um den selben Wert erfolgt, sind die Resultate nicht identisch. Dies liegt daran, dass glScale die Maße verändert hat. Die Verschiebung in X-Richtung erreicht dadurch nur 80% und in Z-Richtung sogar nur 60% der unskalierten Transformation: &lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 Translate.png|framed|center|Unskaliert]] &lt;br /&gt;
|- &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 ScaleTrans.png|framed|center|Skaliert]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Nachwort= &lt;br /&gt;
7 Stunden sind vorbei und das Tutorial ist auf eine ordentliche Länge angewachsen. Ich hoffe ich konnte euch die OpenGL Matrizen etwas näher bringen. &lt;br /&gt;
&lt;br /&gt;
Wer jetzt denkt ''&amp;quot;Bilder sind mir zu statisch!&amp;quot;'', dem möchte ich noch diese Programme ans Herz legen: &lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable}}&lt;br /&gt;
!Name&lt;br /&gt;
!Hersteller&lt;br /&gt;
!Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.delphigl.com/forum/viewtopic.php?p=37378#37378 '''Matrix2 - Skizzenrenderer''']&lt;br /&gt;
|Flash&lt;br /&gt;
|Dieses Programm habe ich geschrieben um die Skizzen für dieses Tutorial zu erstellen. Es wurde so modifiziert, dass man beliebige Kombinationen von glTranslate, glRotate und glScale anzeigen kann. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.phobeus.de/hosting/shared/pixelpracht/main.php?s=opengl&amp;amp;t=1&amp;amp;p=2 '''Matrix Control''']&lt;br /&gt;
|Lithander&lt;br /&gt;
|Das Programm erlaubt euch zu beobachten, wie die Matrizen sich bei den einzelnen Befehlen verändern und wie die Ausgabe aussieht. Besonderheit an diesem Programm ist, dass ihr die Matrizen auch per Hand manipulieren könnt.&lt;br /&gt;
|}&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten immer noch Unklarheiten bestehen bleibt das Forum natürlich auch weiterhin die Anlaufstelle Nummer1. Dies betrifft auch euer Feedback zum Tutorial. &lt;br /&gt;
&lt;br /&gt;
MfG &lt;br /&gt;
: Flash ('''Kevin Fleischer''') &lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_2D]]|-}} &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Matrix2]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Matrix2&amp;diff=21494</id>
		<title>Tutorial Matrix2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Matrix2&amp;diff=21494"/>
				<updated>2008-04-12T21:59:31Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: /* GL_TEXTURE */  Tippfehler&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Matrizen und Matrixmanipulationen= &lt;br /&gt;
&lt;br /&gt;
== Vorwort == &lt;br /&gt;
Willkommen bei meinem 2. Tutorial.&amp;lt;br&amp;gt; &lt;br /&gt;
In letzter Zeit traten im Forum verstärkt fragen wie ''&amp;quot;Wie positioniere ich Objekte richtig?&amp;quot;'' und ''&amp;quot;Ich komm mit den Matrizen net klar. Könnt ihr helfen?&amp;quot;'' auf. Dies war Anlass für mich ein weiteres Tutorial zum Thema Matrizen zu schreiben. Ich werde versuchen viel mit Bildern und Gleichnissen zu arbeiten. Wer aber das ganze Angebot zum Thema &amp;quot;Matrix&amp;quot; nutzen will sollte ruhig auch einen Blick auf Phobeus Matrixtutorial ([[Tutorial_lektion3]]) und auf den Wikiartikel zum Thema [[Matrix]] werfen. &lt;br /&gt;
&lt;br /&gt;
== Matrizen in OpenGL == &lt;br /&gt;
&lt;br /&gt;
OpenGL kennt 3 Matrizen. Wer OpenGL programmieren will sollte diese auch kennen: &lt;br /&gt;
* '''GL_MODELVIEW''' - Die Modelviewmatrix &lt;br /&gt;
: Die Modelviewmatrix sollte immer dann aktiviert sein, wenn ihr an die Grafikkarte [[Vertex]]daten senden wollt. Diese Matrix wird auf die Position der Vertices, die mit [[glVertex]] gesendet werden angewandt. Ebenso beeinflusst sie die Ausrichtung der [[Normalen]], die mit Hilfe von [[glNormal]] gesetzt werden. Kurz, alles was mit den Objekten eurer Welt zu tun hat, erfordert die Aktivierung dieser Matrix.&lt;br /&gt;
* '''GL_PROJECTION''' - Die Projektionsmatrix &lt;br /&gt;
: Diese Matrix wird selten gebraucht. Sie bestimmt, wie am Ende alles angezeigt wird. Sie bestimmt quasi die Eigenschaften der &amp;quot;Kamera&amp;quot;. &lt;br /&gt;
* '''GL_TEXTURE''' - Die Texturmatrix &lt;br /&gt;
: Diese Matrix wird auf die Texturkoordinaten angewandt, mit der Folge, dass sich die Texturen auf den Oberflächen bewegen.&lt;br /&gt;
&lt;br /&gt;
Diese 3 Matrizen können per [[glMatrixMode]] aktiviert werden. Dabei kann immer nur eine Matrix aktiv sein. Wenn ihr z.B. {{INLINE_CODE|glMatrixMode(GL_MODELVIEW)}} aufgerufen habt, dann sagt man &amp;quot;Die Modelviewmatrix ist die '''''aktuelle Matrix'''''&amp;quot;. Alle Matrixmanipulationen (wir kommen gleich dazu was das ist) wirken sich ''nur'' auf die ''aktuelle Matrix'' aus.&lt;br /&gt;
&lt;br /&gt;
== Kurze Matrixtheorie == &lt;br /&gt;
''Was sind Matrizen?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Matrizen sind aufgebaut wie Tabellen. Das tolle daran ist - man kann damit rechnen. &amp;lt;br&amp;gt; &lt;br /&gt;
''&amp;quot;Gaaaaanz toll! Jetzt rechnen die schon mit Tabellen...&amp;quot;''&amp;lt;br&amp;gt; &lt;br /&gt;
So schlimm ist das gar nicht. Denn das Rechnen übernimmt OpenGL für uns. Ihr müsst nur wissen, dass wann immer ihr einen Befehl wie [[glTranslate]], [[glRotate]] oder [[glScale]] verwendet, ihr eine Matrix mit der ''aktuellen Matrix'' multipliziert. &lt;br /&gt;
{{Hinweis|Wenn ihr wissen wollt, wie man Matrizen miteinander multipliziert, dann lest euch einmal den Artikel &amp;quot;[[Matrix]]&amp;quot; durch und auch das dort verlinkte PDF &amp;quot;CompGeoScript&amp;quot;.}} &lt;br /&gt;
&lt;br /&gt;
== Wie sehen Matrizen aus? == &lt;br /&gt;
In &amp;quot;echt&amp;quot; sehen Matrizen wie Tabellen voller Zahlen aus. &amp;lt;br&amp;gt; &lt;br /&gt;
Will man sich eine Matrix grafisch vorstellen, sollte man sich ein 3 dimensionales Gitter vorstellen. Dieses Gitter ist das Koordinatensystem der Matrix. Wenn ihr mit [[glTranslate]], [[glRotate]] oder [[glScale]] die Matrix manipuliert, dann verändert ihr die Position des Koordinatenursprungs (glTranslate), die Ausrichtung der Achsen (glRotate) oder die Maße (glScale). Im dritten Teil des Tutorials gehe ich auf die Auswirkungen dieser Befehle noch einmal genauer ein. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Die drei OpenGL Matrizen = &lt;br /&gt;
&lt;br /&gt;
== GL_PROJECTION == &lt;br /&gt;
Ich möchte zuerst einmal die Projektionsmatrix vorstellen. Diese Matrix wird meist nur am Rande erwähnt, macht aber einen verdammt wichtigen Job: Sie projeziert den Inhalt der Welt auf den Bildschirm. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr der Projektionsmatrix per [[glLoadMatrix]] eine Matrix zuweist, die nur Nullen enthält, werdet ihr feststellen, dass ihr nichts seht. Ihr habt damit nämlich die Projektionsmatrix ausgeschaltet und da wir ja was sehen wollen, unterlassen wir das in Zukunft lieber ;). &lt;br /&gt;
&lt;br /&gt;
''Aber was kann man dann mit der Projektionsmatrix machen (,außer sie nicht auszuschalten ;-) )?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Bei der Vorstellung der einzelnen Matrizen erwähnte ich bereits die &amp;quot;Kamera&amp;quot;. Um gleich mal eins festzustellen: Ein Objekt &amp;quot;Kamera&amp;quot; existiert nicht. Das einzigste was man von der &amp;quot;Kamera&amp;quot; mitbekommt ist die Ausgabe. Und wie wir gerade gelernt haben ist welcher Teil für die Ausgabe zuständig? Richtig! Die Projektionsmatrix. Sie ist unsere &amp;quot;Kamera&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Kommt jetzt aber bitte nicht auf die Idee, eure Projektionsmatrix per '''glTranslate''' und '''glRotate''' irgendwohin zu bewegen... Das ist nämlich gar nicht die Aufgabe der Projektionsmatrix. Ihre Aufgabe ist &amp;quot;das Abbild für die Ausgabe zu manipulieren&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Im Ausgangszustand ([[glLoadIdentity]] wurde für die Projektionsmatrix aufgerufen), gibt die Projektionsmatrix das Bild der Welt unverändert aus. Wenn man '''glTranslate''' auf die Projektionsmatrix anwendet, dann verschiebt man nicht die Welt, sondern sagt der  Projektionsmatrix, dass sie das gesehene Bild verschieben soll. &lt;br /&gt;
&lt;br /&gt;
Befehle wie [[gluPerspective]] und [[glOrtho]] sind typische Befehle zum einstellen der Projektionsmatrix. Diese Befehle bestimmen nämlich in welcher Form die Ausgabe gemacht wird. Entweder perspektivisch verzerrt (gluPerspective) oder durch Parallelprojektion (glOrtho).&lt;br /&gt;
&lt;br /&gt;
Wenn man die Projektionsmatrix manipuliert, ist das vergleichbar mit dem Austauschen des Objektivs bei einer Kamera. Man könnt sogar über die Projektionsmatrix einen &amp;quot;Fischauge&amp;quot; Effekt erzeugen... (Aber fragt mich bitte nicht, wie die Matrix dazu aussieht... ;-) Falls ihrs wißt, einfach im Forum posten. Ich wäre interessiert.)&lt;br /&gt;
&lt;br /&gt;
== GL_MODELVIEW == &lt;br /&gt;
Wie bereits erwähnt ist die Modelviewmatrix die wichtigste Matrix in der OpenGL Welt, denn sie wirkt sich auf Ausrichtung und Position aller Primitive und damit Objekte in der OpenGL Welt aus. Ohne Daten in der Modelviewmatrix, kann die Projektionsmatrix auch nichts ausgeben. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr [[Vertex]]daten  an die Grafikkarte übermittelt solltet ihr die Modelviewmatrix aktiviert haben. Positionsangaben wie z.B. {{INLINE_CODE|glVertex3f(1,0,1);}} beziehen sich auf das aktuelle Koordinatensystem. Das Koordinatensystem ist quasi der Teil der Matrix mit dem ihr arbeitet, und den ihr euch vorstellen könnt (/müßt.).&amp;lt;br&amp;gt;&lt;br /&gt;
Wie ihr bereits wisst kann man mit den Befehlen [[glTranslate]], [[glRotate]] und [[glScale]] das Koordinatensystem manipulieren. Dadurch seit ihr in der Lage beim &amp;quot;bauen&amp;quot; von Objekten mit &amp;quot;lokalen Koordinaten&amp;quot; zu arbeiten. &lt;br /&gt;
&lt;br /&gt;
=== lokale und globale Koordinaten === &lt;br /&gt;
''Worin unterscheiden sich lokale und globale Koordinaten?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Um diese Frage zu klären bedarf es eines kleinen Beispiels: &lt;br /&gt;
&lt;br /&gt;
Stellt euch vor, ihr wollt zwei Würfel zeichnen. Der eine soll um den Punkt (3,4,5)  mit einer Kantenlänge von 1 erstellt werden, der andere soll um den Punkt (1,2,3) mit Kantenlänge 2 und dazu 30° um die Y-Achse gedreht werden. &lt;br /&gt;
&lt;br /&gt;
Wenn man mit '''globalen''' Koordinaten arbeitet lässt man die Matrix so wie sie ist (verzichtet also auf die 3 genannten Befehle) und schreibt die Koordinaten der Eckpunkte per Hand hin: &lt;br /&gt;
&amp;lt;pascal&amp;gt;glBegin(GL_QUADS); &lt;br /&gt;
  //Vorderseite erster Würfel &lt;br /&gt;
  glVertex3f(2,5,6); &lt;br /&gt;
  glVertex3f(2,3,6); &lt;br /&gt;
  glVertex3f(4,3,6); &lt;br /&gt;
  glVertex3f(4,5,6); &lt;br /&gt;
  //Nächste Seite &lt;br /&gt;
  [...] &lt;br /&gt;
&lt;br /&gt;
  //Vorderseite zweiter Würfel &lt;br /&gt;
  glVertex3f(0,3,4); &lt;br /&gt;
  glVertex3f(0,1,4); &lt;br /&gt;
  glVertex3f(2,1,4); &lt;br /&gt;
  glVertex3f(2,3,4); &lt;br /&gt;
  [...] &lt;br /&gt;
&lt;br /&gt;
glEnd; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Bei '''lokalen''' Koordinaten bewegt man zuerst den Koordinatenursprung an die Stelle an die der Würfel entstehen soll, richtet dann wenn nötig die Achsen entsprechend aus, und kann dann '''lokale''' Koordinaten übergeben. Lokal bedeutet hier relativ zum aktuellen Koordinatensystem. &lt;br /&gt;
&lt;br /&gt;
''Aber was soll das für einen Vorteil haben?'' &amp;lt;br&amp;gt; &lt;br /&gt;
Dem ein oder anderen ist vielleicht aufgefallen, dass wir 2x das selbe Objekt zeichnen sollen. Der einzigste Unterschied besteht in der Position, Ausrichtung und Größe/Scalierung. Um Arbeit zu sparen erstellt man deshalb ein Unterprogramm welches einen Einheitswürfel (Kantenlänge 1) rendert, und ruft vor dem zeichnen einfach die passende Kombination aus glTranslate, glRotate und glScale auf: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure zeichneWuerfel; &lt;br /&gt;
begin &lt;br /&gt;
  glBegin(GL_QUADS); &lt;br /&gt;
    glVertex3f(-0.5, 0.5, 0.5); &lt;br /&gt;
    glVertex3f(-0.5,-0.5, 0.5); &lt;br /&gt;
    glVertex3f( 0.5,-0.5, 0.5); &lt;br /&gt;
    glVertex3f( 0.5, 0.5, 0.5); &lt;br /&gt;
    [...] &lt;br /&gt;
  glEnd; &lt;br /&gt;
end; &lt;br /&gt;
&lt;br /&gt;
begin &lt;br /&gt;
  glPushMatrix; &lt;br /&gt;
    glTranslatef(3,4,5); &lt;br /&gt;
    zeichneWuerfel; &lt;br /&gt;
  glPopMatrix; &lt;br /&gt;
  glPushMatrix; &lt;br /&gt;
    glTranslatef(1,2,3); &lt;br /&gt;
    glRotatef(30,0,1,0); &lt;br /&gt;
    glScalef(2,2,2); &lt;br /&gt;
    zeichneWuerfel; &lt;br /&gt;
  glPopMatrix; &lt;br /&gt;
end; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Wie ihr seht, haben lokale Koordinaten den Vorteil, dass man wiederverwendbaren Code schreiben kann. Bei globalen Koordinaten muss für jedes Objekt eigener Code geschrieben werden (und wenn sich das Objekt bewegt dann wieder...).&lt;br /&gt;
&lt;br /&gt;
Dreimal dürft ihr raten, welche Methode häufiger verwendet wird. ;-) &lt;br /&gt;
{{Hinweis|Modeller wie 3D Studio Max benutzen globale Koordinaten beim exportieren der Modelle. Dies hat den Vorteil, dass beim importieren einer ganzen 3DS Szene, die Objekte gleich an der richtigen Position stehen, und nicht erst ausgerichtet werden müssen.}} &lt;br /&gt;
&lt;br /&gt;
== GL_TEXTURE == &lt;br /&gt;
Dieser Matrix sollte endlich mehr Aufmerksamkeit geschenkt werden. Sie kann nämlich mit den Texturen in der Szene einiges anfangen... &lt;br /&gt;
&lt;br /&gt;
Aber der Reihe nach: &lt;br /&gt;
&lt;br /&gt;
Wie ihr vielleicht schon im [[Tutorial_lektion4|Einsteigertutorial 4 - Texturen]] gelesen habt, sind Texturkoordinaten immer so, dass {{INLINE_CODE|[[glTexCoord2f]](0,0)}} die obere linke Ecke und {{INLINE_CODE|glTexCoord2f(1,1)}} die untere Rechte Ecke der Textur betrifft. Wie die Textur außerhalb dieses Bereichs aussieht bestimmt ihr mittels [[glTexParameter]] und dem Parametern '''GL_TEXTURE_WRAP_S''' und '''GL_TEXTURE_WRAP_T'''. &lt;br /&gt;
&lt;br /&gt;
Nun stellt euch einmal vor, ihr habt 2 Quads die beide die selbe Textur bekommen sollen. Einziger Unterschied ist, dass bei dem einen Quad der Inhalt der Textur um 20° in Uhrzeigerrichtung gedreht ist. Blöd, oder? Das heißt ja jetzt, dass ihr in eurem Zeichenprogramm eine weitere Textur erstellen müßt, um das zweite Quad zu texturieren oder die Texturkoordinaten per Hand ändern müsst. &amp;lt;br&amp;gt; &lt;br /&gt;
'''STOP!''' Ihr hab es sicherlich schon mitbekommen: Dieses Szenario kann leicht mit der Texturmatrix gelößt werden. Und zwar so... &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure drawTexturedQuad; &lt;br /&gt;
begin &lt;br /&gt;
  glBegin(GL_QUADS); &lt;br /&gt;
    glTexCoord(0,0); glVertex3f(-1, 1,0); &lt;br /&gt;
    glTexCoord(0,1); glVertex3f(-1,-1,0); &lt;br /&gt;
    glTexCoord(1,1); glVertex3f( 1,-1,0); &lt;br /&gt;
    glTexCoord(1,0); glVertex3f( 1, 1,0); &lt;br /&gt;
  glEnd; &lt;br /&gt;
end; &lt;br /&gt;
&lt;br /&gt;
begin &lt;br /&gt;
  glMatrixMode(GL_MODELVIEW); &lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, texID); &lt;br /&gt;
  glTranslatef(-2,0,0); &lt;br /&gt;
  drawTexturedQuad; &lt;br /&gt;
&lt;br /&gt;
  glMatrixMode(GL_TEXTURE); &lt;br /&gt;
  glRotatef(20,0,0,1); &lt;br /&gt;
&lt;br /&gt;
  glMatrixMode(GL_MODELVIEW); &lt;br /&gt;
  glTranslatef(4,0,0); &lt;br /&gt;
  drawTexturedQuad; &lt;br /&gt;
end;&amp;lt;/pascal&amp;gt; &lt;br /&gt;
''Was ist hier geschehn? ''&amp;lt;br&amp;gt;&lt;br /&gt;
Durch die vorherige Aktivierung der Texturmatrix wirkt sich das nachfolgende glRotate nicht auf die Modelle der Szene sondern auf die Texturkoordinaten aus. Auf gut deutsch: OpenGL dreht vor dem rendern des zweiten Quads die Textur um 20°. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr beim rotieren der Texturmatrix, bei jedem Renderdurchlauf den Winkel um ein Stück erhöht passiert was?... Richtig! Eure Textur dreht sich auf eurem Quad... Das is dann quasi eure erste Animation... Und das ohne ein Objekt zu bewegen... Cool, oder?&lt;br /&gt;
&lt;br /&gt;
= Auswirkungen von Matrixmanipulationen - oder &amp;quot;Wie positioniere ich meine Objekte richtig?&amp;quot;= &lt;br /&gt;
In diesem Teil des Tutorials möchte ich euch zeigen wie die 3 Befehle '''glTranslate, glRotate''' und '''glScale''' eure aktuelle Matrix verändern. Ich bleibe hierbei im 2 dimensionalen Raum, da sonst die Skizzen zu unübersichtlich werden. (Die Befehle sind dabei natürlich die selben wie für 3D Manipulationen. Ich ignoriere nur einfach immer die Y-Angaben.) &lt;br /&gt;
&lt;br /&gt;
Zuersteinmal zum warm werden: &amp;lt;br&amp;gt; &lt;br /&gt;
[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|So stelle ich mir eine 2D-Matrix vor.]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==glTranslate== &lt;br /&gt;
{{INLINE_CODE|[[glTranslate]](a,b,c)}} verschiebt den Koordinatenursprung des aktuellen Koordinatensystems um ''a'' Einheiten in die Richtung der X-Achse, um ''b'' Einheiten in die Richtung der Y-Achse und um ''c'' Einheiten in die Richtung der Z-Achse. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Matrix2 Translate.png|framed|center|Das passiert bei einer Translation um 3.5 Einheiten in X und -3 Einheiten in Z-Richtung.]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==glRotate== &lt;br /&gt;
{{INLINE_CODE|[[glRotate]](w,x,y,z)}} rotiert das Koordinatensystem um ''w'' Grad um die Rotationsachse welche durch (0,0,0) und (''x,y,z'') verläuft. '''glScale richtet also die Achsen neu aus.''' (Die Richtung der Achsen ist z.B. wichtig für glTranslate) &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Matrix2 Rotate.png|framed|center|Das passiert bei einer Rotation um 45° mit der Y-Achse als Rotationsachse.]] &lt;br /&gt;
&lt;br /&gt;
==glScale== &lt;br /&gt;
{{INLINE_CODE|[[glScale]](x,y,z)}} skaliert die Maße der Koordinatenachsen (Bestimmt also wie lange &amp;quot;eine Einheit&amp;quot; wirklich ist). Wenn ''x,y'' oder ''z'' größer als 1 ist, werden die Maßeinheiten der entsprechenden Achse gestreckt, wenn die Werte kleiner 1 sind gestaucht. (Wenn die Werte gleich 0 sind verschwindet die Szene auf nimmer wieder sehn(, da hilft dann nur noch glLoadIdentity um die Matrix wieder nutzbar zu machen), sind die Werte gleich 1 verändert sich nichts.) &lt;br /&gt;
&lt;br /&gt;
''x,y'' und ''z'' muss man sich als Prozentangaben vorstellen. Will man die Szene in X-Richtung um das doppelte (also 200%) vergrößern/strecken muss ''x'' gleich 2 sein. Will man die Y-Richtung auf ein Zehntel (also 10%) verkürzen/stauchen muss ''y'' gleich 0.1 sein. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Matrix2 Scale.png|framed|center|Das passiert bei einer Skalierung. Wie ihr seht, sind die Seiten unterschiedlich skaliert worden (X-Achse: 80%, Z-Achse: 60%).]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Kombination - Translate vor Rotate== &lt;br /&gt;
Wird Translate vor Rotate aufgerufen, bewegt sich der Koordinatenursprung zuerst an den Zielpunkt (über glTranslate angegeben). Anschließend werden die Achsen neu ausgerichtet (durch glRotate). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glTranslatef(3.5,0,-3); &lt;br /&gt;
  glRotatef(45, 0, 1, 0); &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glTranslate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Translate.png|framed|center|Nachdem glTranslate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 TranslateRot.png|framed|center|Nachdem glRotate aufgerufen wurde. Man sieht, dass die jeweils vorhergehende Veränderung bestehend bleibt, und die Basis für die nachfolgende Änderung bildet.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird der Winkel von glRotate bei jedem Renderdurchlauf erhöht, dreht sich ein anschließend gezeichnetes Objekt um die durch glTranslate angegeben Position. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Kombination - Rotate vor Translate== &lt;br /&gt;
Wird Rotate vor Translate aufgerufen, werden zuerst die Achsen neu ausgerichtet und dann der Koordinatenursprung bezüglich dieser neuen Achsen verschoben. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glRotatef(45, 0, 1, 0); &lt;br /&gt;
  glTranslatef(3.5,0,-3);   &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glRotate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Rotate.png|framed|center|Nachdem glRotate aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 RotateTrans.png|framed|center|Nachdem glTranslate aufgerufen wurde. Man sieht, dass die vorhergehende Rotation die Verschieberichtung beeinflusst.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Wird der Winkel von glRotate bei jedem Renderdurchlauf erhöht, bewegt sich ein nach glTranslate gezeichnetes Objekt auf einer Kreisbahn um den Koordinatenursprung wie er beim Aufruf von glRotate aktuell war. Der Radius der Kreisbahn wird durch glTranslate bestimmt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn man die beiden Ergebnisse direkt vergleicht sieht man, dass die Reihenfolge von Bedeutung für das Ergebniss ist. Das die Unterschiede so &amp;quot;klein&amp;quot; ausfallen liegt nur daran, dass bei rotate nicht mit größeren Winkeln rotiert wurde. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 RotateTrans.png|framed|center|Erst Rotiert]] &lt;br /&gt;
|- &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 TranslateRot.png|framed|center|Erst Verschoben]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Kombination - Scale vor Rotate== &lt;br /&gt;
Die Rotation wird nur von der Richung, nicht aber der Länge der Achsen beeinflusst. Der Winkel um den gedreht wird, bleibt von der Skalierung unberührt (45° bleiben 45°. Die Achsen zeigen anschließend jeweils in die gleiche Richtung) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glScalef(0.8, 1, 0.6); &lt;br /&gt;
  glRotatef(45, 0, 1, 0); &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Scale.png|framed|center|Nachdem glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 ScaleRot.png|framed|center|Nachdem glRotate aufgerufen wurde. Man sieht, dass die Skalierung den Winkel nicht beeinflusst. Das Koordinatensystem wurde korrekt um 45° gedreht.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Der direkte Vergleich zeigt, dass die Skalierung keinen Effekt auf den Winkel hatte. Beide Koordinatensysteme sind gleich ausgerichtet: &lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 Rotate.png|framed|center|Unskaliert]] &lt;br /&gt;
|- &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 ScaleRot.png|framed|center|Skaliert]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Kombination - Scale vor Translate== &lt;br /&gt;
Die Verschiebung ist Abhängig von der Ausrichtung der Achsen (glRotate) und der Maße der Achsen (glScale). Aus diesem Grunde beeinflusst glScale die nachfolgenden Translationen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|Folgender Code wird demonstriert: &lt;br /&gt;
&amp;lt;pascal&amp;gt; &lt;br /&gt;
  glScalef(0.8, 1, 0.6); &lt;br /&gt;
  glTranslatef(3.5,0,-3); &lt;br /&gt;
  ZeichneKoordinatensystem; &lt;br /&gt;
&amp;lt;/pascal&amp;gt; &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Ausgangsbild.png|framed|center|Bevor glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 Scale.png|framed|center|Nachdem glScale aufgerufen wurde.]] &lt;br /&gt;
|- &lt;br /&gt;
|[[Bild:Tutorial Matrix2 ScaleTrans.png|framed|center|Nachdem glTranslate aufgerufen wurde.]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Der direkte Vergleich zeigt, dass sich die Skalierung auf die Verschiebung auswirkt. Denn obwohl der Verschiebung in die gleiche Richtung und um den selben Wert erfolgt, sind die Resultate nicht identisch. Dies liegt daran, dass glScale die Maße verändert hat. Die Verschiebung in X-Richtung erreicht dadurch nur 80% und in Z-Richtung sogar nur 60% der unskalierten Transformation: &lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; &lt;br /&gt;
{|{{Prettytable}} &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 Translate.png|framed|center|Unskaliert]] &lt;br /&gt;
|- &lt;br /&gt;
|width=&amp;quot;50%&amp;quot; | [[Bild:Tutorial Matrix2 ScaleTrans.png|framed|center|Skaliert]] &lt;br /&gt;
|}&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Nachwort= &lt;br /&gt;
7 Stunden sind vorbei und das Tutorial ist auf eine ordentliche Länge angewachsen. Ich hoffe ich konnte euch die OpenGL Matrizen etwas näher bringen. &lt;br /&gt;
&lt;br /&gt;
Wer jetzt denkt ''&amp;quot;Bilder sind mir zu statisch!&amp;quot;'', dem möchte ich noch diese Programme ans Herz legen: &lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable}}&lt;br /&gt;
!Name&lt;br /&gt;
!Hersteller&lt;br /&gt;
!Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.delphigl.com/forum/viewtopic.php?p=37378#37378 '''Matrix2 - Skizzenrenderer''']&lt;br /&gt;
|Flash&lt;br /&gt;
|Dieses Programm habe ich geschrieben um die Skizzen für dieses Tutorial zu erstellen. Es wurde so modifiziert, dass man beliebige Kombinationen von glTranslate, glRotate und glScale anzeigen kann. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.phobeus.de/hosting/pixelpracht/main.php?s=opengl&amp;amp;t=1&amp;amp;p=2 '''Matrix Control''']&lt;br /&gt;
|Lithander&lt;br /&gt;
|Das Programm erlaubt euch zu beobachten, wie die Matrizen sich bei den einzelnen Befehlen verändern und wie die Ausgabe aussieht. Besonderheit an diesem Programm ist, dass ihr die Matrizen auch per Hand manipulieren könnt.&lt;br /&gt;
|}&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten immer noch Unklarheiten bestehen bleibt das Forum natürlich auch weiterhin die Anlaufstelle Nummer1. Dies betrifft auch euer Feedback zum Tutorial. &lt;br /&gt;
&lt;br /&gt;
MfG &lt;br /&gt;
: Flash ('''Kevin Fleischer''') &lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_2D]]|-}} &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Matrix2]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Matrix&amp;diff=21493</id>
		<title>Matrix</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Matrix&amp;diff=21493"/>
				<updated>2008-04-12T21:53:49Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Tippfehler&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Matrix / Matrizen==&lt;br /&gt;
&lt;br /&gt;
===Übersicht===&lt;br /&gt;
Eine Matrix ist im wesentlichen nichts anderes als das, was man in der Programmierung als zweidimensionales Array kennt. Dabei beschreibt eine Matrix eine [http://de.wikipedia.org/wiki/Lineare_Abbildung lineare Abbildung], was als Information bei Rechnungen sehr wichtig ist.&lt;br /&gt;
&lt;br /&gt;
'''Wichtig:''' Für den Einstieg in OpenGl ist ein tiefergehendes Verständnis von Matrizen noch nicht notwendig um bereits interessante Ergebnisse zu erzielen. Es genügt am Anfang zu wissen, daß man damit Verscheibungen, Drehungen und Streckungen beschreiben kann und daß die Reihenfolge der Befehle zum Manipulieren der Matrix wichtig ist. Wer also noch seine ersten Erfahrungen mit OpenGl macht, kann sich zuerst in unseren [[Tutorial|Tutorials]] informieren und erst anschließend hier wieder vorbeischauen.&lt;br /&gt;
&lt;br /&gt;
'''Anmerkung:''' Wir wollen mit den Definitionen hier nur soweit gehen, wie es für ein Verständnis von OpenGl Geometrie wichtig ist. In der Linearen Algebra werden einige der hier gegebenen Begriffe deutlich genauer und häufig auch abstrakter betrachtet. Dies würde jedoch unseren kleinen Rahmen deutlich sprengen.&lt;br /&gt;
&lt;br /&gt;
===Definition===&lt;br /&gt;
Matrizen sind Abbildungen auf Vektorräumen ganzzahliger Dimension. Für alle weiteren Betrachtungen seien deshalb die Zahlen n,m und r aus dem Bereich {1,2,3,4,5,...}, also den natürlichen Zahlen ohne Null, fest vorgegeben.&lt;br /&gt;
&lt;br /&gt;
====R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; Vektorräume====&lt;br /&gt;
Um Matrizen definieren zu können, müssen wir zuerst Vektorräume definieren. Ein Vektorraum (V,*,+) ist eine Menge Vektoren V zusammen mit einer Skalar-Multiplikation * und einer Addition auf Vektoren, auf denen man vernünftig Vektorrechnung betreiben kann.&lt;br /&gt;
&lt;br /&gt;
Hat man also zwei Vektoren v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; und v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;, so kann man diesen eindeutig eine Summe zuordnen: &lt;br /&gt;
 v&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt; = v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; + v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; .&lt;br /&gt;
 &lt;br /&gt;
Ausserdem kann man sie mit einem Skalar c aus den reelen Zahlen strecken: &lt;br /&gt;
 v&amp;lt;sub&amp;gt;4&amp;lt;/sub&amp;gt; = c*v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Beispiel''': Der Standardvektorraum R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt;:&lt;br /&gt;
Ein Vektor v aus dem R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; besteht aus n reelen Zahlen ( seinen Komponenten ), deren Reihenfolge wichtig ist. Man kann also v auch in Form seiner Komponenten schreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Vektorkomponenten.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Häufig wird kein Unterschied dahingehend gemacht, ob der Vektor als Zeile oder als Spalte geschrieben wird. Bei der später definierten Matrixmultiplikation wird dies jedoch durchaus interessant, wir wollen uns also erstmal darauf beschränken, daß auch die Schreibweise&lt;br /&gt;
 v=(v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,...,v&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;)&lt;br /&gt;
für unseren Vektor v eine legitime, als Text einfacher verfassbare Schreibweise darstellt. Bei der später definierten Multiplikation mit einer Matrix der Vektor aber immer als Spalte betrachtet wird.&lt;br /&gt;
&lt;br /&gt;
Um unseren Vektorraum zu vervollständigen, brauchen wir nach Definition nun auch noch eine Addition und eine (Skalar-)Multiplikation. Die Addition geschieht komponentenweise. Hat man also einen zweiten Vektor b = v=(b&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,...,b&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;), so ist die Addition definiert durch:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Vektoraddition.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Die Multiplikation eines Vektors v mit einem reellen Faktor &amp;amp;lambda; entspricht einer Streckung des Vektors um &amp;amp;lambda;, was durch Multiplikation aller Komponenten von v mit &amp;amp;lambda; erreicht wird:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Vektorskalarmultiplikation.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Es ergeben sich die von den normalen reelen Zahlen bekannten Rechenregeln:&lt;br /&gt;
 &amp;amp;lambda;*( v + b ) = &amp;amp;lambda;*v + &amp;amp;lambda;*b , &lt;br /&gt;
d.h. man kann Skalare einfach aus Klammern ausmultiplizieren oder wieder hineinziehen. Man beachte aber, daß die Multiplikation von Vektoren mit Vektoren nicht definiert ist( Siehe auch [[Vektorprodukt]], [[Standard Skalarprodukt]] ) .&lt;br /&gt;
&lt;br /&gt;
Ist unser n gerade die Zahl 3 bzw. 2, so kann man durch den R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; gerade den 3-Dimensionalen bzw. 2-Dimensionalen Anschauungsraum darstellen. Vektoren kann man dann sogar zeichnen und bekommt eine bildliche Vorstellung. Vektoren werden zu einer Darstellung von Pfeilen, die eine Richtung beschreiben oder ausgehend vom Nullpunkt des Koordinatensystems einen Punkt definieren:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Vektorvorstellung.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
====Lineare Abbildungen auf dem R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; in den R&amp;lt;sup&amp;gt;m&amp;lt;/sup&amp;gt;====&lt;br /&gt;
Weiter kann man Abbildungen f, die als Parameter Vektoren des R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; annehmen und diese in den R&amp;lt;sup&amp;gt;m&amp;lt;/sup&amp;gt; abbilden, definieren. Insbesondere kann man Abbildungen definieren, die linear sind, d.h. daß f folgende Eigenschaften erfüllt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Lineare Abbildungen.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
und zwar für alle a,b aus R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; und alle &amp;amp;lambda; aus den reellen Zahlen R. Interessant ist, daß solche Abbildungen die Rechenregeln aus unserer Vektorraumdefinition erhalten. Sehr wichtig ist jedoch: Solche Abbildungen existieren. Die einfachste ist die, die alle Vektoren aus R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt;&lt;br /&gt;
auf die 0 abbildet ( die 0 ist der Vektor des R&amp;lt;sup&amp;gt;m&amp;lt;/sup&amp;gt;, in dem alle Komponenten gleich 0 ist. ). Tatsächlich gibt es deutlich mehr dieser Abbildungen und alle lassen sich als Matrizen darstellen. Und umgekehrt: Mit Matrizen lassen sich alle lineare Abbildungen auf unseren Vektorräumen beschreiben.&lt;br /&gt;
&lt;br /&gt;
====mxn-Matrizen und ihre Anwendung auf Vektoren====&lt;br /&gt;
Wie bereits angesprochen, sind Matrizen also 2 Dimensionale Felder aus rellen Zahlen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:mxnMatrix.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Die a&amp;lt;sub&amp;gt;ij&amp;lt;/sub&amp;gt; werden dann die Koeffizienten der Matrix genannt. Nun wollen wir das Anwenden der Matrix A aus R&amp;lt;sup&amp;gt;mxn&amp;lt;/sup&amp;gt; auf einen Vektor x definieren:&lt;br /&gt;
&lt;br /&gt;
[[Bild:mxnMatrixAnwendungaufx.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Beispiel: &lt;br /&gt;
[[Bild:AnwendungsbeispielMatrizen.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Am Bild erkennt man auch, warum die Matrix-Vektor Multiplikation ( &amp;quot; Anwendung &amp;quot; ) auch als Zeile mal Spalte bezeichnet wird, denn die Koeffizienten einer Zeile der Matrix werden der Reihe nach mit den Koeffizienten der &amp;quot;Spalte&amp;quot; des Vektors multipliziert. Dieses Verfahren kann man erweitern, indem man Vektoren als Matrizen interpretiert, die nur eine Spalte haben. Schreibt man mehrere Vektoren nebeneinander, kann man auf jede dieser Spalten die Matrix A darauf anwenden:&lt;br /&gt;
&lt;br /&gt;
====mxn-nxr-Matrix-Matrix Multiplikation====&lt;br /&gt;
Man hat also eine mxn-Matrix A und eine nxr-Matrix B, die man Spaltenweise als Vektoren versteht:&lt;br /&gt;
&lt;br /&gt;
[[Bild:zerlegungMatrixInEinzelvektoren.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Bei der Multiplikation von A mit B, wird dann einfach A auf die Vektoren b&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; angewendet.&lt;br /&gt;
&lt;br /&gt;
[[Bild:MatrixMatrixMultiplikation.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
[[Bild:MatrixMatrixMultiplikationBeispiel.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
====Eigenschaften====&lt;br /&gt;
Diese Multiplikation hat eine Reihe von Eigenschaften:&lt;br /&gt;
* Versteht man die Matrizen A,B als lineare Abbildungen auf Vektoren x aus dem R&amp;lt;sup&amp;gt;n&amp;lt;/sup&amp;gt; und y aus R&amp;lt;sup&amp;gt;r&amp;lt;/sup&amp;gt;, also f(x) = A*x und g(y) = B*y und ist A eine mxn-Matrix, sowie B eine nxr Matrix, dann ist die Abbildung f(g(y)) eine Lineare Abbildung, die beschrieben ist durch &lt;br /&gt;
 f(g(y)) = A*B*y .&lt;br /&gt;
* Daraus ergibt sich, da schon die Definitions-Vektorräume verschieden sind, daß in den meisten Fällen nicht gilt: A*B=B*A . Wer sich dies genauer überlegt, stellt fest, daß das 2. Produkt nur dann definiert ist, wenn A und B beides nxn-Matrizen sind. Aber selbst in diesem Fall ist es im Allgemeinen ein Unterschied, ob ich A*B oder B*A rechne ( Das führt schließlich zu der Tatsache, warum man in OpenGl aufpassen muss, ob man zuerst rotiert und dann verschiebt oder umgekehrt: Diese Operationen werden durch Matrizenmultiplikationen implementiert! ).&lt;br /&gt;
&lt;br /&gt;
* Matrizen stellen Lineare Abbildungen dar, es gilt also:&lt;br /&gt;
 A*(x+x') = A*x + A*x'&lt;br /&gt;
 A*(B+C) = A*B + A*C &lt;br /&gt;
 A*(&amp;amp;lambda;*x) = &amp;amp;lambda;*A*x&lt;br /&gt;
* Man nennt eine Gleichung A*x = b ein Lineares Gleichungssystem, wenn A und b bekannt und x gesucht ist. Es interessiert dann, ob es eine Lösung gibt und welche das ( sofern sie eindeutig ist ) ist.&lt;br /&gt;
&lt;br /&gt;
===Siehe Auch===&lt;br /&gt;
Es gibt noch eine Menge weiterer Eigenschaften, und Funktionen, die in Bezug auf Matrizen höchst interessant sind:&lt;br /&gt;
&lt;br /&gt;
[[Matrix_Transposition]], [[Determinante]], [[Matrix_Inversion]], [[Gauss_Algorithmus]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Matrizen in OpenGl==&lt;br /&gt;
===Die drei OpenGL Matrizen===&lt;br /&gt;
In OpenGL gibt es drei 4x4-Matrizen welche alle mit Hilfe von [[glTranslate]], [[glScale]], [[glRotate]],[[glMultMatrix]],[[glLoadMatrix]] und [[glLoadIdentity]] bearbeitet werden können. Welche Matrix von diesen Funktionen beeinfusst wird, kann durch [[glMatrixMode]] gesteuert werden.&lt;br /&gt;
&lt;br /&gt;
Die 3 Matrizen sind:&lt;br /&gt;
&lt;br /&gt;
====GL_PERSPECTIVE====&lt;br /&gt;
&lt;br /&gt;
Sollte nur für die Festlegung der Perspektive genutzt werden.&lt;br /&gt;
&lt;br /&gt;
====GL_MODELVIEW==== &lt;br /&gt;
&lt;br /&gt;
Legt Position und Größe des zu zeichnenden Primitiven fest&lt;br /&gt;
&lt;br /&gt;
====GL_TEXTURE====&lt;br /&gt;
&lt;br /&gt;
Beinhaltet Informationen wie Texturen dargestellt werden.&lt;br /&gt;
&lt;br /&gt;
Noch mehr Informationen zu den Matrizen und was sie bewirken gibts im [[Tutorial Matrix2]].&lt;br /&gt;
&lt;br /&gt;
===Aufbau einer OpenGL-Matrix===&lt;br /&gt;
&lt;br /&gt;
Möchte man mit OpenGL an einer bestimmten Stelle etwas zeichnen, so kann man mit Hilfe von [[glTranslate]] und [[glRotate]] die Modelview-Matrix so manipulieren, dass etwa der mit [[glVertex]] übergebene Eckpunkt (0/0/0) im Weltkoordinaten System nicht mehr in der Mitte liegt. Alle Punkte erscheinen scheinbar in einen zweiten Koordinaten System welches etwas verdreht, vegrößert oder verrutsch liegen kann.&lt;br /&gt;
&lt;br /&gt;
Dieses zweite Koordinaten-System wird durch eine 4x4-Matrix, also einem zwei dimensionenlen Array mit vier Spalten und Zeilen, beschrieben.&lt;br /&gt;
&lt;br /&gt;
Damit besser verstanden werden kann, wie dies funktioniert, wird die Funktionsweise anhand eines zwei dimensionalen Koordinaten System demonstiert.&lt;br /&gt;
&lt;br /&gt;
Möchte man in einem einfachen 2D Koordiaten-System den Punkt (X/Y) antragen, so hängt man X mal den Vektor der X-Achse aneinander, und Y mal den Vektor der Y-Achse.&lt;br /&gt;
&lt;br /&gt;
[[Bild:KoordinatenSystemA.png]]&lt;br /&gt;
&lt;br /&gt;
Um die Lage und Größe eines Koordinatensystems zu beschreiben werden also einmal die Vektoren benötiget die 1 '''L'''ängen '''E'''inheit meiner Achsen beschreiben, sowie ein Vektor der ihre Position in Anhängigkeit zum übergeordneten Koordinatensystems beschreibt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:KoordinatenSystemB.png]]&lt;br /&gt;
&lt;br /&gt;
Wie bereits bemerkt, müssten die Matrizen eigentlich 3x3-Matrizen sein, da sie ja auf dem 3D-Raum operieren sollen. Damit lassen sich jedoch keine Verschiebungen beschreiben, weswegen man bei der übergabe von Vertexdaten mit [[glVertex]] im Hintergrund eine 4. Koordinate &lt;br /&gt;
w neben (x,y,z) einführt. Diese hat, wenn nicht explizit über glVertex4x angegeben, den Wert 1 und so lassen sich mit 4x4 Matrizen auch Verschiebungen beschreiben:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| X || X || X || X || |&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| Y || Y || Y || Y || |&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| Z || Z || Z || Z || |&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| W || W || W || W || |&lt;br /&gt;
|}&lt;br /&gt;
So wirkt jede Zeile der OpenGl-Matrix auf genau die entsprechende &lt;br /&gt;
Koordinate des Vertex nach der Multiplikation mit einem Vertex (x,y,z,1). Ist die letzte Zeile der Matrix (0,0,0,1), hat also die Matrix die Form:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| X || X || X || X || |&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| Y || Y || Y || Y || |&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| Z || Z || Z || Z || |&lt;br /&gt;
|- align=&amp;quot;center&amp;quot;&lt;br /&gt;
| 0 || 0 || 0 || 1 || |&lt;br /&gt;
|}&lt;br /&gt;
Dann beschreibt die letzte Spalte der Matrix gerade die Verschiebung unseres Vertices, wie man mit der oben definierten Anwendung einer Matrix auf einen Vektor leicht überprüft. Am Ende wird die w-Koordinate, sofern sie 1 ist, wieder verworfen - was sie auch bleibt, denn die letzte Zeile der OpenGl Matrix ist gerade so gewählt, daß dies sichergestellt ist. Nur bei der endgültigen Darstellung auf den Monitor kommt der w-Koordinate noch eine weitere Bedeutung zu, weshalb Projektionsmatrizen ( erzeugt durch [[glOrtho]], [[glFrustum]], ... ) sich an Regel der letzten Zeile (0,0,0,1) nicht halten. &lt;br /&gt;
&lt;br /&gt;
Folgendes Format könnte man nutzen, um eine Matrix mit [[glGetFloatv]] auszulesen oder mit [[glLoadMatrix]] zu setzen.&lt;br /&gt;
&lt;br /&gt;
 TVektor = '''record''' X,Y,Z,W:glFloat '''end''';&lt;br /&gt;
 TMatrix = '''array'''[(mat_XAchse,mat_YAchse,mat_ZAchse,mat_Position)]'''of''' TVektor;&lt;br /&gt;
 PMatrix = ^TMatrix;&lt;br /&gt;
&lt;br /&gt;
Man beachte dabei, daß OpenGl Matrizen '''Spaltenweise''' im Speicher ablegt sind. Siehe dazu auch: [[glMultMatrix]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
===Berechnungen===&lt;br /&gt;
&lt;br /&gt;
====Anwenden einer Matrix auf einen Vektor/Punkt====&lt;br /&gt;
&lt;br /&gt;
Möchte man zum Beispiel wissen wie ein Punkt im übergeordneten Koordinaten-System aussieht, so kann man das folgendermaßen ausrechnen (wie dies zu Berechnen ist kann auch der obigen Zeichung entnommen werden (w wird nicht beachtet)):&lt;br /&gt;
&lt;br /&gt;
 ErgebnisVektor=X*XAchsenVektor + Y*YAchsenVektor + Z*ZAchsenVektor + PositionsVektor&lt;br /&gt;
&lt;br /&gt;
Ausführlich sähe dies dann so aus:&lt;br /&gt;
&lt;br /&gt;
 Ergebnis.X=X*XAchse.X + X*YAchse.X + X*ZAchse.X + Position.X;&lt;br /&gt;
 Ergebnis.Y=Y*XAchse.Y + Y*YAchse.Y + Y*ZAchse.Y + Position.Y;&lt;br /&gt;
 Ergebnis.Z=Z*XAchse.Z + Y*YAchse.Z + Y*ZAchse.Z + Position.Z;&lt;br /&gt;
&lt;br /&gt;
====Matrizen multiplizieren====&lt;br /&gt;
&lt;br /&gt;
Das Multiplizieren, also das Hintereinanderausführen von zwei Matrizen ist einfach, wenn man weis, wie man Vektoren auf Matrizen anwendet und dass (in OpenGL) Matrizen aus in die Spalten geschriebenen Vektoren bestehen. Man braucht nämlich nur auf alle Spalten einer Matrix die andere Matrix anwenden und erhält so eine neue Matrix. Wichtig bei der Matrizenmultiplikation ist auch die &amp;quot;Reihenfolge&amp;quot;, also welche Matrix auf die Spalten der jeweils Anderen angewendet wird (erst drehen dann verschieben oder erst verschieben und dann drehen macht einen Unterschied). &lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix===&lt;br /&gt;
Ist eine Matrix mit folgenden Werten:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|rowspan=4 valign=&amp;quot;middle&amp;quot; |&amp;lt;font style=&amp;quot;font-size:30pt&amp;quot;&amp;gt;{&amp;lt;/font&amp;gt;&lt;br /&gt;
| 1 || 0 || 0 || 0&lt;br /&gt;
|rowspan=4 valign=&amp;quot;middle&amp;quot; |&amp;lt;font style=&amp;quot;font-size:30pt&amp;quot;&amp;gt;}&amp;lt;/font&amp;gt;   &lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || 0 || 0&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || 1 || 0&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || 0 || 1&lt;br /&gt;
|-   &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wendet man auf einen Vektor eine solche Matrix an, so bleibt der Vektor gleich.&lt;br /&gt;
&lt;br /&gt;
Um die aktuelle Matrix zur einer Identitätsmatrix zu machen, ruft man [[glLoadIdentity]] auf.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Zum leichteren Verständnis===&lt;br /&gt;
''Dieser Abschnitt ist nicht für fortgeschrittene 3D Entwickler gedacht, sollte aber Anfängern die immer noch nicht wissen, was Matrizen eigentlich in OpenGL machen einen leichteren Einblick verschaffen.''&lt;br /&gt;
&lt;br /&gt;
Um sich Matrizen in OpenGL leichter vorzustellen, kann man folgendes Bild benutzen:&lt;br /&gt;
&lt;br /&gt;
* Die 3D-Welt ist in einer Art Glaskasten abgelegt in dem es keine Physik gibt (Dinge können in der Luft schweben u.ä.).&lt;br /&gt;
* Matrizen sind Maschinen/Greifarme.&lt;br /&gt;
* Matrizen sind die einzige Möglichkeit in den Glaskasten hinein zu greifen.&lt;br /&gt;
&lt;br /&gt;
Wie wir weiter oben bereits gelernt haben sind Matrizen ja eigentlich Tabellen mit Zahlen. Diese Zahlen sind die Stellschrauben an unseren &amp;quot;Greifarmen&amp;quot;. Mit diesen Stellschrauben können wir die Greifarme im Glaskasten positionieren. Durch den OpenGL-Befehl [[glMatrixMode]] können wir auswählen welchen der beiden Arme wir gerade steuern. &lt;br /&gt;
&lt;br /&gt;
'''ModelView - Der Objektmanipulator'''&lt;br /&gt;
: Wird diese Matrix auf ein Objekt angewendet, ändert sich je nach Einstellung der Matrix dessen Position, Ausrichtung, Größe usw. (Man kann sogar den kompletten Glaskasten damit verschieben.)  (Beispiel: Wirft man einen Würfel in eine Drehungsmatrix, kommt am Ende ein gedrehter Würfel raus.)&lt;br /&gt;
&lt;br /&gt;
'''PerspectivMatrix - Die Kameralinse'''&lt;br /&gt;
: Diese Maschine ist nur für die Ausgabe zuständig. Man kann über die Stellschrauben einstellen, welche Art der Projektion (Parallel-, Perspektivisch-,...), und wie nah und wie weit Objekte maximal von der Kamera entfernt sein dürfen, um sichtbar zu sein.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf den Geschmack gekommen ist und mittels [[glLoadMatrix]] mal selber die Stellschrauben einer der beiden Matrizen ändern möchte, der sollte sich das sehr gute '''Mathe Script''' zum Thema '''Computer Geometrie''' einmal ansehen (siehe Links). Das eben vermittelte Bild mag zwar helfen. Die Theorie muss aber verstanden werden um damit arbeiten zu können.&lt;br /&gt;
&lt;br /&gt;
===Zugehörige Wertrückgaben===&lt;br /&gt;
&lt;br /&gt;
Inhalt einer Matrix:&lt;br /&gt;
*[[glGet#GL_MODELVIEW_MATRIX|glGet]] mit GL_MODELVIEW_MATRIX&lt;br /&gt;
*[[glGet#GL_PROJECTION_MATRIX|glGet]] mit GL_PROJECTION_MATRIX&lt;br /&gt;
*[[glGet#GL_TEXTURE_MATRIX|glGet]] mit GL_TEXTURE_MATRIX&lt;br /&gt;
&lt;br /&gt;
Aktive Matrix:&lt;br /&gt;
*[[glGet#GL_MATRIX_MODE|glGet]] mit GL_MATRIX_MODE&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Zum leichteren Verständnis===&lt;br /&gt;
''Dieser Abschnitt ist nicht für fortgeschrittene 3D Entwickler gedacht, sollte aber Anfängern die immer noch nicht wissen, was Matrizen eigentlich in OpenGL machen einen leichteren Einblick verschaffen.''&lt;br /&gt;
&lt;br /&gt;
Um sich Matrizen in OpenGL leichter vorzustellen, kann man folgendes Bild benutzen:&lt;br /&gt;
&lt;br /&gt;
* Die 3D-Welt ist in einer Art Glaskasten abgelegt in dem es keine Physik gibt (Dinge können in der Luft schweben u.ä.).&lt;br /&gt;
* Matrizen sind Maschinen/Greifarme.&lt;br /&gt;
* Matrizen sind die einzige Möglichkeit in den Glaskasten hinein zu greifen.&lt;br /&gt;
&lt;br /&gt;
Wie wir weiter oben bereits gelernt haben sind Matrizen ja eigentlich Tabellen mit Zahlen. Diese Zahlen sind die Stellschrauben an unseren &amp;quot;Greifarmen&amp;quot;. Mit diesen Stellschrauben können wir die Greifarme im Glaskasten positionieren. Durch den OpenGL-Befehl [[glMatrixMode]] können wir auswählen welchen der beiden Arme wir gerade steuern. &lt;br /&gt;
&lt;br /&gt;
'''ModelView - Der Objektmanipulator'''&lt;br /&gt;
: Wird diese Matrix auf ein Objekt angewendet, ändert sich je nach Einstellung der Matrix dessen Position, Ausrichtung, Größe usw. (Man kann sogar den kompletten Glaskasten damit verschieben.)  (Beispiel: Wirft man einen Würfel in eine Drehungsmatrix, kommt am Ende ein gedrehter Würfel raus.)&lt;br /&gt;
&lt;br /&gt;
'''PerspectivMatrix - Die Kameralinse'''&lt;br /&gt;
: Diese Maschine ist nur für die Ausgabe zuständig. Man kann über die Stellschrauben einstellen, welche Art der Projektion (Parallel-, Perspektivisch-,...), und wie nah und wie weit Objekte maximal von der Kamera entfernt sein dürfen, um sichtbar zu sein.&lt;br /&gt;
&lt;br /&gt;
Wer nun auf den Geschmack gekommen ist und mittels [[glLoadMatrix]] mal selber die Stellschrauben einer der beiden Matrizen ändern möchte, der sollte sich das sehr gute '''Mathe Script''' zum Thema '''Computer Geometrie''' einmal ansehen (siehe Links). Das eben vermittelte Bild mag zwar helfen. Die Theorie muss aber verstanden werden um damit arbeiten zu können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Siehe auch===&lt;br /&gt;
[[glMatrixMode]], [[glGet]], [[glLoadIdentity]], [[glLoadMatrix]], [[glTranslate]], [[glRotate]], [[glScale]], [[Quaternion|Quaternionen]]&lt;br /&gt;
&lt;br /&gt;
===Links===&lt;br /&gt;
*[[Tutorial_Nachsitzen|Tutorial: Nachsitzen]]&lt;br /&gt;
*[http://www-user.tu-chemnitz.de/~pester/Lehre/CompGeo.pdf Recht umfangreiches, gut verständliches Script zum Thema &amp;quot;Computer Geometrie&amp;quot; (PDF)]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Lichts%C3%A4ule&amp;diff=21492</id>
		<title>Lichtsäule</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Lichts%C3%A4ule&amp;diff=21492"/>
				<updated>2008-04-12T21:39:15Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Tippfehler&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Bildwunsch|Ein Bild einer Lichtsäule aus einem Spiel wäre hier schön.}}&lt;br /&gt;
= Lichtsäulen =&lt;br /&gt;
Unter dem Begriff &amp;quot;Lichtsäulen&amp;quot; kann man viele Effekte fassen. Das einzigste was alle Effekte gemein haben ist, dass sie meist mit [[transparent]]en, hellen [[Textur]]en arbeiten um ein Leuchten zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Diese Lichtsäulen werden in Fantasy-Spielen oft benutzt um Anwendung von Zaubersprüchen auf Figuren oder Gegenständen zu verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
== Verschiedene Möglichkeiten ==&lt;br /&gt;
&lt;br /&gt;
=== Partikelsysteme===&lt;br /&gt;
Lichtsäulen können auch einfach nur aufsteigende leuchtende Punkte sein. Um diese zur erzeugen werden [[Partikelsystem]]e verwendet.&lt;br /&gt;
&lt;br /&gt;
=== Zylinder ===&lt;br /&gt;
Ein Zylinder kann auch eine Lichtsäule darstellen. In dem man hierbei die Textur-[[Matrix]] durch  [[glTranslate|Verschiebung]]en so manipuliert, dass das Endresultat zum Beispiel sich nach unten bewegende '''Lichtringe''' simuliert.&lt;br /&gt;
&lt;br /&gt;
=== Zwei sich überkreuzende Rechtecke===&lt;br /&gt;
Zwei sich überkreuzende [[Primitive|Quads]] können auch die Illusion einer Säule hervorrufen. Diese  Technik wurde häufig für die Darstellung [[Polygon]] armer Bäume verwendet. &amp;lt;br&amp;gt;&lt;br /&gt;
Dies ist die schnellste aber auch unschönste Methode, wenn man auf [[Vertexprogramm]]e verzichten will/muss.&lt;br /&gt;
&lt;br /&gt;
=== Billboard ===&lt;br /&gt;
Eine andere Möglichkeit wäre noch, nur ein [[Primitive|Rechteck]] mit [[Textur]] zu zeichnen, und dann durch entsprechende Ausrichtung zum Betrachter eine Säule oder einen Stahl vorzutäuschen. Diese Ausrichtungstechnik nennt man zylindrisches [[Billboard]]ing. Diese Illusion fliegt allerdings auf, wenn man von oben auf die Säule schaut, denn je weiter von oben man auf das zylindrische [[Billboard]] schaut, desto mehr erscheint es als Linie und nicht mehr als [[Primitive|Rechteck]].&lt;br /&gt;
&lt;br /&gt;
== Allgemeine Hinweise ==&lt;br /&gt;
Um die Effekte etwas prickelnder gestalten zu können, kann man mit [[Multitexturing]] auch mehrere Texturen auf die Oberfläche [[Blenden]].&lt;br /&gt;
&lt;br /&gt;
== Grundlagen ==&lt;br /&gt;
*Nun die Grundlagen ([[glBegin]]), wie man Oberflächen rendert auf jeden Fall.&lt;br /&gt;
*Natürlich auch Texturierungsbefehle ([[glTexCoord]], [[glTexParameter]]).&lt;br /&gt;
&lt;br /&gt;
== Brauchbare Artikel ==&lt;br /&gt;
[[Blenden]], [[Multitexturing]], [[Texture Loader]], [[Billboard]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]] [[Kategorie:Effekt]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glPushAttrib&amp;diff=21491</id>
		<title>glPushAttrib</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glPushAttrib&amp;diff=21491"/>
				<updated>2008-04-12T21:26:06Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &amp;quot;gl&amp;quot;s bei Siehe auch hinzugefügt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glPushAttrib, glPopAttrib =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glPushAttrib, glPopAttrib''' - legt Attribute auf bzw. holt Attribute vom [[Stack|Attributstack]].&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glPushAttrib'''(''mask'': TGLbitfield);&lt;br /&gt;
 procedure '''glPopAttrib''';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
&amp;lt;table border=1 rules=all&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''mask''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;Ist ein Bitfeld das angibt, welche Attribute auf den Attributstack gelegt werden sollen. Wie man einzelne Bits im Bitfeld setzt, finden Sie unter '''Beschreibung'''.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
'''glPushAttrib''' nimmt ein Argument, ''mask'', dass angibt, welche Gruppen von Zustandsvariablen der GL auf den Attributstack gelegt werden sollen. Die Bits des Bitfelds ''mask'' werden normalerweise durch symbolische Konstanten gesetzt. Dies geschieht, indem man die einzelnen Konstanten mittels '''or''' verknüpft.&amp;lt;br&amp;gt;&lt;br /&gt;
Möchte man alle speicherbaren Zustände auf den Stack legen, kann man dazu die spezielle Konstante '''GL_ALL_ATTRIB_BITS''' benutzen.&lt;br /&gt;
&lt;br /&gt;
Nach der Initialisierung des Attributstacks ist selbiger leer.&lt;br /&gt;
&lt;br /&gt;
'''glPopAttrib''' stellt die zuletzt auf den Attributstack abgelegten Zustandsvariablen wieder her. Die Variablen, die nicht auf den Stack gelegt wurden, werden nicht verändert.&lt;br /&gt;
&lt;br /&gt;
=== Symbolische Konstanten ===&lt;br /&gt;
Es folgen alle akzeptierten Konstanten und die Zustände der GL die sie repräsentieren. &amp;lt;br&amp;gt;&lt;br /&gt;
(Die eingerückten Abschnitte bezeichnen die Attribute die auf den Stack abgelegt werden.):&lt;br /&gt;
&lt;br /&gt;
'''GL_ACCUM_BUFFER_BIT'''&lt;br /&gt;
: Löschwert für den [[Akkumulationspuffer]]&lt;br /&gt;
&lt;br /&gt;
'''GL_COLOR_BUFFER_BIT'''&lt;br /&gt;
: '''GL_ALPHA_TEST''' Aktivierungsbit&lt;br /&gt;
: Alphatest Funktionen und Referenzwerte&lt;br /&gt;
: '''GL_BLEND''' Aktivierungsbit&lt;br /&gt;
: Quell- und Zielfunktionen für [[Blenden]]&lt;br /&gt;
: '''GL_DITHER''' Aktivierungsbit&lt;br /&gt;
: '''GL_DRAW_BUFFER''' Einstellungen&lt;br /&gt;
: '''GL_LOGIC_OP''' Aktivierungsbit&lt;br /&gt;
: Funktion für logische Operationen&lt;br /&gt;
: Löschwerte für Farb- und Indexmodus&lt;br /&gt;
: Schreibmasken für Farb- und Indexmodus&lt;br /&gt;
&lt;br /&gt;
'''GL_CURRENT_BIT'''&lt;br /&gt;
: Aktuelle RGBA Farbe&lt;br /&gt;
: Aktueller Farbindex&lt;br /&gt;
: Aktueller Normalenvektor&lt;br /&gt;
: Aktuelle Texturkoordinaten&lt;br /&gt;
: Aktuelle Rasterposition&lt;br /&gt;
: '''GL_CURRENT_RASTER_POSITION_VALID''' Flag&lt;br /&gt;
: RGBA Farbe an der aktuellen Rasterposition&lt;br /&gt;
: Farbindex an der aktuellen Rasterposition&lt;br /&gt;
: Texturkoordinaten an der aktuellen Rasterposition&lt;br /&gt;
: '''GL_EDGE_FLAG''' Flag&lt;br /&gt;
&lt;br /&gt;
'''GL_DEPTH_BUFFER_BIT'''&lt;br /&gt;
: '''GL_DEPTH_TEST''' Aktivierungsbit&lt;br /&gt;
: Tiefentest Funktion&lt;br /&gt;
: Löschwert für den [[Tiefenpuffer]]&lt;br /&gt;
: '''GL_DEPTH_WRITEMASK''' Aktivierungsbit&lt;br /&gt;
&lt;br /&gt;
'''GL_ENABLE_BIT'''&lt;br /&gt;
: '''GL_ALPHA_TEST''' Flag&lt;br /&gt;
: '''GL_AUTO_NORMAL''' Flag&lt;br /&gt;
: '''GL_BLEND''' Flag&lt;br /&gt;
: Aktivierungsbits für die nutzerdefinierten [[Clipping Plane|Clipping Planes]]&lt;br /&gt;
: '''GL_COLOR_MATERIAL'''&lt;br /&gt;
: '''GL_CULL_FACE''' Flag&lt;br /&gt;
: '''GL_DEPTH_TEST''' Flag&lt;br /&gt;
: '''GL_DITHER''' Flag&lt;br /&gt;
: '''GL_FOG''' Flag&lt;br /&gt;
: '''GL_LIGHT'''i wobei 0 &amp;lt;= i &amp;lt; '''GL_MAX_LIGHTS'''&lt;br /&gt;
: '''GL_LIGHTING''' Flag&lt;br /&gt;
: '''GL_LINE_SMOOTH''' Flag&lt;br /&gt;
: '''GL_LINE_STIPPLE''' Flag&lt;br /&gt;
: '''GL_COLOR_LOGIC_OP''' Flag&lt;br /&gt;
: '''GL_INDEX_LOGIC_OP''' Flag&lt;br /&gt;
: '''GL_MAP1'''_x wobei x ein Maptyp ist&lt;br /&gt;
: '''GL_MAP2'''_x wobei x ein Maptyp ist&lt;br /&gt;
: '''GL_NORMALIZE''' Flag&lt;br /&gt;
: '''GL_POINT_SMOOTH'''  Flag&lt;br /&gt;
: '''GL_POLYGON_OFFSET_LINE''' Flag&lt;br /&gt;
: '''GL_POLYGON_OFFSET_FILL''' Flag &lt;br /&gt;
: '''GL_POLYGON_OFFSET_POINT''' Flag&lt;br /&gt;
: '''GL_POLYGON_SMOOTH''' Flag&lt;br /&gt;
: '''GL_POLYGON_STIPPLE''' Flag&lt;br /&gt;
: '''GL_SCISSOR_TEST''' Flag&lt;br /&gt;
: '''GL_STENCIL_TEST''' Flag&lt;br /&gt;
: '''GL_TEXTURE_1D''' Flag&lt;br /&gt;
: '''GL_TEXTURE_2D''' Flag&lt;br /&gt;
: '''GL_TEXTURE_3D''' Flag&lt;br /&gt;
: '''GL_TEXTURE_GEN'''_x Flags wobei x = '''S, T, R''' oder '''Q''' ist.&lt;br /&gt;
&lt;br /&gt;
'''GL_EVAL_BIT'''&lt;br /&gt;
: '''GL_MAP1'''_x Aktivierungsbit wobei x ein Maptyp ist.&lt;br /&gt;
: '''GL_MAP2'''_x Aktivierungsbit wobei x ein Maptyp ist.&lt;br /&gt;
: 1D Gitter Endpunkte und Unterteilungen&lt;br /&gt;
: 2D Gitter Endpunkte und Unterteilungen&lt;br /&gt;
: '''GL_AUTO_NORMAL''' Aktivierungsbit&lt;br /&gt;
&lt;br /&gt;
'''GL_FOG_BIT'''&lt;br /&gt;
: '''GL_FOG''' Aktivierungsbit&lt;br /&gt;
: Nebelfarbe&lt;br /&gt;
: Nebeldichte&lt;br /&gt;
: Lineare Nebelstartweite&lt;br /&gt;
: Lineare Nebelendweite&lt;br /&gt;
: Nebelindex&lt;br /&gt;
: '''GL_FOG_MODE''' Wert&lt;br /&gt;
&lt;br /&gt;
'''GL_HINT_BIT'''&lt;br /&gt;
: '''GL_PERSPECTIVE_CORRECTION_HINT''' Einstellung&lt;br /&gt;
: '''GL_POINT_SMOOTH_HINT''' Einstellung&lt;br /&gt;
: '''GL_LINE_SMOOTH_HINT''' Einstellung&lt;br /&gt;
: '''GL_POLYGONE_SMOOTH_HINT''' Einstellung&lt;br /&gt;
: '''GL_FOG_HINT''' Einstellung&lt;br /&gt;
&lt;br /&gt;
'''GL_LIGHTING_BIT'''&lt;br /&gt;
: '''GL_COLOR_MATERIAL''' Aktivierungsbit&lt;br /&gt;
: '''GL_COLOR_FACE_MATERIAL_FACE''' Wert&lt;br /&gt;
: Farbmaterialparameter, welche die aktuelle Farbe beeinflussen.&lt;br /&gt;
: Ambiente Szenenfarbe&lt;br /&gt;
: '''GL_LIGHT_MODEL_LOCAL_VIEWER''' Wert&lt;br /&gt;
: '''GL_LIGHT_MODEL_TWO_SIDE''' Einstellung&lt;br /&gt;
: '''GL_LIGHTING'''  Aktivierungsbit&lt;br /&gt;
: Aktivierungsbits für jedes Licht&lt;br /&gt;
: Ambiente-, Diffuse- und Glanzlichtintensität jedes Licht&lt;br /&gt;
: Richtung, Position, Exponent und Streuwinkel für jedes Licht&lt;br /&gt;
: Konstante, lineare und quadratische Lichtabschwächungsfaktoren für jedes Licht&lt;br /&gt;
: Ambiente-, Diffuse-, Glanzlicht- und Strahlungfarbe für jedes Material.&lt;br /&gt;
: Ambiente-, Diffuse- und Glanzlichtfarbindizes für jedes Material&lt;br /&gt;
: Glanzexponent für jedes Material&lt;br /&gt;
: '''GL_SHADE_MODEL''' Einstellungen&lt;br /&gt;
&lt;br /&gt;
'''GL_LINE_BIT'''&lt;br /&gt;
: '''GL_LINE_SMOOTH''' Flag&lt;br /&gt;
: '''GL_LINE_STIPPLE''' Aktivierungsbit&lt;br /&gt;
: Linienpunktierungsmuster und Wiederholungszähler&lt;br /&gt;
: Linienstärke&lt;br /&gt;
&lt;br /&gt;
'''GL_LIST_BIT'''&lt;br /&gt;
: '''GL_LIST_BASE''' Einstellung&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MODE_BIT'''&lt;br /&gt;
: '''GL_RED_BIAS''' und '''GL_RED_SCALE''' Einstellungen&lt;br /&gt;
: '''GL_GREEN_BIAS''' und '''GL_GREEN_SCALE''' Werte&lt;br /&gt;
: '''GL_BLUE_BIAS''' und '''GL_BLUE_SCALE'''&lt;br /&gt;
: '''GL_ALPHA_BIAS''' und '''GL_ALPHA_SCALE'''&lt;br /&gt;
: '''GL_DEPTH_BIAS''' und '''GL_DEPTH_SCALE'''&lt;br /&gt;
: '''GL_INDEX_OFFSET''' und '''GL_INDEX_SHIFT''' Werte&lt;br /&gt;
: '''GL_MAP_COLOR''' und '''GL_MAP_STENCIL''' Flags&lt;br /&gt;
: '''GL_ZOOM_X''' und '''GL_ZOOM_Y''' Faktoren&lt;br /&gt;
: '''GL_READ_BUFFER''' Einstellung&lt;br /&gt;
&lt;br /&gt;
'''GL_POINT_BIT'''&lt;br /&gt;
: '''GL_POINT_SMOOTH''' Flag&lt;br /&gt;
: Punktgröße&lt;br /&gt;
&lt;br /&gt;
'''GL_POLYGON_BIT'''&lt;br /&gt;
: '''GL_CULL_FACE''' Aktivierungsbit&lt;br /&gt;
: '''GL_CULL_FACE_MODE''' Wert&lt;br /&gt;
: '''GL_FRONT_FACE''' Indikator&lt;br /&gt;
: '''GL_POLYGON_MODE''' Einstellung&lt;br /&gt;
: '''GL_POLYGON_SMOOTH''' Flag&lt;br /&gt;
: '''GL_POLYGON_STIPPLE''' Aktivierungsbit&lt;br /&gt;
: '''GL_POLYGON_OFFSET_FILL''' Flag&lt;br /&gt;
: '''GL_POLYGON_OFFSET_LINE''' Flag&lt;br /&gt;
: '''GL_POLYGON_OFFSET_POINT''' Flag&lt;br /&gt;
: '''GL_POLYGON_OFFSET_FACTOR'''&lt;br /&gt;
: '''GL_POLYGON_OFFSET_UNITS'''&lt;br /&gt;
&lt;br /&gt;
'''GL_POLYGONE_STIPPLE_BIT'''&lt;br /&gt;
: Polygonpunktierungsbild&lt;br /&gt;
&lt;br /&gt;
'''GL_SCISSOR_BIT'''&lt;br /&gt;
: '''GL_SCISSOR_TEST''' Flag&lt;br /&gt;
: Scissorbox&lt;br /&gt;
&lt;br /&gt;
'''GL_STENCIL_BUFFER_BIT'''&lt;br /&gt;
: '''GL_STENCIL_TEST''' Aktivierungsbit&lt;br /&gt;
: Schablonenfunktion und Referenzwert&lt;br /&gt;
: Schablonen-Wertemaske&lt;br /&gt;
: Aktionen bei Bestehen und Durchfallen des Stenciltests und Bestehen des Tiefentests Aktionen&lt;br /&gt;
: Stencilpuffer Löschwert&lt;br /&gt;
: Stencilpuffer Schreibmaske&lt;br /&gt;
&lt;br /&gt;
'''GL_TEXTURE_BIT'''&lt;br /&gt;
: Aktivierungsbits für die vier Texturkoordinaten&lt;br /&gt;
: Randfarbe für jedes Texturbild&lt;br /&gt;
: Verkleinerungsfunktion für jedes Texturbild&lt;br /&gt;
: Vergrößerungsfunktion für jedes Texturbild&lt;br /&gt;
: Texturkoordinaten und Wrapmodus für jedes Texturbild&lt;br /&gt;
: Farbe und Modus für jede Texturumgebung&lt;br /&gt;
: Aktivierungsbits '''GL_TEXTURE_GEN_'''x, x ist dabei '''S, T, R''' oder '''Q'''&lt;br /&gt;
: '''GL_TEXTURE_GEN_MODE'''-Einstellungen für '''S, T, R''' und '''Q'''&lt;br /&gt;
: '''glTexGen''' Ebenengleichung für '''S, T, R''' und '''Q'''&lt;br /&gt;
: Aktuelle gebundenen Texturen (z.B. ''GL_TEXTURE_2D_BINDING)&lt;br /&gt;
&lt;br /&gt;
'''GL_TRANSFORM_BIT'''&lt;br /&gt;
: Koeffizienten der sechs [[Clipping Plane|Clippingplanes]]&lt;br /&gt;
: Aktivierungsbit für die vom Benutzer definierten Clippingplanes&lt;br /&gt;
: '''GL_MATRIX_MODE''' Wert&lt;br /&gt;
: '''GL_NORMALIZE''' Flag&lt;br /&gt;
&lt;br /&gt;
'''GL_VIEWPORT_BIT'''&lt;br /&gt;
: Tiefenbereich (nah und fern) (Depth range)&lt;br /&gt;
: Sichtfeldursprung und Ausdehnung&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
Nicht alle Werte können auf den Attributstack abgelegt werden. So können zum Beispiel PixelPack- und UnPack-Zustand, Rendermoduszustand sowie Selctions- und Feedback-Zustand nicht gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Ein Fehler wird ausgelöst, wenn versucht wird auf einen vollen Attributstack Werte abzulegen, bzw. von einem leeren Stack Werte abzurufen. In beiden Fällen wird das Errorflag gesetzt und es werden keine Änderung an den Zuständen der GL durchgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Tiefe des Attributstack hängt von der Implementierung ab, muss aber mindestens 16 sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_STACK_OVERFLOW''' wird generiert wenn '''glPushAttrib''' aufgerufen wird, während der Attributstack voll ist.&amp;lt;br&amp;gt;&lt;br /&gt;
'''GL_STACK_UNDERFLOW''' wird generiert wenn '''glPopAttrib''' aufgerufen wird, während der Attributstack leer ist.&amp;lt;br&amp;gt;&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn '''glPushAttrib''' innerhalb eines [[glBegin]]-[[glEnd]] Blocks aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Zugehörige Wertrückgaben ==&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_ATTRIB_STACK_DEPTH|GL_ATTRIB_STACK_DEPTH]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_MAX_ATTRIB_STACK_DEPTH|GL_MAX_ATTRIB_STACK_DEPTH]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glGet]], [[glGetClipPlane]], [[glGetError]], [[glGetLight]], [[glGetMap]], [[glGetMaterial]], [[glGetPixelMap]], [[glGetPolygonStipple]], [[glGetString]], [[glGetTexEnv]], [[glGetTexGen]], [[glGetTexImage]], [[glGetTexLevelParameter]], [[glGetTexParameter]], [[glIsEnabled]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|PushAttrib]]&lt;br /&gt;
 [[Kategorie:GL1.0]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Framebufferobject&amp;diff=21473</id>
		<title>Tutorial Framebufferobject</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Framebufferobject&amp;diff=21473"/>
				<updated>2008-04-12T16:34:48Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: mehrere Fehler in Fehlerabfrage korrigiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=GL_EXT_FRAMEBUFFER_OBJECT=&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Willkommen zu meinem ersten Tutorial. Das Thema des Tutorials sind Framebufferobjekte. Diese stellen derzeit die wohl einfachste Möglichkeit für Offscreen Rendering dar. Im Gegensatz zu Pixelbuffern sind sie plattformunabhängig und bieten automatisches Mipmapping. Jedoch benötigen sie mindestens OpenGL 1.1. Außerdem unterstützen Framebufferobjekte kein AntiAliasing. In der Vergangenheit hatten auch ATI Treiber einige Probleme mit ihnen, dies dürfte aber der Vergangenheit angehören. &lt;br /&gt;
&lt;br /&gt;
==Das FBO erstellen==&lt;br /&gt;
Zuerst einmal muss das Framebufferobjekt natürlich generiert werden. Dies läuft ähnlich wie das Erstellen einer Textur ab:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  fbo: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @fbo);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie bei allem anderen auch müssen wir das Framebufferobjekt jetzt binden, damit alles, was folgt sich auf dieses Objekt bezieht:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Der erste Parameter von [[glBindFramebufferEXT]] ist das Ziel an das gebunden wird. Derzeit existiert aber nur GL_FRAMEBUFFER_EXT.&lt;br /&gt;
&lt;br /&gt;
==Einen Depthbuffer hinzufügen==&lt;br /&gt;
Ein einfaches Framebufferobjekt ist noch ziemlich nutzlos. Deswegen fügen wir zuerst einmal einen der neu eingeführten Renderbuffer als Depthbuffer hinzu. &lt;br /&gt;
Renderbuffer sind im Prinzip Objekte, die benutzt werden wenn ein Buffer kein zugehöriges Texturformat besitzt. Dazu zählen u.a. der Stencilbuffer, der Accumulationbuffer und der Depthbuffer. Das Binden an den Accumulationbuffer wurde allerdings auf eine spätere Extension verschoben. &lt;br /&gt;
Wie auch beim Framebufferobjekt müssen wir einen Renderbuffer zuerst generieren und dann binden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  depthbuffer: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenRenderbuffersEXT(1, @depthbuffer);&lt;br /&gt;
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Derzeit hat der Renderbuffer allerdings noch keinen Speicher zugeteilt bekommen. Deswegen sagen wir OpenGL, wie wir den Renderbuffer benutzen wollen und welche Größe er haben soll:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 512, 512);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit [[glRenderbufferStorageEXT]] hat OpenGL den Speicher für den Renderbuffer, den wir als Depthbuffer nutzen, reserviert. Jetzt können wir unseren Depthbuffer zum FBO hinzufügen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,&lt;br /&gt;
  GL_RENDERBUFFER_EXT, depthbuffer);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die letzte Anweisung sollte ziemlich einfach zu verstehen sein. Der zweite Parameter sagt einfach, als was der Renderbuffer genutzt werden soll.&lt;br /&gt;
&lt;br /&gt;
==Eine Textur hinzufügen==&lt;br /&gt;
Um Farbinformationen in unser Framebufferobjekt schreiben zu können, fügen wir eine Textur hinzu. Bevor wir sie hinzufügen können müssen wir sie natürlich noch erstellen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  tex: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @tex);&lt;br /&gt;
  glBindTextures(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  512, 512, 0, GL_RGBA8, GL_UNSIGNED_BYTE, nil);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Es dürfte eigentlich nichts völlig Unverständliches da stehen. Wir erstellen die Textur, binden sie, stellen die Filtermodi ein und erzeugen im Speicher den entsprechenden Platz. Anzumerken ist aber, dass die Textur die '''gleiche Größe wie der Renderbuffer haben muss'''. Alle Größen müssen einheitlich sein. Man kann also nicht einen Renderbuffer von 512*512 und eine Textur von 256*256 erstellen und sie zusammen in einem FBO nutzen. Hinzugefügt wird sie nach dem gleichen Schema wie der Depthbuffer:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie gesagt, nicht viel neues hier. Der zweite Parameter, GL_COLOR_ATTACHMENT0_EXT sagt OpenGL wo die Textur hinzugefügt werden soll (man kann mehrere hinzufügen, doch dazu später mehr). Der letzte Parameter beschreibt das Mipmaping-Level.&lt;br /&gt;
&lt;br /&gt;
==Die Fehlerabfrage==&lt;br /&gt;
Derzeit wissen wir nicht, ob alles so geklappt hat, wie wir es wollten oder ob wir einen Fehler gemacht haben. Deswegen ist nun die Fehlerabfrage an der Reihe. Dazu gibt es die Funktion [[glCheckFramebufferStatusEXT]]. Die Fehlerabfrage lässt sich schön in so einer Prozedur verpacken:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TForm1.CheckFBO;&lt;br /&gt;
var&lt;br /&gt;
  error: GlEnum;&lt;br /&gt;
begin&lt;br /&gt;
  error := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);&lt;br /&gt;
  case error of&lt;br /&gt;
    GL_FRAMEBUFFER_COMPLETE_EXT:&lt;br /&gt;
      Exit;&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete attachment');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:&lt;br /&gt;
      raise Exception.Create('Missing attachment');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete dimensions');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete formats');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete draw buffer');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete read buffer');&lt;br /&gt;
    GL_FRAMEBUFFER_UNSUPPORTED_EXT:&lt;br /&gt;
      raise Exception.Create('Framebufferobjects unsupported');&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Die Codeübersicht==&lt;br /&gt;
Zur Übersicht noch einmal der komplette Code zum erstellen eines Framebufferobjekts:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  fbo: 		GluInt;&lt;br /&gt;
  depthbuffer: 	GluInt;&lt;br /&gt;
  tex: 		GluInt;&lt;br /&gt;
&lt;br /&gt;
procedure TForm1.InitFBO;&lt;br /&gt;
begin&lt;br /&gt;
  glGenFramebuffersEXT(1, @fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);&lt;br /&gt;
  glGenRenderbuffersEXT(1, @depthbuffer);&lt;br /&gt;
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);&lt;br /&gt;
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 512, 512);&lt;br /&gt;
  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer); &lt;br /&gt;
  glGenTextures(1, @tex);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,&lt;br /&gt;
  GL_TEXTURE_2D, tex, 0);&lt;br /&gt;
  CheckFBO;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==In die Textur rendern==&lt;br /&gt;
Der eigentliche Rendervorgang ist ziemlich simpel und unterscheidet sich nicht sonderlich vom normalen Rendern. Das Framebufferobjekt teilt sich alle Einstellungen mit dem eigentlichen  Renderingkontext. Deswegen muss eigentlich nur das FBO gebunden und der Viewport auf die entsprechende Breite und Höhe eingestellt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  //ganz normal rendern – das Ergebnis landet in der Textur&lt;br /&gt;
	&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie gesagt, hier gibt’s nichts bemerkenswertes: Viewport speichern, umstellen, rendern, Viewport laden und mit der letzten Zeile das FBO abschalten.&lt;br /&gt;
Die Textur die an das Framebufferobjekt gebunden wurde, enthält das Gezeichnete und wird ganz normal mit [[glBindTexture]](GL_TEXTURE_2D, tex) benutzt.&lt;br /&gt;
&lt;br /&gt;
==Mipmaps==&lt;br /&gt;
FBOs bieten die Möglichkeit zum automatischem Erstellen der Mipmapdaten. Dazu gibt es die Funktion [[glGenerateMipmapEXT]]. Man bindet die Textur zunächst und ruft dann die Funktion auf:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TForm1.Render;&lt;br /&gt;
begin&lt;br /&gt;
  //...&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glGenerateMipmapEXT(GL_TEXTURE_2D);&lt;br /&gt;
&lt;br /&gt;
  //Textur danach ganz normal benutzen&lt;br /&gt;
&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wenn man hingegen einen der Mipmap Filter verwendet muss der Befehl [[glGenerateMipmapEXT]] bevor der Status des FBOs überprüft oder versucht wird in die Textur zu rendern aufgerufen werden. Ein Beispiel wäre folgender Code in der Initialisierung des Framebufferobjektes:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  fbo: 	GluInt;&lt;br /&gt;
  depthbuffer: 	GluInt;&lt;br /&gt;
  tex: 	GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @tex);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_RGBA, 	GL_UNSIGNED_BYTE, nil);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_MIPMAP_LINEAR);&lt;br /&gt;
  glGenerateMipmapEXT(GL_TEXTURE_2D);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Und wieder aufräumen==&lt;br /&gt;
Beim Beenden unseres Programms soll das alles natürlich auch wieder gelöscht werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glDeleteFramebuffersEXT(1, @fbo);&lt;br /&gt;
  glDeleteRenderbuffersEXT(1, @depthbuffer);&lt;br /&gt;
  glDeleteTextures(1, @tex);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ich denke das Ganze ist selbsterklärend.&lt;br /&gt;
&lt;br /&gt;
==Mehrere Texturen in einem FBO==&lt;br /&gt;
Wie vorhin erwähnt gibt es auch die Möglichkeit mehrere Texturen an ein Framebufferobjekt zu binden. Dazu schauen wir uns nochmal den Befehl zum hinzufügen einer Textur an:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Der zweite Parameter sagt OpenGL an welches COLOR_ATTACHMENT die Textur zugefügt wird. Die derzeitigen Spezifikationen erlauben bis zu 16 COLOR_ATTACHMENTS (GL_COLOR_ATTACHMENT0_EXT bis GL_COLOR_ATTACHMENT15_EXT). Allerdings ist die wirkliche Anzahl von möglichen COLOR_ATTACHMENTS durch die Grafikkarte und deren Treiber begrenzt. Die maximale Anzahl kann durch folgenden Code ermittelt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  maxbuffers: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGetIntegeri(GL_MAX_COLOR_ATTACHMENTS_EXT, @maxbuffers);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Eine zweite, wie oben beschrieben erstellte Textur, kann also mit folgendem Code zum Framebufferobjekt hinzugefügt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, tex2, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==In die zweite Textur rendern==&lt;br /&gt;
Mit dem Befehl [[glDrawBuffer]](GL_COLOR_ATTACHMENT'''n'''_EXT) lässt sich einstellen, in welchen Buffer man rendern möchte (wobei '''n''' den Buffer repräsentiert, also 0, 1, usw.). Standartmäßig ist GL_COLOR_ATTACHMENT0_EXT aktiviert (logisch, sonst hätten wir vorhin nicht viel gesehen, oder ;-) ). Soll also nur in diesen gerendert werden, ist keine weitere Anweisung nötig. Ansonsten sieht der Code folgendermaßen aus:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT0_EXT rendern&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT1_EXT rendern &lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFrameBuffer(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Diesmal werden Viewport und Colorbuffer gespeichert, da Veränderungen immer das Framebufferobjekt und den eigentlichen Renderingkontext betreffen. Veränderungen am RC sind aber nicht gewollt, deswegen wird beides gespeichert und später wieder geladen.&lt;br /&gt;
Wie beim normalen Renderpass ist der Colorbuffer bereits mit den Daten die in die erste Textur geschrieben werden gefüllt. Deswegen leert man diesen normalerweise vor dem Rendern in die zweite Textur mithilfe von [[glClear]]:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT0_EXT rendern&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);&lt;br /&gt;
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT1_EXT rendern &lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFrameBuffer(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Es ist im übrigen schneller ein FBO für mehrere Texturen zu nutzen als mehrere FBOs zu erstellen und zwischen ihnen zu wechseln.&lt;br /&gt;
&lt;br /&gt;
==Multiple Render Targets==&lt;br /&gt;
Mithilfe des Befehls [[glDrawBuffers]] kann in einem FBO gleichzeitig in mehrere Texturen gerendert werden. Die Namen der GL_COLOR_ATTACHMENTS werden in einem Array abgelegt und mit dem Befehl übergeben:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  buffers: Array[0..1] of GlEnum;&lt;br /&gt;
&lt;br /&gt;
  buffers[0] := GL_COLOR_ATTACHMENT0_EXT;&lt;br /&gt;
  buffers[1] := GL_COLOR_ATTACHMENT1_EXT;&lt;br /&gt;
//...&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffers(2, @buffers);&lt;br /&gt;
  //normal rendern&lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Hardware und der Treiber legen die Grenze für die Anzahl von Texturen in die gleichzeitig gerendert werden kann. Der Wert kann mit folgendem Code erhalten werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  maxbuffers: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGetIntegeri(GL_MAX_DRAW_BUFFERS, @maxbuffers);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==MRT und GLSL==&lt;br /&gt;
Solange man mindestens für die OpenGL Version 2.0 (bzw. GLSL Version 1.10) schreibt, kann man mithilfe von GLSL  gleichzeitig unterschiedliche Dinge in zwei Texturen rendern. Dazu benutzt man in GLSL anstelle von gl_FragColor den Array gl_FragData[]. Als Beispiel rendern wir ein rotes und ein grünes Viereck:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  buffers: Array[0..1] of GlEnum;&lt;br /&gt;
//...&lt;br /&gt;
  buffers[0] := GL_COLOR_ATTACHMENT0_EXT;&lt;br /&gt;
  buffers[1] := GL_COLOR_ATTACHMENT1_EXT;&lt;br /&gt;
//...&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffers(2, @buffers);&lt;br /&gt;
  //Viereck zeichnen&lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Der aufmerksame Leser merkts - der Delphi Code hat sich eigentlich nicht verändert :-). Also auf zu den Shadern. Der Vertexshader enthält nur das Nötigste:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
  gl_Position = ftransform();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Und der Fragmentshader sieht folgendermaßen aus:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
  gl_FragData[0] = vec4( 1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
  gl_FragData[1] = vec4( 0.0, 1.0, 0.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Und siehe da – die Textur die zu GL_COLOR_ATTACHMENT0_EXT gehört bekommt die Daten für ein rotes Quad und die zweite Textur die Daten für ein grünes Quad.&lt;br /&gt;
Eine Sache bleibt aber noch zu erwähnen: Es ist die Reihenfolge in der die Werte der COLOR_ATTACHMENTS übergeben werden, die bestimmt was gl_FragData[0] und was gl_FragData[1] ist. Wenn wir also geschrieben hätten&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  buffers: Array[0..1] of GlEnum;&lt;br /&gt;
&lt;br /&gt;
  buffers[0] := GL_COLOR_ATTACHMENT1_EXT;&lt;br /&gt;
  buffers[1] := GL_COLOR_ATTACHMENT0_EXT;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
dann würde gl_FragData[0] GL_COLOR_ATTACHMENT1_EXT beeinflussen und gl_FragData[1] GL_COLOR_ATTACHMENT0_EXT.&lt;br /&gt;
&lt;br /&gt;
==Und fertig!==&lt;br /&gt;
So! Geschafft. Schlussendlich bleibt zu sagen das Framebufferobjekte sehr nützliche Helfer sind, die sich relativ leicht handhaben lassen. &lt;br /&gt;
Zum Abschluss möchte ich euch nochmal daran erinnern, dass dies mein erstes Tutorial war, haltet euch also ordentlich ran mit Feedback ;-)&lt;br /&gt;
&lt;br /&gt;
Cya,&lt;br /&gt;
Deathball&lt;br /&gt;
&lt;br /&gt;
==Quellen==&lt;br /&gt;
* http://www.gamedev.net/reference/articles/article2331.asp&lt;br /&gt;
* http://www.gamedev.net/reference/articles/article2333.asp&lt;br /&gt;
&lt;br /&gt;
==Weiterführende Links==&lt;br /&gt;
* http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt&lt;br /&gt;
* http://http.download.nvidia.com/developer/presentations/2005/GDC/OpenGL_Day/OpenGL_FrameBuffer_Object.pdf&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Pixelbuffer]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Framebufferobject]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Framebufferobject&amp;diff=21472</id>
		<title>Tutorial Framebufferobject</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Framebufferobject&amp;diff=21472"/>
				<updated>2008-04-12T16:23:13Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=GL_EXT_FRAMEBUFFER_OBJECT=&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Willkommen zu meinem ersten Tutorial. Das Thema des Tutorials sind Framebufferobjekte. Diese stellen derzeit die wohl einfachste Möglichkeit für Offscreen Rendering dar. Im Gegensatz zu Pixelbuffern sind sie plattformunabhängig und bieten automatisches Mipmapping. Jedoch benötigen sie mindestens OpenGL 1.1. Außerdem unterstützen Framebufferobjekte kein AntiAliasing. In der Vergangenheit hatten auch ATI Treiber einige Probleme mit ihnen, dies dürfte aber der Vergangenheit angehören. &lt;br /&gt;
&lt;br /&gt;
==Das FBO erstellen==&lt;br /&gt;
Zuerst einmal muss das Framebufferobjekt natürlich generiert werden. Dies läuft ähnlich wie das Erstellen einer Textur ab:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  fbo: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @fbo);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie bei allem anderen auch müssen wir das Framebufferobjekt jetzt binden, damit alles, was folgt sich auf dieses Objekt bezieht:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Der erste Parameter von [[glBindFramebufferEXT]] ist das Ziel an das gebunden wird. Derzeit existiert aber nur GL_FRAMEBUFFER_EXT.&lt;br /&gt;
&lt;br /&gt;
==Einen Depthbuffer hinzufügen==&lt;br /&gt;
Ein einfaches Framebufferobjekt ist noch ziemlich nutzlos. Deswegen fügen wir zuerst einmal einen der neu eingeführten Renderbuffer als Depthbuffer hinzu. &lt;br /&gt;
Renderbuffer sind im Prinzip Objekte, die benutzt werden wenn ein Buffer kein zugehöriges Texturformat besitzt. Dazu zählen u.a. der Stencilbuffer, der Accumulationbuffer und der Depthbuffer. Das Binden an den Accumulationbuffer wurde allerdings auf eine spätere Extension verschoben. &lt;br /&gt;
Wie auch beim Framebufferobjekt müssen wir einen Renderbuffer zuerst generieren und dann binden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  depthbuffer: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenRenderbuffersEXT(1, @depthbuffer);&lt;br /&gt;
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Derzeit hat der Renderbuffer allerdings noch keinen Speicher zugeteilt bekommen. Deswegen sagen wir OpenGL, wie wir den Renderbuffer benutzen wollen und welche Größe er haben soll:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 512, 512);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit [[glRenderbufferStorageEXT]] hat OpenGL den Speicher für den Renderbuffer, den wir als Depthbuffer nutzen, reserviert. Jetzt können wir unseren Depthbuffer zum FBO hinzufügen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,&lt;br /&gt;
  GL_RENDERBUFFER_EXT, depthbuffer);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die letzte Anweisung sollte ziemlich einfach zu verstehen sein. Der zweite Parameter sagt einfach, als was der Renderbuffer genutzt werden soll.&lt;br /&gt;
&lt;br /&gt;
==Eine Textur hinzufügen==&lt;br /&gt;
Um Farbinformationen in unser Framebufferobjekt schreiben zu können, fügen wir eine Textur hinzu. Bevor wir sie hinzufügen können müssen wir sie natürlich noch erstellen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  tex: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @tex);&lt;br /&gt;
  glBindTextures(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  512, 512, 0, GL_RGBA8, GL_UNSIGNED_BYTE, nil);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Es dürfte eigentlich nichts völlig Unverständliches da stehen. Wir erstellen die Textur, binden sie, stellen die Filtermodi ein und erzeugen im Speicher den entsprechenden Platz. Anzumerken ist aber, dass die Textur die '''gleiche Größe wie der Renderbuffer haben muss'''. Alle Größen müssen einheitlich sein. Man kann also nicht einen Renderbuffer von 512*512 und eine Textur von 256*256 erstellen und sie zusammen in einem FBO nutzen. Hinzugefügt wird sie nach dem gleichen Schema wie der Depthbuffer:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie gesagt, nicht viel neues hier. Der zweite Parameter, GL_COLOR_ATTACHMENT0_EXT sagt OpenGL wo die Textur hinzugefügt werden soll (man kann mehrere hinzufügen, doch dazu später mehr). Der letzte Parameter beschreibt das Mipmaping-Level.&lt;br /&gt;
&lt;br /&gt;
==Die Fehlerabfrage==&lt;br /&gt;
Derzeit wissen wir nicht, ob alles so geklappt hat, wie wir es wollten oder ob wir einen Fehler gemacht haben. Deswegen ist nun die Fehlerabfrage an der Reihe. Dazu gibt es die Funktion [[glCheckFramebufferStatusEXT]]. Die Fehlerabfrage lässt sich schön in so einer Prozedur verpacken:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TForm1.CheckFBO;&lt;br /&gt;
var&lt;br /&gt;
  error: GlEnum;&lt;br /&gt;
begin&lt;br /&gt;
  error := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);&lt;br /&gt;
  case s of:&lt;br /&gt;
    GL_FRAMEBUFFER_COMPLETE_EXT:&lt;br /&gt;
      Exit;&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete attachment');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMOPLETE_MISSING_ATTACHMENT_EXT:&lt;br /&gt;
      raise Exception.Create('Missing attachment');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete dimensions');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete formats');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete draw buffer');&lt;br /&gt;
    GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:&lt;br /&gt;
      raise Exception.Create('Incomplete read buffer');&lt;br /&gt;
    GL_FRAMEBUFFER_UNSUPPORTED_EXT:&lt;br /&gt;
      raise Exception.Create('Framebufferobjects unsupported');&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Die Codeübersicht==&lt;br /&gt;
Zur Übersicht noch einmal der komplette Code zum erstellen eines Framebufferobjekts:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  fbo: 		GluInt;&lt;br /&gt;
  depthbuffer: 	GluInt;&lt;br /&gt;
  tex: 		GluInt;&lt;br /&gt;
&lt;br /&gt;
procedure TForm1.InitFBO;&lt;br /&gt;
begin&lt;br /&gt;
  glGenFramebuffersEXT(1, @fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);&lt;br /&gt;
  glGenRenderbuffersEXT(1, @depthbuffer);&lt;br /&gt;
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);&lt;br /&gt;
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 512, 512);&lt;br /&gt;
  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer); &lt;br /&gt;
  glGenTextures(1, @tex);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,&lt;br /&gt;
  GL_TEXTURE_2D, tex, 0);&lt;br /&gt;
  CheckFBO;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==In die Textur rendern==&lt;br /&gt;
Der eigentliche Rendervorgang ist ziemlich simpel und unterscheidet sich nicht sonderlich vom normalen Rendern. Das Framebufferobjekt teilt sich alle Einstellungen mit dem eigentlichen  Renderingkontext. Deswegen muss eigentlich nur das FBO gebunden und der Viewport auf die entsprechende Breite und Höhe eingestellt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  //ganz normal rendern – das Ergebnis landet in der Textur&lt;br /&gt;
	&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie gesagt, hier gibt’s nichts bemerkenswertes: Viewport speichern, umstellen, rendern, Viewport laden und mit der letzten Zeile das FBO abschalten.&lt;br /&gt;
Die Textur die an das Framebufferobjekt gebunden wurde, enthält das Gezeichnete und wird ganz normal mit [[glBindTexture]](GL_TEXTURE_2D, tex) benutzt.&lt;br /&gt;
&lt;br /&gt;
==Mipmaps==&lt;br /&gt;
FBOs bieten die Möglichkeit zum automatischem Erstellen der Mipmapdaten. Dazu gibt es die Funktion [[glGenerateMipmapEXT]]. Man bindet die Textur zunächst und ruft dann die Funktion auf:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TForm1.Render;&lt;br /&gt;
begin&lt;br /&gt;
  //...&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glGenerateMipmapEXT(GL_TEXTURE_2D);&lt;br /&gt;
&lt;br /&gt;
  //Textur danach ganz normal benutzen&lt;br /&gt;
&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wenn man hingegen einen der Mipmap Filter verwendet muss der Befehl [[glGenerateMipmapEXT]] bevor der Status des FBOs überprüft oder versucht wird in die Textur zu rendern aufgerufen werden. Ein Beispiel wäre folgender Code in der Initialisierung des Framebufferobjektes:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  fbo: 	GluInt;&lt;br /&gt;
  depthbuffer: 	GluInt;&lt;br /&gt;
  tex: 	GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @tex);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, tex);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_RGBA, 	GL_UNSIGNED_BYTE, nil);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_MIPMAP_LINEAR);&lt;br /&gt;
  glGenerateMipmapEXT(GL_TEXTURE_2D);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Und wieder aufräumen==&lt;br /&gt;
Beim Beenden unseres Programms soll das alles natürlich auch wieder gelöscht werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glDeleteFramebuffersEXT(1, @fbo);&lt;br /&gt;
  glDeleteRenderbuffersEXT(1, @depthbuffer);&lt;br /&gt;
  glDeleteTextures(1, @tex);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ich denke das Ganze ist selbsterklärend.&lt;br /&gt;
&lt;br /&gt;
==Mehrere Texturen in einem FBO==&lt;br /&gt;
Wie vorhin erwähnt gibt es auch die Möglichkeit mehrere Texturen an ein Framebufferobjekt zu binden. Dazu schauen wir uns nochmal den Befehl zum hinzufügen einer Textur an:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Der zweite Parameter sagt OpenGL an welches COLOR_ATTACHMENT die Textur zugefügt wird. Die derzeitigen Spezifikationen erlauben bis zu 16 COLOR_ATTACHMENTS (GL_COLOR_ATTACHMENT0_EXT bis GL_COLOR_ATTACHMENT15_EXT). Allerdings ist die wirkliche Anzahl von möglichen COLOR_ATTACHMENTS durch die Grafikkarte und deren Treiber begrenzt. Die maximale Anzahl kann durch folgenden Code ermittelt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  maxbuffers: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGetIntegeri(GL_MAX_COLOR_ATTACHMENTS_EXT, @maxbuffers);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Eine zweite, wie oben beschrieben erstellte Textur, kann also mit folgendem Code zum Framebufferobjekt hinzugefügt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, tex2, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==In die zweite Textur rendern==&lt;br /&gt;
Mit dem Befehl [[glDrawBuffer]](GL_COLOR_ATTACHMENT'''n'''_EXT) lässt sich einstellen, in welchen Buffer man rendern möchte (wobei '''n''' den Buffer repräsentiert, also 0, 1, usw.). Standartmäßig ist GL_COLOR_ATTACHMENT0_EXT aktiviert (logisch, sonst hätten wir vorhin nicht viel gesehen, oder ;-) ). Soll also nur in diesen gerendert werden, ist keine weitere Anweisung nötig. Ansonsten sieht der Code folgendermaßen aus:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT0_EXT rendern&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT1_EXT rendern &lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFrameBuffer(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Diesmal werden Viewport und Colorbuffer gespeichert, da Veränderungen immer das Framebufferobjekt und den eigentlichen Renderingkontext betreffen. Veränderungen am RC sind aber nicht gewollt, deswegen wird beides gespeichert und später wieder geladen.&lt;br /&gt;
Wie beim normalen Renderpass ist der Colorbuffer bereits mit den Daten die in die erste Textur geschrieben werden gefüllt. Deswegen leert man diesen normalerweise vor dem Rendern in die zweite Textur mithilfe von [[glClear]]:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT0_EXT rendern&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);&lt;br /&gt;
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
  //in die Textur von GL_COLOR_ATTACHMENT1_EXT rendern &lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFrameBuffer(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Es ist im übrigen schneller ein FBO für mehrere Texturen zu nutzen als mehrere FBOs zu erstellen und zwischen ihnen zu wechseln.&lt;br /&gt;
&lt;br /&gt;
==Multiple Render Targets==&lt;br /&gt;
Mithilfe des Befehls [[glDrawBuffers]] kann in einem FBO gleichzeitig in mehrere Texturen gerendert werden. Die Namen der GL_COLOR_ATTACHMENTS werden in einem Array abgelegt und mit dem Befehl übergeben:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  buffers: Array[0..1] of GlEnum;&lt;br /&gt;
&lt;br /&gt;
  buffers[0] := GL_COLOR_ATTACHMENT0_EXT;&lt;br /&gt;
  buffers[1] := GL_COLOR_ATTACHMENT1_EXT;&lt;br /&gt;
//...&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffers(2, @buffers);&lt;br /&gt;
  //normal rendern&lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Hardware und der Treiber legen die Grenze für die Anzahl von Texturen in die gleichzeitig gerendert werden kann. Der Wert kann mit folgendem Code erhalten werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  maxbuffers: GluInt;&lt;br /&gt;
&lt;br /&gt;
  glGetIntegeri(GL_MAX_DRAW_BUFFERS, @maxbuffers);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==MRT und GLSL==&lt;br /&gt;
Solange man mindestens für die OpenGL Version 2.0 (bzw. GLSL Version 1.10) schreibt, kann man mithilfe von GLSL  gleichzeitig unterschiedliche Dinge in zwei Texturen rendern. Dazu benutzt man in GLSL anstelle von gl_FragColor den Array gl_FragData[]. Als Beispiel rendern wir ein rotes und ein grünes Viereck:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  buffers: Array[0..1] of GlEnum;&lt;br /&gt;
//...&lt;br /&gt;
  buffers[0] := GL_COLOR_ATTACHMENT0_EXT;&lt;br /&gt;
  buffers[1] := GL_COLOR_ATTACHMENT1_EXT;&lt;br /&gt;
//...&lt;br /&gt;
  glBindFramebuffer(GL_FRAMEBUFFER_EXT,  fbo);&lt;br /&gt;
  glPushAttrib(GL_VIEWPORT_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glViewPort(0, 0, 512, 512);&lt;br /&gt;
&lt;br /&gt;
  glDrawBuffers(2, @buffers);&lt;br /&gt;
  //Viereck zeichnen&lt;br /&gt;
&lt;br /&gt;
  glPopAttrib;&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Der aufmerksame Leser merkts - der Delphi Code hat sich eigentlich nicht verändert :-). Also auf zu den Shadern. Der Vertexshader enthält nur das Nötigste:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
  gl_Position = ftransform();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Und der Fragmentshader sieht folgendermaßen aus:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
  gl_FragData[0] = vec4( 1.0, 0.0, 0.0, 1.0);&lt;br /&gt;
  gl_FragData[1] = vec4( 0.0, 1.0, 0.0, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Und siehe da – die Textur die zu GL_COLOR_ATTACHMENT0_EXT gehört bekommt die Daten für ein rotes Quad und die zweite Textur die Daten für ein grünes Quad.&lt;br /&gt;
Eine Sache bleibt aber noch zu erwähnen: Es ist die Reihenfolge in der die Werte der COLOR_ATTACHMENTS übergeben werden, die bestimmt was gl_FragData[0] und was gl_FragData[1] ist. Wenn wir also geschrieben hätten&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  buffers: Array[0..1] of GlEnum;&lt;br /&gt;
&lt;br /&gt;
  buffers[0] := GL_COLOR_ATTACHMENT1_EXT;&lt;br /&gt;
  buffers[1] := GL_COLOR_ATTACHMENT0_EXT;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
dann würde gl_FragData[0] GL_COLOR_ATTACHMENT1_EXT beeinflussen und gl_FragData[1] GL_COLOR_ATTACHMENT0_EXT.&lt;br /&gt;
&lt;br /&gt;
==Und fertig!==&lt;br /&gt;
So! Geschafft. Schlussendlich bleibt zu sagen das Framebufferobjekte sehr nützliche Helfer sind, die sich relativ leicht handhaben lassen. &lt;br /&gt;
Zum Abschluss möchte ich euch nochmal daran erinnern, dass dies mein erstes Tutorial war, haltet euch also ordentlich ran mit Feedback ;-)&lt;br /&gt;
&lt;br /&gt;
Cya,&lt;br /&gt;
Deathball&lt;br /&gt;
&lt;br /&gt;
==Quellen==&lt;br /&gt;
* http://www.gamedev.net/reference/articles/article2331.asp&lt;br /&gt;
* http://www.gamedev.net/reference/articles/article2333.asp&lt;br /&gt;
&lt;br /&gt;
==Weiterführende Links==&lt;br /&gt;
* http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt&lt;br /&gt;
* http://http.download.nvidia.com/developer/presentations/2005/GDC/OpenGL_Day/OpenGL_FrameBuffer_Object.pdf&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Pixelbuffer]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Framebufferobject]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glBegin&amp;diff=21182</id>
		<title>glBegin</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glBegin&amp;diff=21182"/>
				<updated>2008-03-10T14:40:06Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Excellent}}&lt;br /&gt;
= glBegin, glEnd =&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glBegin, glEnd''' - Umschließen die [[Eckpunkt|Eckpunkte (Vertices)]] einer [[Primitive|Primitiven]], oder eine Gruppe gleicher [[Primitiv]]en.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glBegin'''(''mode'' : GLEnum);&lt;br /&gt;
 procedure '''glEnd''';&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! ''mode'' &lt;br /&gt;
| Bestimmt die [[Primitive]] bzw. Gruppe von [[Primitive|Primitiven]] die aus den von '''glBegin''' und '''glEnd''' umschlossenen [[Eckpunkt|Eckpunkten (Vertices)]] erstellt werden.&lt;br /&gt;
Erlaubt sind die folgendenden zehn symbolischen Konstanten:&lt;br /&gt;
'''GL_POINTS''', '''GL_LINES''', '''GL_LINE_STRIP''', '''GL_LINE_LOOP''', '''GL_TRIANGLES''', '''GL_TRIANGLE_STRIP''', '''GL_TRIANGLE_FAN''', '''GL_QUADS''', '''GL_QUAD_STRIP''', und '''GL_POLYGON'''.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
'''glBegin''' und '''glEnd''' umschließen eine Liste von [[Eckpunkt|Eckpunkten (Vertices)]] die eine [[Primitive]] oder Gruppe von [[Primitive|Primitiven]] darstellt. '''glBegin''' erhält ein einzelnes Argument (''mode''), das angibt, auf welche Art und Weise die [[Eckpunkt|Eckpunkte (Vertices)]] interpretiert werden.&lt;br /&gt;
&lt;br /&gt;
Unter der Annahme ''n'' sei ein Integerwert der bei Eins beginnt und ''N'' als Integerwert der die Gesamtanzahl der übergebenen Eckpunkte angibt, ergeben sich folgende Interpretationen :&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!mode&lt;br /&gt;
!Einschätzung&lt;br /&gt;
!Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_POINTS'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|langsam&lt;br /&gt;
|[[Bild:Glbegin_points.jpg|350px|thumb|right]]&lt;br /&gt;
Behandelt jeden Eckpunkt als einzelnen Punkt. Eckpunkt ''n'' definiert Punkt ''n'', und ''N'' Punkte werden gerendert.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_LINES'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|mittel&lt;br /&gt;
|[[Bild:Glbegin_lines.jpg|350px|thumb|right]]&lt;br /&gt;
Behandelt jedes Eckpunkt-Paar als unabhängigen Linienabschnitt. Eckpunkte 2*''n''-1 und 2*''n'' beschreiben Linie n. N/2 Linien werden gerendert.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_LINE_STRIP'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|schnell&lt;br /&gt;
|[[Bild:Glbegin_linestrip.jpg|350px|thumb|right]]&lt;br /&gt;
Rendert eine Gruppe von miteinander verbundenen Liniensegmenten, beginnend beim ersten Eckpunkt bis zum letzten. Eckpunkte ''n'' und ''n+1'' beschreiben dabei Linie ''n''. ''N-1'' Linien werden gerendert.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_LINE_LOOP'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|sehr schnell&lt;br /&gt;
|[[Bild:Glbegin_lineloop.jpg|350px|thumb|right]]&lt;br /&gt;
Rendert eine miteinander verbundene Gruppe von Linienabschnitten, beginnend beim ersten Eckpunkt und endend beim letzten, und dann wieder abschließend zurück zum ersten. Eckpunkte ''n'' und ''n+1'' definieren Linie ''n''. Die letzte Linie wird jedoch durch die Eckpunkte ''N'' und 1 definiert. ''N'' Linien werden gerendert.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_TRIANGLES'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|schnell&lt;br /&gt;
|[[Bild:Glbegin_triangles.jpg|350px|thumb|right]]&lt;br /&gt;
Behandelt jedes Eckpunkt-Trio als unabhängiges Dreieck. Eckpunkte 3*''n''-2, 3*''n''-1 und 3*''n'' beschreiben Dreieck ''n''. ''N''/3 Dreiecke werden gerendert.&lt;br /&gt;
&lt;br /&gt;
'''Eigenschaften''':&lt;br /&gt;
* Alle Dreiecke bestehen aus jeweils 3 Vertices, die ausschließlich nur zu diesem Dreieck gehören.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_TRIANGLE_STRIP'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|am schnellsten&lt;br /&gt;
|[[Bild:Glbegin_trianglestrip.jpg|350px|thumb|right]]&lt;br /&gt;
Rendert eine verbundene Gruppe von Dreiecken. Ein Dreieck wird für jeden Eckpunkt der nach den beiden ersten Eckpunkten definiert wird gerendert. Für ein ungerades ''n'' definieren die Eckpunkte ''n'', ''n''+1 und ''n''+2 Dreieck ''n'', für gerade ''n''s definieren die Eckpunkte ''n''+1, ''n'' und ''n''+2 ein Dreieck. (Man beachte, dass die Reihenfolge bei geraden ''n'' impliziet geändert wird um entgegen der Uhrzeigerrichtung zu rendern. Siehe auch [[glFrontFace]])&lt;br /&gt;
&lt;br /&gt;
''N''-2 Dreiecke werden gerendert.&lt;br /&gt;
&lt;br /&gt;
'''Eigenschaften''':&lt;br /&gt;
* Nacheinander erstellte Dreiecke haben eine gemeinsame Kante.&lt;br /&gt;
* Nacheinander erstellte Dreiecke benutzen 2 gemeinsame Vertices.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_TRIANGLE_FAN'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|schnell&lt;br /&gt;
|[[Bild:Glbegin_trianglefan.jpg|350px|thumb|right]]&lt;br /&gt;
Rendert eine verbundene Gruppe von Dreiecken. Ein Dreieck wird für jeden Eckpunkt gerendert der nach den ersten beiden definiert wird. Eckpunkte 1, ''n''+1 und ''n''+2 definieren Dreieck ''n''. ''N''-2 Dreiecke werden gerendert.&lt;br /&gt;
&lt;br /&gt;
'''Eigenschaften''':&lt;br /&gt;
* Alle Dreiecke haben mindestens einen gemeinsamen Punkt (Vertex1).&lt;br /&gt;
* Nacheinander erstellte Dreiecke haben eine gemeinsame Kante.&lt;br /&gt;
* Nacheinander erstellte Dreiecke benutzen 2 gemeinsame Vertices.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_QUADS'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|schnell&lt;br /&gt;
|[[Bild:Glbegin_quads.jpg|350px|thumb|right]]&lt;br /&gt;
Behandelt jeweils vier Eckpunkte als unabhängiges Viereck. Eckpunkte 4*''n''-3, 4*''n''-2, 4*''n''-1 und 4*''n'' beschreiben Viereck ''n''. ''N''/4 Vierecke werden gerendert.&lt;br /&gt;
&lt;br /&gt;
'''Eigenschaften''':&lt;br /&gt;
* Alle Vierecke bestehen aus jeweils 4 Vertices, die ausschließlich nur zu diesem Viereck gehören.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_QUAD_STRIP'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|sehr schnell&lt;br /&gt;
|[[Bild:Glbegin_quadstrip.jpg|350px|thumb|right]]&lt;br /&gt;
Rendert eine verbundene Gruppe von Vierecken. Ein Viereck wird für jedes nach den ersten beiden Eckpunkten übergebene Eckpunktepaar gerendert. Eckpunkte 2*''n''-1, 2*''n'', 2*''n''+2 und 2*''n''+1 beschreiben Viereck ''n''. ''N''/2-1 Vierecke werden gerendert. Es gilt allerdings zu beachten, dass die Reihenfolge der Eckpunkte, die genutzt werden, um Vierecke aus einem Streifen zu generieren, unterschiedlich ggü. der unabhängigen Konstruktion sind.&lt;br /&gt;
&lt;br /&gt;
'''Eigenschaften''':&lt;br /&gt;
* Nacheinander erstellte Vierecke haben eine gemeinsame Kante.&lt;br /&gt;
* Nacheinander erstellte Vierecke benutzen 2 gemeinsame Vertices.&lt;br /&gt;
|-&lt;br /&gt;
|'''GL_POLYGON'''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|(langsam)&lt;br /&gt;
|[[Bild:Glbegin_polygon.jpg|350px|thumb|right]]&lt;br /&gt;
Rendert eine einzelnes, [[konvex|konvexes]] Polygon (=Vieleck). Eckpunkte 1 bis ''N'' definieren dieses Polygon.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis'''&lt;br /&gt;
&lt;br /&gt;
GL_POLYGON scheint für Anfänger meist die &amp;quot;beste Lösung&amp;quot; zu sein, denn man kann alle möglichen (konvexen) Polygone erzeugen. Dies ist soweit richtig, allerdings ist GL_POLYGON um ein vielfaches langsamer als GL_TRIANGLES! Dies hat die folgenden Gründe: &amp;lt;br&amp;gt;&lt;br /&gt;
1. sind moderne Grafikkarten auf die Darstellung von Dreiecken optimiert und &amp;lt;br&amp;gt;&lt;br /&gt;
2. müssen die Polygone bevor sie von den Grafikkarten verwendet werden können, erst in Dreiecke zerlegt werden (siehe [[Triangulation]]). &amp;lt;br&amp;gt;&lt;br /&gt;
Vorallem der letzte Punkt sorgt für niedrige Frameraten im Vergleich zu dreiecksbasierten Strukturen.&amp;lt;br&amp;gt;&lt;br /&gt;
''Die OpenGL-Spezifikiation erlaubt es jedoch GL_POLYGON annähernd gleich zu behandeln  wie GL_TRIANGLE_FAN (die Ausnahme bildet der Wireframe-Modus mit [[glPolygonMode]]), was auch von vielen Grafikkarten in dieser Form umgesetzt wird. Ist dies der Fall, so fallen alle Vor- und Nachteile gegenüber GL_TRIANGLE_FAN weg.''&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nur eine Untergruppe von GL Befehlen kann zwischen '''glBegin''' und '''glEnd''' genutzt werden. Die Befehle sind [[glVertex]], [[glColor]], [[glIndex]], [[glNormal]], [[glTexCoord]], [[glEvalCoord]], [[glEvalPoint]], [[glArrayElement]], [[glMaterial]] und [[glEdgeFlag]]. Außerdem ist es erlaubt  [[glCallList]] oder [[glCallLists]] zu nutzen, um [[Displaylisten]] auszuführen, die nur oben erwähnte Kommandos enthalten. Sollte ein nicht erwähnter GL Befehl zwischen '''glBegin''' und '''glEnd''' ausgeführt werden, dann wird das Fehlerflag gesetzt und der Befehl ignoriert.&lt;br /&gt;
&lt;br /&gt;
Unabhängig des für ''mode'' übergebenen Wertes gibt es '''keine''' Begrenzung für die Anzahl der übergebenen Eckpunkte die zwischen '''glBegin''' und '''glEnd''' definiert werden. Linien, Dreiecke, Vierecke und Polygone die nicht genügendend beschrieben wurden, werden nicht gerendert.&lt;br /&gt;
Ungenügende Beschreibung bedeutet entweder, dass zu wenige Eckpunkte angegeben wurden, um eine einzelne [[Primitive]] zu beschreiben, oder ein inkorrektes Vielfaches an Eckpunkten übergeben wurde. Nicht komplette Primitiven werden ignoriert; der Rest wird gerendet.&lt;br /&gt;
&lt;br /&gt;
Das Minimum an zu spezifizierenden Eckpunkten für jede Primitive ist wie folgt :&lt;br /&gt;
*1 für einen Punkt&lt;br /&gt;
*2 für eine Linie&lt;br /&gt;
*3 für ein Dreieck&lt;br /&gt;
*4 für ein Viereck und &lt;br /&gt;
*3 für ein Polygon. &lt;br /&gt;
Modi die ein festgelegtes Vielfaches an Eckpunkten brauchen sind '''GL_LINES''' (2), '''GL_TRIANGLES''' (3), '''GL_QUADS''' (4), und '''GL_QUAD_STRIP''' (2).  ''(D.h. wenn man bei GL_TRIANGLES 8 Vertices angibt (kein Vielfaches von 3), werden nur die ersten 6 bearbeitet. Die restlichen 2 ergeben kein Dreieck und werden deshalb verworfen.)''&lt;br /&gt;
&lt;br /&gt;
Wenn Flächen gemeinsame Punkte haben (z.B. bei '''GL_TRIANGLE_FAN''') ist es nicht möglich die Eigenschaften dieser Vertices für jede Fläche individuell zu bestimmen. Wenn dies nötig sein sollte, müssen die entsprechenden Flächen aus individuellen Vertices zusammengestellt werden.&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_INVALID_ENUM''' wird ausgelöst wenn ''mode'' einen ungültigen Wert besitzt.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird ausgelöst, wenn zwischen '''glBegin''' und dem zugehörigen '''glEnd''' ein weiteres '''glBegin''' aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird ausgelöst, wenn '''glEnd''' ohne ein vorhergehendes '''glBegin''' aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird aufgerufen, wenn ein anderer Befehl als [[glVertex]], [[glColor]], [[glIndex]], [[glNormal]], [[glTexCoord]], [[glEvalCoord]], [[glEvalPoint]], [[glArrayElement]], [[glMaterial]], [[glEdgeFlag]], [[glCallList]] oder [[glCallLists]] zwischen '''glBegin''' und dem zugehörigen '''glEnd''' aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein Aufruf von [[glEnableClientState]], [[glDisableClientState]],  [[glPushClientAttrib]],  [[glPopClientAttrib]], [[glEdgeFlagPointer]], [[glTexCoordPointer]], [[glColorPointer]], [[glIndexPointer]], [[glNormalPointer]], [[glVertexPointer]], [[glInterleavedArrays]] oder [[glPixelStore]] nach einem Aufruf von '''glBegin''' und dem zugehörigen '''glEnd''' ist nicht erlaubt, aber je nach Implementation wird möglicherweise kein Fehler ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==Beispiele==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;60%&amp;quot;|Code&lt;br /&gt;
!Ausgabe&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pascal&amp;gt;glBegin(GL_TRIANGLES);&lt;br /&gt;
    glVertex3f(1,0,0);&lt;br /&gt;
    glVertex3f(0,1,0);&lt;br /&gt;
    glVertex3f(0,0,1);&lt;br /&gt;
glEnd;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
|[[Bild:GlBegin_Bsp1.jpg|center]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Zwischen glBegin und glEnd können natürlich auch &amp;quot;nicht OpenGL&amp;quot;-Befehle stehen was man dazu nutzen kann komplexere Gebilde direkt mit einer Schleife zeichnen zu lassen:&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;60%&amp;quot;|Code&lt;br /&gt;
!Ausgabe&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glBegin(GL_LINE_STRIP);&lt;br /&gt;
  f := 0.0;&lt;br /&gt;
  for i:=0 to 20 do&lt;br /&gt;
  begin&lt;br /&gt;
    glVertex3f(cos(f),sin(f),0);&lt;br /&gt;
    f := f + (2*Pi/20);&lt;br /&gt;
  end;&lt;br /&gt;
glEnd;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
|[[Bild:GlBegin_Bsp2.jpg|center]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glArrayElement]], [[glCallList]], [[glCallLists]], [[glColor]], [[glEdgeFlag]], [[glEvalCoord]], [[glEvalPoint]], [[glIndex]], [[glMaterial]], [[glNormal]], [[glTexCoord]], [[glVertex]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|Begin]]&lt;br /&gt;
 [[Kategorie:GL1.0]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Konkav&amp;diff=21181</id>
		<title>Konkav</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Konkav&amp;diff=21181"/>
				<updated>2008-03-10T14:31:56Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: Weiterleitung nach Konvex erstellt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Konvex]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Triangulation&amp;diff=21180</id>
		<title>Triangulation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Triangulation&amp;diff=21180"/>
				<updated>2008-03-10T14:29:13Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Triangulation =&lt;br /&gt;
== Was ist das? ==&lt;br /&gt;
Triangulation steht für &amp;quot;Aufteilen der Polygone innerhalb der Szene in Dreiecke&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Triangulation ist damit eine Spezialisierung der [[Tesselierung]].&lt;br /&gt;
&lt;br /&gt;
== Wozu braucht man das? ==&lt;br /&gt;
Dazu muss man auf die Besonderheiten der Grafikhardware eingehen.&lt;br /&gt;
Heutzutage (und nicht erst seit gestern) werden Grafikkarten auf die Darstellung von (texturierten) Dreiecken optimiert (Linien und Punkte lasse ich mal außen vor). Das hat einen ganz einfachen Grund: &amp;lt;br&amp;gt;&lt;br /&gt;
Jedes Polygon kann als Zusammenstellung von Dreicken dargestellt werden.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Ihr könntet jetzt anbringen, dass ihr aber doch auch &amp;quot;Vierecke und Polygone mittels OpenGL zeichnen&amp;quot; könnt. (siehe Beitrag [[Primitive]])&amp;lt;br&amp;gt;&lt;br /&gt;
Das stimmt. Nur sind die Grafikkarten nunmal auf Dreiecke optimiert. Und wenn man was anderes als Dreiecke zeichnet, müssen diese Flächen erst für die Hardware in Dreiecke zerlegt werden. Und das kostet Zeit. Und Zeit ist etwas, was in der Programmierung (vorallem im Grafikbereich) so wertvoll ist wie der Kaffee in der Nacht. (Also quasi unersetzbar) &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Fazit===&lt;br /&gt;
Wenn ihr die Möglichkeit habt, dann baut eure Szene von Anfang an aus Dreiecken auf. Die müssen nicht mehr nachbearbeitet werden, und das bringt euch vorallem bei großen Szenen noch einen spürbaren Geschwindigkeitszuwachs.&lt;br /&gt;
&lt;br /&gt;
== Wie mach ich es? ==&lt;br /&gt;
Es wäre sicherlich mühselig nun anzufangen die komplette Szene aus einzelnen Dreiecken zusammenzusetzen. Glücklicherweise hat OpenGL dafür eine Lösung.&amp;lt;br&amp;gt;&lt;br /&gt;
Anstatt im glBegin-glEnd Block mit '''GL_TRIANGLES''' zu arbeiten könnt ihr zusammenhängende ('''GL_TRIANGLE_STRIP''') Dreiecke (für rechteckige Flächen oder Flächen die aus Rechtecken zusammengesetzt wurden) oder konzentrische ('''GL_TRIANGLE_FAN''') Dreiecke (für [[Konvex | konvexe]] Polygone) verwenden. Was diese Konstanten konkret verändern ist im Artikel [[glBegin]] beschrieben.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glBegin]], [[Primitive]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Framecounter&amp;diff=21179</id>
		<title>Framecounter</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Framecounter&amp;diff=21179"/>
				<updated>2008-03-10T14:26:40Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wenn man in seinem Programm die [[Frame]]s pro Sekunde (FPS) anzeigen lassen möchte, so gibt es verschiedene Lösungswege.&lt;br /&gt;
&lt;br /&gt;
== Methode 1 ==&lt;br /&gt;
&lt;br /&gt;
Am Anfang der Renderschleife &amp;quot;misst&amp;quot; man die Zeit und speichert sie in einer Variable.&lt;br /&gt;
Dafür kann man die von Windows bereitgestellten Methoden [http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/gettickcount.asp &amp;quot;Gettickcount&amp;quot;] (gibt in Millisekunden an, wie lange Windows läuft) oder [http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/Timers/TimerReference/TimerFunctions/QueryPerformanceCounter.asp &amp;quot;QueryPerformanceCounter&amp;quot;]  verwenden.&lt;br /&gt;
Für unsere Zwecke reichen diese beiden Funktionen vollkommen aus.&lt;br /&gt;
&lt;br /&gt;
Als zweiten Schritt rendert man seine Szene, verarbeitet Tastatureingaben usw. &lt;br /&gt;
Also alles, was in der Renderschleife passiert.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Renderschleife stoppt man dann ein zweites Mal die Zeit und erhält nun eine Zeitdifferenz.&lt;br /&gt;
&lt;br /&gt;
Die FPS erhält man nun durch folgende Berechnung:&lt;br /&gt;
&lt;br /&gt;
 FPS = 1000 / Zeitdifferenz;&lt;br /&gt;
&lt;br /&gt;
Wobei Zeitdifferenz bei dieser Formel auch in Millisekunden angegeben sein muss.&lt;br /&gt;
&lt;br /&gt;
== Methode 2 ==&lt;br /&gt;
&lt;br /&gt;
Diese Methode unterscheidet sich kaum von Methode 1. &lt;br /&gt;
Wieder wird:&lt;br /&gt;
#Startzeit bestimmt&lt;br /&gt;
#gerendert&lt;br /&gt;
#Endzeitbestimmt&lt;br /&gt;
#Zeitdifferenz berechnet&lt;br /&gt;
&lt;br /&gt;
Anschließend wird die Zeitdifferenz auf eine Variable TimeCount addiert. Außerdem wird eine Zählvariable für die Frames erhöht.&lt;br /&gt;
&lt;br /&gt;
Wenn die Variable Timecount größer-gleich 1000 wird (es ist mindestens 1 sec vergangen) wird die Frameanzahl berechnet und ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Die Methode 2 hat gegenüber Methode 1 den Vorteil, dass die Frameanzahl nicht nach jedem Frame sondern maximal nur einmal pro Sekunde berechnet wird.&lt;br /&gt;
&lt;br /&gt;
== Beispielcodes ==&lt;br /&gt;
&lt;br /&gt;
Methode 2:&lt;br /&gt;
Der folgende Code wird im OnIdle-Event des OpenGL Formulars ausgeführt. Die Anzahl der Frames wird in der Beschriftung (Caption) des Fensters ausgegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt; procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);&lt;br /&gt;
 begin&lt;br /&gt;
 //&lt;br /&gt;
   StartTime:= GetTickCount;&lt;br /&gt;
 &lt;br /&gt;
   Render;&lt;br /&gt;
 &lt;br /&gt;
   DrawTime:= GetTickCount - StartTime;&lt;br /&gt;
 &lt;br /&gt;
   inc(TimeCount, DrawTime);&lt;br /&gt;
   inc(FrameCount);&lt;br /&gt;
 &lt;br /&gt;
   if TimeCount &amp;gt;= 1000 then begin&lt;br /&gt;
     Frames:= FrameCount;&lt;br /&gt;
     Dec(TimeCount, 1000);&lt;br /&gt;
     FrameCount:= 0;&lt;br /&gt;
 &lt;br /&gt;
     Caption:= InttoStr(Frames) + 'FPS';&lt;br /&gt;
   end;&lt;br /&gt;
 &lt;br /&gt;
   Done:= false;&lt;br /&gt;
 end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Primitive&amp;diff=21178</id>
		<title>Primitive</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Primitive&amp;diff=21178"/>
				<updated>2008-03-10T14:25:03Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Primitive (Plural: Primitiven) =&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
In OpenGL werden alle 3D- oder 2D-Objekte aus den von der API angebotenen Primitiven zusammengesetzt. Die GL stellt dazu insgesamt 10 verschiedene Primitiventypen zur Verfügung (darunter Punkt, Linie, Dreieck, Rechteck und [[Polygon]]e), von denen Dreiecke (oft auch als Abwandlung über Triangle-Strips oder -Fans) am häufigsten Verwendung finden. Dies ist u.a. damit zu erklären das sich fast alle Oberflächen recht genau mit Dreiecken beschreiben lassen (mit Vierecken wäre dies schon schwerer) und das moderne 3D-Beschleuniger (im Gegensatz zu den ersten Lösung, z.B. dem NV1 von NVidia, der Vierecke nutze) intern mit Dreiecken arbeiten. Dies hat auch zur Folge, das der Primitiventyp &amp;quot;Polygon&amp;quot; von der Grafikkarte erst in Dreiecke [[Tesselierung|tesseliert]] werden muss, weshalb dieser Primitiventyp recht selten genutzt wird.&lt;br /&gt;
Für den Programmierer bedeutet dies im Klartext, dass er beliebig komplexe Szenen mittels OpenGL visualisieren kann, mit der Einschränkung, dass er diese Szenen aus den vorhandenen Primitiven selbst erstellen muss.&lt;br /&gt;
&lt;br /&gt;
Um das erstellen komplexer Szenen zu vereinfachen, kann man komplexere Grundkörper mit den gegeben Primitiven erstellen und in Bibliotheken zusammenfassen. &lt;br /&gt;
Eine solche Bibiothek wurde unter dem Namen [[OpenGL Programming Guide Auxiliary Library]] veröffentlich.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|[[Bild:Primitive_geosphere.jpg|framed|Geosphäre, Zusammengesetzt aus Dreiecken (GL_TRIANGLES)]] &lt;br /&gt;
|[[Bild:Primitive_torus.jpg|framed|Torus, Zusammengesetzt aus Vierecken (GL_QUADS).]] &lt;br /&gt;
|[[Bild:Primitive_complexscene.jpg|framed|Eine komplexe Szene, wie man sie im Normalfall in Spielen oder anderen 3D-Anwendungen findet. Zusammengesetzt aus Dreiecken (Aufbauten), Vierecken (Seitenteile) und Dreiecks-Streifen (GL_TRIANGLESTRIP, Dach).]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
&lt;br /&gt;
[[glBegin]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tiefentest&amp;diff=21177</id>
		<title>Tiefentest</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tiefentest&amp;diff=21177"/>
				<updated>2008-03-10T14:20:28Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bei der Berechnung eines [[Fragment]]es, muss OpenGL feststellen können, welche Teile der Grafik im Vordergrund stehen und welche Objekte ganz oder teilweise durch andere Objekte verdeckt werden.&lt;br /&gt;
&lt;br /&gt;
== Funktionsweise ==&lt;br /&gt;
Für den Tiefentest existiert der [[Tiefenpuffer]]. Dieser ist genauso gross wie der Framebuffer. Für jeden Pixel auf dem Bildschirm gibt es dann also einen weiteren Wert - den Eintrag im Tiefenpuffer. &lt;br /&gt;
&lt;br /&gt;
Im ersten Schritt wird der gesamte Tiefenpuffer auf den größtmöglichen Wert initialisiert (also die maximale Distanz, siehe [[glClear]] und [[glClearDepth]]).&lt;br /&gt;
Sobald dann ein Objekt gerendert wird, wird für jeden Pixel überprüft, ob der Tiefenwert des Pixels dieses Objekts kleiner ist als der Wert im Tiefenpuffer. Ist dies der Fall, wird dieses Pixel in den Framebuffer gezeichnet und der Tiefenpuffer aktualisiert, ansonsten wird es verworfen. Der Test kann mittels [[glDepthFunc]] auch abgeändert werden. Zum Beispiel kann man dafür sorgen, dass auch gleich große Tiefenwerte akzeptiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Tiefentest findet verhältnismäßig früh in der [[Feste_Funktionspipeline#Fragment_Pipeline|Fragment-Pipeline]] statt, wodurch er sehr effizient nicht benötigte Fragmente ausschließen kann. Wenn Objekte tiefensortiert (in diesem Fall von vorne nach hinten) gezeichnet werden, ist der Tiefentest sehr gut geeignet um sehr früh nicht benötigte Fragmente zu verwerfen um so die [[Füllrate]] zu schonen.&lt;br /&gt;
&lt;br /&gt;
Den Tiefentest aktiviert man mit [[glEnable#GL_DEPTH_TEST|glEnable(GL_DEPTH_TEST)]] und deaktiviert ihn entsprechend mit glDisable.&lt;br /&gt;
&lt;br /&gt;
=== Beispiel ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Depthtest_nt_enabled.jpg|thumb|200px|Aktivierter Tiefentest]]&lt;br /&gt;
[[Bild:Depthtest_nt_disabled.jpg|thumb|200px|Deaktivierter Tiefentest]]&lt;br /&gt;
Dieser Rendercode wird einmal mit und einmal ohne Tiefentest verwendet.&lt;br /&gt;
   glBegin(GL_QUADS);&lt;br /&gt;
     glColor4f(1.0, 0.5, 0.5, 1.0);&lt;br /&gt;
     glVertex3f(-1.0, 0.0, -1.0);&lt;br /&gt;
     glVertex3f(-1.0, 0.0, 1.0);&lt;br /&gt;
     glVertex3f(1.0, 0.0, 1.0);&lt;br /&gt;
     glVertex3f(1.0, 0.0, -1.0);&lt;br /&gt;
 &lt;br /&gt;
     glColor4f(0.5, 1.0, 0.5, 1.0);&lt;br /&gt;
     glVertex3f(-1.0, 0.5, -1.0);&lt;br /&gt;
     glVertex3f(-1.0, 0.5, 1.0);&lt;br /&gt;
     glVertex3f(1.0, 0.5, 1.0);&lt;br /&gt;
     glVertex3f(1.0, 0.5, -1.0);&lt;br /&gt;
   glEnd;&lt;br /&gt;
&lt;br /&gt;
Man kann deutlich erkennen, dass bei deaktiviertem Tiefentest das eigentlich vorne liegende rote Quad vom weiter hinten liegenden, allerdings später gerenderten, grünen Quad überdeckt wird.&lt;br /&gt;
&lt;br /&gt;
== Transparenz und Tiefentest ==&lt;br /&gt;
Sobald Transparenz verwendet wird, kann der Tiefentest zumindest für diese Teile nicht mehr benutzt werden. Dies würde zu Fehlern führen, da das transparente Fragment ggfs. das durchscheinende, jedoch erst später an die Grafik-Pipeline gesendete und somit vom Tiefentest verworfene Fragment dahinter völlig verbirgt. Wenn man Transparente Fragmente nicht in den Tiefenbuffer schreibt, so können diese Fragmente von anderen, eigentlich weiter hinten liegenden, Fragmenten komplett überschrieben werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Aus diesem Grund sollten Transparente Objekte nach allen anderen Objekten an OpenGL geschickt werden und diese möglichst von hinten nach vorne sortiert sein. Das Sortieren kann durch einen Alpha Wert im [[Framebuffer]] umgangen werden, jedoch ist dieser nur selten in Hardware vorhanden, wodurch in den weit langsameren Softwaremodus gewechselt wird.&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Objekt_gedreht_und_dennoch_nach_vorne_bewegt&amp;diff=20963</id>
		<title>Tutorial Objekt gedreht und dennoch nach vorne bewegt</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Objekt_gedreht_und_dennoch_nach_vorne_bewegt&amp;diff=20963"/>
				<updated>2007-10-13T12:19:57Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: /* Und wie geht's jetzt weiter? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Beim Erstellen eines 3D-Games steht man irgendwann vor einem gewaltigen Problem: Ich kann zwar mein Objekt drehen und Transformieren, aber was mache ich, wenn sich das Objekt an der aktuellen Position um z.B. 15 Grad drehen und trotzdem in seine Blick-Richtung bewegen soll?!?&lt;br /&gt;
&lt;br /&gt;
Die Lösung des Problems heißt: Look-Vektor!!! Look was?!? Keine Panik, ich wird's euch erklären.&lt;br /&gt;
&lt;br /&gt;
==Der Richtungs-Vektor==&lt;br /&gt;
&lt;br /&gt;
Um ein Objekt immer nach vorne bewegen zu können, muss ich wissen, wo momentan für das Objekt vorne ist. Dazu benötige ich den Richtungs-Vektor (ich nenne ihn mal Look-Vektor) Bei einer Drehung des Objektes, wird der Vektor mitgedreht und zeigt somit immer nach vorn. Klingt komisch, ist aber so :o) Nein, im ernst: Es ist eigentlich kein Problem wie ihr sehen werdet.&lt;br /&gt;
&lt;br /&gt;
==Bevor wir anfangen...==&lt;br /&gt;
&lt;br /&gt;
...gibt es noch ein paar Kleinigkeiten zu regeln.&lt;br /&gt;
*um ein Objekt wie z.B. einen Raumgleiter in einer entsprechenden Simulation zu bewegen, müssen 3 Lokale Vektoren mitverwendet werden, welche ein lokales Koordinatensystem darstellen. Mit diesem Lokalen Koordinatensystem muss dann bei Drehungen gearbeitet werden. Das kommt aber in ein anderes Tutorial. Hier wird das ganze nur mit einem Vektor gemacht, was für den Anfang das Prinzip hinter der ganzen Geschichte verdeutlichen soll.&lt;br /&gt;
*Um die Vektor-Rotation durchführen zu können, verwende ich die Geometry.pas von GLScene. Bei dieser Datei handelt es sich um eine Ansammlung ziemlich nützlicher mathematischer Prozeduren welche teilweise sogar für 3Dnow ™ optimiert sind. Ursprünglich (ohne Optimierung für 3Dnow ™) kommt diese Unit von Mike Lischke.&lt;br /&gt;
*Ich gehe davon aus, dass ihr bereits wisst, wie ein Objekt mit Hilfe von glRotate gedreht, glTranslate positioniert und Objekte mit den entsprechenden Funktionen darstellt. Solltet ihr über dieses Wissen nicht verfügen, schaut euch die anderen Tutorials an. (z.B. [[Tutorial Matrix2]])&lt;br /&gt;
*Ihr wisst bescheid, was ein Vektor ist und was er macht. Wenn nicht: ein Vektor ist ein Zeiger von Punkt A auf Punkt B. A ist meistens der 0-Punkt des globalen Koordinatensystems und B die Position eures Objektes im 3D-Raum. Ok, das war der Vektor in Grob-Form.&lt;br /&gt;
*Das Ganze baut auf das API-Tutorial 2 auf. Es wurden eigentlich nur die Funktionen glDraw und ProcessKeys geändert.&lt;br /&gt;
&lt;br /&gt;
==Und los gehts==&lt;br /&gt;
&lt;br /&gt;
Da wir unser Objekt Rotieren, benötigen wir erst einmal die Variablen um die Rotation der entsprechenden Achse zu merken, sowie den Vektor welcher die Position unseres Objektes beinhaltet. Dieser ist in der Geometry.pas deklariert:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  RotateX  : single;                 // Rotation um die X-Achse&lt;br /&gt;
  RotateY  : single;                 // Rotation um die Y-Achse&lt;br /&gt;
  RotateZ  : single;                 // Rotation um die Z-Achse&lt;br /&gt;
  PosVect  : TVector3f;         // Vector mit der Position des Objektes.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Diese Variablen werden in der WndProc mit den Standard-Werten initialisiert. Dabei wird für den Positions-Vektor der Z Wert auf -5 gesetzt, damit das Objekt überhaupt mal sichtbar ist.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
RotateX := 0;&lt;br /&gt;
        RotateY := 0;&lt;br /&gt;
        RotateZ := 0;&lt;br /&gt;
        PosVect[0] := 0;&lt;br /&gt;
        PosVect[1] := 0;&lt;br /&gt;
        PosVect[2] := -5;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
So, nun kommen wir zu glDraw. Auch hier läuft alles nach dem alt bekannten System ab. Bildschirm und Z-Buffer löschen, Objekt positionieren, rotieren und dann zeichnen. Letzteres wurde von mir in die Prozedur DrawTheObject ausgelagert, um die glDraw nicht ganz so unübersichtlich zu gestallten. Es gibt eigentlich nur zwei Erweiterungen zum Tutorial 2.&lt;br /&gt;
&lt;br /&gt;
Die erste: Das Objekt wird um die X, Y und Z Achse gedreht wird, je nach Wert der Rotations-Variablen. Dabei ist die Reichenfolge von Zuerst X, Y, Z einzuhalten, da es sonst unerwünschten Resultaten kommt. (Echt witzig. Probiert's mal aus ;o) ). Die zweite: für Translate werden nun nicht mehr Fix-Werte verwendet, sondern die aktuellen Verte des Vektors welcher die aktuelle Position des Objektes beinhaltet.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glClearColor(0,0,0,0);&lt;br /&gt;
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
&lt;br /&gt;
  // Das Objekt auf seine aktuelle Position setzen.&lt;br /&gt;
  glTranslate( PosVect[0],  PosVect[1],  PosVect[2]);&lt;br /&gt;
&lt;br /&gt;
  { Das Objekt noch drehen, damit denn wir haben bis jetzt ja nur den }&lt;br /&gt;
  { Vector gedreht.                                                   }&lt;br /&gt;
  glRotate(RotateX, 1, 0, 0);&lt;br /&gt;
  glRotate(RotateY, 0, 1, 0);&lt;br /&gt;
  glRotate(RotateZ, 0, 0, 1);&lt;br /&gt;
&lt;br /&gt;
  DrawTheObject;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Prozedur DrawTheObject muss hier nicht weiter aufgelistet werden, da dort nur die (ständig unveränderten) Objekt-Daten an OpenGL weitergeleitet werden. Bis jetzt nichts außergewöhnliches, oder ?!?&lt;br /&gt;
&lt;br /&gt;
==Die Tasten-Verarbeitung==&lt;br /&gt;
&lt;br /&gt;
ProcessKey wurde ebenfalls ein kleinwenig angepasst. Hier werden die Tasten R (für Reset), W, S, A, D, Links, Rechts, Oben und Unten abgefragt und entsprechend reagiert. Dabei wird mit W und S das Objekt in der X-Achse gedreht, mit A und D in der Y Achse und mit Rechts und Links in der Z Achse. R setzt alles Werte wieder auf den Standard zurück. Ich führe hier nur als Beispiel die Abfrage für die X Achse an. R ist selbsterklärend und auf Oben und Unten gehe ich später noch genauer ein.&lt;br /&gt;
&lt;br /&gt;
Eigentlich wird hier nichts besonderes gemacht: Die Variable mit den Rotations-Daten werden entsprechend der gedrückten Taste angepasst. Sollte der Winkel 360 Grad über- oder 0 Grad unterschreiten, wird entsprechend zurückgesetzt, damit ein Drehwinkel von 0 - 360 Grad eingehalten wird. Ich habe übrigens für jede Rotation eine eigene Prozedur geschrieben um das ganze etwas übersichtlicher zu halten:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Überprüfen, ob W gedrückt wurde (Drehung um X-Achse)&lt;br /&gt;
  if Keys[ord('W')] then&lt;br /&gt;
  begin&lt;br /&gt;
    //--- Die Rotation um die X-Achse erhöhen. ---------------------------------&lt;br /&gt;
    RotateX := RotateX + 0.8;&lt;br /&gt;
    //--- Sollte RotateX größer als 360 Grad sein, den Wert umrechnen. Dadurch&lt;br /&gt;
    //    wird der Drehungs-Bereich auf 0 - 360 Grad begrenzt.&lt;br /&gt;
    if RotateX &amp;gt; 360 then RotateX := RotateX - 360;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Überprüfen, ob W gedrückt wurde (Drehung um X-Achse)&lt;br /&gt;
  if Keys[ord('S')] then&lt;br /&gt;
  begin&lt;br /&gt;
    //--- Die Rotation um die X-Achse erniedrigen. -----------------------------&lt;br /&gt;
    RotateX := RotateX - 0.8;&lt;br /&gt;
    //--- Sollte RotateX kleiner als 0 Grad sein, den Wert umrechnen. Dadurch&lt;br /&gt;
    //    wird der Drehungs-Bereich auf 0 - 360 Grad begrenzt.&lt;br /&gt;
    if RotateX &amp;lt;= 0 then RotateX := RotateX + 360;&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ich denke, mit Hilfe der Kommentare dürften alle übriggebliebenen Fragen geklärt sein (scheint so, als wäre ich Optimist *grins*). Wenn euch die Rotation zu langsam ist, verwendet einfach an Stelle von 0.8 einen anderen Wert. Je größer, um so schneller ist die Rotation.&lt;br /&gt;
&lt;br /&gt;
==Das ganze ist ein auf und ab...==&lt;br /&gt;
&lt;br /&gt;
Ich hab's euch versprochen: auf die Oben und Unten-Taste gehe ich genauer ein. Der Grund ist ganz einfach: hier spielt sich der eigentliche Vektor-Rotations-Vorgang ab. Hier liegt das Geheimnis. Aber keine Angst, ich gehe, wie versprochen, genauer darauf ein. Hier ist nur mal die Vollständige Prozedur:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure UpdateMovement;&lt;br /&gt;
const&lt;br /&gt;
  RotXAxis  : TVector3f = (1, 0, 0);&lt;br /&gt;
  RotYAxis  : TVector3f = (0, 1, 0);&lt;br /&gt;
  RotZAxis  : TVector3f = (0, 0, 1);&lt;br /&gt;
var&lt;br /&gt;
  Direction : single;&lt;br /&gt;
  LookVec   : TVector4f;&lt;br /&gt;
begin&lt;br /&gt;
  // Ist die Vorwärts-Taste gedrückt? Wenn ja, nach vorne gehen.&lt;br /&gt;
  if Keys[VK_UP] then Direction := 1 else&lt;br /&gt;
    // Ist die Rückwärtstaste gedrückt? Wenn ja, nach hinten gehen.&lt;br /&gt;
    if Keys[VK_DOWN] then Direction := -1 else&lt;br /&gt;
      // Wenn keine der beiden Tasten gedrückt wurde, kann die Prozedur&lt;br /&gt;
      // verlassen werden, da dann keine Positions-Anpassung notwendig&lt;br /&gt;
      // ist&lt;br /&gt;
      Exit;&lt;br /&gt;
&lt;br /&gt;
  // Den Blickrichtungs-Vektor initialisieren. Hier soll nur nach vorne,&lt;br /&gt;
  // also in die Y-Richtung geschaut werden.&lt;br /&gt;
  LookVec[0] := 0;&lt;br /&gt;
  LookVec[1] := 1;&lt;br /&gt;
  LookVec[2] := 0;&lt;br /&gt;
  // Den W-Wert auf 0 setzen. Wir benötigen ihn nicht.&lt;br /&gt;
  LookVec[3] := 0;&lt;br /&gt;
&lt;br /&gt;
  // Den Look-Vektor zuerst um die Z-Achse...&lt;br /&gt;
  RotateVector(LookVec, RotZAxis, -DegToRad(RotateZ));&lt;br /&gt;
  // ...um die Y-Achse...&lt;br /&gt;
  RotateVector(LookVec, RotYAxis, -DegToRad(RotateY));&lt;br /&gt;
  // ... und um die X-Achse drehen.&lt;br /&gt;
  RotateVector(LookVec, RotXAxis, -DegToRad(RotateX));&lt;br /&gt;
&lt;br /&gt;
  // Nun den gedrehten Vector zum Aktuellen Positions-Vektor&lt;br /&gt;
  // hinzuzählen. Damit die Bewegung beachtet wird, das ganze&lt;br /&gt;
  // um den Speed-Faktor 0.01 mal Direction multiplizieren.&lt;br /&gt;
  PosVect[0] := PosVect[0] + (LookVec[0] * (Direction * 0.01));&lt;br /&gt;
  PosVect[1] := PosVect[1] + (LookVec[1] * (Direction * 0.01));&lt;br /&gt;
  PosVect[2] := PosVect[2] + (LookVec[2] * (Direction * 0.01));&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Eigentlich gar nicht viel, oder?!? Fangen wird am Anfang an. Wenn ich das Objekt in seiner Position verändern will (durch betätigen der Oben bzw. Unten Tasten), so muss ich zuerst einmal feststellen, in welche Richtung das Objekt verschoben werden soll:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Ist die Vorwärts-Taste gedrückt? Wenn ja, nach vorne gehen.&lt;br /&gt;
  if Keys[VK_UP] then Direction := 1 else&lt;br /&gt;
    // Ist die Rückwärtstaste gedrückt? Wenn ja, nach hinten gehen.&lt;br /&gt;
    if Keys[VK_DOWN] then Direction := -1 else&lt;br /&gt;
      // Wenn keine der beiden Tasten gedrückt wurde, kann die Prozedur&lt;br /&gt;
      // verlassen werden, da dann keine Positions-Anpassung notwendig&lt;br /&gt;
      // ist&lt;br /&gt;
      Exit;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Sollte keine der beiden Tasten betätigt worden sein, dann MUSS die Funktion verlassen werden, um keine falschen Rechnungen durchzuführen. Sonst kann es sein, dass sich das Objekt ohne eure Kontrolle dauernd verschiebt. Ok, wenn ich also nach oben gehen will, wird Direction auf 1 und anderen Falls auf -1 gesetzt. Ich Denke, der Grund dürfte Klar sein: 1 -&amp;gt; vorwärts und -1 -&amp;gt; Rückwärts. Das ganze basiert auf einfachste Mathematik ;o) (Ja, wirklich, man benötigt kein ABI, um 3D-Progger zu sein!!!)&lt;br /&gt;
&lt;br /&gt;
Als nächstes wird mein Richtungs-Vektor initialisiert. Der 2 Eintrag (Y Achse) wird auf 1 gesetzt, da der Richtungs-Vektor in der Null-Stellung des Objektes parallel zur Y Achse steht. Der Grund: das Objekt &amp;quot;blickt&amp;quot; am Anfang oder nach einem Reset auf die Caption des Fensters.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Den Blickrichtungs-Vektor initialisieren. Hier soll nur nach vorne,&lt;br /&gt;
  // also in die Y-Richtung geschaut werden.&lt;br /&gt;
  LookVec[0] := 0;&lt;br /&gt;
  LookVec[1] := 1;&lt;br /&gt;
  LookVec[2] := 0;&lt;br /&gt;
  // Den W-Wert auf 0 setzen. Wir benötigen ihn nicht.&lt;br /&gt;
  LookVec[3] := 0;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Lasst euch von der letzten Zeile nicht irritieren. Es gibt auch noch Vektoren welche einen W-Wert haben. Die RotateVector Funktion arbeitet mit einem solchen Vektor, da bei der Rotation ein Vektor mit einer Rotations-Matrix verrechnet wird, und diese eben ein 4x4 Feld hat. Aus diesem Grund wurde auch der TVector4f Typ verwendet. -&amp;gt; Ignoriert es einfach, der Wert wird sowieso nicht benötigt und sollte deswegen auf 0 stehen.&lt;br /&gt;
&lt;br /&gt;
Nun wird der Vektor um die 3 Achsen gedreht. Da die RotateVector-Funktion einen &amp;quot;Standard-Vektor&amp;quot; (also mit X, Y und Z Wert) benötigt um zu wissen, um welche Achse gedreht werden soll, sind diese am Anfang der Prozedur im const-Bereich als Rot[Achse]Axis definiert. Das ist übrigens das gleiche wie bei glRotate, nur das dort die X, Y und Z Werte getrennt und in einem Vektor zusammengefasst übergeben werden. Hier ist es übrigens auch sehr wichtig, die umgekehrte Reihenfolge zu verwenden. Also zuerst Drehung um die Z, dann um die Y und zum Schluss um die X Achse. Warum weis ich leider auch nicht. Der Winkel muss hier in einen RAD konvertiert werden, da die Funktion nicht mit GRAD angaben arbeitet. Außerdem muss der Winkel noch Invertiert, also mit einem - versehen werden, da sonst der Vektor in die entgegengesetzte Richtung zum Objekt gedreht wird. Ist nicht das was wir wollen. Warum genau, kann ich nicht so direkt erklären. Aber man muss auch nicht alles wissen ;o) Wenn es aber doch jemand weis warum, darf er mir das durchaus mitteilen. Ich lerne gerne dazu!&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Den Look-Vektor zuerst um die Z-Achse...&lt;br /&gt;
  RotateVector(LookVec, RotZAxis, -DegToRad(RotateZ));&lt;br /&gt;
  // ...um die Y-Achse...&lt;br /&gt;
  RotateVector(LookVec, RotYAxis, -DegToRad(RotateY));&lt;br /&gt;
  // ... und um die X-Achse drehen.&lt;br /&gt;
  RotateVector(LookVec, RotXAxis, -DegToRad(RotateX));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Eigentlich gar nicht schwer, oder?!?&lt;br /&gt;
&lt;br /&gt;
==Ein kleiner Ausflug==&lt;br /&gt;
&lt;br /&gt;
Ok, ganz ohne Mathematik geht es leider doch nicht. Jetzt haben wird den gedrehten Vektor und wissen, in welcher Richtung vorne liegt. Aber wie bekomme ich aus dieser Information meine neue Objekt-Position?!? Das Stichwort heißt: Vektor-Arithmetik. Keine Angst, ist nicht schlimm. Folgende &amp;quot;Skizze&amp;quot; soll helfen, sich das Ganze vorzustellen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Objekt_gedreht_und_dennoch_nach_vorne_bewegt_Skizze.gif]]&lt;br /&gt;
&lt;br /&gt;
Wir haben einen Vektor, welcher von A nach B zeigt (ich nenne ich AB). Und wird haben einen, welcher von B nach C Zeigt (BC). Letzterer ist unser Richtungs-Vektor. Ok, so weit so gut, aber wir benötigen einen neuen Positions-Vektor : AC. Denn die neue Position ist C also muss ein Vektor von A (Ursprung) nach C (neue Position) zeigen. Den erhalten wir ganz einfach. Wirklich kein Problem. Einfachste Mathematik:&lt;br /&gt;
&lt;br /&gt;
:AC = AB + BC&lt;br /&gt;
&lt;br /&gt;
Boah ey... cool, oder? So einfach und schon haben wir die neue Position. DAS war Vektor-Arithmetik. Ein Kumpel sagte mal, das Matrizen und Vektoren Rechnung eigentlich wirklich nicht kompliziert ist. Und er hatte recht. +, - ,* und / ist doch wirklich kein Problem, oder?!?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Das neue Ziel==&lt;br /&gt;
&lt;br /&gt;
Ok, nun addieren wir einfach die beiden Vektoren miteinander. Der Richtungs-Vektor muss nur noch etwas &amp;quot;verlängert&amp;quot; werden. Denn bisher haben wir nur die Richtung. Das ganze mit einer Zahl (z.B. 5) multiplizieren, und wir haben unser Objekt 5 Schritte in Blickrichtung bewegt. Hä?!? Warum soll bitte Mathe für 3D-Progger schwer sein?!?&lt;br /&gt;
&lt;br /&gt;
Ich habe das ganze hier so gelöst: Ich multipliziere den Vektor mit der Geschwindigkeit, mit welcher er sich bewegen soll. Erinnert ihr euch noch an Direction? Ja? Gut. Denn somit haben wir die Schritt-Weite. Entweder ein Schritt nach vorne, oder -1 Schritt nach vorne was einem Schritt nach hinten entspricht! Das ganze sieht dann so aus:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Nun den gedrehten Vektor zum Aktuellen Positions-Vektor&lt;br /&gt;
  // hinzuzählen. Damit die Bewegung beachtet wird, das ganze&lt;br /&gt;
  // um den Speed-Faktor 0.01 mal Direction multiplizieren.&lt;br /&gt;
  PosVect[0] := PosVect[0] + (LookVec[0] * (Direction * 0.01));&lt;br /&gt;
  PosVect[1] := PosVect[1] + (LookVec[1] * (Direction * 0.01));&lt;br /&gt;
  PosVect[2] := PosVect[2] + (LookVec[2] * (Direction * 0.01));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
0.01 ist hier dann die Geschwindigkeit und kann nach Lust und Laune von Euch verändert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Happy End?!?==&lt;br /&gt;
&lt;br /&gt;
Wie, DAS war alles? Ja. Es ist gar nicht so schwer wenn man weis, wie es geht. Und dank der Funktionen der Geometry.pas wird einem einiges abgenommen. Die Rotation eines Vektors selber ist eigentlich auch nicht sooo kompliziert, nur IMO etwas schwer zu erklären.&lt;br /&gt;
&lt;br /&gt;
==Und wie geht's jetzt weiter?==&lt;br /&gt;
&lt;br /&gt;
Das liegt an Euch. Wie gesagt: in unserem Beispiel bewegt sich das Objekt nicht ganz so, wie man es von einem Raumgleiter gewöhnt ist. Das Problem ist ganz einfach erklärt: Das Objekt dreht sich immer um das globale Koordinatensystem. Um also die richtige Drehung durch zu führen, muss ein lokales Koordinatensystem mitgeführt werden. Also 3 Vektoren anstelle von einem. Aber dafür gibt's später mal ein anderes Tutorial. Jetzt geht's erst mal in Urlaub ;o)&lt;br /&gt;
&lt;br /&gt;
Außerdem ist hier überhaupt kein Wert auf Optimierung gelegt worden, sondern es ging nur um das Verständnis der Materie selber.&lt;br /&gt;
&lt;br /&gt;
Viel Spaß beim Proggen und liefert DGL ne menge Feedback!!!&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
&lt;br /&gt;
SchodMC&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Nachsitzen]] | [[Tutorial Objekt immer um eigene Achse drehen]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Objekt gedreht]]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Timebased_Movement&amp;diff=20666</id>
		<title>Timebased Movement</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Timebased_Movement&amp;diff=20666"/>
				<updated>2007-07-29T10:04:14Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: /* Prinzip */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Kurz-Beschreibung ==&lt;br /&gt;
'''Timebased Movement''' sorgt dafür, dass die Bewegungsgeschwindigkeiten nicht vom CPU-/Renderspeed abhängen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prinzip ==&lt;br /&gt;
Nehmen wir an wir möchten einen Ball darstellen der sich mit konstanter Geschwindigkeit vom linken Bildschirmrand zum rechten Bildschirmrand bewegt.&lt;br /&gt;
&lt;br /&gt;
Das erste Bild wird den Ball ganz links zeigen. Auf dem nächsten Bild wird der Ball ein Stück weiter sein, die Frage ist nur wie weit? Die Länge der Strecke die der Ball zurücklegen muss legen wir nun mal willkürlich auf 1 Längeneinheit (kurz: LE) fest. Die Strecke soll er in 5 Sekunden zurück legen.&lt;br /&gt;
&lt;br /&gt;
Ein Rechner A braucht 1 Sekunde um 1 Bild zu Berechnen. Um das gewünschte Ergebnis zu erreichen müssten wir den Ball nach jedem Bild 0.2 Felder weiterbewegen.&lt;br /&gt;
&lt;br /&gt;
In einer Sekunde hätten wir also folgende Bilder:&lt;br /&gt;
* Bild 0: Ball Position: 0.0&lt;br /&gt;
* Bild 1: Ball Position: 0.2 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 2: Ball Position: 0.4 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 3: Ball Position: 0.6 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 4: Ball Position: 0.8 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 5: Ball Position: 1.0 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
&lt;br /&gt;
Ein Rechner B braucht nur 0.5 Sekunden um ein Bild zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Ebenfalls in nur einer Sekunde hätten wir folgende Bilder:&lt;br /&gt;
* Bild 0:  Ball Position: 0.0&lt;br /&gt;
* Bild 1:  Ball Position: 0.1 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 2:  Ball Position: 0.2 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 3:  Ball Position: 0.3 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 4:  Ball Position: 0.4 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 5:  Ball Position: 0.5 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 6:  Ball Position: 0.6 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 7:  Ball Position: 0.7 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 8:  Ball Position: 0.8 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 9:  Ball Position: 0.9 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 10: Ball Position: 1.0 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
&lt;br /&gt;
Bei dem einen Rechner muss der Ball bei jedem Bild um 0.2 LE bewegt werden, beim andern Rechner nur 0.1 LE pro Bild. Tut man dies nicht, bewegt sich der Ball zu schnell oder zu langsam. &lt;br /&gt;
&lt;br /&gt;
Doch woher weiß man nun wie weit man seinen Ball auf den jeweiligen Rechner pro Bild bewegen muss?&lt;br /&gt;
&lt;br /&gt;
In unserem Beispiel bewegt sich der Ball mit der konstanten Geschwindigkeit von 0.2 LE pro Sekunde. Mit folgender Formel können wir bei konstanter Geschwindigkeit die neue Position berechnen:&lt;br /&gt;
&lt;br /&gt;
 neue_Position = Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
&lt;br /&gt;
Wir brauchen also nur eine Geschwindigkeit festlegen und messen, wie viel Zeit vergangen ist, um die neue Position zu berechnen zu können.&lt;br /&gt;
&lt;br /&gt;
Wohlgemerkt gilt diese Formel nur wenn sich das Objekt mit konstanter Geschwindigkeit fortbewegt.&lt;br /&gt;
&lt;br /&gt;
== Berechnung der vergangen Zeit ==&lt;br /&gt;
&lt;br /&gt;
Allgemein:&lt;br /&gt;
 VergangeneZeit := ( Zeit1 - Zeit0 ) / Frequenz;&lt;br /&gt;
&lt;br /&gt;
=== Millisekunden genau unter Windows===&lt;br /&gt;
Die wohl einfachste aber auch ungenaueste Möglichkeit unter Windows so etwas zu realisieren besteht darin mit Hilfe von GetTickCount die Zeit (in Millisekunden) seit dem letzen Windows-Start zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Benötigte Variablen&lt;br /&gt;
var&lt;br /&gt;
  BerechnungsZeit : LongWord;&lt;br /&gt;
  Position        : Double;&lt;br /&gt;
&lt;br /&gt;
procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden&lt;br /&gt;
begin&lt;br /&gt;
  BerechnungsZeit := GetTickCount();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen&lt;br /&gt;
const&lt;br /&gt;
  Frequenz = 1000; // Durch Windows festgelegt&lt;br /&gt;
var&lt;br /&gt;
  AktuelleZeit : LongWord;&lt;br /&gt;
begin&lt;br /&gt;
  AktuelleZeit := GetTickCount();&lt;br /&gt;
  Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);&lt;br /&gt;
  BerechnungsZeit := AktuelleZeit;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure Berechne(vergangene_Zeit : Double);&lt;br /&gt;
const&lt;br /&gt;
  Geschwindigkeit = 0.5;&lt;br /&gt;
begin&lt;br /&gt;
  {Alle Berechnungen stehen hier }&lt;br /&gt;
  // z.B.&lt;br /&gt;
  Position := Geschwindigkeit * vergangene_Zeit + Position;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Absolute Genauigkeit per Hardware ===&lt;br /&gt;
Man kann auch die Hardware zur Zeitmessung nutzen um so noch genauere Ergebnisse zu erziehlen. Es kann jedoch theoretisch sein, dass diese nicht zur Verfügung steht.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Benötigte Variablen&lt;br /&gt;
var&lt;br /&gt;
  BerechnungsZeit : Int64;&lt;br /&gt;
  Frequenz        : Int64;&lt;br /&gt;
  Position        : Double;&lt;br /&gt;
&lt;br /&gt;
procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden&lt;br /&gt;
begin&lt;br /&gt;
  if not QueryPerformanceFrequency(Frequenz) then // Frequenz ermitteln&lt;br /&gt;
   raise Exception.create('Kein Hardware Timer vorhanden');&lt;br /&gt;
  QueryPerformanceCounter(BerechnungsZeit); // Aktuelle Zeit ermitteln&lt;br /&gt;
end;&lt;br /&gt;
procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen&lt;br /&gt;
var&lt;br /&gt;
  AktuelleZeit : Int64;&lt;br /&gt;
begin&lt;br /&gt;
  QueryPerformanceCounter(AktuelleZeit);&lt;br /&gt;
  Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);&lt;br /&gt;
  BerechnungsZeit := AktuelleZeit;&lt;br /&gt;
end;&lt;br /&gt;
procedure Berechne(vergangene_Zeit : Double);&lt;br /&gt;
const&lt;br /&gt;
  Geschwindigkeit = 0.5;&lt;br /&gt;
begin&lt;br /&gt;
  {Alle Berechnungen stehen hier }&lt;br /&gt;
  // z.B.&lt;br /&gt;
  Position := Geschwindigkeit * vergangene_Zeit + Position;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man hat nun den Speedfactor, den man mit sämtlichen Bewegungen multipliziert. Wenn der PC viele Frames per Second rendert wird der Speedfactor klein. Die Bewegungen werden dadurch naturlich auch kleiner. Wenn der PC wenige Frames per Second rendert wird der Speedfactor groß, die Bewegungen also auch größer.&lt;br /&gt;
&lt;br /&gt;
== Konstant Beschleunigte Bewegung ==&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir möchten darstellen wie ein Ball zu Boden fällt. Der Ball sei 1 LE über dem Boden und wird dort zum Zeitpunkt 0s losgelassen. Die Kraft welche die Erdanziehung simuliert soll pro Sekunde die Geschwindigkeit des Balles um 1 LE/s erhöhen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die neue Geschwindigkeit die sich durch die Beschleunigung ergeben hat, läßt sich noch sehr einfach Berechnen:&lt;br /&gt;
 neue_Geschwindigkeit := Beschleunigung * vergangene_Zeit + alte_Geschwindigkeit;&lt;br /&gt;
&lt;br /&gt;
Wie sieht es aber mit der Position aus?&lt;br /&gt;
&lt;br /&gt;
Falsch wäre diese Berechnung:&lt;br /&gt;
 neue_Position := alte_Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
Denn so würde sich der Ball von Bild 0 nach Bild 1 gar nicht bewegen.&lt;br /&gt;
&lt;br /&gt;
Genauso falsch wäre diese Berechnung:&lt;br /&gt;
 neue_Position := neue_Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
&lt;br /&gt;
Denn dann würde sich der Ball sofort mit der vollen Geschwindigkeit bewegen und wäre viel zu schnell ab Boden.&lt;br /&gt;
&lt;br /&gt;
Wer sich ein wenig mit Physik auskennt weiß das man bei konstant Beschleunigter Bewegung so die neue Position ausrechnet:&lt;br /&gt;
 neue_Position := 0.5 * Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
&lt;br /&gt;
Beispielcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  Position        : Double;&lt;br /&gt;
  Geschwindigkeit : Double;&lt;br /&gt;
procedure Berechne(vergangene_Zeit : Double);&lt;br /&gt;
const&lt;br /&gt;
  Beschleunigung = 1;&lt;br /&gt;
begin&lt;br /&gt;
  Position := 0.5*Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + Position&lt;br /&gt;
  // Wichtig: alte Geschwindigkeit erst ändern wenn sie nicht mehr gebraucht wird.&lt;br /&gt;
  Geschwindigkeit := Beschleunigung * vergangene_Zeit + Geschwindigkeit&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Umsetzung mit einer Delphi Form ==&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var &lt;br /&gt;
[...] &lt;br /&gt;
 Frequency, StartCount, EndCount: Int64; &lt;br /&gt;
 Speedfactor: Extended;&lt;br /&gt;
&lt;br /&gt;
const &lt;br /&gt;
 Scalefactor = 100;       //Der Scalefactor ist ein beliebiger Wert um den Speedfactor&lt;br /&gt;
                          //zu beeinflussen&lt;br /&gt;
[...]&lt;br /&gt;
procedure TForm1.FormCreate(Sender: TObject);&lt;br /&gt;
begin &lt;br /&gt;
 if not QueryPerformanceFrequency(Frequency) then&lt;br /&gt;
  raise Exception.create('Kein Hardware Timer vorhanden');&lt;br /&gt;
 QueryPerformanceFrequency(Frequency); //Frequenz des Rechners ermitteln &lt;br /&gt;
 [...]&lt;br /&gt;
end;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);&lt;br /&gt;
begin &lt;br /&gt;
 QueryPerformanceCounter(StartCount); //Zeit0 &lt;br /&gt;
 Form1.Render; &lt;br /&gt;
 QueryPerformanceCounter(EndCount); //Zeit1  &lt;br /&gt;
 Speedfactor := ((EndCount - StartCount) /Frequency) * Scalefactor //(Zeit1 - Zeit0) / Frequenz&lt;br /&gt;
 [...]&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man hat nun den Speedfactor, den man mit sämtlichen Bewegungen multipliziert. Und schon hat man eine einfache Umsetzung von Timebased movement, ohne sich über Physik Gedanken machen zu müssen.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
*[http://www.delphigl.com/script/do_show.php?name=bombman2&amp;amp;action=2 Bomberman DGL-Tutorial]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Timebased_Movement&amp;diff=20665</id>
		<title>Timebased Movement</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Timebased_Movement&amp;diff=20665"/>
				<updated>2007-07-29T10:03:41Z</updated>
		
		<summary type="html">&lt;p&gt;Wilson: /* Prinzip */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Kurz-Beschreibung ==&lt;br /&gt;
'''Timebased Movement''' sorgt dafür, dass die Bewegungsgeschwindigkeiten nicht vom CPU-/Renderspeed abhängen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prinzip ==&lt;br /&gt;
Nehmen wir an wir möchten einen Ball darstellen der sich mit konstanter Geschwindigkeit vom linken Bildschirmrand zum rechten Bildschirmrand bewegt.&lt;br /&gt;
&lt;br /&gt;
Das erste Bild wird den Ball ganz links zeigen. Auf dem nächsten Bild wird der Ball ein Stück weiter sein, die Frage ist nur wie weit? Die Länge der Strecke die der Ball zurücklegen muss legen wir nun mal willkürlich auf 1 Längeneinheit (kurz: LE) fest. Die Strecke soll er in 5 Sekunden zurück legen.&lt;br /&gt;
&lt;br /&gt;
Ein Rechner A braucht 1 Sekunde um 1 Bild zu Berechnen. Um das gewünschte Ergebnis zu erreichen müssten wir den Ball nach jedem Bild 0.2 Felder weiterbewegen.&lt;br /&gt;
&lt;br /&gt;
In einer Sekunde hätten wir also folgende Bilder:&lt;br /&gt;
* Bild 0: Ball Position: 0.0&lt;br /&gt;
* Bild 1: Ball Position: 0.2 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 2: Ball Position: 0.4 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 3: Ball Position: 0.6 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 4: Ball Position: 0.8 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
* Bild 5: Ball Position: 1.0 (weiterbewegt um 0.2 LE in 1.0 Sekunden)&lt;br /&gt;
&lt;br /&gt;
Ein Rechner B braucht nur 0.5 Sekunden um ein Bild zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Ebenfalls in nur einer Sekunde hätten wir folgende Bilder:&lt;br /&gt;
* Bild 0:  Ball Position: 0.0&lt;br /&gt;
* Bild 1:  Ball Position: 0.1 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 2:  Ball Position: 0.2 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 3:  Ball Position: 0.3 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 4:  Ball Position: 0.4 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 5:  Ball Position: 0.5 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 6:  Ball Position: 0.6 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 7:  Ball Position: 0.7 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 8:  Ball Position: 0.8 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 9:  Ball Position: 0.9 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
* Bild 10: Ball Position: 1.0 (weiterbewegt um: 0.1 LE in 0.5 Sekunden)&lt;br /&gt;
&lt;br /&gt;
Bei dem einen Rechner muss der Ball bei jedem Bild um 0.2 LE bewegt werden, beim andern Rechner nur 0.1 LE pro Bild. Tut man dies nicht, bewegt sich der Ball zu schnell oder zu langsam. &lt;br /&gt;
&lt;br /&gt;
Doch woher weiß man nun wie weit man seinen Ball auf den jeweiligen Rechner pro Bild bewegen muss?&lt;br /&gt;
&lt;br /&gt;
In unserem Beispiel bewegt sich der Ball mit der konstanten Geschwindigkeit von 0.2 LE pro Sekunde. Mit folgender Formel können wir bei konstanter Geschwindigkeit die neue Position berechnen:&lt;br /&gt;
&lt;br /&gt;
 neue_Position = Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
&lt;br /&gt;
Wir brauchen also nur eine Geschwindigkeit festlegen und messen wie viel Zeit vergangen ist um die neue Position zu berechnen zu können.&lt;br /&gt;
&lt;br /&gt;
Wohlgemerkt gilt diese Formel nur wenn sich das Objekt mit konstanter Geschwindigkeit fortbewegt.&lt;br /&gt;
&lt;br /&gt;
== Berechnung der vergangen Zeit ==&lt;br /&gt;
&lt;br /&gt;
Allgemein:&lt;br /&gt;
 VergangeneZeit := ( Zeit1 - Zeit0 ) / Frequenz;&lt;br /&gt;
&lt;br /&gt;
=== Millisekunden genau unter Windows===&lt;br /&gt;
Die wohl einfachste aber auch ungenaueste Möglichkeit unter Windows so etwas zu realisieren besteht darin mit Hilfe von GetTickCount die Zeit (in Millisekunden) seit dem letzen Windows-Start zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Benötigte Variablen&lt;br /&gt;
var&lt;br /&gt;
  BerechnungsZeit : LongWord;&lt;br /&gt;
  Position        : Double;&lt;br /&gt;
&lt;br /&gt;
procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden&lt;br /&gt;
begin&lt;br /&gt;
  BerechnungsZeit := GetTickCount();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen&lt;br /&gt;
const&lt;br /&gt;
  Frequenz = 1000; // Durch Windows festgelegt&lt;br /&gt;
var&lt;br /&gt;
  AktuelleZeit : LongWord;&lt;br /&gt;
begin&lt;br /&gt;
  AktuelleZeit := GetTickCount();&lt;br /&gt;
  Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);&lt;br /&gt;
  BerechnungsZeit := AktuelleZeit;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure Berechne(vergangene_Zeit : Double);&lt;br /&gt;
const&lt;br /&gt;
  Geschwindigkeit = 0.5;&lt;br /&gt;
begin&lt;br /&gt;
  {Alle Berechnungen stehen hier }&lt;br /&gt;
  // z.B.&lt;br /&gt;
  Position := Geschwindigkeit * vergangene_Zeit + Position;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Absolute Genauigkeit per Hardware ===&lt;br /&gt;
Man kann auch die Hardware zur Zeitmessung nutzen um so noch genauere Ergebnisse zu erziehlen. Es kann jedoch theoretisch sein, dass diese nicht zur Verfügung steht.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Benötigte Variablen&lt;br /&gt;
var&lt;br /&gt;
  BerechnungsZeit : Int64;&lt;br /&gt;
  Frequenz        : Int64;&lt;br /&gt;
  Position        : Double;&lt;br /&gt;
&lt;br /&gt;
procedure BeimStart; // Was hier drinnen steht sollte zum Start ausgeführt werden&lt;br /&gt;
begin&lt;br /&gt;
  if not QueryPerformanceFrequency(Frequenz) then // Frequenz ermitteln&lt;br /&gt;
   raise Exception.create('Kein Hardware Timer vorhanden');&lt;br /&gt;
  QueryPerformanceCounter(BerechnungsZeit); // Aktuelle Zeit ermitteln&lt;br /&gt;
end;&lt;br /&gt;
procedure BerechnungsCheck; // Alle nötigen Berechnungen durchführen&lt;br /&gt;
var&lt;br /&gt;
  AktuelleZeit : Int64;&lt;br /&gt;
begin&lt;br /&gt;
  QueryPerformanceCounter(AktuelleZeit);&lt;br /&gt;
  Berechne((AktuelleZeit - BerechnungsZeit) / Frequenz);&lt;br /&gt;
  BerechnungsZeit := AktuelleZeit;&lt;br /&gt;
end;&lt;br /&gt;
procedure Berechne(vergangene_Zeit : Double);&lt;br /&gt;
const&lt;br /&gt;
  Geschwindigkeit = 0.5;&lt;br /&gt;
begin&lt;br /&gt;
  {Alle Berechnungen stehen hier }&lt;br /&gt;
  // z.B.&lt;br /&gt;
  Position := Geschwindigkeit * vergangene_Zeit + Position;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man hat nun den Speedfactor, den man mit sämtlichen Bewegungen multipliziert. Wenn der PC viele Frames per Second rendert wird der Speedfactor klein. Die Bewegungen werden dadurch naturlich auch kleiner. Wenn der PC wenige Frames per Second rendert wird der Speedfactor groß, die Bewegungen also auch größer.&lt;br /&gt;
&lt;br /&gt;
== Konstant Beschleunigte Bewegung ==&lt;br /&gt;
&lt;br /&gt;
Nehmen wir an wir möchten darstellen wie ein Ball zu Boden fällt. Der Ball sei 1 LE über dem Boden und wird dort zum Zeitpunkt 0s losgelassen. Die Kraft welche die Erdanziehung simuliert soll pro Sekunde die Geschwindigkeit des Balles um 1 LE/s erhöhen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die neue Geschwindigkeit die sich durch die Beschleunigung ergeben hat, läßt sich noch sehr einfach Berechnen:&lt;br /&gt;
 neue_Geschwindigkeit := Beschleunigung * vergangene_Zeit + alte_Geschwindigkeit;&lt;br /&gt;
&lt;br /&gt;
Wie sieht es aber mit der Position aus?&lt;br /&gt;
&lt;br /&gt;
Falsch wäre diese Berechnung:&lt;br /&gt;
 neue_Position := alte_Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
Denn so würde sich der Ball von Bild 0 nach Bild 1 gar nicht bewegen.&lt;br /&gt;
&lt;br /&gt;
Genauso falsch wäre diese Berechnung:&lt;br /&gt;
 neue_Position := neue_Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
&lt;br /&gt;
Denn dann würde sich der Ball sofort mit der vollen Geschwindigkeit bewegen und wäre viel zu schnell ab Boden.&lt;br /&gt;
&lt;br /&gt;
Wer sich ein wenig mit Physik auskennt weiß das man bei konstant Beschleunigter Bewegung so die neue Position ausrechnet:&lt;br /&gt;
 neue_Position := 0.5 * Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + alte_Position&lt;br /&gt;
&lt;br /&gt;
Beispielcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  Position        : Double;&lt;br /&gt;
  Geschwindigkeit : Double;&lt;br /&gt;
procedure Berechne(vergangene_Zeit : Double);&lt;br /&gt;
const&lt;br /&gt;
  Beschleunigung = 1;&lt;br /&gt;
begin&lt;br /&gt;
  Position := 0.5*Beschleunigung * vergangene_Zeit * vergangene_Zeit + Geschwindigkeit * vergangene_Zeit + Position&lt;br /&gt;
  // Wichtig: alte Geschwindigkeit erst ändern wenn sie nicht mehr gebraucht wird.&lt;br /&gt;
  Geschwindigkeit := Beschleunigung * vergangene_Zeit + Geschwindigkeit&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Umsetzung mit einer Delphi Form ==&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
var &lt;br /&gt;
[...] &lt;br /&gt;
 Frequency, StartCount, EndCount: Int64; &lt;br /&gt;
 Speedfactor: Extended;&lt;br /&gt;
&lt;br /&gt;
const &lt;br /&gt;
 Scalefactor = 100;       //Der Scalefactor ist ein beliebiger Wert um den Speedfactor&lt;br /&gt;
                          //zu beeinflussen&lt;br /&gt;
[...]&lt;br /&gt;
procedure TForm1.FormCreate(Sender: TObject);&lt;br /&gt;
begin &lt;br /&gt;
 if not QueryPerformanceFrequency(Frequency) then&lt;br /&gt;
  raise Exception.create('Kein Hardware Timer vorhanden');&lt;br /&gt;
 QueryPerformanceFrequency(Frequency); //Frequenz des Rechners ermitteln &lt;br /&gt;
 [...]&lt;br /&gt;
end;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);&lt;br /&gt;
begin &lt;br /&gt;
 QueryPerformanceCounter(StartCount); //Zeit0 &lt;br /&gt;
 Form1.Render; &lt;br /&gt;
 QueryPerformanceCounter(EndCount); //Zeit1  &lt;br /&gt;
 Speedfactor := ((EndCount - StartCount) /Frequency) * Scalefactor //(Zeit1 - Zeit0) / Frequenz&lt;br /&gt;
 [...]&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man hat nun den Speedfactor, den man mit sämtlichen Bewegungen multipliziert. Und schon hat man eine einfache Umsetzung von Timebased movement, ohne sich über Physik Gedanken machen zu müssen.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
*[http://www.delphigl.com/script/do_show.php?name=bombman2&amp;amp;action=2 Bomberman DGL-Tutorial]&lt;/div&gt;</summary>
		<author><name>Wilson</name></author>	</entry>

	</feed>