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

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Bloom(pseudo-HDR)&amp;diff=26281</id>
		<title>Bloom(pseudo-HDR)</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Bloom(pseudo-HDR)&amp;diff=26281"/>
				<updated>2014-11-24T13:23:00Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Vor- und Nachteile */ Aktuallisierung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Konzept==&lt;br /&gt;
Dieser Artikel zeigt, wie man den bei HDR bekannten Bloom Effekt erzeugt.&lt;br /&gt;
Dieser simuliert den Einfluss von Eigenschaften der menschlichen Pupille.&lt;br /&gt;
Bei dieser Technik ist eine Hardware nötig die OpenGL1.1 API unterstützt.&lt;br /&gt;
&lt;br /&gt;
Um die Qualität des Effektes zu erhöhen, ist es nötig eine nicht völlig ausgelastete CPU zu haben.&lt;br /&gt;
{{Hinweis|Diese Technik funktioniert nur auf den Hintergrund, nicht auf leuchtende Objekte.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zuerst brauchen wir eine Textur, die unseren [[Tiefenpuffer|Z-Buffer]] darstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:fake_z-buffer.png|center]]&lt;br /&gt;
Die Textur muss dann geblurt werden, um einen Verlauf an den Rändern der Geometrie zu erzeugen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:fake_z-buffer-blured.png|center]]&lt;br /&gt;
&lt;br /&gt;
Nun wird die geblurte Textur über die zu rendernde Szene übergeblendet.&lt;br /&gt;
&lt;br /&gt;
[[Bild:fake_z-buffer-blured.png]]+[[Bild:szene.png]]=[[Bild:composit.png]]&lt;br /&gt;
&lt;br /&gt;
==Umsetzung==&lt;br /&gt;
Um die Z-Buffer Textur als RGB zu bekommen, ist ein weiterer Fake von nöten.&lt;br /&gt;
Es gibt mit neuen Techniken die Möglichkeit den Z-Buffer in eine Textur auszulesen aber diese wären warscheinlich nicht so schnell.&lt;br /&gt;
&lt;br /&gt;
Wie erstelle ich also die Z-Buffer Textur ?&lt;br /&gt;
*Modelview Matrix sichern&lt;br /&gt;
*Clearcolor von OpenGL auf Weiß oder andere helle Farben (je nach Himmelfarbe) stellen&lt;br /&gt;
*[[Viewport]] auf eine niedrige Auflösung stellen(z.B. 128x96 oder 64x48)&lt;br /&gt;
*alle Puffer löschen&lt;br /&gt;
*[[Nebel]] aktivieren und die Farbe auf schwarz setzen&lt;br /&gt;
*die Szene rendern&lt;br /&gt;
*[[glCopyTexImage2D]] ausführen&lt;br /&gt;
*Viewport zurück stellen&lt;br /&gt;
*Fog deaktivieren&lt;br /&gt;
*Modelview Matrix wieder herstellen&lt;br /&gt;
&lt;br /&gt;
Dies ist eine ziemlich dreckige Methode aber sie funktioniert und ist ziemlich schnell.&lt;br /&gt;
&lt;br /&gt;
Nun muss die Textur in unseren Arbeitspeicher geladen werden und geblurt werden.&lt;br /&gt;
Hierzu verwendet man glGetTexImage und nach dem Blur muss es wieder eine Textur werden, dies macht man mit glTexImage2D.&lt;br /&gt;
&lt;br /&gt;
Was nun?&lt;br /&gt;
*alle Puffer löschen&lt;br /&gt;
*die Szene rendern&lt;br /&gt;
*Blending aktivieren&lt;br /&gt;
*[[glBlendFunc]](GL_ONE,GL_ONE);&lt;br /&gt;
*die Textur vom Z-Buffer binden&lt;br /&gt;
*in den [[glOrtho|orthogonalen]] Modus wechseln&lt;br /&gt;
*mit glcolor3f(glowing,glowing,glowing) die Deckungsstärke festlegen&lt;br /&gt;
*ein Quad mit den Ausmaßen des Fensters zeichnen&lt;br /&gt;
*orthogonalen Modus verlassen&lt;br /&gt;
*Blending deaktivieren&lt;br /&gt;
&lt;br /&gt;
Um den Effekt zu verbessern, kann man noch einen Variable anlegen, die den invertierten Wert von Glowing darstellt.&lt;br /&gt;
Diesen InvGlowing Wert kann man dann mit den Farbwerten der zu zeichnenden Flächen multiplizieren.&lt;br /&gt;
So scheint es dann, dass bei hoher Lichtintensität alles dunkler ist als bei niedriger.&lt;br /&gt;
Diesen Effekt kann man durch eine invertierte Z-Buffer Textur auch erreichen.&lt;br /&gt;
&lt;br /&gt;
Wie man nun die Glowing-Variable regelt ist dem Entwickler überlassen.&lt;br /&gt;
Man könnte z.B. sagen, desto näher man mit dem Sichtfeld der Sonne zuwendet, desto höher ist die Variable.&lt;br /&gt;
Alternativ kann man auch den Regler an den Pixel unter dem Cursor abhängig machen.&lt;br /&gt;
&lt;br /&gt;
==Vor- und Nachteile==&lt;br /&gt;
'''Vorteile'''&lt;br /&gt;
*läuft auf älterer Hardware&lt;br /&gt;
'''Nachteile'''&lt;br /&gt;
*Qualitativ schlechter als mit Shadern&lt;br /&gt;
*Physikalisch nicht korrekt wie bei Shadern&lt;br /&gt;
*Shader laufen heutzutage schneller.&lt;br /&gt;
&lt;br /&gt;
==Beispiel==&lt;br /&gt;
[[Bild:Fake_HDR.png|center|framed|Zu sehen sind 3 Quads, die durch das Hintergrundlicht in ihrer Ausleuchtung beeinflusst werden.]]&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
*[https://svn.linuxprofessionals.org/filedetails.php?repname=xdream&amp;amp;path=%2Fbranches%2F0.2v%2Fcore%2FXD_Fake_HDR.pas Quellcodebeispiel aus dem X-Dream Source (im SVN)]&lt;br /&gt;
*http://edusworld.org/ew/ficheros/2006/paginasWeb/making_of_sotc.html&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial&amp;diff=26168</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial&amp;diff=26168"/>
				<updated>2014-03-13T13:11:02Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Terrain und Landschaften */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Auf dieser Seite findet ihr alle Tutorials die DelphiGL.com zu bieten hat. Falls ihr zu einem Thema kein Tutorial findet könnt ihr noch einen Blick auf die [[Techniken und Algorithmen]] werfen. Diese enthalten weitere Artikel zu bestimmten Techniken.&lt;br /&gt;
&lt;br /&gt;
=Hinweise=&lt;br /&gt;
Bitte tragt selbst '''keine''' eigenen Tutorials ohne Absprache mit [[Benutzer:Flash (Kevin Fleischer)|Flash]] bzw. [[Benutzer:Phobeus|Phobeus]] hier ein. Tutorials werden prinzipiell vom DGL-Team gegengelesen, ''bevor'' sie veröffentlicht werden.&lt;br /&gt;
&lt;br /&gt;
Wer mit dem Gedanken spielt, ein Tutorial für DGL zu schreiben, sollte sich bereits bei der Themenwahl mit dem DGL-Team absprechen. DGL ist sehr an neuen Tutorials interessiert. Nur sollte man beachten, dass nichts doppelt geschrieben wird, bzw. dass nicht 2 Mann zur selben Zeit das selbe Thema beackern.&lt;br /&gt;
&lt;br /&gt;
==Hinweis für alle Programmieranfänger==&lt;br /&gt;
Falls ihr OpenGL nutzen wollt aber noch keinerlei Programmiererfahrung habt, so solltet ihr zuerst eine Programmiersprache lernen.&lt;br /&gt;
&lt;br /&gt;
DGL kann folgende Tutorials empfehlen:&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!Link&lt;br /&gt;
!Sprache&lt;br /&gt;
!Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.delphi-treff.de/tutorials/ Delphitutorials bei www.delphi-treff.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Delphi Source der Delphi Treff entstand durch den Zusammenschluss von Delphi-Source und dem Delphi-Treff und wurde mittlerweile wieder in Delphi-Treff umbenannt. Diese Community verfügt über eine ausgezeichnete Sammlung von Tutorials zum Thema &amp;quot;Delphiprogrammierung&amp;quot;. Es werden nicht nur die Grundlagen erklärt sondern nahezu alle Bereiche der Programmierung mit Delphi. Außerdem verfügt diese Community über ein Forum welches mit seiner ''Bastelecke'' auch für Anfänger geeignet ist.&lt;br /&gt;
|-&lt;br /&gt;
|[http://crashkurs.christian-stelzmann.de/ Crashkurs von Christian Stelzmann]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Der Crashkurs von Christian erklärt neben den Grundlagen zur und über die Sprache auch die IDE anhand von zahlreichen einfachen Beispielen, die den Einstieg in Delphi stark vereinfachen und so eine einfache Einführung in die Arbeit mit Delphi bieten.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
''Wer sehen möchte was DGLer aus dem hier Gelernten und ihrer Kreativität so machen, findet Beispiele davon in der [[DGL_Projekte]]-Ecke.''&lt;br /&gt;
&lt;br /&gt;
=Tutorials=&lt;br /&gt;
{{Hinweis|Alle Tutorials sind der [[:Kategorie:Tutorial]] zugeordnet.}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Schwierigkeitsgrad&lt;br /&gt;
!Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_1}} &lt;br /&gt;
|Jeder Schritt wird ausführlich erklärt. Absolut Einsteigertauglich.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_2}} &lt;br /&gt;
|Verständnis der Grundprinzipien wird voraus gesetzt. Die Materie bleibt aber einfach.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_3}}&lt;br /&gt;
|Ihr wisst um was es geht. Es wird erwartet, dass ihr selbst das Thema weiterdenkt.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_4}}  &lt;br /&gt;
|Das Tutorial bietet euch einen Einstieg. Es wird erwartet, dass ihr euch selbst noch eingehender mit den beschriebenen Techniken befasst. Für Fragen steht unser Forum zur Verfügung.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_5}}  &lt;br /&gt;
|Um das Tutorial zu verstehen werden Kenntnisse auf dem entsprechenden Gebiet vorausgesetzt, welche über Grundwissen hinausgehen. Es wird erwartet, dass ihr euch eingehender mit dem Thema auseinandersetzt und auch andere Quellen lest/gelesen habt. Für Fragen steht unser Forum zur Verfügung.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einsteiger-Tutorials ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{{Hinweis|Die Einsteiger-Tutorials wurden auf [[SDL]] umgestellt. Dadurch wurde das Laden von Texturen erleichtert, vor allem aber ermöglicht SDL plattformunabhängig zu programmieren. Ihr benötigt deshalb die ''SDL.pas''. Diese Datei und alle anderen benötigten Dateien findet ihr im '''[[DGLSDK]]'''}}&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Quickstart]] (VCL)&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion1.gif|right]] &amp;quot;Quickstart: OpenGL &amp;amp; Delphi&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Für alle, die einen schnellen Einstieg in die OpenGL Programmierung mit Delphi suchen, hat Flash hier einen Einstieg geschaffen. Neben dem erstellen eines eigenen OpenGL-Templates hat er für alle, die Großes mit OpenGL vorhaben, am Ende noch einige Hinweise bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
''In diesem Tutorial wird eine Codevorlage für OpenGL-Projekte geschaffen. Diese basiert allerdings auf Borlands Visual Component Library (VCL) und nicht auf SDL. '''Unabhängig davon beherbergt dieses Tutorial im 2. Teil einige allgemeingültige Hinweise für OpenGL-Anfänger.''' Wer nicht mit SDL arbeitet weil z.B. Plattformunabhängigkeit nicht gewünscht oder durch die Sprache bereits gegeben ist, kann diese Codebasis leicht auf seine Sprache übertragen.''&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 1]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion1.gif|right]] &amp;quot;Nicht zu weit aus dem Fenster lehnen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Dieses Tutorial von Magellan ist für alle Neueinsteiger gedacht. Hier werden Grundlagen von &amp;quot;Was ist OpenGL&amp;quot; bis zu &amp;quot;Wie initialisiere ich OpenGL?&amp;quot; besprochen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 2]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion2.jpg|right]] &amp;quot;Entdeckung einer neuen Welt&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Unter dieser Überschrift empfängt euch Phobeus zu eurem ersten OpenGL Tutorial welches sich mit der Anwendung der OpenGL-API befasst.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 3]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion3.gif|right]] &amp;quot;Eine Welt des Grauens?&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Hinter diesem Titel verbirgt sich ein Einsteigertutorial zum Thema Matrizen in OpenGL. Wiederum führt euch Phobeus durch den Stoff.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 4]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion4.png|right]] &amp;quot;Texturen, Tapeten und Ihre Tücken&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Wie bekomme ich ein Bild auf meine Primitiven? Wer sich diese Frage bei den vorigen Tutorials gestellt hat, der bekommt hier nun von Phobeus die Antworten.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 5]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion5.jpg|right]] &amp;quot;Artenvielfalten und Ihre Folgen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial geht Phobeus auf weitere Zeichentechniken und Methoden zur Verbesserung der Performance unter OpenGL ein.&lt;br /&gt;
|-&lt;br /&gt;
!''Tutorial Lektion 6 ''&lt;br /&gt;
|[[Bild:Tutorial_na.jpg|right]] &amp;quot;Dark Engine&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Dieses Tutorial wurde geplant aber niemals umgesetzt. Heute hätte es auch keine Relevanz mehr, da die Dark Engine nicht gepflegt wurde. Falls ihr ein gutes Einsteigertutorial als Ersatz vorschlagen wollt, könnt ihr dies im Feedback-Forum von DelphiGL.com tun.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 7]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion7.png|right]] &amp;quot;Verblendet!&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Wenn man halbdurchsichtige Fensterscheiben, Lightmaps oder etwas ähnliches in sein Projekt einbauen will, dann kommt man um Blending nicht herum. Wie man das ganze Nutzen kann ist in diesem Tutorial von Phobeus erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 8]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion8.gif|right]] &amp;quot;Das Wesen von hell und dunkel - Licht&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Ohne Beleuchtung sieht selbst jede 3D-Umgebung platt aus. In diesem Tutorial wird primär der richtige Gebrauch des OpenGL-Lichtes beschrieben. Darüberhinaus wird noch die Berechnung von Normalen erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial 2D]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_2D.jpg|right]] &amp;quot;2D mit OpenGL&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
OpenGL ist zwar primär eine 3D-API, eignet sich aber, nicht zuletzt dank seiner leistungsstarken Hardwarebeschleunigung und der damit verbundenen Features, auch sehr gut für reine 2D-Anwendungen. Dieses Tutorial von Sascha Willems geht sehr ausführlich auf die Nutzung von OpenGL für 2D-Anwendungen ein.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Matrix2]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Matrix2.png|right]] &amp;quot;Matrix2 - Matrizen und Matrixmanipulationen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Das Thema Matrizen stellt OpenGL-Einsteiger regelmäßig vor &amp;quot;unlösbare&amp;quot; Aufgaben:&amp;lt;br&amp;gt;&lt;br /&gt;
''Wieso dreht sich der Würfel so komisch, und nicht um sich selbst?''&amp;lt;br&amp;gt; &lt;br /&gt;
''Wieso verschiebt OpenGL die Kugel denn dahin, und nicht dorthin?''&amp;lt;br&amp;gt;&lt;br /&gt;
Dieses Tutorial von Flash befasst sich mit den 3 Matrixtypen, die es in OpenGL gibt und erklärt was die Befehle '''glScale, glRotate und glTranslate''' wirklich machen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Grundlagen-Tutorials ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Abseits eckiger Welten]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Abseits_eckiger_Welten.gif|right]] &amp;quot;Abseits eckiger Welten&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
3D-Welten bestehen seit eh und je aus Dreiecken, was sie oft recht eckig erscheinen lässt. In diesem Tutorial lernt ihr allerdings wie man mit Hilfe von Evaluatoren in OpenGL auch Rundungen erzeugen kann.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Renderpass]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Renderpass.jpg|right]] &amp;quot;Renderpass - Die Welt daneben&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
OpenGL bietet nicht nur die Möglichkeit seine Szene direkt auf den Bildschirm zu rendern, sondern auch diese in eine Textur zu rendern um diese dann auf ein Objekt zu kleben. Dadurch ergeben sich diverse neue Möglichkeiten, wie z.B. Spiegel, Portale oder nachträgliche Manipulation der Textur. Wie ihr eure Szene in eine Textur bekommt, erfahrt ihr hier.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Selection]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Selection.gif|right]] &amp;quot;Objectselektion A&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Die Selektion von Objekten braucht man spätestens dann, wenn man ein komfortable Interaktion mit der Spielwelt erstellen will. Mit diesem Tutorial von DCW_MrT ist die Thematik kein Problem mehr.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Objektselektion]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
| [[Bild:Tutorial_Selection_tut03.jpg|right]] &amp;quot;Objektselektion B&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Wie simpel der Objektselektionsmodus von OpenGL zu benutzen ist, wird in diesem Tutorial von Sascha Willems vermittelt. Dazu gibt es den Source-Code und eine fertig kompilierte Anwendung.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial ColorPicking Shader]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
| [[Bild:Tutorial_ColorPicking_Screenie.png|right]] &amp;quot;Color Picking Implementation mit Shadern&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Die einfache Umsetzung von Color Picking ohne [[Shader]] enthält einige Nachteile die bei einer entsprechenden Umsetzung mit Shadern vermieden werden können. Dieses Tutorial zeigt eine shaderbasierte Methode ColorPicking so einzusetzen, dass es performant auch in größeren Szenen genutzt werden kann. Durch die Nutzung von Shadern und dem Fokus auf Optimierung des Selektionsvorganges sowie der Beachtung von Sonderfällen richtet sich dieses Tutorial an erfahrenere OpenGL Programmierer.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial TexFilter]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_TexFilter.jpg|right]] &amp;quot;Texturfilterung - Texturen-Feintuning&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Texturen sind seit langem ein wichtiger Bestandteil im Bereich der Echtzeitgrafik. OpenGL bietet auf diesem Gebiet auch diverse Möglichkeiten Texturen auch filtern zu lassen. Welche das sind und wie sie sich auswirken, könnt ihr in diesem Tutorial von Delphic nachlesen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kamera1]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Kamera1.gif|right]] &amp;quot;Dreht sich das Universum um uns? und andere philosophische Fragen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial von Delphic geht es um die Kamera. Wie eine Kameraklasse gebaut sein könnte und was sie macht wird hier erklärt.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Effekte ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Nebel]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Nebel.jpg|right]] &amp;quot;DGL Fogging Tutorial&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Erstaunlich einfach lässt sich mit OpenGL Nebel darstellen. Wie einfach, zeigt euch Lithander in diesem Tutorial. &lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Partikel1]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Partikel1.gif|right]] &amp;quot;Partikel-Tutorial I&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Eine Partikel-Engine sollte in (fast) jeder Engine enthalten sein. Anhand dieses Tutorials von Lithander könnt ihr den Grundstein dazu legen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial BumpMap]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_BumpMap.png|right]] &amp;quot;Bumpmapping - Plastisches 2D&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Bumpmapping ist eine immer stärker genutzte Technik, um polygonarme Oberflächen ohne Tesselation mit vorgegaukelten Details - abhängig vom Lichteinfall - zu versehen. In diesem Tutorial zeigt euch HomerS, wie man Bumpmapping über die NVIDIA-spezifischen Combiner realisiert.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial MultiTexturing]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Multitex05.jpg|right]] &amp;quot;Multitexturing&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Wie man mehrere Texturen auf ein Polygon bringen kann, erklärt auch Sascha Willems in diesem Tutorial zum Thema Multitexturing. Multitexturing ist seit OpenGL1.3 Teil des GL-Kerns und kann für z.B. für Lightmapping bzw. Detailmapping verwendet werden.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial StencilSpiegel]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_StencilSpiegel.jpg|right]] &amp;quot;Spiegelungen mit dem Stencil-Buffer&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Eine Echtzeit-Spiegelung ist einer der schönsten Effekte einer 3D-Welt und trägt viel zum Realismus bei. Eine Möglichkeit Spiegelungen über den Stencilpuffer zu realisieren, wird in diesem Tutorial von Sascha Willems erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial StereoSehen]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_StereoSehen.gif|right]]Auch wenn moderne Grafikkarten durch eine immer besser werdende Darstellung dem Benutzer versuchen das Betreten einer virtuellen 3D-Welt vorzugaukeln, so schafft es doch auch das beste Doom3-Monster nur bis zur Glasröhre zu erschrecken, rutscht dann aber quietschend davon ab. Was also tun, wenn man einen Schritt weiter gehen und dem Anwender wirkliches 3D bieten möchte? Wer eine 3D-Brille hat, wird mit diesem Tutorial von Delphic eine Möglichkeit finden, die dritte Dimension am Computer zur erschließen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Alphamasking]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Alphamasking_tut04.jpg|right]]In diesem kleinen aber feinen Tutorial erklärt Sascha Willems, wie man Alphamasking dazu verwenden kann, eine Szene optisch aufzuwerten und gleichzeitig Performance zu sparen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Wassereffekt]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Wassertutorial-scrshot-preview.jpg|right]]In diesem Tutorial erklärt Lord Horazont wie man eine Wasserebene mit Brechungen mit und ohne Shader erzeugen kann.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Cubemap]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Cubemap_mini.jpg|right]] &amp;quot;GL_ARB_Texture_Cubemap&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial erklärt Sascha Willems die Grundfunktionen der '''GL_ARB_Texture_Cubemap'''-Extension und zeigt auch weiterführende Techniken auf.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Vertexbufferobject]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial Vertexbufferobject preview.jpg|right]] &amp;quot;GL_ARB_Vertex_Buffer_Object&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Diese Extension führte '''VBO'''s ein. Wie man mit damit Vertexdaten schnell im Grafikkarten- und Hauptspeicher ablegt und darauf zugreift, erklärt Sascha Willems in diesem Tutorial.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Vertexprogramme]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_VP_preview.jpg|right]] &amp;quot;GL_ARB_Vertex_Program&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem umfangreichen Tutorial werden alle wichtigen Bereiche der Programmierung mit der GL_ARB_Vertex_Program-Extension abgedeckt. Man kann es als umfassende deutsche Referenz zu diesem Thema sehen, da auch alle wichtigen Funktionen aufgelistet werden und es auch sonst an nichts fehlt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial NVOcclusionQuery]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_NVO_preview.jpg|right]] &amp;quot;NV_Occlusion_Query&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Lard Middendorf geht in diesem Tutorial auf die Verwendung der NV_Occlusion_Query-Extension ein.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Pixelbuffer]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Pixelbuffer_preview.jpg|right]] &amp;quot;WGL_ARB_Pixel_Buffer&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Sascha Willems erklärt hier leicht verständlich den Umgang mit der Pixelbuffer-Extension. Als Additum wird auch noch auf die Nutzung dieser Extension für Shadowmapping eingegangen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial_Framebufferobject]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Framebufferobject_Preview.jpg|right]] &amp;quot;GL_EXT_FRAMEBUFFER_OBJECT&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Deathball erklärt in diesem Tutorial wie man Framebufferobjekte erstellt und diese zum Offscreenrendern benutzt.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Shader ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial glsl|Tutorial glSlang]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_glsl1.png|right]] &amp;quot;Einführung in GLSL&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Nach langem Ringen und Handeln hat es das ARB letztendlich doch geschafft, eine einheitliche Shaderhochsprache für OpenGL zu veröffentlichen, nämlich ''glSlang''. Mit glSlang können nun auch unter OpenGL Vertex- und Fragment-Shader in einer lesbaren, C-ähnlichen Hochsprache geschrieben werden, was deren Entwicklung stark vereinfacht. Diese Einführung von Sascha Willems ist weniger ein Tutorial, als ein kompletter Überblick über glSlang. Hier erfährt der Leser nicht nur etwas über die Benutzung von Shadern im Programm, sondern auch alles über die Sprachelemente, inklusive diverser Beispiele.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial glsl2|Tutorial glSlang 2]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_na.jpg|right]] &amp;quot;GLSL-Ergänzungen und Beispiele&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Dieses Tutorial von La_Boda ist eine direkte Fortsetzung des GLSL-Tutorials. Es behandelt verstärkt die Praxis und liefert anhand von einigen Beispielen eine bessere Sicht auf die bereits gelernte Theorie.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== KI ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial pathfinding|Tutorial Pathfinding]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_pathfinding.png|right]] &amp;quot;Pathfinding 1&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial zeigt euch Flo wie man recht simpel eine Wegfindungsroutine implementiert. Besonders wenn man sowas ohne großen Lernaufwand in sein Spiel einbinden möchte, sollte man einen Blick riskieren.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial pathfinding2|Tutorial Pathfinding 2]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_pathfinding2.png|right]] &amp;quot;Pathfinding 2&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Gerade bei aktuelleren Programmen reicht es meist nicht aus, wenn man seine Einheiten nur in 8 Himmelsrichtungen bewegen kann. Frase stellt in diesem Tutorial vor, wie man eine Wegfindungsroutine implementieren kann, wie diese in einem heutigen RTS vorkommen kann.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Terrain und Landschaften ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Terrain1]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Terrain1.gif|right]] &amp;quot;Außenlandschaften mit System - Heightmaps&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Anhand der Graustufenwerte einer Bitmap-Datei kann man relativ einfach eine imposante Landschaft erstellen. Wie das ganze funktioniert erklärt euch Delphic in diesem Tutorial. Außerdem wird noch die Implementation von Skyboxen erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Terrain2|Tutorial Terrain 2]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Terrain2.gif|right]] &amp;quot;Heightmap-Texturen&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Da das Terrain aus dem vorigen Tutorial noch recht eintönig grau aussieht und das natürlich geändert werden soll, erklärt euch Delphic, wie man schmucke Schatten und Texturen für die Heightmap generieren kann.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Terrain3|Tutorial Terrain 3]]&lt;br /&gt;
{{Level_5}} &lt;br /&gt;
|[[Bild:Tutorial_Terrain3.gif|right]] &amp;quot;Terrain im Detail&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Da größere Landschaften aufgrund der hohen Polygonanzahl sehr aufwändig zu rendern sind erklärt euch Delphic hier, wie man entfernte Dreiecke &amp;quot;zusammenlegen&amp;quot; kann, um Rechenleistung zu sparen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Skyboxen]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Skybox_Vorschau.jpg|right]] &amp;quot;Skyboxen&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial erklärt Sascha Willems kurz und bündig den Umgang mit Skyboxen, mit denen man Landschaften schnell sehr stark optisch aufwerten kann. Es wird sowohl auf die Erstellung der Skybox-Texturen mit dem Programm Terragen als auch die Implementation der Skybox in OpenGL eingegangen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spieletutorials und Softwareentwicklung==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Bomberman1|Tutorial Bomberman 1]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Bomberman1.jpg|right]] &amp;quot;Bomberman1 - Codebasis und Editor&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im ersten Teil dieser kleinen Tutorialserie zum Thema Spieleprogrammierung kümmern wir uns neben der Erstellung unseres Basiscodes auch um einen fertigen Editor. Nach der Durcharbeitung dieses Tutorials von Sascha Willems sollte der Leser alle Grundprinzipien zur Programmierung eines Spiels verstanden haben.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Bomberman2|Tutorial Bomberman 2]]&lt;br /&gt;
{{Level_3}}&lt;br /&gt;
|[[Bild:Tutorial_Bomberman2.jpg|right]] &amp;quot;Bomberman2 - Der 3D-Bombermanklon (Grundversion)&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im zweiten Teil gehts ans Eingemachte, nämlich einen fertigen Bombermanklon. In Sascha Willems Tutorial werdet ihr zusätzlich zu den bereits erworbenen Prinzipien diverse Techniken die in so ziemlich jedem Spiel Verwendung finden erlernen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Softwareentwicklung1|Tutorial Softwareentwicklung 1]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_SWE1.jpg|right]] &amp;quot;Softwareentwicklung1 - Objektorientierte Softwareentwicklung mit UML&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im ersten Teil dieser Tutorialserie zum Thema Softwareentwicklung erklärt euch Flash, wie man an ein Projekt herangeht und herausfindet was eigentlich zu tun ist. Es geht dabei um Analyse der Anforderungen und die Modellierung sogenannter Use Cases. Die hier vorgestellten Arbeiten sind Grundlage um später Klassen zu finden auf denen dann der Code aufgebaut wird.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Softwareentwicklung2|Tutorial Softwareentwicklung 2]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_SWE2.jpg|right]] &amp;quot;Softwareentwicklung2 - Objektorientierte Softwareentwicklung mit UML&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im zweiten und umfangreichsten Teil der Serie steht das Thema &amp;quot;Klassen&amp;quot; im Zentrum. Flash erklärt euch wie man aus den Use Cases Klassen ableitet und welche unterschiedlichen Einsatzgebiete Klassen innerhalb der Software haben können.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Softwareentwicklung3|Tutorial Softwareentwicklung 3]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_SWE3_Interface.jpg|right|128px]] &amp;quot;Softwareentwicklung3 - Objektorientierte Softwareentwicklung mit UML&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im letzten Teil der Serie steht das Thema &amp;quot;Verhalten&amp;quot; im Zentrum. Flash erklärt euch wie die Klassen miteinander in Beziehung gesetzt werden. Außerdem wird nocheinmal auf den RUP als '''iterative''' Vorgehensweise eingegangen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Mathematisches ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lineare Algebra]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_lineare_Algebra_Preview.jpg|right]] &amp;quot;Vektorrechnung&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In vielen Tutorials tauchen eine Menge Begriffe aus der linearen Algebra und analytischen Geometrie auf. Wer bei Begriffen wie Vektoren, Skalar-Produkt, Vektorkreuzprodukt, etc. ein wenig Auffrischung und Implementationshinweise braucht, ist mit diesem Tutorial von EternalLearner an der richtigen Stelle.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Nachsitzen]]{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Nachsitzen_preview.png|right]] &amp;quot;3d-Mathematik&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Wer die mathematischen Grundlagen wie Sinus, Cosinus und Matrizen aus der Schule schon wieder vergessen oder noch vor sich liegen hat, der kann mit Hilfe dieses Tutorials von Delphic dieses Wissen erlernen bzw. auffrischen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Objekt_gedreht_und_dennoch_nach_vorne_bewegt_preview.gif|right]] &amp;quot;Objekt gedreht und dennoch nach vorne bewegt&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
SchodMC erklärt in diesem Tutorial wie man ein Objekt drehen und dabei trotzdem vorwärts bewegen kann. Quer fahrende Autos sind zwar praktisch zum Einparken Aber doch eher selten ;-)&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Objekt immer um eigene Achse drehen]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Objekt_immer_um_die_eigene_Achse_drehen_preview.gif|right]] &amp;quot;Objekt immer um eigene Achse drehen&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Wenn ihr euer Objekt nun noch um die eigene Achse drehen wollt, seid ihr mit diesem Tutorial von SchodMC an der richtigen Adresse&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Separating Axis Theorem]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:SAT_Kollision.jpg|right|128px]] &amp;quot;Separating Axis Theorem&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Seth erklärt in diesem Tutorial wie man Polygonkollisionen mit Hilfe des ''Seperating Axis Theorem'' erkennen kann. &lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kollision1]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Kollision1_Coll2.png|128px|right]] &amp;quot;Kollision 1&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Reinhard Niehoff fragte uns ob er ein Tutorial über Kollision schreiben könnte. Das konnten wir nicht ablehnen, und so entstand dieses Tutorial in dem grundlegende Kollisionsberechnungen erklärt werden. Weitere sollen folgen. &lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kollision2]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Kollision2_Thumb.png|128px|right]] &amp;quot;Kollision 2&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Beim zweiten Tutorial gehts mehr in die Tiefe und einige Spezialfälle bei Kugel-Polygon-Kollisionen werden erläutert. Mit dabei: Die [[Werkzeugkiste]] mit nützlichen Funktionen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kollision3]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Kollision3_Thumb.png|128px|right]] &amp;quot;Kollision 3&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Beim letzten Tutorial dieser Serie gehts darum, wie man die bisherigen Ansätze in einem Programm unterbringt.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Grafik und Modellierung ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Modellierung eines Low-Poly Menschen Teil 1]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Low-Poly-Mensch1_preview.jpg|right]] &amp;quot;Modellierung eines Low-Poly-Menschen&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Die Modellierung von organischen &amp;quot;Objekten&amp;quot; gehört mit zu den kompliziertesten Aufgaben, die es beim Modelling gibt. Wie man einen Menschen mit aus möglichst wenigen Polygonen mit dem Programm 3D Studio Max erstellen kann wird in diesem Tutorial von Sascha Willems erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Modellierung eines Low-Poly Menschen Teil 2]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Low-Poly-Mensch2_preview.jpg|right]] &amp;quot;Kleider machen Leute (UVW-Mapping)&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Nun spendiert Sascha Willems seinem Menschen aus dem 1. Tutorial eine schmucke Uniform, so dass er sich endlich in der Öffentlichkeit blicken lassen kann.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Skripte ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Scripting mit JvInterpreterProgram]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_JvInterpreter_preview.png|right]] &amp;quot;Skripting mithilfe der Jedi-Code-Library&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
SchodMC erklärt hier wie man mit relativ wenig Aufwand Skripte in eigene Programme integrieren kann.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Scriptsprachen Teil 1]]&lt;br /&gt;
{{Level_5}} &lt;br /&gt;
|[[Bild:Tutorial_Skriptsprachen1_preview.gif|right]] &amp;quot;Scriptsprachen Teil 1 - Einführung&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Für alle die schon immer einmal wissen wollten wie ein Compiler arbeitet ist diese Tutorial-Reihe von Delphic genau das richtige.&lt;br /&gt;
&lt;br /&gt;
Der erste Teil widmet sich der Lexikalischen Analyse und dem Parsen des Quellcodes&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Scriptsprachen Teil 2]]&lt;br /&gt;
{{Level_5}} &lt;br /&gt;
|[[Bild:Tutorial_Skriptsprachen2_preview.gif|right]] &amp;quot;Scriptsprachen Teil 2 - Virtuelle Computer und Code Erzeugung&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Für alle die schon immer einmal wissen wollten wie ein Compiler arbeitet ist diese Tutorial-Reihe von Delphic genau das richtige.&lt;br /&gt;
&lt;br /&gt;
Der zweite Teil beschreibt den Bau einer VM und der Codeerzeugung&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Delphi allgemein ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Debugging]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
| [[Bild:Tutorial Debugging.gif|right]] &amp;quot;Debugger benutzen und andere praktische Tipps&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Tutorial werdet von Delphic mit der Nutzung des Delphi-Debuggers eingeführt. Auch werden Wege zur Vermeidung von Fehlern aufgezeigt. Genauso findet Ihr aber auch in diesem Tutorial Hinweise, zu häufig begangenen Fehlern und deren Ursachen.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Komponentenentwicklung]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
| [[Bild:Tutorial Komponentenentwicklung.png|right]] &amp;quot;Komponentenentwicklung&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Tutorial werdet ihr ein wenig tiefer in die Entwicklung von Komponenten unter Delphi eingeführt. Es wird Grundwissen auf diesem Gebiet vorausgesetzt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Multithreading]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Multithreading.gif|right]] &amp;quot;Das Prinzip der Dualität&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Threads sind ein erweitertes Prinzip des bekannten Multitasking und werden innerhalb eines Programmes oft dazu genutzt, verschiedene Aufträge gleichzeitig abzuarbeiten. LossyEx erklärt euch hier deren Nutzung.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Software-Synthesizer]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Bild:Noexist.jpg|right]] &amp;quot;Software-Synthesizer&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Computerspiele bestehen nicht nur aus Grafik. Dieses Tutorial widmet sich einem ganz anderen Bereich der Spieleprogrammierung: Der Erzeugung von synthetischen Sounds und Musik.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== SDL ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial SDL Einstieg]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion1.gif|right]] &amp;quot;SDL-Einsteiger-Tutorial&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Crossplattform-Programmierung ist das Zauberwort, welches in den letzten Jahren - dank verstärkter Präsenz von Linux - immer wieder in den Programmierforen des Internets auftaucht. Für Grafikprogrammier ist [[SDL]] hier das Mittel der Wahl. Bekannte Titel wie &amp;quot;Quake III&amp;quot; und &amp;quot;Civilisation - Call to Power&amp;quot; bauen bereits auf diese Bibiothek für ihre Linux-Ports. Phobeus zeigt euch in diesem ersten SDL-Tutorial was SDL ist und wie man es benutzt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial SDL_RWops]]&lt;br /&gt;
{{Level_2}}&lt;br /&gt;
| [[Bild:Noexist.jpg|right]] &amp;quot;SDL_RWops-Tutorial&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
SDL benutzt für den Dateizugriff SDL_RWops. [[Benutzer:Lord Horazont|Lord Horazont]] zeigt euch in diesen Tutorial wie man diese benutzt und auch komfortabler gestaltet.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Rendertechniken ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Frustum Culling]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
| [[Bild:Tutorial Frustum Culling.jpg|right]] &amp;quot;Frustum Culling&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Frustum Culling ist eine einfache Möglichkeit die Rendergeschwindigkeit zu erhöhen, da man damit schon vor dem Senden der Daten an die Grafikkarten feststellen kann, welche Objekte sich im Blickfeld des Spielers befinden und welche nicht.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Octree]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
| [[Bild:Tutorial Octree preview.jpg|right]] &amp;quot;Octrees&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Octrees sind eine einfach zu implementierende, aber sehr effiziente Möglichkeit um besonders Outdoor-Szenen abhängig vom Betrachterblickfeld stark zu beschleunigen. In diesem Tutorial zeigt Shadow euch eine komplette Implementation eines Octrees inklusive ausgiebigem Quellcode.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Charakteranimation]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Bild:Tutorial_na.jpg|right]] &amp;quot;Charakteranimation&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Wer menschliche Charaktere oder Tiere lebendig aussehend animieren will, kommt mit herkömmlichen Mitteln wie Translation und Rotation der Modelview-Matrix nicht weiter. In diesem Tutorial erklärt euch glAwesome, wie ihr eure Meshes zum Leben erweckt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Raytracing ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Raytracing - Grundlagen I]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Bild:Tutorial_RaytracingI_thumb.jpg|right]] &amp;quot;Raytracing - Grundlagen I&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Die Grundzüge des Raytracings Teil 1 - Von den Strahlen bis zur ersten Darstellung von Kugeln und Ebenen&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Raytracing - Grundlagen II]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Bild:Tutorial_RaytracingI_thumb.jpg|right]] &amp;quot;Raytracing - Grundlagen II&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Die Grundzüge des Raytracings Teil 2 - Einfache Basisobjekte, Transformationen und Phong-Lightning&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial GLScene]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
| [[Bild:Tutorial GLScene preview.jpg|right]] &amp;quot;Einführung in GLScene&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
GLScene ist eine zu erstaunlicher Größe angewachsene Komponentensammlung, die quasi einen OpenGL-Wrapper darstellt und euch dank Delphis VCL dadurch recht einfach OpenGL-Programme erstellen lässt. LaBoda gibt euch zu dieser Komponentensammlung in diesem Tutorial deshalb eine kleine Einführung.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial WebGL]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Datei:webgl-sporeviewer.jpg|128px|right]] &amp;quot;WebGL&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
WebGL ist der neue Standard für OpenGL im Browser. Der Standard ermöglicht es hardwarebeschleunigte 3D-Grafik mit Shadern im Browser darzustellen, ohne dabei auf spezielle Plugins angewiesen zu sein. [[Benutzer:Coolcat|Coolcat]] stellt euch in diesem Tutorial die Besonderheiten dieses JavaScript-Bindings für OpenGL ES 2.0 gegenüber anderen OpenGL-Anwendungen vor.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Charakteranimation&amp;diff=26071</id>
		<title>Tutorial Charakteranimation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Charakteranimation&amp;diff=26071"/>
				<updated>2014-02-19T13:03:53Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Skinning für Fortgeschrittene */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Einleitung==&lt;br /&gt;
In diesem Tutorial möchte ich euch beibringen, wie man starre [[Mesh]]es lebendig erscheinen lässt, indem man sie bewegt. Und zwar wollen wir sie nicht nur verschieben und drehen, sondern richtig animieren, also verformen. Ein sicherer Umgang mit [[Matrizen]], [[VBO]]s und [[Shader]]n wird hier vorausgesetzt.&lt;br /&gt;
&lt;br /&gt;
==Das Skelett==&lt;br /&gt;
Es gibt verschiedene Ansätze, ein Mesh durch Animation zu verformen. Meistens möchte man in Computerspielen Menschen oder Tiere (oder etwas, das ihnen ähnelt) animieren, die sich nur sehr eingeschränkt verformen können - nämlich so, wie es ihr Skelett zulässt. Daher kommt meistens Skelett-basierte Animation zum Einsatz. Sich bewegene Maschinen oder Roboter sind meistens noch beschränkter in ihrer Bewegegungsfreiheit, sodass sich deren Animationen ebenfalls mittels eines Skeletts realisieren lässt.&lt;br /&gt;
Die Idee ist einfach: Man speichert für einen Charakter nur, wie sich das Skelett bei einer Animation bewegt. Das Skelett besteht aus deutlich weniger Teilen, als das Mesh (die Haut) [[Vertices]] hat. Die Auswirkungen auf die Vertices selbst werden erst während des Renderns in Echtzeit berechnet. Durch dieses Verfahren wird eine Menge Speicherplatz, aber auch Aufwand beim Erstellen und Bearbeiten von Animationen gespart.&lt;br /&gt;
&lt;br /&gt;
Woraus besteht also ein Skelett? Aus Gelenken ('''Joints''') und Knochen ('''Bones'''). In der Grafikprogrammierung hat es sich bewährt, Skelette hierarchisch aufzubauen. Das heißt, es gibt genau ein Supergelenk, das keinem anderen Gelenk untergeordnet ist. Dieses Gelenk wird auch Wurzel genannt, denn in der Informatik würde man sagen, das Skelett ist ein [https://de.wikipedia.org/wiki/Baum_%28Graphentheorie%29 Baum]. Das Wurzelgelenk besitzt untergeordnete Gelenke (Kinder), die mit jeweils einem Knochen mit ihm verbunden sind. Dreht man nun das Wurzelgelenk, so drehen sich alle untergeordneten Knochen und Gelenke (und deren Kinder) mit. Dies entspricht der Realität: Wenn du deinen Arm hebst, d.h. dein Schultergelenk drehst, bewegen sich das Ellenbogen- und Handgelenk, sowie alle Knochen der Hand entsprechend mit.&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Das für die Animation benötigte Skelett muss bei weitem nicht so detailliert sein, wie das reale menschliche Skelett. Mit 64 Joints (inklusive Finger) kann man bereits gute Ergebnisse erzielen. Das hier abgebildete Skelett hat 65 Joints, wobei man sich die Spitzen der Finger und Füße noch sparen könnte. (Sie dienen hier nur dazu, die äußersten Knochen zu visualisieren.)}}&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Skelett_T-Pose.png]]&lt;br /&gt;
&lt;br /&gt;
Mathematisch gesehen können wir ein Gelenk durch eine Rotation, eine Position, um die rotiert wird, und die Menge aller Untergelenke beschreiben. Dadurch werden gleichzeitig auch alle Knochen beschrieben, da diese nichts weiter als die Verbindung zwischen einem Eltern- und Kind-Joint sind. Die Rotation lässt sich auf viele Arten beschreiben, z.B. durch eine 3x3-[[Matrix]] oder ein [[Quaternion]] (wobei letzteres aufgrund der guten Interpolierbarkeit zu empfehlen ist). Die Position beschreibt man am einfachsten durch einen Translationsvektor relativ zum Elternknoten. Die Rotation wird in der Regel auch erstmal relativ zum Elternknoten angegeben.&lt;br /&gt;
&lt;br /&gt;
Die absolute Rotation eines Gelenks erhält man ganz einfach, indem man die absolute Rotation des Elternknotens mit der eigenen relativen multipliziert. Die absolute Rotation des Elternknotens muss man natürlich vorher erst einmal berechnen (es sei denn, der Elternknoten ist die Wurzel). Der aufmerksame Leser merkt schon - es riecht nach Rekursion.&amp;lt;br&amp;gt;&lt;br /&gt;
Die absolute Position lässt sich ebenfalls rekursiv berechnen. Man multipliziert die absolute Rotationsmatrix des Elternknotens mit der relativen Position und addiert anschließend die absolute Position des Elternknotens. Beide Berechnungen lassen sich in eine Methode stecken:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;void ComputeAbsJoint(CJoint&amp;amp; Joint, quat parentRot)&lt;br /&gt;
{&lt;br /&gt;
  Joint.AbsRot = parentRot * Joint.RelRot&lt;br /&gt;
  for(int i=0; i&amp;lt;Joint.numberOfChildren; ++i)&lt;br /&gt;
  {&lt;br /&gt;
    Joint.Child[i].AbsPos = Joint.AbsRot * Joint.Child[i].RelPos  + Joint.AbsPos;&lt;br /&gt;
    ComputeAbsJoint(Joint.Child[i], Joint.AbsRot);&lt;br /&gt;
  }&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
''Joint'' ist also eine Instanz vom Typ ''CJoint'' wird der Funktion [https://de.wikipedia.org/wiki/Call_by_reference per-reference] übergeben. ''Joint.Child'' ist ein Array von Joints.&lt;br /&gt;
''quat'' ist der Typ für ein Quaternion. Hier könnte man wie gesagt auch eine Matrix (''mat3'') oder alles andere nehmen, was in der Lage ist, eine Rotation zu speichern und multipliziert (verkettet) zu werden.&lt;br /&gt;
&lt;br /&gt;
Ich hoffe, der Code ist für Programmierer jeder Sprache verständlich :-).&lt;br /&gt;
&lt;br /&gt;
==Die Animation==&lt;br /&gt;
Die Animation besteht nun aus einer Folge von '''KeyFrames'''. Ein KeyFrame beschreibt den Zustand des Skeletts zu einer bestimmten Zeit. Für jeden KeyFrame werden also gespeichert:&lt;br /&gt;
*Die Zeit&lt;br /&gt;
*Die Rotation jedes Joints (relativ zum Eltern-Joint)&lt;br /&gt;
*Die Position jedes Joints (ebenfalls relativ zum Eltern-Joint)&lt;br /&gt;
Die KeyFrames werden nach der Zeit sortiert in einem Array gespeichert. Zwischen den KeyFrames kann man interpolieren und somit auch Zustände des Skeletts zwischen zwei KeyFrames berechnen. Das macht man sich bei der Animation zu nutze.&lt;br /&gt;
&lt;br /&gt;
Man benötigt also eine Zeitvariable ''time'' (vom Typ float), die man beim Starten der Animation auf 0 setzt. In jedem Frame (hier ist nicht '''Key'''Frame gemeint, sondern Frame wie in [[Framerate]]) erhöht man ''time'' um die im letzten Frame vergangene Zeit. Nun sucht man den KeyFrame mit der größten Zeit, die noch kleiner ist als ''time''. Bei der Suche sollte man ausnutzen, dass man die KeyFrames nach der Zeit sortiert hat. Es wäre unnötig langsam, jeden einzelnen KeyFrame der Liste abzuklappern. Besser wäre&lt;br /&gt;
*sich das Suchergebnis vom letzten Frame zu merken und die Suche ab dort zu starten oder&lt;br /&gt;
*eine [https://de.wikipedia.org/wiki/Bin%C3%A4re_Suche binäre Suche] oder &lt;br /&gt;
*eine [https://de.wikipedia.org/wiki/Interpolationssuche proportionale Suche].&lt;br /&gt;
Die Suche liefert uns den Index k des gesuchten KeyFrames, so dass gilt:&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;KeyFrames[k].time &amp;lt; time &amp;lt;= KeyFrames[k+1].time&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das endgültige Skelett können wir nun durch die [[Interpolation]] der KeyFrames k und k+1 (Vorsicht vor Überlauf!) berechnen. Der zur Interpolation nötige Faktor ''f'' lässt sich mit&amp;lt;source lang=cpp&amp;gt;f = (time - KeyFrames[k].time) / (KeyFrames[k+1].time - KeyFrames[k].time)&amp;lt;/source&amp;gt;berechnen. ''f'' entspricht z.B. dem letzten Parameter der GLSL-Funktion [[Tutorial_glsl#Standardfunktionen|mix]]. Um schöne Ergebnisse zu erzielen, sollte man jedoch etwas weicheres als lineare Interpolation verwenden, z.B. die [https://de.wikipedia.org/wiki/Hermiteinterpolation Hermiteinterpolation].&lt;br /&gt;
&lt;br /&gt;
==Skinning==&lt;br /&gt;
Schön und gut, wir wissen jetzt, was ein Skelett ist und wie man es animiert. Doch was ändert das am Mesh? Schließlich wollen wir in der Endanwendung ja nichts mehr vom Skelett sehen. Offensichtlich benötigen wir eine Möglichkeit, die Vertices des Meshs mit dem Skelett zu verbinden. Das ist nicht schwierig: Wir ordnen jedem Vertex die Nummer (einen Integer) des Gelenks zu, das ihn beeinflusst. Das ist nicht der Weisheit letzter Schluss, aber sehr einfach und genau das Richtige, wenn man überhaupt erstmal ein Ergebnis sehen will.&lt;br /&gt;
&lt;br /&gt;
===Transformation der Positionen===&lt;br /&gt;
Wir wissen nun von einem Vertex, welche Position er in der Standardpose (bei Menschen i.d.R. T-Pose) hat und von welchem Gelenk er beeinflusst wird. Um zu verstehen, was mit den Vertices bei der Animation passiert, betrachten wir beispielhaft den hier in grün markierten Vertex:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:arm2_tpose2.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
Er ist dem Ellenbogen-Gelenk (roter Kreis links neben ihm) des linken (aus unserer Sicht rechten) Arms zugeordnet.&lt;br /&gt;
&lt;br /&gt;
Als erstes berechnen wir den Verbindungsvektor vom Joint in T-Pose zum Vertex:&lt;br /&gt;
 Diff = VPos - TPoseJoint.AbsPos&lt;br /&gt;
Diesen Verbindungsvektor rotieren wir nun entsprechend der aktuellen Ausrichtung des Joints. Das heißt, wir wenden die absolute Rotationsmatrix bzw. das Quaternion des Joints an:&lt;br /&gt;
 Rotated = Joint.AbsRot * Diff&lt;br /&gt;
Den erhaltenen Rotationsvektor addieren wir schließlich auf die absolute Position des Joints im animierten Skelett;&lt;br /&gt;
 Result = Joint.AbsPos + Rotated&lt;br /&gt;
Die fertige Position entspricht dem, was wir hier sehen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:arm2_moved2.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
Diese drei Schritte solltest du unbedingt nachvollzogen und verstanden haben, bevor du dich an die Implementierung machst. Man beachte v.a. den Unterschied zwischen TPoseJoint (enthält Position und Rotation in Standardpose, also unbewegt wie im ersten Bild) und Joint (das Ergebnis der KeyFrame-Interpolation, zweites Bild).&lt;br /&gt;
&lt;br /&gt;
===Transformation von Normalen===&lt;br /&gt;
Ein [[Vertex]] besteht nicht nur aus einer Position. [[Normale]]n und [[TBN Matrix|andere Vektoren]], die lediglich eine Richtung und keine Position enthalten, brauchen natürlich nicht wie Positionsvektoren transliert werden. Auf sie wird nur die Rotation (Schritt 2) angewandt.&lt;br /&gt;
&lt;br /&gt;
===Transformation von Texturkoordinaten===&lt;br /&gt;
&amp;quot;Hö? Wieso müssen Texturkoordinaten transformiert werden?&amp;quot; Wenn du dich das beim Lesen der Überschrift dieses Abschnitts gefragt hast, liegst du genau richtig. Texturkoordinaten sind nicht von der Animation betroffen. Dieser Abschnitt ist nur ein Test, ob du bis hierher alles verstanden hast. ;-)&amp;lt;br&amp;gt;&lt;br /&gt;
Hier wäre eine gute Stelle, das bisher gelernte zu vertiefen, indem du dich an einer eigener Implementation versuchst.&lt;br /&gt;
&lt;br /&gt;
==Skinning für Fortgeschrittene==&lt;br /&gt;
Im letzten Abschnitt habe ich geschrieben, dass wir jedem Vertex ein Gelenk zuordnen. Wenn es gut aussehen soll, reicht eins allein jedoch nicht aus. Denn was soll man beispielsweise mit einem Vertex machen, der auf der Haut nahe des Handgelenks eines Menschen liegt? Gehört er zum Hand- oder doch zum Unterarmknochen? Die Antwort lautet: beides. Seine Position wird sowohl von der Drehung des Ellenbogens, als auch von der Drehung des Handgelenks beeinflusst. Das heißt, wir müssen jedem Vertex mindestens zwei Gelenke zuordnen. In der Praxis nimmt man oft sogar vier. So werden wir auch im folgenden Verfahren.&lt;br /&gt;
&lt;br /&gt;
Doch nun, da wir festgestellt haben, dass oft kein Knochen alleinigen Einfluss auf einen Vertex hat, müssen wir für jeden der 4 Joints auch noch den Anteil an Einfluss speichern. Dafür hat sich der Begriff '''BoneWeight''' eingebürgert. Ich benutze lieber die Bezeichnung '''JointWeight''', da wir die Transformationen, die wir hiermit gewichten, nicht pro Bone, sondern pro Joint speichern. Das JointWeight hat einen Wert zwischen 0 und 1 und i.d.R. ist es so, dass die Summe aller JointWeights eines Vertex 1 ergibt. Somit kann man ein wenig Speicherplatz sparen, da man das letzte JointWeight jederzeit berechnen kann:&lt;br /&gt;
 Leztes JointWeight = 1 - (Summe aller anderen JointWeights)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Die Gewichtung der einzelnen Joints tatsächlich umzusetzen, ist nicht trivial. Um genau zu sein: Es ist wahrscheinlich das schwierigste Problem des ganzen Themas. Es ohne störende Artefakte zu lösen, gelang in der Praxis erst vor einigen Jahren mithilfe höherer Mathematik. Doch nun erstmal die verschiedenen Ansätze der Reihe nach:&lt;br /&gt;
&lt;br /&gt;
===Matrix-Interpolation===&lt;br /&gt;
Im letzten Abschnitt haben wir gesehen, dass die Transformation eines Vertex (bzw. seiner Position) aus drei Schritten besteht. Erst eine Translation, dann eine Rotation und zum Schluss noch eine Translation. Wer sich ein bisschen mit Matrizen auskennt (und das hatte ich am Anfang des Tutorials vorausgesetzt ;-) ), der weiß, dass man alle drei Transformationen in nur eine Matrix stecken kann. Da scheint es doch naheliegend zu sein, für jeden Joint eine solche Matrix zu bauen:&lt;br /&gt;
 TransMatrix1.setTranslation(-TPoseJoint.AbsPos);&lt;br /&gt;
 RotMatrix.setRotation(Joint.AbsRot);&lt;br /&gt;
 TransMatrix2.setTranslation(Joint.AbsPos);&lt;br /&gt;
 Matrix = TransMatrix2 * RotMatrix * TransMatrix1;&lt;br /&gt;
&lt;br /&gt;
Da jeder Vertex von 4 Joints beeinflusst wird, warum gewichtet man dann nicht einfach die Matrizen?&lt;br /&gt;
 finalMatrix = Matrix[JointID[0]] * JointWeight[0]&lt;br /&gt;
             + Matrix[JointID[1]] * JointWeight[1]&lt;br /&gt;
             + Matrix[JointID[2]] * JointWeight[2]&lt;br /&gt;
             + Matrix[JointID[3]] * JointWeight[3];&lt;br /&gt;
 finalPos = finalMatrix * VPos;&lt;br /&gt;
Leider bringt die Matrix-Interpolation nicht das gewünschte Ergebnis. Dies lässt sich sehr einfach an einem Beispiel nachvollziehen:&amp;lt;br&amp;gt;&lt;br /&gt;
Wir nehmen an, ein Vertex wird von zwei Joints zu je 50% beeinflusst (d.h. JointWeight[0] = JointWeight[1] = 0.5 und JointWeight[2] = JointWeight[3] = 0.0). Der eine Joint hat die Identitätsmatrix und der andere eine um 90° um die x-Achse rotierte Identitätsmatrix. Als Mittelung dieser beiden Drehungen würde man eine Rotation um 45° um die x-Achse erwarten. Doch was kommt tatsächlich raus?&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:matrix_blending_beispiel.png|526px]]&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Das ist offensichtlicht nicht das gleiche wie eine 45°-Rotationsmatrix um die x-Achse:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:45grad_um_X_Matrix.png|210px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Der interpolierten Matrix ist außerdem noch eine wichtige Eigenschaft verloren gegangen: Wenn man den 3x3-Teil herausschneidet, hat man keine reine Rotationsmatrix mehr. Denn die Länge der letzten beiden Spaltenvektoren ist nicht mehr 1, sondern&lt;br /&gt;
 sqrt(0² + 0.5² + 0.5²) = sqrt(0.5) = 0.707&lt;br /&gt;
Die Matrix enthält nun also zusätzlich eine unerwünschte Skalierung. Zwar könnte man alle Spaltenvektoren nach dem Blending normalisieren, doch das ist teuer und es gibt viel bessere Lösungen, wie die nächsten Abschnitte zeigen werden.&lt;br /&gt;
&lt;br /&gt;
===Lineare Vertex-Interpolation===&lt;br /&gt;
Was dagegen schon halbwegs brauchbar ist, ist ein ähnlicher Ansatz namens '''Vertex Blending'''. Man baut wieder die Matrizen wie beim Ansatz eben. Zum Gewichten der Transformation mittelt man nun aber nicht die Matrizen, sondern die mit ihnen transformierten Vektoren:&lt;br /&gt;
 pos0 = Matrix[JointID[0]] * VPos;&lt;br /&gt;
 pos1 = Matrix[JointID[1]] * VPos;&lt;br /&gt;
 pos2 = Matrix[JointID[2]] * VPos;&lt;br /&gt;
 pos3 = Matrix[JointID[3]] * VPos;&lt;br /&gt;
 finalPos = pos0 * JointWeight[0]&lt;br /&gt;
          + pos1 * JointWeight[1]&lt;br /&gt;
          + pos2 * JointWeight[2]&lt;br /&gt;
          + pos3 * JointWeight[3];&lt;br /&gt;
Dass dieser Ansatz auch nicht optimal ist, kann man gut an dieser Grafik sehen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:linear vs spherical blending.png|430px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Angenommen wir haben zwei Joints, die Einfluss auf einen Vertex haben. Beide Joints rotieren um die selbe Achse (in der Grafik: um den Punkt P0), jedoch verschieden stark. Der erste Joint würde den Vertex an Position ''v0'' bringen und die Transformation mit dem zweiten Joint hätte ''v1'' als Ergebnis. Wenn wir nun den Vertex Blending-Ansatz zum Mitteln der Transformation anwenden, wäre das Ergebnis ''v'''. Das Blending verläuft entlang der oberen gepunkteten Linie. Was man aber in der Regel haben will, ist eine Interpolation des Winkels, sodass das Ergebnis immer ein Punkt auf der Kreislinie ist. Für den Beispiel-Fall, dass die JointWeights jeweils 0.5 sind, wäre das Ergebnis der (idealen) sphärischen Interpolation der Punkt ''P1'' an dem sich die Winkelhalbierende (orange) mit der Kreislinie schneidet.&lt;br /&gt;
&lt;br /&gt;
Je stärker sich die Rotationen zweier Joints unterscheiden, desto größer wird also der Fehler (= Abstand zwischen ''v''' und ''P1'') des linearen Vertex Blending. Dies wird besonders deutlich, wenn z.B. ein menschlicher Charakter seine Hand oder seinen Arm dreht, die dann wie abgeschnürt aussieht.&lt;br /&gt;
&lt;br /&gt;
===Quaternion + Translationsvektor===&lt;br /&gt;
In [[Quaternion]]en kann man Rotationen speichern und im Gegensatz zu Matrizen lassen sie sich auch sehr gut Interpolieren. Da ihnen aber die Translationsfähigkeit fehlt, benötigt man zusätzlich einen Vektor dafür. Wir möchten erreichen, dass sich ein Vertex wie folgt transformieren lässt:&lt;br /&gt;
 mixedQuaternion = Quaternion[JointID[0]] * JointWeight[0]&lt;br /&gt;
                 + Quaternion[JointID[1]] * JointWeight[1]&lt;br /&gt;
                 + Quaternion[JointID[2]] * JointWeight[2]&lt;br /&gt;
                 + Quaternion[JointID[3]] * JointWeight[3];&lt;br /&gt;
 finalQuaternion = normalize(mixedQuaternion);&lt;br /&gt;
 finalTranslation = Translation[JointID[0]] * JointWeight[0]&lt;br /&gt;
                  + Translation[JointID[1]] * JointWeight[1]&lt;br /&gt;
                  + Translation[JointID[2]] * JointWeight[2]&lt;br /&gt;
                  + Translation[JointID[3]] * JointWeight[3];&lt;br /&gt;
 finalPos = finalQuaternion * VPos + finalTranslation;&lt;br /&gt;
&lt;br /&gt;
Dies ist möglich, aber ein kleines bisschen komplizierter, da wir eigentlich zwei Translationen haben: Eine vor und eine nach der Rotation. Diese müssen wir nun zusammenfassen zu nur einer Translation, die nach der Rotation stattfindet. Dazu wenden wir auf den ersten Translationsvektor einfach die Rotation des Joints an, bevor wir die Summe mit seinem &amp;quot;Kollegen&amp;quot; bilden:&lt;br /&gt;
 Translation = Quaternion * (-TPoseJoint.AbsPos) + Joint.AbsPos;&lt;br /&gt;
Der große Vorteil der Quaternionen gegenüber den voherigen Ansätzen ist wie gesagt die gute Interpolierbarkeit. Wenn man die Quaternionen wie oben gewichtet addiert und das Resultat normalisiert, landet man immer auf der Kreislinie. Zwar entspricht dies nicht ganz der sphärischen Interpolation, aber es gibt einen mathematischen Beweis, der zeigt, dass man nie weiter als 8,15° (Winkel zwischen den beiden orangenen Linien) vom idealen Ergebnis entfernt ist. Dies ist eine obere Grenze für den Fehler - in der Praxis liegt man meistens noch deutlich darunter.&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:quaternion vs spherical blending.png|430px]]&lt;br /&gt;
&lt;br /&gt;
===Dual Quaternions===&lt;br /&gt;
Beim [[Dual Quaternion]]-Ansatz geht man im Prinzip den gleichen Weg, wie bei Matrizen. Man erzeugt also zwei Dual Quaternions für Translation und eines für Rotation. Via Multiplikation fasst man alle drei Transformationen in einem Dual Quaternion zusammen. Auf diese Weise erzeugt man für jeden Joint ein Dual Quaternion. Das Tolle an Dual Quaternions ist jedoch, dass man sie im Gegensatz zu Matrizen ganz hervorragend (genau wie gewöhnliche Quaternionen) interpolieren kann. Die Vertex-Transformation sieht also so aus:&lt;br /&gt;
 finalDQ = DualQuat[JointID[0]] * JointWeight[0]&lt;br /&gt;
         + DualQuat[JointID[1]] * JointWeight[1]&lt;br /&gt;
         + DualQuat[JointID[2]] * JointWeight[2]&lt;br /&gt;
         + DualQuat[JointID[3]] * JointWeight[3];&lt;br /&gt;
 finalDQ.normalize();&lt;br /&gt;
 finalPos = finalDQ * VPos;&lt;br /&gt;
Was genau die letzten beiden Zeilen machen, ist im Artikel [[Dual Quaternion]] erklärt.&lt;br /&gt;
Da Normalenvektoren der Translationsteil des Dual Quaternions nicht betrifft, wird auf ihn nur das nicht-duale Quaternion angewandt:&lt;br /&gt;
 finalNormal = finalDQ.real * Normal&lt;br /&gt;
&lt;br /&gt;
Dual Quaternion-Skinning bietet neben der schönen Interpolation den Vorteil, dass ein Dual Quaternion nur halb so viel Platz benötigt wie eine Matrix. Leider ist es jedoch nicht so schnell wie der Vertex-Blending Ansatz und die Mathematik dahinter ist schwer in aller Tiefe verstehen.&lt;br /&gt;
&lt;br /&gt;
==Implementation im Vertexshader==&lt;br /&gt;
Ein Model hat in der Regel mehrere tausend Vertices und da man in Videospielen meistens auch noch mehrere animierte Models gleichzeitig sieht, müssen schnell mal einige zehntausend Vertices pro Frame per skeletaler Animation transformiert werden. Selbst heutige CPUs stoßen da schonmal an Grenzen - vor allem, wenn sie auch noch andere Aufgaben erledigen soll. Die benötigte Rechenleistung lässt sich nur durch Parallelisierung bereitstellen. Und - Quizfrage: Welcher Prozessor im PC arbeitet extrem parallel? Na...?&amp;lt;br&amp;gt;&lt;br /&gt;
Ja, richtig: Die GPU. Also nutzen wir doch deren Shader-Rechenwerke für die Transformation. Genauer gesagt, werden wir den Vertexshader dafür nutzen:&lt;br /&gt;
&amp;lt;source lang=glsl&amp;gt;#version 330&lt;br /&gt;
const int g_JointsMax = 64;&lt;br /&gt;
&lt;br /&gt;
uniform mat4 u_ModelViewProjectionMatrix;&lt;br /&gt;
uniform mat3 u_NormalMatrix;&lt;br /&gt;
uniform vec4 u_DualQuats[g_JointsMax*2];&lt;br /&gt;
&lt;br /&gt;
in vec3 inPos;&lt;br /&gt;
in vec3 inNormal;&lt;br /&gt;
in vec2 inTexCoord;&lt;br /&gt;
in vec4 inJointWeight;&lt;br /&gt;
in uvec4 inJointID;&lt;br /&gt;
&lt;br /&gt;
out vec3 vf_Normal;&lt;br /&gt;
out vec2 vf_TexCoord;&lt;br /&gt;
&lt;br /&gt;
void NormalizeDualQuat(inout vec4 real, inout vec4 dual)&lt;br /&gt;
{&lt;br /&gt;
  real = normalize(real);&lt;br /&gt;
  dual -= real * dot(real, dual);&lt;br /&gt;
}&lt;br /&gt;
void GetDualQuat(out vec4 real, out vec4 dual)&lt;br /&gt;
{&lt;br /&gt;
  real = u_DualQuats[inJointID[0]*2u] * inJointWeight[0]&lt;br /&gt;
       + u_DualQuats[inJointID[1]*2u] * inJointWeight[1]&lt;br /&gt;
       + u_DualQuats[inJointID[2]*2u] * inJointWeight[2]&lt;br /&gt;
       + u_DualQuats[inJointID[3]*2u] * inJointWeight[3];&lt;br /&gt;
  dual = u_DualQuats[inJointID[0]*2u +1u] * inJointWeight[0]&lt;br /&gt;
       + u_DualQuats[inJointID[1]*2u +1u] * inJointWeight[1]&lt;br /&gt;
       + u_DualQuats[inJointID[2]*2u +1u] * inJointWeight[2]&lt;br /&gt;
       + u_DualQuats[inJointID[3]*2u +1u] * inJointWeight[3];&lt;br /&gt;
&lt;br /&gt;
  NormalizeDualQuat(real, dual);&lt;br /&gt;
}&lt;br /&gt;
vec3 TransformPosition(vec3 v, vec4 real, vec4 dual)&lt;br /&gt;
{&lt;br /&gt;
  vec3 term1 = cross(real.xyz,  cross(real.xyz, v) + real.w*v);&lt;br /&gt;
  v += 2.0 * (term1 + real.w*dual.xyz - dual.w*real.xyz + cross(real.xyz, dual.xyz));&lt;br /&gt;
  return v;&lt;br /&gt;
}&lt;br /&gt;
vec3 TransformNormal(vec3 n, vec4 quat)&lt;br /&gt;
{&lt;br /&gt;
  n += 2.0 * cross(quat.xyz,  cross(quat.xyz, n) + quat.w*n);&lt;br /&gt;
  return n;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
  vec3 skinnedPos    = inPos;&lt;br /&gt;
  vec3 skinnedNormal = inNormal;&lt;br /&gt;
&lt;br /&gt;
  // dual quaternion skinning&lt;br /&gt;
  if(inJointWeight[0] &amp;gt; 0.0)&lt;br /&gt;
  {&lt;br /&gt;
    vec4 real, dual;&lt;br /&gt;
    GetDualQuat(real, dual);&lt;br /&gt;
    skinnedPos    = TransformPosition(inPos, real, dual);&lt;br /&gt;
    skinnedNormal = TransformNormal(inNormal, real);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // usual transformation&lt;br /&gt;
  vf_TexCoord = inTexCoord;&lt;br /&gt;
  vf_Normal = normalize(u_NormalMatrix * skinnedNormal);&lt;br /&gt;
  gl_Position = u_ModelViewProjectionMatrix * vec4(skinnedPos, 1.0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dieser Vertexshader implementiert DualQuaternion-Skinning. Bei Vertices, die nicht geskinnt werden sollen, setzt man einfach die erste Komponente des Vertexattributs ''inJointWeight'' auf 0. Wie man sieht, ist die Implementierung sehr nahe am Pseudocode der Beschreibung des Ansatzes oben. Es sollte daher leicht fallen, auch die anderen Verfahren im Vertexshader zu implementieren.&lt;br /&gt;
&lt;br /&gt;
Die Transformation mittels Quaternion und Translationsvektor würde z.B. so aussehen:&lt;br /&gt;
&amp;lt;source lang=glsl&amp;gt;vec3 TransformPosition(vec3 v, vec4 quat, vec3 trans)&lt;br /&gt;
{&lt;br /&gt;
  return TransformNormal(v, quat) + trans;&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Schlusswort==&lt;br /&gt;
Das war es auch schon mit meinem ersten Wiki-Artikel in der Kategorie Tutorial. Ich hoffe, die Erklärungen waren verständlich und nicht zu trocken. Falls nicht, gibt es immer noch unser [http://www.delphigl.com/forum/index.php Forum], das auf Feedback und Fragen wartet.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann man die in diesem Tutorial beschriebene Animationstechnik noch erweitern. Sinnvoll wäre z.B., wenn ein Charakter mehrere Animationen gleichzeitig ausführen kann (manche Animationen betreffen ja nur Teile des Skeletts) oder ein sanftes Überblenden vom Kriechen zum Gehen und vom Gehen zum Rennen.&lt;br /&gt;
&lt;br /&gt;
Für diejenigen, die noch tiefer in die Materie der Charakteranimation einsteigen wollen, gibt es noch eine Menge anderer interessanter Techniken zu erlernen. Mittels inverser Kinematik kann man beispielsweise berechnen, wie sich der Rest des Skeletts bewegen muss, um einen bestimmten Joint eines Charakters an eine bestimmte Position zu bekommen. Damit lassen sich u.a. automatisch an die Umgebung angepasste Animationen erzeugen.&lt;br /&gt;
Wenn du eine coole Technik erlernt hast, zu der es noch kein Tutorial auf DGL gibt, würde es (nicht nur) mich natürlich freuen, wenn du die Plattform nutzt, dein Wissen zu teilen. In diesem Sinne: Frohes Schaffen!&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=alGetString&amp;diff=26004</id>
		<title>alGetString</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=alGetString&amp;diff=26004"/>
				<updated>2014-01-02T22:21:21Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Delphi-Spezifikation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= alGetString =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''alGetString''' - Liefert eine OpenAL-Stringeigenschaft.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 function '''alGetString'''(''param'': TALenum): PALubyte;&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! ''param'' &lt;br /&gt;
| Eigenschaft, welche zurückgegeben werden soll&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die Funktion '''alGetString''' liefert eine Stringeigenschaft von [[OpenAL]] zurück. Der Rückgabewert ist ein Zeiger auf einen [[Null-terminiert|null-terminierten]] String.&lt;br /&gt;
&lt;br /&gt;
Folgende Werte werden für ''param'' akzeptiert:&lt;br /&gt;
=== AL_EXTENSIONS ===&lt;br /&gt;
: Eine Liste der verfügbaren Erweiterungen wird zurückgegeben, die einzelnen Erweiterungen sind durch Leerzeichen voneinander getrennt. Um auf einfachem Wege zu testen, ob eine bestimmte Erweiterung vorhanden ist, kann man auch die Funktion [[alIsExtensionPresent]] verwenden.&lt;br /&gt;
&lt;br /&gt;
=== AL_RENDERER ===&lt;br /&gt;
: Gibt den Namen des Renderers zurück.&lt;br /&gt;
&lt;br /&gt;
=== AL_VENDOR ===&lt;br /&gt;
: Der Name des Herstellers der OpenAL-Implementation wird zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
=== AL_VERSION ===&lt;br /&gt;
: Die Version der OpenAL wird zurückgegeben. Diese hat normalerweise das Format &amp;quot;&amp;lt;Hauptversion&amp;gt;.&amp;lt;Nebenversion&amp;gt;&amp;quot; und kann anschließend eventuell noch herstellerspezifische Informationen enthalten.&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
Falls ein ungültiger Wert für ''param'' angegeben wird, gibt die Funktion einen '''nil'''-Zeiger zurück und der Fehler '''AL_INVALID_ENUM''' wird generiert. Der Fehler kann dann mit der Funktion [[alGetError]] erfragt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''AL_INVALID_ENUM''' wird generiert, wenn der angegebene Wert von ''param'' ungültig ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[alcGetString]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AL|GetString]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=alcCaptureCloseDevice&amp;diff=26003</id>
		<title>alcCaptureCloseDevice</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=alcCaptureCloseDevice&amp;diff=26003"/>
				<updated>2014-01-02T20:11:04Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Delphi-Spezifikation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= alcCaptureCloseDevice =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''alcCaptureCloseDevice''' - Schließt ein Audioaufnahmegerät.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 function '''alcCaptureCloseDevice'''(''device'': PALCdevice): TALCboolean;&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! ''device'' &lt;br /&gt;
| Zeiger auf das zu schließende Aufnahmegerät&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die Funktion '''alcCaptureCloseDevice''' schließt das durch ''device'' angegebene Audioaufnahmegerät. Im Erfolgsfall wird '''ALC_TRUE''' zurückgegeben, bei Fehlschlag '''ALC_FALSE'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
Der '''nil'''-Zeiger ist kein gültiger Wert für ''device''. Sobald das Aufnahmegerät geschlossen wurde, bezeichnet ''device'' ebenfalls kein gültiges Aufnahmegerät mehr.&lt;br /&gt;
&lt;br /&gt;
Falls bei der Ausführung ein Fehler auftritt, kann dieser mit [[alcGetError]] abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Änderungen ==&lt;br /&gt;
Folgende Erweiterungen hat die Funktion erfahren:&lt;br /&gt;
=== Ab OpenAL-Version 1.1 ===&lt;br /&gt;
Die Funktion '''alcCaptureCloseDevice''' ist erst ab der OpenAL-Version 1.1 verfügbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''ALC_INVALID_DEVICE''' wird generiert, wenn ''device'' kein zulässiges Aufnahmegerät ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[alcCaptureOpenDevice]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AL|CaptureCloseDevice]]&lt;br /&gt;
[[Kategorie:ALC|CaptureCloseDevice]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=alBuffer&amp;diff=26002</id>
		<title>alBuffer</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=alBuffer&amp;diff=26002"/>
				<updated>2014-01-02T16:52:21Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Delphi-Spezifikation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= alBuffer =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''alBuffer''' - Setzt Eigenschaften eines Puffers der OpenAL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''alBuffer3f'''(''buffer'': TALuint; ''param'': TALenum; ''v1'': TALfloat; ''v2'': TALfloat; ''v3'': TALfloat);&lt;br /&gt;
 procedure '''alBufferf'''(''buffer'': TALuint; ''param'': TALenum; ''value'': TALfloat);&lt;br /&gt;
 procedure '''alBufferfv'''(''buffer'': TALuint; ''param'': TALenum; ''values'': PALfloat);&lt;br /&gt;
 procedure '''alBuffer3i'''(''buffer'': TALuint; ''param'': TALenum; ''v1'': TALint; ''v2'': TALint; ''v3'': TALint);&lt;br /&gt;
 procedure '''alBufferi'''(''buffer'': TALuint; ''param'': TALenum; ''value'': TALint);&lt;br /&gt;
 procedure '''alBufferiv'''(''buffer'': TALuint; ''param'': TALenum; ''values'': PALint);&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! ''buffer'' &lt;br /&gt;
| Puffer, dessen Eigenschaft gesetzt werden soll&lt;br /&gt;
|-&lt;br /&gt;
! ''param'' &lt;br /&gt;
| Symbolische Konstante, welche die zu setzende Eigenschaft bestimmt&lt;br /&gt;
|-&lt;br /&gt;
! ''value''&lt;br /&gt;
| Der zu setzende TALfloat- bzw. TALint-Wert (nur bei '''alBufferf''' bzw. '''alBufferi''')&lt;br /&gt;
|-&lt;br /&gt;
! ''values''&lt;br /&gt;
| Zeiger auf einen TALfloat-/ TALint-Array, welcher die zu setzenden Werte enthält (nur bei '''alBufferfv''' bzw. '''alBufferiv''')&lt;br /&gt;
|-&lt;br /&gt;
! ''v1, v2, v3''&lt;br /&gt;
| Die drei zu setzenden TALfloat- bzw. TALint-Werte (nur bei '''alBuffer3f''' bzw. '''alBuffer3i''')&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die Funktion '''alBuffer''' bzw. ihre Varianten für verschiedene Wertargumente setzt die durch den Parameter ''param'' angegebene Eigenschaft eines OpenAL-Puffers.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
In der Spezifikation für OpenAL 1.1 sind keine relevanten Eigenschaften definiert, welche durch diese Funktion gesetzt werden könnten. Puffereigenschaften werden zur Zeit allein beim Füllen eines Puffers durch [[alBufferData]] festgelegt. Jedoch besteht die Möglichkeit, dass eine OpenAL-Erweiterung die Funktion '''alBuffer''' benutzt.&lt;br /&gt;
&lt;br /&gt;
Falls bei der Ausführung ein Fehler auftritt, kann dieser mit [[alGetError]] abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Änderungen ==&lt;br /&gt;
Folgende Erweiterungen hat die Funktion erfahren:&lt;br /&gt;
=== Ab OpenAL-Version 1.1 ===&lt;br /&gt;
Die Funktion '''alBuffer''' bzw. ihre Varianten '''alBuffer3f''', '''alBufferf''', '''alBufferfv''', '''alBuffer3i''', '''alBufferi''' und '''alBufferiv''' sind erst ab Version 1.1 der AL verfügbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''AL_INVALID_ENUM''' wird generiert, wenn der angegebene Parameter ''param'' unzulässig ist.&lt;br /&gt;
&lt;br /&gt;
'''AL_INVALID_NAME''' wird generiert, falls der Puffer ''buffer'' keine Parameter hat (sprich: der Nullpuffer ist) oder wenn dieser Puffer nicht existiert. (Siehe dazu auch [[alIsBuffer]].)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Zugehörige Wertrückgaben ==&lt;br /&gt;
[[alGetBuffer]] mit entsprechendem Token&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[alBufferData]], [[alGetBuffer]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AL|Buffer]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=alcCreateContext&amp;diff=26001</id>
		<title>alcCreateContext</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=alcCreateContext&amp;diff=26001"/>
				<updated>2014-01-02T16:14:13Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Beschreibung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= alcCreateContext =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''alcCreateContext''' - Erzeugt einen neuen [[ALC-Kontext]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 function '''alcCreateContext'''(''pDevice'': PALCdevice; ''attrList'': PALCint): PALCcontext;&lt;br /&gt;
&lt;br /&gt;
&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;
! ''pDevice'' &lt;br /&gt;
| Zeiger auf das Gerät, für das ein neuer ALC Context erstellt werden soll.&lt;br /&gt;
|-&lt;br /&gt;
! ''attrList'' &lt;br /&gt;
| Zeiger auf eine Liste mit Attributen. Siehe Beschreibung.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die Funktion '''alcCreateContext''' erstellt für das ALC-Gerät ''pDevice'' einen neuen Kontext und gibt den Zeiger auf den neuen Kontext zurück. Bei Fehlschlag wird ein '''nil'''-Zeiger zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
AL (bzw. ALC) ordnet jedem Kontext ein entsprechendes Gerät zu. Folglich kann ein Kontext erst (mit Hilfe der Funktion '''alcCreateContext''') erstellt werden, wenn zuvor ein Gerät geöffnet wurde. Siehe dazu [[alcOpenDevice]].&lt;br /&gt;
&lt;br /&gt;
Beim Erstellen eines Kontextes können bestimmte Attribute gesetzt werden. Werden diese nicht gesetzt, werden implementationsabhängige Standardwerte benutzt.&lt;br /&gt;
&lt;br /&gt;
Die Kontexterstellung schlägt fehl, wenn &lt;br /&gt;
*die Anwendung Attribute anfordert, welche nicht geliefert werden können oder &lt;br /&gt;
*eine ungültige Kombination von Attributen angefordert wurde oder&lt;br /&gt;
*der Wert eines spezifizierten Attributes bzw. eine Kombination von Attributen nicht mit den Standardwerten für unspezifizierte Attribute übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
Als Attribute kann '''nil''' oder eine ALC_INVALID-terminierte Liste von Integer-Paaren verwendet werden. Jedes Paar besteht dabei aus einer der nachfolgenden Konstanten und dem zugehörigen Wert.&lt;br /&gt;
&lt;br /&gt;
Folgende Konstanten können genutzt werden:&lt;br /&gt;
===ALC_FREQUENCY===&lt;br /&gt;
: Erwartet als Wert die interne Frequenz in Hertz für das Zusammenmischen von Ausgabepuffern.&lt;br /&gt;
&lt;br /&gt;
===ALC_MONO_SOURCES===&lt;br /&gt;
: Erwartet als Wert einen Hinweis, wie viele Source-Objekte in der Lage sein sollen, Monoaudiodaten zu unterstützen.&lt;br /&gt;
&lt;br /&gt;
===ALC_REFRESH===&lt;br /&gt;
: Erwartet als Wert die Frequenz in Hertz für das Refreshintervall. Übliche Werte liegen bei 5..15 Hz.&lt;br /&gt;
&lt;br /&gt;
===ALC_STEREO_SOURCES===&lt;br /&gt;
: Erwartet als Wert einen Hinweis, wie viele Source-Objekte in der Lage sein sollen, Stereodaten zu unterstützen.&lt;br /&gt;
&lt;br /&gt;
===ALC_SYNC===&lt;br /&gt;
: Boolean, gibt an ob der Kontext einen eigenen Thread startet (AL_FALSE, Standard) oder manuell [[alcUpdateContext]] verwendet werden soll (AL_TRUE).&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
Awendungen haben möglicherweise einen festen oder beschränkten Rhythmus für Zustandsänderungen (z.B. synchron mit der OpenGL-Framerate). In diesem Fall ist es wünschenswert den '''''mixahead interval (milliseconds)''''' oder die Refreshrate (Hz) für den Thread anzugeben. Dies ist besonders für synchrone Kontexte wichtig, wo die Anwendung ein Refreshintervall, welches sie einhalten möchte, anzugeben hat.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beispiel ==&lt;br /&gt;
Folgender Code öffnet ein Gerät und erzeugt darin einen Kontext, der zum aktuellen Kontext gemacht wird.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;var device: PALCdevice;&lt;br /&gt;
    context: PALCcontext;&lt;br /&gt;
...&lt;br /&gt;
device:= alcOpenDevice(nil); //öffnet das Standardgerät&lt;br /&gt;
if device&amp;lt;&amp;gt;nil then&lt;br /&gt;
begin&lt;br /&gt;
  context:= alcCreateContext(device, nil); //erzeugt einen ALC-Kontext&lt;br /&gt;
  if context&amp;lt;&amp;gt;nil then&lt;br /&gt;
    alcMakeContextCurrent(context); //setzt den aktiven Kontext&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''ALC_INVALID_DEVICE''' wird generiert, wenn kein gültiges Gerät angegeben wurde.&lt;br /&gt;
&lt;br /&gt;
'''ALC_INVALID_OPERATION''' wird generiert, falls kein weiterer ALC-Kontext für das angegebene Gerät erstellt werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[alcDestroyContext]], [[alcGetCurrentContext]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AL|CreateContext]]&lt;br /&gt;
[[Kategorie:ALC|CreateContext]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Lokalisierung&amp;diff=26000</id>
		<title>Lokalisierung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Lokalisierung&amp;diff=26000"/>
				<updated>2014-01-01T23:23:52Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Anforderungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lokalisierung =&lt;br /&gt;
== Allgemein ==&lt;br /&gt;
Als Lokalisierung bezeichnet man den Vorgang eine Software in verschiedene Sprachen zu übersetzen.&lt;br /&gt;
&lt;br /&gt;
Besonders schwer ist die Übersetzung in Sprachen mit komplett anderem Zeichensatz (Kyrillisch, Chinesisch, Japanisch etc.), insbesondere wenn diese Multibyte-Schriften benötigen. So weit wird jedoch kaum ein Hobbyentwickler gehen, der aus keinem dieser Länder stammt, weshalb ich darauf nicht eingehen werde.&lt;br /&gt;
&lt;br /&gt;
== Anforderungen ==&lt;br /&gt;
* Einfach einzusetzen&lt;br /&gt;
* Übersetzen in weitere Sprachen ohne Neukompilierung&lt;br /&gt;
* Auch bei anderem Satzbau noch verwendbar&lt;br /&gt;
&lt;br /&gt;
== Ansätze ==&lt;br /&gt;
* Formularresourcen (Borland)&amp;lt;br&amp;gt;Nachteil: Es ist schwer das Formular nach dem Übersetzen noch anzupassen und es wird bei sonstigen Texten keine Unterstützung geboten&lt;br /&gt;
* Programm das im Quelltext alle Strings suchen und ersetzen kann&amp;lt;br&amp;gt;Nachteil: Es gibt viele nicht zu übersetzende Strings, Programm muss für jede Sprache kompiliert werden&lt;br /&gt;
* Übersetzungsfunktion:&amp;lt;br&amp;gt;Vorteil: Kann überall im Quelltext eingesetzt werden&amp;lt;br&amp;gt;Nachteil: Jeder zu übersetzende String muss an diese Funktion übergeben werden&lt;br /&gt;
&lt;br /&gt;
== Einfaches Übersetzungssystem ==&lt;br /&gt;
=== Allgemeine Übersetzungen ===&lt;br /&gt;
Hier werde ich den 3. Ansatz implementieren: Eine Übersetzungsfunktion.&lt;br /&gt;
Ich verwende zur Übersetzung Stringlisten der Form&lt;br /&gt;
 Bezeichner=Wert&lt;br /&gt;
Sie sind also ähnlich wie Ini-Dateien aufgebaut, jedoch ohne Sektionen.&lt;br /&gt;
&lt;br /&gt;
Sie werden mit Hilfe der Funktion '''LoadLanguage''' geladen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure LoadLanguage(const Lang: String);&lt;br /&gt;
begin&lt;br /&gt;
 CurLang:=LowerCase(Lang);&lt;br /&gt;
 LangData.LoadFromFile(ChangeFileExt(ParamStr(0),'.'+CurLang));&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion macht nicht mehr als die momentane Sprache in einer Variable zu speichern und die Übersetzungsdatei zu laden. Der Dateiname wird bei mir über '''ChangeFileExt(ParamStr(0),'.'+CurLang)''' festgelegt, das solltet ihr jedoch an euer Projekt anpassen.&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Übersetzung wird von der Funktion '''Translate''' durchgeführt.&lt;br /&gt;
(Ich bevorzuge aussagekräftige Funktionsnamen, besonders im C/C++ Bereich habe ich auch schon einen einfachen Unterstrich als Namen für so eine Funktion gesehen. Das ist auch in Delphi möglich, falls ihr so tippfaul seid)&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function Translate(const Name: string): string;overload;&lt;br /&gt;
var i:Integer;&lt;br /&gt;
begin&lt;br /&gt;
 i := LangData.IndexOfName(Name);&lt;br /&gt;
 if (I&amp;gt;-1)&lt;br /&gt;
  then Result:=LangData.Values[Name];&lt;br /&gt;
  else raise Exception.Create('String not translated: &amp;quot;'+Name+'&amp;quot;');&lt;br /&gt;
 Result:=StringReplace(result,'\r',#13,[rfReplaceAll]);&lt;br /&gt;
 Result:=StringReplace(result,'\n',#10,[rfReplaceAll]);&lt;br /&gt;
 Result:=StringReplace(result,'\\','\',[rfReplaceAll]);&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion sucht den über den Parameter ''Name'' übergebenen Bezeichner in der Stringlist (ich verwende auf Performancegründen eine sortierte Stringlist und die Funktion Find) wenn sie ihn findet werden noch die Escapezeichen \r (Wagenrücklauf=#13) und \n (Neue Zeile=#10) sowie der Doppelbackslash ersetzt und das Ergebnis zurückgeliefert.&lt;br /&gt;
Wenn der Bezeichner nicht gefunden wird, wird eine Exception generiert. Dieses Verhalten ist zum Debuggen nützlich, sollte im Endprodukt jedoch möglichst geändert werden, wenn man den Benutzer nicht mit Exceptions verärgern will.&lt;br /&gt;
&lt;br /&gt;
Ein kleines Beispiel:&lt;br /&gt;
Man hat folgende Übersetzungsdatei:&lt;br /&gt;
&lt;br /&gt;
 Projektname.de&lt;br /&gt;
  startmsg=Herzlich Willkommen&lt;br /&gt;
  quitmsg=Auf Wiedersehen&lt;br /&gt;
&lt;br /&gt;
Dann kann man das im Programm folgendermaßen verwenden:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure TForm1.FormCreate(Sender: TObject);&lt;br /&gt;
begin&lt;br /&gt;
 LoadLanguage('de');&lt;br /&gt;
 ShowMessage(Translate('startmsg'));&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);&lt;br /&gt;
begin&lt;br /&gt;
 ShowMessage(Translate('quitmsg'));&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
Es ist jedoch darauf zu achten, dass dass '''Translate''' case-sensitive ist, also '''Translate('StartMsg')''' nicht das selbe wie '''Translate('startmsg')''' ist.&lt;br /&gt;
&lt;br /&gt;
Diese Funktion hat jedoch den Nachteil nicht für dynamische Texte einsetzbar zu sein.&lt;br /&gt;
z.B. wenn ich den Text 'Spieler '+SpielerNummer+' greift dich an' übersetzen will, bräuchte ich für jede Spielernummer einen eigenen Bezeichner, was sicher nicht effizient ist, und bei Spielernamen komplett versagen würde.&lt;br /&gt;
&lt;br /&gt;
Daher gibt es noch eine zweite erweiterte Übersetzungsfunktion die auf die erste zurückgreift:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;Function Translate(const Name: string; const Args: array of const): String; overload;&lt;br /&gt;
begin&lt;br /&gt;
 Result:=Format(Translate(Name),Args);&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese Funktion übernimmt zusammen mit dem Bezeichner noch ein Array an Variablen/Konstanten, die es dann zusammen mit der Übersetzung des Bezeichners an die Delphifunktion '''Format''' übergibt.&lt;br /&gt;
&lt;br /&gt;
'''Format''' ersetzt bestimmte Zeichenkombinationen im Text durch die Variablen des Arrays:&lt;br /&gt;
%d für Integer&lt;br /&gt;
%s für Strings&lt;br /&gt;
%f für Kommazahlen&lt;br /&gt;
Weitere Informationen dazu bietet die Delphi-Hilfe unter &amp;quot;Format-Strings&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Auch hierzu ein Beispiel:&lt;br /&gt;
 Projektname.de&lt;br /&gt;
  attackmsg=Spieler %d greift sie an&lt;br /&gt;
  chatmsg=&amp;lt;Spieler %d&amp;gt; %s&lt;br /&gt;
&lt;br /&gt;
Verwendet werden sie dann so&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt; LoadLanguage('de');&lt;br /&gt;
 showmessage(translate('attackmsg',[SpielerNummer]));&lt;br /&gt;
 showmessahe(translate('chatmsg',[SpielerNummer,Nachricht]));&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zur Abfrage welche Sprache momentan aktiv ist dient: (Ihr Ergebnis ist klein geschrieben)&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function CurrentLanguage:string;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier noch der gesamte Quelltext der Übersetzungsunit:&lt;br /&gt;
''Translator.pas''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;unit Translator;&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
function Translate(const Name: String; const Args: array of const): String; overload;&lt;br /&gt;
function Translate(const Name: String): String; overload;&lt;br /&gt;
&lt;br /&gt;
procedure LoadLanguage(const Lang: String);&lt;br /&gt;
function CurrentLanguage: String;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
uses SysUtils,Classes;&lt;br /&gt;
&lt;br /&gt;
var LangData:TStringlist;&lt;br /&gt;
    CurLang:String;&lt;br /&gt;
&lt;br /&gt;
Function Translate(const Name: string; const Args: array of const): String; overload;&lt;br /&gt;
begin&lt;br /&gt;
 Result:=Format(Translate(Name),Args);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
Function Translate(const Name: string): String; overload;&lt;br /&gt;
var i:Integer;&lt;br /&gt;
begin&lt;br /&gt;
 i := LangData.IndexOfName(Name);&lt;br /&gt;
 if (I&amp;gt;-1)&lt;br /&gt;
  then Result:=LangData.Values[Name];&lt;br /&gt;
  else raise Exception.Create('String not translated: &amp;quot;'+Name+'&amp;quot;');&lt;br /&gt;
 Result:=StringReplace(result,'\r',#13,[rfReplaceAll]);&lt;br /&gt;
 Result:=StringReplace(result,'\n',#10,[rfReplaceAll]);&lt;br /&gt;
 Result:=StringReplace(result,'\\','\',[rfReplaceAll]);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure LoadLanguage(const Lang:String);&lt;br /&gt;
begin&lt;br /&gt;
 CurLang:=LowerCase(Lang);&lt;br /&gt;
 LangData.LoadFromFile(ChangeFileExt(ParamStr(0),'.'+CurLang));&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function CurrentLanguage:String;&lt;br /&gt;
begin&lt;br /&gt;
 Result:=CurLang;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
initialization&lt;br /&gt;
 LangData:=TStringList.Create;&lt;br /&gt;
 LangData.Sorted:=true;&lt;br /&gt;
finalization&lt;br /&gt;
 LangData.Free;&lt;br /&gt;
end.&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung von Formularen und Komponenten ===&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zu ''Translator.pas'' die relativ allgemein einsetzbar ist, ist diese darauf aufbauende Unit auf die Delphi VCL spezialisiert.&lt;br /&gt;
Sie stellt zwei weitere Funktionen zu Verfügung:&lt;br /&gt;
Zum einen eine weitere Überladung von '''Translate''', die ein ganzes Formular auf einmal übersetzt&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;Procedure Translate(const Component:TComponent;Path:String='');overload;&amp;lt;/source&amp;gt;&lt;br /&gt;
Verwendung:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;Translate(Form1)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und eine weitere Funktion die eine ensprechende Übersetzungsdatei aus einem Formular generiert:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure CreateTranslationTable(const Component:TComponent;const Filename:String);&amp;lt;/source&amp;gt;&lt;br /&gt;
Verwendung:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;CreateTranslationTable(Form1,'Form1table.txt');&amp;lt;/source&amp;gt;&lt;br /&gt;
Dabei entsteht eine Datei die etwa wie die folgende aussieht, und dann vom Benutzer übersetzt und in die jeweilige Sprachdatei integriert werden sollte:&lt;br /&gt;
 Form1.Caption=Form1&lt;br /&gt;
 Form1.Label1.Caption=Label1&lt;br /&gt;
 Form1.CheckBox1.Caption=CheckBox1&lt;br /&gt;
 Form1.RadioButton1.Caption=RadioButton1&lt;br /&gt;
 Form1.GroupBox1.Caption=GroupBox1&lt;br /&gt;
 Form1.RadioGroup1.Caption=RadioGroup1&lt;br /&gt;
 Form1.Panel1.Caption=Panel1&lt;br /&gt;
 Form1.BitBtn1.Caption=BitBtn1&lt;br /&gt;
 Form1.BitBtn1.Hint=Klick Me&lt;br /&gt;
 Form1.TabControl1.Tabs=a\r\nb\r\nc\r\n&lt;br /&gt;
 Form1.TabSheet1.Caption=TabSheet1&lt;br /&gt;
 Form1.Memo1.Caption=a\r\nb\r\nc\r\n&lt;br /&gt;
 Form1.ListBox1.Items=a\r\nb\r\nc\r\n&lt;br /&gt;
 Form1.ComboBox1.Caption=ComboBox1&lt;br /&gt;
 Form1.ComboBox1.Items=a\r\nb\r\nc\r\n&lt;br /&gt;
 Form1.a.Caption=a&lt;br /&gt;
 Form1.a.Hint=&amp;gt;&amp;gt;a&amp;lt;&amp;lt;&lt;br /&gt;
 Form1.Action1.Caption=Hallo&lt;br /&gt;
 Form1.Action1.Hint=Hallo und Willkommen&lt;br /&gt;
&lt;br /&gt;
Dabei werden folgende Eigenschaften gespeichtert/gelesen:&lt;br /&gt;
* Bei allen von TControl abgeleiteten Komponenten sowie TMenuItem und TCustomAction die Eigenschaften Caption/Text und Hint sofern sie im ursprünglichen Formular den Wert '' hat&amp;lt;br&amp;gt;Das funktioniert beispielsweise bei Label, Edit, Memo, Panel ...&lt;br /&gt;
* TCombobox/TListbox: Die Eigenschaft Items&lt;br /&gt;
* TTabControl: Die Eigenschaft Tabs&lt;br /&gt;
&lt;br /&gt;
''TranslatorVCL.pas''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;unit TranslatorVCL;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
uses classes,translator,controls,menus,actnlist,sysutils,comctrls,stdctrls;&lt;br /&gt;
Procedure Translate(const Component:TComponent;Path:String='');overload;&lt;br /&gt;
procedure CreateTranslationTable(const Component:TComponent;const Filename:String);&lt;br /&gt;
implementation&lt;br /&gt;
Type TMyControl=class(TControl);&lt;br /&gt;
&lt;br /&gt;
Procedure Translate(const Component:TComponent;Path:String='');overload;&lt;br /&gt;
var i:integer;&lt;br /&gt;
begin&lt;br /&gt;
 //Pfad anpassen&lt;br /&gt;
 if Path=''&lt;br /&gt;
  then Path:=Component.Name&lt;br /&gt;
  else Path:=Path+'.'+Component.Name;&lt;br /&gt;
 //Eigenschaften übersetzen&lt;br /&gt;
 if (Component is TControl)and&lt;br /&gt;
    (TMyControl(Component).Caption&amp;lt;&amp;gt;'')then &lt;br /&gt;
    TMyControl(Component).Caption:=Translate(Path+'.Caption');&lt;br /&gt;
 if (Component is TControl)and&lt;br /&gt;
    (TControl(Component).Hint&amp;lt;&amp;gt;'')then &lt;br /&gt;
    TMyControl(Component).Hint:=Translate(Path+'.Hint');&lt;br /&gt;
 if (Component is TMenuItem)and&lt;br /&gt;
    (TMenuItem(Component).Caption&amp;lt;&amp;gt;'')and&lt;br /&gt;
    (TMenuItem(Component).Action=nil)then &lt;br /&gt;
    TMenuItem(Component).Caption:=Translate(Path+'.Caption');&lt;br /&gt;
 if (Component is TMenuItem)and&lt;br /&gt;
    (TMenuItem(Component).Hint&amp;lt;&amp;gt;'')and&lt;br /&gt;
    (TMenuItem(Component).Action=nil)then &lt;br /&gt;
    TMenuItem(Component).Hint:=Translate(Path+'.Hint');&lt;br /&gt;
 if (Component is TCustomAction)and&lt;br /&gt;
    (TCustomAction(Component).Caption&amp;lt;&amp;gt;'')then &lt;br /&gt;
    TCustomAction(Component).Caption:=Translate(Path+'.Caption');&lt;br /&gt;
 if (Component is TCustomAction)and&lt;br /&gt;
    (TCustomAction(Component).Hint&amp;lt;&amp;gt;'')then &lt;br /&gt;
    TCustomAction(Component).Hint:=Translate(Path+'.Hint');&lt;br /&gt;
 if (Component is TTabControl)and&lt;br /&gt;
    (TTabControl(Component).Tabs.text&amp;lt;&amp;gt;'')then &lt;br /&gt;
    TTabControl(Component).Tabs.text:=Translate(Path+'.Tabs');&lt;br /&gt;
 if (Component is TCustomComboBox)and&lt;br /&gt;
    (TCustomComboBox(Component).items.text&amp;lt;&amp;gt;'')then &lt;br /&gt;
    TCustomComboBox(Component).items.text:=Translate(Path+'.Items');&lt;br /&gt;
 if (Component is TCustomListBox)and&lt;br /&gt;
    (TCustomListBox(Component).items.text&amp;lt;&amp;gt;'')then &lt;br /&gt;
    TCustomListBox(Component).items.text:=Translate(Path+'.Items');&lt;br /&gt;
 //Unterkomponenten übersetzen&lt;br /&gt;
 for i:=0 to Component.ComponentCount-1do&lt;br /&gt;
  Translate(Component.Components[i],Path);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure CreateTranslationTable(const Component:TComponent;const Filename:String);&lt;br /&gt;
var List:TStringlist;&lt;br /&gt;
   function Escape(const S:String):String;&lt;br /&gt;
   begin&lt;br /&gt;
    result:=S;&lt;br /&gt;
    result:=stringreplace(result,'\','\\',[rfReplaceAll]);&lt;br /&gt;
    result:=stringreplace(result,#13,'\r',[rfReplaceAll]);&lt;br /&gt;
    result:=stringreplace(result,#10,'\n',[rfReplaceAll]);&lt;br /&gt;
   end;&lt;br /&gt;
&lt;br /&gt;
   procedure AddComponent(const Component:TComponent;Path:String);&lt;br /&gt;
   var i:integer;&lt;br /&gt;
   begin&lt;br /&gt;
    //Pfad anpassen&lt;br /&gt;
    if Path=''&lt;br /&gt;
     then Path:=Component.Name&lt;br /&gt;
     else Path:=Path+'.'+Component.Name;&lt;br /&gt;
    //Eigenschaften speichern&lt;br /&gt;
        if (Component is TControl)and&lt;br /&gt;
       (TMyControl(Component).Caption&amp;lt;&amp;gt;'')then &lt;br /&gt;
       List.add(Path+'.Caption='+Escape(TMyControl(Component).Caption));&lt;br /&gt;
    if (Component is TControl)and&lt;br /&gt;
       (TControl(Component).Hint&amp;lt;&amp;gt;'')then &lt;br /&gt;
       List.add(Path+'.Hint='+Escape(TMyControl(Component).Hint));&lt;br /&gt;
    if (Component is TMenuItem)and&lt;br /&gt;
       (TMenuItem(Component).Caption&amp;lt;&amp;gt;'')and&lt;br /&gt;
       (TMenuItem(Component).Action=nil)then &lt;br /&gt;
       List.add(Path+'.Caption='+Escape(TMenuItem(Component).Caption));&lt;br /&gt;
    if (Component is TMenuItem)and&lt;br /&gt;
       (TMenuItem(Component).Hint&amp;lt;&amp;gt;'')and&lt;br /&gt;
       (TMenuItem(Component).Action=nil)then &lt;br /&gt;
       List.add(Path+'.Hint='+Escape(TMenuItem(Component).Hint));&lt;br /&gt;
    if (Component is TCustomAction)and&lt;br /&gt;
       (TCustomAction(Component).Caption&amp;lt;&amp;gt;'')then &lt;br /&gt;
       List.add(Path+'.Caption='+Escape(TCustomAction(Component).Caption));&lt;br /&gt;
    if (Component is TCustomAction)and&lt;br /&gt;
       (TCustomAction(Component).Hint&amp;lt;&amp;gt;'')then &lt;br /&gt;
       List.add(Path+'.Hint='+Escape(TCustomAction(Component).Hint));&lt;br /&gt;
    if (Component is TTabControl)and&lt;br /&gt;
       (TTabControl(Component).Tabs.text&amp;lt;&amp;gt;'')then &lt;br /&gt;
       List.add(Path+'.Tabs='+Escape(TTabControl(Component).Tabs.text));&lt;br /&gt;
    if (Component is TCustomComboBox)and&lt;br /&gt;
       (TCustomComboBox(Component).Items.text&amp;lt;&amp;gt;'')then &lt;br /&gt;
       List.add(Path+'.Items='+Escape(TCustomComboBox(Component).Items.text));&lt;br /&gt;
    if (Component is TCustomListBox)and&lt;br /&gt;
       (TCustomListBox(Component).Items.text&amp;lt;&amp;gt;'')then &lt;br /&gt;
       List.add(Path+'.Items='+Escape(TCustomListBox(Component).Items.text));&lt;br /&gt;
    //Unterkomponenten speichern&lt;br /&gt;
    for i:=0 to Component.ComponentCount-1do&lt;br /&gt;
     AddComponent(Component.Components[i],Path);&lt;br /&gt;
   end;&lt;br /&gt;
begin&lt;br /&gt;
 List:=TStringlist.create;&lt;br /&gt;
 try&lt;br /&gt;
  AddComponent(Component,'');&lt;br /&gt;
  List.SaveToFile(Filename);&lt;br /&gt;
 finally&lt;br /&gt;
  List.free;&lt;br /&gt;
 end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&amp;lt;/source&amp;gt;&lt;br /&gt;
{{Hinweis|Beide units können frei in beliebigen Projekten verwendet und angepasst werden.}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Technik oder Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=SDL_PumpEvents&amp;diff=25927</id>
		<title>SDL PumpEvents</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=SDL_PumpEvents&amp;diff=25927"/>
				<updated>2013-11-01T17:24:51Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Beschreibung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SDL_PumpEvents =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''SDL_PumpEvents''' - Befüllt die SDL Event-[[Queue]] mit Events, welche von den Eingabegeräten bezogen werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''SDL_PumpEvents'''()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
'''SDL_PumpEvents''' &amp;quot;pumpt&amp;quot; Events von den Eingabegeräten (Maus, Tastatur, etc.) in die SDL Eventqueue.&lt;br /&gt;
&lt;br /&gt;
Ohne einen Aufruf von '''SDL_PumpEvents''' würden nie Events in die Eventqueue gelegt werden. Oftmals werden Aufrufe von '''SDL_PumpEvents''' für den Programmierer versteckt durchgeführt. Dies geschieht z.B. durch impliziete Aufrufe in den Funktionen [[SDL_PollEvent]] und [[SDL_WaitEvent]]. Falls diese beiden Funktionen nicht benutzt werden, muss man direkt '''SDL_PumpEvents''' nutzen, damit die Eventqueue aktualisiert wird.&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
Man kann '''SDL_PumpEvents''' nur in dem Thread aufrufen, von dem aus der Videomodus gesetzt wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[SDL_PollEvent]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:SDL|PumpEvents]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Kollision1&amp;diff=25855</id>
		<title>Tutorial Kollision1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Kollision1&amp;diff=25855"/>
				<updated>2013-09-25T14:33:22Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Überall anstoßen - Kollisionen im 3D-Programm=&lt;br /&gt;
&lt;br /&gt;
==Wie es zu diesem Tutorial kam==&lt;br /&gt;
&lt;br /&gt;
Wahrscheinlich würde es dieses Tutorial nicht geben, wenn da nicht ''Tuxracer'' mit seiner miserablen Kollisionsbehandlung wäre. Irgendwie fühle ich mich diesem Programm verpflichtet, und irgendwie landete ich im Forum von ''Extreme Tuxracer'', einem Nachfolger der bekannten Open-Source-Version. Ein paar gut gemeinte Ratschläge von mir, und im Gegenzug war man der Meinung, ich könnte mich wohl um eine vernünftige Kollisionsbehandlung und ordentliche Objekte kümmern.&lt;br /&gt;
&lt;br /&gt;
Dermaßen unter Zugzwang gesetzt, kümmerte ich mich also und betrat damit völliges Neuland. Ich stellte ''Tuxracer'' in die Ecke, baute eine Testumgebung auf und befasste mich mit der Berechnung von Schnittpunkten und ähnlichen erquicklichen Dingen. Zugegeben, manchmal hakte es ganz schön, und die vielen Vektoren, die durch meinen Kopf schwirrten, verfolgten mich gelegentlich im Traum und durchbohrten mich wie spitze Pfeile. Irgendwie erreichte ich das gesteckte Ziel. Ob der Code demnächst mal in Tuxracer einfließen wird, kann ich zur Zeit noch nicht genau sagen. Ich weiß ja nicht, was die Jungs noch alles vorhaben, und Programmierer sind oft eigenwillige Menschen.&lt;br /&gt;
&lt;br /&gt;
Auf jeden Fall aber bietet sich nun die Gelegenheit, mich ein wenig für die Hilfe, die ich von der DGL-Community erfahren habe, zu revanchieren. So präsentiere ich hier mein erstes Tutorial, das aus zwei Teilen bestehen wird:&lt;br /&gt;
&lt;br /&gt;
#Der Teil, den du hier liest. Eine einfache und allgemeine Einführung: Was ist das überhaupt, so eine Kollision? Klar, dass sich dieser Teil an Leser richtet, die ganz neu einsteigen wollen. Für den praktischen Einstieg gibt es erste Beispiele zu Strahl-Ebenen-Schnitten und zu Kollisionen von Kugeln mit Ebenen bzw. kreisförmigen Hindernissen.&lt;br /&gt;
#Der zweite Teil wird sich mit Kollisionen von Kugeln an dreieckigen Primitiven (erweiterbar auf mehreckige Polygone) befassen. Das ist die vielleicht wichtigste Form der Kollision überhaupt. Ich werde hauptsächlich auf die geometrischen Dinge eingehen.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen für Teil 1==&lt;br /&gt;
&lt;br /&gt;
Was musst du als Leser mitbringen? Eigentlich nicht viel, ein paar OpenGL-Kenntnisse und das Wichtigste über Vektoren. Was unter einem Skalarprodukt zu verstehen ist oder wozu eine [[Normale]] gut ist, solltest du schon wissen; auf diese Dinge werde ich nicht näher eingehen. Sollte es hier und da noch etwas hapern, muss ich dich auf andere Tutorials verweisen. Was Kollisionen betrifft, sind keinerlei Voraussetzungen erforderlich. Wer schon etwas darüber weiß, wird wahrscheinlich mit diesem ersten Teil nicht allzu viel anfangen können.&lt;br /&gt;
&lt;br /&gt;
'''Ein paar Anmerkungen zu Physik-Engines:'''&lt;br /&gt;
&lt;br /&gt;
Wir müssen uns in diesem Zusammenhang auch die Frage stellen, ob es nicht besser ist, auf eine Physik-Engine wie ODE mit eingebauter Kollisionsbehandlung zurückzugreifen. Zweifellos bietet solch eine Engine manchen Vorteil, vor allem, wenn es um kompliziertere Fälle geht. Dennoch gibt es nach meiner Auffassung gute Gründe, sich selber mit der Programmierung von Kollisionen auseinanderzusetzen.&lt;br /&gt;
&lt;br /&gt;
*So eine Engine ist universell ausgelegt, das heißt, sie ist selten auf die Situation, mit der man es zu tun hat, zugeschnitten. Sie kann meistens mehr als man braucht, macht aber das, was man wirklich braucht, nicht unbedingt optiomal.&lt;br /&gt;
*Sich in eine solche Engine einzuarbeiten, geht nicht immer ruck-zuck. Ich weiß nicht, wie es anderen ergeht, aber ich tu mich mit solchen Libraries mitunter recht schwer. &lt;br /&gt;
*Selbst wenn man eine Engine benutzt, kann es nicht schaden, wenn man sie nicht blind einsetzt, sondern die Vorgänge etwas versteht. &lt;br /&gt;
&lt;br /&gt;
==Was ist eine Kollision?==&lt;br /&gt;
&lt;br /&gt;
Die virtuelle Welt wimmelt von Kollisionen, oft an Stellen, wo wir es auf den ersten Blick gar nicht vermuten. Eine Kollision tritt immer dann auf, wenn ein bewegtes Objekt ein anderes bewegtes oder feststehendes Objekt berührt. In den meisten Fällen wird das Programm darauf reagieren, wobei diese Reaktion sehr unterschiedlich sein kann. So ist z.B. denkbar, dass ein Objekt verschwindet, weil es &amp;quot;verschluckt&amp;quot;, &amp;quot;eingefangen&amp;quot; oder in irgendeiner Weise zerstört wird. Solche Vorgänge werden oft mit entsprechenden '''Kollisionsgeräuschen''' oder Animationen (z.B. Explosionsdarstellungen) verbunden. Es gibt ganz fiese Arten, eine Kollision sichtbar zu machen, aber da meine Gedanken frei sind, muss ich mir das nicht so genau vorstellen - geschweige denn am Bildschirm angucken.&lt;br /&gt;
&lt;br /&gt;
Mindestens ebenso häufig kommt es vor, dass bewegte Objekte durch die Kollision eine '''Bewegungsänderung''' erfahren, das heißt eine andere Richtung oder Geschwindigkeit erhalten bzw. sich um die eigenen Achsen drehen. Oft tritt alles gleichzeitig ein, und es ist einzusehen, dass es bei diesen Dingen die physikalische Zusammenhänge eine Rolle spielen. In besonderen Fällen kann sich eine Kollision sogar auf Teile des Objektes auswirken, das dadurch eine andere Gestalt oder &amp;quot;Körperhaltung&amp;quot; erhält. All dieses fasst man üblicherweise unter dem Begriff der '''Kollisionsverarbeitung''' ''(collision response)'' zusammen.&lt;br /&gt;
&lt;br /&gt;
Doch bevor auf eine Kollision reagiert wird, muss sie erst mal erkannt werden. Die '''Kollisionserkennung''' ''(collision detection)'' kann mitunter recht aufwendig sein, denn dazu müssen die Berührungspunkte berechnet werden - in erster Linie eine geometrische Aufgabenstellung. Aber da wir nicht die ersten sind, die sich mit solchen Dingen befassen,  gibt es eine Reihe von bewährten Funktionen, mit denen diese Aufgaben gelöst werden können. &lt;br /&gt;
&lt;br /&gt;
Bei der Kollisionserkennung kommt noch etwas hinzu: Meistens sind es sehr, sehr viele Dinge, Flächen usw., die möglicherweise im Wege stehen können. Dieses &amp;quot;möglicherweise&amp;quot; ist ernst zu nehmen. Würden wir grundsätzlich alle Objekte in Betracht ziehen, hätten wir es u.U. mit hunderttausenden von Kollisionsprüfungen in jedem Zeittakt zu tun, was verständlicherweise viel kostbare Zeit in Anspruch nimmt. Um den Vorgang zu optimieren, blenden wir von vornherein alle Objekte aus, die aufgrund ihrer Lage keine Kollision verursachen können. Da sind kluge Algorithmen gefragt, und wir setzen uns mit ''&amp;quot;bounding volumes&amp;quot;'' und ähnlichen Dingen auseinander. Später etwas mehr davon. &lt;br /&gt;
&lt;br /&gt;
==Kollisionen, etwas genauer betrachtet==&lt;br /&gt;
&lt;br /&gt;
Kollision ist nicht gleich Kollision. Es gibt viele verschiedene Situationen, die sich sowohl in der Methode der Kollisionserkennung als auch in der Kollisionsverarbeitung unterscheiden. Dazu einige Beispiele, zunächst so etwas wie den &amp;quot;Normalfall&amp;quot;.  Ein Junge spielt mit einem Gummiball, den er fortwährend gegen die Hauswand schießt. Wer kennt nicht dieses nervtötende Rumsen, das unvermeidliche Kollisionsgeräusch, das dabei entsteht? Nun springt der Ball in Nachbars Garten. Der freundliche Nachbar will zeigen, dass er auch noch was in den Beinen hat, und schießt den Ball zurück. Der Schuss gerät zu hoch, der Ball prallt auf das Hausdach ...&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Haus.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Die Abbildung zeigt, dass der Ball nicht mit dem Haus als Ganzes kollidiert, sondern mit den Flächen, die das Haus umschließen. Dabei spielt die Richtung der Fläche eine erhebliche Rolle.&lt;br /&gt;
&lt;br /&gt;
Wenn wir also ein Objekt auf mögliche Kollisionen überprüfen, dann muss das mit allen Flächen geschehen, die das Objekt bilden. Es leuchtet ein, dass dieser Vorgang mitunter sehr komplex werden kann, denn in den seltensten Fällen ist ein Objekt so einfach gestrickt wie das Haus. Dutzende von Flächen sind eher die Regel.&lt;br /&gt;
&lt;br /&gt;
Doch nicht immer haben wir den &amp;quot;Normalfall&amp;quot;. Es gibt Situationen, wo wir den Vorgang vereinfachen können. Das können wir an einer Kugel beobachten. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Kugel1.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Die abgebildete Kugel besteht aus 144 Flächen, die alle eine andere Ausrichtung haben. Natürlich könnten wir &amp;quot;normal&amp;quot; vorgehen und alle Flächen auf Kollision testen. Die Frage ist jedoch, wozu das gut sein soll, denn das Auge nimmt überhaupt nicht wahr, an welcher Fläche genau die Kollision stattfindet. Die Flächen in ihrer Gesamtheit werden vielmehr als Kugel wahrgenommen ... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Kugel2.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
... und dann können wir auch gleich hingehen und die Kollision so berechnen, als hätten wir eine ideale Kugel vor uns, mit einer einzigen, kugelförmigen Fläche. Das geht wesentlich einfacher und schneller, als wenn wir uns alle Teilflächen vornähmen. Bei der dargestellen Kugel handelt es sich übrigens um dieselbe wie im Bild davor, nur wurde sie diesmal mit aktiviertem Smooth-Shading unter Verwendung der Vertexnormalen gezeichnet. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nicht ganz unproblematisch ist die Kollision an Objekten, die stark vereinfacht gezeichnet werden. Wenn z.B. sehr viele Bäume zu zeichen sind, werden sie oft nur als Textur dargestellt, und zwar kreuzweise, damit der Eindruck eines 3-dimensionalen Objektes entsteht. Das Verfahren ist praktisch und schnell, hat aber deutliche Schwächen, wenn wir die Objekte aus der Nähe betrachten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Pseudo1.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
So ähnlich können Nadelbäume dargestellt werden, auf die Textur habe ich hier verzichtet. Als Kinder haben wir mit solchen Dingern aus Karton unseren Playmobil-Zoo begrünt, also auch in der konkreten Welt sind solche Gebilde praktisch. Eine Kollsion könnte zwar genau berechnet werden, wäre aber völlig unrealistisch, denn der Baum würde wie ein Fangkäfig wirken und die Kugel zurückweisen. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Pseudo2.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Wenn diese Art von Objekten überhaupt &amp;quot;kollisionsfähig&amp;quot; gemacht werden sollen, dann geht das nur, indem wir einen unsichtbaren, virtuellen Körper darum spannen, die Kollision daran vornehmen und hoffen, dass der Anwender nicht allzu kritisch ist. &lt;br /&gt;
&lt;br /&gt;
Bleiben wir noch etwas bei den Bäumen. Der ideale Baum ist so gestaltet, dass er einfache, kollisionsfähige Flächen aufweist, andererseits aber doch einen guten Gesamteindruck macht. Hier ein Screenshot aus dem Programm Tuxracer 1.1:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Baum1.jpg|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Der blaue Pfeil deutet an, dass hier der Baum ohne Kollision durchquert werden kann, während der rote Pfeil eine mögliche Kollision beschreibt. &lt;br /&gt;
&lt;br /&gt;
Die Situation sieht wieder ganz anders aus, wenn der Baum relativ klein gegenüber dem bewegten Objekt ist. Dann gibt es trotz Lücken kein Durchkommen, und auch der Aufprall auf einem &amp;quot;Blätterdach&amp;quot; lässt sich kaum noch vernünftig umsetzen. Ein Beispiel, das die Situation noch deutlicher macht:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Baum2.jpg|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Was soll denn nun geschehen, wenn ein Ball in dieses Blättergewirr fliegt? Kollisionen an den einzelnen Blättern? Das wäre nicht nur programmtechnisch unzumutbar, sondern zudem völlig unrealistisch. Ein einzelnes Blatt oder ein dünner Zweig stellt für den Ball keinen nennenswerten Widerstand dar, wohl aber die Baumkrone als Ganzes, mit dem Gewirr von Blättern und Zweigen. In solchen Fällen hilft uns die Realität weiter. Der Ball würde irgendwo in der Baumkrone zum Stoppen kommen und dann herunterfallen. Sowas wie eine weiche Kollision, die sich mit etwas Einfallsreichtum durchaus simulieren lässt.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es ja noch den Winter mit kahlen Baumkronen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Baum3.jpg|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Wahrscheinlich wird der Ball gelegentlich &amp;quot;hängen bleiben&amp;quot;, aber ebenso könnte er irgendwo aufprallen, seine Richtung ändern und mit verminderter Geschwindkeit weiter fliegen. Wo er aufprallt, ist kaum auszumachen und wahrzunehmen. Da könnten wir ein wenig mit dem Zufall arbeiten, die Richtung etwas ändern, die Geschwindigkeit herabsetzen usw.&lt;br /&gt;
&lt;br /&gt;
Nun ist die Sache mit den Bäumen ja klar; das sind Objekte, die aufs Gelände gesetzt werden und deshalb im Wege stehen können. Es gibt aber noch etwas anderes, was im Weg ist, nämlich der Weg selbst. Verrückt? Nicht, wenn wir daran denken, was ich weiter oben angemerkt habe, nämlich dass jede Berührung, die irgendwie den Lauf unseres Objektes beeinflusst, eine Kollision ist. Ohne eine Kollsision mit dem Weg oder - programmtechnisch ausgedrückt - mit den ''Polygonen'' würde unser Objekt wie ein Taucher unter der Erdoberfläche oder dem Fussboden verschwinden. Und wir Beobachter, die wir dem Objekt mit der Kamera folgen, gleich mit.&lt;br /&gt;
&lt;br /&gt;
Heißt das nun, dass wir im Grunde gar nicht zwischen dem natürlichen Untergrund und den aufgesetzten Objekten unterscheiden? Im Prinzip läuft es tatsächlich darauf hinaus, denn auch der Untergrund ist nichts anderes als ein ausgedehntes Objekt, bestehend aus vielen Dreiecken (ich setze mal voraus, dass wir nicht zu den Experten gehören, die die Landschaft aus Bezierflächen und ähnlichen Gebilden der höheren Mathematik bilden). Der Unterschied zwischen dem natürlichen Surface und den anderen Objekten besteht eigentlich nur darin, dass wir die Daten an verschiedenen Stellen im Programm speichern.&lt;br /&gt;
&lt;br /&gt;
Werfen wir noch einmal einen Blick in das Programm ''Tuxracer'':&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Tux.jpg|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Hier liegt der Pinguin vor einer Brücke, über die er hinübergleiten soll. Ohne Brücke würde er dem Terrain folgen und ins Tal rutschen. Notgedrungen müssten wir ihm folgen und auf der anderen Seite motivieren, wieder hinaufzuklettern. Mühsam, deshalb haben wir ihm ja eine Brücke gebaut, eine sehr nützliche Kollision, wie wir sehen. Und wenn wir außerdem erkennen, dass es egal ist, ob der antarktische Vogel über natürliches  Terrain oder eine künstliche Brücke gleitet, haben wir so ziemlich erfasst, wass eine Kollision im 3D-Programm ist.&lt;br /&gt;
&lt;br /&gt;
==Wir bauen einen Billardtisch ...==&lt;br /&gt;
&lt;br /&gt;
Ursprünglich wollte ich an dieser Stelle noch einen wichtigen Gedanken zur Kollision zum Besten geben, aber ich höre schon die Mahnung des Lektors: &amp;quot;Die Leute wollen nicht nur lesen, die wollen was ausprobieren.&amp;quot; Stimmt absolut, deshalb bringe ich zuerst einige Vorschläge zu Experimenten mit ganz einfachen Kollisionen, die aber trotz der Einfachheit - hoffe ich jedenfalls - etwas lehrreich sind. Den wichtigen Gedanken kann ich anschließend noch anbringen. &lt;br /&gt;
&lt;br /&gt;
Nun ja, wie die Überschrift schon sagt, geht es um die Kugel auf dem Billardtisch. Das ist eine fast klinisch reine Situation für Kollisionen nach dem Motto '''Einfallswinkel = Ausfallswinkel'''. Außerdem können wir die Sache zweidimensional untersuchen, obwohl die Szenerie dreidimensional gestaltet ist. &lt;br /&gt;
&lt;br /&gt;
Um mit der Billardkugel herumspielen und herumrechnen zu können, brauchen wir erst mal eine geeignete '''Testumgebung'''. Die will ich aber bewusst nicht in allen Einzelheiten beschreiben, etwas musst du als Leser selbst dazu beitragen. Du kannst ein Delphi-Template von DGL benutzen, oder du verwendest ein C-Programmgerüst mit SDL, ähnlich wie ich es auf meiner Webseite beschrieben habe. Letzteres bietet sich an, wenn du Linux bevorzugst (ich gehöre dazu). Du kannst natürlich auch eines der ersten Nehe-Tutorials nehmen, die für alle denkbaren Plattformen und Programmiersprachen zur Verfügung stehen. Die Szenerie, also der Billardtisch, ist recht schlicht aufgebaut und lässt sich schnell programmieren. Ich denke, auch diese Aufgabe kannst du  selber lösen. Am Schluss könnte es etwa so aussehen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Tisch.jpg|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Die Kugel wird am einfachsten mit '''gluSphere''' erzeugt. Nicht vergessen, in Beleuchtung und Material das Specular-Licht richtig einzustellen, sonst erscheint die Kugel wie eine tote Scheibe. Die Umgebung kann auch ohne Beleuchtung gezeichnet werden. Nun ja, und dann solltest du noch eine verstellbare '''Kamera''' einbauen. Es kann ganz nützlich sein, wenn der Blickwinkel geändert wird, besonders der Blick von oben zeigt einiges genauer.&lt;br /&gt;
&lt;br /&gt;
==... und lassen die Kugel rollen==&lt;br /&gt;
&lt;br /&gt;
Ich denke, das ist nun der richtige Zeitpunkt, ein wenig über die '''Bewegung von Objekten''' in 3D-Programmen nachzudenken. Grundsätzlich gibt es keine echte Bewegung, sondern es wird nur Bewegung vorgetäuscht, indem Objekte schnell genug an verschiedenen Stellen gezeichnet werden. Dieses &amp;quot;schnell genug&amp;quot; wird durch die Trägheit des Auges bestimmt; das Auge verschmilzt Abläufe, die schneller als etwa 20 mal pro Sekunde präsentiert werden, zu einem flüssig erscheinenden Vorgang. Ich will nicht weiter darauf eingehen, denn die Zusammenhänge dürften von Film und Fernsehen her bekannt sein. &lt;br /&gt;
&lt;br /&gt;
Jedenfalls ist es in 3D-Programmmen nicht anders. Dort spricht man von Frames und misst die Schnelligkeit der Bildfolge in fps ''(frames per second)''. In jedem Frame zeichnen wir das bewegte Objekt an einer anderen Stelle. Damit dürften wir bereits erkennen, dass es vor allem um die Berechnung der &amp;quot;richtigen&amp;quot; Stelle geht, wenn die Bewegung als flüssig und realistisch wahrgenommen werden soll.&lt;br /&gt;
&lt;br /&gt;
Dazu betrachten wir wieder unseren Billardtisch und nehmen an, dass die Kugel sich mit konstanter Geschwindigkeit in gleicher Richtung fortbewegen soll. Mögliche Kollisionen lassen wir noch außer acht.&lt;br /&gt;
&lt;br /&gt;
Um die Bewegung zu kontrollieren, müssen wir in jedem Frame zwei Dinge festhalten. Da ist zum einen die '''Position''', an dem die Kugel gezeichnet wurde, zum anderen die '''Geschwindigkeit''', die sie beim Erreichen dieser Position hat. Die Position ist, geometrisch gesehen, ein Punkt und wird durch seine drei Koordinaten x, y und z beschrieben. Auch die Geschwindigkeit benötigt diese 3 Komponenten, dann dabei handelt es sich um einen Vektor. In der realen Welt meinen wir mit Geschwindigkeit zwar meistens nur den skalaren Wert (z.B.80 km/h), doch in 3D-Programmen müssen wir die Geschwindigkeit voll erfassen, d.h. die Richtung mit einbeziehen. In diesem Zusammenhang noch eine kurze begriffliche Klärung: Wenn ich im folgenden nur den skalaren Anteil meine, werde ich zur Unterscheidung den Ausdruck '''Geschwindigkeitsbetrag''' verwenden. In Programmen, wo meisten englische Bezeichner verwendet werden, wird oft eine ähnliche Unterscheidung getroffen: Geht es um die Geschwindigkeit (mit Richtung), dann finden wir häufig den Ausdruck ''velocity''; geht es nur um den (skalaren) Betrag, dann wird der Begriff ''speed'' bevorzugt.&lt;br /&gt;
&lt;br /&gt;
Aber zurück zur Kugel. Wir befinden uns nun im nächsten Frame und müssen die Kugel an der neuen Position zeichnen. Nun sollte wohl eines klar sein: Wenn wir einen Punkt verschieben wollen, dann erreichen wir das, indem wir einen Vektor addieren. Nur kann ich nicht ohne weiteres eine Geschwindigkeit zu einer räumlichen Position addieren, das sind verschiedene Dinge. Aber es kommt ja die Zeit hinzu, die seit dem letzten Frame vergangen ist. Je mehr Zeit vergangen ist, desto größer ist der Bewegungsschritt. Folglich muss ich den Geschwindigkeitsvektor mit der Zeitspanne multiplizieren (evtl. noch zusätzlich skalieren), und nach dem Gesetz v * t = s wird aus dem Geschwindigkeitsvektor ein Wegvektor, den ich im folgenden '''Bewegungsvektor''' nenne. Den addieren wir zur alten Position und wissen, wo die Kugel nun gezeichnet werden muss. Die neue Position halten wir nun wieder für den nächsten Frame fest. Die Geschwindigkeit hatten wir ja als konstant vorausgesetzt und muss nicht aktualisiert werden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Beweg1.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Noch einmal kurz zur Zeitspanne zwischen zwei Frames. Zwar wird diese auf ein- und demselben Rechner meistens nicht allzusehr schwanken, aber es gibt immer wieder Dinge, die von Frame zu Frame unterschiedlich sind. Außerdem schlägt natürlich die Rechnergeschwindigkeit voll durch. Um Konstanz zu erzeugen und die Bewegung flüssig erscheinen zu lassen, sollten wir unbedingt die realen Zeitspannen berücksichtigen und nicht versuchen, die Geschwindigkeit durch irgendeine Konstante auf das richtige Maß zu quetschen. Zu dieser Problematik gibt es einen aufschlussreichen Artikel im DGL-Wiki: &amp;quot;[[Timebased Movement]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wir brauchen also zwei Vektor-Variablen, die wir nach dem Programmstart auf geeignete Anfangswerte setzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
TVector position;&lt;br /&gt;
TVector velocity;&lt;br /&gt;
&lt;br /&gt;
position.x = 0.0 // richtet sich nach dem Billardkasten&lt;br /&gt;
position.y = 0.5 // entspricht dem Radius der Kugel, bleibt konstant&lt;br /&gt;
position.z = 0.0 // richtet sich nach dem Billardkasten&lt;br /&gt;
velocity.x = 0.1 // etwas nach rechts bewegen&lt;br /&gt;
velocity.y = 0.0 // bleibt immer 0, zweidimensional&lt;br /&gt;
velocity.z = -0.5 // Vorwärtsbewegung&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Werte müssen wir natürlich anpassen. Vor dem Zeichnen der Kugel wird in jedem Frame die Position aktualisiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
position = AddVectors (position, ScaleVector (timestep, velocity));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir das Programm starten, rollt die Kugel, lässt sich aber von der Bande nicht aufhalten und verschwindet in der unendlichen Weite. Vielleicht wird sie irgendwann den Mars umkreisen oder in der Sonne verglühen, wobei wir dafür erst den passenden Code schreiben müssten.  ;)&lt;br /&gt;
&lt;br /&gt;
==Nun zur Kollision==&lt;br /&gt;
&lt;br /&gt;
... und damit zum Kern dieser einfachen Kollisionsexperimente. Die Kollisionserkennung besteht darin, dass wir feststellen, ob und wo die Kugel die Bande berührt, so dass wir sie dann im richtigen Winkel in den Innenraum zurückschicken können. Das wäre die Kollisionsverarbeitung. Dass jeder Aufprall und auch das Rollen auf dem grünen Tuch mit Energieverlust verbunden ist, übersehen wir mal großzügig. Das ist das Schöne an der virtuellen Welt, wir können sie nach unseren Vorstellungen gestalten und Naturgesetze einfach ignorieren.&lt;br /&gt;
&lt;br /&gt;
Ein Problem ist die '''Abmessung der Kugel'''. Wenn wir die Position angeben, dann meinen wir natürlich den Mittelpunkt, alles andere wäre unsinnig. Nun berührt der Mittelpunkt aber niemals die Bande, doch zum Glück können wir diesen Umstand recht einfach umgehen. Später, bei &amp;quot;richtigen&amp;quot; Kollisionen, werden sich daraus allerdings einige Probleme ergeben. Schauen wir zunächst die Abbildung an:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Coll1.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Links sehen wir die Kugel, wie sie gerade die Bande berührt. Wir erkennen auch, wie der Weg weitergehen soll. Die weiße Linie grenzt den Bereich ein, in dem der Mittelpunkt sich bewegen kann. Das heißt, wir brauchen den &amp;quot;bekugelbaren&amp;quot; Innenraum nur um den Radius der Kugel zu verkleinern. Immer, wenn z.B. die x-Position der Kugel sich auf der linken, weißen Linie befindet, berührt die Kugel die Bande; ist die x-Position kleiner als die Linie, taucht sie bereits in die Bande ein (in der virtuellen Welt geht das). Das wäre bei der unteren Kugel der Fall, nur dass es hier um die z-Position geht.&lt;br /&gt;
&lt;br /&gt;
Was ist zu tun? Genauer: Wo müssen wir die Kugel abfangen und ihr mitteilen, dass es beim nächsten Mal in anderer Richtung weitergeht? Wir können das erledigen, nachdem die Kugel die Grenzlinie überschritten hat, oder wir machen das vorher, indem wir den anstehenden Bewegungsschritt nur probehalber durchführen und ggfs. unterlassen? Beides ist nicht ganz sauber, und nur, wenn die Kugel sehr langsam rollt und die Bewegungsschritte entsprechend klein sind, fällt es nicht auf. Wenn wir genau sein wollen, müssen wir ein wenig weiter ausholen und den Berührungspunkt auf der weißen Linie finden. Nennen wir ihn '''Intersektionspunkt''', obwohl der eigentliche Intersektionspunkt direkt an der Bande liegt.&lt;br /&gt;
&lt;br /&gt;
Damit sind wir schon mitten drin im Kollisionszirkel. Es geht daraum, den Schnittpunkt eines Strahls mit einer Ebene zu berechnen ''(ray-plane intersection)''. Der Strahl ist nichts anderes als der Bewegungsvektor der Kugel, der von der Kugelposition wegzeigt. Und die Ebene müssen wir uns senkrecht auf der weißen Linie vorstellen, wie eine unsichtbare Wand. &lt;br /&gt;
&lt;br /&gt;
Die mathematischen Hintergründe wollen wir uns ersparen, hier die Funktion, die den Intersektionspunkt ausrechnet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
double PlaneIntersect (TVector pOrigin, TVector pNormal, TVector sPosition, TVector sDir)&lt;br /&gt;
{&lt;br /&gt;
	double d = -(DotProduct (pNormal, pOrigin));&lt;br /&gt;
	double num = DotProduct (pNormal, sPosition) + d;&lt;br /&gt;
	double denom = DotProduct (pNormal, sDir);&lt;br /&gt;
	return -(num / denom);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''pOrigin'' ist irgendein Punkt auf der Ebene und damit auf der weißen Hilfslinie. Es dürfte kein Problem sein, irgendeinen geeigneten Punkt zu finden. ''pNormal'' ist die Normale der Ebene, ein Vektor, den wir ganz einfach im Kopf ausrechnen können. Nehmen wir dazu die linke Begrenzungsebene. Aus der Sicht der Kugel zeigt die Normale nach rechts, also ist der Vektor (1, 0, 0). Ähnliches gilt für die anderen drei Ebenen.&lt;br /&gt;
&lt;br /&gt;
''sPosition'' ist der Positionspunkt der Kugel, und ''sDir'' ist der Bewegungsvektor. Das Ergebnis gibt den Abstand von sPosition zur Ebene an, und zwar als Faktor, mit dem wir den Bewegungsvektor multiplizieren müssen, wobei es egal ist, ob der Vektor normalisiert ist oder nicht. Ist das Ergebnis negativ oder größer als der Bewegungsschritt, wird die Bande nicht erreicht und wir bewegen die Kugel ganz normal vorwärts. Andernfalls verkürzen wir den Schritt, so dass die Kugel direkt an der Bande zu liegen kommt. &lt;br /&gt;
&lt;br /&gt;
Nun könnten wir auf den Gedanken kommen, es ganz perfekt machen zu wollen und im selben Frame einen zweiten Teilschritt in der neuen Richtung anzuschließen, so dass sich ein vollständiger Bewegungsschritt ergibt. Vom Bewegungsablauf her wäre das korrekt, doch es kommt ein anderer Aspekt hinzu. Wir würden nur selten die Kugel unmittelbar an der Bande sehen, und wir bekämen den Eindruck, als hätte sie Berührungsängste. Tatsächlich dürfen wir den optischen Eindruck nicht außer Acht lassen. Wenn die Kugel dagegen mal einen zu kurzen Bewegungsschritt macht, fällt es wegen der plötzlichen Richtungsänderung nicht auf. Du kannst es ja ausprobieren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Coll2.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
An der Bande lassen wir die Kugel zunächst liegen, versäumen aber nicht, die Richtung so zu verändern, dass der Aufprallwinkel gleich dem Rückprallwinkel ist. Auch das ist kein Problem, schauen wir wieder auf die linke Bande. Es ändert sich hier nur die x-Richtung, während die Fortbewegung in z-Richtung gleich bleibt. Also stülpen wir den x-Wert des Bewegungsvektors um:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
velocity.x = - velocity.x;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit den anderen Banden verfahren wir analog. Es ist aber wichtig, dass wir immer '''alle vier Banden''' überprüfen. Es kann nämlich sein, dass die Kugel auf eine Ecke zusteuert und gleichzeitig mit zwei Banden in Konflikt gerät. Dann müssen in ein- und demselben Frame zwei Richtungen umgedreht werden. Wenn wir feststellen, dass die Kugel gelegentlich außerhalb des Käfigs hin- und herzittert und nicht wieder hinein will, haben wir diesen Punkt nicht beachtet.&lt;br /&gt;
&lt;br /&gt;
==Geht noch mehr?==&lt;br /&gt;
&lt;br /&gt;
Oh ja, wir können noch wesentlich mehr mit dem Billardtisch anfangen, aber dazu will ich nur einige Tipps geben. Wenn das Bisherige verstanden ist, dürfte die Umsetzung keine großen Probleme mehr machen.&lt;br /&gt;
&lt;br /&gt;
Eigentlich war die Bewegung der Kugel bis jetzt langweilig, immer dieselben Bahnen und Winkel, kreuz und quer. Wir können es zwar einrichten, dass wir per Tastendruck die Richtung der Kugel verstellen, aber so richtig interessant ist auch das nicht. Besser ist es, ein Hindernis einzubauen, das nicht so berechenbar ist. Dazu nehmen wir einen Zylinder oder eine zweite Kugel, die wir fest irgendwo im Innern des Billardtisches positionieren. Mit diesem runden Gebilde soll die bewegliche Kugel nun kollidieren - wenn sie zufällig getroffen wird. Schauen wir uns also an, wie das gemeint ist: &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Coll3.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
In der Abbildung steckt alles, was wir zur Lösung des Problems brauchen. Wieder haben wir die weiße Linie, die uns erlaubt, mit dem Mittelpunkt der Kugel zu rechnen, und natürlich ist der äußere Kreis um den Radius der Kugel größer als der eigentliche Kollisionskörper. Wir sehen die gelb eingezeichnete Tangente, an der wir die Reflexion vornehmen. Doch vorher müssen wir wieder den Intersektionspunkt haben, worauf der blaue Pfeil zeigt. Hier nun die Funktion, die uns den Punkt liefert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
double CircleIntersect (TVector center, double radius, &lt;br /&gt;
					   TVector sPosition, TVector sDir)&lt;br /&gt;
{&lt;br /&gt;
	center.y = sPosition.y = sDir.y = 0;&lt;br /&gt;
	TVector q = SubtractVectors (center, sPosition);&lt;br /&gt;
	double c = VectorLength (q);&lt;br /&gt;
	double v = DotProduct (q, sDir);&lt;br /&gt;
	double d = radius * radius - (c * c - v * v);&lt;br /&gt;
	&lt;br /&gt;
	if (d &amp;lt; 0.0) return -1;&lt;br /&gt;
	return v - sqrt (d);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten beiden Parameter beschreiben den Kollisionskreis (oder Zylinder) und dürften selbsterklärend sein; die beiden anderen Parameter sind dieselben wie bei der Funktion weiter oben. Auch das Ergebnis wird in gleicher Weise verwendet. Halt, eines ist zu beachten: '''sDir muss nun auf jeden Fall normalisiert sein!'''&lt;br /&gt;
&lt;br /&gt;
Schauen wir genauer hin, dann entdecken wir darin eine quadratische Gleichung. Nun hat eine quadratische Gleichung mitunter zwei Lösungen, und das ist auch erklärlich, denn der Strahl schneidet den Kreis meistens an zwei Stellen. Die Funktion liefert aber nur den Eintrittspunkt des Strahls zurück, denn der hintere Schnittpunkt ist uninteressant. Wird der Kreis nicht geschnitten, ist das Ergebnis -1. Übrigens ist die Funktion eigentlich für eine Kugel ausgelegt. Sie kann aber auch zweidimensional für einen Kreis oder Zylinder benutzt werden, indem die y-Komponenten auf 0 gesetzt werden (1. Zeile).&lt;br /&gt;
&lt;br /&gt;
Der '''Reflexionswinkel''' lässt sich leider nicht mehr ganz so einfach berechnen wie bei der Kollision an der Bande. Die Tangente ist ja nicht nach x oder z ausgerichtet, sondern kann irgendwie liegen. Aber auch hierfür gibt es eine praktische Funktion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
TVector ReflectVector (TVector a, TVector norm) &lt;br /&gt;
{&lt;br /&gt;
	TVector res;&lt;br /&gt;
//	NormalizeVector (&amp;amp;a);&lt;br /&gt;
//	NormalizeVector (&amp;amp;norm);&lt;br /&gt;
	double dotprod = DotProduct (a, norm);&lt;br /&gt;
	res.x = a.x - 2 * norm.x * dotprod;&lt;br /&gt;
	res.y = a.y - 2 * norm.y * dotprod;&lt;br /&gt;
	res.z = a.z - 2 * norm.z * dotprod;&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''a'' ist der normalisierte Bewegungsvektor, der auf den Intersektionspunkt zeigt, und ''norm'' ist die Normale der Tangente bzw. der Ebene, die sie repräsentiert. Diese Normale lässt sich schnell aus dem Mittelpunkt des Kreises und dem Intersektionspunkt ableiten (blauer Pfeil). Das Ergebnis ist die Richtung des neuen Bewegungsvektors, der dann noch auf die ursprüngliche Länge gebracht werden muss. &lt;br /&gt;
&lt;br /&gt;
Für den Fall, dass einer der beiden Parameter in nicht-normalisierter Form übergeben werden soll, lässt sich das in der Funktion nachholen. Dazu dienen die beiden auskommentierten Zeilen. &lt;br /&gt;
&lt;br /&gt;
Wer Spaß am Billardtisch gefunden hat, kann noch eine ganze Menge damit machen. Mit mehreren runden Hindernissen ließe sich z.B. so etwas wie ein Flipperautomat aufbauen. Bei Berührung prallt die Kugel nicht nur ab, sondern erhält einen Geschwindigkeitsimpuls. Wer allerdings vorhat, ein richtiges Billardspiel zu bauen, mit mehreren bewegten Kugeln, muss wesentlich tiefer in die mathematische Kiste greifen. Die andere Kugel hält ja nicht bis zum nächsten Frame still, sondern der Zusammenprall wird in der Regel &amp;quot;zwischen den Zeiten&amp;quot; erfolgen. Diese Zeitpunkte und Kollisionsstellen müssen dann berechnet werden, was häufig auf Verfahren wie die ODE-Solver (von ''ordinary differential equations'') hinausläuft. Nicht zu verwechseln mit der eingangs erwähnten Physik-Engine ODE ''(open dynamics engine)''. Gerade bei Aufgabenstellungen wie der Billardtisch dürfte auch das letztgenannte ODE eine gute Hilfe sein.&lt;br /&gt;
&lt;br /&gt;
Wer sich für einfache Zusammenstöße zweier Kugeln interessiert, kann ja mal im Netz unter den Stichwörtern &amp;quot;Stoßgesetze&amp;quot; und &amp;quot;Impulsgesetze&amp;quot; nach Informationen suchen. Eine gute Einstiegsseite ist die von Wikipedia, auf der u.a der Zusammenprall zweier Kugeln in einer Animation veranschaulicht wird:&lt;br /&gt;
&lt;br /&gt;
http://de.wikipedia.org/wiki/Sto%C3%9F_(Physik)&lt;br /&gt;
&lt;br /&gt;
Und, nicht zu vergessen, auch das gute, alte Physikbuch kann hilfreich sein - sofern ihr nach Beendigung der Schulzeit nicht alle Bücher verbrannt habt  ;-)&lt;br /&gt;
&lt;br /&gt;
==Nun doch noch der wichtige Gedanke==&lt;br /&gt;
&lt;br /&gt;
Auf einen Punkt möchte ich noch hinweisen, weil er für eine saubere Kollisionsberechnung von großer Bedeutung ist. Wir haben bei den Versuchen rund um den Billardtisch den Berührungspunkt der Kugel mit der Bande (Intersektionspunkt) quasi aus der Ferne berechnet. Wenn der Punkt so weit weg liegt, dass keine Kollision stattfinden kann, gut, dann lassen wir der Kugel freien Lauf. Voraussetzung für diese sichere Methode ist, dass wir wissen, welcher Punkt der Kugel das Hindernis berührt; dann können wir die Bahn dieses Punktes als Strahl betrachten. Im Falle des Billardtisches gelang es uns deshalb, weil wir die unsichtbaren Linien oder Ebenen definieren konnten, wo der Mittelpunkt der Kugel anstößt. Das funktioniert aber nur in ganz bestimmten Fällen, nämlich bei kreisrunden oder unbegrenzt geraden Hindernissen. Ein viereckiges Hindernis könnten wir mit der Methode nicht auf den Billardtisch stellen, wie das folgende Bild zeigt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Kollision1_Coll4.png|center|framed]]&lt;br /&gt;
&lt;br /&gt;
Die Kugel würde an der Kollisionslinie zurückprallen, obwohl sie das Hindernis nur streift und allenfalls ein wenig abgelenkt wird.&lt;br /&gt;
&lt;br /&gt;
Bei unseren Versuchen lernten wir zwei Intersektions-Funktionen kennen. Wenn wir uns im Internet umschauen, dann finden wir eine Vielzahl von solchen Funktionen, es gibt sie für alle möglichen Linien, Flächen und Körper. Doch die weitaus meisten sind für Kollisionsberechnungen nur bedingt brauchbar, denn ihre Ergebnisse stellen uns vor vollendete Tatsachen. Sie geben nämlich an, ob und wo die Objekte sich bereits schneiden, nicht aber, an welchem Punkt genau die wichtige Erstberührung stattfindet. &lt;br /&gt;
&lt;br /&gt;
Manchmal reicht aber die Feststellung, '''ob''' sich zwei Objekte schneiden, z.B. bei der Kollisionserkennung mit Hüllkörpern ''(bounding volumes)''. Dabei geht es nur darum, in einem ersten Schritt zu ermitteln, ob sich zwei Objekte nahe genug gekommen sind, um eine genauere Kollisionserkennung anzuschließen. Besonders einfach und schnell geht diese &amp;quot;Vorerkennung&amp;quot; mit Kugeln oder Kreisen. Die schneiden sich nämlich, wenn der Abstand der Mittelpunkte kleiner als die Summe der Radien ist, was relativ einfach nachzuvollziehen ist. Allerdings heißt es ein wenig aufpassen, denn bei größeren Geschwindigkeiten kann es passieren, dass ein Objekt übersprungen wird und die Kollisionserkennung fehlschlägt. Genaueres zu diesen Methoden werde ich vielleicht in einem Folge-Tutorial sagen. &lt;br /&gt;
&lt;br /&gt;
So, das war's für dieses Mal. Es ging in diesem Tutorial noch nicht um komplizierte Techniken zur Kollisionsberechnung, sondern es sollte vor allem ein Gespür für Kollisionen und die zu erwartenden Probleme entstehen. Sollte das rübergekommen sein, hat das Tutorial seinen Zweck erreicht. Im nächsten Tutorial geht es dann schon mehr zur Sache, dann werde ich die vielleicht wichtigste Form der Kollision beschreiben, nämlich die an dreieckigen Polygonen und vor allem deren Kanten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Viel Spaß beim Experimentieren mit Kollisionen. &lt;br /&gt;
&lt;br /&gt;
'''Reinhard'''&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial Separating Axis Theorem]]|[[Tutorial Kollision2]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Kollision1]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=25854</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=25854"/>
				<updated>2013-09-25T14:32:58Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch die Normale der Kollision oder '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Rotation ==&lt;br /&gt;
&lt;br /&gt;
Um Polygone behandeln zu können, die rotieren, sind lediglich einige Änderungen an der Polygonklasse erforderlich.&lt;br /&gt;
Hierbei gibt es mehrere Optionen, zum einen können wir unsere Vertices in jedem Schritt drehen und speichern, allerdings kann dies auf Dauer zu Ungenauigkeiten führen. Eine zweite Möglichkeit wäre, bei jedem Zugriff auf die Vertices, einen gedrehten Vektor auszugeben. Dies erhöht zwar&lt;br /&gt;
die benötigte Rechenleistung, ist aber deutlich genauer. Das Seperation Axis Theorem kann dann mit den gedrehten Vertices weiter verfahren.&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_exe|text=Windows-Binary}}&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Kreis_exe|text=Windows-Binary}}&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Kreis_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Trennung_exe|text=Windows-Binary}}&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Trennung_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 4 - Rotation ===&lt;br /&gt;
&lt;br /&gt;
Die Rotation des Polygons erfolgt beim Auslesen der Vertex Koordinaten mittels einer Rotationsmatrix:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  acos, asin: extended;&lt;br /&gt;
begin&lt;br /&gt;
  sincos(degtorad(fangle),asin,acos);&lt;br /&gt;
  result.x := fvertices[n].x * acos + fvertices[n].y * -asin;&lt;br /&gt;
  result.y := fvertices[n].x * asin + fvertices[n].y * acos;&lt;br /&gt;
end;   &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es den Code für die Behandlung von Rotation:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Rotation_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.metanetsoftware.com/technique/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spaß gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=25853</id>
		<title>DGL Projekte</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=25853"/>
				<updated>2013-09-25T14:32:42Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
Willkommen in der '''[[DelphiGL|DGL]] Projekte Ecke'''!&lt;br /&gt;
[[Bild:ProjekteEcke.png|center]]&lt;br /&gt;
Auf dieser Seite findet ihr Projekte von '''Mitgliedern von [http://DelphiGL.com DelphiGL.com]''',  welche als '''&amp;quot;für die Benutzung freigegeben&amp;quot;''' gewertet wurden.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wichtiges zuerst==&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|'''Rechtliches:''' Die Software wurde von Mitgliedern von DelphiGL.com in ihrer Freizeit geschrieben. Es kann deshalb für die angebotene Software keinerlei Garantie gegeben werden. Unsere Mitglieder geben allerdings ihr Bestes damit die hier angebotene Software euch Spaß ohne Reue beschehrt. Aus rechtlichen Gründen gilt wie bei allen Angeboten von DelphiGL.com: Download und Nutzung auf eigene Gefahr.}}&lt;br /&gt;
&lt;br /&gt;
===Eigene Projekte vorstellen===&lt;br /&gt;
Falls ihr selbst Mitglied von DelphiGL.com seid und ein Projekt habt welches ihr als &amp;quot;benutzbar&amp;quot; bezeichnet (und idealerweise schon bei DelphiGL.com in der Projektesektion vorgestellt habt), dann könnt ihr es hier veröffentlichen.&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Bitte sortiert eure Spiele '''alphabetisch''' in die Kategorien ein.}}&lt;br /&gt;
&lt;br /&gt;
===Auszeichnungen===&lt;br /&gt;
Einige Projekte wurden mit einem oder mehreren [[DGL_Award]]s ausgezeichnet. Mit dem DGL Award ehrt die DelphiGL Community vorbildliche Projekte und Engagement in der Community.&lt;br /&gt;
&lt;br /&gt;
==Spiele==&lt;br /&gt;
Viele, um nicht zu sagen die meisten, DGL-Mitglieder widmen sich dem Thema Spiele. Was dabei an respektablen Ergebnissen entstanden ist könnt ihr in dieser Rubrik sehen.&lt;br /&gt;
&lt;br /&gt;
===3D Shooter und Labyrinth Spiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Action===&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_asteroids.jpg|framed|center|Link: '''[[Projekt_Asteroids|Asteroids]]''']]&lt;br /&gt;
&lt;br /&gt;
|Asteroids ist ein Remake des alten Klassikers &amp;quot;Comet&amp;quot;. Ziel des Spiels ist es so viel Asteroiden wie möglich zu zerstören um dadurch möglichst viele Punkte zusammeln, ohne dabei von den herum fliegenden Trümmern getroffen zu werden. &lt;br /&gt;
&lt;br /&gt;
An einem Spiel können bis zu 4 Spieler gleichzeitig teilnehmen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Magellan|Magellan]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_napalmbomber.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=90 Napalmbomber3D Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|NapalmBomber3D ist wie der Titel schon vermuten lässt ein 3D-Klon des bekannten Bombermanspielprinzips.Dieses hochbrisante und fesselnde Spiel besticht durch seine tolle Grafik die natürlich mittels OpenGL realisiert wurde.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zum Spiel gibt es natürlich auch noch einen Karteneditor mit dem sich in Windeseile eigenen Maps erstellen lassen.&lt;br /&gt;
&lt;br /&gt;
Neben inzwischen über 50.000 Downloads (im Schnitt sind es immernoch &amp;gt; 400 pro Monat) und diversen sehr guten Reviews hat es das Spiel sogar auf die PC-Action Ausgabe 07/2004 geschafft.&lt;br /&gt;
&lt;br /&gt;
''([[Tutorial#Spieletutorials_und_Softwareentwicklung|Hier]] findet ihr 2 Tutorials mit denen ihr dieses tolle Spielchen nachbauen könnt.)''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:PE2.jpg|thumb|center|168px|Link: '''[http://ziz.delphigl.com/pereff_download.php Perniciei Effector]''']]&lt;br /&gt;
|Ein typischer Weltraum Shooter mit 2D Steuerung aber 3D Grafik. Ziel des Spiels ist es in der Highscore möglichst hoch zu klettern. Dies erreicht man durch die passende Auswahl des Raumschiffes zu beginn und die vielen Items, die die Gegner verlieren.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Ziz|Ziz]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Brett-, Denk- und Kartenspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Balance.jpg|thumb|center|168px|Link: '''[[Projekt_Balance|Balance]]''']]&lt;br /&gt;
|Durch geschicktes erhöhen von Ladungen werden Kettenreaktionen ausgelöst mithilfe derer man das gesammte Spielfeld erobert. Das Spiel ist Mehrsprachig (Deutsch/Englisch) und enthält einen Einzelspieler und zwei Multiplayer-Modi (HotSeat u. LAN).&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Flash|Kevin Fleischer aka Flash]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Projekt_Hex_Change_Screenshot.jpg|thumb|center|168px|Link: '''[[Projekt_Hex-Change|Hex-Change]]''']]&lt;br /&gt;
|2 Spieler konkurrieren um die Felder auf einer Hexagon Fläche. Das Spiel enthält einen Einzelspieler- (gegen KI) und einen &amp;quot;Hot-Seat&amp;quot;-Mehrspielermodus.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:H.A.S.E.|H.A.S.E.]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Reaktions- und Geschicklichkeitsspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_beanmachine.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=86 Bean Machine Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|&amp;quot;Bean Machine&amp;quot; basiert auf dem Sega MegaDrive-Klassiker &amp;quot;Dr.Robotnik's Mean Bean Machine&amp;quot; (ausserhalb Europas auch als &amp;quot;Puyo Puyo&amp;quot; bekannt) und spielt sich somit ähnlich wie Tetris.&lt;br /&gt;
Auch dieses Klassikerremake spielt sich fast genauso wie die Vorlage, allerdings gibt es dank OpenGL recht aufwendige Grafiken, natürlich gewohnt komplett in 3D.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_confusingball.jpg|framed|center|Link: '''[[Projekt_ConfusingBall|Confusing Ball]]''']]&lt;br /&gt;
&lt;br /&gt;
|In &amp;quot;Confusing Ball&amp;quot; steuert man einen Ball durch ein 3D Labyrinth, in dem die Gesetze der Physik neu definiert werden müssen. Um ins Ziel eines Levels zu gelangen benötigt man einen gewissen Orientierungssinn und ein gutes räumliches Vorstellungsvermögen.&lt;br /&gt;
Nebenher muss man ja auch noch die Münzen einsammeln, und den Bomben aus dem Weg gehen. Frei verschiebbare Steine erhöhen den Schwierigkeitsgrad.  &lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:MatReno|MatReno]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Heiliger Damm.jpg|thumb|center|168px|Link: '''[[Projekt Heiliger_Damm|Heiliger Damm]]''']]&lt;br /&gt;
&lt;br /&gt;
|&amp;quot;Heiliger Damm&amp;quot; ist ein Geschicklichkeitsspiel passend zum G8-Treffen 2007 in Heiligendamm. Der Spieler übernimmt die Aufgabe, den &amp;quot;heiligen Damm&amp;quot; (eine Oase in der Wüste) vor den Globalisierungsgegner zu schützen. Dies erreicht er, indem er mit der Maus Linien (Zäune) zieht.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:GTA-Place|Fabian Gärtner / GTA-Place]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Simulationen===&lt;br /&gt;
====Wirtschaftssimulationen/Manager====&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:PBM2_Kdr.jpg|thumb|center|168px|Link: '''[[Projekt_PBM2|PBall Manager 2]]''']]&lt;br /&gt;
&lt;br /&gt;
|Der PBall Manager 2 ist ein Sportmanager in welchem man in die Rolle des Trainers/Managers eines von 96 PBall Teams aus ganz Europa schlüpft. PBall selbst ist eine fiktive Sportart welche ähnlich Fußball ist.&lt;br /&gt;
&lt;br /&gt;
Im Spiel hat man die Kontrolle über alle Abläufe: Von der Aufstellung über Spielerkäufe bis hin zum Stadionausbau liegt alles in der Hand des Spielers. Doch auch die eigene Karriere kann voran getrieben werden indem man zu anderen Clubs wechselt.&lt;br /&gt;
&lt;br /&gt;
Das Ziel aller PBaller ist der Liga-Meister-Pokal indem die besten Clubs der 4 Europäischen Ligen um den Titel spielen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Flash|Kevin Fleischer alias Flash]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Flugsimulationen====&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Rennsimulationen====&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strategie===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:planeto7.jpg|thumb|center|168px|Link: '''[http://nilsbeckmann.de/ Planeto]''']]&lt;br /&gt;
&lt;br /&gt;
|Planeto ist ein rundenbasiertes Science-Fiction Strategiespiel. Du landest auf einem unbekannten Planeten. Deine Aufgabe ist es, diesen zu erkunden, Rohstoffe zu sichern und die militärische Vorherrschaft zu behaupten. Spieler können gegen Computerspieler antreten oder untereinander simultan übers Netzwerk und Internet. Zur Auswahl stehen mehr als 400 Einheiten, Forschungen und Aufwertungen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Nils Beckmann|Nils Beckmann]]&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:projektw_wiki_projektecke.jpg|thumb|center|168px|Link: '''[http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;]''']]&lt;br /&gt;
&lt;br /&gt;
|Projekt &amp;quot;W&amp;quot; ist ein runden-basierendes Strategiespiel, dessen Ziel die Erlangung der Weltherrschaft ist. Der Spieler kann sich für eine der fünf neuen großen Nationen entscheiden, und muss diese dann zum Sieg über alle anderen Nationen führen.&lt;br /&gt;
&lt;br /&gt;
Dazu muss man seine Regionen verwalten, dort Gebäude bauen und auf wichtige Faktoren achten. Man baut zudem militärische Einheiten und gliedert diese in Divisionen um damit das eigene Territorium zu verteidigen, bzw. gegnerische Regionen einzunehmen. Zusätzlich kann man Technologien erforschen, die u.A. neue Gebäude und Militäreinheiten freischalten. Auch Spionage und Sabotage spielen eine wichtige Rolle, so kann man z.B. mit Hilfe eines eingeschleusten Spions an wichtige Informationen gelangen oder die Stromversorgung einer Region lahmlegen.&lt;br /&gt;
&lt;br /&gt;
Neben dem Einzelspielermodus, in dem man gegen die KI bestehen muss, gibt es auch einen Hotseatmodus, bei dem mehrere Spieler an einem Rechner gegeneinander antreten können. Präsentiert wirds wie gewohnt in schicker 3D-Grafik, und auf passender Hardware wird das Ganze noch mit Shadern garniert.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Effekte==&lt;br /&gt;
Für den optischen Anspruch eines Spiels haben Spezialeffekte große Bedeutung. Was beim einfachen Feuer beim Abschießen einer virtuellen Kugel anfängt, kann sich über plastischen Nebel bis zu imposanten, realistischen Blitzen ziehen.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Pic6.jpg|thumb|center|168px|Link: '''[http://sourceforge.net/projects/fireblade/ FireBlade]''']]&lt;br /&gt;
&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Project_OTY08.png|center&lt;br /&gt;
rect 0 0 100 40 [[DGL_Award#Best_Project_Award]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|FireBlade ist ein flexibles und leistungsstarkes Partikelsystem auf OpenGL-Basis. Sie ist sehr effizient im Bezug auf Tiefensortierung, Speichermanagement, Ansprechbarkeit und Erweiterbarkeit, und lässt sich durch die Art und Weise, wie Effekte beschrieben werden, sehr gut vor allem in größere Projekte einbringen. Dabei eignet sie sich sowohl für 2D als auch für 3D-Anwendungen. Highlights sind zum Beispiel die integrierte, problemlos erweiterbare Kollisionsabfrage, ein breites, ebenfalls erweiterbares Emitter-Set und ein einfacher, aber sehr effizienter Manager, der die Performance gerade für viele Effekte enorm steigern kann. Alle Eigenschaften, selbst die Textur- und Raumkoordinaten der einzelnen Billboard-Vertices sind manipulierbar.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Kyro|Sebastian Wagner alias Kyro]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Bibliotheken==&lt;br /&gt;
Diese Rubrik enthält Bibliotheken, die die Grafikprogrammierung vereinfachen und dem Spiele-/Anwendungsentwickler helfend unter die Arme greifen.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:AndorraLogo.png|thumb|center|168px|Link: '''[http://andorra.sourceforge.net/ Andorra 2D]''']]&lt;br /&gt;
&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Useful_OTY08.png|center&lt;br /&gt;
rect 0 0 100 40 [[DGL_Award#Most_Useful_Project_Award]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|Andorra 2D ist eine flexible Lösung um 2D-Spiele oder Anwendungen zu entwickeln. Durch den durchdachten Aufbau des Engine-Kerns ist Andorra 2D komplett von der Grafikschnittstelle und dem Betriebssystem getrennt. Eine Anbindung an OpenGL und Direct3D, sowie Unterstützung für Windows und Linux 32/64 Bit sind gegeben. Andorra 2D ist einfach zu verwenden und erlaubt es auch Einsteigern schnell erste Ergebnisse auf den Bildschirm auszugeben. Andererseits wendet es sich mit Features wie Shadern auch an fortgeschrittene Benutzer.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Igel457|Andreas Stöckel alias Igel457]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:AudorraLogo.png|thumb|center|168px|Link: '''[http://audorra.sourceforge.net/ Audorra]''']]&lt;br /&gt;
|Audorra ist eine Bibliothek zur Wiedergabe von 3D-Positionalem Audio und vor allem für den Einsatz in Spielen gedacht. Durch den modularen Aufbau kann es - die richtigen Audio-Backends (&amp;quot;Driver&amp;quot;) und Decoder vorrausgesetzt - auf fast jeder Plattform eingesetzt werden. Der verwendete 3D-Audio-Softwarerenderer garantiert gleiche Ergbnisse und unterstützt Effekte wie Phasenverschiebung und Dopplereffekt. Mehr über das Projekt gibt es auch im [http://www.delphigl.com/forum/viewtopic.php?f=13&amp;amp;t=8819 Forumsthread] zu erfahren.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Igel457|Andreas Stöckel alias Igel457]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Tools==&lt;br /&gt;
Diese Rubrik enthält Werkzeuge, die man benutzt um Inhalte zu erstellen.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Beei.png|thumb|center|168px|Link: '''[http://projects.blender.org/projects/beei/ Blender External Engine Interface]''']]&lt;br /&gt;
|BEEI steht für Blender External Engine Interface und dient als Schnittstelle für externe Renderer und Gameengines.&lt;br /&gt;
Der externe Renderer oder Gameengine muss in Form einer .dll oder .so Datei vorliegen und die von der Schnittstelle erwarteten Funktionen bieten. Das Plugin wird dann von Blender geladen und befindet sich dann im Speicher von Blender.&lt;br /&gt;
Nun kann man z.B. mit OpenGL Renderbefehle ausführen und diese werden dann im Space von Blender dargestellt.&lt;br /&gt;
Man hat zugriff auf die Blender Daten und kann sie lesen oder schreiben, wobei das Lesen die sichere Art ist und zum schreiben Python und BEEI Boardmittel verwendet werden sollten. Das Testplugin ist ein frühes Framework von Karmarama.&lt;br /&gt;
Es zeigt die Blenderdaten wie der interne Blenderrenderer mit der ausnahme, dass ein Entity mit dem Namen Glow als Pfeil dargestellt wird. BEEI bietet neben der schnittstelle noch zugriff auf die Blender UI elemente, um eigene Toolfenster zu erstellen. Der tiefere Sinn liegt im WYSIWYG und erlaubt ein wesentlich leichteres erstellen von Content aller Art.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|Thomas Kunze&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:xenorate.png|thumb|center|160px|Link: '''[http://www.xenorate.com Xenorate Media Player]''']]&lt;br /&gt;
|Xenorate Media player ist ein konfortabler multimedia player welches sehr viele medienformate beherscht.&lt;br /&gt;
Es unterstützt DVD, VCD/SVCD, Video/Audio Dateien und kann Livestreams abspielen + aufnehmen.&lt;br /&gt;
&lt;br /&gt;
Mit einem integriertem audio system (basierend auf BASS) kann es einige audio formate &amp;quot;out-of-the-box&amp;quot; abspielen:&lt;br /&gt;
MP3, OGG, FLAC, MPC, M4A, AAC, AC3, WAV, ...&lt;br /&gt;
&lt;br /&gt;
Xenorate enthält ein mächtiges video system welches directshow nutzt um dvd und video content abzuspielen.&lt;br /&gt;
Es unterstützt interne und externe untertitel sowie mehrere ton spuren. &lt;br /&gt;
Um jede mögliche filter kombination abzuspielen (DirectShow Graph) hat Xenorate eine DirectShow Script Engine (basierend auf BeroScript).&lt;br /&gt;
&lt;br /&gt;
Es gibt außerdem noch ein eigenes Codec Pack welches alle notwendingen codecs enthält die man heutzutage benötigt.&lt;br /&gt;
&lt;br /&gt;
Entwickelt wurde das Projekt 1999 mit Borland Delphi 2-7 und hat mittlerweile 250.000 zeilen code erreicht.&lt;br /&gt;
Komplett auf Userwünschen abgestimmt enthält es eine sehr grosse Palette an features wie z.b.&lt;br /&gt;
&lt;br /&gt;
- Eine sehr schnelle statische eigene skin engine basierend auf TBitmap.&lt;br /&gt;
- Ein dynamisches shortcut system mit multimedia keys unterstützung.&lt;br /&gt;
- Intelligente untertitel erkennung&lt;br /&gt;
- Media information erkennung&lt;br /&gt;
- Vollständiger playlist editor mit ID3 v1/v2 unterstützung.&lt;br /&gt;
- Unicode support (WideString)&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|Torsten Sailer&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Terrain3&amp;diff=25852</id>
		<title>Tutorial Terrain3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Terrain3&amp;diff=25852"/>
				<updated>2013-09-25T14:31:58Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Continuous Level of Detail fur Heightmaps=&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
&lt;br /&gt;
Hi, &lt;br /&gt;
&lt;br /&gt;
Ich habe in meinem ersten Heightmap Tutorial im Nachwort erzahlt, dass ich vielleicht ein Tutorial uber Level of Detail (LOD) fur Heightmaps schreibe. Ich will hiermit mein Versprechen einlösen, will euch aber auch gleich warnen, es ist nicht so leicht, wie man eigentlich denken könnte, denn viele Probleme stellen sich einem in den Weg, z.B. Cracks im [[Mesh]]. &lt;br /&gt;
&lt;br /&gt;
Erkundigt man sich unter Spieleentwicklern nach LOD fur Heightmaps, wird man in den meisten Fallen wohl auf den Begriff ROAMing stosen. Dieser wird z.B. in einem meiner Lieblingsgames Tribes 2 verwendet. Mich hat dieser Algorithmus nicht wirklich angesprochen und ich habe weitergesucht. Nach einiger Zeit bin ich auf den Algorithmus aufmerksam geworden, der im Spiel Aquanox sein Konnen zeigt. Genauer gesagt bin ich über das [http://www.vterrain.org Virtual Terrain Project] darauf gestosen. Das Original Script von [http://www9.cs.fau.de/Persons/Roettger Stefan Röttger] findet sich direkt auf seiner Homepage unter Terrain Rendering: [http://wwwvis.informatik.uni-stuttgart.de/~roettger/data/Papers/TERRAIN.PDF Real-Time Generation of Continuous Levels of Detail for Height Fields] Ich kann euch wirklich warmstens empfehlen, dieses Script sich einmal genauer anzuschauen - sehr interessant. In diesem Tutorial werde ich das Schriftstück etwas genauer beleuchten und ein paar Hilfestellungen dazu geben, in der Hoffnung, dass ihr es mir gleich tut und diesen Algorithmus selbst einmal nachbaut.&lt;br /&gt;
&lt;br /&gt;
==Quadtree==&lt;br /&gt;
&lt;br /&gt;
Der ganze Algorithmus basiert auf einem Quadtree. Dieser wird durch eine Boolean Matrix (für die Delpher, die immer noch nicht wissen, was eine Matrix ist: Wir reden uber ein 2 Dimensionales '''Array[0..n,0..n] of Boolean''') reprasentiert, so kann man sich eine Menge Pointer (und damit Speicherplatz) und viel Rechenarbeit sparen. Wir gehen davon aus, dass die Matrix eine Größe von (2n+1)x(2n+1) hat. Idealerweise hat die verwendete Heightmap die gleichen Ausmaße. Die Hauptnode sitzt in der Mitte der Matrix, die 4 Kinder... Bevor ich in Erklarungsnöte komme, hier einfach ein Bild, das den Sachverhalt verdeutlichen soll:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_quadmatrix.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Ok, wir wissen nun, wie die Matrix aufgebaut ist, wie die Mutter Kind Verhältnisse des Quadtrees sind, etc., nur ist noch immer nicht klar, wozu diese Matrix. Wie bereits gesagt, handelt es sich um eine Boolean Matrix. Die Werte, die die Matrix annehmen kann, sind True oder False :-). Diese sagen aus, ob eine Node gesetzt ist und damit gezeichnet wird, oder eben nicht. Unsere Ziele sind also zum einen die Matrix rendern und zum andern die Matrix berechnen&lt;br /&gt;
&lt;br /&gt;
==Rendern der Heightmap==&lt;br /&gt;
&lt;br /&gt;
Unsere Landschaft wird gerendert, indem wir den Quadtree rekursiv entlanggehen und immer wenn ein Endpunkt des Baums erreicht wird, wird ein kompletter oder Teile eines Dreieck Fans gezeichnet. Diese Fans sind besonders gut dazu geeignet, ohne Löcher und Cracks im Mesh ein Heightfield darzustellen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_setmatrix.gif]]&lt;br /&gt;
[[Bild:Tutorial_Terrain3_triangulation.gif]]  &lt;br /&gt;
&lt;br /&gt;
Das linke Bild stellt eine Beispiel Matrix dar, das rechte die dazu passende Triangulation. Ihr könnt gerne nach Stellen suchen, an denen die Moglichkeit besteht, dass dort ein Crack ist. Ihr werdet keine finden. Zuerst wird einmal davon ausgegangen, dass der Levelunterschied im Quadtree zweier benachbarter Blocke niemals mehr als 1 beträgt. Diese Bedingung wird beim Berechnen der Matrix abgesichert, dazu später mehr. Das Zentrum eines Fans, ist immer auch das Zentrum eines Quadtree Blattes. Vier Vertieces bilden die Ecken des Blocks und weitere 4 bilden jeweils die Mittelpunkte der Seiten des Blattes:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_fan.gif]]&lt;br /&gt;
 &lt;br /&gt;
Es werden also höchstens 8 Dreiecke gezeichnet. Hat eine Seite keinen benachbarten Block gleichen Levels, so wird das Vertex in der Mitte der Seite einfach ubersprungen, was zur obigen Beispiel Triangulation fuhrt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Erzeugen der Matrix==&lt;br /&gt;
&lt;br /&gt;
LOD besagt, dass Gegenstände in großer Entfernung mit einer niedrigeren Auflösung angezeigt werden, als nahe Objekte. Daneben werden auch bei größerer Entfernung bestimmte Teile eines Meshes mit höherer Auflösung angezeigt, deren Oberflache besonders uneben ist, wodurch die Bildqualitat stark erhoht wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Oberflächenfehler===&lt;br /&gt;
&lt;br /&gt;
Fehler? Fehler?!? Will ich euch jetzt verarschen, wäre doch dumm Fehler zu machen... Nein, die gemeinten Fehler besagen ausschließlich, wie verfälscht eine Stelle in der Landschaft aussehen wurde, wenn man beim Hinuntergehen des Baumes an der aktuellen Stelle aufhort und zu rendern beginnt. Je hoher dieser Wert, desto wichtiger ist es, den Baum noch tiefer hinabzuschreiten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_dhvalues.jpg|center]]&lt;br /&gt;
Um diese '''d2''' genannten Werte fur ein Quadree Blatt zu erhalten, errechnet man zuerst die Erhebungsunterschiede an den Mitten der 4 Seiten und an den 2 Diagonalen(Achtung: das sind unterschiedliche Werte). Der '''d2''' Wert errechnet sich daraus so:&lt;br /&gt;
&lt;br /&gt;
'''d2=(1/d)*maxi=1..6|dhi|'''&lt;br /&gt;
&lt;br /&gt;
In Delphi konnte das ganze dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure CalcD2Value(X, Z, Size : Longint);&lt;br /&gt;
  var&lt;br /&gt;
    HSize : LongInt; //Hälfte der eigenen Seitenlänge&lt;br /&gt;
    I : LongInt;&lt;br /&gt;
    EdgeHeights : Array[1..4] of Single; //Höhe der Ecken&lt;br /&gt;
    ExpectedHeight : Single;             //Erwartete höhe zw 2 Punkten&lt;br /&gt;
    RealHeight : Single;                 //Tatsächliche Höhe&lt;br /&gt;
&lt;br /&gt;
    DHValues : Array[1..6] of Single;    //DHWerte&lt;br /&gt;
&lt;br /&gt;
  const&lt;br /&gt;
    //Ort der Ecken des Quads&lt;br /&gt;
    Edges : Array[1..4] of Array[0..1] of ShortInt = ((+1, +1),(+1, -1),(-1,-1),(-1,+1));&lt;br /&gt;
    //Jeweils die 2 Ecken, zwischen denen ein DHWert berechnet wird&lt;br /&gt;
    DHLines : Array[1..6] of Array[0..1] of Byte =&lt;br /&gt;
      ((1,2),(2,3),(3,4),(4,1),(1,3),(2,4));&lt;br /&gt;
&lt;br /&gt;
    //Positionen der DHWerte selber&lt;br /&gt;
    DHPositions : Array[1..6] of Array[0..1] of ShortInt =&lt;br /&gt;
      ((1,0),(0,-1),(-1,0),(0,1),(0,0),(0,0));&lt;br /&gt;
&lt;br /&gt;
  begin&lt;br /&gt;
    //Höhen der 4 Ecken&lt;br /&gt;
    for I := 1 to 4 do&lt;br /&gt;
      EdgeHeights[I] := GetHeightMapHeight(X + Size * Edges[i,0],&lt;br /&gt;
                          Z + Size * Edges[i,1]);&lt;br /&gt;
&lt;br /&gt;
    //DHWerte berechen&lt;br /&gt;
    for i := 1 to 6 do&lt;br /&gt;
    begin&lt;br /&gt;
      //Erwartete Höhe zwischen 2 Punkten&lt;br /&gt;
      ExpectedHeight := (EdgeHeights[DHLines[i,0]] + EdgeHeights[DHLines[i,1]])/2;&lt;br /&gt;
      //Tatsächlich vorliegende Höhe&lt;br /&gt;
      RealHeight := GetHeightMapHeight(&lt;br /&gt;
        X + DHPositions[i,0] * Size,&lt;br /&gt;
        Z + DHPositions[i,1] * Size);&lt;br /&gt;
      //DH Wert ist |absoluter Fehler|&lt;br /&gt;
      DHValues[I] := Abs(ExpectedHeight - RealHeight)&lt;br /&gt;
    end;&lt;br /&gt;
&lt;br /&gt;
    //D2Value finden und setzen&lt;br /&gt;
    QuadMatrix[X,Z].D2Value := Trunc(1/(2*Size) * Max(DHValues));&lt;br /&gt;
&lt;br /&gt;
    //D2Values für die 4 Kinder&lt;br /&gt;
    if Size &amp;gt; 1 then&lt;br /&gt;
    begin&lt;br /&gt;
      HSize := Size div 2;&lt;br /&gt;
      CalcD2Value(X + HSize, Z + HSize, HSize);&lt;br /&gt;
      CalcD2Value(X + HSize, Z - HSize, HSize);&lt;br /&gt;
      CalcD2Value(X - HSize, Z + HSize, HSize);&lt;br /&gt;
      CalcD2Value(X - HSize, Z - HSize, HSize)&lt;br /&gt;
    end&lt;br /&gt;
  end; (*CalcD2Values*)&lt;br /&gt;
  ...&lt;br /&gt;
  CalcD2Value((QuadTreeLength-1) div 2, (QuadTreeLength-1) div 2,&lt;br /&gt;
    (QuadTreeLength-1) div 2);&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel steht '''Size''' immer fur die Hälfte der Seitenlange einer Quadtreenode. Man denke hier am Besten an den Radius eines Kreises. Die '''d2''' Werte werden auf Bytegröße komprimiert, um wertvollen Speicher einzusparen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Matrix erzeugen===&lt;br /&gt;
&lt;br /&gt;
Jetzt wollen wir uns daran machen, die fürs Zeichnen unbedingt nötige Matrix zu erzeugen. Gehen wir einmal davon aus, dass die Matrix bereits sauber entleert ist und damit kein Node als gesetzt gilt. Wir laufen den Quadtree wieder rekursiv hinab und entscheiden an jeder Node nach folgender Formel, ob weiter unterteilt werden muss oder nicht:&lt;br /&gt;
&lt;br /&gt;
'''f=l/(d*C*max(c*d2, 1)'''&lt;br /&gt;
&lt;br /&gt;
Ist der Wert von '''f''' kleiner 1, dann wird weiter unterteilt. Es gilt: '''C''' ist eine feste Konstante. Je höher sie ist, desto höher ist die Landschaft insgesamt aufgelost. '''l''' ist die Entfernung des Node Mittelpunkts zur Kamera und klein '''c''' kontrolliert die Auflösung in Bereichen, die einen hohen Oberflächenfehler aufweisen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schweizer Kase===&lt;br /&gt;
[[Bild:Tutorial_Terrain3_kaese.jpg|center]]&lt;br /&gt;
Das bisherige Ergebnis ist doch mehr ernüchternd als erfreulich. Es sieht alles mehr nach Schweizer Kase aus. Viele Löcher, aber sonst nicht viel zu bieten. In einem Spiel kann man so ganz schnell dem Spieler den Spaß verderben, wir sollten also etwas dagegen unternehmen.&lt;br /&gt;
&lt;br /&gt;
Um dieses Ziel zu erreichen, müssen wir ganz einfach die '''d2''' Werte so verändern, dass Nebeneinanderliegende Blocke keinen Levelunterschied größer als 1 aufweisen (Bedingung für das Rendern der Matrix, siehe oben). Zuerst mussen also die '''d2''' Werte einmal berechnet worden sein. Nun gehen wir den Quadtree wieder soweit herunter, bis wir genau 1 level vor dem niedrigsten sind und setzen den '''d2''' Wert der Node neu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
QuadMatrix[X,Z].D2Value := Max(QuadMatrix[X,Z].D2Value, &lt;br /&gt;
                               (d2Werte der benachbarten Nodes ein Level tiefer) * K)&lt;br /&gt;
K = C / (2 * (C - 1)); C groser 2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure DoCrackAvoid(X, Z, Size, SizeToCheck : Longint);&lt;br /&gt;
  const&lt;br /&gt;
    Neighbours : Array[0..8] of Array[0..1] of ShortInt =&lt;br /&gt;
      ((+0,+0), (+3,+1),(+3,-1),(+1,-3),(-1,-3),(-3,-1),(-3,+1),(-1,+3),(+1,+3));&lt;br /&gt;
  var&lt;br /&gt;
    HSize : LongInt; //1/4 der Seitenlänge&lt;br /&gt;
    I : LongInt;&lt;br /&gt;
    D2Values : Array[0..8] of Byte;&lt;br /&gt;
&lt;br /&gt;
  begin&lt;br /&gt;
    Assert(Size &amp;gt; 1);&lt;br /&gt;
    //Der Baum wird rekursiv abgehandlet(nicht unbedingt die&lt;br /&gt;
    //beste Idee. Wer Lust hat, darf sich gerne daran versuchen&lt;br /&gt;
    //es einmal ohne Rekursivität zu probieren!)&lt;br /&gt;
&lt;br /&gt;
    HSize := Size div 2;&lt;br /&gt;
    //Wir haben noch nicht das gewünschte Level erreicht&lt;br /&gt;
    if Size &amp;gt; SizeToCheck then&lt;br /&gt;
    begin&lt;br /&gt;
      DoCrackAvoid(X + HSize, Z + HSize, HSize,SizeToCheck);&lt;br /&gt;
      DoCrackAvoid(X + HSize, Z - HSize, HSize,SizeToCheck);&lt;br /&gt;
      DoCrackAvoid(X - HSize, Z + HSize, HSize,SizeToCheck);&lt;br /&gt;
      DoCrackAvoid(X - HSize, Z - HSize, HSize,SizeToCheck)&lt;br /&gt;
    end&lt;br /&gt;
    else&lt;br /&gt;
    begin&lt;br /&gt;
      Assert(SizeToCheck = Size);&lt;br /&gt;
      D2Values[0] := QuadMatrix[X,Z].D2Value;&lt;br /&gt;
      for i := 1 to 8 do&lt;br /&gt;
        //Nachbarnodes holen....&lt;br /&gt;
        D2Values[i] := GetNode(X + HSize * Neighbours[i][0],&lt;br /&gt;
                               Z + HSize * Neighbours[i][1]) * K;&lt;br /&gt;
&lt;br /&gt;
      QuadMatrix[X,Z].D2Value := MaxByte(D2Values)&lt;br /&gt;
    end&lt;br /&gt;
  end; (*DoCrackAvoid*)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diesen Vorgang wiederholen wir, wobei wir immer ein Level niedriger gehen, bis wir schlieslich das Level 1 erreichen. Wenn wir nun unsere Matrix berechnen, ist unsere Bedingung erfüllt und wir erhalten ein Mesh ohne Löcher:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_result.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_wireframe.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wer glaubt hier ein paar Locher finden zu können liegt falsch. Die Stellen die schwarz erscheinen, werden durch das OpenGL Licht nur so unglucklich getroffen, dass sie fast schwarz erscheinen. Ist euer Monitor richtig eingestellt, sollte dagegen alles passen. Siehe dazu auch: [[Farbraum]]{{excIcon}}. Die &amp;quot;Kamera&amp;quot; befindet sich übrigens links unten im Bild, dort wo ein rotes Quad sichtbar ist.&lt;br /&gt;
&lt;br /&gt;
'''Anmerkung:''' Nach Aussage von Stefan Röttger ist diese Methode um Löcher zu entfernen nicht optimal. Es genügt bei jedem Vater Knoten alle Kinder in die Berechnung einzubeziehen. Die Nachbarn müssen nicht einbezogen werden. Genaueres findet sich in diesem [http://www.delphigl.com/forum/viewtopic.php?p=48761#48761 Forumsbeitrag].&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Wie gehts weiter?&lt;br /&gt;
Um die ganze Sache nun noch ein bisschen weiter zu verbessern, sollte man überlegen, ob man die Landschaft nicht vielleicht texturiert. Hier bietet sich sicher das [[Tutorial_Terrain2|2. Heightmap Tutorial]] als guter Anfang an. Auch konnte man das &amp;quot;Popping&amp;quot; unterbinden, das auftritt, wenn man sich einer Stelle nähert und plötzlich ein paar neue Dreiecke angezeigt werden. Das ganze ist bekannt unter dem Begriff Geomorphing. &lt;br /&gt;
&lt;br /&gt;
Delphic&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_terrainclod_delphi_vcl|text=Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_terrainclod_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Terrain2]]|[[Tutorial_Skyboxen]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Tutorial3]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Softwareentwicklung1&amp;diff=25851</id>
		<title>Tutorial Softwareentwicklung1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Softwareentwicklung1&amp;diff=25851"/>
				<updated>2013-09-25T14:31:39Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Grundlagen der Softwareentwicklung &amp;lt;br&amp;gt; Objektorientierte Softwareentwicklung mit UML=&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
Hallo und willkommen zu meinem dritten Tutorial. Diesmal geht es um objektorientierte Sofwareentwicklung und UML.&lt;br /&gt;
&lt;br /&gt;
Wieso dieses Thema? Der ein oder andere von euch wird das kennen: Ihr schreibt Programme, die durchaus funktionieren, doch je größer sie werden, desto unübersichtlicher werden sie. Wartung und Codepflege sind nahezu unmöglich, und wehe es will jemand eine neue Funktion eingebaut haben.&lt;br /&gt;
&lt;br /&gt;
Das passiert wenn man &amp;quot;mal eben ein Programm schreibt&amp;quot;. Viele Programme werden, vorallem im Hobby-Bereich, ohne ausreichend durchdacht zu werden einfach programmiert. Bei kleinen Programmen, die nur für kurze Zeit im Zentrum eures Interesses stehen mag das gehen, aber sobald mehr als 20 Klassen zusammenarbeiten sollen, ist der Fitz (und das dirty programming) schon vorprogrammiert (im wahrsten Sinne des Wortes).&lt;br /&gt;
&lt;br /&gt;
Mir ging es leider nicht anders. Als ich, naiv wie ich war, ohne Plan(ung) an die Arbeiten am PBall-Manager 2 ging, habe ich wohl so ziemlich alle Vorgaben einer anständigen Programmierung (nicht wissend) ignoriert und habe mir damit selbst eine Lehre erteilt, wie man es '''nicht''' machen sollte.&lt;br /&gt;
&lt;br /&gt;
Da mir auch bei meiner Arbeit in der Uni niemand sagte wie man richtig programmiert, habe ich mich selbst auf die Suche nach Quellen gemacht. Ein Arbeitskollege war dann der Schlüssel. Er lieh mir das Buch &amp;quot;Visual Modeling with Rational Rose 2000 and UML&amp;quot; von Terry Quatrani (ISBN 0201699613) und erzählte mir einiges was er selbst auf Schulungen zu diesem Thema gerlernt hatte. &lt;br /&gt;
&lt;br /&gt;
Ich werde versuchen so viel wie möglich von dem wieder zu geben, was ich seitdem gelesen und gelernt habe. Ich orientiere mich dabei an dem oben genannten Buch. Da das Buch allerdings zu groß ist, um ein Tutorial daraus zu machen werde ich das Thema in mehreren Tutorials abhandeln. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
Eigentlich gibt es keine.&lt;br /&gt;
&lt;br /&gt;
Um diesen Teil des Softwareentwicklungsprozesses zu verstehen braucht ihr noch nicht einmal einen PC (Vorausgesetzt ihr druckt euch diesen Text hier aus ;) ). Programmiert wird hier nichts. Allerdings werde ich euch einige Tools vorstellen, mit denen ihr die Schritte am Computer nachvollziehen könnt.&lt;br /&gt;
&lt;br /&gt;
Auch tiefgreifendes Verständnis von OOP ist nicht von Nöten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ziele==&lt;br /&gt;
Am Ende dieses Tutorials solltet ihr wissen was UML ist und wie man damit grundlegende Planungsschritte macht. &lt;br /&gt;
&lt;br /&gt;
Ihr werdet wissen, wieso man eine, auf den ersten Blick, so umständliche Herangehensweise wählt und wieso ein Programm ohne Dokumentation irgendwie nicht vollständig ist.&lt;br /&gt;
&lt;br /&gt;
Ihr werdet weiterhin lernen wie man Anforderungen analysiert, daraus Anwendungsfälle macht und diese für weitere Analysen sinnvoll darstellt.&lt;br /&gt;
&lt;br /&gt;
In dieses Tutorials werdet ihr die Grundlagen schaffen, um im zweiten Teil des Tutorials Klassen zu erkennen und deren Beziehnungen untereinander zu modellieren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==UML==&lt;br /&gt;
1997 wurde UML als Standard für Objekt Orientierte Modellierung festgesetzt. Die '''''U'''nified '''M'''odeling '''L'''anguage'' ist wie der Name schon sagt eine Sprache zur Modellierung von Software. &lt;br /&gt;
&lt;br /&gt;
Es existieren eine Menge graphischer Editoren, welche es dem Softwaredesigner ermöglichen auf graphischem Wege seine Software zu entwickeln. Diese graphische Darstellung gibt einem Entwickler viel schneller einen Überblick über das System, was er zu entwickeln, pflegen oder zu warten hat.&lt;br /&gt;
&lt;br /&gt;
UML bietet Möglichkeiten um alle im Softwareentwicklungsprozess nötigen Diagramme zu erzeugen. Da UML den Aufbau von Softwaresystemen modelliert ist es möglich aus den erstellten Diagrammen (im besonderen aus den Klassendiagrammen) Code generieren zu lassen. (Nicht jedes Tool beherrscht diese Fähigkeit, und leider werden nicht alle Sprachen unterstützt.)&lt;br /&gt;
&lt;br /&gt;
Einige Tools beherrschen sogar den umgekehrten Weg, sie können bestehenden Code analysieren und daraus eine UML Darstellung generieren (''round-trip engineering''). Damit ist es leicht die Dokumentation auf dem Stand der Software zu halten. Die Planung erspart uns diese Fähigkeit aber nicht.&lt;br /&gt;
&lt;br /&gt;
Neben kommerziellen Editoren die Funktionen wie Codegenerierung in verschiedene Sprachen unterstützen, (z.B. Rational Rose 2000) gibt es auch einige kostenlose Editoren.&lt;br /&gt;
&lt;br /&gt;
Eine Liste mit UML-Editoren findet ihr zum Beispiel hier: &lt;br /&gt;
*[http://en.wikipedia.org/wiki/List_of_Unified_Modeling_Language_tools Englischer Wikipedia Artikel]&lt;br /&gt;
*[http://www.jeckle.de/umltools.htm Jekle.de]&lt;br /&gt;
&lt;br /&gt;
Welchen ihr nehmt sollt hängt von der Plattform auf der ihr entwickelt und dem Code der generiert wird ab. Die Optik der entstehenden Diagramme ist auf alle Fälle immer gleich, weil der UML-Standard dieses vorgibt. Unter Linux ist meist Umbrella vorinstalliert.&lt;br /&gt;
&lt;br /&gt;
''(Wer mit Java arbeitet hat sehr viele Möglichkeiten. Ein Blick auf '''ArgoUML''' oder '''Fujaba''' könnte lohnen. Für letzteren gibt es auch ein Eclipse Plugin.)''&lt;br /&gt;
&lt;br /&gt;
==Wieso Dokumentation?==&lt;br /&gt;
''Wieso soll ich meinen Code dokumentieren? Ich weiß doch was er macht!''&lt;br /&gt;
&lt;br /&gt;
Solche &amp;quot;Argumente&amp;quot; hört man des Öffteren wenn es darum geht Zeit in die Dokumentation des Programmes zu stecken. Allerdings ist dies keinesfalls verlorene Zeit. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr ein Programm, z.B. ein Spiel, entwickelt welches mehr als 15.000 Zeilen Code umfasst, dann gibt es Teile im Code die euch nach einem halben Jahr nicht mehr bekannt sind. Meist ist das kein Problem, denn man kann sich ja einarbeiten. Stellt euch aber nun vor es wäre ein Jahr vergangen und ihr wollte einen Nachfolger programmieren. ''Kein Problem'' denkt ihr, ''ich hab ja den alten Code noch''. Stimmt. Aber der Frust ist groß wenn man sich in Code einarbeiten muss, den man heute ganz anders schreiben würde (man hat ja dazugelernt seit damals). Eine Dokumentation wäre toll. Aber sowas wurde ja nie gemacht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Noch schlimmer ist es, wenn man im Team programmiert. Stellt euch vor, euer KI-Spezialist ist im Urlaub und ein Bug der die komplette Betatestphase blockiert tritt auf. Da wäre eine Dokumentation eine tolle Sache.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ihr seht Dokumentation hilft euch Zeit zu sparen, auch wenn es am Anfang den Anschein hat, als ob sie nur Zeit kosten würde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Aber was gehört in die Dokumentation eines Projektes? Ganz einfach: Alles was im Verlauf der Entwicklung an Dokumenten anfällt. Von den Anforderungen, den zig UML-Diagrammen bis zu den Testberichten. Einfach alles. Bei großen Projekten füllt sowas schnell mal ganze Ordner (aber immer noch besser als bei Problemen 250.000 Zeilen Code ab zu suchen).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Aber alle Dokumentation nützt nichts, wenn sie nicht den aktuellen Zustand des Projektes wiedergibt. Im Verlauf der Implementierung passiert es immer wieder, dass Klassen benötigt werden, die in der Planungsphase so nicht verausgesehen werden konnten. Diese Klassen müssen auch in die Dokumentation eingepflegt werden. Denn die Doku dokumentiert immer das aktuelle Programm, nicht das &amp;quot;wies mal geplant war&amp;quot;! Für solche Fälle ist ein Tool welches Code analysieren kann und daraus Klassendiagramme baut wirklich hilfreich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wir halten uns in diesem Tutorial weitestgehend am '''RUP'''. RUP steht für '''Rational Unified Process''' und ist im Kern mit dem [[Wasserfallmodell]] vergleichbar. Der positive Nebeneffekt am RUP ist, dass die Dokumentation ein Nebenprodukt des gesamten Planungsvorgangs ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Phasen der Entwicklung==&lt;br /&gt;
Werden wir nun etwas konkreter. Über die Zeit in der ein Programm entwickelt wird, durchläuft es verschiedene Phasen:&lt;br /&gt;
&lt;br /&gt;
; Einstieg/Konzept (Inception) : In dieser Phase werden die Anforderungen, die Umgebung des Programms und die zu erreichenden Ziele untersucht.&lt;br /&gt;
; Ausarbeitung/Spezifikation (Elaboration) : In dieser Phase werden Aktivitäten und benötigte Ressourcen eingeplant und definiert welche Eigenschaften und Codedesign das Projekt haben soll.&lt;br /&gt;
; Konstruktion (Construction) : In dieser Phase wird das Programm über mehrere Programmierzyklen hinweg geschrieben (und getestet).&lt;br /&gt;
; Übertragung (Transition) : Das Übertragen und in Betriebnehmen beim Kunden ist auch eine eigene Phase.&lt;br /&gt;
&lt;br /&gt;
Die obige Gliederung ist einsichtig. Leider wird auch niemand wirklich schlauer damit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine andere Einteilung in Phasen ist die, entlang der Aktivitäten die man zu tun hat:&lt;br /&gt;
; Aufgaben Modellierung (Business Modelling) : Hier wird geklärt in welchem Umfeld das Programm eingesetzt werden soll und was der Nutzer wirklich will/braucht.&lt;br /&gt;
; Anforderungen (Requirements) : Eine schriftliche Schilderung der Vision die man für das Programm hat. Umfasst alle funktionalen und nicht funktionalen Anforderungen.&lt;br /&gt;
; Analyse und Design : Eine Beschreibung wie das System später zu implementieren ist.&lt;br /&gt;
; Implementation : Schreiben des Codes mit dem Resultat eines funktionierenden Systems&lt;br /&gt;
; Test : Prüfen der Funktionen des gesamten Systems&lt;br /&gt;
; Aufstellen (Deployment) : Installation des Systems beim Kunden und Anwenderschulung.&lt;br /&gt;
&lt;br /&gt;
Ich gebe zu das ist sehr weit gegriffen, vorallem im Bezug auf Spieleentwicklung. Aber dieses Tutorial soll euch auch dann noch etwas nutzen, wenn ihr mal keine kleinen Spielchen mehr schreibt. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beide genannten Gliederungen können als Diagramm dargestellt werden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SWE1_Phasen.jpg|center|Quelle: 'Visual Modeling with Rational Rose 2000 and UML' Terry Quatrani]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial bewegen wir uns in der Einstiegs und Ausarbeitungsphase. Dabei befassen wir uns vorallem mit Business Modeling, Anforderungsanalyse und den ersten Schritten in Analyse und Design des Programms.&lt;br /&gt;
&lt;br /&gt;
==Vor dem Start==&lt;br /&gt;
''Folgende Situation:''&lt;br /&gt;
&lt;br /&gt;
Jemand (der Kunde oder ihr selbst) sagt zu euch &amp;quot;Ich brauche ein Programm&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ihr fragt dann zurück &amp;quot;Was soll es denn können?&amp;quot;. Die Antwort wird meist nicht zufriedenstellend sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn ihr nur so zum Spaß entwickelt, dann könnt ihr den Kunden einfach weg schicken. Wenn ihr Geld verdienen wollt, dann habt ihr ein Problem: Ihr habt einen Kunden, der euch einen Auftrag gibt, aber ihr wisst nicht was zu tun ist.&lt;br /&gt;
&lt;br /&gt;
Wir befinden uns mitten in der Einstiegsphase. Business Modelling und Anforderungen sind hier Schlagwörter die es umzusetzen gilt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im klassischen Fall kommt der Kunde mit einem Lastenheft zu euch und möchte, dass dies umgesetzt wird. In der Realität ist der Wunsch des Kunden eine Software zu besitzen meist eher fertig als das Lastenheft. Ihr müsst also quasi dem Kunden sagen, was er eigentlich will.&lt;br /&gt;
&lt;br /&gt;
Die ersten Frage die ihr euch stellen müsst sind &lt;br /&gt;
*&amp;quot;Wird die Software wirklich gebraucht?&amp;quot; und&lt;br /&gt;
*&amp;quot;Sind die Probleme die zu lösen sind wirklich dort wo die Software eingesetzt werden soll?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hobbymäßig entwickelte Spiele werden gebraucht und lösen Probleme, aber das versteht sich in diesem Falle ja von selbst. ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn ihr es mit einem Kunden zu tun habt, dann sind die nächsten Schritte&lt;br /&gt;
* Ideen festigen (was will der Kunde eigentlich)&lt;br /&gt;
* Einschätzen welche Teilaufgaben am Kompliziertesten sind, bzw. welche Probleme machen könnte. (Risikobewertung)&lt;br /&gt;
* Feststellen wer das System einsetzen soll&lt;br /&gt;
* Feststellen welche Hauptfunktionen das System haben soll&lt;br /&gt;
* Bauen erster Prototypen (Wegwerf-Code!) um Konzepte und Ideen zu testen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Welche Mittel stehen uns zu diesem Zeitpunkt zur Verfügung?&lt;br /&gt;
*Brainstorming&lt;br /&gt;
*Recherche&lt;br /&gt;
*Marktanalysen &lt;br /&gt;
*Kosten Nutzen Analyse&lt;br /&gt;
*Use Cases&lt;br /&gt;
*Prototyping&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei kommerziellen Systemen sind eine Menge verschiedener Leute in dieser Phase beteiligt. Vorallem Leute die vom Umfeld der Software mehr verstehen, als das die Programmierer könnten (und müssten). Die Ideen, wie das System einmal aussehen könnte kommen von:&lt;br /&gt;
* Kunden&lt;br /&gt;
* Experten des Anwendungsgebiets&lt;br /&gt;
* Industrieexperten&lt;br /&gt;
* andere Entwickler&lt;br /&gt;
* Prüfung bereits bestehender Systeme (Analyse der Konkurenz)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Neben den Anforderungen die an den Code gestellt werden (die sogenannten funktionalen Anforderungen) müssen in dieser Phase auch die nicht funktionalen Anforderungen geklärt werden. Das sind z.B:&lt;br /&gt;
* Zielplattform für die entwickelt wird (Hardware, Betriebssystem)&lt;br /&gt;
* Zu welcher Software es Schnittstellen geben muss, bzw. welche Software noch läuft&lt;br /&gt;
* Wie die Software eingesetzt wird (Verteilung auf Rechner)&lt;br /&gt;
* Wie lange die Software genutzt wird&lt;br /&gt;
* Wie lange die Software am Stück läuft.&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei all diesen Punkten kann der Wunschzettel des Kunden schnell größer werden als das Portemonnee. Aus diesem Grunde gilt immer: '''Der Umfang des Projekts wird beschränkt durch''' &lt;br /&gt;
* den Nutzen den das Projekt für den Kunden bringt&lt;br /&gt;
* die Ressourcen die zur Verfügung stehen (Arbeitskräft, IDEs, Hardware, GELD!)&lt;br /&gt;
* die Technologien die eingesetzt werden können/dürfen&lt;br /&gt;
* die Wünsche der späteren Nutzer bezüglich des Systems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Ende der Phase '''muss eine Produktvision stehen''', die Aussage '''&amp;quot;Das zu entwickelnde System tut ...&amp;quot;'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Vision sollte '''schriftlich festgehalten''' werden (Sie gehört zum Auftrag!). Bei umfangreichen System kann dies einige Seiten Text bedeuten, aber nichts ist schlimmer als nach 2 Monaten Arbeit vom Kunde zu hören &amp;quot;Schön das ihre SW das kann, aber wir wollten das gar nicht, sondern ...&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Mitarbeit des Kunden/Auftraggebers ist ein entscheidender Punkt für den Erfolg/Akzeptanz der Software (siehe auch &amp;quot;IT Projektmanagement Kompakt&amp;quot; von Pascal Mangold; ISBN 3827415020). Vorallem zu Beginn des Projektes ist deshalb Kommunikation das wichtigste. Leider ist dabei nicht auszuschließen, dass es zu Missverständnissen kommt. Aus diesem Grund wird bei großen (und wichtigen) Projekten eine Art &amp;quot;Wörterbuch&amp;quot; mit Begriffen definiert, mit denen man sich unterhalten kann. Man spricht hier von &amp;quot;der Sprache des Anwendungsgebietes&amp;quot; (Domain Language). Es reicht aus, wenn alle Beteiligten wissen, wie man mit dem anderen Reden muss, es ist nicht wichtig dass dies schriftlich hinterlegt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Prototyping und Risikobewertung==&lt;br /&gt;
Was ist eigentlich ''&amp;quot;Risikobewertung&amp;quot;''?&lt;br /&gt;
&lt;br /&gt;
Jedes Projekt hängt vom Erfolg bzw. von der Realisierbarkeit bestimmter Sachverhalte ab. Zum Beispiel ist es für ein Online Spiel extrem wichtig, dass die Programmierer es schaffen eine Netzwerkverbindung zu bauen und ein Serversystem welches dem erwarteten Nutzeraufkommen gerecht wird. In Firmensoftware könnte wichtig sein, dass die Datenbank von 1967 in die SW integriert werden kann, oder dass eine bestimmte Hardware genutzt werden kann.&lt;br /&gt;
&lt;br /&gt;
Sachverhalte die absolut essentiell für das Gelingen eines Projektes sind, enthalten das größte Risiko. Denn wenn sie fehlschlagen bzw. nicht umgesetzt werden können, dann stirbt meist auch das gesamte Projekt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
An diesem Punkt kommt das Prototyping ins Spiel. Es wird eigentlich nur benötigt, um zu testen, ob die riskanten Sachverhalte umgesetzt werden können oder nicht. Die dabei entstehenden Prototypen sind Wegwerfprodukte. Sie dienen nur dem Nachweis, ob man etwas machen kann oder nicht. Sie sind sind maximal Ideengeber. Der produzierte Code wird aber (weil nicht geplant und dokumentiert) nicht für das spätere System verwendet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es wird immer der Sachverhalt mit dem größten Risiko zuerst untersucht. Aus diesem Grund ist die Risikoanalyse von entscheidender Bedeutung. &lt;br /&gt;
&lt;br /&gt;
Ohne Risikoanalyse kann man von Glück reden wenn sich ein Projekt zu einem frühen Zeitpunkt als &amp;quot;nicht durchführbar&amp;quot; herausstellt und nicht nach 6 Monaten Planung und Design.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Von Fall zu Fall - Use Case Diagramme==&lt;br /&gt;
Wie oben bereits angesprochen sind '''Use Cases''' ein probates Mittel um heraus zu finden was das Programm eigentlich tun soll. Auf den ersten Blick sehen Use Case Diagramme (im folgenden UCD) recht harmlos, vielleicht sogar nutzlos aus. Der Schein trügt. Sie sind der Einstiegspunkt in die Entwicklung des System. &lt;br /&gt;
&lt;br /&gt;
Doch der Reihe nach. Use Cases, zu deutsch Anwendungsfälle, bezeichnen Aufgaben und Situationen die das fertige Programm beherrschen muss. Das geht von &amp;quot;Spieler startet neues Spiel&amp;quot;, über &amp;quot;Spieler baut Gebäude XYZ&amp;quot; bis hin zu &amp;quot;Gameserver fragt die Clienteinstellungen ab&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
UCD bestehen aus den Use Cases und den sogenannten '''Akteuren''', beide betrachten wir im folgenden noch genauer. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Hauptaufgabe eines Use Case Diagramms ist die Kommunikation zwischen Entwicklern und Anwendern über die Funktion des Systems.''' Aus diesem Grund wird bei der Dokumentation immer die Sprache des Einsatzgebietes (die Sprache des Kunden) benutzt, und nicht eine implementations Orientierte. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jedes System besitzt mindestens ein UCD, das '''Haupt Use Case Diagramm''' (Main UCD). Dieses Diagramm zeigt die Systemgrenzen (Akteure) und Hauptfunktionen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zusätzlich dazu sind Use Cases zu folgenden Zwecken angemessen:&lt;br /&gt;
* UCD welches alle Use Cases eines Akteurs anzeigt.&lt;br /&gt;
* UCD welches alle Use Cases enthält die innerhalb eines Implementationsschrittes implementiert werden sollen.&lt;br /&gt;
* UCD welches einen Use Case mit all seinen Beziehungen zu anderen Use Cases zeigt. (Siehe [[Tutorial Softwareentwicklung1#Beziehungen zwischen Use Cases| Beziehungen zwischen Use Cases]])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Akteure===&lt;br /&gt;
[[Bild:Tutorial_SWE1_Akteur.jpg|right]]&lt;br /&gt;
Akteure sind nicht Teil der Software, sondern bezeichnen alle die Dinge und Personen, welche mit der Software interagieren müssen. &lt;br /&gt;
&lt;br /&gt;
Akteure können nur 3 Funktionen übernehmen:&lt;br /&gt;
* Daten entgegen nehmen.&lt;br /&gt;
* Daten liefern&lt;br /&gt;
* Daten liefern und entgegen nehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie findet man heraus, was ein Akteur für unsere Software ist? Zu diesem Zweck gibt es eine Checklist mit Fragen, welche man abarbeiten kann:&lt;br /&gt;
'''&lt;br /&gt;
* Wer interessiert sich für eine bestimmte Anforderung?&lt;br /&gt;
* Wo in der Organisation des Kunden wird das System angewandt?&lt;br /&gt;
* Wer profitiert von der neuen Software?&lt;br /&gt;
* Wer liefert Informationen in die Software, wer benutzt Informationen aus der SW und wer entfernt Informationen aus der SW?&lt;br /&gt;
* Wer wartet und pflegt die SW?&lt;br /&gt;
* Nutzt die SW externe Ressourcen? (Die Ressourcen sind dann auch Akteure)&lt;br /&gt;
* Interagiert die SW mit einem Uralt-System (legacy System = Systeme die schön seit ewigen Zeiten in Benutzung sind)&lt;br /&gt;
* Hat eine Person mehrere Rollen? (Ein Akteur pro Rolle)&lt;br /&gt;
* Haben verschiedene Personen die selbe Rolle? (Ein Akteur pro Rolle)&lt;br /&gt;
'''&lt;br /&gt;
&lt;br /&gt;
''Wenn man die KI eines Spieles als eigenständige Software sieht, wäre sie auch ein Akteur.''&lt;br /&gt;
&lt;br /&gt;
Nachdem die Akteure gefunden wurden, sollte man selbige Dokumentieren. Es geht dabei darum kurz verbal zu beschreiben was die Aufgaben des Akteurs sind. Absolut fehl am Platz sind hier Implementationsdetails wie Funktionen oder Propertys.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Use Cases===&lt;br /&gt;
[[Bild:Tutorial_SWE1_UseCase.jpg|right]]&lt;br /&gt;
Use Cases repräsentieren Funktionen des Systems. Die formale Definition lautet: ''&amp;quot;Ein Use Case ist eine Abfolge von Transaktionen durch das System welche ein messbares Ergebnis von Werten für einen Nutzer bringt.&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auch zum finden von Use Cases gibt es eine Liste von Hilfsfragen:&lt;br /&gt;
'''&lt;br /&gt;
* Welche Aufgaben hat jeder Akteur?&lt;br /&gt;
* Wird ein Akteur Informationen erstellen, speichern, ändern, entfernen oder lesen?&lt;br /&gt;
* Durch welche Anwendungsfälle werden Informationen erstellt, gespeichert, geändert, entfernt oder gelesen?&lt;br /&gt;
* Wird ein Akteur die Software über plötzliche externe Änderungen informieren?&lt;br /&gt;
* Muss ein Akteur über Vorkommnisse im System informiert werden?&lt;br /&gt;
* Welcher Use Case pflegt und wartet das System?&lt;br /&gt;
* Können alle funktionalen Anforderungen durch die Use Cases abgedeckt werden?&lt;br /&gt;
'''&lt;br /&gt;
&lt;br /&gt;
====Von guten und schlechten Use Cases====&lt;br /&gt;
Wann ist ein Use Case gut? &lt;br /&gt;
&lt;br /&gt;
Über die Angemessenheit von Use Cases wurde viel diskutiert. Hauptsächlich bezüglich dem Detailgrad von Use Cases (also wie groß sie sein dürfen).&lt;br /&gt;
&lt;br /&gt;
Als Richtschnur gelten bei solchen Fragen zwei Aussagen:&lt;br /&gt;
'''&lt;br /&gt;
*Ein Use Case repräsentiert eine Hauptfunktion des Systems und zwar komplett vom Anfang bis zum Ende.&lt;br /&gt;
*Ein Use Case muss einem Akteur etwas von Wert zur Verfügung stellen.&lt;br /&gt;
'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Beispiel 1:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sind ''Spieler wählt Multiplayerspiel'', ''Spieler wird in die Liste der Teilnehmer aufgenommen'' und ''Spieler wählt Spielfigur aus''' drei verschiedene Use Cases oder einer?&lt;br /&gt;
&lt;br /&gt;
Laut den oben genannten Richtlinien ist die ein Use Case: ''Spieler startet Multiplayerspiel''. Wieso? Weil alle 3 genannten Fälle Teile eines größeren sind und ohne die anderen nutzlos wären.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Beispiel 2:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Sind ''Spieler ändert Musikeinstellungen'' und ''Spieler ändert Spielauflösung'' verschiedene Use Cases oder einer?&lt;br /&gt;
&lt;br /&gt;
Auch hier wäre wieder ein Use Case ''Spieler ändert Spieleinstellungen'' angebracht. Denn ein Akteur verändert die selbe Entität (Spieleinstellungen. Was eine Entität ist wird im zweiten Teil des Tutorials besprochen.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Dokumentation von Use Cases====&lt;br /&gt;
Auch Use Cases müssen Dokumentiert werden. Wie bei den Akteuren geht es darum die Aufgabe/Funktion des Use Cases grob zu erklären. Implementationsdetails sind nicht gefragt. Bei großen mehrstufigen Use Cases kann eine andere Methode angewandt werden:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Use Case Ereignisfluss'''&lt;br /&gt;
&lt;br /&gt;
Der Ereignisfluss ist eine Beschreibung der Ereignisse stattfinden müssen, um das gewünschte Verhalten eines Use Cases zu erreichen.&lt;br /&gt;
&lt;br /&gt;
Wichtig ist '''WAS''' nicht wie etwas gemacht werden soll. Aus diesem Grund wird die Sprache des Anwendungsgebietes benutzt nicht eine Implementationsorientierte. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Ereignisfluss enthält:&lt;br /&gt;
* Wann und Wie beginnt ein Use Case bzw. endet er.&lt;br /&gt;
* Welche Interaktionen hat der Use Case mit den Akteuren.&lt;br /&gt;
* Welche Daten benötigt der Use Case.&lt;br /&gt;
* Der normale (zu erwartende) Ereignisablauf für den Use Case.&lt;br /&gt;
* Eine Beschreibung der Alternativ- bzw. Exception Flüssen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um die Flüsse zu erstellen geht man iterativ vor:&lt;br /&gt;
* kurzer Abriss aller nötigen Events die für den normalen Fluss wichtig sind.&lt;br /&gt;
: dann&lt;br /&gt;
* Ausbau der Stufen mit mehr Details&lt;br /&gt;
: dann&lt;br /&gt;
* Hinzufügen von Exception Flüssen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Innerhalb eines Projektes sollte man eine immer gleiche Vorlage(Template) für die Ereignisflüsse benutzen. Eine mögliche Vorlage wäre z.B.:&lt;br /&gt;
 X. Ereignisfluss für den &amp;lt;NAME&amp;gt; Use Case&lt;br /&gt;
 X.1. Vorbedingungen&lt;br /&gt;
 X.2. Hauptfluss&lt;br /&gt;
 X.3. Unterflüsse (Subflows; falls nötig)&lt;br /&gt;
 X.4. Alternativflüsse&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung der Flüsse erfolgt verbal. (&amp;quot;Nutzer loggt sich ein und wählt einen Menüpunkt. Wenn Menüpunkt &amp;quot;XYZ&amp;quot; dann Unterfluss S1 sonst [...]&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SWE1_UCrelation.jpg|right|thumb|250px]]&lt;br /&gt;
====Beziehungen zwischen Use Cases====&lt;br /&gt;
&lt;br /&gt;
Man unterscheidet zwei mögliche Beziehungsarten: &lt;br /&gt;
&lt;br /&gt;
*unidirektionale Beziehungen gehen nur in eine Richtung&lt;br /&gt;
*bidirektionale Beziehungen gehen in beide Richtungen&lt;br /&gt;
&lt;br /&gt;
Der Pfeil bei unidirektionalen Beziehungen zeigt auf den genutzen/aufgerufenen Use Case bzw. Akteur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Neben diesen ''normalen'' Beziehungen gibt es noch zwei Sonderformen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SWE1_UCinclude.jpg|right|thumb]]&lt;br /&gt;
*'''Include-Beziehung'''&lt;br /&gt;
: Teile/Funktionen welche in mehreren Use Cases benötigt werden, werden als eigenständiger Use Case dargestellt und über eine include-Beziehung einbezogen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SWE1_UCextend.jpg|right|thumb]]&lt;br /&gt;
*'''Extend-Beziehungen'''&lt;br /&gt;
: Funktionen welche als optionales Verhalten gelten, oder nur ausgeführt werden, wenn ein besonderes Ereignis eintritt (z.B. ein Alarm) bzw. Funktionen die nur von bestimmten Akteuren ausgelößt werden können, werden durch extend-Beziehungen eingebunden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Aktivitätsdiagramme===&lt;br /&gt;
Wir haben nun die Use Cases gefunden, welche unser System ausmachen. Aktivitätsdiagramme sind Flussdiagramme mit denen man den Workflow eines Systems zeigen kann. Man sieht in diesen Diagrammen gut wie der Kontrollfluss von Aktion zu Aktion wandert, was parallel laufen kann und welche Alternativen es gibt.&lt;br /&gt;
&lt;br /&gt;
Nachdem die Use Cases gefunden wurden, können Aktivitätsdiagramme benutzt werden um den Fluss zwischen Use Cases zu zeigen, oder wie der Fluss in einem Use Case aussieht.&lt;br /&gt;
&lt;br /&gt;
In Aktivitätsdiagrammen werden folgende UML Symbole verwendet:&lt;br /&gt;
[[Bild:Tutorial_SWE1_AktivDiagramSymbole.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; Aktivität : Repräsentiert ein bestimmtes Verhalten (Funktionalität) im Workflow.&lt;br /&gt;
&lt;br /&gt;
; Transition : Symbolisiert die Übertragung des Kontrollflusses von einer Aktivität zur nächsten, und wird in der Regel durch den Abschluss des Vorgängers ausgelösst.&lt;br /&gt;
&lt;br /&gt;
; Entscheidung : Zeigt alternative Flussmöglichkeiten. Ausgehend von der Entscheidung gehen sogenannte &amp;quot;bewachte&amp;quot; Transitions aus. Diese besitzen eine Bedingung die erfüllt sein muss, damit die Transition benutzt werden kann.&lt;br /&gt;
&lt;br /&gt;
; Synchronisationsbalken : Sind eine Möglichkeit um Paralellität zu zeigen. Synch. Balken können mehrere ein und ausgehende Pfade haben.&lt;br /&gt;
&lt;br /&gt;
; Start und Endpunkt : Sind die definierten Orte, wo ein Fluss startet und endet. Es ''kann'' mehrere Endpunkte geben, aber in der Regel nur einen Startpunkt.&lt;br /&gt;
[[Bild:Tutorial_SWE1_AktivDiagram.jpg|right|thumb|250px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bild rechts sieht man ein mögliches Aktivitätsdiagram. &lt;br /&gt;
&lt;br /&gt;
Als '''Swimlanes''' bezeichnet man die Linien welche das Diagramm in Bereiche unterteilen. Sie zeigen an, welche Personen oder Organisationen was im Workflow zu tun haben. Mein UML Editor bietet diese Möglichkeit im Moment noch nicht, aber wenn ihr sie seht, werdet ihr sie erkennen und verstehen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ausblick==&lt;br /&gt;
6 Stunden Schreiberei sind vorüber und das Tutorial ist mittlerweile auf eine beachtliche Größe angewachsen. Mit dem Abschluss der Arbeiten an den Use Cases sind wir soweit Klassen zu bestimmen und die Interaktionen der Selbigen. Dies wird aber erst im zweiten Tutorial eine Rolle spielen. Jetzt wird erst einmal ausgeruht und Weihnachten gefeiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn ihr das Tutorial einmal an einem eigenen Projekt umsetzt werdet ihr das Gefühl haben viel Zeit zu verbrauchen, ohne etwas produziert zu haben. Wenn ihr aber erst in der Implementationsphase seid, werdet ihr feststellen, dass ihr euch eine Menge Zeit spart, weil ihr sofort wisst wie welche Teile beschaffen sein müssen, damit am Ende eure Software herauskommt.&lt;br /&gt;
&lt;br /&gt;
Außerdem müsst ihr immer daran denken: '''Die Dokumentation ist kein Extra. Die Dokumentation ist genauso Teil der Software wie der geschriebene Code.'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es ist durchaus realistisch, dass ihr 1-2 Wochen für Planung, Analyse und Design eines 15.000 Zeilen Programms benötigt, bis ihr die ersten Zeilen Code schreibt. (Professionelle Entwickler die einen &amp;gt;8h Tag haben, schaffen es vielleicht auch in der Hälfte der Zeit.) Aber was sind schon 2 Wochen, wenn ihr in den folgenden 4 Monaten in einem ordentlich strukutierten Code programmieren könnt. (Und den Code in einem Jahr noch versteht.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
: '''Kevin Fleischer''' aka Flash&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Bomberman2]]|[[Tutorial Softwareentwicklung2]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Softwareentwicklung1]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Software-Synthesizer&amp;diff=25850</id>
		<title>Tutorial Software-Synthesizer</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Software-Synthesizer&amp;diff=25850"/>
				<updated>2013-09-25T14:31:23Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Über Schall und Digitalisierung==&lt;br /&gt;
&lt;br /&gt;
Schall ist, wie sicherlich Jeder weis, nichts anderes als Druckschwankungen im uns umgebenden Medium: meist Luft. Aber er lässt sich auch gut durch Wasser oder Metall übertragen, nur vor dem Nichts, dem Vakuum, muss er kapitulieren. Die Druckschwankungen werden vom Trommelfell in unserem Ohr auf ein Knochensystem und von diesem auf das eigentliche Hörorgan übrtragen, welches über feine Haare die Druckschwankungen in Nervensignale übersetzt. Unser Gehirn bereitet die Daten auf, wobei ein subjektiver Eindruck entsteht - wir hören.&lt;br /&gt;
&lt;br /&gt;
Dabei ist unser Ohr im Stande, unterschiedliche Frequenzen als solche einzeln wahrzunehmen. Das ist insofern etwas besonderes, da unser Auge genau das nicht kann. Treffen auf die Netzhaut gleich intensiv und gemeinsam blaues und gelbes Licht, so entsteht ein grüner Farbeindruck. Unser Ohr, würde es nicht auf Schall, sondern auf elektromagnetische Wellen reagieren, würde das Blau und das Gelb als solche einzeln identifizieren können. Manche Menschen haben im übrigen eine andere Sehstäbchenzusammensetzung auf der Netzhaut, als der &amp;quot;normale&amp;quot; Mensch - so empfinden einige das gemischte Computergelb als eine andere Farbe, als das &amp;quot;echte&amp;quot; Gelb.&lt;br /&gt;
&lt;br /&gt;
Nun wollten wir uns aber nicht mit dem Sehen, sondern mit dem Hören beschäftigen. Um Schall zu digitalisieren und damit in Computertaugliche Form zu bringen, benutzt man Mikrofone. Diese besitzen eine Membran, die durch die Druckveränderungen der umgebenden Luft in Schwingung versetzt wird. An einer Stelle der Membran befindet sich eine Spule, in einem Magnetfeld. Wird die Membran durch Schall bewegt, wird die Spule im Magnetfeld bewegt: es entsteht ein Induktionsstrom, der nach Verstärkung ein elektrisches Signal liefert. Dieses Signal könnte man z.B. an einen Lautsprecher weiterleiten und so wieder vertonen.&lt;br /&gt;
&lt;br /&gt;
In unserem Falle wollen wir die Signaldaten jedoch digitalisieren. Dazu wird ein Analog/Digitalwandler verwendet, der die unterschiedlichen Spannungen in Zahlenwerte umwandelt (digitalisiert). Das analoge Signal ist durchgängig, während digitale Daten immer nur kleine Abschnitte des Signals darstellen können, weshalb das Signal gesampelt wird: In einer Sekunde werden gleichverteilt die Signalpegel des analogen Signals in eine Reihe Zahlenwerte umgewandelt. Die Anzahl der Zahlenwerte pro Sekunde wird als Samplingrate bezeichnet. Audio CDs werden mit 44,1 kHz gesampelt, d.h. pro Sekunde wird das analoge Signal des Mikrofons 44100 mal in einen digitalen Wert, ein Sampel, übersetzt.&lt;br /&gt;
&lt;br /&gt;
Wir wollen jedoch den umgekehrten Weg gehen: Wir wollen eine Reihe Sampels selbst erzeugen, um so wohlklingende Töne zu erzeugen, die wir dann als Sounds oder Musik in unseren Projekten einsetzen können. Bis dahin ist es ein längerer Weg. Lest das Tutorial nicht zu schnell, pausiert auch hin und wieder mal, damit ihr das gelernte ausprobieren könnt. Eigene Ideen können häufig auch sehr interessant klingendes hervorbringen. Probiert einfach mal ein wenig rum, aber denkt immer daran, dass, solltet ihr einmal nichts hören können, ein aufdrehen der Lautsprecher ungesund werden könnte. Bleibt mit dem Regler in den Bereichen, die ihr auch sonst nutzt.&lt;br /&gt;
&lt;br /&gt;
Für viele der hier gezeigten Experimente ist hochwertiges Equipment zu empfehlen. Es kann durchaus sein, dass durch billige Boxen euch einige Erkenntnisse verwehrt bleiben, weil die Sache einfach nicht so klingt, wie sie soll. Da klappert mal etwas mit und schon verändert sich der Ton oder es entstehen zusätzliche, andersfrequente Töne, die den klaren Eindruck trüben. Die 5 Euro Boxen, die zum üblichen Komplettsystem gehören sind in keinem Fall geeignet. Auch eine ordentliche Soundkarte wäre zu empfehlen, wobei diese noch nicht einmal neu sein muss - auch eine alte Soundblaster AWE-32 wäre vollkommen ausreichend: nur hochwertig muss sie sein. Ach ja, eine 16-Bit Soundkarte sollte es dann schon sein ;-) Viele Onboard Soundkarten tuns auch, nur leider nicht alle :-(.&lt;br /&gt;
&lt;br /&gt;
{{Warnung|Dieses Tutorial wird euch den Weg in die faszinierende Welt der Software Synthese ebnen. Dies kann jedoch zu gesundheitlichen und materiellen Schäden führen, wenn ihr nicht ein paar grundlegende Dinge beachtet. Euer Gehör ist empfindlich und eure Boxenmembranen sind teuer. Vor Versuchen sollte immer mit einem euch bekannten Programm, die Lautstärkepegel eurer Soundkarte und eures Boxensystems überprüft werden. Zu hohe Lautstärken schaden euch und euren Boxen/Verstärkern oder allem, was sonst dazwischen hängt. Geht die Sache verantwortungsvoll an und ihr werdet viel Spaß haben.}}&lt;br /&gt;
&lt;br /&gt;
==Voreinstellungen==&lt;br /&gt;
&lt;br /&gt;
Um direkt Töne aus den Boxen zu zaubern, werden wir uns der FMOD Bibliothek bedienen. Ich habe hier nicht vor, diese Bibliothek bis ins Kleinste zu erklären. Es dürfte genügen, wenn ihr euch die zugehörigen Tutorials anschaut. Zum Abspielen werden wir uns der Callbackfunktionalität der Bibliothek bedienen, d.h. FMOD ruft eine von uns definierte Funktion immer wieder auf. Diese wird dann die nächsten, gesampelten Daten zurückgeben, so dass diese dann auf der Soundkarte ausgegeben werden.&lt;br /&gt;
&lt;br /&gt;
Da FMOD eine ganze Reihe Treiber für unterschiedliche Soundsysteme mitbringt, müssen ein paar Einstellungen getroffen werden. Damit das nicht bei jedem Programmstart geschieht, habe ich ein kleines Programm geschrieben, dass für alle der hier geschriebenen Programme entsprechende Voreinstellungen trifft und abspeichert. Bevor ihr weitermacht, startet einmal '''fmodconf''', stellt das ganze eurem System entsprechend ein und drückt auf Save:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_konfiguration.png]]&lt;br /&gt;
&lt;br /&gt;
==Der erste Ton==&lt;br /&gt;
&lt;br /&gt;
Der einfachste Ton, der von unserem Gehör als eindeutig nur zu einer Frequenz zugeordnet wird, lässt sich mit einer Sinuskurve beschreiben. Das gleiche erzeugen im übrigen auch gute Stimmgabeln, mit denen ihr sicherlich schon alle einmal im Physik- oder Musikunterricht Freundschaft schliessen konntet. Das ganze klingt sehr dünn, aber das ist genau das, was ich euch zeigen möchte.&lt;br /&gt;
&lt;br /&gt;
Zuerst sollten wir jedoch ein paar wesentliche Begriffe einer Welle klären:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_welle.png]]&lt;br /&gt;
&lt;br /&gt;
Dieses Diagramm zeigt den durch ein gutes Mikrofon erzeugten Verlauf der Spannung auf der Zeit an, wenn eine angeschlagene Stimmgabel einen Ton erzeugt.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable}}&lt;br /&gt;
|'''Amplitude(A)''': Der Betrag des stärksten Ausschlags der Welle. Eine grössere Amplitude erzeugt einen lauteren Ton - und umgekehrt.&lt;br /&gt;
|-&lt;br /&gt;
|'''Periodendauer(T)''': Die Dauer einer vollständigen Schwingung.&lt;br /&gt;
|-&lt;br /&gt;
|'''Frequenz''': Die Zahl der vollständigen Schwingungen in einer Zeiteinheit. Sie wird üblicherweise pro Sekunde betrachtet:&lt;br /&gt;
&lt;br /&gt;
:f = 1 / T Einheit: 1/s=1Hz&lt;br /&gt;
 &lt;br /&gt;
:Die Frequenz eines Tones bestimmt indirekt auch die empfundene Lautstärke, da durch die mechanische Übertragung des Schalls in unserem Ohr bestimmte Frequenzbereiche besser, andere schlechter übertragen werden.&lt;br /&gt;
|-&lt;br /&gt;
|'''Schallgeschwindigkeit''': Die Geschwindigkeit, mit der sich der Schall vorwärtsbewegt: 331 m/s in der Luft.&lt;br /&gt;
|-&lt;br /&gt;
|'''Wellenlänge''': Ist die Länge einer Welle. Sie errechnet sich aus der Schallgeschwindigkeit geteilt durch die Frequenz.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nun wollen wir also eine Stimmgabel mit dem Computer simulieren. Alles was wir dazu machen müssen, ist eine Sinuskurve an FMOD zu übergeben. Wie bereits erklärt, wird eine Sekunde in eine Reihe Sampels zerlegt. Wir wollen mit einer Scrollbar die Frequenz des Tones einstellen können:&lt;br /&gt;
&lt;br /&gt;
'''ssynth1:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  Pos : Integer;&lt;br /&gt;
  Freq : Integer;&lt;br /&gt;
&lt;br /&gt;
function StreamCallback(Stream: PFSoundStream; Buff: Pointer; Len, Param: Integer): ByteBool; stdcall;&lt;br /&gt;
var&lt;br /&gt;
  Count: Integer; &lt;br /&gt;
  Buffer: PChar;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  Freq := SinGenForm.FreqBar.Position;&lt;br /&gt;
  Buffer := PChar(Buff);&lt;br /&gt;
  Count := 0;&lt;br /&gt;
&lt;br /&gt;
  while Count &amp;lt; (Len div 4) do	{ div 4 = 16bit stereo (4 bytes per sample) }&lt;br /&gt;
  begin&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Sin(2*Pi/SamplingRate*Freq*Pos) * (32767.0/2.0));    { Left channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Sin(2*Pi/SamplingRate*Freq*Pos) * (32767.0/2.0));   { Right channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
&lt;br /&gt;
    Inc(Count);&lt;br /&gt;
    Inc(Pos);&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  Result := True;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Variable Pos dient dem linearen Voranschreiten in unserer Sinuskurve. Durch das Teilen durch die Sampling-Rate erreichen wir, dass jede Sekunde ein Bereich von '''k''' bis '''k+1''' durchlaufen wird, also ein Intervall der Länge '''1: [0..1]+k'''; Wenn durch unsere Zählvariable jede Sekunde ein Bereich der Länge '''1''' durchlaufen wird, wird die Sache für uns viel einfacher. Durch die Multiplikation mit der Frequenz, wird dann nämlich ein Intervall von '''[0..Freq]''' durchlaufen und wir sind nahe dran an dem, was wir haben wollen. Wir müssen nur bedenken, dass der Sinus eine volle Schwingung im Bereich '''[0..2*Pi]''' beschreibt, also multiplizieren wir mit '''2*Pi''' und erzeugen damit eine Sinus-Kurve, die in einer Sekunde '''Freq''' viele Schwingungen macht. Es wird Zeit zum Ausprobieren von synth1. Das Programm ist im im übrigen auf den Kammerton a: 440Hz voreingestellt - nur damit wir gleich mal den Bezug zur Musik herstellen. ;-)&lt;br /&gt;
&lt;br /&gt;
==Die Schwebung==&lt;br /&gt;
&lt;br /&gt;
Wir wollen unserer Stimmgabel eine weitere, gleichlaute Stimmgabel hinzufügen. Diese ist um wenige Frequenzteile verstimmt, so dass die Frequenzen wirklich sehr nahe beieinander liegen. Mit unserer Scrollbar wollen wir diesmal nicht einen großen Frequenzbereich abdecken, sondern nur eine Möglichkeit zum manipulieren des Anteils schaffen. Die Hauptfrequenz legen wir auf 880 Hz fest. Freundlicherweise genügt es, die zweite Stimmgabel durch Addition einer zweiten Sinuskurve hinzuzufügen - wir müssen nur darauf achten, dass wir dann in dem uns begrenzenden Werteintervall bleiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_schwebgen.png]]&lt;br /&gt;
&lt;br /&gt;
Bewegt man den Regler an den äusseren Rand, so nimmt man zwei erkennbar unterschiedliche Töne wahr. Kommt man der Mitte näher, verändert sich das Klangbild stark. Es entsteht eine art Pulsierender Ton. Dieser Effekt kommt häufig in Musikinstrumenten zum Einsatz, so hat jede Taste im Klavier drei zugehörige Saiten, die leicht gegeneinander verstimmt sind, so dass sie einen schwebungstypischen Klang erzeugen.&lt;br /&gt;
&lt;br /&gt;
Wer will, soll einmal einen typischen Audioeditor starten, etwa den kostenlosen Audacity, und betrachte damit einmal den Funktionsgraphen. Einen derartigen Audioeditor solltet ihr für eure Versuche immer parat halten, um bei bedarf mal genau hinzusehen, was ihr da eigentlich erzeugt und ob das dem entspricht, was ihr euch vorgestellt habt.&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|&lt;br /&gt;
Um die Ergebnisse der bislang gemachten Versuche bestaunen zu können, startet den jeweiligen Generator und nehmt einfach ein Stück mit einem Audioeditor auf. Vergesst dabei nicht, die Aufnahmeeinstellungen der Soundkarte entsprechend anzupassen.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
'''ssynth2:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function StreamCallback(Stream: PFSoundStream; Buff: Pointer; Len, Param: Integer): ByteBool; stdcall;&lt;br /&gt;
var&lt;br /&gt;
  Count: Integer;&lt;br /&gt;
  Buffer: PChar;&lt;br /&gt;
  Value : Single;&lt;br /&gt;
  Delta : Single;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  Freq := 880;&lt;br /&gt;
  Buffer := PChar(Buff);&lt;br /&gt;
  Count := 0;&lt;br /&gt;
&lt;br /&gt;
  Delta := 1.0 + (1/10000.0 * SchwebGenForm.PercentBar.Position);&lt;br /&gt;
&lt;br /&gt;
  while Count &amp;lt; (Len div 4) do		&lt;br /&gt;
  begin&lt;br /&gt;
    Value := (Sin(2*Pi/SamplingRate*Freq*Pos) + Sin(2*Pi/SamplingRate*Freq*Pos*Delta));&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Value * (32767.0/2.0));    { Left channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Value * (32767.0/2.0));   { Right channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
&lt;br /&gt;
    Inc(Count);&lt;br /&gt;
    Inc(Pos);&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  Result := True;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Andere Wellenformen==&lt;br /&gt;
&lt;br /&gt;
Statt Sinusförmigen Wellen, bietet es sich an, pulsierende, dreieckige oder jegliche Arten anderer, (periodischer) Funktionen zu verwenden. Diese klingen dann teilweise etwas ungewöhnlich, aber wesentlich voller als der typische Sinuston. Dies liegt daran, dass, würde man die Graphen aus Sinuskurven nachbauen, so würde man die Sinus-Graphen aus ganzen Frequenzbändern benötigen, wodurch das gehörte Frequenzspektrum natürlich stark zunimmt. Der Effekt: Der Ton hört sich wesentlich voller an.&lt;br /&gt;
&lt;br /&gt;
Ein wertvolles Hilfsmittel zur Analyse der dadurch &amp;quot;betonten&amp;quot; Frequenzbereiche ist die Fourier Analyse. FMOD bietet eine leicht zugängliche API, um eine ganze Reihe Frequenzbänder zu untersuchen. Das bedeutet für uns: Ab sofort benötigt jeder unserer Synthesizer ein Display zur Frequenzanalyse. Leider sind diese Analysen nie so recht perfekt, aber um einen Eindruck der belegten Frequenzen zu erhalten, genügt es allemal.&lt;br /&gt;
&lt;br /&gt;
===Sinus===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_sinus.png]]&lt;br /&gt;
&lt;br /&gt;
Der altbekannte Sinus muss natürlich zum Vergleich wieder mit dabei sein:&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function SinWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := Sin(2*Pi*x);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Dreieck===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_dreieck.png]]&lt;br /&gt;
&lt;br /&gt;
Das Dreieck klingt ähnlich wie der Sinus, nur ein wenig voller. Dass beide sehr verwand sein müssen, lässt sich ja bereits am Graphen erkennen.&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function DreieckWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := Abs(frac(x) - 0.5) * 4 - 1;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sägezahn===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_saegezahn.png]]&lt;br /&gt;
&lt;br /&gt;
Der Sägezahn klingt dann schon wesentlich voller und bissiger, aber macht euch am besten selbst ein Bild - man muss es gehört haben, um zu wissen wie es klingt ;-)&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function SaegezahnWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := (-1 + 2 * frac(x));&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Puls===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_puls.png]]&lt;br /&gt;
&lt;br /&gt;
Der Puls schlägt dann schon sehr aus der Reihe. Durch Veränderunge der Länge der gleichartigen Bereiche, kann man den klang sehr gut und einfach manipulieren.&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function PulseWave(x: Single): Single;&lt;br /&gt;
  function Sgn(x : Single) : Single;&lt;br /&gt;
  begin&lt;br /&gt;
    if x &amp;lt; 0 then&lt;br /&gt;
      Result := -1.0&lt;br /&gt;
    else&lt;br /&gt;
      Result := +1.0;&lt;br /&gt;
  end;&lt;br /&gt;
begin&lt;br /&gt;
  Result := Sgn(frac(x) - IrgendwasZwischen0undEinhalbes);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Rauschen===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_rauschen.png]]&lt;br /&gt;
&lt;br /&gt;
Nun, dieser Klang ist sehr charakteristisch und ich vermute jeder kennt ihn längst ;-) Wers nicht erkennt, möge ihn sich anhören.&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function RauschenWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := (Random -0.5)*2;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Hausgemachte Ober- und Untertöne==&lt;br /&gt;
&lt;br /&gt;
Durch unterschiedliche Wellenformen können wir nun unseren Tönen etwas mehr Fülle verleihen. Es bietet sich jedoch noch eine weitere Möglichkeit an: Obertöne. Statt einer einzelnen Sinuskurve werden hier eine ganze Reihe an Sinuskurven übereinandergelegt. Deren Amplitude ist immer etwas geringer, als die des Haupttones, deren Frequenz jedoch um den Faktor 2^n erhöht:&lt;br /&gt;
&lt;br /&gt;
'''ssyth4:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Ton :=       20 * SinWave(x);&lt;br /&gt;
Ton := Ton + 10 * SinWave(x*2); //1 Oktave  höher als der Grundton&lt;br /&gt;
Ton := Ton + 7  * SinWave(x*4); //2 Oktaven höher als der Grundton&lt;br /&gt;
Ton := Ton + 5  * SinWave(x*8); //3 Oktaven höher als der Grundton&lt;br /&gt;
...&lt;br /&gt;
Ton := 1.0/(20+10+7+5+...)*Ton;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Äquivalent kann man auch Untertöne erzeugen: Statt Oktavschritte nach oben, geht man Oktavschritte mit der Frequenz nach unten (teilen durch 2):&lt;br /&gt;
&lt;br /&gt;
'''ssyth4:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Ton :=       20 * SinWave(x);&lt;br /&gt;
Ton := Ton + 10 * SinWave(1/2*x); //1 Oktave  niedriger als der Grundton&lt;br /&gt;
Ton := Ton + 7  * SinWave(1/4*x); //2 Oktaven niedriger als der Grundton&lt;br /&gt;
Ton := Ton + 5  * SinWave(1/8*x); //3 Oktaven niedriger als der Grundton&lt;br /&gt;
...&lt;br /&gt;
Ton := 1.0/(20+10+7+5+...)*Ton;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Hüllkurven oder Attack, Decay, Sustain, Release Envelopes==&lt;br /&gt;
&lt;br /&gt;
Obwohl sich das alles noch sehr langweilig anhört und an sich nicht wesentlich mehr als ohrenbetäubendes quietschen ist, sind wir schon sehr weit fortgeschritten. Eigentlich fehlt uns gar nicht mehr viel, um wohlgeformte Klänge aus den Boxen zu zaubern. Bevor wir das jedoch tun können, benötigen wir noch ein kleines Hilfsmittel: eine Hüllkurve. Das ist an sich nicht mehr, als ein simulierter Lautstärkenverlauf des Anschlages eines Instrumentes, der sich bei vielen Instrumenten in 4 Teilbereiche aufspaltet:&lt;br /&gt;
&lt;br /&gt;
'''Attack''': Der Attack-Teil beschreibt den Lautstärkenverlauf direkt beim und nach dem Anschlag. Die Saite gibt vorerst keinen Ton von sich. Durch Zupfen oder Anschlagen schnellt der von ihr erzeugte Schalldruck in kurzer Zeit auf sein Maximum. Danach fällt die Lautstärke während der '''Decay-Phase''' auf einen mittleren Wert zurück, verweilt dann in der '''Sustainphase''' eine Zeit lang auf nahezu konstantem Niveau (für uns soll echt konstant genügen), worauf sich die '''Releasephase''' anschliesst, in der der Ton - häufig gedämpft - ausklingt:&lt;br /&gt;
&lt;br /&gt;
Prinzip einer ADSR_Hüllkurve:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_adsr-prinzip.png]]&lt;br /&gt;
&lt;br /&gt;
Zur Lautstärkenregulierung bietet sich die Amplitude unserer Wellenfunktionen an, die wir ganz einfach durch Multiplikation des Sampels mit einem Wert zwischen Null und Eins nach belieben manipulieren können. Daneben müssen wir jedoch beachten, dass unser Gehör auf exponentiell steigende &amp;quot;Werte&amp;quot; geeicht ist, der einfache Kurvenverlauf auf dem obigen Bild würde seltsam klingen. Wandeln wir den Graphen also ein wenig um:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_adsr-huellfunktion.png]]&lt;br /&gt;
&lt;br /&gt;
Mithilfe der '''exp''' Funktion sollte ein Jeder imstande sein, eine entsprechende Funktion zusammenzustöpseln.&lt;br /&gt;
&lt;br /&gt;
'''Etwas ADSR-Hüllkurvenquellcode:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function ADSREnvelope(t, a, d, s, r, maxlevel, holdlevel : Single): Single;&lt;br /&gt;
const&lt;br /&gt;
  e = 2.71828182846;&lt;br /&gt;
&lt;br /&gt;
  Start = -4.65;&lt;br /&gt;
  Intervallaenge = 1.0 - Start;&lt;br /&gt;
&lt;br /&gt;
var&lt;br /&gt;
  Pos, x, delta : Single;&lt;br /&gt;
begin&lt;br /&gt;
  if t &amp;lt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    Result := 0;&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Attack&lt;br /&gt;
  Pos := a;&lt;br /&gt;
  if t &amp;lt; Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    x := 1.0 - t/a; //x zwischen 0 und 1&lt;br /&gt;
    x := x * Intervallaenge + Start; //x auf das Intervall mappen&lt;br /&gt;
    Result := (1.0 - 1/e*(Power(e, x)))*maxlevel;&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Decay&lt;br /&gt;
  Pos := Pos + d;&lt;br /&gt;
  if t &amp;lt;= Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    delta := maxlevel - holdlevel;&lt;br /&gt;
    if delta &amp;lt;= 0.0 then&lt;br /&gt;
    begin&lt;br /&gt;
      Result := holdlevel;&lt;br /&gt;
      Exit&lt;br /&gt;
    end;&lt;br /&gt;
    x := 1.0 - (t - Pos + d)/d;&lt;br /&gt;
    x := x * Intervallaenge + Start;&lt;br /&gt;
    Result := Maxlevel - (1.0 - 1/e*(Power(e, x)))*delta;&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Sustain&lt;br /&gt;
  Pos := Pos + s;&lt;br /&gt;
  if t &amp;lt;= Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    Result := holdlevel;&lt;br /&gt;
    Exit&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Release&lt;br /&gt;
  Pos := Pos + r;&lt;br /&gt;
  if t &amp;lt;= Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    x := 1.0 - (t - Pos + r)/r;&lt;br /&gt;
    x := x * Intervallaenge + Start;&lt;br /&gt;
    Result := holdlevel - holdlevel * (1.0 - 1/e*(Power(e, x)));&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  Result := 0.0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich benötigen wir noch ein paar weitere Hüllkurven, die ich hier jedoch etwas weniger ausführlich beschreiben werde:&lt;br /&gt;
&lt;br /&gt;
Eine Attack-Sustain-Release-Hüllkurve hat, wie ihr Name verrät 3 Phasen. Im Attack Bereich schwillt die Lautstärke auf ihr Maximum, bleibt dann im Sustain Bereich auf diesem Niveau, um schließlich wieder wie gehabt in der Release-Phase abzufallen.&lt;br /&gt;
&lt;br /&gt;
Eine abbrechbare Attack-Decay-Hüllkurve: Der Attack Bereich ist wie gehabt. In der Decay-Phase fällt die Lautstärke bis auf das Null Niveau ab. Dieser Vorgang kann jedoch an jeder beliebigen Stelle abgebrochen werden und in eine gedämpfte Release-Phase übergehen.&lt;br /&gt;
&lt;br /&gt;
==Ein paar synthetische Musikinstrumente==&lt;br /&gt;
&lt;br /&gt;
Nun wird es wirklich einmal Zeit, Töne zu erzeugen, bei denen man sich nicht nach kürzester Zeit gequält die Ohren zuhalten muss. Eine gute Möglichkeit dies zu erreichen, besteht darin echte Musikinstrumente zu simulieren. Die einfachen Mittel, die wir bis jetzt kennengelernt haben, reichen dafür völlig aus. Ich werde hier nicht an jeder Stelle Quellcodes mitliefern, ein Blick in die Dateien des synth5 Projektes sollte jedoch Klarheit schaffen. Beim Nachstellen eines Instrumentes ist v.a. ein wenig mit den Parametern spielen angesagt - den Spaß will ich euch nicht nehmen. Viele meiner Instrumente sind sicherlich noch verbesserungsfähig.&lt;br /&gt;
&lt;br /&gt;
===Klavier===&lt;br /&gt;
&lt;br /&gt;
Das Öffnen eines Klavieres kann uns sehr dabei helfen, herauszufinden, wie wir einen Ton synthetisieren müssen. Das typische Klavier besitzt 52 weiße Tasten, die mechanisch die ihnen zugehörigen Saiten mit einem Hammer anschlagen. Zu jeder Taste gehören 3 gespannte, metallische Saiten, die leicht gegeneinander verstimmt sind, so dass eine Schwebung entsteht. Ein Klavier hat einen sehr vollen Ton, so dass wir davon ausgehen können, dass jeder Ton aus einer ganzen Reihe an sinusförmigen Obertönen besteht.&lt;br /&gt;
&lt;br /&gt;
Kommen wir noch zu unserer Hüllkurve: Durch den Anschlag mit dem Hammer steigt die Lautstärke schnell auf ihr Maximum. Bei längerem Tastendruck fällt die Lautstärke langsam ab und wird nach dem loslassen stark gedämpft (Durch Benutzung der unteren Pedale lässt sich hier viel verändern - d.h. hier kann man ruhig ein wenig variieren und herumspielen). Wesentlich an den Hüllkurven ist jedoch, dass die einzelnen Abschnitte der AD-Hüllkurve in ihrer Länge von der Frequenz des Grundtones abhängig sind, weshalb man die Längen nicht in Zeitdauern angibt, sondern durch die Zahl der Schwingungen.&lt;br /&gt;
&lt;br /&gt;
===Klavinett===&lt;br /&gt;
&lt;br /&gt;
Das Klavinett ist dem Klavier sehr sehr ähnlich. Um seine etwas rauheren Töne zu synthetisieren eignen sich Dreiecke oder Sägezähne sehr gut. Mit Dreiecken klingt das Klavinett ziemlich sanft, mit Sägezähnen dagegen schon sehr hart - was die zweite Variante in Verbindung mit tiefen Tönen sehr imposant erscheinen lässt. An den Hüllkurven des Klaviers muss man dagegen nichts ändern.&lt;br /&gt;
&lt;br /&gt;
===Flöte===&lt;br /&gt;
&lt;br /&gt;
Wir wollen uns hier mit einer einfachen Flöte begnügen: Man nehme eine ASR-Hüllkurve und eine Dreiecks-Schwingung. Testweise kann man auch einen Sägezahn ausprobieren, der dann zwar nicht mehr nach einer Flöte klingt, jedoch in den tiefen Tönen sehr schöne Ergebnisse liefert. Die Attack und Release Zeiten sollten sich ähneln. Üblicherweise wählt man sie rel. kurz.&lt;br /&gt;
&lt;br /&gt;
===Glocken===&lt;br /&gt;
&lt;br /&gt;
Glocken geben einen sehr untertonreichen, feinen Klang von sich, entsprechend wählt man als Wellenfunktion den Sinus. Bei vielen Glocken lässt sich auch eine Schwebung heraushören. Als Hüllkurve wählt man wie beim Klavier einen AD-Envelope.&lt;br /&gt;
&lt;br /&gt;
==Oktaven, Halbtöne und was sonst dazugehört==&lt;br /&gt;
&lt;br /&gt;
Wer sich Synth5 schon ein wenig genauer angeschaut hat, wird festgestellt haben, dass sich dort die Frequenzen für die Töne nicht mehr frei wählen lassen, sondern eine Klaviatur zur Eingabe dient. Wollen wir also ein paar Worte zur Berechnung der Frequenzen, die zu den einzelnen Tasten gehören, verlieren:&lt;br /&gt;
&lt;br /&gt;
Ein Oktavschritt verdoppelt die Frequenz, um also vom Kammerton a auf a' zu kommen, muss 440Hz * 2 gerechnet werden (Kammerton a ist auf 440Hz bzw. 436Hz festgelegt).&lt;br /&gt;
&lt;br /&gt;
Eine Oktave soll dann in 12 Teile zerlegt werden, so dass durch Multiplikation mit einem Faktor der nächst höhere Ton entsteht: Da eine Oktave einer Frequenzverdoppelung entspricht, muss für einen Halbton mit dem Faktor 12te Wurzel aus 2 = 2^(1/12) multipliziert werden.&lt;br /&gt;
&lt;br /&gt;
==Abschluss==&lt;br /&gt;
&lt;br /&gt;
Wer etwa 14 MB Festplattenplatz frei hat, möge einmal [http://files.delphigl.com/new/softsynth_src.zip synth_test] starten, um Beethovens Für-Elise mit Glocken gespielt zu hören. Wenn Interesse besteht, werde ich den Synthesizer vielleicht auch noch vor dem Projekt veröffentlichen, zu dem er eigentlich gehört: Ein bisschen Feedback wäre sicher angebracht.&lt;br /&gt;
&lt;br /&gt;
Ich hoffe eure Ohren haben diesen Angriff meinerseits gut überstanden. Vielleicht konnte ich dieses Thema ja halbwegs entmystifizieren, wo es doch eigentlich eine ganz andere Thematik als die üblichen DGL Tutorials beschreibt. Ich fand es jedenfalls faszinierend, hier in eine auch für mich bis dato völlig unbekannte Welt vorzustossen, wobei das Meiste einfach aus reinem Ausprobieren entstanden ist. Gut, ich muss zugeben, dass ich hin und wieder in ein altes Buch zum Synthesizer löten gespickt habe und auch mein Dad hi und da mit Rat zur Seite stand - tagelanges rumspielen mit Geräuschen, die durchs gesamte Haus hallen können nunmal nicht ungehört bleiben. Jemand, der selbst in seinen jüngeren Jahren einmal einen Synthesizer gebaut hat, lässt es eben nicht kalt, wenn bekannte Geräusche ertönen - wenn auch nicht analog mit Schaltungen, sondern digital erzeugt ;-).&lt;br /&gt;
&lt;br /&gt;
Euer Delphic&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Multithreading]] |-}} &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Software-Synthesizer]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=25849</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=25849"/>
				<updated>2013-09-25T14:30:55Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
Immer wieder muss ich feststellen, dass viele, die (mit OpenGl) 3D Anwendungen schreiben, nichts mit der Mathematik dahinter anfangen können. Um das Ein oder Andere zu verstehen oder sich selbst überlegen zu können, ist dieses Wissen aber unabdingbar. Ich möchte mit diesem Artikel helfen, diesen Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
Man stelle sich vor, man hat einen Kreis, mit Radius 1. Der Mittelpunkt des Kreises befindet sich auf dem Koordinatensystem Ursprung. An der X-Achse ist ein Winkel ß angetragen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
An der x-Achse bildet sich dann ein rechter Winkel (wichtig für normale Trigonometrie). Die diesem Winkel gegenüberliegende Seite(r) nennt man Hypotenuse. Die am Winkel ß anliegende Seite(x) ist die Ankathete. Die dem Winkel gegenüberliegende Seite(y) heißt Gegenkathete. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
für ß im Bereich 0° - 90°. In den anderen Quadranten des Koordinatensystems, sind die Umkehrfunktionen nicht für alle Winkel eindeutig zurückzurechnen, hier muss man also ein wenig aufpassen, z.B. gibt arcsin(sin(ß)) im Bereich 90°-180° den Winkel 180° - ß aus. Im übrigen ist darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, dass [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Außenpunkte dieser Kreise (als Radius gezogen auf der x/z-Ebene), bei entfernter Betrachtung, selbst wieder einen Kreis (hier blau gezeichnet) beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
Ich denke, zu den 3 ersten Koordinaten muss ich nichts weiter sagen, zur w-Koordinate hingegen schon: w ist normalerweise immer 1.0. Mit glVertex4 kann bei Bedarf auch ein anderer Wert zugewiesen werden. Ist w ungleich Null, so wird ein Vertex als folgender 3-Dimensionaler Punkt interpretiert: (x/w, y/w, z/w). Im Normalfall sollte der Wert für w aber auf 1.0 belassen werden, es sei denn man hat eine interessante Idee, die sich mit einem w ungleich 1.0 besonders schön realisieren lässt. Wen die w-Koordinate interessiert, sollte in der OpenGl Spezifikation unter Coordinate Transformations nachschauen.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel für die Effekt beim Einsatz von w Koordinaten: Beim ersten Dreieck ist im oberen Punkt w = 1.0, im 2. ist w = 0.5:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verschiebung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Unser Ziel ist, dass x_neu gleich x ist. Das lässt sich immer erreichen, indem wir den Koeffizienten a[1,1] = 1.0 setzen und die restichen = 0. Dann steht da nämlich:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die gleiche Überlegung kann man auch für die Anderen 3 Elemente y,z und w machen. Jede dieser Überlegungen ergibt eine Zeile der Identitätsmatrix. Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, wenn man ihn auch noch aus verschiedenen Blickwinkeln anschauen und frei drehen kann. Den meisten dürfte damit schon klar sein, worauf ich hinaus will: Drehungen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-). Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1.0, 0.0, 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]] &lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spaß und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber erklären, was sie tun und was man damit anstellen kann. Wer diese Operationen verwenden möchte, sollte mal auf Mike Lischkes Homepage vorbeischaun. Dort findet ihr eine Geometry.pas, die diese Funktionen und noch viele mehr beinhaltet. Eine etwas verbesserte und immer wieder aktualisierte Variante liegt dem glScene Projekt bei. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
Eine wichtige Operation ist die Matrixmultiplikation. Sie verbindet zwei Matrizen zu einer so, dass sie nacheinander ausgeführt werden. Dabei ist zu bedenken, dass die Reihenfolge einen Unterschied macht: erst drehen und dann verschieben ist ungleich erst verschieben und dann drehen, aber das solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
Eine invertierte Matrix macht genau das Gegenteil der ursprünglichen Matrix. Verschiebt die ursprüngliche ein Vertex um 3 nach rechts, so schiebt die intervtierte Matrix ein Vertex um 3 nach links (Achtung: nicht alle Matrizen sind invertierbar, Rotations- und Translationsmatrizen lassen sich jedoch immer invertieren). Dies lässt sich sinnvoll bei Kameras einsetzen:&lt;br /&gt;
&lt;br /&gt;
Man hat ein Objekt, dessen Rotation durch eine Matrix beschrieben wird, was generell sinnvoll ist, wenn das Objekt voneinander abhängige Drehungen vollführen soll oder man das lokale Koordinatensystem des Objekts benötigt. Jedenfalls will man nun das Objekt nicht von außen bestaunen, sondern sich in die Ansicht des Objekts selbst hineinversetzen, so kann man dessen Rotationsmatrix einfach invertieren und schon hat man sein Ziel erreicht. Wen ähnliches interessiert, sollte sich jetzt einmal an mein [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
Wie hat man sich gefreut, als man glaubt Matrizen endlich ein wenig verstanden zu haben und dann das! Die ersten Versuche mit [[glLoadMatrix]] und [[glMultMatrix]] müssen zwingend schiefgehen. Immer, wenn man nicht vorgewarnt wird. Wer glaubt seine Matrizen einfach mit einem 2 Dimensionalen Array beschreiben zu können irrt. Die Idee ist zwar nicht schlecht, aber aus Performancegründen liegen die OpenGl Matrizen nicht zeilenweise, sondern spaltenweise im Speicher:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ich persönlich bevorzuge meist, statt dass ich in einem 2D-Array immer mit den Zugriffsvariablen herumwurschtle, den Zugriff auf die Matrix mit einem eindimensionalen Array. Die obige Tabelle hilft, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
Ahh, wieder eines meiner schrecklichen Tutorials überlebt. Ich hoffe, dass wenigstens ein paar Leute unter euch das ein oder andere Verstanden haben und ich das alles nicht umsonst geschrieben habe (wenns nur einer Verstanden hat, bin ich schon glücklich ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
Delphic&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Kamera1&amp;diff=25848</id>
		<title>Tutorial Kamera1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Kamera1&amp;diff=25848"/>
				<updated>2013-09-25T14:30:35Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Dreht sich das Universum um uns und andere philosophische Fragen=&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Sicherlich standen schon einige von euch vor dem Problem, wie man denn eine Kamera in OpenGl implementieren könnte. Es stellen sich einem dabei viele Probleme, z.B. wie kann ich die Kamera auf ein Objekt ausrichten. Oder wie sieht es mit Billboarding aus? Die Liste kann fast unendlich erweitert werden. Ich werde versuchen, ein paar dieser Probleme zu lösen und vielleicht schaffe ich es sogar, den Einen oder Anderen dazu zu bringen, selbst eigene Kameratechnische Probleme zu lösen.&lt;br /&gt;
&lt;br /&gt;
Wer SchodMC's Objekt xxx Tutorials gelesen hat, hat übrigens schon einiges an Vorwissen, das er hier prima wiederverwerten kann. Ich kann die Lektüre dieser gut gelungenen Werke vor dem Weiterlesen nur wärmstens empfehlen.&lt;br /&gt;
&lt;br /&gt;
==Die Kamera Analogie==&lt;br /&gt;
Dreht sich die Erde um die Sonne oder die Sonne um die Erde? Ist euch bewusst, dass diese Frage eigentlich nicht zu beantworten ist? Tatsächlich macht es, wenn man richtig darüber nachdenkt keinen Unterschied. Das könnt ihr selber überprüfen: Geht vor eure Haustür und stellt euch hin (pfui, es regnet - nein, macht es doch lieber drinnen). Dreht euch einmal im Kreis. Was habt ihr gesehen? Habt ihr euch nun im Universum gedreht oder das ganze Unviversum um euch herum? Eine seltsame Frage? ... Vielleicht hat`s der Ein oder Andere schon bemerkt... Für den Mensch der sich da grad im Regen gedreht hat, wäre beides denkbar. Tatsächlich macht es für das Auge keinen Unterschied. Es handelt sich nur um ein philosophisches Problem, besonders eines der westlich geprägten Welt, das ihr zu überwinden habt. Alles dreht sich um euch, nicht ihr darin. Also: Dreht ihr euch nach rechts, ist das gleichbedeutend damit, dass sich das Univerum unter euren Füssen nach links gedreht hat. Noch Fragen?&lt;br /&gt;
&lt;br /&gt;
In der Hoffnung euch jetzt alle komplett verwirrt zu haben, mache ich jetzt einfach mal weiter.&lt;br /&gt;
&lt;br /&gt;
==Darstellung von Objekten==&lt;br /&gt;
Bevor wir irgendwelche Objekte zeichnen, müssen wir uns erst einmal eine Welt ausdenken. Der zweite Punkt ist dann, zu definieren, wie diese Objekte dargestellt werden sollen. Mir sind unterschiedliche Ideen gekommen, die sich alle mit mehr oder weniger Aufwand realisieren lassen.&lt;br /&gt;
&lt;br /&gt;
Letztendlich habe ich mich an einer Weltraumszene festgehängt. Hier lässt sich so einiges zeigen. Besonderen dank an [http://www.delphigl.de Sascha Willems], der - freundlich wie er ist - gestattete, einen Satz seiner Texturen einzusetzen und gleich noch ein Paar Orte verriet, an denen man gute Sonnensystem-Texturen finden kann.&lt;br /&gt;
&lt;br /&gt;
Kommen wir nun zu den Objekten selbst. Wir wollen hier ein wenig OOP verwenden. Das bietet sich an, da es in unserem Fall vorteilhaft ist, einige Objekte voneinander abzuleiten zu können. Alle Objekte müssen 2 Eigenschaften besitzen: Position und Rotationsmatrix:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;  type&lt;br /&gt;
    //Basis Objekt&lt;br /&gt;
    TObjekt = class&lt;br /&gt;
    private&lt;br /&gt;
    public&lt;br /&gt;
      ObjektName : String;&lt;br /&gt;
      Rotation  : THomogeneousMatrix;&lt;br /&gt;
      Position  : TVertex;&lt;br /&gt;
      constructor Create; virtual;&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um die Planeten darzustellen, werden unterschiedliche Nachfolger dieses Objektes verwendet. Ich will auf diese nicht weiter eingehen, da sie an sich nichts mit unserem eigentlichem Interessensgebiet zu tun haben - den Kameras.&lt;br /&gt;
&lt;br /&gt;
==Das Kameraobjekt==&lt;br /&gt;
Bevor wir uns daran machen, über die Implementierung nachzudenken, sollten wir überlegen, was wir eigentlich haben wollen. Eine Kamera, das ist klar. Was soll sie können? Sie soll einmal aus der Sicht des Objektes schauen können, ein Objekt fest in den Blick nehmen und auch eine freie Ansicht bieten (Freie Bewegungen sind bislang nicht in den Beispielsource mit eingebaut. Eine freie Ansicht hingegen schon - steuerbar mit dem Joystick). Wir wollen aber keine stationäre Kamera, sondern eine die sich gleich noch mehr oder weniger automatisch bewegt.&lt;br /&gt;
&lt;br /&gt;
Wir brauchen außerdem die Möglichkeit, unterschiedliche Modi einzustellen und Zielobjekte festzulegen. Nicht zu vergessen auch eine Funktion, die eine Kameramatrix erzeugt und diese auch noch gleich an OpenGL weitergibt.&lt;br /&gt;
&lt;br /&gt;
Dies sollte uns für den Anfang erst einmal genügen. Fangen wir also an, uns die gewünschte Kamera zu bauen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    TLookMode = (lmFree, lmObjektSight, lmLookAtObjekt);&lt;br /&gt;
    TMoveMode = (mmFree, mmAttatched);&lt;br /&gt;
    TKamera = class(TObjekt)&lt;br /&gt;
    private&lt;br /&gt;
    public&lt;br /&gt;
      LookMode : TLookMode; //Ansichtsmodus&lt;br /&gt;
      MoveMode : TMoveMode; //Bewegungsmodus&lt;br /&gt;
&lt;br /&gt;
      LookTarget, MoveTarget : TKugel; //Ansichtsziel und Bewegungsziel&lt;br /&gt;
&lt;br /&gt;
      procedure UseMatrix; virtual; //Kamera-Matrix einsetzen&lt;br /&gt;
      constructor Create; override;&lt;br /&gt;
      procedure ResetView; //Ansicht zurücksetzen&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
==Implementation der Kameramodi==&lt;br /&gt;
===lmFree und lmObjektSight===&lt;br /&gt;
&lt;br /&gt;
Diese Modi haben einige Gemeinsamkeiten. lmObjektSight steht für die Blickrichtung, die ein Objekt hat, lmFree ist die frei wählbare Variante. Häufig gleichen sich diese Modi, wenn man z.B. das Objekt von dem aus man in die Welt schaut gleich auch vom Spieler gesteuert wird. Von der Implementierung her sind sie fast Identisch. Das Problem besteht darin, dass die Kameramatrix genau anders herum drehen muss, als wie das Objekt gedreht ist (siehe Kamera Analogie). Die Mathematiker haben das Problem für uns schon gelöst - mit invertierten Matrizen. Wir müssen also nicht einmal das Rad neu erfinden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    procedure TKamera.UseMatrix;&lt;br /&gt;
    var&lt;br /&gt;
      RotMatrix : THomogeneousMatrix;&lt;br /&gt;
      Pos : TVertex;&lt;br /&gt;
&lt;br /&gt;
    begin&lt;br /&gt;
      //Ansichten&lt;br /&gt;
      case LookMode of&lt;br /&gt;
        lmFree     : begin&lt;br /&gt;
                       RotMatrix := Rotation;&lt;br /&gt;
                       InvertMatrix(RotMatrix)&lt;br /&gt;
                     end;&lt;br /&gt;
        lmObjektSight: begin&lt;br /&gt;
                         Assert(Assigned(LookTarget));&lt;br /&gt;
                         Rotation := LookTarget.Rotation;&lt;br /&gt;
                         RotMatrix := Rotation;&lt;br /&gt;
                         InvertMatrix(RotMatrix)&lt;br /&gt;
                       end&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      //Bewegungen&lt;br /&gt;
      case MoveMode of&lt;br /&gt;
        mmFree     : begin&lt;br /&gt;
                       Pos := Position&lt;br /&gt;
                     end;&lt;br /&gt;
        mmAttatched : begin&lt;br /&gt;
                       Assert(Assigned(MoveTarget));&lt;br /&gt;
                       Position := MoveTarget.Position;&lt;br /&gt;
                       Pos := Position;&lt;br /&gt;
                     end;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
      //Matrix einlegen&lt;br /&gt;
      glLoadMatrixf(@RotMatrix[0,0]);&lt;br /&gt;
      glTranslatef(-Pos[0], -Pos[1], -Pos[2])&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
War doch schon mal gar nicht so schwer, oder? &lt;br /&gt;
&lt;br /&gt;
===lmLookAtObjekt===&lt;br /&gt;
Nun wollen wir ein Objekt in den Fokus der Kamera nehmen. Voraussetzung ist, dass wir bereits die Koordinaten unserer Kamera kennen, denn sonst können wir nicht bestimmen, in welcher Richtung das Objekt liegt.&lt;br /&gt;
&lt;br /&gt;
Wir müssen uns entscheiden: Wollen wir eine komplett neue Matrix erstellen, oder wollen wir die bereits bestehende Rotationsmatrix verwenden und sie so manipulieren, dass die Kamera auf das Objekt ausgerichtet ist? Ich habe mich für letztere Variante entschieden, da man dieses Wissen in Spielen auch anderorts wiederverwerten kann.&lt;br /&gt;
&lt;br /&gt;
Kommen wir also zur Idee, die hinter unserem Problem steckt: Ich hab eine Rotationsmatrix und die Globale Richtung von unserem Objekt zu unserem Zielpunkt. Drehen wir nun diese Globale Richtung in das lokale Koordinatensystem unseres Objektes, so können wir die Winkel errechnen, die nötig sind, um unsere Kamera auf das Ziel auszurichten.&lt;br /&gt;
&lt;br /&gt;
'''Das Problem:''' Ein Problem, das sich mir beim Nachdenken über diese Idee gestellt hat, ist, dass die Blickrichtung von OpenGl immer in die negative Z-Richtung geht. An sich wird das Problem nicht wesentlich schwieriger, man muss nur an ein paar geschickten Stellen ein Minus verteilen, bzw. Minuend und Subtrahend vertauschen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir einmal davon aus, dass wir die globale Richtung in die lokale transformiert haben. Wie kommen wir nun an unsere Rotationsmatrix? Bzw. wie kommen wir an die benötigten Kosinus- und Sinuswerte? Zuerst wollen wir um die y-Achse drehen. Deshalb können wir den y-Wert der lokalen Richung erst einmal außer Acht lassen. Setzen wir diesen auf 0 und normalisieren unseren Vektor. Wir erhalten dadurch einen Vektor auf dem Einheitskreis - Vorteil: wir müssen unseren Sinus und Cosinus nicht kompliziert errechnen, denn wir haben ihn bereits. Keine Arbeit mehr für uns. Matrix erzeugen und wir haben fertig.&lt;br /&gt;
&lt;br /&gt;
Jetzt haben wir die Kamera um die y-Achse ausgerichtet. Es fehlt noch die x-Achse. Wir haben bereits einiges an Vorarbeit geleistet. Wir können ganz einfach den Winkel zwischen der lokalen Richtung und dem Vektor auf dem Einheitskreis von vorhin berechnen. Sind beides Einheitsvektoren, so ist das Skalarprodukt(zu Englisch Dotproduct) der Kosinus des gesuchten Winkels. Wie sicher Einigen bekannt ist, gilt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;'''Cos²(α) + Sin²(α) = 1'''&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir kennen also auch den Wert des Sinus. Nur das Vorzeichen ist uns dann noch unbekannt. Dies ergibt sich aber daraus, ob der y-Wert der lokalen Richtung positiv oder negativ ist.&lt;br /&gt;
&lt;br /&gt;
Ich würde sagen Problem gelöst, hier der passende Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    procedure LockTarget(Target : TObjekt);&lt;br /&gt;
    var&lt;br /&gt;
      InvMatrix, M1, M2 : THomogeneousMatrix;&lt;br /&gt;
      ObjektPosition : TVertex;&lt;br /&gt;
&lt;br /&gt;
      Cos, Sin : Single;&lt;br /&gt;
      xzEbenenPosition : TVertex;&lt;br /&gt;
    begin&lt;br /&gt;
      try&lt;br /&gt;
        InvMatrix := Rotation;&lt;br /&gt;
        InvertMatrix(InvMatrix);&lt;br /&gt;
&lt;br /&gt;
        //Globale Objekt Position&lt;br /&gt;
        ObjektPosition := VectorSubtract(Position, Target.Position);&lt;br /&gt;
        //In lokale Koordinaten drehen&lt;br /&gt;
        ObjektPosition := VectorTransform(ObjektPosition, InvMatrix);&lt;br /&gt;
&lt;br /&gt;
        xzEbenenPosition[0] := ObjektPosition[0];&lt;br /&gt;
        xzEbenenPosition[1] := 0;&lt;br /&gt;
        xzEbenenPosition[2] := ObjektPosition[2];&lt;br /&gt;
        if not((xzEbenenPosition[0] = 0.0) and (xzEbenenPosition[2] = 0.0)) then&lt;br /&gt;
        begin&lt;br /&gt;
          NormalizeVector(xzEbenenPosition);&lt;br /&gt;
          M1 := CreateRotationMatrixY(xzEbenenPosition[0], xzEbenenPosition[2])&lt;br /&gt;
        end&lt;br /&gt;
        else&lt;br /&gt;
          M1 := IdentityHmgMatrix;&lt;br /&gt;
&lt;br /&gt;
        NormalizeVector(ObjektPosition);&lt;br /&gt;
        Cos := VectorDotProduct(xzEbenenPosition, ObjektPosition);&lt;br /&gt;
        Sin := Sqrt(1- Cos*Cos);&lt;br /&gt;
&lt;br /&gt;
        if (ObjektPosition[1] &amp;gt; 0.0) then&lt;br /&gt;
          Sin := - Sin;&lt;br /&gt;
        M2 := CreateRotationMatrixX(Sin, Cos);&lt;br /&gt;
&lt;br /&gt;
        RotMatrix := MatrixMultiply(M1, M2);&lt;br /&gt;
        Rotation := MatrixMultiply(RotMatrix, Rotation);&lt;br /&gt;
        RotMatrix := Rotation;&lt;br /&gt;
        InvertMatrix(RotMatrix)&lt;br /&gt;
      except&lt;br /&gt;
        RotMatrix := IdentityHmgMatrix&lt;br /&gt;
      end&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorwärts, Rückwärts, Links, Rechts, Hoch, Runter==&lt;br /&gt;
Eine in Ego Shootern als Strafen bezeichnete Art sich zu bewegen, ist das Bewegen der Kamera in eine bestimmte Richtung, die von der Ausrichtung der Kamera abhängt. Dies beschreibt ein recht häufig auftretendes Problem im Zusammenhang mit Kameras. An sich ist es nicht weiter schwer, z.B. entspricht links Strafen dem Bewegen entlang der negativen x-Achse im lokalen Koordinatensystem der Kamera. Will man also die Position der Kamera in dieser Art manipulieren, so erstellt man einfach einen Vektor, der in der zur Kamera lokalen Richtung zeigt (im Beispiel also: [-1, 0,0]). Dann dreht man mit Hilfe der Rotationsmatrix der Kamera diesen Vektor ins globale Koordinatensystem und addiert ihn zum Positionsvektor der Kamera. (Allen denen es nicht aufgefallen ist: Das war eine Kurzfassung der Mathematik in SchodMCs &amp;quot;Objekt gedreht und dennoch nach vorne bewegt&amp;quot; Tutorial).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Billboarding==&lt;br /&gt;
Eine weitere Kameraspezifische Sache ist das Billboarding. Das Problem stellt sich einem, wenn man eine Partikelengine schreibt und die Polygone immer parallel zur Kamera ausgerichtet sein sollen. Man muss hierfür einfach die Rotation aus der Matrix entfernen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    procedure Billboard;&lt;br /&gt;
    const&lt;br /&gt;
      NewModelView : Array[0..11] of TGLFloat =&lt;br /&gt;
        (1,0,0,0,0,1,0,0,0,0,1,0);&lt;br /&gt;
    var&lt;br /&gt;
      Modelview : Array[0..15] of TGLFloat;&lt;br /&gt;
&lt;br /&gt;
    begin&lt;br /&gt;
      // Modelview Matrix holen&lt;br /&gt;
      glGetFloatv(GL_MODELVIEW_MATRIX , @Modelview[0]);&lt;br /&gt;
      Move(NewModelView[0], ModelView[0], SizeOf(NewModelview));&lt;br /&gt;
      glLoadMatrixf(@Modelview[0])&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
Der Renderer des Kameratutorials könnte dann so abgeändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    ...&lt;br /&gt;
    //Kamera initialisieren&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
    Kamera.UseMatrix;&lt;br /&gt;
&lt;br /&gt;
    //Planeten rendern&lt;br /&gt;
    for I := Low(Planeten) to High(Planeten) do&lt;br /&gt;
      if i &amp;lt;&amp;gt; 3 then&lt;br /&gt;
      Planeten[I].Render;&lt;br /&gt;
&lt;br /&gt;
    with Planeten[3] do&lt;br /&gt;
      glTranslatef(Position[0], Position[1], Position[2]);&lt;br /&gt;
&lt;br /&gt;
    Billboard;&lt;br /&gt;
&lt;br /&gt;
    glBegin(GL_QUADS);&lt;br /&gt;
      glVertex3f(-10, -10, 0);&lt;br /&gt;
      glVertex3f(10, -10, 0);&lt;br /&gt;
      glVertex3f(10, 10, 0);&lt;br /&gt;
      glVertex3f(-10, 10, 0);&lt;br /&gt;
    glEnd();&lt;br /&gt;
    ...&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
Ich habe jetzt beschlossen, dass ich hier einmal aufhöre. Das Geschreibe ist doch recht anstrengend und ich will euch doch nicht alle Ideen vorwegnehmen. Deshalb wünsch ich euch jetzt viel Spaß beim Rumprobieren&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
:'''Delphic'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nachtrag===&lt;br /&gt;
:Weitere Hinweise zum erstellen von Kameraklassen findet ihr im Artikel [[Kamera (1)]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_kameras_src_vcl|text=Beispiel-Quelltext (Delphi)}}&lt;br /&gt;
* {{ArchivLink|file=tut_kameras_exe|text=Beispiel-Programm}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial TexFilter]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Kamera1]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_SDL_Einstieg&amp;diff=25847</id>
		<title>Tutorial SDL Einstieg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_SDL_Einstieg&amp;diff=25847"/>
				<updated>2013-09-25T14:30:15Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=SDL - Simple Directmedia Layer=&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Ich weiß, dass ich mich damit unbeliebt machen werde,aber... Was haben GLUT und DirectX gemeinsam? Na, Na! Wer weiß es? Richtig, sie haben beide keine Zukunft mehr. ;) Na gut, war nicht wirklich der Reißer, aber zumindest war es der Gedanke, den ich hatte als ich mich das erste Mal mit dem Simple DirectMedia Layer befaßt habe (kurz SDL). Das Ganze hat nichts mit einem Breitbandanschluß oder einer neuen Designer-Droge zu tun, sondern es handelt sich dabei um eine plattformübergreifende API.&lt;br /&gt;
&lt;br /&gt;
Die Idee die dahinter steckt ist genauso simpel wie genial! DirectX ist eine wirklich hervorragende API, allerdings hat das ganze ein Nachteil! Es kommt von Microsoft und ist nur für Windows verfügbar. Die OpenSource-Gemeinde müsste vor Scham im Boden versinken, wenn man dazu nicht passend ein Projekt ins Leben rufen würde, dass diesem Defizit ein Ende bereitet. Bei SDL handelt es sich um einen abstrakten Layer der auf jeder Plattform gleich ist und dann im Hintergrund die Befehle entsprechend dem darunter befindlichen OS umwandelt. Der Vorteil für den Programmierer ist klar: Wer seine Anwendung mit SDL schreibt, kann diese auch sehr schnell auf andere Systeme portieren. Eine reine SDL Anwendung in Delphi geschrieben, sollte sich also ohne Probleme auch unter Kylix kompilieren lassen und das ganz ohne den ganzen Source-Code umzubauen. Das Ganze ist zwar nicht so komplex wie DirectX von Microsoft, hat aber mindestens genauso viel Potenzial! Wer sich nun fragt, wozu das Ganze für ihn interessant sein soll, hat nicht mitgedacht! SDL für Fensterverwaltung und Benutzerinteraktion und dazu die geilste und portabelste Grafik-API, die es auf der Welt gibt : OpenGL! ;)&lt;br /&gt;
&lt;br /&gt;
Ich hoffe sehr, dass ich mit diesem Artikel einige von euch für die Kombination SDL und OpenGL begeistern kann, denn gerade wir Delpher haben auch im Linux-Sektor eine Menge Potenzial, dass leider nicht genutzt wird! In diesem Sinne viel Erfolg! ;)&lt;br /&gt;
&lt;br /&gt;
==Initialisierung von SDL==&lt;br /&gt;
===SDL! Bitte kommen!===&lt;br /&gt;
&lt;br /&gt;
Wer sich bereits einmal mit der Programmierung der Windows-API beschäftigt hat, wird hier sicherlich nichts stark Befremdliches vorfinden. Sicherlich, alles heißt irgendwie anders, aber dafür ist das Ganze auch um einiges leichter zu handhaben als die Fenstererzeugung mit der WinAPI. Direkt im Hauptprogramm fangen wir erst einmal damit an SDL zu initialisieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt; SDL_Init ( SDL_INIT_VIDEO );&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf diese Weise teilen wir unserem Programm mit welche Teile von SDL initialisiert werden sollen. In unserem Beispiel die Bildschirmausgabe. Wir können als Parameter auch weitere Subsysteme übergeben z. B:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt; SDL_Init ( SDL_INIT_VIDEO or SDL_INIT_TIMER );&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dazu aber später mehr! Wie immer ist es wichtig, dass man nicht nur Code an den Computer schickt, sondern auch darauf vorbereitet ist dass eventuell ein Fehler aufgetreten ist. Dieser soll dann natürlich auch vom Programm abgefangen werden!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Initalisieren vom Simple DirectMedia Layer&lt;br /&gt;
  if ( SDL_Init( SDL_INIT_VIDEO ) &amp;lt; 0 ) then&lt;br /&gt;
  begin&lt;br /&gt;
    Log.LogError('Initalisierung von SDL schlug fehl: '+SDL_GetError,'SDL_Init');&lt;br /&gt;
    Quit_App;&lt;br /&gt;
  end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte ein negativer Wert als Rückgabe erfolgen, so ist ein Fehler aufgetreten. Wir machen uns in diesem Fall die Fehlerbehandlung sehr einfach. Wir nutzen das im SDL integrierte Log-File und geben dort eine Fehlermeldung aus. Um die Orientierung zu erleichtern geben wir noch das Modul an in dem der Fehler auftrat. In diesem Fall eben bei der Initialisierung von SDL. Zu {{INLINE_CODE|Quit_App}} kommen wir später. Es handelt sich dabei um eine selbst geschriebene Funktion zum Freigeben der Ressourcen.&lt;br /&gt;
&lt;br /&gt;
===Grafikkarten sind gar nicht so anders===&lt;br /&gt;
&lt;br /&gt;
Sicherlich ist es nicht jedem Leser hier bewusst, dass man für eine grafische Ausgabe auch eine Grafikkarte braucht. Deswegen werde ich hier noch einmal explizit darauf eingehen! :) Da SDL uns zur Verfügung steht können wir es auch verwenden um uns Informationen über die eingebaute Grafikkarte einzuholen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Information über Grafikkarte einholen&lt;br /&gt;
  videoInfo := SDL_GetVideoInfo;&lt;br /&gt;
  if ( videoInfo = nil ) then&lt;br /&gt;
  begin&lt;br /&gt;
    Log.LogError('Grafikkarte ließ sich nicht abfragen: '+SDL_GetError,'SDL_Init' );&lt;br /&gt;
    Quit_App;&lt;br /&gt;
  end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei VideoInfo handelt es sich um eine {{INLINE_CODE|PSDL_VideoInfo}}-Struktur. Konnten die Informationen erfolgreich abgefragt werden, so sind alle interessanten Informationen in dieser Struktur enthalten, z.B. wie viel MB Speicher diese hat! Ist die Rückgabe undefiniert, greift natürlich unsere Fehlerbehandlung.&lt;br /&gt;
&lt;br /&gt;
===Die Suche nach dem wahren Pixelformat===&lt;br /&gt;
&lt;br /&gt;
Unser nächstes Ziel ist nun die Erzeugung der eigentlichen Zeichenfläche. Diese ist zu vergleichen mit dem Canvas eines Windows-Fensters. Natürlich müssen wir auch hier erst einige Einstellungen vornehmen!Immerhin wollen wir ja auch nicht ein paar 2D-Bilder á la DirectDraw rendern, sondern hardwarebeschleunigtes OpenGL!Also beginnen wir die Flags für die eigentliche Initalisierung zu sammeln:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Flags für den SDL-Grafikmodus setzen&lt;br /&gt;
  videoFlags := SDL_OPENGL or                  // OpenGL-Unterstützung aktivieren&lt;br /&gt;
                SDL_HWPALETTE;                 // Palette in Hardware speichern&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vermutlich wird sich niemand finden, der die Sinnhaftigkeit dieser Flags wirklich anzweifeln wird!Als nächstes ermitteln wir ob die Möglichkeit besteht den Speicher und die eigentliche Hardwarebeschleunigung auch zu nutzen. Ich denke nicht, dass jemand heutzutage noch darauf verzichtet wenn er es nicht muss ;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Kann das Surface in den Speicher?&lt;br /&gt;
  if ( videoInfo.hw_available &amp;lt;&amp;gt; 0 ) then&lt;br /&gt;
    videoFlags := videoFlags or SDL_HWSURFACE&lt;br /&gt;
  else&lt;br /&gt;
    videoFlags := videoFlags or SDL_SWSURFACE;&lt;br /&gt;
&lt;br /&gt;
  // Wird hardware blitting unterstützt?&lt;br /&gt;
  if ( videoInfo.blit_hw &amp;lt;&amp;gt; 0 ) then videoFlags := videoFlags or SDL_HWACCEL;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun erfolgt die die Definition des PixelFormats dass für die Initialisierung von OpenGL unentbehrlich ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Setzen der OpenGL-Attribute&lt;br /&gt;
  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );&lt;br /&gt;
  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );&lt;br /&gt;
  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );&lt;br /&gt;
  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );&lt;br /&gt;
  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Farbwerte sollten so belassen werden. Der Tiefenbuffer wird auf 16 Bit festgelegt und ein BackBuffer soll auch erzeugt werden. Jeder der sich bereits einmal mit der Initialisierung beschäftigt hat, wird hier Gemeinsamkeiten finden und sich auch denken können wie man z.B. den Stencil-Buffer unter SDL setzt:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE,  8 );&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun würden wir einen 8 Bit-Stencil-Buffer initialisieren. Gleiches gilt natürlich auch für den Akkumulations-Buffer!Damit haben wir alle Informationen gesammelt die wir brauchen um ein OpenGL-Fenster mit SDL zu erzeugen. Wenn man sich den Source Code ansieht, wird man merken, dass dieser um einiges schlanker ist als die Initalisierung der WinAPI und wir zudem auch noch plattformunabhängig sind!Einige kleinere Einstellungen nehmen wir allerdings noch vor. Nur kleine kosmetische Änderungen wie der Fenstertitel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Fenstertitel festlegen&lt;br /&gt;
  SDL_WM_SetCaption( WINDOWS_CAPTION , nil);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als einfacher String wird der Titelname übergeben, der zweite Paramter kann dazu verwendet werden ein Icon für die Leiste zu definieren. Auch können wir an dieser Stelle entscheiden ob der Benutzer in der Lage sein soll das Fenster in seiner Größe zu verändern. Standardgemäß ist dieses Feature deaktiviert, so dass die Fenstergröße immer gleich bleibt. Wollen wir ein Skalieren jedoch zulassen, übergeben wir einfach ein weiteres Video-Flag:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;videoflags := videoFlags or SDL_RESIZABLE;    // Enable window resizing&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun haben wir alles beisammen und erzeugen unser Surface!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;videoflags := // Initalisierung der Surface&lt;br /&gt;
  surface := SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,videoflags );&lt;br /&gt;
  if ( surface = nil ) then&lt;br /&gt;
  begin&lt;br /&gt;
    Log.LogError('Erzeugen einer OpenGL-Zeichenfläche schlug fehl: '+SDL_GetError,'SDL_Init' );&lt;br /&gt;
    Quit_App;&lt;br /&gt;
  end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich denke nicht, dass es einer genaueren Erklärung bedarf was an dieser Stelle geschieht. Die Fenstergröße und Farbtiefe, sowie die Wunschliste unserer Video-Flags wird übergeben und wenn alles angeforderte auch möglich ist, erhalten wir von SDL ein {{INLINE_CODE|PSDL_Surface}} zurück mit der wir dann weiterarbeiten können (und auch werden) ;)&lt;br /&gt;
&lt;br /&gt;
==OpenGL Initalisierung==&lt;br /&gt;
&lt;br /&gt;
Die meisten Leute gehen von einem ziemlich komplexen, aufwendigen und vor allem schweren Vorfang aus, wenn sie hören dass jemand OpenGL initalisiert. Dabei ist OpenGL gar nicht schwer zu initalisieren. Das eigentliche Problem ist vielmehr an ein Fenster vom Betriebsystem zu kommen dass auch OpenGL unterstützt. Dies haben wir allerdings bereits erfolgreich im letzten Kapitel geschafft, so dass wir nun nur noch dafür sorgen müssen, dass wir Zugriff auf die OpenGL-Runtimes erhalten. Dies ist jedoch ziemlich leicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt; // Laden und Initalisieren von OpenGL&lt;br /&gt;
    InitOpenGL;&lt;br /&gt;
    ReadExtensions;&lt;br /&gt;
    ReadImplementationProperties;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fertig! Schon steht nichts mehr zwischen uns und dem OpenGL-Render-Spaß ;) Allerdings empfiehlt es sich immer noch einige grundlegende Dinge einzustellen, einfach weil es hübscher gerendert wird ;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    glClearColor(0.0, 0.0, 0.0, 1.0);         // Bildschirm löschen (schwarz)&lt;br /&gt;
    glClearDepth(1.0);                                    // Depth Buffer Setup&lt;br /&gt;
    glEnable(GL_DEPTH_TEST);                        // Aktiviert Depth Testing&lt;br /&gt;
    glDepthFunc(GL_LEQUAL);                          // Bestimmt den Typ des Depth Testing&lt;br /&gt;
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// Qualitativ bessere Koordinaten&lt;br /&gt;
                                                       // Interpolation&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das wir OpenGL initalisiert haben ist sicher ein guter Anfang, allerdings wollen wir natürlich auch etwas sehen. Dafür ist es notwendig, dass wir unseren Viewport setzen und die Projektions-Matrix auf die entsprechende Größe transformieren. Aus taktischen Gründen schreiben wir uns dafür eine Funtion, die wir auch später beim Event-Handlung wiederverwenden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function glResizeWindow( width : integer; height : integer ) : Boolean;&lt;br /&gt;
begin&lt;br /&gt;
// Verhindern von &amp;quot;Division by Zero&amp;quot;&lt;br /&gt;
  if ( height = 0 ) then height := 1;&lt;br /&gt;
&lt;br /&gt;
  // Viewport und Projektions-Matrix aktualisieren&lt;br /&gt;
  glViewport( 0, 0, width, height );&lt;br /&gt;
&lt;br /&gt;
  glMatrixMode( GL_PROJECTION );&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
    gluPerspective( 45.0, width / height, 0.1, 100.0 );&lt;br /&gt;
  glMatrixMode( GL_MODELVIEW );&lt;br /&gt;
&lt;br /&gt;
  // Rücksetzen der World-Matrix&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
&lt;br /&gt;
  // Vorgang erfolgreich&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All diese Vorgänge sollten für einen OpenGL-Programmierer nichts erschreckend neues sein. Damit der Viewport auch wirklich richtig gesetzt wird, rufen wir diese Funktion einfach einmal auf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;// Anpassen der Fenstergröße&lt;br /&gt;
  glResizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tag, Post!==&lt;br /&gt;
===Die Idee===&lt;br /&gt;
&lt;br /&gt;
Würden wir nun unser Programm in diesem Zustand starten, würden wir für den Bruchteil einer Sekunde ein Fenster angezeigt bekommen (das immerhin OpenGL-kompatibel ist! *g) und danach sofort wieder verschwindet. Überlegt man sich einmal ganz genau, was passiert, wird einem der Grund dafür schnell klar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;begin&lt;br /&gt;
  // Initalisierung&lt;br /&gt;
  Init_SDL;&lt;br /&gt;
  Init_OpenGL;&lt;br /&gt;
&lt;br /&gt;
  // Anpassen der Fenstergröße&lt;br /&gt;
  glResizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );&lt;br /&gt;
end.&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unser Hauptprogramm initalisiert SDL, danach OpenGL, passt das Ganze an der Fenstergröße an und beendet danach die Aufgabenliste. Für Windows bedeutet dies, dass das Programm seine Verarbeitung abgeschlossen hat und somit nicht mehr gebraucht wird und schon findet sich unsere SDL-Anwendung auf dem Müllhaufen. (Um Mißverständnisse zu vermeiden: Nicht der Papierkorb und nicht aufm Desktop *g*). Wir brauchen also eine Schleife die sich immer wieder im Programm wiederholt und dafür sorgt, dass diese nur unter einer ganz bestimmten Bedingung verlassen wird und somit das Programm auch beendet wird. Man spricht von dem Main-Loop oder auch Game-Loop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;begin&lt;br /&gt;
  // Initalisierung&lt;br /&gt;
  Init_SDL;&lt;br /&gt;
  Init_OpenGL;&lt;br /&gt;
&lt;br /&gt;
  // Anpassen der Fenstergröße&lt;br /&gt;
  glResizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );&lt;br /&gt;
&lt;br /&gt;
  // Eintritt in Main-Loop&lt;br /&gt;
  while ( Done &amp;lt;&amp;gt; -1 ) do&lt;br /&gt;
  begin&lt;br /&gt;
    glHandleEvents;&lt;br /&gt;
    glDrawScene;&lt;br /&gt;
  end;&lt;br /&gt;
end.&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Done ist in unserem Fall ein einfacher Integer-Wert. Sobald dieser im eigentlichen Programm auf -1 gesetzt wird, wird die Schleife nicht ein weiteres Mal durchlaufen. Wir sehen auch, dass in der Schleife zwei Funktionen aufgerufen werden. Dies bietet sich an um die Übersicht zu wahren!Natürlich können wir auch noch weitere Aufgaben in der Schleife verarbeiten!&lt;br /&gt;
GlDrawSzene ist die Funktion die die OpenGL-Befehle beinhaltet und sich um die grafische Ausgabe kümmert. Dieser Teil ist identisch mit der entsprechenden Funktion unter der WinAPI oder der VCL. Würden wir allerdings die Schleife immer nur mit dieser Funktion durchlaufen, so würde der Benutzer keine Interaktion mit dem Programm durchführen können, da immer nur die Schleife durchlaufen wird. Die Anwendung würde hängen. Es ist daher notwendig, dass diese auf Ereignisse des Betriebsystems oder des Anwenders reagiert.&lt;br /&gt;
&lt;br /&gt;
===Event-Handling===&lt;br /&gt;
&lt;br /&gt;
Um zu begreifen wie genau eine solche Ereignis-Reaktion aussieht, schauen wir uns die Funktion {{INLINE_CODE|glHandleEvents}} etwas genauer an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure glHandleEvents;&lt;br /&gt;
var event       : TSDL_Event;&lt;br /&gt;
begin;&lt;br /&gt;
    // Verarbeiten der Events&lt;br /&gt;
    while ( SDL_PollEvent( @event ) = 1 ) do&lt;br /&gt;
    begin&lt;br /&gt;
      case event.type_ of&lt;br /&gt;
&lt;br /&gt;
        // Beenden der Applikation&lt;br /&gt;
        SDL_QUITEV :&lt;br /&gt;
        begin&lt;br /&gt;
          Done := -1;&lt;br /&gt;
        end;&lt;br /&gt;
&lt;br /&gt;
        // Taste wurde gedrückt&lt;br /&gt;
        SDL_KEYDOWN :&lt;br /&gt;
        begin&lt;br /&gt;
          glHandleKeyPress( @event.key.keysym );&lt;br /&gt;
        end;&lt;br /&gt;
&lt;br /&gt;
        // Fenster-Größe hat sich verändert&lt;br /&gt;
        SDL_VIDEORESIZE :&lt;br /&gt;
        begin&lt;br /&gt;
          glResizeWindow( event.resize.w, event.resize.h );&lt;br /&gt;
        end;&lt;br /&gt;
      end;//case&lt;br /&gt;
    end;//while&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit {{INLINE_CODE|SDL_PollEvent}} fragen wir bei SDL an, ob Nachrichten für unsere Anwendung vorliegen. Ist dies der Fall, so durchlaufen wir alle diese Nachrichten nacheinander. Um die Art der Nachricht zu ermitteln übergeben wir eine Struktur vom Typ {{INLINE_CODE|TSDL_EVENT}} und nutzen {{INLINE_CODE|.type_}} um zu ermitteln, um was für eine Nachricht es sich handelt. In unserem Fall reagieren wir auf 3 Ereignisse.&lt;br /&gt;
&lt;br /&gt;
===Sein oder nicht sein...===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;  // Beenden der Applikation&lt;br /&gt;
        SDL_QUITEV :&lt;br /&gt;
        begin&lt;br /&gt;
          Done := -1;&lt;br /&gt;
        end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Liegt ein Ereignis vom Typ {{INLINE_CODE|SDL_QUITEV}} vor, so hat die Anwendung die Meldung erhalten dass sie beendet werden soll. Der wahrscheinlichste Grund dafür wird sein, dass der Anwender auf das X im Fenstertitel geklickt hat. Es liegt nun an uns dafür zu sorgen, dass diesem Wunsch auch nachgekommen wird. Wie wir uns erinnern wird das Programm verlassen, sobald {{INLINE_CODE|done := -1;}} gesetzt ist. Also machen wir dies auch. Nachdem alle Nachrichten abgearbeitet sind und der Main-Loop betreten wird, ist die Bedingung für einen Programmabbruch erfüllt. &lt;br /&gt;
&lt;br /&gt;
===Tastatur-Handling===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;   // Taste wurde gedrückt&lt;br /&gt;
        SDL_KEYDOWN :&lt;br /&gt;
        begin&lt;br /&gt;
          glHandleKeyPress( @event.key.keysym );&lt;br /&gt;
        end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieses Event wird dann ausgelöst, wenn eine Taste gedrückt wurde. Wir übergeben in diesem Fall das Ereignis weiter an eine Funktion, die sich dann mit der Auswertung beschäftigt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure glHandleKeyPress( keysym : PSDL_keysym );&lt;br /&gt;
begin;&lt;br /&gt;
  case keysym.sym of&lt;br /&gt;
    SDLK_ESCAPE : done := -1;&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierzu überprüfen wir, welche Taste gedrückt wurde. In diesem Fall handelt es sich um die Escape-Taste und sie soll beim Betätigen das Programm beenden. Würden wir abfragen wollen, ob die F1-Taste gedrückt wurde, so könnten wir dies mit {{INLINE_CODE|SDLK_F1}} machen. Weitesgehend entsprechen die SDLK-Konsten den VK-Konstanten der WINAPI. Wer über eine neuere Delphi-Version verfügt, kann ja auch mal STRG drücken und dann mit der linken Maustaste auf {{INLINE_CODE|SDLK_ESCAPE}} klicken. Delphi wird dann an die Stelle springen, wo die Konstanten definiert sind. Dort werdet ihr sicherlich auch recht schnell die anderen Tasten finden, die ihr sucht.  &lt;br /&gt;
&lt;br /&gt;
===Eine Frage der wahren Größe===&lt;br /&gt;
&lt;br /&gt;
{{INLINE_CODE|SDL_VIDEORESIZE}} wird dann ausgelöst, wenn sich die Zeichenfläche in Ihrer Größe verändert hat. Zum Beispiel, weil der Anwender gerade das Fenster größer gezogen hat.&lt;br /&gt;
&lt;br /&gt;
Durch diese Veränderung der Zeichenfläche werden unsere Projektions-Matrix und der Viewport ungültig. Wir müssen diese also neu anpassen. Wer sich gut erinnern kann, wird nun verstehen warum ich anfangs gesagt habe, dass wir uns die {{INLINE_CODE|glResizeWindow}}-Funktion so schreiben, dass wir sie in einem Event wieder verwenden können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glResizeWindow( event.resize.w, event.resize.h );&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir übergeben einfach die vom Event übergebene neue Größe unseres Fensters und passen die Projektions-Matrix neu an. Schon kann der Anwender nach belieben die Größe des Render-Fensters verändern. So einfach ist das...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==OpenGL? Überall gleich!==&lt;br /&gt;
&lt;br /&gt;
Wie ich bereits erwähnt habe, ist in der Funktion glDrawScene nichts wirklich Neues anzufinden, was nicht in einer API oder VCL-Lösung anzutreffen wäre. Schließlich ist OpenGL eben dafür geschaffen worden so portabel wie möglich zu sein:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure glDrawScene;&lt;br /&gt;
begin&lt;br /&gt;
  // Screen- und Tiefenbuffer bereinigen&lt;br /&gt;
  glClear( GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT );&lt;br /&gt;
&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
  glTranslatef( -1.5, 0.0, -6.0 );&lt;br /&gt;
&lt;br /&gt;
  // Zeichne Dreieck&lt;br /&gt;
  glBegin( GL_TRIANGLES );&lt;br /&gt;
    glVertex3f( 0.0, 1.0, 0.0 );&lt;br /&gt;
    glVertex3f( 1.0, -1.0, 0.0 );&lt;br /&gt;
    glVertex3f( -1.0, -1.0, 0.0 );&lt;br /&gt;
  glEnd;&lt;br /&gt;
&lt;br /&gt;
  glTranslatef( 3.0, 0.0, 0.0 );&lt;br /&gt;
&lt;br /&gt;
  // Zeichne ein Quadrat&lt;br /&gt;
  glBegin( GL_QUADS );&lt;br /&gt;
    glVertex3f( -1.0, 1.0, 0.0 );&lt;br /&gt;
    glVertex3f( 1.0, 1.0, 0.0 );&lt;br /&gt;
    glVertex3f( 1.0, -1.0, 0.0 );&lt;br /&gt;
    glVertex3f( -1.0, -1.0, 0.0 );&lt;br /&gt;
  glEnd;&lt;br /&gt;
&lt;br /&gt;
  // Buffer-Wechseln ==&amp;gt; Anzeigen&lt;br /&gt;
  SDL_GL_SwapBuffers;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einzig und alleine die letzte Zeile ist anders. Hat unter der WINAPI an dieser Stelle noch eine WGL-Funktion ihren Dienst verrichtet, so macht dies hier eine SDL-Funktion. WGL steht unter Linux nicht zur Verfügung und man würde sich ansonsten auf Windows-Systeme festlegen. Technisch geschieht hier aber nichts anders als auch bei der WGL-Funktion nämlich das der hintere Framebuffer nach &amp;quot;vorne&amp;quot; geholt wird, sprich auf dem Bildschirm angezeigt wird. Ohne diesen Aufruf würde OpenGL zwar brav im Hintergrund rendern, aber niemals etwas anzeigen. Das kann auch nicht in unserem Interesse sein, oder? ;) &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Time to say goodbye!==&lt;br /&gt;
&lt;br /&gt;
Ich weiß ja wirklich nicht wie es Euch geht,  aber ich bin immer wenn ich etwas wegschmeiße ziemlich sensibel drauf. Und wenn ich mich hier im Zimmer umsehe, habe ich auch das Gefühl dass ich mich nie wirklich von einem meiner Computer getrennt habe O_o (habe sie halt immer noch alle ziemlich lieb *schnief). Aber es gibt eben Momente bei denen man sich von etwas was man gerne hat auch wieder trennt und wenn es sich nicht mehr vermeiden läßt, sollte man den Moment wenigstens in Ehre halten. &lt;br /&gt;
&lt;br /&gt;
Nein, wer nun erwartet dass ich für euch große unsinkbare Schiffe versenke, wird enttäuscht sein ;) Wir schreiben einfach eine kleine Prozedur die unsere Anwendung umweltfreundlich entsorgt. Diese Prozedur können wir auch dann einsetzen wenn ein Fehler augetreten ist. Sicher könnte man den ganzen Kram auch einfach seinem Schicksal (Windows) überlassen, aber zu einem sauberen Code gehört es sich eben, dass freizugeben was man auch angefordert hat. Ich denke nicht dass der Code wirklich einer näheren Erklärung bedarf!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;//----------------------------------------------------------------------------&lt;br /&gt;
// Terminieren der SDL-Anwendung&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
procedure Quit_App;&lt;br /&gt;
begin;&lt;br /&gt;
  // Freigeben der Ressourcen&lt;br /&gt;
  SDL_QUIT;&lt;br /&gt;
  Halt(0);&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Das war also bereits unser kleiner Crash-Kurs in die Welt des SDL. Ich hoffe sehrmdass dieses Tutorial verständlich genug war um SDL auch künftig einzusetzen. Es ist meiner Meinung nach wichtig ein Gegengewicht zu Microsoft in der Welt zu haben und der Programmierer soll ja ökonomisch denken. Was spricht also dagegen seine Anwendung so zu gestalten, dass man sie ohne Probleme auch nach Linux übersetzen könnte?Gerade in Verbindung mit OpenGL entfaltet sich ein richtges Dream-Team. Der eine für die Fensterverwaltung, der andere für die grafische Ausgabe. Jeder der bereits (oder immer noch?!) mit GLUT arbeitet, sollte schleunigst davon weg kommen und auf SDL umsteigen. Weil es einfach besser ist ;)&lt;br /&gt;
&lt;br /&gt;
Sicherlich werden nun nicht unbedingt SDL-Anwendungen aus dem Boden schießen, aber der eine oder andere hat ja vielleicht schon ein wenig Blut geleckt und möchte etwas weiter damit herum spielen? Habe ich bereits erwähnt, dass SDL auch etwas für Joysticks, Mäuse und Sound zur Verfügung stellt? Auch ein abstraktes System für mehre Threads ist mit von der Partie, sowie einige Funktionen zum Benutzen von Audio-CDs. Wer Lust auf mehr SDL hat, sollte unbedingt einmal einen Blick in die SDL-Hilfe werfen. Das Projekt ist jung, aber motiviert und hat eine Menge Potenzial!Die Delphi-Portierung wird von den JEDIs selbst unter der Projekt-Führung von Dominique Louis durchgeführt. Wer bereits seit DelphiX-Zeiten in der Szene unterwegs ist wird wissen, was es bedeutet! Gute Arbeit und Sicherheit für die Zukunft ;)&lt;br /&gt;
In diesem Sinne ... viel Spaß ;)&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:'''Phobeus'''&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_SDL_RWops]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|SDL_Einstieg]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Link&amp;diff=25846</id>
		<title>Link</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Link&amp;diff=25846"/>
				<updated>2013-09-25T14:29:37Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Rechtschreibfehler ausgebessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--&lt;br /&gt;
!!!!!!!! NUTZT DIESE TABELLE ALS VORLAGE FÜR WEITERE LINKTABELLEN !!!!!!!&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[Link]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[Link]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Linksammlung soll allgemeine Links zu unterschiedlichen Themen bieten, die mit der Multimediaentwicklung zu tun haben.&lt;br /&gt;
{{Hinweis|Vielleicht ist eine Zusammenführung mit [[Tool]] sinnvoll!}}&lt;br /&gt;
{{Hinweis|Vielleicht ist eine Aufteilung in Unterseiten sinnvoll (möglicherweise mit Kategorien)}}&lt;br /&gt;
&lt;br /&gt;
= Entwicklung mit OpenGL =&lt;br /&gt;
&lt;br /&gt;
== Hardwareinfos ==&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20090417044334/http://delphi3d.net/hardware/listreports.php OpenGL Hardware Registry - Hardwareübersicht]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Eine Datenbank aller Grafikkarten die in der Harware Registry vorhanden sind. Die einzelnen Artikel enthalten Infos darüber, welche Extensions von der Grafikkarte unterstützt werden.&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20090506094005/http://delphi3d.net/hardware/ OpenGL Hardware Registry - Extensionübersicht]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Eine Datenbank aller Extensions die in der Harware Registry vorhanden sind. Die einzelnen Artikel enthalten Infos darüber, welche Grafikkarten die entsprechende Extension unterstützen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tutorials ==&lt;br /&gt;
&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
||[[Tutorial|DGL Wiki - Tutorial]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|DelphiGL.com ist Betreiber dieses Wikis und stellt eine Vielzahl Tutorials mit Schwehrpunkt OpenGL zur Verfügung. &lt;br /&gt;
Neben Tutorials für Einsteiger und OpenGL Anfänger gibt es auch fortgeschrittene Themen wie Shader oder Partikelsysteme.Sprache der Wahl ist hier Delphi.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.joachimrohde.com/cms/xoops/modules/articles/index.php?cat_id=1 joachimrohde.com]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Auf dieser Seite findet ihr deutsche Übersetzungen der bekannten NeHe Tutorials. Sprache der Wahl ist hier C++.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.cg.tuwien.ac.at/studentwork/VRSem96/OpenGL/ Technische Universität Wien]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Diese Seite bietet einen allgemeinen Überblick über die primären Funktionen von OpenGL und richtet sich vor allem an Einsteiger.&lt;br /&gt;
|-&lt;br /&gt;
|[http://nehe.gamedev.net/ Nehe] &lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Die berühmt berüchtigten NeHe Tutorials sind eine umfangreiche Sammlung an Tutorials zum Thema OpenGL. Von Anfängertutorials bis hin zu komplexen Effekten wird alles behandelt. Sprache der Wahl ist hier C++. (Eine Übersetzung der NeHe Tutorials findet ihr bei Joachim Rhode (siehe oben). )&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.sulaco.co.za/tut.htm sulaco.co.za] &lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| OpenGL Beispiele in Delphi&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OpenGL Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== GL ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[[:Kategorie:GL|DGL Wiki - Kategorie GL]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Wiki-Kategorie die alle übersetzten OpenGL Befehle enthält.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL.tar.gz OpenGL.org - Original Spezifkationen]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Die Originalspezifikationen der OpenGL 1.0 und OpenGL 1.1 Befehle. (Diese HTML-Dokumente sind nicht Copy&amp;amp;Paste freundlich, da sie vermutlich automatisch aus vorhandenen Dateien (Postscript) erzeugt wurden.)&lt;br /&gt;
|-&lt;br /&gt;
|[http://developer.3dlabs.com/documents/glmanpage_index.htm 3dLabs]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Die Originalspezifikationen der OpenGL 1.0 und OpenGL 1.1 Befehle.&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20040616082839/http://www.mevis.de/~uwe/opengl/opengl.html mevis.de]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Sammlung von Englischsprachigen Spezifikationen für GL(bis Version 1.1), GLX und GLU Funktionen.&lt;br /&gt;
|-&lt;br /&gt;
|[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/glfunc01_4f03.asp MSDN von Microsoft]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|OpenGL Dokumentation in der MSDN. Die Erklärung der MSDN sind meist keine reinen Kopien der Originalspezifikationen, sondern enthalten hin und wieder auch zusätzliche Informationen, oder formulieren Texte auf verständlichere Art und Weise.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== GLU ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[[:Kategorie:GLU|DGL Wiki - Kategorie GLU]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Wiki-Kategorie die alle übersetzten GLU Befehle enthält.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/ OpenGL.org - Original Spezifkationen]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Originalspezifikationen für die GLU Befehle. (Diese HTML-Dokumente sind nicht Copy&amp;amp;Paste freundlich, da sie vermutlich automatisch aus vorhandenen Dateien (Postscript) erzeugt wurden.)&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20040616082839/http://www.mevis.de/~uwe/opengl/opengl.html mevis.de mevis.de]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Sammlung von englischsprachigen Spezifikationen für GL(bis Version 1.1), GLX und GLU Funktionen.&lt;br /&gt;
|-&lt;br /&gt;
|[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/glufnc01_0e43.asp MSDN von Microsoft]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|GLU Dokumentation in der MSDN. Die Erklärung der MSDN sind meist keine reinen Kopien der Originalspezifikationen, sondern enthalten hin und wieder auch zusätzliche Informationen, oder formulieren Texte auf verständlichere Art und Weise.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== GLX ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[[:Kategorie:GLX|DGL Wiki - Kategorie GLX]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Wiki-Kategorie die alle übersetzten GLX Befehle enthält.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glx/ OpenGL.org - Original  Spezifkationen]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Orgninalspezifikationen der GLX Befehle bei OpenGL.org.&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20040616082839/http://www.mevis.de/~uwe/opengl/opengl.html mevis.de mevis.de]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Sammlung von Englischsprachigen Spezifikationen für GL(bis Version 1.1), GLX und GLU Funktionen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== WGL ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[[:Kategorie:WGL|DGL Wiki - Kategorie WGL]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Wiki-Kategorie die alle übersetzten WGL Befehle enthält.&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20071218151417/http://developer.3dlabs.com/documents/wglmanpage_index.htm 3dLabs]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Sammlung einiger WGL Befehlsspezifikationen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== GLUT ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://freeglut.sourceforge.net/docs/api.php The freeglut Projekt]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Englischsprachige Dokumentation zum OpenGL Utility Toolkit kurz GLUT.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDL ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[[:Kategorie:SDL|DGL Wiki - Kategorie SDL]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Übersicht aller auf die SDL bezogenen Artikel hier im Wiki. Darunter befinden sich eine Vielzahl von Übersetzungen der SDL Befehlspezifikationen. Diese können auch in der [[SDL-Funktionsübersicht]] gefunden werden.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.libsdl.org/cgi/docwiki.cgi/SDL_20API libsdl.org]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Das Dokumentationswiki von libSDL.org enthält die komplette Dokumenation zur SDL in englischer Sprache.&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.freepascal-meets-sdl.net/ freepascal meets sdl]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Eine Webseite die speziell Informationen über die Programmierung von SDL unter Freepascal zur Verfügung stellt.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== FAQs ==&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[[FAQ| DGL Wiki - FAQ]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Ein FAQ (Frequently Asked Questions = Häufig gestellte Fragen) zu DelphiGL.com und dem DGL Wiki.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.3dsource.de/faq/index.htm 3dsource.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Ein FAQ zu Fragen rund um OpenGL.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Effekte und Techniken mit OpenGL ==&lt;br /&gt;
&lt;br /&gt;
===Glow===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamasutra.com/view/feature/2107/realtime_glow.php Gamasutra]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Beschreibt, wie man mit Hilfe von Shader(hier DirectX Shader) den Gloweffekt in Realtime umsetzt. Dabei wird erst die Technik dahinter erklärt, und dann wie man sie Schritt für Schritt umsetzt. &lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20071118043007/http://collective.valve-erc.com/index.php?go=tron1 valve-erc.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Schritt für Schritt Anleitung, wie man mit Hilfe von Cg in OpenGL den Glow Effekt realisieren kann &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===HDR===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20090601052809/http://www.gamedev.net/columns/hardcore/hdrrendering/ gamedev.net]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Hier wird sehr kurz eingeleitet, was HDR Rendering überhaupt ist, dann wird der Aufbau des *.hdr Formats erläutert, und dann geht es schon von 0 auf 100 zum Programmieren. Erklärungen gibt es kaum, dafür werden fertige Shader(für DirectX) geboten. &lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20090601202039/http://www.gamedev.net/reference/articles/article2208.asp gamedev.net]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Beschreibt auch nur etwas kurz das HDR Verfahren, jedoch mit mehr mathematischen Hintergrund in Sachen Tonemapping. Beispielcode für Tonemapping in C++ liegt bei. &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===BSP Bäume===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20081201115631/http://www.3dtechdev.com/tutorials/leafbsp/3dbsptrees.html 3dtechdev.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Das beste Dokument überhaupt, für allem die selber BSP Bäume compilieren möchte. Ist belegt mit sehr viel Grafik. Erst beginnt er das Prinzip allgemein zum umschreiben, dann wird alles genau erläutert, und mit verständlichen Pseudocode untermalt. &lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20081019041535/http://www.3dtechdev.com/tutorials/illegalgeometry/illegalgeometrytut.html 3dtechdev.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Nicht ganz so gut geworden, wie sein erstes Tutorial, aber erklärt auch sehr gut, wie man illegale Geometrie aufspürt und beseitigt. Wieder mit Grafiken und Pseudocodes verständlich belegt. Hiermit kann man seinem Map-Compiler den letzten Schliff verleien. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamedev.net/reference/articles/article981.asp Gamedev]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Von Michael Abrash, dürfte der ''Erfinder'' von Quake sein. Naja, meine Englischkenntnisse reichen hier nicht ganz aus, um den Text zu verstehen. Ist etwas umständlich geschrieben. Dafür mit Grafiken unterlegt. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.zfx-online.de/Tutorials.php?ID=11 Part 1 - Allgemein]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Einzigste deutsche Referenz zu BSP Bäumen, dafür Daumen hoch. Ist aber nicht das Wahre: schlechter C Code, und ich hatte auch nicht den Einduck, das er die Theorie zu diesem Thema bis in die Tiefe verstanden hat(oder er wollte es nicht zu akademisch Erklären oO). Aber ein guter Einstieg in dieses Thema. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.zfx-online.de/Tutorials.php?ID=13 Part 2 - Kollision und PVS]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20060516103821/http://www.cs.uwec.edu/~stevende/cs455/programs/GameTutorials%20-%20Quake%203%20BSP%20Format.htm Quake3 *.bsp Format]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Die beste Dokumentation für das BSP Format, die ich gefunden habe, besser als den Quake3 Sourcecode zu durchforsten. Leider etwas magere Eklährung zu wichtigen Themen wie Patches(Curved Surfaces). Ich pers. hatte jetzt 1 1/2 Wochen gebraucht, um das *.bsp Format vollständig zu verstehen. Ist aber anscheinend die beste Format Dokumentation im Netz. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.flipcode.com/articles/article_q2bsp.shtml Quake2 *.bsp Format]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Kann auch nur soviel sagen, wie beim Link zuvor. Es fehlen hier auch zum Teil Informationen. Man muss halt viel ausprobieren, und sich den Quake 2 Source zu Herzen nehmen, damit man es versteht. &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Himmel &amp;amp; Wolken===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamedev.net/community/forums/topic.asp?topic_id=86024 Gamedev]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Guter Thread mit vielen Anregungen und Links. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamedev.net/community/forums/topic.asp?topic_id=135654 Gamedev]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Hier wird die Diskussion zum obigen Link weitergeführt. &lt;br /&gt;
|-&lt;br /&gt;
|[http://freespace.virgin.net/hugo.elias/models/m_clouds.htm Plasma]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Eine nette Idee um Plasma in Echtzeit zu generieren, und zu verändern. Leider nichts zum Shading. &lt;br /&gt;
|-&lt;br /&gt;
|[http://nis-lab.is.s.u-tokyo.ac.jp/~nis/cdrom/sig00_cloud.pdf 3D Wolken]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Paper über generieren und rendern von 3 dimensionalen Wolken inklusive Schatten und Lichtstrahlen. Ich hab nur den Lichtstahlen-Algorithmus ausprobiert. Saulangsam aber sehr einfach zu implementieren. Einen Blick ist es auf jeden Fall wert. &lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20031011052035/http://www.geocities.com/ngdash/whitepapers/skydomecolor.html Skydome]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Wenn man mal schnell gute Farben für seinen Skydome braucht... &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Terrain===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.flipcode.com/articles/article_geomipmaps.shtml FlipCode]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Artikel zu Geomipmaping. Zummindest hab ich es hier zum ersten mal gesehen. Und es funzt ganz gut. &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.vterrain.org Virtual Terrain Project]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Eine Seite mit Links und Artikeln zu allem, was etwas mit Terrainrendering zu tun hat.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Sonstiges===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[[Materialsammlung]]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Sammlung von gängigen Parametern für [[glMaterial]] hier im Wiki.&lt;br /&gt;
|-&lt;br /&gt;
|[http://freespace.virgin.net/hugo.elias/radiosity/radiosity.htm Radiosity]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Erklärt sehr schön die Funktionsweise von Radiosity, liefert Beispielcodes und ist recht gut illustriert.&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20050825110920/http://legion.gibbering.net/projectx/paper/shadow%20mapping/ Shadowmapping]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Beschreibt das Trapezoidal Shadow Mapping - Verfahren für gerichte Lichter.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.flipcode.com/articles/article_generatingnames.shtml Namensgenerator]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Per Zufallsgenrator Namen erzeugen, und nie wieder kreativ werden müssen.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.paulsprojects.net/tutorials/simplebump/simplebump.html Bumpmapping]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Bumpmapping auf Lowend-Grakas. Damals war Bumpmapping noch was ganz tolles... &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.paulsprojects.net/opengl/dpreflect/dpreflect.html Dot Product Reflect]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|zwar nur ne Demo, aber wenn man schon immer mal mit EMBM das Wasser aus Morrowind nachproggen wollte... &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Beispiele/Demos mit Quelltext ==&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.delphigl.de DelphiGL.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Hier finden sich besonders eindrucksvolle Newton Physik Demos. Meißtens sogar mit Quelltext.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.shadow3d.de.vu/ Shadow 3D]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Hier finden sich zwei Demos wie man Quake 3 Modelle lädt und eine glSlang Demo&lt;br /&gt;
|-&lt;br /&gt;
|[[Shadersammlung]] im DGL Wiki&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Hier findet man freie Shadersourcen.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.humus.name Humus]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Diverse eindrucksvolle Demos zu verschiedenen Techniken, häufig mit Quelltext in C (teilweise OpenGL / DirectX)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== weitere Links ==&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www-user.tu-chemnitz.de/~pester/Lehre/CompGeo.pdf CompGeo.pdf]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Script &amp;quot;Einführung in die Computergeometrie&amp;quot; von Dr. Pester (TU-Chemnitz). Ideales Nachschlagewerk für die Mathematik die einem bei der Grafikprogrammierung so begegnet.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.robsite.de/ robsite.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Auf dieser riesigen Seite finden sich auch viele weitere Links über verschiedene Themen der 3D Programmierung.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.3dlinks.com/links.cfm?categoryid=3&amp;amp;subcategoryid=21 3dlinks.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Diese Seite hat es sich zur Hauptaufgabe gemacht Links auf Seiten mit dem Thema 3D zu sammeln.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.two-kings.de/links.html two-kings.de]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Sammlung diverser interessanter Links, vorallem auf Themen im gamedev-Forum verweisend.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.delgine.com Delgine.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Heimat des freien 3D Modellers &amp;quot;DeleD&amp;quot;, welcher in Delphi programmiert ist. Ihr findet dort auch Modellpackete, Texturpackete, Plugins und Hilfe bei der Programmierung von Delphi und OpenGL.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Spieleentwicklung =&lt;br /&gt;
&lt;br /&gt;
==Allgemein==&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.spieleprogrammierung.net/ Spieleprogrammierung - OpenGL - GLSL - OpenAL - KI - Animation - Spielephysik]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Auf dieser Seite findet Ihr Artikel, Tutorials und Programmbeispiele rund um das Thema Spieleprogrammierung. Programmiersprache ist hier C/C++.&lt;br /&gt;
|-&lt;br /&gt;
|[http://graphics-and-physics-framework.spieleprogrammierung.net/ OpenGL Graphics And Physics Framework]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Auf dieser Seite findet Ihr ein frei verfügbares OpenGL basiertes Grafik und Physik Framework (LGPL-Lizenz) samt zugehöriger Probammbeispiele. Programmiersprache ist hier C/C++.&lt;br /&gt;
|-&lt;br /&gt;
|[http://audio-framework.spieleprogrammierung.net/ OpenAL Audio Framework]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Auf dieser Seite findet Ihr ein frei verfügbares OpenAL Audio Framework (LGPL-Lizenz) samt zugehöriger Probammbeispiele. Unterstützt werden 3D Sounds, EFX (EAX Alternative) Reverb Effekte sowie Audio Streaming (Music and Voices). Programmiersprache ist hier C/C++.&lt;br /&gt;
|-&lt;br /&gt;
|[http://spieleentwicklung-im-web.spieleprogrammierung.net/ Spieleentwicklung im Web]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Auf dieser Seite findet Ihr Links (E-Books, Präsentationen, wissenschaftliche Arbeiten und Tutorials) zu verschiedenen Themengebieten der Spieleentwicklung.&lt;br /&gt;
|-&lt;br /&gt;
|[http://harablog.wordpress.com/2011/08/26/fast-pathfinding-via-symmetry-breaking/ Fast pathfinding via symmetry breaking]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Optimierungen für A* Pfadsuche durch Ausnutzung von Symmetrien.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Kopierschutz==&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://inner-smile.com/nocrack.phtml Inner-Smile.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Seite mit Gedanken zum Thema &amp;quot;Wie schütze ich meine Programme vor Crackern&amp;quot;. Falls die Seite nicht erreichbar ist hat Google noch ne [http://www.google.com/search?q=cache:hpqPT5G4WB0J:www.inner-smile.com/nocrack.phtml+http://inner-smile.com/nocrack.phtml&amp;amp;hl=de&amp;amp;gl=de&amp;amp;ct=clnk&amp;amp;cd=1 Version im Archiv].&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Künstliche Intelligenz ==&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20080319034335/http://www.kbs.uni-hannover.de/Lehre/KI2/Presentationen/presentation9798/esprit/spieltheorie/spieltheorie.html Uni-Hannover - Spieltheorie]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Artikel über die Grundlagen von KI in Spielen.&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20080927010337/http://www.robsite.de/tutorials.php?tut=ki Robsite KI-Tutorials]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Sammlung von Texten zum Thema KI in Spielen. Beispiele sind meist in C++.&lt;br /&gt;
|-&lt;br /&gt;
|[http://ai-depot.com/ AI-Depot.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Seite die sich ausschließlich mit KI in Spielen beschäftigt.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.ai-junkie.com/links.html AI-Junkie.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Linkseite mit vielen KI relevanten Links. Die Seite AI-Junie selbst behandelt auch viele Themen rund um KI.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.aiwisdom.com/ AIWisdom.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Seite die sich mit KIs in Spielen beschäftigt und sich zum Ziel gesetzt hat, alle Artikel zum Thema zu finden und zu Katalogisieren. Es gibt hier auch Artikel über die KIs bestehender Spiele.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.aiguru.com/ AIGuru.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Newsseite zum Thema KI, Künstliches Leben, Hiernforschung, Robotik, Nanotechnologie - Halt alles was Spaß macht.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.generation5.org/ Generation5.org]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Seite über KI, Robotik, etc. . Leider scheint die Seite Probleme zu haben regelmäßig aktualisiert zu werden. Aber zumindest sollte man einige Artikel finden. Die werden ja nicht schlecht.&lt;br /&gt;
|-&lt;br /&gt;
|[http://web.archive.org/web/20080702005527/http://www.gameai.com/ www.gameai.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|''Wurde Januar 2010 als down gemeldet. Weiss irgendwer etwas genaueres?'' Seite zum Thema KI in Spielen. Soll wohl einen gewissen Stellenwert in der AI-Szene haben.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www-i1.informatik.rwth-aachen.de/~algorithmus/algo19.php Algorithmus der Woche - Informatikjahr 2006]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Vielleicht schon etwas älter aber doch eine gute Anleitung um eine einfache Schach-KI zu erstellen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Ressourcen =&lt;br /&gt;
In dieser Gruppe finden sich Links um die Ressourcen für Eure Projekte zu erstellen.&lt;br /&gt;
&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;80%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://opengameart.org/ opengameart.org]&lt;br /&gt;
|Eine Seite die es jedem anbietet Spielressourcen wie Musik, Texturen, 3D-Modelle und anderes hochzuladen und diese unter einer beliebigen Lizenz zu veröffentlichen. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Texturen / 2D-Grafiken ==&lt;br /&gt;
&lt;br /&gt;
'''Legende:'''&lt;br /&gt;
:'''Kostenpflichtige Seiten''' sind mit einem * zu '''kennzeichnen'''&lt;br /&gt;
:GPL: Kompatibel mit der GPL&lt;br /&gt;
:MPL: Kompatibel mit der MPL&lt;br /&gt;
:OSS: Verwendung in OpenSource Software nicht verboten&lt;br /&gt;
:CSS: Verwendung in ClosedSource Software nicht verboten&lt;br /&gt;
:Komm: Verwendung in kommerzieller Software nicht verboten&lt;br /&gt;
&lt;br /&gt;
=== Texturen ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;10%&amp;quot;|Genre&lt;br /&gt;
!width=&amp;quot;10%&amp;quot;|Lizenz&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|GPL&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|MPL&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|OSS&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|CSS&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Komm.&lt;br /&gt;
!width=&amp;quot;35%&amp;quot;|Bemerkungen&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.davegh.com/vg/home.htm davegh.com]&lt;br /&gt;
|Fantasy&lt;br /&gt;
|[http://www.davegh.com/vg/termsandconditions.htm Eigene]&lt;br /&gt;
|?&lt;br /&gt;
|?&lt;br /&gt;
|✔&lt;br /&gt;
|✔&lt;br /&gt;
|✘&lt;br /&gt;
|Die Lizenz vererbt sich in die Projekte hinein.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.cgtextures.com/ cgtextures.com]&lt;br /&gt;
|Allgemein&lt;br /&gt;
|[http://www.cgtextures.com/content.php?action=license Eigene]&lt;br /&gt;
|✘&lt;br /&gt;
|✘&lt;br /&gt;
|✘&lt;br /&gt;
|?&lt;br /&gt;
|?&lt;br /&gt;
|Die Lizenz will im wesentlichen verhindern das Texturen in anderen Textursammlungen auftauchen. So wie ich das verstehe ist es kein Problem die Texturen unter einer anderen Lizenz zu veröffentlichen als die eigentliche Software. Die Software kann also sehr wohl OpenSource sein. Im Zweifelsfalls einfach den Support anschreiben, der ist sehr nett.&lt;br /&gt;
|-&lt;br /&gt;
|[https://wiki.openstreetmap.org/wiki/Texture_Library OpenStreetMap Texture Library]&lt;br /&gt;
|Allgemein &lt;br /&gt;
|Public Domain&lt;br /&gt;
|✘&lt;br /&gt;
|✘&lt;br /&gt;
|✘&lt;br /&gt;
|✘&lt;br /&gt;
|✘&lt;br /&gt;
|Die Texturen dienen der Visualisierung der 3D-Gebäude im OpenStreetMap Projekt&lt;br /&gt;
|-&lt;br /&gt;
|url&lt;br /&gt;
|Futuristisch, Mittelalter, etc.&lt;br /&gt;
|CC-BY-SA, etc., gerne auch mit Direktlink auf die Lizenzseite, so vorhanden.&lt;br /&gt;
|✔/✘/?&lt;br /&gt;
|✔/✘/?&lt;br /&gt;
|✔/✘/?&lt;br /&gt;
|✔/✘/?&lt;br /&gt;
|✔/✘/?&lt;br /&gt;
|Alle Bilder sind von Käse&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sonstige 2D-Grafiken ===&lt;br /&gt;
&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;45%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;10%&amp;quot;|Lizenz&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|GPL&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|MPL&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|OSS&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|CSS&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Komm.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.famfamfam.com/lab/icons/silk/ famfamfam silk]&lt;br /&gt;
|Iconset, welches inzwischen relativ weit verbreitet ist. 700 sauber gezeichnete, erkennbare PNG-Icons in TrueColor. Man kann praktisch jede (Arbeits-)Anwendung mit diesem Set vollständig mit Icons versorgen.&lt;br /&gt;
|[http://creativecommons.org/licenses/by/2.5/ CC-BY 2.5], [http://creativecommons.org/licenses/by/3.0/ CC-BY 3.0]&lt;br /&gt;
|✔&lt;br /&gt;
|✔&lt;br /&gt;
|✔&lt;br /&gt;
|✔&lt;br /&gt;
|✔&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Texturerstellung ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://3d.diehlsworld.de/textures/index.htm 3d.diehlsworld.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Auf dieser Seite findet ihr kurze aber inhaltlich reiche Tutorials zu der Frage &amp;quot;Wie erstelle ich XXXXX-Texturen&amp;quot;. Dabei reicht die Palette von Untergrundtexturen wie Gras, Sand , Fels und Wasser (und Kombinationen dieser) bis hin zu Blitzen und Partikeln. Als Programm wird hier Photoshop verwendet.&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gimps.de/gimp/textur-muster/ gimps.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Schritt für Schritt Anleitungen wie man mit Gimp verschiedene Texturen erstellt.&lt;br /&gt;
|-&lt;br /&gt;
|[http://cbt.k090999.de/gimp.php#texturen k090999.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Gimptutorials zum Erstellen verschiedene Texturen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Modelle / 3D-Grafiken ==&lt;br /&gt;
&lt;br /&gt;
=== Blender ===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://blendpolis.de/f/viewtopic.php?t=5786 Blendpolis]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Ein Thread im Forum von [http://blendpolis.de Blendpolis] in dem '''sehr''' viele Tutorials aufgelistet sind&lt;br /&gt;
|-&lt;br /&gt;
|[http://blendpolis.de/f/article_cat.php?fldAuto=7 Blendpolis]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
| Eigentliche Tutorial Seite von [http://blendpolis.de Blendpolis] die Auswahl ist hier aber nicht so groß&lt;br /&gt;
|-&lt;br /&gt;
|[http://wikivid.com/index.php/Blender Blender at wikivid.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Linksammlung von Blender Video Tutorials &lt;br /&gt;
|-&lt;br /&gt;
|[http://www.blender.org/education-help/tutorials/getting-started/ blender3d.org]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| Auch die Heimatseite von Blender bietet viele Tutorials unter anderm auch Video Tuorials&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.Blenderunderground.com Blenderunderground]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
| '''sehr gute''' Video-Tutorials&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Sounds ==&lt;br /&gt;
&lt;br /&gt;
===Musik===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.jamendo.com/ Jamendo.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Viele Künstler stellen hier ihre Alben unter einer Creative Commons Lizenz online. Man kann dort die Künstler auch kontaktieren und fragen ob man ihre Musik nutzen kann. Taugt außerdem als Radio! ;)&lt;br /&gt;
|-&lt;br /&gt;
|[http://incompetech.com/m/c/royalty-free/ Incompetech.com]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Viele sehr schön gemacht instrumentale Musik aus allen möglichen Genres. Sie ist frei verwenderbar, wenn man den Macher der Musik (Kevin MacLeod) in seinem Programm erwähnt. Aber das hat er auch verdient. Folgende Programme nutzen beispielsweise (auch) Musik von incompetech.com:&lt;br /&gt;
* OpenParty&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Soundeffekte===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.freesound.org/ freesound.org]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|Diverse Sounds unter [http://www.creativecommons.org/ CreativeCommons] Lizenzen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Soundprogramme===&lt;br /&gt;
{| width = &amp;quot;100%&amp;quot; {{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;25%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;5%&amp;quot;|Sprache&lt;br /&gt;
!width=&amp;quot;70%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://audacity.sourceforge.net/?lang=de Sourceforgeseite von Audacity]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Ein einfaches, freies Programm um Sounddateien zu bearbeiten. Man kann es auch nutzen um Soundeffekte neu zu erstellen, indem man z.B. ein Geräusch mit dem Mikrofon aufnimmt und einige Effekt anwendet, um es passender und nicht mehr aufgenommen klingen zu lassen.&lt;br /&gt;
|-&lt;br /&gt;
|[http://lmms.sourceforge.net/ LMMS]&lt;br /&gt;
|{{Englisch}}&lt;br /&gt;
|LMMS (Linux MultiMedia Studio) ist ein OpenSource+Freeware Composer-Programm ähnlich zum bekannteren aber auch teuren CuBase(r). Trotz des Namens auch für Windows erhältlich.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=25845</id>
		<title>Techniken und Algorithmen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=25845"/>
				<updated>2013-09-25T14:17:02Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Dynamische Effekte */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Artikel dieses Wiki-Abschnittes sind im Gegensatz zu den [[Tutorial]]s meist kürzer. Dafür enthalten sie mitunter sehr viel Code der direkt verwendet werden, oder als Grundlage für die eigene Arbeit dienen kann.&lt;br /&gt;
&lt;br /&gt;
== Was hier hinein gehört ==&lt;br /&gt;
Hier kommen, wie der Name vermuten lässt '''Erklärungen''' zu, in der 3D-Echtzeitprogrammierung verwendeten, '''Techniken''' hin. Z.B. verschiedene Schattentechniken, Bump-Mapping, etc.&lt;br /&gt;
&lt;br /&gt;
[[Hintergrundwissen]] gehört hier nicht rein. Sachen wie ''&amp;quot;was ist ein Tiefenpuffer und wofür ist er gut&amp;quot;'' haben hier nichts zu suchen.&amp;lt;br&amp;gt;&lt;br /&gt;
Sollte es für eine Technik/Thematik (siehe unten für Beispiel) mehrere &amp;quot;Lösungswege&amp;quot; geben, sollte eine kleine Überschrift eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr einen Technik oder Algorithmus Artikel erstellt, so solltet ihr unter den Artikel ein&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[Kategorie:Technik_oder_Algorithmus]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
stellen. Damit wird der Artikel der  [[:Kategorie:Technik_oder_Algorithmus]] zugeordnet.&lt;br /&gt;
Falls dieser Artikel nicht nur erklärt was der Begriff bedeutet, sondern auch noch eine Anleitung ist, wie man die entsprechende Technik realisiert, so könnt ihr den Artikel auch noch der Kategorie [[:Kategorie:Anleitung|Anleitung]] zuweisen.&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
=== Sammlungen ===&lt;br /&gt;
* [[Materialsammlung]] (Enthält Materialien für [[glMaterial]].)&lt;br /&gt;
* [[Shadersammlung]] (Enthält Shader.)&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Helfer ===&lt;br /&gt;
In dieser Rubrik findet sich all das, was ein OpenGL/Graphikprogrammierer immer brauch oder schnell mal zur Hand haben muss:&lt;br /&gt;
* [[Framecounter]] (Wie schnell läuft mein Programm?)&lt;br /&gt;
* [[Frameratenbegrenzung]] (Beschränken der Bildwiederholrate und sparen von CPU-Leistung und Strom)&lt;br /&gt;
* [[Texture Loader]] (Laden und verwalten von Texturen)&lt;br /&gt;
* [[Model Loader]] (Laden von Modellen die mit Programmen wie 3D Studio Max, Lightwave, Milkshape usw. erstellt wurden.)&lt;br /&gt;
* Eine Möglichkeit zum [[Text ausgeben]]&lt;br /&gt;
* [[Kamera]]&lt;br /&gt;
** [[Kamera (1)]] (Szene in drei Ebenen verschieben und drehen, jetzt mit Beispielprogramm)&lt;br /&gt;
** [[Kamera (2)]] (Kamera Source, letztes Update 1.10.2006)&lt;br /&gt;
** [[Kamera (3)]] (Für die Kamera benötigte Utilities)&lt;br /&gt;
* [[Extensionausgabe]] (Ausgabe der unterstützten Extensions und sonstiger Eigenschaften)&lt;br /&gt;
* [[Techniken_zur_Matrixinversion|Techniken zur Matrixinversion]]&lt;br /&gt;
&lt;br /&gt;
=== Mathematisches ===&lt;br /&gt;
==== Geometrie Objekte ====&lt;br /&gt;
In dieser Rubrik findet ihr Code zum erzeugen von komplexen geometrischen Objekten, denn nicht immer ist die Kapselung die z.B. eine [[Quadrik]] bietet das was man sucht. &lt;br /&gt;
&lt;br /&gt;
* [[Würfel]]&lt;br /&gt;
* [[Kugel]]&lt;br /&gt;
* [[Zylinder]]&lt;br /&gt;
* [[Paraboloid]]&lt;br /&gt;
* [[Hyperboloid]]&lt;br /&gt;
* [[Capsule]]&lt;br /&gt;
* [[Scheibe]]&lt;br /&gt;
* [[Kreis]]&lt;br /&gt;
* [[Kuchenstück]]&lt;br /&gt;
* [[Zweifach_Parametrisierte_Geometrie|Geometrie durch zwei Parameter]]&lt;br /&gt;
* [[Geometrie_durch_Kurven|Geometrie durch Kurven]]&lt;br /&gt;
* [[Rotationskörper]]&lt;br /&gt;
&lt;br /&gt;
==== Rechenhilfen ====&lt;br /&gt;
* [[Matrixmultiplikation]]&lt;br /&gt;
&lt;br /&gt;
=== Licht und Schatten ===&lt;br /&gt;
Das Beleuchtungsmodell von OpenGL besitzt von Haus aus keine Möglichkeit zur Darstellung von Schatten (nicht zuletzt weil es dafür immernoch keine einheitliche Methode gibt), allerdings haben sich über die Jahre hinweg einige Techniken mehr oder weniger durchgesetzt :&lt;br /&gt;
* [[Lightmaps]]&lt;br /&gt;
* [[Projezierte Shadowmaps]] / [[Projezierte Textur]]en&lt;br /&gt;
* [[Volumetrische Stencilschatten]]{{excIcon}}&lt;br /&gt;
* [[Silhouette]] {{icpIcon}}&lt;br /&gt;
* [[Bloom(pseudo-HDR)]] {{icpIcon}}&lt;br /&gt;
&lt;br /&gt;
=== Statische Umgebungen ===&lt;br /&gt;
Besonders in Aussenszenen ist es oft nötig dem Betrachter den Eindruck zu vermitteln, er befinde sich in einer unendlich großen Umgebung. Da man dies jedoch schlecht über speziell dafür erstellte Geometrie lösen kann (weil das schlichtweg zu viel Aufwand und zu leistungsintensiv wäre), haben sich einige Techniken eingebürgert, mit denen man dem Betrachter eine solche unendliche Landschaft mit  wenig Geometrie und einigen Tricks vorgaugeln kann :&lt;br /&gt;
* [[Skyboxen]]&lt;br /&gt;
* [[Skydome]]&lt;br /&gt;
* [[Skysphere]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Dynamische Effekte ===&lt;br /&gt;
Das Auge isst bekanntlich mit. Auch bei 3D Anwendungen, vor allem in der Unterhaltungsindustrie, spielen gigantische Effekte, die dem User ein &amp;quot;Ohhh&amp;quot; und &amp;quot;Ahhh&amp;quot; und vor allem &amp;quot;Wow!&amp;quot; entlocken eine immer größere Rolle. Wie man solche Effekte am besten implementiert finden Sie in den Artikeln dieses Abschnitts.&amp;lt;br&amp;gt;&lt;br /&gt;
(Befassen Sie sich zuerst mit den Grundlagen von [[Partikelsysteme|Partikelsystemen]].)&lt;br /&gt;
* [[Explosionen]] (Allseits gern gesehen. Außer in direkter Nachbarschaft)&lt;br /&gt;
* [[Lichtsäulen]] (Bekannt für die magischen Momente in diversen Rollenspielen.)&lt;br /&gt;
* [[Partikelsysteme]] {{excIcon}} (Grundlage für viele Effekte)&lt;br /&gt;
** [[GLSL Partikel]] (Partikelsystem auf der GPU)&lt;br /&gt;
** [[GLSL Partikel 2]] (Partikelsystem auf der GPU mit Shader Model 4.0)&lt;br /&gt;
&lt;br /&gt;
=== Natürliche Phänomene ===&lt;br /&gt;
Ziel vieler Echtzeit 3D-Anwendung (auch wenn genau der gegenteilige Trend manchmal interessant sein dürfte) ist eine zumindest optische Annäherung an die Realität, also Szenen möglichst &amp;quot;naturgetreu&amp;quot; (auch urbane Szenen können &amp;quot;naturgetreu&amp;quot; sein, auch wenn diese wenig natürlich sind) darzustellen. Dazu gehören auch natürliche Phänomene, wie z.B. realistisch spiegelndes Wasser, Wetterbedingungen (Regen, Schnee, Nebel), Feuer, etc. Oft gibt es für ein natürliches Phänomen recht fortgeschrittene Umsetzungsmöglichkeiten, manchmal liegt die Lösung aber auch recht nahe :&lt;br /&gt;
* [[Prozeduale Bäume|Bäume]]&lt;br /&gt;
* [[Blitz]]&lt;br /&gt;
* [[Feuer]]&lt;br /&gt;
* [[Himmel]]&lt;br /&gt;
* [[Nebel]]&lt;br /&gt;
* [[Staub]]&lt;br /&gt;
* [[Tiefenunschärfe]]&lt;br /&gt;
* [[Wasser]]&lt;br /&gt;
* [[Wettereffekt]]e (Regen, Schnee)&lt;br /&gt;
* [[Wolken]] (als Ergänzung zu den statischen Umgebungen)&lt;br /&gt;
&lt;br /&gt;
=== Raumunterteilungstechniken ===&lt;br /&gt;
Moderne 3D-Anwendungen müssen immer größere und komplexere 3D-Umgebungen darstellen, wobei oft jedoch große Teile eben dieser nicht sichtbar sind, aber ohne entsprechende Optimierungen trotzdem über den Datenbus geschoben (und von der Grafikkarte geclippt) werden müssen. Deshalb finden diverse Raumunterteilungstechniken (die u.a. aus anderen Bereichen stammen) in modernen 3D-Programmen Anwendung :&lt;br /&gt;
* [[BSP-Bäume]] (Binary Space Partitioning = Binäre Raumunterteilung)&lt;br /&gt;
* [[Quadtree]]s &lt;br /&gt;
* [[Octree]]s (Dreidimensionale Erweiterung eines [[Quadtree]]s)&lt;br /&gt;
* [[Portal]]e (Logische Sichtbegrenzung an Durchgängen)&lt;br /&gt;
* [[PVS]] (Potentially Visible Sets = Mögliche sichtbare Sets)&lt;br /&gt;
&lt;br /&gt;
=== Terrain Darstellung ===&lt;br /&gt;
In vielen 3D Anwendungen, vom Flugsimulator über Egoshooter bis zum Strategiespiel, muss die Umgebung visualisiert werden. Welche Techniken bei der Speicherung (siehe auch '''Raumunterteilungstechniken'''), Bildaufbau und Texturierung zum Einsatz kommen, findet ihr hier:&amp;lt;br&amp;gt;&lt;br /&gt;
:'''[[LOD|Level of Detail]] Algorithmen für Landschaften'''&lt;br /&gt;
&lt;br /&gt;
*[[VDPM]] ('''V'''iew-'''D'''ependent '''P'''rogressive '''M'''eshes)&lt;br /&gt;
*[[ROAM]] ('''R'''eal-time '''O'''ptimally '''A'''dapting '''M'''eshes)&lt;br /&gt;
*[[Tutorial_Terrain3|Röttger Algorithmus]]&lt;br /&gt;
*[[Geometrical Mipmapping]]&lt;br /&gt;
*[[VIPMs]] ('''V'''iew '''I'''ndependent '''P'''rogressive '''M'''eshe'''s''')&lt;br /&gt;
&lt;br /&gt;
:'''Texturierung'''&lt;br /&gt;
&lt;br /&gt;
*[[Texture Splatting]] (Kombination von Texturen mittels [[Blenden|Blending]] und [[Multitexturing]])&lt;br /&gt;
*[[Texture Backing]] (Dynamisches erstellen von Texturen)&lt;br /&gt;
&lt;br /&gt;
=== Prozeduale Grafiken ===&lt;br /&gt;
Prozeduale Grafiken werden häufig verwendet um&lt;br /&gt;
*eine vielfältige Umgebung zu gewährleisten&lt;br /&gt;
*Speicherplatz auf der Festplatte zu sparen&lt;br /&gt;
*den Grafikern die Arbeit zu erleichtern (und teilweise sogar erst zu ermöglichen)&lt;br /&gt;
Die Algorithmen und Möglichkeiten die sich dabei bieten sind hier aufgelistet:&lt;br /&gt;
* [[Perlin Noise]] {{excIcon}} (Algorithmus für Texturen, Landschaft und vieles mehr)&lt;br /&gt;
* [[L-Systems]] (aus wenig mach viel, Landschaftsgenerierung, Baumgenerierung, ...)&lt;br /&gt;
* [[Fault Formation]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Prozeduale Landschaft]] (Spezielle Hinweise und Techniken zur Landschaftsgenerierung&lt;br /&gt;
* [[Midpoint Displacement]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Hügel_Algorithmen]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Prozeduale Bäume]] (Techniken und Algorithmen speziell zur Baumgenerierung)&lt;br /&gt;
* [[Prozeduale Texturen]] (Spezielle Hinweise zu Wasser, Lava und ähnliches)&lt;br /&gt;
&lt;br /&gt;
=== Pathfinding ===&lt;br /&gt;
Pathfinding ist einer der grundlegenden Bereiche der Künstlichen Intelligenz, und aus diesem Grund für Spiele mit Computergegnern meistens unumgänglich.&lt;br /&gt;
* [[Tiefensuche]]&lt;br /&gt;
* [[Breitensuche]]&lt;br /&gt;
* [[A-Stern]]&lt;br /&gt;
* [[Dijkstra]]&lt;br /&gt;
* [[Floyd Warshall]]&lt;br /&gt;
* [[Navigation Meshes]]&lt;br /&gt;
* [[Pathfinding-Level of Detail]]&lt;br /&gt;
&lt;br /&gt;
=== Sonstiges ===&lt;br /&gt;
* [[Bilder als Ressourcen]] speichern und laden&lt;br /&gt;
* [[Blenderscript|Exportscript für Blender]]&lt;br /&gt;
* [[Blenderexporter|Blenderexport ausführliche Anleitung]]&lt;br /&gt;
* [[GUI_Leitfaden|Leitfaden Graphisches Nutzerinterface]]&lt;br /&gt;
* [[Interpolation]]&lt;br /&gt;
* [[Lokalisierung]]&lt;br /&gt;
* [[Pixelweise Bildbearbeitung]]&lt;br /&gt;
* [[Physik und 3D|Wie verbinde ich Physikberechnung und 3D Rendering?]]&lt;br /&gt;
* [[Screenshot]]s von OpenGL Ausgaben&lt;br /&gt;
* [[Tesselierung|Polygone tesselieren]]&lt;br /&gt;
* [[TGA Bilder laden]]&lt;br /&gt;
* [[Verfügbare Auflösungen]] anzeigen&lt;br /&gt;
* [[Zielen auf bewegte Gegner]]&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
Weitere Links zum Thema &amp;quot;Effekte unter OpenGL&amp;quot; findet ihr in der [[Link]]-Sammlung unter [[Link#Effekte_und_Techniken_mit_OpenGL|Effekte und Techniken mit OpenGL]].&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=25684</id>
		<title>Boneanimation per Vertexshader</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=25684"/>
				<updated>2012-06-29T15:34:25Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Matrix basierende Boneanimation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richtet sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Auch Kenntnisse über Quaternionen oder Matrizen sind vorausgesetzt.&lt;br /&gt;
&lt;br /&gt;
Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern. Jedoch sollten variablen die über das ganze Model gleich bleiben, auf der CPU berechnet werden.&lt;br /&gt;
&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen wollte, ist hier genau richtig.&lt;br /&gt;
&lt;br /&gt;
==Grundlagen==&lt;br /&gt;
&lt;br /&gt;
===Was sind Bones===&lt;br /&gt;
&lt;br /&gt;
Bones entsprechen nicht nur Knochen. Mathematisch gesehen repräsenteriert jeder Bone eine Transformationsmatrix, der einen gewichteten Einfluss auf verschiedene Vertices nehmen kann. Da Bones sehr häufig in einem Animationsskelet zusammengefast sind, werden sie durch Gelenke (Joints) verbunden, die Drehpunkten der Matrizen entsprechen. &lt;br /&gt;
Sehr häufig werden Bones als Stab oder ähnliches dargestellt, sie können jedoch auch komplexer Formen haben (z.B. das Becken einen Menschen). Bones die durch ein festes unbewegliches Gelenk verbunden sind sollten umbedingt vermieden werden, da sie nur Resurcen kosten ohne einen Nutzen zu bringen.&lt;br /&gt;
Grundsätzlich sollte alles was sich unabhängig voneinander bewegen können muss durch einen eigenen Bone dargestellt werden. Neben den nachgebildeten Kochen, gehören auch andere bewegliche Modelteile dazu wie Mimik und Augen.&lt;br /&gt;
&lt;br /&gt;
===Woher kommen die Animationsdaten?===&lt;br /&gt;
&lt;br /&gt;
Die Animationen können entweder aufgezeichnete Daten sein, durch Inverse Kinematik erzeugt werde oder aus einer Physikengine stammen. Bei einfachen Modellen ist es auch möglich diese Daten per Scripsprache zu erzeugen. In diesem Artikel werden die Bones eher als Schnittstelle dienen und Animationsdaten aus Blender übernommen.&lt;br /&gt;
&lt;br /&gt;
===Limits===&lt;br /&gt;
&lt;br /&gt;
Aktuelle Grafikkarten erlauben 256 bis 1024 Uniformvariablend des Typs Float4. Für einen Bone werden zwei bis vier Float4 vektoren benötigt. Damit lassen sich etwa 80 bis 500 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellen diese Werte kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert durch Spiegelung fast verdoppeln. Wenn das nicht ausreicht macht es Sinn bei Objekte mit vielen Bones Teile wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Modeldaten==&lt;br /&gt;
&lt;br /&gt;
Das Vertexbufferobjekt muss zu den sonst verwendeten Daten wie Vertices, Normalen, Texturkoordinaten und gegebenfalls Tangent und Bitangent noch zusätzliche Daten über die Abhängigkeit zu den Bones gespeichert werden. &lt;br /&gt;
&lt;br /&gt;
Im einfachstem Fall kann jedem Vertex nur ein Bone zugewiesen werden. Hier genügt ein einzelner Integer, der als Index dient.&lt;br /&gt;
&lt;br /&gt;
Wenn zwischen meheren Bones interpoliert werden soll, ist als erstes ein Wert nötig, der angibt wie viele Bones einen Einfluss auf den Vertex haben. Dann muss für jeden Bone die Gewichtung als Float und der Index als Int gespeichert werden. In den meisten Fällen sollte der Einfluss von vier Bones ausreichen.&lt;br /&gt;
Um die größe der Geometriedaten (Attribute) klein zu halten macht es Sinn, den Index mit der Gewichtung zu addieren. Da die Summe aller gewichungen 1.0 ist, ist das trennen im shader kein problem. Lediglich der Sonderfall der Gewichtung von 1.0, muss auf zwei Gewichtungen zu 0.5 aufgeteilt werden. &lt;br /&gt;
&lt;br /&gt;
In den Meisten Fällen beinflussen nur zwei Bones einen Vertex. Ein Knie sieht etwas seltsam aus wenn am Gelenk linear interpoliert wird. Hier kann ein Quaternion basierendes Animationsystem zu mehr Qualität helfen.&lt;br /&gt;
&lt;br /&gt;
==Vertexshader==&lt;br /&gt;
&lt;br /&gt;
Hier werden die beiden Varianten von Vertexshadern beschrieben. &lt;br /&gt;
&lt;br /&gt;
===Matrix basierende Boneanimation===&lt;br /&gt;
&lt;br /&gt;
Zum Gewichten werden pro Matrix 4 Vektor MADDs (Multiplikation und Addition) benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute vec4 Bones; &lt;br /&gt;
attribute vec3 Tangent; &lt;br /&gt;
uniform mat4 Pose[32]; &lt;br /&gt;
varying vec3 T,B,N; &lt;br /&gt;
 &lt;br /&gt;
void main(void){ &lt;br /&gt;
	mat4 mat = 0.0; &lt;br /&gt;
 &lt;br /&gt;
	for ( int i = 0; i &amp;lt; 4; i++){ &lt;br /&gt;
		mat += Pose[int(Bones[i])] * fract(Bones[i]); &lt;br /&gt;
		} &lt;br /&gt;
 &lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat *gl_Vertex); &lt;br /&gt;
&lt;br /&gt;
	mat3 m3 = mat3(mat[0].xyz, mat[0].xyz, mat[0].xyz); // &amp;quot;mat3(mat)&amp;quot;&lt;br /&gt;
 	&lt;br /&gt;
	N = gl_NormalMatrix * (m3 * gl_Normal); &lt;br /&gt;
	//T = gl_NormalMatrix * (m3 * Tangent); &lt;br /&gt;
	//B = cross (T,N); &lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0; &lt;br /&gt;
	} &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinnvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlastet werden kann:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
	gl_Position = gl_ProjectionMatrix * (mat *gl_Vertex); &lt;br /&gt;
&lt;br /&gt;
	N = m3 * gl_Normal; &lt;br /&gt;
	//T = m3 * Tangent; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Lange gab es die diskusion ob Quaternion in shadern überhaupt Sinn machen, bei der Boneanimation im Vertexshader, hat sich herausgestellt, das die Anzahl der benötigten Instruktionen ähnlich ist wie bei der Matrix basierenden Variante. Der entscheidene Vorteil ist das sie  für organische strukturen qualitativ besser ist und das nur zwei Uniform Float4 Vektoren pro Joint/Bone verbraucht werden.&lt;br /&gt;
Etwas problematisch ist, dass die Vertexpositionen nicht mehr absolut zum Modelnullpunkt, sondern relativ zu dem Joint angegeben werden muss um das eine spherische Interpolation durchgeführt werden soll. Die W-komponente wird dabei durch die Indexnummer des Joints ersetzt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute vec4 Bones; &lt;br /&gt;
attribute vec3 Tangent; &lt;br /&gt;
 &lt;br /&gt;
uniform vec3 Joints[32]; &lt;br /&gt;
uniform vec4 Quaternions[32]; &lt;br /&gt;
varying vec3 T,B,N; &lt;br /&gt;
 &lt;br /&gt;
vec3 qrot( vec4 q, vec3 v ){ &lt;br /&gt;
	return v + 2.0*cross(q.xyz, cross(q.xyz ,v) + q.w*v); &lt;br /&gt;
	} &lt;br /&gt;
 &lt;br /&gt;
void main(void){ &lt;br /&gt;
	vec4 quaternion = vec4(0.0, 0.0, 0.0, 0.0); &lt;br /&gt;
 &lt;br /&gt;
	for ( int i = 0; i &amp;lt; 4; i++){ &lt;br /&gt;
		quaternion += Quaternions[Bones[i]] * fract(Bones[i]); &lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	normalize(quaternion); &lt;br /&gt;
 &lt;br /&gt;
	vec4 vert = vec4(qrot(quaternion,gl_Vertex.xyz) + Joints[gl_Vertex.w] ,1.0) &lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vert; &lt;br /&gt;
 &lt;br /&gt;
	N = gl_NormalMatrix * qrot(quaternion, gl_Normal); &lt;br /&gt;
	//T = gl_NormalMatrix * qrot(quaternion, Tangent); &lt;br /&gt;
	//B = cross (T,N); &lt;br /&gt;
 &lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0; &lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die qrot Funktion rotiert einen Vektor mit hilfe eines Quaternions. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auch hier kann es sinnvoll sein, die Joints in den Modelviewspace zu transformieren und die Quaternionen mit der Normalmatrix (gegebenfals in ein Quaternion umwandeln) zu rotieren:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
	gl_Position = gl_ProjectionMatrix * vert; &lt;br /&gt;
 &lt;br /&gt;
	N = qrot(quaternion, gl_Normal); &lt;br /&gt;
	//T = qrot(quaternion, Tangent); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==CPU side Stuff==&lt;br /&gt;
&lt;br /&gt;
Wer gedacht hat das war es schon, wird nun leider entäuscht werden, es ist zwar nur ein geringes Problem um die uniform arrays mit fertigen Posen zu füllen, die man z.B. mit einem Blender exporter erzeugen könnte, jedoch macht es mehr Sinn eine Armature zu bauen über die man das Modell manipulieren kann. Zur inversen Kinematik ist es dann nur noch ein kleiner Schritt. Die Armature kann Quaternion als auch Matrix basierend aufgebaut werden. Für alle die Quaternionen noch etwas fremdes sind, hilft es sehr wenn man diese als eine andere Form von Rotationsmatrizen betrachted, auch wenn sie etwas andere Eigenschaften haben.&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich sind folgende Eigenschaften für jeden Bone unverzichtbar:&lt;br /&gt;
&lt;br /&gt;
Initial Joint Position, einem Positionsvektor mit 3 Kompoinenten.&lt;br /&gt;
Aktuelle Joint Position, ebenfalls einem Positionsvektor.&lt;br /&gt;
Die Rotation, sie kann durch ein Quaternion oder eine Rotationsmatrix dargestellt werden.&lt;br /&gt;
Eine Liste aller Children.&lt;br /&gt;
&lt;br /&gt;
Unnötig sind dagegen:&lt;br /&gt;
Ein zweites Boneende, wie viele Editoren es verwenden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird ein Bone rotiert, müssen alle Children mit rotiert werden. Das beiduetet, das sich deren Rotationen und Jointpositionen ändern. Alle Joints müssen dabei um den eigenen Joint mit der entsprechnden Rotation rotiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To continue...&lt;br /&gt;
&lt;br /&gt;
==Externe Links==&lt;br /&gt;
&lt;br /&gt;
http://lumina.sourceforge.net/?id=27 Beispiel in Lumina. Der mit Lumina mitgelieferte Blenderexporter ist in der Lage die benötigten Daten zu erzeugen.&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=25683</id>
		<title>Boneanimation per Vertexshader</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=25683"/>
				<updated>2012-06-29T15:33:28Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Matrix basierende Boneanimation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richtet sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Auch Kenntnisse über Quaternionen oder Matrizen sind vorausgesetzt.&lt;br /&gt;
&lt;br /&gt;
Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern. Jedoch sollten variablen die über das ganze Model gleich bleiben, auf der CPU berechnet werden.&lt;br /&gt;
&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen wollte, ist hier genau richtig.&lt;br /&gt;
&lt;br /&gt;
==Grundlagen==&lt;br /&gt;
&lt;br /&gt;
===Was sind Bones===&lt;br /&gt;
&lt;br /&gt;
Bones entsprechen nicht nur Knochen. Mathematisch gesehen repräsenteriert jeder Bone eine Transformationsmatrix, der einen gewichteten Einfluss auf verschiedene Vertices nehmen kann. Da Bones sehr häufig in einem Animationsskelet zusammengefast sind, werden sie durch Gelenke (Joints) verbunden, die Drehpunkten der Matrizen entsprechen. &lt;br /&gt;
Sehr häufig werden Bones als Stab oder ähnliches dargestellt, sie können jedoch auch komplexer Formen haben (z.B. das Becken einen Menschen). Bones die durch ein festes unbewegliches Gelenk verbunden sind sollten umbedingt vermieden werden, da sie nur Resurcen kosten ohne einen Nutzen zu bringen.&lt;br /&gt;
Grundsätzlich sollte alles was sich unabhängig voneinander bewegen können muss durch einen eigenen Bone dargestellt werden. Neben den nachgebildeten Kochen, gehören auch andere bewegliche Modelteile dazu wie Mimik und Augen.&lt;br /&gt;
&lt;br /&gt;
===Woher kommen die Animationsdaten?===&lt;br /&gt;
&lt;br /&gt;
Die Animationen können entweder aufgezeichnete Daten sein, durch Inverse Kinematik erzeugt werde oder aus einer Physikengine stammen. Bei einfachen Modellen ist es auch möglich diese Daten per Scripsprache zu erzeugen. In diesem Artikel werden die Bones eher als Schnittstelle dienen und Animationsdaten aus Blender übernommen.&lt;br /&gt;
&lt;br /&gt;
===Limits===&lt;br /&gt;
&lt;br /&gt;
Aktuelle Grafikkarten erlauben 256 bis 1024 Uniformvariablend des Typs Float4. Für einen Bone werden zwei bis vier Float4 vektoren benötigt. Damit lassen sich etwa 80 bis 500 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellen diese Werte kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert durch Spiegelung fast verdoppeln. Wenn das nicht ausreicht macht es Sinn bei Objekte mit vielen Bones Teile wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Modeldaten==&lt;br /&gt;
&lt;br /&gt;
Das Vertexbufferobjekt muss zu den sonst verwendeten Daten wie Vertices, Normalen, Texturkoordinaten und gegebenfalls Tangent und Bitangent noch zusätzliche Daten über die Abhängigkeit zu den Bones gespeichert werden. &lt;br /&gt;
&lt;br /&gt;
Im einfachstem Fall kann jedem Vertex nur ein Bone zugewiesen werden. Hier genügt ein einzelner Integer, der als Index dient.&lt;br /&gt;
&lt;br /&gt;
Wenn zwischen meheren Bones interpoliert werden soll, ist als erstes ein Wert nötig, der angibt wie viele Bones einen Einfluss auf den Vertex haben. Dann muss für jeden Bone die Gewichtung als Float und der Index als Int gespeichert werden. In den meisten Fällen sollte der Einfluss von vier Bones ausreichen.&lt;br /&gt;
Um die größe der Geometriedaten (Attribute) klein zu halten macht es Sinn, den Index mit der Gewichtung zu addieren. Da die Summe aller gewichungen 1.0 ist, ist das trennen im shader kein problem. Lediglich der Sonderfall der Gewichtung von 1.0, muss auf zwei Gewichtungen zu 0.5 aufgeteilt werden. &lt;br /&gt;
&lt;br /&gt;
In den Meisten Fällen beinflussen nur zwei Bones einen Vertex. Ein Knie sieht etwas seltsam aus wenn am Gelenk linear interpoliert wird. Hier kann ein Quaternion basierendes Animationsystem zu mehr Qualität helfen.&lt;br /&gt;
&lt;br /&gt;
==Vertexshader==&lt;br /&gt;
&lt;br /&gt;
Hier werden die beiden Varianten von Vertexshadern beschrieben. &lt;br /&gt;
&lt;br /&gt;
===Matrix basierende Boneanimation===&lt;br /&gt;
&lt;br /&gt;
Zum gewichten werden pro Matrix 4 Vector MADDs (Multiplikation und Addition) benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute vec4 Bones; &lt;br /&gt;
attribute vec3 Tangent; &lt;br /&gt;
uniform mat4 Pose[32]; &lt;br /&gt;
varying vec3 T,B,N; &lt;br /&gt;
 &lt;br /&gt;
void main(void){ &lt;br /&gt;
	mat4 mat = 0.0; &lt;br /&gt;
 &lt;br /&gt;
	for ( int i = 0; i &amp;lt; 4; i++){ &lt;br /&gt;
		mat += Pose[int(Bones[i])] * fract(Bones[i]); &lt;br /&gt;
		} &lt;br /&gt;
 &lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat *gl_Vertex); &lt;br /&gt;
&lt;br /&gt;
	mat3 m3 = mat3(mat[0].xyz, mat[0].xyz, mat[0].xyz); // &amp;quot;mat3(mat)&amp;quot;&lt;br /&gt;
 	&lt;br /&gt;
	N = gl_NormalMatrix * (m3 * gl_Normal); &lt;br /&gt;
	//T = gl_NormalMatrix * (m3 * Tangent); &lt;br /&gt;
	//B = cross (T,N); &lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0; &lt;br /&gt;
	} &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinnvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
	gl_Position = gl_ProjectionMatrix * (mat *gl_Vertex); &lt;br /&gt;
&lt;br /&gt;
	N = m3 * gl_Normal; &lt;br /&gt;
	//T = m3 * Tangent; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Lange gab es die diskusion ob Quaternion in shadern überhaupt Sinn machen, bei der Boneanimation im Vertexshader, hat sich herausgestellt, das die Anzahl der benötigten Instruktionen ähnlich ist wie bei der Matrix basierenden Variante. Der entscheidene Vorteil ist das sie  für organische strukturen qualitativ besser ist und das nur zwei Uniform Float4 Vektoren pro Joint/Bone verbraucht werden.&lt;br /&gt;
Etwas problematisch ist, dass die Vertexpositionen nicht mehr absolut zum Modelnullpunkt, sondern relativ zu dem Joint angegeben werden muss um das eine spherische Interpolation durchgeführt werden soll. Die W-komponente wird dabei durch die Indexnummer des Joints ersetzt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
attribute vec4 Bones; &lt;br /&gt;
attribute vec3 Tangent; &lt;br /&gt;
 &lt;br /&gt;
uniform vec3 Joints[32]; &lt;br /&gt;
uniform vec4 Quaternions[32]; &lt;br /&gt;
varying vec3 T,B,N; &lt;br /&gt;
 &lt;br /&gt;
vec3 qrot( vec4 q, vec3 v ){ &lt;br /&gt;
	return v + 2.0*cross(q.xyz, cross(q.xyz ,v) + q.w*v); &lt;br /&gt;
	} &lt;br /&gt;
 &lt;br /&gt;
void main(void){ &lt;br /&gt;
	vec4 quaternion = vec4(0.0, 0.0, 0.0, 0.0); &lt;br /&gt;
 &lt;br /&gt;
	for ( int i = 0; i &amp;lt; 4; i++){ &lt;br /&gt;
		quaternion += Quaternions[Bones[i]] * fract(Bones[i]); &lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	normalize(quaternion); &lt;br /&gt;
 &lt;br /&gt;
	vec4 vert = vec4(qrot(quaternion,gl_Vertex.xyz) + Joints[gl_Vertex.w] ,1.0) &lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vert; &lt;br /&gt;
 &lt;br /&gt;
	N = gl_NormalMatrix * qrot(quaternion, gl_Normal); &lt;br /&gt;
	//T = gl_NormalMatrix * qrot(quaternion, Tangent); &lt;br /&gt;
	//B = cross (T,N); &lt;br /&gt;
 &lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0; &lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die qrot Funktion rotiert einen Vektor mit hilfe eines Quaternions. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auch hier kann es sinnvoll sein, die Joints in den Modelviewspace zu transformieren und die Quaternionen mit der Normalmatrix (gegebenfals in ein Quaternion umwandeln) zu rotieren:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
	gl_Position = gl_ProjectionMatrix * vert; &lt;br /&gt;
 &lt;br /&gt;
	N = qrot(quaternion, gl_Normal); &lt;br /&gt;
	//T = qrot(quaternion, Tangent); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==CPU side Stuff==&lt;br /&gt;
&lt;br /&gt;
Wer gedacht hat das war es schon, wird nun leider entäuscht werden, es ist zwar nur ein geringes Problem um die uniform arrays mit fertigen Posen zu füllen, die man z.B. mit einem Blender exporter erzeugen könnte, jedoch macht es mehr Sinn eine Armature zu bauen über die man das Modell manipulieren kann. Zur inversen Kinematik ist es dann nur noch ein kleiner Schritt. Die Armature kann Quaternion als auch Matrix basierend aufgebaut werden. Für alle die Quaternionen noch etwas fremdes sind, hilft es sehr wenn man diese als eine andere Form von Rotationsmatrizen betrachted, auch wenn sie etwas andere Eigenschaften haben.&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich sind folgende Eigenschaften für jeden Bone unverzichtbar:&lt;br /&gt;
&lt;br /&gt;
Initial Joint Position, einem Positionsvektor mit 3 Kompoinenten.&lt;br /&gt;
Aktuelle Joint Position, ebenfalls einem Positionsvektor.&lt;br /&gt;
Die Rotation, sie kann durch ein Quaternion oder eine Rotationsmatrix dargestellt werden.&lt;br /&gt;
Eine Liste aller Children.&lt;br /&gt;
&lt;br /&gt;
Unnötig sind dagegen:&lt;br /&gt;
Ein zweites Boneende, wie viele Editoren es verwenden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird ein Bone rotiert, müssen alle Children mit rotiert werden. Das beiduetet, das sich deren Rotationen und Jointpositionen ändern. Alle Joints müssen dabei um den eigenen Joint mit der entsprechnden Rotation rotiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To continue...&lt;br /&gt;
&lt;br /&gt;
==Externe Links==&lt;br /&gt;
&lt;br /&gt;
http://lumina.sourceforge.net/?id=27 Beispiel in Lumina. Der mit Lumina mitgelieferte Blenderexporter ist in der Lage die benötigten Daten zu erzeugen.&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Modellierung_eines_Low-Poly_Menschen_Teil_2&amp;diff=25681</id>
		<title>Tutorial Modellierung eines Low-Poly Menschen Teil 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Modellierung_eines_Low-Poly_Menschen_Teil_2&amp;diff=25681"/>
				<updated>2012-06-09T16:07:37Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Nachwort */ Rechtschreibung :(&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Ave!==&lt;br /&gt;
&lt;br /&gt;
Und willkommen zum Nachfolger meines ersten Low-Poly-Tutorials.Nachdem wir in diesem gelernt haben aus möglichst wenigen Dreiecken eine menschliche Figur zu modellieren,beschäftigen wir uns nun mit der Texturierung eben dieses Polygoniers.&lt;br /&gt;
&lt;br /&gt;
Wie bekannt tragen gerade die Texturen sehr viel zum Aussehen eines 3D-Modelles bei und können leicht zum simulieren von Details genutzt werden,ohne das dadurch die Anzahl der genutzten Polygone steigt.&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial werden wir unseren fertigen Polygonhelden also mit '''einer''' selbstgemachten Textur versehen.Wenn ihr aufmerksam ward,dann habt ihr sicher bemerkt das ich im lezten Satz &amp;quot;einer&amp;quot; betont habe.Das hat auch einen Grund,denn wir belegen nicht jeden [[Mesh]] unserer Figur mit einer eigenen Textur,sondern nutzen nur eine einzige Textur für alle Meshes des Modelles.Diese eine Textur wird im Fachjargon auch &amp;quot;Skin&amp;quot; genannt und hat im Groben zwei Vorteile ggü. der Nutzung mehrere Texturen.Texturenwechsel (via glBindTexture) sind ja bekannterweise recht zeitintensiv und können bei häufigem Autreften schonmal nen Flaschenhals darstellen.Durch die Nutzung einer einzigen Textur für das komplette Modell sparen wir also ganz einfach diverse Texturenwechsel und machen der GPU das Leben leichter.Ein weiterer,vielleicht sogar besserer Grund für die Nutzung eines einzigen Skins für unser Modell ist die Tatsache das man anhand eines einfachen Texturenwechsel innerhalb seines Spiels das komplette Aussehen des 3D-Helden darüber verändern kann.Diese Technik findet auch in professionellen Spielen (u.a. UT2003) häufig Anwendung,und ein gutes Beispiel ist z.B. ein 2.WK-Shooter.Statt ein Modell für einen Wehrmachtssoldaten und eins für einen allierten Soldaten zu erstellen (und damit zwei Modelle im Speicher zu halten) wird nur ein Grundmodell erstellt,dessen Zugehörigkeit oder Spezialfähigkeit (z.B. Mediziner) dann über sein Skin sichtbar ist.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
Für dieses Tutorial benötigt ihr unbedingt einen 3D-Modeller der euch einen visuellen Editor zum Verändern der UVW-Koordinaten auf Vertexbasis und einen UVW-Unwrap-Modifikator anbietet,da ihr sonst Probleme haben werdet das im Tutorial gemachte nachzuvollziehen.&lt;br /&gt;
Ansonsten solltet ihr wie im ersten Tutorial zumindest grundlegende Kenntnisse in Sachen 3D-Modellierung und Nutzung eurer 3D-Software mitbringen.&lt;br /&gt;
&lt;br /&gt;
In Sachen Bildbearbeitungssoftware ist eigentlich alles erlaubt und ich habe zum Erstellen der Textur auch &amp;quot;nur&amp;quot; Picture Publisher 9 gentutzt,welches bei meinem Webspacepaket dabei war.Photoshop,PaintShop Pro oder Gimp (kostenlos) sollten also auch ausreichen.&lt;br /&gt;
&lt;br /&gt;
==Erstellen der Textur==&lt;br /&gt;
&lt;br /&gt;
Beginnen wollen wir also mit dem Erstellen der Textur die unsere Figur später schmücken soll.Da wir für das komplette Modell nur eine Textur verwenden,sollten wir uns erstmal Gedanken um die Einteilung eben dieser machen und dafür sorgen das alle Meshes Platz darauf haben.Unser Polygonmensch besteht aus zwei Armen,zwei Beinen,einem Becken,dem Rumpf,einem Hals und seinem Kopf.Aufgrund der Symetrie des Körpers können wir übrigens die beiden Arme und Beine auf jeweils auf ein Exemplar beschränken.Summa Sumarum sind das also 6 Körperteile,wobei man einige davon aus den anderen heraus texturieren könnte.Für das Tutorial erstelle ich nämlich einen uniformierten Soldaten,der deshalb an Beinen und Armen (bis auf Hände und Stiefel) gleich texturiert werden kann,also brauche ich keine extra Textur für das Beinkleid.Genausowenig braucht der Hals eine eigene Textur,da sich in der Textur für den Kopf garantiert genug Haut findet um sie über den Hals zu legen.&lt;br /&gt;
&lt;br /&gt;
Im Endeffekt bräuchten wir jetzt also nur noch Platz für vier Körperteile auf unserer Textur (Arm,Rumpf,Becken,Kopf).Allerdings sollte man sich auch vor dem Erstellen eben dieser Überlegen,ob man nicht doch noch irgendwelche Stellen besonders behandeln will.Ist dies der Fall,sollte man das natürlich beim Einteilen des Platzes mitberücksichtigen.So hat mein Soldat auf den Schultern noch ein paar Abzeichen,also kann ich für diese nicht einfach die Textur des Rumpfes nutzen.Aber diese Besonderheiten sind abhängig von dem was ihr machen wollt,also müsst ihr euch da auch selbst was einfallen lassen.&lt;br /&gt;
&lt;br /&gt;
Da sich eine solche Einteilung recht schlecht in Schrift und Wort erklären lässt,zeige ich euch mal wie ich das bei meinem Soldaten mit der Texturunterteilung gehandhabt habe.Folgend seht ihr die farblich eingeteilten Bereiche :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_skin1_col2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ich hoffe mal das diese Einteilung zumindest halbwegs nachvollziehbar erscheint,und rate euch sowas auch zuerst mit farbigen Blöcken durchzuspielen,bevor ihr beim Basteln der Textur plötlich merkt das kein Platz mehr für ein bestimmtes Körperteil da ist und wieder von vorne anfangen müsst.&lt;br /&gt;
Im Bezug auf die Texturengröße gibts auch keinen allgemeingültigen Rat,denn diese hängt von mehreren Faktoren ab.Zum einen wie nahe der Spieler dem Modell je kommt,wie detailliert das Modell an sich ist und wie viele Details ihr gerne über die Textur realisieren wollt.Ich habe für mein Modell ganz einfach eine 256x256 Pixel große Textur genommen,damit ich hier und da ein Detail einbringen kann.&lt;br /&gt;
&lt;br /&gt;
Da es nicht Gegenstand dieses Tutorials ist euch das Erstellen einer Textur beizubringen,überlasse ich euch mal euren Bildbearbeitungskünsten (Kleiner Tipp falls ihr v.a. Details für die Textur sucht : Die google Bildsuche hilft ungemein) und präsentiere euch direkt meine fertige Textur (etwas verkleinert) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_skin1_prev.jpg]]&lt;br /&gt;
&lt;br /&gt;
Das sollte bei euch zumindest ähnlich aussehen und wenn nicht,dann nehmt halt die Farbtextur und nutzt diese zum Texturieren des Modelles.Der Rest kann ja später noch gemacht werden.&lt;br /&gt;
&lt;br /&gt;
==UVW-Mapping==&lt;br /&gt;
&lt;br /&gt;
Da wir jetzt sowohl eine fertige Textur (oder etwa nicht?) sowie ein fertiges 3D-Modell haben,wollen wir diese natürlich auch gerne zusammenführen.Dazu machen wir uns die Möglichkeit zu Nutze,das ein halbwegs brauchbares 3D-Modellierungsprogramm in der Lage ist die UVW-Koordinaten für jedes Vertex zu verändern.Wers noch nicht weis : UVW sind die Texturkoordinaten eines Vertexes und werden in OpenGL allgemein auch als STQ referenziert,wobei uns die letzte Koordinate (W) nichts angeht.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_01.jpg|right]]Wir laden also unser im letzten Tut gebasteltes 3D-Modell und holen uns (sofern möglich) den perspektivischen Viewport auf den kompletten Schirm.Nun öffnen wir den Materialeditor (Shortcut m) und laden in die Diffuse-Map des ersten Materials unsere Textur zu,bevor wir diese dann dem kompletten Modell zuweisen.Ausserdem sollte natürlich &amp;quot;Map im Viewport zeigen&amp;quot; aktiv sein,da wir unsere Textur später sonst nicht sehen.Momentan sehen wir natürlich noch nicht viel von der Textur,da kein einziger Mesh UVW-Koordinaten besitzt.&lt;br /&gt;
&lt;br /&gt;
Anfangen wollen wir mit dem Arm und nutzen ein nettes Feature von 3DSMax um diesen einzeln bearbeiten zu können,nämliches das Isolationstool.Dazu selektieren wir den Arm und drücken '''ALT+Q''' (oder im Hauptmenü über den Eintrag Tools-&amp;gt;Selektion isolieren) und schon wird der Rest des Models ausgeblendet,während ein kleines Fenster erscheint das uns über den Isolationsmodus informiert.&lt;br /&gt;
Dem Arm,allein auf dem Schirm und noch selektiert,weisen wir jetzt aus der Modifikatorliste den '''Unwrap UVW'''-Modifikator zu (befindet sich recht weit unten),der auch automatisch UVW-Koordinaten für den selektieren Mesh erstellt,die wie zu sehen allerdings keinesfalls brauchbar sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_02.jpg|right]]Als nächstes wollen wir uns endlich ins UVW-Mappen stürzen.Dabei gehen wir beim Arm Seite-für-Seite vor,und selektieren deshalb alle Faces der Vorderseite.Dazu öffnen wir den UVW-Unwarp-Modifikator des Arms und klicken auf &amp;quot;Face selektieren&amp;quot;,bevor wir dann im Viewport alle Faces der Vorderseite des Armes selektieren (Um mehrere Objekte zu selektieren STRG gedrückt halten).Wenn ihr das gemacht habt,dann sollte eure perspektivische Ansicht in etwa so aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_03.jpg]]&lt;br /&gt;
&lt;br /&gt;
Nun öffnen wir durch einen Klick auf '''&amp;quot;Bearbeiten...&amp;quot;''' in den Eigenschaften des UVW-Modifikators den UVW-Editor,der danach ungefähr so auf eurem Bildschirm erscheinen sollte :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_04.jpg]]&lt;br /&gt;
&lt;br /&gt;
Was euch evtl. direkt auffällt (und den ein oder anderen evtl. auch schon ein paar nerven gekostet hat),ist die Tatsache das dort wo eure Textur sein sollte nur ein schwarzes Quadrat ist.Das liegt ganz einfach daran das dass 3DStudio die Textur aus einem mir unerklärlichen Grund mit einer Helligkeit von 0 anzeigt.Wollt ihr also was von eurer zugewiesenen Textur sehen,dann öffnet mit bem Button ganz unten rechts (Show options) eine kleine Zusatzleiste am unteren Fensterrand und setzt die Helligkeit dort auf 1.Ausserdem solltet ihr auch den Haken vor &amp;quot;Bitmap wiederholen&amp;quot; (Tile Bitmap) entfernen.&lt;br /&gt;
Nun sind wir also endlich bereit unserem Arm die passenden UVs zuzuordnen.Ein kleiner Tipp für die Produktivität : Wenn ihr eure Fenster so anordnet wie ich (links UVW-Editor und das zu editierende Objekt rechts daneben),dann lässt sich nicht nur bequem arbeiten,sondern die Änderungen im UVW-Editor auch in Echtzeit auf dem Modell verfolgen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_05.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_06.jpg|right]]Immernoch die Frontfaces unseres Armes selektiert klicken wir in den Eigenschaften des Modifikators jetzt also auf '''Planar Map''' um die Texturkoordinaten der gewählten Vertexe auf die Textur zu projizieren.Bei den Frontfaces wird die Notwendigkeit dieser Aktion noch nicht so recht sichtbar,aber spätestens bei den Seiten des Armes wird euch dies klar werden.Ausserdem aktivieren wir &amp;quot;Filter selected Faces&amp;quot;,damit nur die gewählten Faces im UVW-Editor sichtbar sind.Habt ihr dieses Prozedere korrekt nachvollzogen,dann sollte euer UVW-Editor in etwa so aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_07.jpg]]&lt;br /&gt;
&lt;br /&gt;
Nun sehen wir ein korrektes Abbild unserer Armgeometrie auf der Textur,allerdings passen die Texturkoordinaten noch absolut nicht.Wir schnappen uns also die Vertices des Armes und verschieben diese so,das sie den Bereich einnehmen den wir auf unserer Textur für den Arm vorgesehen haben.Ich mach das übrigens lieber über die Eingabefelder,denn das blosse Verschieben mit der Maus ist nicht gerade genau.Danach sollte die Vorderseite des Armes so auf der Textur zugewiesen sein und wie rechts zu erkennen aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_08.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch2_09.jpg]]&lt;br /&gt;
&lt;br /&gt;
Diese Prozedur müsst ihr jetzt natürlich für alle vier Seiten des Armes,sowie die Unterseite der &amp;quot;Hand&amp;quot; anwenden.Wer dann auch noch mitgedacht hat,wird sich nicht blindlinks auf den zweiten Arm stürzen,sondern diesen durch eine Kopie unseres bereits UVW-Gemappten Armes ersetzen.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts jetzt mit dem Torso unseres Polygonators.Nachdem wir diesen angewählt haben,gehen wir wieder in den Isolationsmodus und selektieren wie gewohnt alle Frontfaces.Allerdings werden wir jetzt direkt sehen dass das Mapping (welches momentan auf &amp;quot;Averaged Normals&amp;quot; steht) nicht &amp;quot;korrekt&amp;quot; ist,denn das gelbe Mappingquadrat steht schief (siehe Links).Um das zu korrigieren (damit die Frontfaces des Torsos auch auf der Textur richtig liegen) wählen wir diesmal bei den Sub object Parametern &amp;quot;Z&amp;quot; und sofort sollte das Mappingquadrat in der richtigen Position liegen (siehe Rechts).Hier könnt ihr also je nach Bedarf mit den Optionen rumprobieren und sobald ihr die richtige Einstellung gefunden habt wieder auf '''Planar Map''' klicken :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_10.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch2_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch diesmal skaliert und verschiebt ihr die Vertices der Vorderseite des Torus solange im UVW-Editor,bis diese alle im dafür vorgesehen Bereich der Textur liegen.Evtl. müsst ihr an einigen Stellen noch ein wenig rumschieben bis alles so aussieht wie es soll :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_12.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch2_13.jpg]]&lt;br /&gt;
&lt;br /&gt;
Zur Texturierung der Rückseite bzw. der beiden anderen Seiten könnt ihr übrigens ganz einfach den Teil der Textur nutzen in dem keine Medallien abgelegt sind.Folgend seht ihr den gemappten Rücken (oben) und eine Seite (unten) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_14.jpg]]&lt;br /&gt;
&lt;br /&gt;
amit wären wir eigentlich auch schon am Ende des Tutorials angelangt.Euch jetzt noch bebildert zu erzählen wie die restlichen Körperteile texturiert werden würde,wäre in meinen Augen Schwachsinn.Die Grundlagen und evtl. auftretende Schwierigkeiten hab ich ja bereits angesprochen,und den Rest des Modells solltet ihr ohne Problem fertigtexturieren können.&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Wenn ihr meinen Beschreibungen folgen konntet,dann sollte euer Polygonsoldat nun in etwa so aussehen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_15.jpg]]&lt;br /&gt;
&lt;br /&gt;
Das ist doch die Mühe wert, oder? Zumal ihr nun behaupten könnt neben dem Modell auch noch die Textur für euer Modell komplett selbst erstellt zu haben. Außerdem bietet sich euch jetzt durch die Nutzung eines einzigen Skins für unser Modell noch jede Menge Erweiterungsmöglichkeiten, von der andersfarbigen Uniform bis hin zu einer total anderen Bekleidung.&lt;br /&gt;
&lt;br /&gt;
Wie immer hoffe ich, dass euch dieses Tut so viel Spaß gemacht hat wie mir das Verfassen eben dieses. Ich bin auf euer Feedback und eure Modellierergebnisse mehr als gespannt!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Modellierung eines Low-Poly Menschen Teil 1]] | - }} &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Modellierung eines Low-Poly Menschen Teil 2]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Model_Loader&amp;diff=25676</id>
		<title>Model Loader</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Model_Loader&amp;diff=25676"/>
				<updated>2012-05-13T15:39:55Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Welche Modellformate gibt es? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Was ist das?==&lt;br /&gt;
Ein Modell-Loader ist eine Unit, oder DLL die ein 3D-Model in einem bestimmten Typ* vorliegt für ein Programm oder für was auch immer lädt, damit es angezeigt werden kann.&lt;br /&gt;
&lt;br /&gt;
==Für was brauch ich das?==&lt;br /&gt;
Wenn man 3D Modelle von speziellen Objekten (z.B. Einheiten, Landschaftsgegenstände und Gebäude in Strategiespiele, oder Gegner für Shooter) benötigt, ist es wesentlich komfortabler ein Modell in einem speziellen 3D Modellierungsprogramm zu modellieren, als es „von Hand“ in OpenGL zu bauen. Man muss allerdings anschließend die Daten (Informationen zur Geometrie, Texturierung eventl. Animierung) selbst aus den abgespeicherten Modellformaten extrahieren.&lt;br /&gt;
&lt;br /&gt;
Und genau da kommt der „Model Loader“ ins Spiel. Dieses Stück Code ermöglicht es dem Nutzer die Daten komfortabel aus den Dateien zu Laden. Das erleichtert die Arbeit im Vergleich zu selber gebauten Objekten natürlich enorm. Und die Modelle sehen, wenn man genügend Talent hat, auch meist wesentlich besser aus.&lt;br /&gt;
&lt;br /&gt;
==Speichern alle Formate Animationen?==&lt;br /&gt;
Nein! Es sind sogar nur recht wenige die Animationen bieten. Außerdem gibt es Modeller die Animationen nicht in einer Datei sondern in vielen Einzeldateien speichern. Allerdings heißt das nicht, dass nur die Modelle aus teuren Modellern Animationen (vernünftig) speichern können. Es gibt auch freie und günstige Software (Milkshape 3D), die so etwas kann.&lt;br /&gt;
&lt;br /&gt;
==Welche Modellformate gibt es?==&lt;br /&gt;
Hier eine kleine Auflistung der gebräuchlichsten Formate:&lt;br /&gt;
* .blend ([http://blender3d.org Blender])&lt;br /&gt;
* .collada ([http://www.khronos.org/collada/ Collada])&lt;br /&gt;
* .3ds (3D Studio)&lt;br /&gt;
* .obj (Wavefront OBJ)&lt;br /&gt;
* .lwo (Lightwave)&lt;br /&gt;
* .ms3d (Milkshape 3D)&lt;br /&gt;
* .bsp (ID Software BSP)&lt;br /&gt;
* .md3 (ID Software MD3)&lt;br /&gt;
* .x (Microsoft DirectX)&lt;br /&gt;
* .off (Object File Format)&lt;br /&gt;
&lt;br /&gt;
==Wozu gibt es Exporter Plugins und Scripte?==&lt;br /&gt;
Für 3D Entwicker ist es wichtig, die erstellten Meshdaten auch in ein vorhandenes oder eigenes Format zu speichern.&lt;br /&gt;
Hierzu gibt es von den meisten 3D Editioren Plugins oder Scripte die dieses erledigen.&lt;br /&gt;
&lt;br /&gt;
Einige Programme wie 3DS Max und Blender bieten beides, wobei in Fall von 3DS Max lieber Plugins verwendet werden sollten (Geschwindigkeitsvorteil). Blender bietet für Scripte einen Python Interpreter, der lediglich ein bisschen modifiziert wurde.&lt;br /&gt;
&lt;br /&gt;
Mit der Möglichkeit, eigene Format zu speichern, kann man sich auch aus dem Lizensproblem für bestimmte Formate rauswinden und man hat die Möglichkeit das Format an benötigte Bedingungen anzupassen.&lt;br /&gt;
&lt;br /&gt;
== Format und Model Loader Liste ==&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;10%&amp;quot;| Format&lt;br /&gt;
!width=&amp;quot;40%&amp;quot;| Format Features&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;| Loader&lt;br /&gt;
|-&lt;br /&gt;
| Cal3D&lt;br /&gt;
|&lt;br /&gt;
* kombinieren von Animationen (30%&amp;amp;nbsp;gehen, 50%&amp;amp;nbsp;rennen, 20%&amp;amp;nbsp;stolzieren und Winken)&lt;br /&gt;
* stufenloses [[Level of Detail]]&lt;br /&gt;
|&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
! Name&lt;br /&gt;
! nutzbar mit&lt;br /&gt;
! Umgesetzte Features&lt;br /&gt;
|-&lt;br /&gt;
| [http://gna.org/projects/cal3d/ Cal3D]&lt;br /&gt;
| C++&lt;br /&gt;
| alle Cal3D&amp;amp;nbsp;(0.10) Features&lt;br /&gt;
|-&lt;br /&gt;
| DCal3D&lt;br /&gt;
| Delphi / Object Pascal&lt;br /&gt;
| nur Cal3D&amp;amp;nbsp;0.6 Features&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
| 3DS&lt;br /&gt;
|&lt;br /&gt;
* Meshbasierendes 3D-Format&lt;br /&gt;
* Vertexbasierende Animationen via Keyframes&lt;br /&gt;
* Normalen werden indirekt über Smoothinggroups gesichert&lt;br /&gt;
'''Format stammt noch aus DOS-zeiten, daher diverse Einschränkungen :'''&lt;br /&gt;
* Maximal 65k Vertices pro [[Mesh]]&lt;br /&gt;
* Texturnamen sind auf [http://de.wikipedia.org/wiki/8.3 8.3 Dateinamen] beschränkt&lt;br /&gt;
* Bones werden nicht exportiert&lt;br /&gt;
* Normalen werden nicht exportiert (nur Smoothinggroups)&lt;br /&gt;
'''Kein freies Format'''&lt;br /&gt;
|&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
! Name&lt;br /&gt;
! nutzbar mit&lt;br /&gt;
! Umgesetzte Features&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.delphigl.com/forum/viewtopic.php?t=2421 gl3ds]&lt;br /&gt;
| Delphi / Object Pascal&lt;br /&gt;
| Unbekannt&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.lib3ds.org/ lib3ds]&lt;br /&gt;
| C/C++&lt;br /&gt;
| Unbekannt&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
| OFF&lt;br /&gt;
|&lt;br /&gt;
* extrem einfaches 3D-Format&lt;br /&gt;
* ASCII und Binär-Variante&lt;br /&gt;
* nur Vertices, Normalen, Texturkoordinaten und Farben&lt;br /&gt;
* nicht auf Dreiecke beschränkt, beliebige Polygone möglich.&lt;br /&gt;
* '''nicht jeder Exporter (z.B. Blender) kann das vollständige Format!'''&lt;br /&gt;
| Da das Format so einfach ist ist ein Loader schnell implementiert:&lt;br /&gt;
[http://web.mit.edu/lugao/MacData/afs/athena/software/geomview_v1.9.3/www/OFF.html Formatbeschreibung].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25675</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25675"/>
				<updated>2012-05-13T15:28:18Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Die Zukunft */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Einleitung=&lt;br /&gt;
Hallo und willkommen bei meiner &amp;quot;Einführung&amp;quot; in GLSL (kurz für &amp;quot;Open'''GL''' '''S'''hading '''L'''anguage&amp;quot;), der offiziellen Hochlevel-Shadersprache von OpenGL. In diesem umfangreichen Dokument werde ich versuchen, sowohl auf die Nutzung (sprich das Laden und Anhängen von Shadern im Quellcode), als auch auf die Programmierung von Shadern selbst einzugehen, inklusive aller Sprachelemente der OpenGL Shadersprache. Es wird also auch recht viele Informationen zu der C-ähnlichen Programmstruktur und den von GLSL angebotenen Variablen und Attributen gehen. Am Ende dieser Einführung sollten alle die, die sich für das Thema interessieren, in der Lage sein, zumindest einfach Shader zu schreiben und auch in ihren Programmen zu nutzen. Außerdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von Khronoes veröffentlichten Shaderspezifikationen, und damit als alltägliches Nachschlagewerk, dienen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Wie auch schon mein ARB_VP-Tutorial richtet sich auch diese Einführung aufgrund ihrer Thematik eher an die fortgeschritteneren GL-Programmierer und neben sehr guten GL-Kenntnissen sollten sich alle, die sich daran versuchen wollen, mit den technischen Hintergründen der GL, wie z.B. dem Aufbau der Renderpipeline auskennen. Weiterhin sind C-Kenntnisse absolut erforderlich, da die Shader ja in einer an ANSI-C angelehnten Syntax geschrieben werden. Auch Begriffsdefinitionen zu Vertex oder Fragment werden zum Verständis dieser Einführung benötigt. Wer also noch am Anfang seiner GL-Karriere steht, dem wird dieses Dokument nicht viel nützen. Ganz nebenbei solltet ihr auch noch eine gehörige Portion Zeit (am besten nen kompletten Nachmittag) mitbringen, denn die folgende Kost ist nicht nur umfangreich, sondern auch manchmal recht schwer verdaulich.&lt;br /&gt;
&lt;br /&gt;
=Was ist GLSL?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei GLSL um eine Shadersprache, also um eine Hochsprache, in der man die programmierbaren Teile aktueller Grafikbeschleuniger nach eigenem Belieben programmieren kann. Sie stellt quasi den Nachfolger zu den in Assembler geschriebenen Vertex- und Fragmentprogrammen ([[GL_ARB_vertex_program]]/[[GL_ARB_fragment_program]]) dar und basiert auf ANSI C, erweitert um Vektor- und Matrixtypen sowie einige C++-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
Die in GLSL geschriebenen Programme nennen sich, angepasst an die Terminologie von RenderMan und DirectX, [[Shader]] (im Gegensatz zu &amp;quot;Programme&amp;quot; bei ARB_VP/FP) und werden entweder auf Eckpunkte (VertexShader), Fragmente (FragmentShader) angewendet, oder (neuerdings, ab Shadermodell 4.0) auch genutzt um Geometrie zu erstellen (Geometryshader). Andere Teile der Renderpipeline (z.B. die Rasterisierung) können momentan noch nicht durch Shader beeinflusst werden, was allerdings in Zukunft noch kommen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
GLSL wurde 2005 mit OpenGL 1.5 eingeführt. Während es in Sachen Treiber- und Hardwareunterstützung anfänglich noch dürftig aussah, wird man inzwischen keine Grafikkarte mehr kaufen können die nicht zumindest Vertex- und Fragmentshader beherscht. Geometrieshader hingegen sind relativ neu und wurden erst mit Shadermodell 4.0 eingeführt, hier ist es also unter Umständen noch möglich dass selbst aktuelle Treiber/Karten keine Geometrieshader beherrschen.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt man auch einen passenden OpenGL-Header der die für GLSL nötigen Funktionen exportiert. Ich verweise dazu auf unseren eigenen OpenGL-Header [[DGLOpenGL.pas]], der peermanent auf dem aktuellsten Stand gehalten wird und auch Support für Geometrieshader mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
&lt;br /&gt;
Die GL-Shadersprache &amp;quot;besteht&amp;quot; in ihrer aktuellen Version aus folgenden Extensions, fürs Verständnis wäre es nicht schlecht, wenn ihr euch zumindest die Einleitungen dazu durchlest :&lt;br /&gt;
* [[GL_ARB_shader_objects]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shader_objects.txt Originalspezifikation])&lt;br /&gt;
: Definiert die API-Aufrufe, die zum Erstellen, Kompilieren, Linken, Anhängen und Aktivieren von Shader- und Programmobjekten nötig sind. &lt;br /&gt;
* [[GL_ARB_vertex_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Vertexebene hinzu. &lt;br /&gt;
* [[GL_ARB_fragment_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Fragmentebene hinzu. &lt;br /&gt;
* [[GL_ARB_shading_language_100]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shading_language_100.txt Originalspezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis''' : Seit OpenGL 2.0 ist GLSL Teil des Kerns. Wenn die Karte also OpenGL 2.0 unterstützt, dann unterstützt sie auch (zumindest in Software) Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sprachversionen==&lt;br /&gt;
&lt;br /&gt;
Neben der OpenGL-Version und dem vorhandenen Shadermodell (das eher an DirectX ausgerichtet ist), bietet auch GLSL verschiedene Versionen, die entsprechend erweiterte Funktionalität bieten.&lt;br /&gt;
&lt;br /&gt;
Auslesen kann man die verfürgbare GLSL-Version wie folgt:&lt;br /&gt;
&lt;br /&gt;
 glGetString(GL_SHADING_LANGUAGE_VERSION)&lt;br /&gt;
&lt;br /&gt;
Erst ab Version 1.4. kann man davon ausgehen dass GLSL alle Features des Shadermodells 4.0 liefert, ab 1.3 grob gesagt Shadermodell 3.0 (bei GLSL lässt sich das leider nicht so leicht unterteilen).&lt;br /&gt;
&lt;br /&gt;
Außerdem kann man seinem Shader eine Versionsnummer verpassen. Sollte der Shadercompiler (also Treiber bzw. Hardware) diese Version nicht unterstützen, gibt dieser eine Fehlermeldung heraus:&lt;br /&gt;
&lt;br /&gt;
 #version 1.50 &lt;br /&gt;
&lt;br /&gt;
''(Hinweis: Muss am Anfang des Shaders stehen)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&lt;br /&gt;
&lt;br /&gt;
Im Zuge der Vereinheitlichung der GL wird immer häufiger in Objekte gekapselt, deren API dann auch aneinander angelehnt ist. Ziel ist, dabei die Programmierung der GL uniform zu machen, so dass z.B. zwischen dem Erstellen und Verwalten eines Vertex-Buffer-Objektes oder eines Shader-Objektes kaum ein Unterschied besteht (demnächst kommen dann auch Pixel-Buffer-Objekte dazu). Mit glSlang wurden dann im Zuge dieser Aktion zwei neue Objekte eingeführt, deren Definition ihr euch unbedingt einprägen solltet:&lt;br /&gt;
&lt;br /&gt;
* '''Programmobjekt'''&lt;br /&gt;
:Ein Objekt, an das die Shader später angebunden werden. Bietet Funktionalität zum Linken der Shader und prüft dabei die Kompatibilität zwischen Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
* '''Shaderobjekt'''&lt;br /&gt;
:Dieses Objekt verwaltet den Quellcodestring eines Shaders und ist entweder vom Typ '''GL_VERTEX_SHADER''', '''GL_FRAGMENT_SHADER_ARB''' oder '''GL_GEOMETRY_SHADER'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
&lt;br /&gt;
Die Shadersprache ist keinesfalls final und es wurden bereits diverse Ausdrücke für zukünftige Verwendung reserviert, denn ein Ziel bei ihrer Entwicklung war es, sie so zukunftsorientiert zu gestalten, dass auch Grafikkarten der nächsten und übernächsten Generation voll ausgenutzt werden können. Damit einher geht die Tatsache, dass sich die Spezifikationen in Zukunft ändern/erweitern werden, weshalb man da immer einen Blick hineinwerfen sollte. Die Anlaufstelle dafür ist die [http://www.opengl.org/documentation/specs/ Spezifikationenliste auf OpenGL.org].&lt;br /&gt;
&lt;br /&gt;
=GLSL im Programm=&lt;br /&gt;
Bevor wir uns mit der Syntax von glSlang beschäftigen, zeige ich euch erstmal, wie ihr Shader in euer Programm einbindet und nutzt. Warum das zuerst? Ganz einfach deshalb, weil ihr dann das, was ihr im glSlang-Syntaxteil lernt, direkt in eurer Testanwendung verwenden könnt. Hoffe diese Entscheidung klingt logisch und findet Anklang.&lt;br /&gt;
&lt;br /&gt;
Zuerst benötigen wir natürlich unsere Objekte. Zum einen ein ''Programmobjekt'', an das unsere Shader gebunden werden, und zwei ''Shaderobjekte'', die den Quellcode unseres Vertex bzw. Fragment Shaders aufnehmen. Dazu wurde eigens der neue &amp;quot;Datentyp&amp;quot; {{INLINE_CODE|glHandle}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandle;&lt;br /&gt;
 VertexShaderObject   : GLhandle;&lt;br /&gt;
 FragmentShaderObject : GLhandle;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dieser Deklaration können wir dann damit beginnen unsere Objekte zu erstellen. Den Anfang macht das Programmobjekt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        := glCreateProgram;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgram]] erstellt uns oben ein leeres Programmobjekt und gibt ein gültiges Handle darauf zurück.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Erstellung unseres Vertex bzw. Fragment Shaders :&lt;br /&gt;
&lt;br /&gt;
 VertexShaderObject   := glCreateShader(GL_VERTEX_SHADER);&lt;br /&gt;
 FragmentShaderObject := glCreateShader(GL_FRAGMENT_SHADER);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShader]] dient zur Generierung eines leeren Shaderobjektes. Momentan unterstützt diese Funktion VertexShader und FragmentShader.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun also zwei gültige Shaderobjekte haben, wollen wir diese auch mit entsprechendem Quellcode versorgen :&lt;br /&gt;
&lt;br /&gt;
 glShaderSource(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSource(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSource]] setzen wir den Quellcode eines Shaderobjektes ''komplett'' neu. Zum Laden des Quellcodes bietet sich unter Delphi übrigens eine TStringList geradezu an. Es sollte beachtet werden, dass der Quellcode zu diesem Zeitpunkt ''nicht geparst'' wird, also keine Fehleruntersuchung stattfindet.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode wurde jetzt also an unsere Shaderobjekte gebunden und sollte dann natürlich auch noch kompiliert werden :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 glCompileShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShader]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der Shadercompiler (je nach Treiber) recht detaillierte Infos aus. Wie man an diese Infos kommt könnt ihr gleich nachlesen.&lt;br /&gt;
&lt;br /&gt;
Wenn unsere Shader dann kompiliert werden konnten, ist es Zeit, diese an unser anfangs erstelltes Programmobjekt anzuhängen :&lt;br /&gt;
&lt;br /&gt;
 glAttachShader(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachShader(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehängt wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteShader(VertexShaderObject);&lt;br /&gt;
 glDeleteShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Schluß müssen wir dann noch unsere ans Programmobjekt gebundenen Shader linken :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShader]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgram]] die angehangenen Shader zu einem ausführbaren Shader gelinkt. Folgende Bedingungen führen zu einem '''Linkerfehler''':&lt;br /&gt;
&lt;br /&gt;
* Die Zahl der von der Implementation unterstützten Attributvariablen wurde überschritten&lt;br /&gt;
* Der Speicherplatz für Uniformvariablen wurde überschritten&lt;br /&gt;
* Die Zahl der von der Implementation angebotenen Sampler wurde überschritten&lt;br /&gt;
* Die main-Funktion fehlt&lt;br /&gt;
* Die Liste der Varying-Variablen des Vertexshaders stimmt nicht mit der des Fragmentshaders überein&lt;br /&gt;
* Funktions- oder Variablenname nicht gefunden&lt;br /&gt;
* Eine gemeinsame Globale ist mit unterschiedlichen Werten oder Typen initialisiert worden&lt;br /&gt;
* Zwei Sampler unterschiedlichen Typs zeigen auf die selbe Textureneinheit&lt;br /&gt;
* Ein oder mehrere angehangene(r) Shader wurden nicht erfolgreich kompiliert&lt;br /&gt;
&lt;br /&gt;
Die Nutzung von glSlang im eigenen Programm ist wie oben erkennbar also nicht wirklich schwer und innerhalb kurzer Zeit realisiert. Natürlich ist es auch möglich z.B. nur einen VertexShader oder nur einen FragmentShader an ein Programmobjekt zu binden.&lt;br /&gt;
&lt;br /&gt;
Noch eine kleine Notiz zum Löschen der Shader mittel [[glDeleteShader]] : Da Shader(objekte) einen Referenzzähler besitzen und erst gelöscht werden wenn diese nirgendwo mehr benötigt werden, ist es nicht falsch diese vor dem Linkvorgang zu löschen. Allerdings spielt es letztendlich keine Rolle ob die Löschanweisung vorher der nachher ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fehlererkennung==&lt;br /&gt;
Natürlich wird es ohne Fehlerausgabe recht schwer, etwaige Probleme in einem Vertex- oder Fragmentshader zu finden. Doch auch in diesem Bereich wurde glSlang recht gut durchdacht und es wurden zwei Funktionen eingeführt, welche im Zusammenspiel die Fehlersuche recht einfach machen, nämlich [[glGetShaderInfoLog]] und [[glGetShader]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH}}. Erstere Funktion liefert uns einen Logstring, während uns letztere Funktion dessen Länge angibt. Der Logstring wird verändert, sobald ein Shader kompiliert oder ein Programm gelinkt wird.&lt;br /&gt;
&lt;br /&gt;
Um die Ausgabe dieses Logs so einfach wie möglich zu machen, bietet es sich an beide in einer einfach Funktion unterzubringen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function glSlang_GetInfoLog(pShader: GLHandleARB): String;&lt;br /&gt;
var&lt;br /&gt;
  blen, slen: GLInt;&lt;br /&gt;
  InfoLog: PGLCharARB;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  glGetShaderiv(glObject, GL_INFO_LOG_LENGTH , @blen);&lt;br /&gt;
  if blen &amp;gt; 1 then&lt;br /&gt;
  begin&lt;br /&gt;
    GetMem(InfoLog, blen * SizeOf(GLCharARB));&lt;br /&gt;
    glGetShaderInfoLog(pShader, blen, slen, InfoLog);&lt;br /&gt;
    Result := PChar(InfoLog);&lt;br /&gt;
    Dispose(InfoLog);&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist recht leicht erklärt : Zuerst lassen wir uns über {{INLINE_CODE|glGetShaderiv}} mitteilen wie lang der aktuelle Infolog ist. Sollte dort tatsächlich etwas drinstehen (blen &amp;gt; 1), dann lassen wir uns dessen Inhalt via {{INLINE_CODE|glGetShaderInfoLog}} in {{INLINE_CODE|InfoLog}} ausgeben und liefern diesen als Ergebnis zurück.&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt wird nur nach dem Kompilieren eines Shaders bzw. dem Linken eines Programmobjektes ein Infolog erstellt. Es bietet sich dadurch an, direkt danach einen solchen Aufruf zu machen :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 ShowMessage(glSlang_GetInfoLog(VertexShaderObject));&lt;br /&gt;
&lt;br /&gt;
Wenn unser Vertex Shader komplett fehlerfrei kompiliert werden konnte, dann sehen wir als Ergebnis nur einen leeren Dialog. Ist dies nicht der Fall, so werden wir vom Treiber mit recht detaillierten Fehlerinformationen &amp;quot;belohnt&amp;quot;, z.B. so :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL_error_vshader.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch das Infolog nach dem Linken des Programmobjektes dürfte, selbst wenn keine Fehler vorkommen, recht interessant sein, das sieht dann nämlich so aus :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL info programobject.jpg]]&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen, wird uns nach dem erfolgreichen Linken auch gesagt, ob und welcher Shader in Hardware bzw. Software läuft. Für Debuggingzwecke sicherlich eine mehr als brauchbare Information.&lt;br /&gt;
&lt;br /&gt;
==Shader benutzen==&lt;br /&gt;
Um den Shader auch für die nächsten Polygone zu benutzen oder Uniformparameter übergeben zu können, ruft man die Funktion&lt;br /&gt;
 glUseProgramt(ProgramObject);&lt;br /&gt;
um alle Shader zu deaktivieren, ruft man dieselbe Funktion mit dem Parameter 0.&lt;br /&gt;
&lt;br /&gt;
==Parameterübergabe==&lt;br /&gt;
Uniformparameter (mehr dazu später) stellen die Schnittstelle zwischen eurem Programm und dem Shader dar, werden also genutzt um Daten aus dem Programm heraus an einen Shader zu übergeben. Zur Übergabe dieser Parameter bietet OpenGL diverse Funktionen, die alle Abkömmlinge von [[glUniform]] sind. Während mit {{INLINE_CODE|glUniform4f}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fv}} ganze Matrizen schnell und einfach übergeben. Außerdem gibt es nun die Möglichkeit Uniformparameter direkt über ihren Namen, statt wie unter ARB_FP/VP über einen festen Index zu adressieren. Die Funktion [[glGetUniformLocationARB]] gibt anhand des übergebenen Parameternamens dessen Position zurück. Man kann also ganz einfach über den Namen drauf zugreifen :&lt;br /&gt;
&lt;br /&gt;
 glUniform3f(glGetUniformLocation(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1i(glGetUniformLocation(ProgramObject, PGLCharARB('texSamplerTMU3')), 3);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier, das man je nach Parametertyp auch die passende Anzahl von Argumenten übergibt. Also für einen 4-Komponenten Floatvektor {{INLINE_CODE|glUniform4fARB}} und für einen einfachen Integerwert (z.B. Textureinheit für einen Sampler) glUnifrom1iARB. Auch nicht vergessen dürft ihr, das die Namen der Parameter genauso wie im Shader geschrieben werden müssen, also Groß- und Kleinschreibung beachtet werden muß.&lt;br /&gt;
&lt;br /&gt;
=Die Shadersprache=&lt;br /&gt;
&lt;br /&gt;
Nachdem wir uns mit der Einbindung der glSlang-Shader in unser Programm beschäftigt haben, wollen wir uns in den folgenden Kapiteln um die Sprachelemente von glSlang kümmern. Wie schon gesagt basiert glSlang auf ANSI-C, wurde allerdings um speziell auf den Zielbereich angepasste Vektor- und Matrixtypen und einige C++-Features wie das freie deklarieren von Variablen an jeder Stelle und das Funktionsüberladen auf Basis des Argumenttyps erweitert. Wer sich ein wenig mit C/C++ auskennt sollte also in der nun folgenden Materie keine Probleme bekommen.&lt;br /&gt;
&lt;br /&gt;
'''Obligatorische Hinweise für verwöhnte Delphi-Nutzer : '''&lt;br /&gt;
*Wie von C/C++ her gewohnt, spielt auch in glSlang die Groß- und Kleinschreibung eine wichtige Rolle, also bitte achtet darauf. gl_Position ist eine komplett andere Variable als z.B. gl_position.&lt;br /&gt;
*Es findet keine automatische Typenkonvertierung statt. Das bedeutet also das float MyFloat = 1 ungültig ist und es in dem Falle float MyFloat = 1.0 heissen muss. Typecasts müssen also immer manuell stattfinden, z.B. MyFloat = float(MyInt).&lt;br /&gt;
&lt;br /&gt;
'''Kleine Programmstrukturkunde für C-Unkundige :'''&amp;lt;br&amp;gt;&lt;br /&gt;
Da sicherlich einige Delpher nie richtig was mit C gemacht haben, zeige ich mal anhand eines kleinen Beispieles (das auf keinen Fall nen brauchbaren Shader darstellt) den grundlegenden Aufbau eines glSlang-Shaders, der natürlich dem Aufbau eines C-Programmes stark ähnelt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 VariableA;&lt;br /&gt;
float VariableB;&lt;br /&gt;
vec3  VariableC;&lt;br /&gt;
const float KonstanteA = 256.0;&lt;br /&gt;
&lt;br /&gt;
float MyFunction(vec4 ArgumentA)&lt;br /&gt;
{&lt;br /&gt;
    float FunktionsVariableA = float(5.0);&lt;br /&gt;
&lt;br /&gt;
    return float(ArgumentA * (FunktionsVariableA + KonstanteA));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Ich bin ein Kommentar&lt;br /&gt;
/* Und ich auch */&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
    gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht doch recht bekannt aus, unser Programmaufbau. Delphi und C haben ja so einige Grundlagen gleich, darunter auch der ungefähre Programmaufbau. Ausserhalb jeglicher Funktionen legen wir am Programmanfang unsere Variablen, Konstanten und Attribute fest, die dann ''global'' nutzbar sind, also in jeder Funktion.&lt;br /&gt;
&lt;br /&gt;
Darunter deklarieren wir dann eine kleine Funktion. Wie auch bei den Variablendeklarationen wird hier der Rückgabetyp nicht wie bei Pascal nach dem Funktionsnamen untergebracht, sondern davor. Innerhalb der Funktion können dann wieder Variablen deklariert werden, die dann allerdings ''lokal'', also nur in dieser Funktion nutzbar sind. Vorteil dieser Deklaration ist die Tatsache, dass je nach Grafikkarte nur bestimmt viele globale Variablen deklariert werden können. Wenn möglich sollte man also mit lokalen Vorlieb nehmen. Unsere Funktion gibt dann natürlich noch via return einen Wert zurück, ''was gemacht werden muss'', sofern man diese nicht als void deklariert hat (entspräche dann einer Prozedur in Pascal). Wird dies nicht getan, so spuckt der Compiler einen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Auch wichtig sind natürlich Kommentare. Erste Variante (Doppelslash) ist auch in der Pascalwelt verfügbar und kommentiert eine einzelne Zeile aus. Die Variante darunter kann man für Kommentarblöcke nutzen (/* .. */) und entspricht den Kommentaren in geschweiften Klammern in Delphi.&lt;br /&gt;
&lt;br /&gt;
Danach kommt dann die '''wichtigste Funktion''' des Shaders, nämlich '''main''', die in keinem Shader fehlen darf. Sie stellt quasi den Programmkörper dar und ist oft auch die einzige Funktion in einem Shader. Sie erhält weder ein Argument, noch gibt sie einen Wert zurück.&lt;br /&gt;
&lt;br /&gt;
Soviel also zum grundlegenden Aufbau eines Shader. Hoffe das jetzt alle die in C nicht so bewandert sind damit klar kommen, und dann bald ihre ersten glSlang-Shader schreiben können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Datentypen==&lt;br /&gt;
&lt;br /&gt;
Obwohl einige Datentypen aus C übernommen wurden, sieht man der Typenliste an, das diese speziell auf den 3D-Bereich zugeschnitten wurde. Variablen müssen vor ihrer Nutzung eindeutig deklariert sein, Typecasting erfolgt über Konstruktoren (dazu später mehr). Folgende Datentypen stehen sowohl im Vertex- als auch Fragmentshader zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|void 	&lt;br /&gt;
|Für Funktionen die keinen Wert zurückgeben&lt;br /&gt;
|-&lt;br /&gt;
|bool 	&lt;br /&gt;
|Konditionaler Typ, entweder true (wahr) oder false (falsch)&lt;br /&gt;
|-&lt;br /&gt;
|int 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenbehafteter Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|uint 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenloser Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|float 	&lt;br /&gt;
|Fließkommaskalar mit Singlegenauigkeit (32 Bit)&lt;br /&gt;
|-&lt;br /&gt;
|vec2 	&lt;br /&gt;
|2-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec3 	&lt;br /&gt;
|3-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec4 	&lt;br /&gt;
|4-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec2 	&lt;br /&gt;
|2-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec3 	&lt;br /&gt;
|3-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec4 	&lt;br /&gt;
|4-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec2 	&lt;br /&gt;
|2-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec2 	&lt;br /&gt;
|2-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec3 	&lt;br /&gt;
|3-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec4 	&lt;br /&gt;
|4-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|mat2 	&lt;br /&gt;
|2x2 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat3 	&lt;br /&gt;
|3x3 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat4 	&lt;br /&gt;
|4x4 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|matMxN 	&lt;br /&gt;
|Matrix mit M Spalten und N Zeilen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse zum Zugriff auf Texturen dar, und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|sampler1D 	&lt;br /&gt;
|Zugriff auf 1D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler2D 	&lt;br /&gt;
|Zugriff auf 2D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler3D 	&lt;br /&gt;
|Zugriff auf 3D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|samplerCube 	&lt;br /&gt;
|Zugriff auf Cubemap&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRect 	&lt;br /&gt;
|Zugriff auf Texturen die nicht 2^n * 2^n entsprechen (&amp;quot;non power-of-two&amp;quot;, NPOT)&lt;br /&gt;
|-&lt;br /&gt;
|sampler1DShadow 	&lt;br /&gt;
|Zugriff auf 1D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DShadow 	&lt;br /&gt;
|Zugriff auf 2D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|samplerCubeShadow&lt;br /&gt;
|Zugriff auf Tiefentextur in einer Cubemap (z.b. für omni-diretionale Lichtquellen)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRectShadow&lt;br /&gt;
|Zugriff auf 2D-NPOT-Tiefentextur &lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|sampler1DArray&lt;br /&gt;
|Zugriff auf ein array aus 1D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArray&lt;br /&gt;
|Zugriff auf ein array aus 2D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler1DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 1D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 2D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|samplerBuffer&lt;br /&gt;
|Zugriff auf eine Puffertextur (1D-Texutr zum Speichern von Pufferobjekten)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMS&lt;br /&gt;
|Zugriff auf eine 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMSArray&lt;br /&gt;
|Zugriff auf einarray aus 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Arrays===&lt;br /&gt;
&lt;br /&gt;
Natürlich unterstützt glSlang auch Arrays, die wie in C deklariert werden und deren Index bei 0 beginnt. Folgendes Array im Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
beginnt also bei Index 0 und endet bei Index 2. Im Gegensatz zu C lassen sich Arrays in glSlang allerdings ''nicht bei der Initialisierung vorbelegen''. Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strukturen===&lt;br /&gt;
&lt;br /&gt;
Neu ggü. ARB_FP/VP ist nun auch die Möglichkeit, Strukturen in einem Shader zu deklarieren. Vor allem die Übersicht komplexerer Shader kann dadurch stark verbessert werden. Strukturen werden wie gewohnt mit dem Schlüsselwort {{INLINE_CODE|struct}} eingeleitet und können dann zur Typisierung von Variablen genutzt werden. Folgendes Beispiel dürfte die Nutzung verdeutlichen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct light&lt;br /&gt;
{&lt;br /&gt;
    bool active;&lt;br /&gt;
    float intensity;&lt;br /&gt;
    vec3 position;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
LightSource[i].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Typenqualifzierer==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur Typendeklaration kann eine Variable noch einen Typenqualifizerer vorangestellt bekommen, der an den Anfang der Deklaration gehört.&lt;br /&gt;
&lt;br /&gt;
* '''const'''&lt;br /&gt;
: Festgelegte (nur lesen) Konstante bzw. nur lesbarer Funktionsparameter.&lt;br /&gt;
&lt;br /&gt;
* '''uniform'''&lt;br /&gt;
: Ein den ganzen Shader über gleichbleibender Wert, der eine Schnittstelle zwischen dem Shader und der OpenGL-Anwendung darstellt. Ein Uniformwert wird in der Hauptanwendung an den entsprechenden Shader übergeben und kann dort dann genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* '''attribute'''&lt;br /&gt;
: Nur lesbare Werte die eine Verbindung zwischen dem Shader und der OpenGL-VertexAPI darstellen (z.B. VertexParameter eines VertexArrays). Natürlich nur in einem Vertex Shader nutzbar.&lt;br /&gt;
&lt;br /&gt;
* '''varying'''&lt;br /&gt;
: Stellt die Verbindung zwischen einem Vertex- und einem FragmentShader dar. Werden im VertexShader geschrieben und dann perspektivisch korrekt über die Primitive interpoliert, um dann im Fragment Shader gelesen werden zu können. Nutzbar sind hier nur die Typen float, vec2, vec3, vec4, mat2, mat3 und mat4, Strukturen und andere Datentypen können nicht varying sein. Die Namen einer varying-Variable müssen sowohl im VertexShader als auch im FragmentShader gleich sein.&lt;br /&gt;
&lt;br /&gt;
* '''in'''&lt;br /&gt;
: Für Variablen die an eine Funktion übergeben und dort ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* '''out'''&lt;br /&gt;
: Für Variablen die von einer Funktion nach außen zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
* '''inout'''&lt;br /&gt;
: Für Variablen die sowohl an eine Funktion übergeben als auch von dieser zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um obige Auflistung nicht leer im Raum stehen zu lassen zeige ich ein paar Beispiele die hoffentlich zum Verständnis beitragen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Vertexnormale soll an einen FragmenShader (interpoliert) übergeben werden :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
VertexNormal = normalize(MV_IT * gl_Normal);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Uniformparameter zur nachträglichen Farbänderung der Szene wird im Programm übergeben :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im Programm :&lt;br /&gt;
&lt;br /&gt;
 glUniform4fARB(glSlang_GetUniLoc(ProgramObject, 'GlobalColor'), Col[0], Col[1], Col[2], Col[3]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Beispiel C=== &lt;br /&gt;
Konstante zur festen Farbänderung :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
const vec4 ColorBias = vec4(0.2, 0.3, 0.0, 0.0);&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = ColorBias * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Konstruktoren==&lt;br /&gt;
&lt;br /&gt;
Um in einem Shader ''Vektoren'' oder ''Matrizen'' mit Werten zu belegen, gibt es sogenannte Konstruktoren (nicht zu verwechseln mit z.B. Klassenkonstruktoren unter Delphi), die im Endeffekt nichts anderes als Funktionen zur Vorbelegung von Vektoren oder Matrizen darstellen. Dabei trägt der Konstruktor den selben Namen wie die Typendeklaration, also lässt sich eine Variable vom Typ {{INLINE_CODE|vec4}} mit dem Konstruktor {{INLINE_CODE|vec4(float, float, float, float)}} initialisieren.&lt;br /&gt;
&lt;br /&gt;
Allerdings hat man sich recht viel Mühe bei dieser Konstruktorgeschichte gemacht, so dass man einen vec4 nicht unbedingt mit einem {{INLINE_CODE|vec4}}-Konstruktor vorbelegen muss, sondern es vielseitige Möglichkeiten gibt. Um dies zu verdeutlichen gibts ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(1.0, 0.0, 0.0, 0.0);&lt;br /&gt;
vec4 Color = vec4(MyVec3, 1.0);&lt;br /&gt;
vec4 Color = vec4(MyVec2_A, MyVec2_B);&lt;br /&gt;
&lt;br /&gt;
vec3 LVec  = vec3(MyVec4);&lt;br /&gt;
vec2 Tmp   = vec2(MyVec3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trotz der recht wenigen Beispiele sollte schnell erkennbar sein, das man hier wirklich sehr viele Kombinationsmöglichkeiten hat, die dann gültig sind ''wenn man mindestens auf die benötigte Anzahl der Argumente kommt''. Im vorletzten Beispiel wird z.B. ein 3-Komponentenvektor aus einem 4-Komponentenvektor initialisiert. Das erzeugt keinen Fehler, sondern führt dazu das {{INLINE_CODE|vec3.x, vec3.y, vec3.z}} aus MyVec4 übernommen werden und MyVec4.w einfach ignoriert wird.&lt;br /&gt;
&lt;br /&gt;
Das Umkehrbeispiel, also&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
funktioniert allerdings nicht, da hier die Zahl der benötigten Argumente nicht erreicht wird. In diesem Falle müsste es dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
heissen.&lt;br /&gt;
&lt;br /&gt;
Obiges gilt natürlich auch für ''Matrixkonstruktoren'', hier sind z.B. folgende Konstuktoren denkbar, obwohl eigentlich alle Möglichkeiten nutzbar sind, ''solange die benötigte Zahl an Argumenten erreicht wird'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
mat4 MyMatrix = mat4(MyVec4, MyVec4, MyVec4, MyVec4);&lt;br /&gt;
mat2 MyMatrix = mat4(1.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 1.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 1.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixkomponenten==&lt;br /&gt;
&lt;br /&gt;
Was natürlich in keiner Shadersprache fehlen darf, ist der leichte Zugriff auf die einzelnen Komponenten eines Vektors. glSlang bietet, je nach Anwendungsgebiet gleich drei Namensets für den Zugriff auf die Komponenten eines solchen Vektors, welches Set man nutzen will bleibt natürlich frei und ist unabhängig von der Deklaration eines Vektors. Man sollte nur darauf achten, beim gleichzeitigen Zugriff auf mehrere Komponenten im gleichen Namenset zu verbleiben :&lt;br /&gt;
&lt;br /&gt;
* {x, y, z, w}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Punkte, Normale oder sonstige Vertexdaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {r, g, b, a}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Farbwerte repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {s, t, p, q}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Texturkoordinaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
Ein paar Beispiele zur Unterstreichung des oben gesagten :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
v4.rgba = vec4(1.0, 0.0, 0.0, 0.0);  // gültig&lt;br /&gt;
v4.rgzw = vec4(1.0, 1.0, 1.0, 2.0);  // Ungültig, da verschiedenen Namensets&lt;br /&gt;
v2.rgb  = vec3(1.0, 2.0, 1.0);       // Ungültig, da vec2 nur r+g besitzt&lt;br /&gt;
v2.xx   = vec2(5.0, 3.0);            // Ungültig, da 2 mal gleiche Komponente&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch der Zugriff auf die Komponenten einer Matrix geht leicht von der Hand. Namensets wie bei den Vektoren gibt es hier natürlich keine, aber folgende Beispiele sollen den Zugriff aufzeigen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
MyMat4[2]    = vec4(1.0); // Setzt die 3.Zeile der Matrix komplett auf 1.0&lt;br /&gt;
MyMat4[3][3] = 3.5;       // Setzt das Element unren rechts auf 3.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Matrixelemente ausserhalb ihrer Dimension (also z.B. MyMat4[4][4]) liefert unvorhersehabre Ergebnise, also sollte man auf diese Fälle prüfen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixoperationen==&lt;br /&gt;
&lt;br /&gt;
Wie von C gewohnt sind in glSlang so ziemlich alle Operatoren die man auf Matrizen oder Vektoren anwenden kann überladen, so das man nicht umständlich über selbstgeschriebene Funktionen kombinieren muss. Darüber hinaus ist es in den meisten Fällen auch möglich ohne Konvertierung Fließkommawerte mit kompletten Matrizen oder Vektoren zu kombinieren. Folgende Beispiele zeigen einige der vielfältigen Kombinationsmöglichkeiten auf :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
float factor;&lt;br /&gt;
&lt;br /&gt;
vec3 dest = source + factor; &lt;br /&gt;
&lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = source.x + factor;&lt;br /&gt;
dest.y = source.y + factor;&lt;br /&gt;
dest.z = source.z + factor;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
mat3  MyMat;&lt;br /&gt;
 &lt;br /&gt;
dest = source * MyMat; &lt;br /&gt;
 &lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = dot(source, MyMat[0]);&lt;br /&gt;
dest.y = dot(source, MyMat[1]);&lt;br /&gt;
dest.z = dot(source, MyMat[2]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier sind die Möglichkeiten fast unbeschränkt und zeigen wieder wie flexibel glSlang ausgelegt ist. &lt;br /&gt;
&lt;br /&gt;
==Operatoren==&lt;br /&gt;
&lt;br /&gt;
glSlang bietet (momentan) folgende Operatoren, die Liste ist nach ihrer Gewichtung sortiert (Anfang = höchste). Alle ''reservierten'' Operatoren werden erst in kommender Hardware/glSlang-Versionen nutzbar sein :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div  align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Operatorklasse  	&lt;br /&gt;
!Operatoren  	&lt;br /&gt;
!Assoziation&lt;br /&gt;
|-&lt;br /&gt;
|Gruppering 	&lt;br /&gt;
|() 	&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
|Arrayindizierung&amp;lt;br&amp;gt;Funktionsaufrufe und Konstruktoren&amp;lt;br&amp;gt;Strukturfeldwahl und Swizzle&amp;lt;br&amp;gt;Postinkrement und -dekrement&amp;lt;br&amp;gt; 	&lt;br /&gt;
|[]&amp;lt;br&amp;gt;()&amp;lt;br&amp;gt;.&amp;lt;br&amp;gt;++ -- 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Prefixinkrement- und dekrement&amp;lt;br&amp;gt;Einheitlich (~ reserviert) 	&lt;br /&gt;
| ++ --&amp;lt;br&amp;gt; + - ~ ! 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Mulitplikation (% reserviert) 	&lt;br /&gt;
|* / % 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Additiv 	&lt;br /&gt;
| + - 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises Verschieben (reserviert) 	&lt;br /&gt;
|&amp;lt;&amp;lt;  &amp;gt;&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Relation 	&lt;br /&gt;
|&amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;= 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Vergleich 	&lt;br /&gt;
|==  != 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises AND (reserviert) 	&lt;br /&gt;
|&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises XOR (reserviert) 	&lt;br /&gt;
|^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises OR (reserviert) 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches AND 	&lt;br /&gt;
|&amp;amp;&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches XOR 	&lt;br /&gt;
|^^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches OR 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Auswahl 	&lt;br /&gt;
|?: 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Zuweisung&amp;lt;br&amp;gt;Arithmetrische Zuweisung&amp;lt;br&amp;gt;(Modulis, Shift und bitweise Op. reserviert) 	&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;+= -=  *=  /=  %=&amp;lt;/nowiki&amp;gt; &amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;&amp;lt;&amp;lt;=  &amp;gt;&amp;gt;= &amp;amp;=  ^=  |=&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Aufzählung 	&lt;br /&gt;
|, 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von Hochsprachen ist u.A. die Möglichkeit oft genutzte Codeteile in Funktionen (bzw. auch Prozeduren unter Pascal) zu verpacken um so Flexibilität als auch Übersichtlichkeit zu steigern. Wer schonmal was in C geschrieben hat, der wird sich jetzt sicherlich kein Kopfzerbrechen machen müssen. Funktionen werden in glSlang genauso nach folgendem Prinzip deklariert :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
RückgabeTyp FunktionsName(Typ0 Argument0, Typ1, Argument1, ... , TypN, ArgumentN)&lt;br /&gt;
 {&lt;br /&gt;
 return RückgabeWert;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, außerdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach außen übergeben soll, muss dieses Argument mit dem Typenqualifizierer out (Siehe Kapitel 4.2) versehen werden. ''Arrays'' können nur als Eingabeargumente übergeben werden und dürfen nich dimensioniert als Argument verwendet werden, sondern müssen mit leeren Klammern argumentiert werden.&lt;br /&gt;
Ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void MeineFunktion(float EingabeWert; out float AusgabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 AusgabeWert = EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach außen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float MeineFunktion(float EingabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 return EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bietet genau die selbe Funktionalität wie das Beispiel darüber. Allerdings wird hier der berechnete Wert als Ergebnis der Funktion zurückgeliefert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float VektorSumme(float v[])&lt;br /&gt;
 {&lt;br /&gt;
 return v[0]+v[1]+v[2]+v[3];&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt darf ein Array als Argument keine Dimensionierung enthalten. Wenn man der Funktion also ein Array übergibt, sollte man vorher drauf achten das es entsprechend der in der Funktion genutzten Indizes dimensioniert wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==if-Anweisung==&lt;br /&gt;
&lt;br /&gt;
Selektion über eine if-Anweisung darf auch in keiner Hochsprache fehlen. Genauso wie in C oder Delphi erwartet auch hier die If-Anweisung einen boolschen Ausdruck (Wahr oder Falsch) und wird dann ausgeführt (wahr) bzw. verzweigt auf ein (wenn vorhanden) else (falsch). Verschachtelung ist wie erwartet auch möglich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis : ''' &lt;br /&gt;
Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten im Fragmentshader kein Early-Out, was zur Folge hat das bei einer If-Anweisung immer alle Zweige ausgeführt werden. Am Ende wird dann aber nur ein Ergebnis geschrieben, die anderen verworfen. Auf solchen Karten bringen If-Anweisungen also im Normalfall keine Geschwindigkeitssteigerung, sondern oft eher das Gegenteil.&lt;br /&gt;
Neuere SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall, da hier dynamische Verzweigungen und auch Early-Out von der Hardware implementiert werden.&lt;br /&gt;
&lt;br /&gt;
==Schleifen==&lt;br /&gt;
&lt;br /&gt;
Auch Schleifen, ein wichtiges Konzept jeder Hochsprache haben ihren Weg in glSlang gefunden. Unterstützt werden folgende Schleifentypen :&lt;br /&gt;
&lt;br /&gt;
* '''for'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
do&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
 while (Durchlaufbedingung)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hinweis :''' Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten Schleifen nicht in Hardware. Schleifen werden dann beim Kompilieren vom Treiber entrollt, wodurch natürlich Shader mit weitaus mehr Instruktionen als erwartet generiert werden. Von daher sollte man auf solchen Karten möglichst auf Schleifen verzichten, oder diese nur recht kurz halten. Bei SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Variablen, Attribute und Konstanten=&lt;br /&gt;
Nachdem wir uns nun lange genug mit den minderinterssanten Elementen der glSlang-Syntax beschäftigt haben, gehts jetzt endlich an die wirklich interessanten Dinge. Wie schon ARB_VP/ARB_FP bringt auch glSlang jede Menge eingabauter Variablen, Attribute und Konstanten mit, deren Aliase sie recht leicht identifizierbar machen (ganz im Gegensatz zum Indexgewusel bei den DX-Shadern).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Vertex Shader==&lt;br /&gt;
Exklusiv im Vertex Shader stehen die folgenden Variablen zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Position    muss geschrieben werden&lt;br /&gt;
:Dieser Variable '''muss''' im Vertexshader ein Wert zugewiesen werden, wird dies nicht getan ist das Ergebnis (sprich die Position des Vertex) undefiniert. Vorgesehen ist diese Variable für die ''homogene Position des Vertex'' und wird u.a. zum Clipping und Culling verwendet. Sie darf natürlich auch (mehrfach) geschrieben und ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* float gl_PointSize    kann geschrieben werden&lt;br /&gt;
:Diese Variable wurde dazu vorgesehen um dort im VertexShader die Punktgröße in Pixeln hineinzuschreiben.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_ClipVertex    kann geschrieben werden&lt;br /&gt;
:Falls genutzt, sollten hier die Vertexkoordinaten die im Zusammenhang mit benutzerdefinierten Clippingplanes genutzt werden abgelegt werden. Wichtig ist, das gl_ClipVertex im selben Koordinatenraum wie die Clippingplane definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Attribute im Vertex Shader==&lt;br /&gt;
&lt;br /&gt;
Folgende Attribute stehen nur im Vertex Shader zur Verfügung und '''können nur gelesen werden''' :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Color&lt;br /&gt;
: Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_SecondaryColor&lt;br /&gt;
:Sekundärer Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_Normal&lt;br /&gt;
:Normale des Vertex.&lt;br /&gt;
* vec4 gl_Vertex&lt;br /&gt;
:Koordinaten des Vertex;&lt;br /&gt;
* vec4 gl_MultiTexCoord0..7&lt;br /&gt;
:Texturkoordinaten auf Textureinheit 0..7.&lt;br /&gt;
* float gl_FogCoord&lt;br /&gt;
:Nebelkoordinate des Vertex. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Fragment Shader==&lt;br /&gt;
&lt;br /&gt;
Im Fragment Shader sind folgende Variablen exklusiv nutzbar :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragColor&lt;br /&gt;
: Speichert den Farbwert des Fragmentes, der von folgenden Funktionen der festen Pipeline genutzt wird. Wird dieser Variable nichts zugewiesen, so ist ihr Inhalt undefiniert und darauf aufbauende Ergebnisse ebenfalls.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragData[0..15]&lt;br /&gt;
: Ersetzt gl_FragColor bei der Verwendung von multiplen Rendertargets. &lt;br /&gt;
&lt;br /&gt;
* float gl_FragDepth&lt;br /&gt;
: Durch schreiben dieser Variable kann man den von der festen Funktionspipeline ermittelten Tiefenwert überspringen, der mit {{INLINE_CODE|gl_FragCoord.z}} ausgelesen werden kann. Wird dieser Wert nicht geschrieben, nutzen folgende Funktionen der Pipeline den vorher fest berechneten Wert.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragCoord    nur lesen&lt;br /&gt;
: In dieser Variable ist die Position des Fragmentes relativ zur Fensterposition im Format x,y,z,1/w abgelegt, wobei z den von der festen Funktionspipeline berechneten Tiefenwert enthält.&lt;br /&gt;
&lt;br /&gt;
* bool gl_FrontFacing    nur lesen&lt;br /&gt;
: Gibt an ob das Fragment zu einer nach vorne zeigenden Primitive gehört (=true). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bezug auf {{INLINE_CODE|gl_FragColor}} und {{INLINE_CODE|gl_FragDepth}} sei noch anzumerken das diese ''nicht'' in den Wertebereich 0..1 gebracht werden müssen, da dies später durch die feste Funktionspipeline automatisch gemacht wird.&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Varyings==&lt;br /&gt;
&lt;br /&gt;
Wie bereits in Kapitel 4.2 erwähnt, stellen Varyings eine Schnittstelle zwischen dem Vertex und dem Fragment Shader dar. Sie werden im Vertex Shader geschrieben und können dann im Fragment Shader ausgelesen werden, ohne das die folgenden Varyings dafür explizit deklariert werden müssen :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontColor&lt;br /&gt;
: Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackColor&lt;br /&gt;
: Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_TexCoord[x]&lt;br /&gt;
: Texturkoordinaten des Vertex auf Textureinheit x, wobei x die von der Hardware zur Verfügung gestellte Zahl der Textureinheiten-1 nicht überschreiten darf.&lt;br /&gt;
&lt;br /&gt;
* float gl_FogFragCoord&lt;br /&gt;
: Nebelkoordinate des Fragmentes. &lt;br /&gt;
&lt;br /&gt;
Die Varyings {{INLINE_CODE|gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor}} und {{INLINE_CODE|gl_BackSecondaryColor}} können im FragmentShader nur unter den Aliases gl_Color bzw. gl_SecondaryColor gelesen werden. Welcher Wert des Vertex Shaders im Fragment Shader dort eingesetzt wird ist abhängig davon ob das Fragment zu einer nach vorne oder nach hinten zeigenden Primitive gehört.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Konstanten==&lt;br /&gt;
Auch diverse Konstanten wurden definiert um darauf schnell im Shader zugreifen zu können. In den Klammern stehen die von einer GL-Implementation als Mindestanforderung anzubietenden Werte. Alle Konstanten sind sowohl im Vertex als auch im Fragment Shader abrufbar :&lt;br /&gt;
&lt;br /&gt;
: OpenGL 1.0/1.2 :&lt;br /&gt;
* int gl_MaxLights (8)&lt;br /&gt;
* int gl_MaxClipPlanes (6)&lt;br /&gt;
* int gl_MaxTextureUnits (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: ARB_Fragment_Program :&lt;br /&gt;
* int gl_MaxTextureCoordsARB (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Vertex_Shader :&lt;br /&gt;
* int gl_MaxVertexAttributesGL2 (16)&lt;br /&gt;
* int gl_MaxVertexUniformFloatsGL2 (512)&lt;br /&gt;
* int gl_MaxVaryingFloatsGL2 (32)&lt;br /&gt;
* int gl_MaxVertexTextureUnitsGL2 (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Fragment_Shader :&lt;br /&gt;
* int gl_MaxFragmentTextureUnitsGL2 (2)&lt;br /&gt;
* int gl_MaxFragmentUniformFloatsGL2 (64)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Uniformvariablen==&lt;br /&gt;
&lt;br /&gt;
Um den Zugriff auf OpenGL-Staten zu vereinfachen wurden in glSlang diverse Uniformvariablen zur direkten Verwendung im Shader eingebaut. Wie gewohnt wurden auch hier sinnvolle Namen verwendet, so dass eine tiefere Erklärung unnötig sein dürfte :&lt;br /&gt;
&lt;br /&gt;
* mat4 gl_ModelViewMatrix&lt;br /&gt;
* mat4 gl_ProjectionMatrix&lt;br /&gt;
* mat4 gl_ModelViewProjectionMatrix&lt;br /&gt;
* mat3 gl_NormalMatrix&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die invertierten und anschließend transponierten oberen 3x3 Werte der {{INLINE_CODE|gl_ModelViewMatrix}}.&lt;br /&gt;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
* float gl_NormalScale&lt;br /&gt;
: Gibt den unter OpenGL festgelegten Faktor zur Skalierung der Normalen zurück.&lt;br /&gt;
&lt;br /&gt;
* struct gl_DepthRangeParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_DepthRangeParameters&lt;br /&gt;
{&lt;br /&gt;
 float near;&lt;br /&gt;
 float far;&lt;br /&gt;
 float diff;&lt;br /&gt;
};&lt;br /&gt;
gl_DepthRangeParameters gl_DepthRange;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_PointParameters&lt;br /&gt;
{&lt;br /&gt;
 float size;&lt;br /&gt;
 float sizeMin;&lt;br /&gt;
 float sizeMax;&lt;br /&gt;
 float fadeThresholdSize;&lt;br /&gt;
 float distanceConstantAttenuation;&lt;br /&gt;
 float distanceLinearAttenuation;&lt;br /&gt;
 float distanceQuadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_PointParameters gl_Point;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_MaterialParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 emission;&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 float shininess;&lt;br /&gt;
};&lt;br /&gt;
gl_MaterialParameters gl_FrontMaterial;&lt;br /&gt;
gl_MaterialParameters gl_BackMaterial;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightSourceParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 vec4 position;&lt;br /&gt;
 vec4 halfVector;&lt;br /&gt;
 vec3 spotDirection;&lt;br /&gt;
 float spotExponent;&lt;br /&gt;
 float spotCutoff;&lt;br /&gt;
 float spotCosCutoff;&lt;br /&gt;
 float constantAttenuation;&lt;br /&gt;
 float linearAttenuation;&lt;br /&gt;
 float quadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_LightSourceParameters gl_LightSource[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelParameters gl_LightModel;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 sceneColor;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelProducts gl_FrontLightModelProduct;&lt;br /&gt;
gl_LightModelProducts gl_BackLightModelProduct;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
};&lt;br /&gt;
gl_LightProducts gl_FrontLightProduct[gl_MaxLights];&lt;br /&gt;
gl_LightProducts gl_BackLightProduct[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* vec4 gl_TextureEnvColor[gl_MaxFragmentTextureUnitsGL2]&lt;br /&gt;
* vec4 gl_EyePlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
*struct gl_FogParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_FogParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 color;&lt;br /&gt;
 float density;&lt;br /&gt;
 float start;&lt;br /&gt;
 float end;&lt;br /&gt;
 float scale;&lt;br /&gt;
};&lt;br /&gt;
gl_FogParameters gl_Fog;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese recht umfangreiche GL-Stateliste sollte eigentlich jeden Bedarf decken und momentan gibts kaum einen OpenGL-Status den man so nicht in einem Shader abfragen bzw. nutzen kann.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Funktionen=&lt;br /&gt;
glSlang ist mit diversen Skalar- und Vektorfunktionen ausgestattet, die teilweise (idealerweise) sogar direkt in der Hardware ausgeführt werden, weshalb einer fertigen Funktion ggü. gleichwertigen eigenen Berechnungen immer der Vorzug zu geben ist.&lt;br /&gt;
{{Hinweis| ''genType'' kann vom Type float, vec2, vec3 oder vec4 sein, ''mat'' vom Typ mat2, mat3 oder mat4.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie und Winkel==&lt;br /&gt;
Alle übergebenen Winkel sollten, soweit nicht anders vermerkt, in Radien angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* genType radians (genType degrees)&lt;br /&gt;
: Wandelt von Grad nach Radien. &lt;br /&gt;
* genType degrees (genType radians)&lt;br /&gt;
: Wandelt von Radien nach Grad.&lt;br /&gt;
* genType sin (genType x)&lt;br /&gt;
: Gibt den Sinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType x)&lt;br /&gt;
: Gibt den Kosinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType x)&lt;br /&gt;
: Gibt den Tangens von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType asin (genType x)&lt;br /&gt;
: Liefert den Arcsinus von x zurück, also den Winkel dessen Sinus x ergeben würde.&lt;br /&gt;
* genType acos (genType x)&lt;br /&gt;
: Liefert den Arckosinus von x zurück, also den Winkel dessen Cosinus x ergeben würde.&lt;br /&gt;
* genType atan (genType y, genType x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x/y ergeben würde.&lt;br /&gt;
* genType atan (genType y_over_x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x über y ergeben würde.&lt;br /&gt;
&lt;br /&gt;
==Hyperbolisch==&lt;br /&gt;
* genType sinh (genType x)&lt;br /&gt;
: Gibt den Sinus Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) * 0.5; )&lt;br /&gt;
* genType cosh (genType x)&lt;br /&gt;
: Gibt den Kosinus Hyperbolicus von x zurück. (return = (exp(x) + exp(-x)) * 0.5; )&lt;br /&gt;
* genType tanh (genType x)&lt;br /&gt;
: Gibt den Tangens Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) / (exp(x) + exp(-x)); )&lt;br /&gt;
* genType asinh (genType angle)&lt;br /&gt;
: Gibt den Areasinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x + 1.0)); )&lt;br /&gt;
* genType acosh (genType angle)&lt;br /&gt;
: Gibt den Areakosinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x - 1.0)); )&lt;br /&gt;
* genType atanh (genType x)&lt;br /&gt;
: Gibt den Areatangens Hyperbolicus von x zurück. (return = log((1.0 + x) / (1.0 - x)) * 0.5; )&lt;br /&gt;
&lt;br /&gt;
==Exponentiell==&lt;br /&gt;
* genType pow (genType x, genType y)&lt;br /&gt;
: Gibt x hoch y zurück.&lt;br /&gt;
* genType exp (genType x)&lt;br /&gt;
: Gibt e(Eulerischezahl ≈ 2.7182) hoch x zurück.&lt;br /&gt;
* genType log (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis e(Eulerischezahl ≈ 2.7182) von x zurück.&lt;br /&gt;
* genType exp2 (genType x)&lt;br /&gt;
: Gibt 2 hoch x zurück.&lt;br /&gt;
* genType log2 (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis 2 von x zurück.&lt;br /&gt;
* genType sqrt (genType x)&lt;br /&gt;
: Gibt die Wurzel von x zurück.&lt;br /&gt;
* genType inversesqrt (genType x)&lt;br /&gt;
: Gibt die umgekehrte Wurzel von x zurück.&lt;br /&gt;
&lt;br /&gt;
==Standardfunktionen==&lt;br /&gt;
* genType abs (genType x)&lt;br /&gt;
: Liefert den absoluten Wert von x zurück.&lt;br /&gt;
* genType sign (genType x)&lt;br /&gt;
: Gibt -1.0 zurück, wenn x &amp;lt; 0.0, 0.0 wenn x = 0.0 und 1.0 wenn x &amp;gt; 0.0.&lt;br /&gt;
* genType roundeven(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. Bei &amp;quot;.5&amp;quot; Werten wird zur nächsten geraden Zahl gerundet.&lt;br /&gt;
* genType round(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. &amp;quot;.5&amp;quot; Werte werden je nach Implementation anders behandelt.&lt;br /&gt;
* genType trunc(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert dessen Absoluterwert nicht größer ist als der Absolutewert von x&lt;br /&gt;
* genType floor (genType x)&lt;br /&gt;
: Gibt denn größten Integerwert zurück, der kleiner oder gleich x ist.&lt;br /&gt;
* genType ceil (genType x)&lt;br /&gt;
: Gibt den kleinsten Integerwert zurück, der größer oder gleich x ist.&lt;br /&gt;
* genType fract (genType x)&lt;br /&gt;
: Gibt den Nachkommateil von x zurück.&lt;br /&gt;
* genType mod (genType x, float y) &lt;br /&gt;
* genType mod (genType x, genType y)&lt;br /&gt;
: Gibt den Modulus zurück. (result = x - y * floor(x / y)) &lt;br /&gt;
* genType min (genType x, genType y) &lt;br /&gt;
* genType min (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn y &amp;lt; x, ansonsten x. &lt;br /&gt;
* genType max (genType x, genType y) &lt;br /&gt;
* genType max (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn x &amp;lt; y, ansonsten x. &lt;br /&gt;
* genType clamp (genType x, genType minVal, genType maxVal) &lt;br /&gt;
* genType clamp (genType x, float minVal, float maxVal)&lt;br /&gt;
: Zwängt x in den Bereich minVal ... maxVal .  (return = min(minVal, max(maxVal, x)))&lt;br /&gt;
* genType mix (genType x, genType y, genType a)&lt;br /&gt;
* genType mix (genType x, genType y, float a)&lt;br /&gt;
: Liefert den linearen Blend zwischen x und y zurück. (result = x * (1 - a) + y * a) &lt;br /&gt;
* genType step (genType edge, genType x)&lt;br /&gt;
* genType step (float edge, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt; edge, ansonsten 1.0. &lt;br /&gt;
* genType smoothstep (genType edge0, genType edge1, genType x)&lt;br /&gt;
* genType smoothstep (float edge0, float edge1, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge0 und 1.0 wenn x &amp;gt;= edge1. Dazwischen wird eine weiche Hermite Interpolation durchgeführt.&lt;br /&gt;
::float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);&lt;br /&gt;
::result = t * t * (3.0 - 2.0 * t)&lt;br /&gt;
&lt;br /&gt;
==Geometrie==&lt;br /&gt;
* float length (genType x)&lt;br /&gt;
: Gibt die Länge des Vektors x (= sqrt(x[0]² + x[1]² + ... + x[n]²) zurück. &lt;br /&gt;
* float distance (genType p0, genType p1)&lt;br /&gt;
: Gibt die Distanz zwischen den zwei Vektoren p0 un p1 (= length(p0-p1)) zurück. &lt;br /&gt;
* float dot (genType x, genType y)&lt;br /&gt;
: Gibt das Punktprodukt von x und y zurück (=x[0]*y[0] + x[1]*y[1] + ... + x[n]*y[n]). &lt;br /&gt;
* vec3 cross (vec3 x, vec3 y)&lt;br /&gt;
: Gibt das Kreuzprodukt von x und y zurück. &lt;br /&gt;
* genType normalize (genType x)&lt;br /&gt;
: Normalisiert den Vektor x auf die Länge 1. &lt;br /&gt;
* vec4 ftransform()&lt;br /&gt;
: Nur im Vertex Shader. Die Funktion stellt sicher, das das eingehende Vertex haargenau so transformiert wird wie in der festen Funktionspipeline. gl_Position = ftransform() wird dann also gebraucht, wenn in mehreren Durchgängen sowohl im Shader als auch in der festen Pipeline gerendert wird, um sicherzustellen das in beiden Fällen die gleiche Vertexposition herauskommt. &lt;br /&gt;
* genType faceforward (genType N, genType I, genType Nref)&lt;br /&gt;
: Gibt einen nach vorne zeigenden Vektor N zurück. (If dot(NRef, I) &amp;lt; 0 return N else return -N) &lt;br /&gt;
* genType reflect (genType l, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (result = l - 2.0 * dot(N,I) * N; )&lt;br /&gt;
* genType refract (genType l, genType N, float eta)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N mit dem Brechungsindex eta gebrochenen Vektor l zurück. &lt;br /&gt;
::gentype k = 1.0 - eta * eta * (1.0 - dot(N, l) * dot(N, l))&lt;br /&gt;
::if (k &amp;lt; 0.0)&lt;br /&gt;
:::result = 0.0&lt;br /&gt;
::else &lt;br /&gt;
:::result = eta * l - (eta * dot(N, l) * sqrt(k)) * N&lt;br /&gt;
&lt;br /&gt;
==Matrixfunktionen==&lt;br /&gt;
* mat matrixCompMult (mat x, mat y)&lt;br /&gt;
: Multipliziert Matrix X mit Matrix Y komponentenweise. Um eine normale lineare Matrixmultiplikation durchzuführen, sollte der &amp;quot;*&amp;quot;-Operator genutzt werden.&lt;br /&gt;
* mat transpose (mat m)&lt;br /&gt;
: Gibt die transponierte Matrix von m zurück.&lt;br /&gt;
* mat invert (mat m)&lt;br /&gt;
: Gibt die invertierte Matrix von m zurück. Also die Matrix, die mit m multipliziert die Normalmatrix ergeben würde.&lt;br /&gt;
* mat outerProduct(vec c, vec r)&lt;br /&gt;
: Gibt eine eine Matrix als Ergebnis der linearen (return[m, n] = c[m] * r[n])-Operation zurück.&lt;br /&gt;
&lt;br /&gt;
==Vektorvergleiche==&lt;br /&gt;
Die meisten Vektorvergleichsfunktionen liefern als Ergebnis einen boolvektor zurück, da die Vergleiche per Komponente stattfinden. Wenn man also x = vec4(1.0, 3.0, 0.0, 0.0) mit y = vec4(2.0, 1.5, 1.5, 0.0) via lessThan(x, y) vergleicht, erhält man als Ergebnis bvec(true, false, true, false).&lt;br /&gt;
&lt;br /&gt;
* bvec lessThan (vec x, vec y)&lt;br /&gt;
* bvec lessThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt; y zurück. &lt;br /&gt;
* bvec lessThanEqual (vec x, vec y)&lt;br /&gt;
* bvec lessThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt;= y zurück. &lt;br /&gt;
* bvec greaterThan (vec x, vec y)&lt;br /&gt;
* bvec greaterThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt; y zurück. &lt;br /&gt;
* bvec greaterThanEqual (vec x, vec y)&lt;br /&gt;
* bvec greaterThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt;= y zurück. &lt;br /&gt;
* bvec equal (vec x, vec y)&lt;br /&gt;
* bvec equal (ivec x, ivec y)&lt;br /&gt;
* bvec equal (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x == y zurück. &lt;br /&gt;
* bvec notEqual (vec x, vec y)&lt;br /&gt;
* bvec notEqual (ivec x, ivec y)&lt;br /&gt;
* bvec notEqual (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x != y zurück. &lt;br /&gt;
* bool any (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn mindestens eine der Komponenten von x true ist.&lt;br /&gt;
* bool all (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn alle Komponenten von x true sind. &lt;br /&gt;
* bvec not (bvec x)&lt;br /&gt;
: Liefert die logische Negation von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Texturenzugriffe==&lt;br /&gt;
&lt;br /&gt;
Diese wichtige Funktionskategorie dient dazu, Werte aus einer an eine Textureinheit gebundenen Textur zu ermitteln. Die Texturenzugriffe können sowohl im Vertex (!) als auch im Fragment Shader ausgeführt werden, wobei der optionale Parameter bias im Vertex Shader ignoriert wird. Allerdings gibt es zusätzlich Funktionen die auf &amp;quot;Lod&amp;quot; enden und nur im Vertex Shader genutzt werden dürfen um eben dieses Manko zu umgehen. Funktionen mit dem Suffix &amp;quot;Proj&amp;quot; geben einen projizierten Texturenwert zurück.&lt;br /&gt;
&lt;br /&gt;
: '''1D-Texturen :'''&lt;br /&gt;
* vec4 texture1D (sampler1D sampler, float coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 texture1DLod (sampler1D sampler, float coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''2D-Texturen :'''&lt;br /&gt;
* vec4 texture2D (sampler2D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''3D-Texturen :'''&lt;br /&gt;
* vec4 texture3D (sampler3D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture3DProj (sampler3D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture3DProjLod (sampler3D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Cubemap :'''&lt;br /&gt;
* vec4 textureCube (samplerCube sampler, vec3 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
*vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Tiefentextur (Shadowmap) :'''&lt;br /&gt;
* vec4 shadow1D (sampler1DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow2D (sampler2DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
* vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow1DProjLod (sampler1DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
* vec4 shadow2DProjLod (sampler2DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Texturegröße :'''&lt;br /&gt;
Mit den textureSize-Befehlen kann die Größe einer Textur bestimmt werden, wobei lod das Mipmaplevel angibt:&lt;br /&gt;
*int textureSize(sampler1D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2D sampler, int lod)&lt;br /&gt;
*ivec3 textureSize(sampler3D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(samplerCube sampler, int lod)&lt;br /&gt;
*int textureSize(sampler1DShadow sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2DShadow sampler, int lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie bereits eingangs gesagt ist dieses Kapitel ein sehr wichtiges, denn eine 3D-Szene ohne Texturen ist heute kaum denkbar. Darüber hinaus lassen sich durch Texturenzugriffe recht viele interessante Sachen machen, z.B. ein einfacher Blurfilter oder das freie überblenden bestimmter Texturenteile. Deshalb führe ich hier kurz ein paar Beispiele an, welche die Nutzung dieser Funktionen verdeutlichen sollen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Eine Textur gebunden die einfach ausgegeben werden soll&lt;br /&gt;
&lt;br /&gt;
''Im Vertex Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
Der Vertex Shader ist recht minimal. Neben der homogenen Vertexposition leiten wir hier nur die im OpenGL-Programm angegebenen Texturkoordinaten weiter. ''Dies ist aber unbedingt nötig!'' Ohne die letzte Zeile hätten wir im Fragment Shader keine gültigen Texturkoordinaten auf TMU0, was in einer Fehldarstellung enden würde.&lt;br /&gt;
&lt;br /&gt;
''im Fragment Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSampler;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(texSampler, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zuerst deklarieren wir hier einen 2D-Texturensampler, wichtig : '''Texturensampler müssen IMMER als uniform deklariert werden!''' In der Hauptfunktion weisen wir dann einfach den über die Funktion texture2D aus unserer gebundenen Textur ausgelesenen Farbwert, anhand der vom Vertex Shader übergebenen Texturkoordinaten, zu.&lt;br /&gt;
{{Vorlage:Hinweis|Der Uniform-Integer für den Sampler referenziert '''nicht''' den Namen (die ID) des Texturobjektes, sondern die Nummer der Texturunit.}}&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Zwei Texturen, jeweils auf TMU0 und TMU1. Fragmentfarbe soll eine Multiplikation der beiden Texturen darstellen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielfall (der recht häufig vorkommt) müssen wir im Programm festlegen, ''welcher Sampler welche Textureinheit adressiert'', genau deshalb müssen die Texturensampler auch als uniform deklariert werden. Die Standardtextureneinheit eines Samplers ist TMU0, was in unserem Falle natürlich nicht brauchbar ist. Also müssen wir unserem zweiten Textursampler im Programm mitteilen das er seine Daten aus TMU1 beziehen soll :&lt;br /&gt;
&lt;br /&gt;
 glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&lt;br /&gt;
Dies ist also unbedingt zu machen, sobald ein Texturensampler eine Textureinheit &amp;gt; GL_TEXTURE_0 adressieren will. Die Textureneinheit des Samplers lässt sich also nicht im Shader selbst festlegen. Der Fragment Shader ist nun allerdings schnell hergeleitet (Vertex Shader verändert sich nicht, da TMU1 die Texturkoordinaten auch von TMU0 bezieht) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
im Fragment Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSamplerTMU0;&lt;br /&gt;
uniform sampler2D texSamplerTMU1;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_FragColor = texture2D(texSamplerTMU0, vec2(gl_TexCoord[0])) *&lt;br /&gt;
                   texture2D(texSamplerTMU1, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich [[GLSL noise|Noisefunktionen]] nutzen, mit deren Hilfe sich eine gewisse &amp;quot;Zufälligkeit&amp;quot; simulieren lässt (wirklich zufällige Werte sind es natürlich nicht). Ein zurückgegebener Wert liegt dabei immer im Bereich [-1..1] und ist immer bei gleichem Eigabewert auch immer gleich. Die Verwendung empfiehlt sich derzeit allerdings eher nicht, da nur die 3DLabs Treiber die Funktionen unterstützen und eine Noisetextur wahrscheinlich performanter ist.&lt;br /&gt;
&lt;br /&gt;
* float noise1 (genType x)&lt;br /&gt;
* vec2 noise2 (genType x)&lt;br /&gt;
* vec3 noise3 (genType x)&lt;br /&gt;
* vec4 noise4 (genType x)&lt;br /&gt;
&lt;br /&gt;
==Discard==&lt;br /&gt;
Eigentlich keine Funktion, sondern eine Abbruchbedingung '''nur im Fragment Shader'''. Das Schlüsselwort {{INLINE_CODE|discard}} verwirft das aktuell bearbeitete Fragment und beendet gleichzeitig den Shader. Es kann z.B. genutzt werden um Alphamasking manuell durchzuführen.&lt;br /&gt;
Man sollte dabei jedoch beachten dass ein Großteil der aktuellen Hardware kein &amp;quot;early-out&amp;quot; (frühes Beenden) im Fragmentshader unterstützt. Wenn dort also ein {{INLINE_CODE|discard}} auftaucht, wird trotzdem auch der Code danach ausgeführt und einfach verworfen. Einen Geschwindigkeitsvorteil durch diesen Befehl wird man also erst auf neueren Karten feststellen, die dieses Faeature auch so unterstützen wie es angedacht war. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispielshader=&lt;br /&gt;
Wen bis hierhin nicht der Mut verlassen hat, und wer aufmerksam gelesen hat, dürfte jetzt also zumindest in der Lage sein kleinere Shader in glSlang zu schreiben und diese auch im Programm zu nutzen. Ich habe im Themenbereich &amp;quot;glSlang&amp;quot; versucht alle Bereiche der Shadersprache selbst anzusprechen und hoffe das auch brauchbar rübergebracht zu haben. Um oben erlerntes (hoffe ich doch mal) nochmal zu vertiefen werde ich jetzt (wie ich das bereits bei meinem ARB_VP-Tutorial getan habe) einen simplen Beispielshader (Vertex und Fragment Shader) auseinanderpflücken um so u.a. auch die Programmstruktur für alle die in C nicht so bewandert sind zu erörtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Vertex Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_FrontColor   = gl_Color * GlobalColor;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie gesagt recht simpel. Angefangen wird mit der Deklaration einer globalen Uniformvariable namens {{INLINE_CODE|GlobalColor}}. Wie wir uns erinnern gibt der Typenqualifizierer uniform an, das wir den Wert dieser Variable (ein 4-Komponentenvektor, da Farbwerte aus R,G,B und A bestehen) in unserem Programm an den Shader übermitteln.&lt;br /&gt;
&lt;br /&gt;
Danach gehts ohne Umwege direkt in unsere Hauptfunktion, da wir im Vertex Shader keine anderen Funktionen benötigen. Dort berechnen wir zuerst die homogene Position unseres Vertex, die sich aus der eingehenden Vertexposition multipliziert mit der Modelansichtsmatrix ergibt. Wie schonmal gesagt '''muss diesem Wert etwas zugewiesen werden''', da sonst alle darauf aufbauenden Funktionen unvorhersehbare Ergebnisse liefern.&lt;br /&gt;
Außerdem wollen wir die Frontfarbe unseres Vertex jedesmal mit der im Programm übergebenen GlobalColor multiplizieren, so dass wir den Farbwert der gesamten Szene aus unserem Programm heraus manipulieren können. Zu guterletzt geben wir dann noch unsere aus der festen Funktionspipeline erhaltenen Texturkoordinaten auf Textureinheit 0 weiter. Wenn im Fragmentshader Texturkoordinaten verwendet werden, '''muss das getan werden'''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Fragment Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
uniform sampler2D Texture2;&lt;br /&gt;
uniform sampler2D Texture3;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec2 TexCoord = vec2( gl_TexCoord[0] );&lt;br /&gt;
 vec4 RGB      = texture2D( Texture0, TexCoord );&lt;br /&gt;
&lt;br /&gt;
 gl_FragColor  = texture2D(Texture1, TexCoord) * RGB.r +&lt;br /&gt;
                 texture2D(Texture2, TexCoord) * RGB.g +&lt;br /&gt;
                 texture2D(Texture3, TexCoord) * RGB.b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier passiert nicht wirklich viel Großartiges. Wir deklarieren beim Shaderanfang zuerst vier Texturensampler, da wir insgesamt vier verschiedene Texturen im Shader auslesen wollen, eine Verlaufstextur und drei Oberflächentexturen. Auch hier sei wieder gesagt das man Sampler '''immer als uniform deklarieren muss'''. In der Hauptfunktion deklarieren wir dann einen Farbvektor, der auch direkt einen Farbwert aus Textureinheit 0 zugewiesen bekommt. Auf Textureinheit 0 haben wir ihm Hauptprogramm eine Verlaufstextur gebunden, die angibt wie die drei folgenden Texturen ineinander geblendet werden.&lt;br /&gt;
Danach schreiben wir dann den Farbwert des Fragmentes, der '''im Fragment Shader ausgegeben werden muss'''. Der besteht wie einfach zu erkennen aus Farbwert von Textureinheit 1 * Rotwert von Textureinheit 0 + Farbwert von Textureinheit 2 * Grünwert von Textureinheit 0 + Farbwert von Textureinheit 3 * Blauwert von Textureinheit 0. So ist z.B. an Stellen an denen in der Verlaufstextur reines blau liegt nur die dritte Textur sichtbar.&lt;br /&gt;
&lt;br /&gt;
So viel also zu unserem kleinen Beispielshader. Er ist weder besonders toll noch besonders sinnvoll, sollte aber auch eher dazu dienen euch glSlang ein wenig zu veranschaulichen, was mir hoffentlich gelungen ist.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr in den vorangegangenen Kapiteln zumindest ein wenig aufgepasst habt, dann könnt ihr euch vor eurem inneren Auge hoffentlich vortstellen was der Shader macht : Er blendet drei Texturen weich anhand der Verlaufstextur ineinander über. Sowas kann man z.B. für ein Terrain nutzen, um dieses anhand einer Farbtextur zu texturieren. Für alle, die damit Probleme haben hier zwei Bilder die den Shader veranschaulichen. Links die Verlaufstextur, die angibt wo welche Textur wie stark gewichtet wird und rechts dann das Ergebnis :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; [[BILD:GLSL_sample_shader_a.jpg]] [[BILD:GLSL_sample_shader_b.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post Mortem=&lt;br /&gt;
Das wars also, meine &amp;quot;Einführung&amp;quot; in die OpenGL Shader Sprache. Ich hoffe es hat euch nicht gelangweilt und auch die von mir zur Verfügung gestellten Informationen haben euch hoffentlich ausgereicht. Mit der Veröffentlichung dieser Einführung geht übrigens auch die Eröffnung eines Shaderforums hier auf der DGL einher, in der ihr dann also fleissig Fragen zum Thema stellen oder eure Shader präsentieren könnt. In diesem Post Mortem gehe ich jetzt noch kurz auf die Zukunft von glSlang ein und zeige ein paar Screenshots (damit die Augen entspannen können), bevor ihr euch dann selbst in die Shaderwelt stürzen könnt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
Anbei ein paar exemplarische Screenshots. Da man mit GLSL aber alle möglichen Effekte berechnen kann (u.a. auch 1:1 die feste Funktionspipeline) ist es hier unmöglich einen Überblick aller möglichen Techniken zu geben.&lt;br /&gt;
&lt;br /&gt;
[[Datei:tut_glsl_eigenershader_01.png]] [[Datei:tut_glsl_eigenershader_02.png]] [[Datei:tut_glsl_eigenershader_03.png]]&lt;br /&gt;
&lt;br /&gt;
Wie im ersten (und dritten) Screenshot zu sehen ist es natürlich auch möglich mehrere Techniken innerhalb einer Szene zu nutzen. Hier sind letztendlich bis auf Hardwarelimitationen keine Grenzen gesetzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Als dieses Tutorial geschrieben wurde, war noch nicht ganz abzusehen dass bzw. ob sich GLSL auch durchsetzen würde. ARB-Shader und NVidias cG waren damals die Platzhirsche, aber inzwischen werden ARB-Shader nicht mehr genutzt (und auch schon länger nicht mehr weiterentwickelt) und auch NVidia setzt primär auf GLSL. GLSL wird permanent weiterenwtickelt und Hersteller können dank des flexiblen Extensionsystems auch in GLSL eigene Extensions offenlegen um die aktuellsten Features (wie z.b. den Tesselator auf aktuellen ATI-Karten) nutzen zu können. GLSL gilt inzwischen auch offizielle die Shadersprache für OpenGL und wird permanent an die neusten technischen Entwicklungen im Grafikkartenbereich angepasst.&lt;br /&gt;
&lt;br /&gt;
Wer also unter OpenGL etwas mit Shadern machen möchte, kommt an GLSL nicht vorbei!&lt;br /&gt;
&lt;br /&gt;
Also viel Spaß beim Experimentieren und Shaderschreiben! Und nicht vergessen : Wir wollen sehen was ihr so treibt,&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_glsl2]]}}&lt;br /&gt;
[[Kategorie:Tutorial|GLSL]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glRect&amp;diff=25674</id>
		<title>glRect</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glRect&amp;diff=25674"/>
				<updated>2012-05-13T12:45:24Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Name */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glRect =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glRect''' - Zeichnet ein Rechteck.&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glRectd'''(''x1'', ''y1'', ''x2'', ''y2'' : TGLDouble); &lt;br /&gt;
 procedure '''glRectf'''(''x1'', ''y1'', ''x2'', ''y2'' : TGLFloat); &lt;br /&gt;
 procedure '''glRecti'''(''x1'', ''y1'', ''x2'', ''y2'' : TGLInt); &lt;br /&gt;
 procedure '''glRects'''(''x1'', ''y1'', ''x2'', ''y2'' : TGLShort); &lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! ''x1, y1''&lt;br /&gt;
| Beschreibt die Position eines Vertex des Rechtecks.&lt;br /&gt;
|-&lt;br /&gt;
! ''x2, y2''&lt;br /&gt;
| Beschreibt die Position des gegenüberliegenden Vertex des Rechtecks.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glRectdv'''(consts ''v1'',''v2'' : PGLDouble);&lt;br /&gt;
 procedure '''glRectfv'''(consts ''v1'',''v2'' : PGLFloat);&lt;br /&gt;
 procedure '''glRectiv'''(consts ''v1'',''v2'' : PGLInt);&lt;br /&gt;
 procedure '''glRectsv'''(consts ''v1'',''v2'' : PGLShort);&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! ''v1''&lt;br /&gt;
| Beschreibt einen Zeiger zu einem Vertex eines Rechteckes.&lt;br /&gt;
|-&lt;br /&gt;
! ''v2''&lt;br /&gt;
| Beschreibt einen Zeiger zum gegenüberliegenden Vertex des Rechteckes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Mit '''glRect''' kann man leicht ein Rechteck konstruieren, in dem man einen Eckpunkt und den gegenüberliegenden Eckpunkt definiert. Jeder Rechteck-Befehl benötigt vier Argumente, entweder organisiert als zwei aufeinanderfolgende Paare von (x,y) Koordinaten oder als zwei Zeiger auf Arrays, die jeweils ein (x,y)-Paar enthalten. Das daraus resultierende Rechteck hat einen z-Wert von 0.&lt;br /&gt;
&lt;br /&gt;
'''glRect'''(x1, y1, x2, y2) entspricht exakt der folgenden Anweisung:&lt;br /&gt;
&lt;br /&gt;
   glBegin(GL_POLYGON);&lt;br /&gt;
     glVertex2(x1, y1);&lt;br /&gt;
     glVertex2(x2, y1);&lt;br /&gt;
     glVertex2(x2, y2);&lt;br /&gt;
     glVertex2(x1, y2);&lt;br /&gt;
   glEnd;&lt;br /&gt;
&lt;br /&gt;
Bitte beachtet, dass wenn das zweite Vertex über und rechts von dem ersten Vertex ist, dieses gegen den Uhrzeigersinn konstruiert wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn '''glRect''' innerhalb eines [[glBegin]]-[[glEnd]] Blocks aufgerufen wird.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glBegin]], [[glVertex]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|Rect]]&lt;br /&gt;
 [[Kategorie:GL1.0]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25669</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25669"/>
				<updated>2012-04-21T11:03:31Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Standardfunktionen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Einleitung=&lt;br /&gt;
Hallo und willkommen bei meiner &amp;quot;Einführung&amp;quot; in GLSL (kurz für &amp;quot;Open'''GL''' '''S'''hading '''L'''anguage&amp;quot;), der offiziellen Hochlevel-Shadersprache von OpenGL. In diesem umfangreichen Dokument werde ich versuchen, sowohl auf die Nutzung (sprich das Laden und Anhängen von Shadern im Quellcode), als auch auf die Programmierung von Shadern selbst einzugehen, inklusive aller Sprachelemente der OpenGL Shadersprache. Es wird also auch recht viele Informationen zu der C-ähnlichen Programmstruktur und den von GLSL angebotenen Variablen und Attributen gehen. Am Ende dieser Einführung sollten alle die, die sich für das Thema interessieren, in der Lage sein, zumindest einfach Shader zu schreiben und auch in ihren Programmen zu nutzen. Außerdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von Khronoes veröffentlichten Shaderspezifikationen, und damit als alltägliches Nachschlagewerk, dienen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Wie auch schon mein ARB_VP-Tutorial richtet sich auch diese Einführung aufgrund ihrer Thematik eher an die fortgeschritteneren GL-Programmierer und neben sehr guten GL-Kenntnissen sollten sich alle, die sich daran versuchen wollen, mit den technischen Hintergründen der GL, wie z.B. dem Aufbau der Renderpipeline auskennen. Weiterhin sind C-Kenntnisse absolut erforderlich, da die Shader ja in einer an ANSI-C angelehnten Syntax geschrieben werden. Auch Begriffsdefinitionen zu Vertex oder Fragment werden zum Verständis dieser Einführung benötigt. Wer also noch am Anfang seiner GL-Karriere steht, dem wird dieses Dokument nicht viel nützen. Ganz nebenbei solltet ihr auch noch eine gehörige Portion Zeit (am besten nen kompletten Nachmittag) mitbringen, denn die folgende Kost ist nicht nur umfangreich, sondern auch manchmal recht schwer verdaulich.&lt;br /&gt;
&lt;br /&gt;
=Was ist GLSL?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei GLSL um eine Shadersprache, also um eine Hochsprache, in der man die programmierbaren Teile aktueller Grafikbeschleuniger nach eigenem Belieben programmieren kann. Sie stellt quasi den Nachfolger zu den in Assembler geschriebenen Vertex- und Fragmentprogrammen ([[GL_ARB_vertex_program]]/[[GL_ARB_fragment_program]]) dar und basiert auf ANSI C, erweitert um Vektor- und Matrixtypen sowie einige C++-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
Die in GLSL geschriebenen Programme nennen sich, angepasst an die Terminologie von RenderMan und DirectX, [[Shader]] (im Gegensatz zu &amp;quot;Programme&amp;quot; bei ARB_VP/FP) und werden entweder auf Eckpunkte (VertexShader), Fragmente (FragmentShader) angewendet, oder (neuerdings, ab Shadermodell 4.0) auch genutzt um Geometrie zu erstellen (Geometryshader). Andere Teile der Renderpipeline (z.B. die Rasterisierung) können momentan noch nicht durch Shader beeinflusst werden, was allerdings in Zukunft noch kommen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
GLSL wurde 2005 mit OpenGL 1.5 eingeführt. Während es in Sachen Treiber- und Hardwareunterstützung anfänglich noch dürftig aussah, wird man inzwischen keine Grafikkarte mehr kaufen können die nicht zumindest Vertex- und Fragmentshader beherscht. Geometrieshader hingegen sind relativ neu und wurden erst mit Shadermodell 4.0 eingeführt, hier ist es also unter Umständen noch möglich dass selbst aktuelle Treiber/Karten keine Geometrieshader beherrschen.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt man auch einen passenden OpenGL-Header der die für GLSL nötigen Funktionen exportiert. Ich verweise dazu auf unseren eigenen OpenGL-Header [[DGLOpenGL.pas]], der peermanent auf dem aktuellsten Stand gehalten wird und auch Support für Geometrieshader mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
&lt;br /&gt;
Die GL-Shadersprache &amp;quot;besteht&amp;quot; in ihrer aktuellen Version aus folgenden Extensions, fürs Verständnis wäre es nicht schlecht, wenn ihr euch zumindest die Einleitungen dazu durchlest :&lt;br /&gt;
* [[GL_ARB_shader_objects]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shader_objects.txt Originalspezifikation])&lt;br /&gt;
: Definiert die API-Aufrufe, die zum Erstellen, Kompilieren, Linken, Anhängen und Aktivieren von Shader- und Programmobjekten nötig sind. &lt;br /&gt;
* [[GL_ARB_vertex_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Vertexebene hinzu. &lt;br /&gt;
* [[GL_ARB_fragment_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Fragmentebene hinzu. &lt;br /&gt;
* [[GL_ARB_shading_language_100]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shading_language_100.txt Originalspezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis''' : Seit OpenGL 2.0 ist GLSL Teil des Kerns. Wenn die Karte also OpenGL 2.0 unterstützt, dann unterstützt sie auch (zumindest in Software) Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sprachversionen==&lt;br /&gt;
&lt;br /&gt;
Neben der OpenGL-Version und dem vorhandenen Shadermodell (das eher an DirectX ausgerichtet ist), bietet auch GLSL verschiedene Versionen, die entsprechend erweiterte Funktionalität bieten.&lt;br /&gt;
&lt;br /&gt;
Auslesen kann man die verfürgbare GLSL-Version wie folgt:&lt;br /&gt;
&lt;br /&gt;
 glGetString(GL_SHADING_LANGUAGE_VERSION)&lt;br /&gt;
&lt;br /&gt;
Erst ab Version 1.4. kann man davon ausgehen dass GLSL alle Features des Shadermodells 4.0 liefert, ab 1.3 grob gesagt Shadermodell 3.0 (bei GLSL lässt sich das leider nicht so leicht unterteilen).&lt;br /&gt;
&lt;br /&gt;
Außerdem kann man seinem Shader eine Versionsnummer verpassen. Sollte der Shadercompiler (also Treiber bzw. Hardware) diese Version nicht unterstützen, gibt dieser eine Fehlermeldung heraus:&lt;br /&gt;
&lt;br /&gt;
 #version 1.50 &lt;br /&gt;
&lt;br /&gt;
''(Hinweis: Muss am Anfang des Shaders stehen)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&lt;br /&gt;
&lt;br /&gt;
Im Zuge der Vereinheitlichung der GL wird immer häufiger in Objekte gekapselt, deren API dann auch aneinander angelehnt ist. Ziel ist, dabei die Programmierung der GL uniform zu machen, so dass z.B. zwischen dem Erstellen und Verwalten eines Vertex-Buffer-Objektes oder eines Shader-Objektes kaum ein Unterschied besteht (demnächst kommen dann auch Pixel-Buffer-Objekte dazu). Mit glSlang wurden dann im Zuge dieser Aktion zwei neue Objekte eingeführt, deren Definition ihr euch unbedingt einprägen solltet:&lt;br /&gt;
&lt;br /&gt;
* '''Programmobjekt'''&lt;br /&gt;
:Ein Objekt, an das die Shader später angebunden werden. Bietet Funktionalität zum Linken der Shader und prüft dabei die Kompatibilität zwischen Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
* '''Shaderobjekt'''&lt;br /&gt;
:Dieses Objekt verwaltet den Quellcodestring eines Shaders und ist entweder vom Typ '''GL_VERTEX_SHADER''', '''GL_FRAGMENT_SHADER_ARB''' oder '''GL_GEOMETRY_SHADER'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
&lt;br /&gt;
Die Shadersprache ist keinesfalls final und es wurden bereits diverse Ausdrücke für zukünftige Verwendung reserviert, denn ein Ziel bei ihrer Entwicklung war es, sie so zukunftsorientiert zu gestalten, dass auch Grafikkarten der nächsten und übernächsten Generation voll ausgenutzt werden können. Damit einher geht die Tatsache, dass sich die Spezifikationen in Zukunft ändern/erweitern werden, weshalb man da immer einen Blick hineinwerfen sollte. Die Anlaufstelle dafür ist die [http://www.opengl.org/documentation/specs/ Spezifikationenliste auf OpenGL.org].&lt;br /&gt;
&lt;br /&gt;
=GLSL im Programm=&lt;br /&gt;
Bevor wir uns mit der Syntax von glSlang beschäftigen, zeige ich euch erstmal, wie ihr Shader in euer Programm einbindet und nutzt. Warum das zuerst? Ganz einfach deshalb, weil ihr dann das, was ihr im glSlang-Syntaxteil lernt, direkt in eurer Testanwendung verwenden könnt. Hoffe diese Entscheidung klingt logisch und findet Anklang.&lt;br /&gt;
&lt;br /&gt;
Zuerst benötigen wir natürlich unsere Objekte. Zum einen ein ''Programmobjekt'', an das unsere Shader gebunden werden, und zwei ''Shaderobjekte'', die den Quellcode unseres Vertex bzw. Fragment Shaders aufnehmen. Dazu wurde eigens der neue &amp;quot;Datentyp&amp;quot; {{INLINE_CODE|glHandle}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandle;&lt;br /&gt;
 VertexShaderObject   : GLhandle;&lt;br /&gt;
 FragmentShaderObject : GLhandle;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dieser Deklaration können wir dann damit beginnen unsere Objekte zu erstellen. Den Anfang macht das Programmobjekt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        := glCreateProgram;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgram]] erstellt uns oben ein leeres Programmobjekt und gibt ein gültiges Handle darauf zurück.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Erstellung unseres Vertex bzw. Fragment Shaders :&lt;br /&gt;
&lt;br /&gt;
 VertexShaderObject   := glCreateShader(GL_VERTEX_SHADER);&lt;br /&gt;
 FragmentShaderObject := glCreateShader(GL_FRAGMENT_SHADER);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShader]] dient zur Generierung eines leeren Shaderobjektes. Momentan unterstützt diese Funktion VertexShader und FragmentShader.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun also zwei gültige Shaderobjekte haben, wollen wir diese auch mit entsprechendem Quellcode versorgen :&lt;br /&gt;
&lt;br /&gt;
 glShaderSource(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSource(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSource]] setzen wir den Quellcode eines Shaderobjektes ''komplett'' neu. Zum Laden des Quellcodes bietet sich unter Delphi übrigens eine TStringList geradezu an. Es sollte beachtet werden, dass der Quellcode zu diesem Zeitpunkt ''nicht geparst'' wird, also keine Fehleruntersuchung stattfindet.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode wurde jetzt also an unsere Shaderobjekte gebunden und sollte dann natürlich auch noch kompiliert werden :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 glCompileShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShader]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der Shadercompiler (je nach Treiber) recht detaillierte Infos aus. Wie man an diese Infos kommt könnt ihr gleich nachlesen.&lt;br /&gt;
&lt;br /&gt;
Wenn unsere Shader dann kompiliert werden konnten, ist es Zeit, diese an unser anfangs erstelltes Programmobjekt anzuhängen :&lt;br /&gt;
&lt;br /&gt;
 glAttachShader(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachShader(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehängt wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteShader(VertexShaderObject);&lt;br /&gt;
 glDeleteShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Schluß müssen wir dann noch unsere ans Programmobjekt gebundenen Shader linken :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShader]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgram]] die angehangenen Shader zu einem ausführbaren Shader gelinkt. Folgende Bedingungen führen zu einem '''Linkerfehler''':&lt;br /&gt;
&lt;br /&gt;
* Die Zahl der von der Implementation unterstützten Attributvariablen wurde überschritten&lt;br /&gt;
* Der Speicherplatz für Uniformvariablen wurde überschritten&lt;br /&gt;
* Die Zahl der von der Implementation angebotenen Sampler wurde überschritten&lt;br /&gt;
* Die main-Funktion fehlt&lt;br /&gt;
* Die Liste der Varying-Variablen des Vertexshaders stimmt nicht mit der des Fragmentshaders überein&lt;br /&gt;
* Funktions- oder Variablenname nicht gefunden&lt;br /&gt;
* Eine gemeinsame Globale ist mit unterschiedlichen Werten oder Typen initialisiert worden&lt;br /&gt;
* Zwei Sampler unterschiedlichen Typs zeigen auf die selbe Textureneinheit&lt;br /&gt;
* Ein oder mehrere angehangene(r) Shader wurden nicht erfolgreich kompiliert&lt;br /&gt;
&lt;br /&gt;
Die Nutzung von glSlang im eigenen Programm ist wie oben erkennbar also nicht wirklich schwer und innerhalb kurzer Zeit realisiert. Natürlich ist es auch möglich z.B. nur einen VertexShader oder nur einen FragmentShader an ein Programmobjekt zu binden.&lt;br /&gt;
&lt;br /&gt;
Noch eine kleine Notiz zum Löschen der Shader mittel [[glDeleteShader]] : Da Shader(objekte) einen Referenzzähler besitzen und erst gelöscht werden wenn diese nirgendwo mehr benötigt werden, ist es nicht falsch diese vor dem Linkvorgang zu löschen. Allerdings spielt es letztendlich keine Rolle ob die Löschanweisung vorher der nachher ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fehlererkennung==&lt;br /&gt;
Natürlich wird es ohne Fehlerausgabe recht schwer, etwaige Probleme in einem Vertex- oder Fragmentshader zu finden. Doch auch in diesem Bereich wurde glSlang recht gut durchdacht und es wurden zwei Funktionen eingeführt, welche im Zusammenspiel die Fehlersuche recht einfach machen, nämlich [[glGetShaderInfoLog]] und [[glGetShader]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH}}. Erstere Funktion liefert uns einen Logstring, während uns letztere Funktion dessen Länge angibt. Der Logstring wird verändert, sobald ein Shader kompiliert oder ein Programm gelinkt wird.&lt;br /&gt;
&lt;br /&gt;
Um die Ausgabe dieses Logs so einfach wie möglich zu machen, bietet es sich an beide in einer einfach Funktion unterzubringen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function glSlang_GetInfoLog(pShader: GLHandleARB): String;&lt;br /&gt;
var&lt;br /&gt;
  blen, slen: GLInt;&lt;br /&gt;
  InfoLog: PGLCharARB;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  glGetShaderiv(glObject, GL_INFO_LOG_LENGTH , @blen);&lt;br /&gt;
  if blen &amp;gt; 1 then&lt;br /&gt;
  begin&lt;br /&gt;
    GetMem(InfoLog, blen * SizeOf(GLCharARB));&lt;br /&gt;
    glGetShaderInfoLog(pShader, blen, slen, InfoLog);&lt;br /&gt;
    Result := PChar(InfoLog);&lt;br /&gt;
    Dispose(InfoLog);&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist recht leicht erklärt : Zuerst lassen wir uns über {{INLINE_CODE|glGetShaderiv}} mitteilen wie lang der aktuelle Infolog ist. Sollte dort tatsächlich etwas drinstehen (blen &amp;gt; 1), dann lassen wir uns dessen Inhalt via {{INLINE_CODE|glGetShaderInfoLog}} in {{INLINE_CODE|InfoLog}} ausgeben und liefern diesen als Ergebnis zurück.&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt wird nur nach dem Kompilieren eines Shaders bzw. dem Linken eines Programmobjektes ein Infolog erstellt. Es bietet sich dadurch an, direkt danach einen solchen Aufruf zu machen :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 ShowMessage(glSlang_GetInfoLog(VertexShaderObject));&lt;br /&gt;
&lt;br /&gt;
Wenn unser Vertex Shader komplett fehlerfrei kompiliert werden konnte, dann sehen wir als Ergebnis nur einen leeren Dialog. Ist dies nicht der Fall, so werden wir vom Treiber mit recht detaillierten Fehlerinformationen &amp;quot;belohnt&amp;quot;, z.B. so :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL_error_vshader.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch das Infolog nach dem Linken des Programmobjektes dürfte, selbst wenn keine Fehler vorkommen, recht interessant sein, das sieht dann nämlich so aus :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL info programobject.jpg]]&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen, wird uns nach dem erfolgreichen Linken auch gesagt, ob und welcher Shader in Hardware bzw. Software läuft. Für Debuggingzwecke sicherlich eine mehr als brauchbare Information.&lt;br /&gt;
&lt;br /&gt;
==Shader benutzen==&lt;br /&gt;
Um den Shader auch für die nächsten Polygone zu benutzen oder Uniformparameter übergeben zu können, ruft man die Funktion&lt;br /&gt;
 glUseProgramt(ProgramObject);&lt;br /&gt;
um alle Shader zu deaktivieren, ruft man dieselbe Funktion mit dem Parameter 0.&lt;br /&gt;
&lt;br /&gt;
==Parameterübergabe==&lt;br /&gt;
Uniformparameter (mehr dazu später) stellen die Schnittstelle zwischen eurem Programm und dem Shader dar, werden also genutzt um Daten aus dem Programm heraus an einen Shader zu übergeben. Zur Übergabe dieser Parameter bietet OpenGL diverse Funktionen, die alle Abkömmlinge von [[glUniform]] sind. Während mit {{INLINE_CODE|glUniform4f}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fv}} ganze Matrizen schnell und einfach übergeben. Außerdem gibt es nun die Möglichkeit Uniformparameter direkt über ihren Namen, statt wie unter ARB_FP/VP über einen festen Index zu adressieren. Die Funktion [[glGetUniformLocationARB]] gibt anhand des übergebenen Parameternamens dessen Position zurück. Man kann also ganz einfach über den Namen drauf zugreifen :&lt;br /&gt;
&lt;br /&gt;
 glUniform3f(glGetUniformLocation(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1i(glGetUniformLocation(ProgramObject, PGLCharARB('texSamplerTMU3')), 3);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier, das man je nach Parametertyp auch die passende Anzahl von Argumenten übergibt. Also für einen 4-Komponenten Floatvektor {{INLINE_CODE|glUniform4fARB}} und für einen einfachen Integerwert (z.B. Textureinheit für einen Sampler) glUnifrom1iARB. Auch nicht vergessen dürft ihr, das die Namen der Parameter genauso wie im Shader geschrieben werden müssen, also Groß- und Kleinschreibung beachtet werden muß.&lt;br /&gt;
&lt;br /&gt;
=Die Shadersprache=&lt;br /&gt;
&lt;br /&gt;
Nachdem wir uns mit der Einbindung der glSlang-Shader in unser Programm beschäftigt haben, wollen wir uns in den folgenden Kapiteln um die Sprachelemente von glSlang kümmern. Wie schon gesagt basiert glSlang auf ANSI-C, wurde allerdings um speziell auf den Zielbereich angepasste Vektor- und Matrixtypen und einige C++-Features wie das freie deklarieren von Variablen an jeder Stelle und das Funktionsüberladen auf Basis des Argumenttyps erweitert. Wer sich ein wenig mit C/C++ auskennt sollte also in der nun folgenden Materie keine Probleme bekommen.&lt;br /&gt;
&lt;br /&gt;
'''Obligatorische Hinweise für verwöhnte Delphi-Nutzer : '''&lt;br /&gt;
*Wie von C/C++ her gewohnt, spielt auch in glSlang die Groß- und Kleinschreibung eine wichtige Rolle, also bitte achtet darauf. gl_Position ist eine komplett andere Variable als z.B. gl_position.&lt;br /&gt;
*Es findet keine automatische Typenkonvertierung statt. Das bedeutet also das float MyFloat = 1 ungültig ist und es in dem Falle float MyFloat = 1.0 heissen muss. Typecasts müssen also immer manuell stattfinden, z.B. MyFloat = float(MyInt).&lt;br /&gt;
&lt;br /&gt;
'''Kleine Programmstrukturkunde für C-Unkundige :'''&amp;lt;br&amp;gt;&lt;br /&gt;
Da sicherlich einige Delpher nie richtig was mit C gemacht haben, zeige ich mal anhand eines kleinen Beispieles (das auf keinen Fall nen brauchbaren Shader darstellt) den grundlegenden Aufbau eines glSlang-Shaders, der natürlich dem Aufbau eines C-Programmes stark ähnelt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 VariableA;&lt;br /&gt;
float VariableB;&lt;br /&gt;
vec3  VariableC;&lt;br /&gt;
const float KonstanteA = 256.0;&lt;br /&gt;
&lt;br /&gt;
float MyFunction(vec4 ArgumentA)&lt;br /&gt;
{&lt;br /&gt;
    float FunktionsVariableA = float(5.0);&lt;br /&gt;
&lt;br /&gt;
    return float(ArgumentA * (FunktionsVariableA + KonstanteA));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Ich bin ein Kommentar&lt;br /&gt;
/* Und ich auch */&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
    gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht doch recht bekannt aus, unser Programmaufbau. Delphi und C haben ja so einige Grundlagen gleich, darunter auch der ungefähre Programmaufbau. Ausserhalb jeglicher Funktionen legen wir am Programmanfang unsere Variablen, Konstanten und Attribute fest, die dann ''global'' nutzbar sind, also in jeder Funktion.&lt;br /&gt;
&lt;br /&gt;
Darunter deklarieren wir dann eine kleine Funktion. Wie auch bei den Variablendeklarationen wird hier der Rückgabetyp nicht wie bei Pascal nach dem Funktionsnamen untergebracht, sondern davor. Innerhalb der Funktion können dann wieder Variablen deklariert werden, die dann allerdings ''lokal'', also nur in dieser Funktion nutzbar sind. Vorteil dieser Deklaration ist die Tatsache, dass je nach Grafikkarte nur bestimmt viele globale Variablen deklariert werden können. Wenn möglich sollte man also mit lokalen Vorlieb nehmen. Unsere Funktion gibt dann natürlich noch via return einen Wert zurück, ''was gemacht werden muss'', sofern man diese nicht als void deklariert hat (entspräche dann einer Prozedur in Pascal). Wird dies nicht getan, so spuckt der Compiler einen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Auch wichtig sind natürlich Kommentare. Erste Variante (Doppelslash) ist auch in der Pascalwelt verfügbar und kommentiert eine einzelne Zeile aus. Die Variante darunter kann man für Kommentarblöcke nutzen (/* .. */) und entspricht den Kommentaren in geschweiften Klammern in Delphi.&lt;br /&gt;
&lt;br /&gt;
Danach kommt dann die '''wichtigste Funktion''' des Shaders, nämlich '''main''', die in keinem Shader fehlen darf. Sie stellt quasi den Programmkörper dar und ist oft auch die einzige Funktion in einem Shader. Sie erhält weder ein Argument, noch gibt sie einen Wert zurück.&lt;br /&gt;
&lt;br /&gt;
Soviel also zum grundlegenden Aufbau eines Shader. Hoffe das jetzt alle die in C nicht so bewandert sind damit klar kommen, und dann bald ihre ersten glSlang-Shader schreiben können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Datentypen==&lt;br /&gt;
&lt;br /&gt;
Obwohl einige Datentypen aus C übernommen wurden, sieht man der Typenliste an, das diese speziell auf den 3D-Bereich zugeschnitten wurde. Variablen müssen vor ihrer Nutzung eindeutig deklariert sein, Typecasting erfolgt über Konstruktoren (dazu später mehr). Folgende Datentypen stehen sowohl im Vertex- als auch Fragmentshader zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|void 	&lt;br /&gt;
|Für Funktionen die keinen Wert zurückgeben&lt;br /&gt;
|-&lt;br /&gt;
|bool 	&lt;br /&gt;
|Konditionaler Typ, entweder true (wahr) oder false (falsch)&lt;br /&gt;
|-&lt;br /&gt;
|int 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenbehafteter Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|uint 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenloser Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|float 	&lt;br /&gt;
|Fließkommaskalar mit Singlegenauigkeit (32 Bit)&lt;br /&gt;
|-&lt;br /&gt;
|vec2 	&lt;br /&gt;
|2-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec3 	&lt;br /&gt;
|3-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec4 	&lt;br /&gt;
|4-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec2 	&lt;br /&gt;
|2-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec3 	&lt;br /&gt;
|3-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec4 	&lt;br /&gt;
|4-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec2 	&lt;br /&gt;
|2-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec2 	&lt;br /&gt;
|2-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec3 	&lt;br /&gt;
|3-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec4 	&lt;br /&gt;
|4-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|mat2 	&lt;br /&gt;
|2x2 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat3 	&lt;br /&gt;
|3x3 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat4 	&lt;br /&gt;
|4x4 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|matMxN 	&lt;br /&gt;
|Matrix mit M Spalten und N Zeilen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse zum Zugriff auf Texturen dar, und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|sampler1D 	&lt;br /&gt;
|Zugriff auf 1D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler2D 	&lt;br /&gt;
|Zugriff auf 2D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler3D 	&lt;br /&gt;
|Zugriff auf 3D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|samplerCube 	&lt;br /&gt;
|Zugriff auf Cubemap&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRect 	&lt;br /&gt;
|Zugriff auf Texturen die nicht 2^n * 2^n entsprechen (&amp;quot;non power-of-two&amp;quot;, NPOT)&lt;br /&gt;
|-&lt;br /&gt;
|sampler1DShadow 	&lt;br /&gt;
|Zugriff auf 1D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DShadow 	&lt;br /&gt;
|Zugriff auf 2D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|samplerCubeShadow&lt;br /&gt;
|Zugriff auf Tiefentextur in einer Cubemap (z.b. für omni-diretionale Lichtquellen)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRectShadow&lt;br /&gt;
|Zugriff auf 2D-NPOT-Tiefentextur &lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|sampler1DArray&lt;br /&gt;
|Zugriff auf ein array aus 1D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArray&lt;br /&gt;
|Zugriff auf ein array aus 2D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler1DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 1D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 2D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|samplerBuffer&lt;br /&gt;
|Zugriff auf eine Puffertextur (1D-Texutr zum Speichern von Pufferobjekten)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMS&lt;br /&gt;
|Zugriff auf eine 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMSArray&lt;br /&gt;
|Zugriff auf einarray aus 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Arrays===&lt;br /&gt;
&lt;br /&gt;
Natürlich unterstützt glSlang auch Arrays, die wie in C deklariert werden und deren Index bei 0 beginnt. Folgendes Array im Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
beginnt also bei Index 0 und endet bei Index 2. Im Gegensatz zu C lassen sich Arrays in glSlang allerdings ''nicht bei der Initialisierung vorbelegen''. Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strukturen===&lt;br /&gt;
&lt;br /&gt;
Neu ggü. ARB_FP/VP ist nun auch die Möglichkeit, Strukturen in einem Shader zu deklarieren. Vor allem die Übersicht komplexerer Shader kann dadurch stark verbessert werden. Strukturen werden wie gewohnt mit dem Schlüsselwort {{INLINE_CODE|struct}} eingeleitet und können dann zur Typisierung von Variablen genutzt werden. Folgendes Beispiel dürfte die Nutzung verdeutlichen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct light&lt;br /&gt;
{&lt;br /&gt;
    bool active;&lt;br /&gt;
    float intensity;&lt;br /&gt;
    vec3 position;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
LightSource[i].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Typenqualifzierer==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur Typendeklaration kann eine Variable noch einen Typenqualifizerer vorangestellt bekommen, der an den Anfang der Deklaration gehört.&lt;br /&gt;
&lt;br /&gt;
* '''const'''&lt;br /&gt;
: Festgelegte (nur lesen) Konstante bzw. nur lesbarer Funktionsparameter.&lt;br /&gt;
&lt;br /&gt;
* '''uniform'''&lt;br /&gt;
: Ein den ganzen Shader über gleichbleibender Wert, der eine Schnittstelle zwischen dem Shader und der OpenGL-Anwendung darstellt. Ein Uniformwert wird in der Hauptanwendung an den entsprechenden Shader übergeben und kann dort dann genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* '''attribute'''&lt;br /&gt;
: Nur lesbare Werte die eine Verbindung zwischen dem Shader und der OpenGL-VertexAPI darstellen (z.B. VertexParameter eines VertexArrays). Natürlich nur in einem Vertex Shader nutzbar.&lt;br /&gt;
&lt;br /&gt;
* '''varying'''&lt;br /&gt;
: Stellt die Verbindung zwischen einem Vertex- und einem FragmentShader dar. Werden im VertexShader geschrieben und dann perspektivisch korrekt über die Primitive interpoliert, um dann im Fragment Shader gelesen werden zu können. Nutzbar sind hier nur die Typen float, vec2, vec3, vec4, mat2, mat3 und mat4, Strukturen und andere Datentypen können nicht varying sein. Die Namen einer varying-Variable müssen sowohl im VertexShader als auch im FragmentShader gleich sein.&lt;br /&gt;
&lt;br /&gt;
* '''in'''&lt;br /&gt;
: Für Variablen die an eine Funktion übergeben und dort ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* '''out'''&lt;br /&gt;
: Für Variablen die von einer Funktion nach außen zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
* '''inout'''&lt;br /&gt;
: Für Variablen die sowohl an eine Funktion übergeben als auch von dieser zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um obige Auflistung nicht leer im Raum stehen zu lassen zeige ich ein paar Beispiele die hoffentlich zum Verständnis beitragen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Vertexnormale soll an einen FragmenShader (interpoliert) übergeben werden :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
VertexNormal = normalize(MV_IT * gl_Normal);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Uniformparameter zur nachträglichen Farbänderung der Szene wird im Programm übergeben :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im Programm :&lt;br /&gt;
&lt;br /&gt;
 glUniform4fARB(glSlang_GetUniLoc(ProgramObject, 'GlobalColor'), Col[0], Col[1], Col[2], Col[3]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Beispiel C=== &lt;br /&gt;
Konstante zur festen Farbänderung :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
const vec4 ColorBias = vec4(0.2, 0.3, 0.0, 0.0);&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = ColorBias * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Konstruktoren==&lt;br /&gt;
&lt;br /&gt;
Um in einem Shader ''Vektoren'' oder ''Matrizen'' mit Werten zu belegen, gibt es sogenannte Konstruktoren (nicht zu verwechseln mit z.B. Klassenkonstruktoren unter Delphi), die im Endeffekt nichts anderes als Funktionen zur Vorbelegung von Vektoren oder Matrizen darstellen. Dabei trägt der Konstruktor den selben Namen wie die Typendeklaration, also lässt sich eine Variable vom Typ {{INLINE_CODE|vec4}} mit dem Konstruktor {{INLINE_CODE|vec4(float, float, float, float)}} initialisieren.&lt;br /&gt;
&lt;br /&gt;
Allerdings hat man sich recht viel Mühe bei dieser Konstruktorgeschichte gemacht, so dass man einen vec4 nicht unbedingt mit einem {{INLINE_CODE|vec4}}-Konstruktor vorbelegen muss, sondern es vielseitige Möglichkeiten gibt. Um dies zu verdeutlichen gibts ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(1.0, 0.0, 0.0, 0.0);&lt;br /&gt;
vec4 Color = vec4(MyVec3, 1.0);&lt;br /&gt;
vec4 Color = vec4(MyVec2_A, MyVec2_B);&lt;br /&gt;
&lt;br /&gt;
vec3 LVec  = vec3(MyVec4);&lt;br /&gt;
vec2 Tmp   = vec2(MyVec3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trotz der recht wenigen Beispiele sollte schnell erkennbar sein, das man hier wirklich sehr viele Kombinationsmöglichkeiten hat, die dann gültig sind ''wenn man mindestens auf die benötigte Anzahl der Argumente kommt''. Im vorletzten Beispiel wird z.B. ein 3-Komponentenvektor aus einem 4-Komponentenvektor initialisiert. Das erzeugt keinen Fehler, sondern führt dazu das {{INLINE_CODE|vec3.x, vec3.y, vec3.z}} aus MyVec4 übernommen werden und MyVec4.w einfach ignoriert wird.&lt;br /&gt;
&lt;br /&gt;
Das Umkehrbeispiel, also&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
funktioniert allerdings nicht, da hier die Zahl der benötigten Argumente nicht erreicht wird. In diesem Falle müsste es dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
heissen.&lt;br /&gt;
&lt;br /&gt;
Obiges gilt natürlich auch für ''Matrixkonstruktoren'', hier sind z.B. folgende Konstuktoren denkbar, obwohl eigentlich alle Möglichkeiten nutzbar sind, ''solange die benötigte Zahl an Argumenten erreicht wird'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
mat4 MyMatrix = mat4(MyVec4, MyVec4, MyVec4, MyVec4);&lt;br /&gt;
mat2 MyMatrix = mat4(1.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 1.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 1.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixkomponenten==&lt;br /&gt;
&lt;br /&gt;
Was natürlich in keiner Shadersprache fehlen darf, ist der leichte Zugriff auf die einzelnen Komponenten eines Vektors. glSlang bietet, je nach Anwendungsgebiet gleich drei Namensets für den Zugriff auf die Komponenten eines solchen Vektors, welches Set man nutzen will bleibt natürlich frei und ist unabhängig von der Deklaration eines Vektors. Man sollte nur darauf achten, beim gleichzeitigen Zugriff auf mehrere Komponenten im gleichen Namenset zu verbleiben :&lt;br /&gt;
&lt;br /&gt;
* {x, y, z, w}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Punkte, Normale oder sonstige Vertexdaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {r, g, b, a}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Farbwerte repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {s, t, p, q}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Texturkoordinaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
Ein paar Beispiele zur Unterstreichung des oben gesagten :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
v4.rgba = vec4(1.0, 0.0, 0.0, 0.0);  // gültig&lt;br /&gt;
v4.rgzw = vec4(1.0, 1.0, 1.0, 2.0);  // Ungültig, da verschiedenen Namensets&lt;br /&gt;
v2.rgb  = vec3(1.0, 2.0, 1.0);       // Ungültig, da vec2 nur r+g besitzt&lt;br /&gt;
v2.xx   = vec2(5.0, 3.0);            // Ungültig, da 2 mal gleiche Komponente&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch der Zugriff auf die Komponenten einer Matrix geht leicht von der Hand. Namensets wie bei den Vektoren gibt es hier natürlich keine, aber folgende Beispiele sollen den Zugriff aufzeigen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
MyMat4[2]    = vec4(1.0); // Setzt die 3.Zeile der Matrix komplett auf 1.0&lt;br /&gt;
MyMat4[3][3] = 3.5;       // Setzt das Element unren rechts auf 3.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Matrixelemente ausserhalb ihrer Dimension (also z.B. MyMat4[4][4]) liefert unvorhersehabre Ergebnise, also sollte man auf diese Fälle prüfen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixoperationen==&lt;br /&gt;
&lt;br /&gt;
Wie von C gewohnt sind in glSlang so ziemlich alle Operatoren die man auf Matrizen oder Vektoren anwenden kann überladen, so das man nicht umständlich über selbstgeschriebene Funktionen kombinieren muss. Darüber hinaus ist es in den meisten Fällen auch möglich ohne Konvertierung Fließkommawerte mit kompletten Matrizen oder Vektoren zu kombinieren. Folgende Beispiele zeigen einige der vielfältigen Kombinationsmöglichkeiten auf :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
float factor;&lt;br /&gt;
&lt;br /&gt;
vec3 dest = source + factor; &lt;br /&gt;
&lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = source.x + factor;&lt;br /&gt;
dest.y = source.y + factor;&lt;br /&gt;
dest.z = source.z + factor;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
mat3  MyMat;&lt;br /&gt;
 &lt;br /&gt;
dest = source * MyMat; &lt;br /&gt;
 &lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = dot(source, MyMat[0]);&lt;br /&gt;
dest.y = dot(source, MyMat[1]);&lt;br /&gt;
dest.z = dot(source, MyMat[2]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier sind die Möglichkeiten fast unbeschränkt und zeigen wieder wie flexibel glSlang ausgelegt ist. &lt;br /&gt;
&lt;br /&gt;
==Operatoren==&lt;br /&gt;
&lt;br /&gt;
glSlang bietet (momentan) folgende Operatoren, die Liste ist nach ihrer Gewichtung sortiert (Anfang = höchste). Alle ''reservierten'' Operatoren werden erst in kommender Hardware/glSlang-Versionen nutzbar sein :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div  align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Operatorklasse  	&lt;br /&gt;
!Operatoren  	&lt;br /&gt;
!Assoziation&lt;br /&gt;
|-&lt;br /&gt;
|Gruppering 	&lt;br /&gt;
|() 	&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
|Arrayindizierung&amp;lt;br&amp;gt;Funktionsaufrufe und Konstruktoren&amp;lt;br&amp;gt;Strukturfeldwahl und Swizzle&amp;lt;br&amp;gt;Postinkrement und -dekrement&amp;lt;br&amp;gt; 	&lt;br /&gt;
|[]&amp;lt;br&amp;gt;()&amp;lt;br&amp;gt;.&amp;lt;br&amp;gt;++ -- 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Prefixinkrement- und dekrement&amp;lt;br&amp;gt;Einheitlich (~ reserviert) 	&lt;br /&gt;
| ++ --&amp;lt;br&amp;gt; + - ~ ! 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Mulitplikation (% reserviert) 	&lt;br /&gt;
|* / % 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Additiv 	&lt;br /&gt;
| + - 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises Verschieben (reserviert) 	&lt;br /&gt;
|&amp;lt;&amp;lt;  &amp;gt;&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Relation 	&lt;br /&gt;
|&amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;= 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Vergleich 	&lt;br /&gt;
|==  != 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises AND (reserviert) 	&lt;br /&gt;
|&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises XOR (reserviert) 	&lt;br /&gt;
|^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises OR (reserviert) 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches AND 	&lt;br /&gt;
|&amp;amp;&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches XOR 	&lt;br /&gt;
|^^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches OR 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Auswahl 	&lt;br /&gt;
|?: 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Zuweisung&amp;lt;br&amp;gt;Arithmetrische Zuweisung&amp;lt;br&amp;gt;(Modulis, Shift und bitweise Op. reserviert) 	&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;+= -=  *=  /=  %=&amp;lt;/nowiki&amp;gt; &amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;&amp;lt;&amp;lt;=  &amp;gt;&amp;gt;= &amp;amp;=  ^=  |=&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Aufzählung 	&lt;br /&gt;
|, 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von Hochsprachen ist u.A. die Möglichkeit oft genutzte Codeteile in Funktionen (bzw. auch Prozeduren unter Pascal) zu verpacken um so Flexibilität als auch Übersichtlichkeit zu steigern. Wer schonmal was in C geschrieben hat, der wird sich jetzt sicherlich kein Kopfzerbrechen machen müssen. Funktionen werden in glSlang genauso nach folgendem Prinzip deklariert :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
RückgabeTyp FunktionsName(Typ0 Argument0, Typ1, Argument1, ... , TypN, ArgumentN)&lt;br /&gt;
 {&lt;br /&gt;
 return RückgabeWert;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, außerdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach außen übergeben soll, muss dieses Argument mit dem Typenqualifizierer out (Siehe Kapitel 4.2) versehen werden. ''Arrays'' können nur als Eingabeargumente übergeben werden und dürfen nich dimensioniert als Argument verwendet werden, sondern müssen mit leeren Klammern argumentiert werden.&lt;br /&gt;
Ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void MeineFunktion(float EingabeWert; out float AusgabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 AusgabeWert = EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach außen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float MeineFunktion(float EingabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 return EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bietet genau die selbe Funktionalität wie das Beispiel darüber. Allerdings wird hier der berechnete Wert als Ergebnis der Funktion zurückgeliefert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float VektorSumme(float v[])&lt;br /&gt;
 {&lt;br /&gt;
 return v[0]+v[1]+v[2]+v[3];&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt darf ein Array als Argument keine Dimensionierung enthalten. Wenn man der Funktion also ein Array übergibt, sollte man vorher drauf achten das es entsprechend der in der Funktion genutzten Indizes dimensioniert wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==if-Anweisung==&lt;br /&gt;
&lt;br /&gt;
Selektion über eine if-Anweisung darf auch in keiner Hochsprache fehlen. Genauso wie in C oder Delphi erwartet auch hier die If-Anweisung einen boolschen Ausdruck (Wahr oder Falsch) und wird dann ausgeführt (wahr) bzw. verzweigt auf ein (wenn vorhanden) else (falsch). Verschachtelung ist wie erwartet auch möglich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis : ''' &lt;br /&gt;
Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten im Fragmentshader kein Early-Out, was zur Folge hat das bei einer If-Anweisung immer alle Zweige ausgeführt werden. Am Ende wird dann aber nur ein Ergebnis geschrieben, die anderen verworfen. Auf solchen Karten bringen If-Anweisungen also im Normalfall keine Geschwindigkeitssteigerung, sondern oft eher das Gegenteil.&lt;br /&gt;
Neuere SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall, da hier dynamische Verzweigungen und auch Early-Out von der Hardware implementiert werden.&lt;br /&gt;
&lt;br /&gt;
==Schleifen==&lt;br /&gt;
&lt;br /&gt;
Auch Schleifen, ein wichtiges Konzept jeder Hochsprache haben ihren Weg in glSlang gefunden. Unterstützt werden folgende Schleifentypen :&lt;br /&gt;
&lt;br /&gt;
* '''for'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
do&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
 while (Durchlaufbedingung)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hinweis :''' Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten Schleifen nicht in Hardware. Schleifen werden dann beim Kompilieren vom Treiber entrollt, wodurch natürlich Shader mit weitaus mehr Instruktionen als erwartet generiert werden. Von daher sollte man auf solchen Karten möglichst auf Schleifen verzichten, oder diese nur recht kurz halten. Bei SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Variablen, Attribute und Konstanten=&lt;br /&gt;
Nachdem wir uns nun lange genug mit den minderinterssanten Elementen der glSlang-Syntax beschäftigt haben, gehts jetzt endlich an die wirklich interessanten Dinge. Wie schon ARB_VP/ARB_FP bringt auch glSlang jede Menge eingabauter Variablen, Attribute und Konstanten mit, deren Aliase sie recht leicht identifizierbar machen (ganz im Gegensatz zum Indexgewusel bei den DX-Shadern).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Vertex Shader==&lt;br /&gt;
Exklusiv im Vertex Shader stehen die folgenden Variablen zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Position    muss geschrieben werden&lt;br /&gt;
:Dieser Variable '''muss''' im Vertexshader ein Wert zugewiesen werden, wird dies nicht getan ist das Ergebnis (sprich die Position des Vertex) undefiniert. Vorgesehen ist diese Variable für die ''homogene Position des Vertex'' und wird u.a. zum Clipping und Culling verwendet. Sie darf natürlich auch (mehrfach) geschrieben und ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* float gl_PointSize    kann geschrieben werden&lt;br /&gt;
:Diese Variable wurde dazu vorgesehen um dort im VertexShader die Punktgröße in Pixeln hineinzuschreiben.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_ClipVertex    kann geschrieben werden&lt;br /&gt;
:Falls genutzt, sollten hier die Vertexkoordinaten die im Zusammenhang mit benutzerdefinierten Clippingplanes genutzt werden abgelegt werden. Wichtig ist, das gl_ClipVertex im selben Koordinatenraum wie die Clippingplane definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Attribute im Vertex Shader==&lt;br /&gt;
&lt;br /&gt;
Folgende Attribute stehen nur im Vertex Shader zur Verfügung und '''können nur gelesen werden''' :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Color&lt;br /&gt;
: Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_SecondaryColor&lt;br /&gt;
:Sekundärer Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_Normal&lt;br /&gt;
:Normale des Vertex.&lt;br /&gt;
* vec4 gl_Vertex&lt;br /&gt;
:Koordinaten des Vertex;&lt;br /&gt;
* vec4 gl_MultiTexCoord0..7&lt;br /&gt;
:Texturkoordinaten auf Textureinheit 0..7.&lt;br /&gt;
* float gl_FogCoord&lt;br /&gt;
:Nebelkoordinate des Vertex. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Fragment Shader==&lt;br /&gt;
&lt;br /&gt;
Im Fragment Shader sind folgende Variablen exklusiv nutzbar :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragColor&lt;br /&gt;
: Speichert den Farbwert des Fragmentes, der von folgenden Funktionen der festen Pipeline genutzt wird. Wird dieser Variable nichts zugewiesen, so ist ihr Inhalt undefiniert und darauf aufbauende Ergebnisse ebenfalls.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragData[0..15]&lt;br /&gt;
: Ersetzt gl_FragColor bei der Verwendung von multiplen Rendertargets. &lt;br /&gt;
&lt;br /&gt;
* float gl_FragDepth&lt;br /&gt;
: Durch schreiben dieser Variable kann man den von der festen Funktionspipeline ermittelten Tiefenwert überspringen, der mit {{INLINE_CODE|gl_FragCoord.z}} ausgelesen werden kann. Wird dieser Wert nicht geschrieben, nutzen folgende Funktionen der Pipeline den vorher fest berechneten Wert.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragCoord    nur lesen&lt;br /&gt;
: In dieser Variable ist die Position des Fragmentes relativ zur Fensterposition im Format x,y,z,1/w abgelegt, wobei z den von der festen Funktionspipeline berechneten Tiefenwert enthält.&lt;br /&gt;
&lt;br /&gt;
* bool gl_FrontFacing    nur lesen&lt;br /&gt;
: Gibt an ob das Fragment zu einer nach vorne zeigenden Primitive gehört (=true). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bezug auf {{INLINE_CODE|gl_FragColor}} und {{INLINE_CODE|gl_FragDepth}} sei noch anzumerken das diese ''nicht'' in den Wertebereich 0..1 gebracht werden müssen, da dies später durch die feste Funktionspipeline automatisch gemacht wird.&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Varyings==&lt;br /&gt;
&lt;br /&gt;
Wie bereits in Kapitel 4.2 erwähnt, stellen Varyings eine Schnittstelle zwischen dem Vertex und dem Fragment Shader dar. Sie werden im Vertex Shader geschrieben und können dann im Fragment Shader ausgelesen werden, ohne das die folgenden Varyings dafür explizit deklariert werden müssen :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontColor&lt;br /&gt;
: Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackColor&lt;br /&gt;
: Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_TexCoord[x]&lt;br /&gt;
: Texturkoordinaten des Vertex auf Textureinheit x, wobei x die von der Hardware zur Verfügung gestellte Zahl der Textureinheiten-1 nicht überschreiten darf.&lt;br /&gt;
&lt;br /&gt;
* float gl_FogFragCoord&lt;br /&gt;
: Nebelkoordinate des Fragmentes. &lt;br /&gt;
&lt;br /&gt;
Die Varyings {{INLINE_CODE|gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor}} und {{INLINE_CODE|gl_BackSecondaryColor}} können im FragmentShader nur unter den Aliases gl_Color bzw. gl_SecondaryColor gelesen werden. Welcher Wert des Vertex Shaders im Fragment Shader dort eingesetzt wird ist abhängig davon ob das Fragment zu einer nach vorne oder nach hinten zeigenden Primitive gehört.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Konstanten==&lt;br /&gt;
Auch diverse Konstanten wurden definiert um darauf schnell im Shader zugreifen zu können. In den Klammern stehen die von einer GL-Implementation als Mindestanforderung anzubietenden Werte. Alle Konstanten sind sowohl im Vertex als auch im Fragment Shader abrufbar :&lt;br /&gt;
&lt;br /&gt;
: OpenGL 1.0/1.2 :&lt;br /&gt;
* int gl_MaxLights (8)&lt;br /&gt;
* int gl_MaxClipPlanes (6)&lt;br /&gt;
* int gl_MaxTextureUnits (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: ARB_Fragment_Program :&lt;br /&gt;
* int gl_MaxTextureCoordsARB (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Vertex_Shader :&lt;br /&gt;
* int gl_MaxVertexAttributesGL2 (16)&lt;br /&gt;
* int gl_MaxVertexUniformFloatsGL2 (512)&lt;br /&gt;
* int gl_MaxVaryingFloatsGL2 (32)&lt;br /&gt;
* int gl_MaxVertexTextureUnitsGL2 (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Fragment_Shader :&lt;br /&gt;
* int gl_MaxFragmentTextureUnitsGL2 (2)&lt;br /&gt;
* int gl_MaxFragmentUniformFloatsGL2 (64)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Uniformvariablen==&lt;br /&gt;
&lt;br /&gt;
Um den Zugriff auf OpenGL-Staten zu vereinfachen wurden in glSlang diverse Uniformvariablen zur direkten Verwendung im Shader eingebaut. Wie gewohnt wurden auch hier sinnvolle Namen verwendet, so dass eine tiefere Erklärung unnötig sein dürfte :&lt;br /&gt;
&lt;br /&gt;
* mat4 gl_ModelViewMatrix&lt;br /&gt;
* mat4 gl_ProjectionMatrix&lt;br /&gt;
* mat4 gl_ModelViewProjectionMatrix&lt;br /&gt;
* mat3 gl_NormalMatrix&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die invertierten und anschließend transponierten oberen 3x3 Werte der {{INLINE_CODE|gl_ModelViewMatrix}}.&lt;br /&gt;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
* float gl_NormalScale&lt;br /&gt;
: Gibt den unter OpenGL festgelegten Faktor zur Skalierung der Normalen zurück.&lt;br /&gt;
&lt;br /&gt;
* struct gl_DepthRangeParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_DepthRangeParameters&lt;br /&gt;
{&lt;br /&gt;
 float near;&lt;br /&gt;
 float far;&lt;br /&gt;
 float diff;&lt;br /&gt;
};&lt;br /&gt;
gl_DepthRangeParameters gl_DepthRange;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_PointParameters&lt;br /&gt;
{&lt;br /&gt;
 float size;&lt;br /&gt;
 float sizeMin;&lt;br /&gt;
 float sizeMax;&lt;br /&gt;
 float fadeThresholdSize;&lt;br /&gt;
 float distanceConstantAttenuation;&lt;br /&gt;
 float distanceLinearAttenuation;&lt;br /&gt;
 float distanceQuadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_PointParameters gl_Point;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_MaterialParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 emission;&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 float shininess;&lt;br /&gt;
};&lt;br /&gt;
gl_MaterialParameters gl_FrontMaterial;&lt;br /&gt;
gl_MaterialParameters gl_BackMaterial;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightSourceParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 vec4 position;&lt;br /&gt;
 vec4 halfVector;&lt;br /&gt;
 vec3 spotDirection;&lt;br /&gt;
 float spotExponent;&lt;br /&gt;
 float spotCutoff;&lt;br /&gt;
 float spotCosCutoff;&lt;br /&gt;
 float constantAttenuation;&lt;br /&gt;
 float linearAttenuation;&lt;br /&gt;
 float quadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_LightSourceParameters gl_LightSource[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelParameters gl_LightModel;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 sceneColor;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelProducts gl_FrontLightModelProduct;&lt;br /&gt;
gl_LightModelProducts gl_BackLightModelProduct;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
};&lt;br /&gt;
gl_LightProducts gl_FrontLightProduct[gl_MaxLights];&lt;br /&gt;
gl_LightProducts gl_BackLightProduct[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* vec4 gl_TextureEnvColor[gl_MaxFragmentTextureUnitsGL2]&lt;br /&gt;
* vec4 gl_EyePlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
*struct gl_FogParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_FogParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 color;&lt;br /&gt;
 float density;&lt;br /&gt;
 float start;&lt;br /&gt;
 float end;&lt;br /&gt;
 float scale;&lt;br /&gt;
};&lt;br /&gt;
gl_FogParameters gl_Fog;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese recht umfangreiche GL-Stateliste sollte eigentlich jeden Bedarf decken und momentan gibts kaum einen OpenGL-Status den man so nicht in einem Shader abfragen bzw. nutzen kann.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Funktionen=&lt;br /&gt;
glSlang ist mit diversen Skalar- und Vektorfunktionen ausgestattet, die teilweise (idealerweise) sogar direkt in der Hardware ausgeführt werden, weshalb einer fertigen Funktion ggü. gleichwertigen eigenen Berechnungen immer der Vorzug zu geben ist.&lt;br /&gt;
{{Hinweis| ''genType'' kann vom Type float, vec2, vec3 oder vec4 sein, ''mat'' vom Typ mat2, mat3 oder mat4.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie und Winkel==&lt;br /&gt;
Alle übergebenen Winkel sollten, soweit nicht anders vermerkt, in Radien angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* genType radians (genType degrees)&lt;br /&gt;
: Wandelt von Grad nach Radien. &lt;br /&gt;
* genType degrees (genType radians)&lt;br /&gt;
: Wandelt von Radien nach Grad.&lt;br /&gt;
* genType sin (genType x)&lt;br /&gt;
: Gibt den Sinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType x)&lt;br /&gt;
: Gibt den Kosinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType x)&lt;br /&gt;
: Gibt den Tangens von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType asin (genType x)&lt;br /&gt;
: Liefert den Arcsinus von x zurück, also den Winkel dessen Sinus x ergeben würde.&lt;br /&gt;
* genType acos (genType x)&lt;br /&gt;
: Liefert den Arckosinus von x zurück, also den Winkel dessen Cosinus x ergeben würde.&lt;br /&gt;
* genType atan (genType y, genType x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x/y ergeben würde.&lt;br /&gt;
* genType atan (genType y_over_x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x über y ergeben würde.&lt;br /&gt;
&lt;br /&gt;
==Hyperbolisch==&lt;br /&gt;
* genType sinh (genType x)&lt;br /&gt;
: Gibt den Sinus Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) * 0.5; )&lt;br /&gt;
* genType cosh (genType x)&lt;br /&gt;
: Gibt den Kosinus Hyperbolicus von x zurück. (return = (exp(x) + exp(-x)) * 0.5; )&lt;br /&gt;
* genType tanh (genType x)&lt;br /&gt;
: Gibt den Tangens Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) / (exp(x) + exp(-x)); )&lt;br /&gt;
* genType asinh (genType angle)&lt;br /&gt;
: Gibt den Areasinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x + 1.0)); )&lt;br /&gt;
* genType acosh (genType angle)&lt;br /&gt;
: Gibt den Areakosinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x - 1.0)); )&lt;br /&gt;
* genType atanh (genType x)&lt;br /&gt;
: Gibt den Areatangens Hyperbolicus von x zurück. (return = log((1.0 + x) / (1.0 - x)) * 0.5; )&lt;br /&gt;
&lt;br /&gt;
==Exponentiell==&lt;br /&gt;
* genType pow (genType x, genType y)&lt;br /&gt;
: Gibt x hoch y zurück.&lt;br /&gt;
* genType exp (genType x)&lt;br /&gt;
: Gibt e(Eulerischezahl ≈ 2.7182) hoch x zurück.&lt;br /&gt;
* genType log (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis e(Eulerischezahl ≈ 2.7182) von x zurück.&lt;br /&gt;
* genType exp2 (genType x)&lt;br /&gt;
: Gibt 2 hoch x zurück.&lt;br /&gt;
* genType log2 (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis 2 von x zurück.&lt;br /&gt;
* genType sqrt (genType x)&lt;br /&gt;
: Gibt die Wurzel von x zurück.&lt;br /&gt;
* genType inversesqrt (genType x)&lt;br /&gt;
: Gibt die umgekehrte Wurzel von x zurück.&lt;br /&gt;
&lt;br /&gt;
==Standardfunktionen==&lt;br /&gt;
* genType abs (genType x)&lt;br /&gt;
: Liefert den absoluten Wert von x zurück.&lt;br /&gt;
* genType sign (genType x)&lt;br /&gt;
: Gibt -1.0 zurück, wenn x &amp;lt; 0.0, 0.0 wenn x = 0.0 und 1.0 wenn x &amp;gt; 0.0.&lt;br /&gt;
* genType roundeven(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. Bei &amp;quot;.5&amp;quot; Werten wird zur nächsten geraden Zahl gerundet.&lt;br /&gt;
* genType round(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. &amp;quot;.5&amp;quot; Werte werden je nach Implementation anders behandelt.&lt;br /&gt;
* genType trunc(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert dessen Absoluterwert nicht größer ist als der Absolutewert von x&lt;br /&gt;
* genType floor (genType x)&lt;br /&gt;
: Gibt denn größten Integerwert zurück, der kleiner oder gleich x ist.&lt;br /&gt;
* genType ceil (genType x)&lt;br /&gt;
: Gibt den kleinsten Integerwert zurück, der größer oder gleich x ist.&lt;br /&gt;
* genType fract (genType x)&lt;br /&gt;
: Gibt den Nachkommateil von x zurück.&lt;br /&gt;
* genType mod (genType x, float y) &lt;br /&gt;
* genType mod (genType x, genType y)&lt;br /&gt;
: Gibt den Modulus zurück. (result = x - y * floor(x / y)) &lt;br /&gt;
* genType min (genType x, genType y) &lt;br /&gt;
* genType min (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn y &amp;lt; x, ansonsten x. &lt;br /&gt;
* genType max (genType x, genType y) &lt;br /&gt;
* genType max (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn x &amp;lt; y, ansonsten x. &lt;br /&gt;
* genType clamp (genType x, genType minVal, genType maxVal) &lt;br /&gt;
* genType clamp (genType x, float minVal, float maxVal)&lt;br /&gt;
: Zwängt x in den Bereich minVal ... maxVal .  (return = min(minVal, max(maxVal, x)))&lt;br /&gt;
* genType mix (genType x, genType y, genType a)&lt;br /&gt;
* genType mix (genType x, genType y, float a)&lt;br /&gt;
: Liefert den linearen Blend zwischen x und y zurück. (result = x * (1 - a) + y * a) &lt;br /&gt;
* genType step (genType edge, genType x)&lt;br /&gt;
* genType step (float edge, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt; edge, ansonsten 1.0. &lt;br /&gt;
* genType smoothstep (genType edge0, genType edge1, genType x)&lt;br /&gt;
* genType smoothstep (float edge0, float edge1, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge0 und 1.0 wenn x &amp;gt;= edge1. Dazwischen wird eine weiche Hermite Interpolation durchgeführt.&lt;br /&gt;
::float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);&lt;br /&gt;
::result = t * t * (3.0 - 2.0 * t)&lt;br /&gt;
&lt;br /&gt;
==Geometrie==&lt;br /&gt;
* float length (genType x)&lt;br /&gt;
: Gibt die Länge des Vektors x (= sqrt(x[0]² + x[1]² + ... + x[n]²) zurück. &lt;br /&gt;
* float distance (genType p0, genType p1)&lt;br /&gt;
: Gibt die Distanz zwischen den zwei Vektoren p0 un p1 (= length(p0-p1)) zurück. &lt;br /&gt;
* float dot (genType x, genType y)&lt;br /&gt;
: Gibt das Punktprodukt von x und y zurück (=x[0]*y[0] + x[1]*y[1] + ... + x[n]*y[n]). &lt;br /&gt;
* vec3 cross (vec3 x, vec3 y)&lt;br /&gt;
: Gibt das Kreuzprodukt von x und y zurück. &lt;br /&gt;
* genType normalize (genType x)&lt;br /&gt;
: Normalisiert den Vektor x auf die Länge 1. &lt;br /&gt;
* vec4 ftransform()&lt;br /&gt;
: Nur im Vertex Shader. Die Funktion stellt sicher, das das eingehende Vertex haargenau so transformiert wird wie in der festen Funktionspipeline. gl_Position = ftransform() wird dann also gebraucht, wenn in mehreren Durchgängen sowohl im Shader als auch in der festen Pipeline gerendert wird, um sicherzustellen das in beiden Fällen die gleiche Vertexposition herauskommt. &lt;br /&gt;
* genType faceforward (genType N, genType I, genType Nref)&lt;br /&gt;
: Gibt einen nach vorne zeigenden Vektor N zurück. (If dot(NRef, I) &amp;lt; 0 return N else return -N) &lt;br /&gt;
* genType reflect (genType l, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (result = l - 2.0 * dot(N,I) * N; )&lt;br /&gt;
* genType refract (genType l, genType N, float eta)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N mit dem Brechungsindex eta gebrochenen Vektor l zurück. &lt;br /&gt;
::gentype k = 1.0 - eta * eta * (1.0 - dot(N, l) * dot(N, l))&lt;br /&gt;
::if (k &amp;lt; 0.0)&lt;br /&gt;
:::result = 0.0&lt;br /&gt;
::else &lt;br /&gt;
:::result = eta * l - (eta * dot(N, l) * sqrt(k)) * N&lt;br /&gt;
&lt;br /&gt;
==Matrixfunktionen==&lt;br /&gt;
* mat matrixCompMult (mat x, mat y)&lt;br /&gt;
: Multipliziert Matrix X mit Matrix Y komponentenweise. Um eine normale lineare Matrixmultiplikation durchzuführen, sollte der &amp;quot;*&amp;quot;-Operator genutzt werden.&lt;br /&gt;
* mat transpose (mat m)&lt;br /&gt;
: Gibt die transponierte Matrix von m zurück.&lt;br /&gt;
* mat invert (mat m)&lt;br /&gt;
: Gibt die invertierte Matrix von m zurück. Also die Matrix, die mit m multipliziert die Normalmatrix ergeben würde.&lt;br /&gt;
* mat outerProduct(vec c, vec r)&lt;br /&gt;
: Gibt eine eine Matrix als Ergebnis der linearen (return[m, n] = c[m] * r[n])-Operation zurück.&lt;br /&gt;
&lt;br /&gt;
==Vektorvergleiche==&lt;br /&gt;
Die meisten Vektorvergleichsfunktionen liefern als Ergebnis einen boolvektor zurück, da die Vergleiche per Komponente stattfinden. Wenn man also x = vec4(1.0, 3.0, 0.0, 0.0) mit y = vec4(2.0, 1.5, 1.5, 0.0) via lessThan(x, y) vergleicht, erhält man als Ergebnis bvec(true, false, true, false).&lt;br /&gt;
&lt;br /&gt;
* bvec lessThan (vec x, vec y)&lt;br /&gt;
* bvec lessThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt; y zurück. &lt;br /&gt;
* bvec lessThanEqual (vec x, vec y)&lt;br /&gt;
* bvec lessThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt;= y zurück. &lt;br /&gt;
* bvec greaterThan (vec x, vec y)&lt;br /&gt;
* bvec greaterThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt; y zurück. &lt;br /&gt;
* bvec greaterThanEqual (vec x, vec y)&lt;br /&gt;
* bvec greaterThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt;= y zurück. &lt;br /&gt;
* bvec equal (vec x, vec y)&lt;br /&gt;
* bvec equal (ivec x, ivec y)&lt;br /&gt;
* bvec equal (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x == y zurück. &lt;br /&gt;
* bvec notEqual (vec x, vec y)&lt;br /&gt;
* bvec notEqual (ivec x, ivec y)&lt;br /&gt;
* bvec notEqual (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x != y zurück. &lt;br /&gt;
* bool any (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn mindestens eine der Komponenten von x true ist.&lt;br /&gt;
* bool all (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn alle Komponenten von x true sind. &lt;br /&gt;
* bvec not (bvec x)&lt;br /&gt;
: Liefert die logische Negation von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Texturenzugriffe==&lt;br /&gt;
&lt;br /&gt;
Diese wichtige Funktionskategorie dient dazu, Werte aus einer an eine Textureinheit gebundenen Textur zu ermitteln. Die Texturenzugriffe können sowohl im Vertex (!) als auch im Fragment Shader ausgeführt werden, wobei der optionale Parameter bias im Vertex Shader ignoriert wird. Allerdings gibt es zusätzlich Funktionen die auf &amp;quot;Lod&amp;quot; enden und nur im Vertex Shader genutzt werden dürfen um eben dieses Manko zu umgehen. Funktionen mit dem Suffix &amp;quot;Proj&amp;quot; geben einen projizierten Texturenwert zurück.&lt;br /&gt;
&lt;br /&gt;
: '''1D-Texturen :'''&lt;br /&gt;
* vec4 texture1D (sampler1D sampler, float coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 texture1DLod (sampler1D sampler, float coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''2D-Texturen :'''&lt;br /&gt;
* vec4 texture2D (sampler2D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''3D-Texturen :'''&lt;br /&gt;
* vec4 texture3D (sampler3D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture3DProj (sampler3D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture3DProjLod (sampler3D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Cubemap :'''&lt;br /&gt;
* vec4 textureCube (samplerCube sampler, vec3 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
*vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Tiefentextur (Shadowmap) :'''&lt;br /&gt;
* vec4 shadow1D (sampler1DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow2D (sampler2DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
* vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow1DProjLod (sampler1DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
* vec4 shadow2DProjLod (sampler2DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Texturegröße :'''&lt;br /&gt;
Mit den textureSize-Befehlen kann die Größe einer Textur bestimmt werden, wobei lod das Mipmaplevel angibt:&lt;br /&gt;
*int textureSize(sampler1D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2D sampler, int lod)&lt;br /&gt;
*ivec3 textureSize(sampler3D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(samplerCube sampler, int lod)&lt;br /&gt;
*int textureSize(sampler1DShadow sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2DShadow sampler, int lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie bereits eingangs gesagt ist dieses Kapitel ein sehr wichtiges, denn eine 3D-Szene ohne Texturen ist heute kaum denkbar. Darüber hinaus lassen sich durch Texturenzugriffe recht viele interessante Sachen machen, z.B. ein einfacher Blurfilter oder das freie überblenden bestimmter Texturenteile. Deshalb führe ich hier kurz ein paar Beispiele an, welche die Nutzung dieser Funktionen verdeutlichen sollen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Eine Textur gebunden die einfach ausgegeben werden soll&lt;br /&gt;
&lt;br /&gt;
''Im Vertex Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
Der Vertex Shader ist recht minimal. Neben der homogenen Vertexposition leiten wir hier nur die im OpenGL-Programm angegebenen Texturkoordinaten weiter. ''Dies ist aber unbedingt nötig!'' Ohne die letzte Zeile hätten wir im Fragment Shader keine gültigen Texturkoordinaten auf TMU0, was in einer Fehldarstellung enden würde.&lt;br /&gt;
&lt;br /&gt;
''im Fragment Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSampler;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(texSampler, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zuerst deklarieren wir hier einen 2D-Texturensampler, wichtig : '''Texturensampler müssen IMMER als uniform deklariert werden!''' In der Hauptfunktion weisen wir dann einfach den über die Funktion texture2D aus unserer gebundenen Textur ausgelesenen Farbwert, anhand der vom Vertex Shader übergebenen Texturkoordinaten, zu.&lt;br /&gt;
{{Vorlage:Hinweis|Der Uniform-Integer für den Sampler referenziert '''nicht''' den Namen (die ID) des Texturobjektes, sondern die Nummer der Texturunit.}}&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Zwei Texturen, jeweils auf TMU0 und TMU1. Fragmentfarbe soll eine Multiplikation der beiden Texturen darstellen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielfall (der recht häufig vorkommt) müssen wir im Programm festlegen, ''welcher Sampler welche Textureinheit adressiert'', genau deshalb müssen die Texturensampler auch als uniform deklariert werden. Die Standardtextureneinheit eines Samplers ist TMU0, was in unserem Falle natürlich nicht brauchbar ist. Also müssen wir unserem zweiten Textursampler im Programm mitteilen das er seine Daten aus TMU1 beziehen soll :&lt;br /&gt;
&lt;br /&gt;
 glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&lt;br /&gt;
Dies ist also unbedingt zu machen, sobald ein Texturensampler eine Textureinheit &amp;gt; GL_TEXTURE_0 adressieren will. Die Textureneinheit des Samplers lässt sich also nicht im Shader selbst festlegen. Der Fragment Shader ist nun allerdings schnell hergeleitet (Vertex Shader verändert sich nicht, da TMU1 die Texturkoordinaten auch von TMU0 bezieht) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
im Fragment Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSamplerTMU0;&lt;br /&gt;
uniform sampler2D texSamplerTMU1;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_FragColor = texture2D(texSamplerTMU0, vec2(gl_TexCoord[0])) *&lt;br /&gt;
                   texture2D(texSamplerTMU1, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich [[GLSL noise|Noisefunktionen]] nutzen, mit deren Hilfe sich eine gewisse &amp;quot;Zufälligkeit&amp;quot; simulieren lässt (wirklich zufällige Werte sind es natürlich nicht). Ein zurückgegebener Wert liegt dabei immer im Bereich [-1..1] und ist immer bei gleichem Eigabewert auch immer gleich. Die Verwendung empfiehlt sich derzeit allerdings eher nicht, da nur die 3DLabs Treiber die Funktionen unterstützen und eine Noisetextur wahrscheinlich performanter ist.&lt;br /&gt;
&lt;br /&gt;
* float noise1 (genType x)&lt;br /&gt;
* vec2 noise2 (genType x)&lt;br /&gt;
* vec3 noise3 (genType x)&lt;br /&gt;
* vec4 noise4 (genType x)&lt;br /&gt;
&lt;br /&gt;
==Discard==&lt;br /&gt;
Eigentlich keine Funktion, sondern eine Abbruchbedingung '''nur im Fragment Shader'''. Das Schlüsselwort {{INLINE_CODE|discard}} verwirft das aktuell bearbeitete Fragment und beendet gleichzeitig den Shader. Es kann z.B. genutzt werden um Alphamasking manuell durchzuführen.&lt;br /&gt;
Man sollte dabei jedoch beachten dass ein Großteil der aktuellen Hardware kein &amp;quot;early-out&amp;quot; (frühes Beenden) im Fragmentshader unterstützt. Wenn dort also ein {{INLINE_CODE|discard}} auftaucht, wird trotzdem auch der Code danach ausgeführt und einfach verworfen. Einen Geschwindigkeitsvorteil durch diesen Befehl wird man also erst auf neueren Karten feststellen, die dieses Faeature auch so unterstützen wie es angedacht war. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispielshader=&lt;br /&gt;
Wen bis hierhin nicht der Mut verlassen hat, und wer aufmerksam gelesen hat, dürfte jetzt also zumindest in der Lage sein kleinere Shader in glSlang zu schreiben und diese auch im Programm zu nutzen. Ich habe im Themenbereich &amp;quot;glSlang&amp;quot; versucht alle Bereiche der Shadersprache selbst anzusprechen und hoffe das auch brauchbar rübergebracht zu haben. Um oben erlerntes (hoffe ich doch mal) nochmal zu vertiefen werde ich jetzt (wie ich das bereits bei meinem ARB_VP-Tutorial getan habe) einen simplen Beispielshader (Vertex und Fragment Shader) auseinanderpflücken um so u.a. auch die Programmstruktur für alle die in C nicht so bewandert sind zu erörtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Vertex Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_FrontColor   = gl_Color * GlobalColor;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie gesagt recht simpel. Angefangen wird mit der Deklaration einer globalen Uniformvariable namens {{INLINE_CODE|GlobalColor}}. Wie wir uns erinnern gibt der Typenqualifizierer uniform an, das wir den Wert dieser Variable (ein 4-Komponentenvektor, da Farbwerte aus R,G,B und A bestehen) in unserem Programm an den Shader übermitteln.&lt;br /&gt;
&lt;br /&gt;
Danach gehts ohne Umwege direkt in unsere Hauptfunktion, da wir im Vertex Shader keine anderen Funktionen benötigen. Dort berechnen wir zuerst die homogene Position unseres Vertex, die sich aus der eingehenden Vertexposition multipliziert mit der Modelansichtsmatrix ergibt. Wie schonmal gesagt '''muss diesem Wert etwas zugewiesen werden''', da sonst alle darauf aufbauenden Funktionen unvorhersehbare Ergebnisse liefern.&lt;br /&gt;
Außerdem wollen wir die Frontfarbe unseres Vertex jedesmal mit der im Programm übergebenen GlobalColor multiplizieren, so dass wir den Farbwert der gesamten Szene aus unserem Programm heraus manipulieren können. Zu guterletzt geben wir dann noch unsere aus der festen Funktionspipeline erhaltenen Texturkoordinaten auf Textureinheit 0 weiter. Wenn im Fragmentshader Texturkoordinaten verwendet werden, '''muss das getan werden'''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Fragment Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
uniform sampler2D Texture2;&lt;br /&gt;
uniform sampler2D Texture3;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec2 TexCoord = vec2( gl_TexCoord[0] );&lt;br /&gt;
 vec4 RGB      = texture2D( Texture0, TexCoord );&lt;br /&gt;
&lt;br /&gt;
 gl_FragColor  = texture2D(Texture1, TexCoord) * RGB.r +&lt;br /&gt;
                 texture2D(Texture2, TexCoord) * RGB.g +&lt;br /&gt;
                 texture2D(Texture3, TexCoord) * RGB.b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier passiert nicht wirklich viel Großartiges. Wir deklarieren beim Shaderanfang zuerst vier Texturensampler, da wir insgesamt vier verschiedene Texturen im Shader auslesen wollen, eine Verlaufstextur und drei Oberflächentexturen. Auch hier sei wieder gesagt das man Sampler '''immer als uniform deklarieren muss'''. In der Hauptfunktion deklarieren wir dann einen Farbvektor, der auch direkt einen Farbwert aus Textureinheit 0 zugewiesen bekommt. Auf Textureinheit 0 haben wir ihm Hauptprogramm eine Verlaufstextur gebunden, die angibt wie die drei folgenden Texturen ineinander geblendet werden.&lt;br /&gt;
Danach schreiben wir dann den Farbwert des Fragmentes, der '''im Fragment Shader ausgegeben werden muss'''. Der besteht wie einfach zu erkennen aus Farbwert von Textureinheit 1 * Rotwert von Textureinheit 0 + Farbwert von Textureinheit 2 * Grünwert von Textureinheit 0 + Farbwert von Textureinheit 3 * Blauwert von Textureinheit 0. So ist z.B. an Stellen an denen in der Verlaufstextur reines blau liegt nur die dritte Textur sichtbar.&lt;br /&gt;
&lt;br /&gt;
So viel also zu unserem kleinen Beispielshader. Er ist weder besonders toll noch besonders sinnvoll, sollte aber auch eher dazu dienen euch glSlang ein wenig zu veranschaulichen, was mir hoffentlich gelungen ist.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr in den vorangegangenen Kapiteln zumindest ein wenig aufgepasst habt, dann könnt ihr euch vor eurem inneren Auge hoffentlich vortstellen was der Shader macht : Er blendet drei Texturen weich anhand der Verlaufstextur ineinander über. Sowas kann man z.B. für ein Terrain nutzen, um dieses anhand einer Farbtextur zu texturieren. Für alle, die damit Probleme haben hier zwei Bilder die den Shader veranschaulichen. Links die Verlaufstextur, die angibt wo welche Textur wie stark gewichtet wird und rechts dann das Ergebnis :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; [[BILD:GLSL_sample_shader_a.jpg]] [[BILD:GLSL_sample_shader_b.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post Mortem=&lt;br /&gt;
Das wars also, meine &amp;quot;Einführung&amp;quot; in die OpenGL Shader Sprache. Ich hoffe es hat euch nicht gelangweilt und auch die von mir zur Verfügung gestellten Informationen haben euch hoffentlich ausgereicht. Mit der Veröffentlichung dieser Einführung geht übrigens auch die Eröffnung eines Shaderforums hier auf der DGL einher, in der ihr dann also fleissig Fragen zum Thema stellen oder eure Shader präsentieren könnt. In diesem Post Mortem gehe ich jetzt noch kurz auf die Zukunft von glSlang ein und zeige ein paar Screenshots (damit die Augen entspannen können), bevor ihr euch dann selbst in die Shaderwelt stürzen könnt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
Anbei ein paar exemplarische Screenshots. Da man mit GLSL aber alle möglichen Effekte berechnen kann (u.a. auch 1:1 die feste Funktionspipeline) ist es hier unmöglich einen Überblick aller möglichen Techniken zu geben.&lt;br /&gt;
&lt;br /&gt;
[[Datei:tut_glsl_eigenershader_01.png]] [[Datei:tut_glsl_eigenershader_02.png]] [[Datei:tut_glsl_eigenershader_03.png]]&lt;br /&gt;
&lt;br /&gt;
Wie im ersten (und dritten) Screenshot zu sehen ist es natürlich auch möglich mehrere Techniken innerhalb einer Szene zu nutzen. Hier sind letztendlich bis auf Hardwarelimitationen keine Grenzen gesetzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Als dieses Tutorial geschrieben wurde, war noch nicht ganz abzusehen dass bzw. ob sich GLSL auch durchsetzen würde. ARB-Shadr und NVidias cG waren damals die Platzhirsche, aber inzwischen werden ARB-Shader nicht mehr genutzt (und auch schon länger nicht mehr weiterentwickelt) und auch NVidia setzt primär auf GLSL. GLSL wird permanent weiterenwtickelt und Hersteller können dank des flexiblen Extensionsystems auch in GLSL eigene Extensions offenlegen um die aktuellsten Features (wie z.b. den Tesselator auf aktuellen ATI-Karten) nutzen zu können. GLSL gilt inzwischen auch offizielle die Shadersprache für OpenGL und wird permanent an die neusten technischen Entwicklungen im Grafikkartenbereich angepasst.&lt;br /&gt;
&lt;br /&gt;
Wer also unter OpenGL etwas mit Shadern machen möchte, kommt an GLSL nicht vorbei!&lt;br /&gt;
&lt;br /&gt;
Also viel Spaß beim Experimentieren und Shaderschreiben! Und nicht vergessen : Wir wollen sehen was ihr so treibt,&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_glsl2]]}}&lt;br /&gt;
[[Kategorie:Tutorial|GLSL]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25668</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25668"/>
				<updated>2012-04-21T11:03:06Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Standardfunktionen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Einleitung=&lt;br /&gt;
Hallo und willkommen bei meiner &amp;quot;Einführung&amp;quot; in GLSL (kurz für &amp;quot;Open'''GL''' '''S'''hading '''L'''anguage&amp;quot;), der offiziellen Hochlevel-Shadersprache von OpenGL. In diesem umfangreichen Dokument werde ich versuchen, sowohl auf die Nutzung (sprich das Laden und Anhängen von Shadern im Quellcode), als auch auf die Programmierung von Shadern selbst einzugehen, inklusive aller Sprachelemente der OpenGL Shadersprache. Es wird also auch recht viele Informationen zu der C-ähnlichen Programmstruktur und den von GLSL angebotenen Variablen und Attributen gehen. Am Ende dieser Einführung sollten alle die, die sich für das Thema interessieren, in der Lage sein, zumindest einfach Shader zu schreiben und auch in ihren Programmen zu nutzen. Außerdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von Khronoes veröffentlichten Shaderspezifikationen, und damit als alltägliches Nachschlagewerk, dienen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Wie auch schon mein ARB_VP-Tutorial richtet sich auch diese Einführung aufgrund ihrer Thematik eher an die fortgeschritteneren GL-Programmierer und neben sehr guten GL-Kenntnissen sollten sich alle, die sich daran versuchen wollen, mit den technischen Hintergründen der GL, wie z.B. dem Aufbau der Renderpipeline auskennen. Weiterhin sind C-Kenntnisse absolut erforderlich, da die Shader ja in einer an ANSI-C angelehnten Syntax geschrieben werden. Auch Begriffsdefinitionen zu Vertex oder Fragment werden zum Verständis dieser Einführung benötigt. Wer also noch am Anfang seiner GL-Karriere steht, dem wird dieses Dokument nicht viel nützen. Ganz nebenbei solltet ihr auch noch eine gehörige Portion Zeit (am besten nen kompletten Nachmittag) mitbringen, denn die folgende Kost ist nicht nur umfangreich, sondern auch manchmal recht schwer verdaulich.&lt;br /&gt;
&lt;br /&gt;
=Was ist GLSL?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei GLSL um eine Shadersprache, also um eine Hochsprache, in der man die programmierbaren Teile aktueller Grafikbeschleuniger nach eigenem Belieben programmieren kann. Sie stellt quasi den Nachfolger zu den in Assembler geschriebenen Vertex- und Fragmentprogrammen ([[GL_ARB_vertex_program]]/[[GL_ARB_fragment_program]]) dar und basiert auf ANSI C, erweitert um Vektor- und Matrixtypen sowie einige C++-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
Die in GLSL geschriebenen Programme nennen sich, angepasst an die Terminologie von RenderMan und DirectX, [[Shader]] (im Gegensatz zu &amp;quot;Programme&amp;quot; bei ARB_VP/FP) und werden entweder auf Eckpunkte (VertexShader), Fragmente (FragmentShader) angewendet, oder (neuerdings, ab Shadermodell 4.0) auch genutzt um Geometrie zu erstellen (Geometryshader). Andere Teile der Renderpipeline (z.B. die Rasterisierung) können momentan noch nicht durch Shader beeinflusst werden, was allerdings in Zukunft noch kommen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
GLSL wurde 2005 mit OpenGL 1.5 eingeführt. Während es in Sachen Treiber- und Hardwareunterstützung anfänglich noch dürftig aussah, wird man inzwischen keine Grafikkarte mehr kaufen können die nicht zumindest Vertex- und Fragmentshader beherscht. Geometrieshader hingegen sind relativ neu und wurden erst mit Shadermodell 4.0 eingeführt, hier ist es also unter Umständen noch möglich dass selbst aktuelle Treiber/Karten keine Geometrieshader beherrschen.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt man auch einen passenden OpenGL-Header der die für GLSL nötigen Funktionen exportiert. Ich verweise dazu auf unseren eigenen OpenGL-Header [[DGLOpenGL.pas]], der peermanent auf dem aktuellsten Stand gehalten wird und auch Support für Geometrieshader mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
&lt;br /&gt;
Die GL-Shadersprache &amp;quot;besteht&amp;quot; in ihrer aktuellen Version aus folgenden Extensions, fürs Verständnis wäre es nicht schlecht, wenn ihr euch zumindest die Einleitungen dazu durchlest :&lt;br /&gt;
* [[GL_ARB_shader_objects]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shader_objects.txt Originalspezifikation])&lt;br /&gt;
: Definiert die API-Aufrufe, die zum Erstellen, Kompilieren, Linken, Anhängen und Aktivieren von Shader- und Programmobjekten nötig sind. &lt;br /&gt;
* [[GL_ARB_vertex_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Vertexebene hinzu. &lt;br /&gt;
* [[GL_ARB_fragment_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Fragmentebene hinzu. &lt;br /&gt;
* [[GL_ARB_shading_language_100]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shading_language_100.txt Originalspezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis''' : Seit OpenGL 2.0 ist GLSL Teil des Kerns. Wenn die Karte also OpenGL 2.0 unterstützt, dann unterstützt sie auch (zumindest in Software) Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sprachversionen==&lt;br /&gt;
&lt;br /&gt;
Neben der OpenGL-Version und dem vorhandenen Shadermodell (das eher an DirectX ausgerichtet ist), bietet auch GLSL verschiedene Versionen, die entsprechend erweiterte Funktionalität bieten.&lt;br /&gt;
&lt;br /&gt;
Auslesen kann man die verfürgbare GLSL-Version wie folgt:&lt;br /&gt;
&lt;br /&gt;
 glGetString(GL_SHADING_LANGUAGE_VERSION)&lt;br /&gt;
&lt;br /&gt;
Erst ab Version 1.4. kann man davon ausgehen dass GLSL alle Features des Shadermodells 4.0 liefert, ab 1.3 grob gesagt Shadermodell 3.0 (bei GLSL lässt sich das leider nicht so leicht unterteilen).&lt;br /&gt;
&lt;br /&gt;
Außerdem kann man seinem Shader eine Versionsnummer verpassen. Sollte der Shadercompiler (also Treiber bzw. Hardware) diese Version nicht unterstützen, gibt dieser eine Fehlermeldung heraus:&lt;br /&gt;
&lt;br /&gt;
 #version 1.50 &lt;br /&gt;
&lt;br /&gt;
''(Hinweis: Muss am Anfang des Shaders stehen)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&lt;br /&gt;
&lt;br /&gt;
Im Zuge der Vereinheitlichung der GL wird immer häufiger in Objekte gekapselt, deren API dann auch aneinander angelehnt ist. Ziel ist, dabei die Programmierung der GL uniform zu machen, so dass z.B. zwischen dem Erstellen und Verwalten eines Vertex-Buffer-Objektes oder eines Shader-Objektes kaum ein Unterschied besteht (demnächst kommen dann auch Pixel-Buffer-Objekte dazu). Mit glSlang wurden dann im Zuge dieser Aktion zwei neue Objekte eingeführt, deren Definition ihr euch unbedingt einprägen solltet:&lt;br /&gt;
&lt;br /&gt;
* '''Programmobjekt'''&lt;br /&gt;
:Ein Objekt, an das die Shader später angebunden werden. Bietet Funktionalität zum Linken der Shader und prüft dabei die Kompatibilität zwischen Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
* '''Shaderobjekt'''&lt;br /&gt;
:Dieses Objekt verwaltet den Quellcodestring eines Shaders und ist entweder vom Typ '''GL_VERTEX_SHADER''', '''GL_FRAGMENT_SHADER_ARB''' oder '''GL_GEOMETRY_SHADER'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
&lt;br /&gt;
Die Shadersprache ist keinesfalls final und es wurden bereits diverse Ausdrücke für zukünftige Verwendung reserviert, denn ein Ziel bei ihrer Entwicklung war es, sie so zukunftsorientiert zu gestalten, dass auch Grafikkarten der nächsten und übernächsten Generation voll ausgenutzt werden können. Damit einher geht die Tatsache, dass sich die Spezifikationen in Zukunft ändern/erweitern werden, weshalb man da immer einen Blick hineinwerfen sollte. Die Anlaufstelle dafür ist die [http://www.opengl.org/documentation/specs/ Spezifikationenliste auf OpenGL.org].&lt;br /&gt;
&lt;br /&gt;
=GLSL im Programm=&lt;br /&gt;
Bevor wir uns mit der Syntax von glSlang beschäftigen, zeige ich euch erstmal, wie ihr Shader in euer Programm einbindet und nutzt. Warum das zuerst? Ganz einfach deshalb, weil ihr dann das, was ihr im glSlang-Syntaxteil lernt, direkt in eurer Testanwendung verwenden könnt. Hoffe diese Entscheidung klingt logisch und findet Anklang.&lt;br /&gt;
&lt;br /&gt;
Zuerst benötigen wir natürlich unsere Objekte. Zum einen ein ''Programmobjekt'', an das unsere Shader gebunden werden, und zwei ''Shaderobjekte'', die den Quellcode unseres Vertex bzw. Fragment Shaders aufnehmen. Dazu wurde eigens der neue &amp;quot;Datentyp&amp;quot; {{INLINE_CODE|glHandle}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandle;&lt;br /&gt;
 VertexShaderObject   : GLhandle;&lt;br /&gt;
 FragmentShaderObject : GLhandle;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dieser Deklaration können wir dann damit beginnen unsere Objekte zu erstellen. Den Anfang macht das Programmobjekt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        := glCreateProgram;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgram]] erstellt uns oben ein leeres Programmobjekt und gibt ein gültiges Handle darauf zurück.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Erstellung unseres Vertex bzw. Fragment Shaders :&lt;br /&gt;
&lt;br /&gt;
 VertexShaderObject   := glCreateShader(GL_VERTEX_SHADER);&lt;br /&gt;
 FragmentShaderObject := glCreateShader(GL_FRAGMENT_SHADER);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShader]] dient zur Generierung eines leeren Shaderobjektes. Momentan unterstützt diese Funktion VertexShader und FragmentShader.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun also zwei gültige Shaderobjekte haben, wollen wir diese auch mit entsprechendem Quellcode versorgen :&lt;br /&gt;
&lt;br /&gt;
 glShaderSource(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSource(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSource]] setzen wir den Quellcode eines Shaderobjektes ''komplett'' neu. Zum Laden des Quellcodes bietet sich unter Delphi übrigens eine TStringList geradezu an. Es sollte beachtet werden, dass der Quellcode zu diesem Zeitpunkt ''nicht geparst'' wird, also keine Fehleruntersuchung stattfindet.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode wurde jetzt also an unsere Shaderobjekte gebunden und sollte dann natürlich auch noch kompiliert werden :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 glCompileShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShader]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der Shadercompiler (je nach Treiber) recht detaillierte Infos aus. Wie man an diese Infos kommt könnt ihr gleich nachlesen.&lt;br /&gt;
&lt;br /&gt;
Wenn unsere Shader dann kompiliert werden konnten, ist es Zeit, diese an unser anfangs erstelltes Programmobjekt anzuhängen :&lt;br /&gt;
&lt;br /&gt;
 glAttachShader(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachShader(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehängt wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteShader(VertexShaderObject);&lt;br /&gt;
 glDeleteShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Schluß müssen wir dann noch unsere ans Programmobjekt gebundenen Shader linken :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShader]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgram]] die angehangenen Shader zu einem ausführbaren Shader gelinkt. Folgende Bedingungen führen zu einem '''Linkerfehler''':&lt;br /&gt;
&lt;br /&gt;
* Die Zahl der von der Implementation unterstützten Attributvariablen wurde überschritten&lt;br /&gt;
* Der Speicherplatz für Uniformvariablen wurde überschritten&lt;br /&gt;
* Die Zahl der von der Implementation angebotenen Sampler wurde überschritten&lt;br /&gt;
* Die main-Funktion fehlt&lt;br /&gt;
* Die Liste der Varying-Variablen des Vertexshaders stimmt nicht mit der des Fragmentshaders überein&lt;br /&gt;
* Funktions- oder Variablenname nicht gefunden&lt;br /&gt;
* Eine gemeinsame Globale ist mit unterschiedlichen Werten oder Typen initialisiert worden&lt;br /&gt;
* Zwei Sampler unterschiedlichen Typs zeigen auf die selbe Textureneinheit&lt;br /&gt;
* Ein oder mehrere angehangene(r) Shader wurden nicht erfolgreich kompiliert&lt;br /&gt;
&lt;br /&gt;
Die Nutzung von glSlang im eigenen Programm ist wie oben erkennbar also nicht wirklich schwer und innerhalb kurzer Zeit realisiert. Natürlich ist es auch möglich z.B. nur einen VertexShader oder nur einen FragmentShader an ein Programmobjekt zu binden.&lt;br /&gt;
&lt;br /&gt;
Noch eine kleine Notiz zum Löschen der Shader mittel [[glDeleteShader]] : Da Shader(objekte) einen Referenzzähler besitzen und erst gelöscht werden wenn diese nirgendwo mehr benötigt werden, ist es nicht falsch diese vor dem Linkvorgang zu löschen. Allerdings spielt es letztendlich keine Rolle ob die Löschanweisung vorher der nachher ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fehlererkennung==&lt;br /&gt;
Natürlich wird es ohne Fehlerausgabe recht schwer, etwaige Probleme in einem Vertex- oder Fragmentshader zu finden. Doch auch in diesem Bereich wurde glSlang recht gut durchdacht und es wurden zwei Funktionen eingeführt, welche im Zusammenspiel die Fehlersuche recht einfach machen, nämlich [[glGetShaderInfoLog]] und [[glGetShader]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH}}. Erstere Funktion liefert uns einen Logstring, während uns letztere Funktion dessen Länge angibt. Der Logstring wird verändert, sobald ein Shader kompiliert oder ein Programm gelinkt wird.&lt;br /&gt;
&lt;br /&gt;
Um die Ausgabe dieses Logs so einfach wie möglich zu machen, bietet es sich an beide in einer einfach Funktion unterzubringen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function glSlang_GetInfoLog(pShader: GLHandleARB): String;&lt;br /&gt;
var&lt;br /&gt;
  blen, slen: GLInt;&lt;br /&gt;
  InfoLog: PGLCharARB;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  glGetShaderiv(glObject, GL_INFO_LOG_LENGTH , @blen);&lt;br /&gt;
  if blen &amp;gt; 1 then&lt;br /&gt;
  begin&lt;br /&gt;
    GetMem(InfoLog, blen * SizeOf(GLCharARB));&lt;br /&gt;
    glGetShaderInfoLog(pShader, blen, slen, InfoLog);&lt;br /&gt;
    Result := PChar(InfoLog);&lt;br /&gt;
    Dispose(InfoLog);&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist recht leicht erklärt : Zuerst lassen wir uns über {{INLINE_CODE|glGetShaderiv}} mitteilen wie lang der aktuelle Infolog ist. Sollte dort tatsächlich etwas drinstehen (blen &amp;gt; 1), dann lassen wir uns dessen Inhalt via {{INLINE_CODE|glGetShaderInfoLog}} in {{INLINE_CODE|InfoLog}} ausgeben und liefern diesen als Ergebnis zurück.&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt wird nur nach dem Kompilieren eines Shaders bzw. dem Linken eines Programmobjektes ein Infolog erstellt. Es bietet sich dadurch an, direkt danach einen solchen Aufruf zu machen :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 ShowMessage(glSlang_GetInfoLog(VertexShaderObject));&lt;br /&gt;
&lt;br /&gt;
Wenn unser Vertex Shader komplett fehlerfrei kompiliert werden konnte, dann sehen wir als Ergebnis nur einen leeren Dialog. Ist dies nicht der Fall, so werden wir vom Treiber mit recht detaillierten Fehlerinformationen &amp;quot;belohnt&amp;quot;, z.B. so :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL_error_vshader.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch das Infolog nach dem Linken des Programmobjektes dürfte, selbst wenn keine Fehler vorkommen, recht interessant sein, das sieht dann nämlich so aus :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL info programobject.jpg]]&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen, wird uns nach dem erfolgreichen Linken auch gesagt, ob und welcher Shader in Hardware bzw. Software läuft. Für Debuggingzwecke sicherlich eine mehr als brauchbare Information.&lt;br /&gt;
&lt;br /&gt;
==Shader benutzen==&lt;br /&gt;
Um den Shader auch für die nächsten Polygone zu benutzen oder Uniformparameter übergeben zu können, ruft man die Funktion&lt;br /&gt;
 glUseProgramt(ProgramObject);&lt;br /&gt;
um alle Shader zu deaktivieren, ruft man dieselbe Funktion mit dem Parameter 0.&lt;br /&gt;
&lt;br /&gt;
==Parameterübergabe==&lt;br /&gt;
Uniformparameter (mehr dazu später) stellen die Schnittstelle zwischen eurem Programm und dem Shader dar, werden also genutzt um Daten aus dem Programm heraus an einen Shader zu übergeben. Zur Übergabe dieser Parameter bietet OpenGL diverse Funktionen, die alle Abkömmlinge von [[glUniform]] sind. Während mit {{INLINE_CODE|glUniform4f}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fv}} ganze Matrizen schnell und einfach übergeben. Außerdem gibt es nun die Möglichkeit Uniformparameter direkt über ihren Namen, statt wie unter ARB_FP/VP über einen festen Index zu adressieren. Die Funktion [[glGetUniformLocationARB]] gibt anhand des übergebenen Parameternamens dessen Position zurück. Man kann also ganz einfach über den Namen drauf zugreifen :&lt;br /&gt;
&lt;br /&gt;
 glUniform3f(glGetUniformLocation(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1i(glGetUniformLocation(ProgramObject, PGLCharARB('texSamplerTMU3')), 3);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier, das man je nach Parametertyp auch die passende Anzahl von Argumenten übergibt. Also für einen 4-Komponenten Floatvektor {{INLINE_CODE|glUniform4fARB}} und für einen einfachen Integerwert (z.B. Textureinheit für einen Sampler) glUnifrom1iARB. Auch nicht vergessen dürft ihr, das die Namen der Parameter genauso wie im Shader geschrieben werden müssen, also Groß- und Kleinschreibung beachtet werden muß.&lt;br /&gt;
&lt;br /&gt;
=Die Shadersprache=&lt;br /&gt;
&lt;br /&gt;
Nachdem wir uns mit der Einbindung der glSlang-Shader in unser Programm beschäftigt haben, wollen wir uns in den folgenden Kapiteln um die Sprachelemente von glSlang kümmern. Wie schon gesagt basiert glSlang auf ANSI-C, wurde allerdings um speziell auf den Zielbereich angepasste Vektor- und Matrixtypen und einige C++-Features wie das freie deklarieren von Variablen an jeder Stelle und das Funktionsüberladen auf Basis des Argumenttyps erweitert. Wer sich ein wenig mit C/C++ auskennt sollte also in der nun folgenden Materie keine Probleme bekommen.&lt;br /&gt;
&lt;br /&gt;
'''Obligatorische Hinweise für verwöhnte Delphi-Nutzer : '''&lt;br /&gt;
*Wie von C/C++ her gewohnt, spielt auch in glSlang die Groß- und Kleinschreibung eine wichtige Rolle, also bitte achtet darauf. gl_Position ist eine komplett andere Variable als z.B. gl_position.&lt;br /&gt;
*Es findet keine automatische Typenkonvertierung statt. Das bedeutet also das float MyFloat = 1 ungültig ist und es in dem Falle float MyFloat = 1.0 heissen muss. Typecasts müssen also immer manuell stattfinden, z.B. MyFloat = float(MyInt).&lt;br /&gt;
&lt;br /&gt;
'''Kleine Programmstrukturkunde für C-Unkundige :'''&amp;lt;br&amp;gt;&lt;br /&gt;
Da sicherlich einige Delpher nie richtig was mit C gemacht haben, zeige ich mal anhand eines kleinen Beispieles (das auf keinen Fall nen brauchbaren Shader darstellt) den grundlegenden Aufbau eines glSlang-Shaders, der natürlich dem Aufbau eines C-Programmes stark ähnelt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 VariableA;&lt;br /&gt;
float VariableB;&lt;br /&gt;
vec3  VariableC;&lt;br /&gt;
const float KonstanteA = 256.0;&lt;br /&gt;
&lt;br /&gt;
float MyFunction(vec4 ArgumentA)&lt;br /&gt;
{&lt;br /&gt;
    float FunktionsVariableA = float(5.0);&lt;br /&gt;
&lt;br /&gt;
    return float(ArgumentA * (FunktionsVariableA + KonstanteA));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Ich bin ein Kommentar&lt;br /&gt;
/* Und ich auch */&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
    gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht doch recht bekannt aus, unser Programmaufbau. Delphi und C haben ja so einige Grundlagen gleich, darunter auch der ungefähre Programmaufbau. Ausserhalb jeglicher Funktionen legen wir am Programmanfang unsere Variablen, Konstanten und Attribute fest, die dann ''global'' nutzbar sind, also in jeder Funktion.&lt;br /&gt;
&lt;br /&gt;
Darunter deklarieren wir dann eine kleine Funktion. Wie auch bei den Variablendeklarationen wird hier der Rückgabetyp nicht wie bei Pascal nach dem Funktionsnamen untergebracht, sondern davor. Innerhalb der Funktion können dann wieder Variablen deklariert werden, die dann allerdings ''lokal'', also nur in dieser Funktion nutzbar sind. Vorteil dieser Deklaration ist die Tatsache, dass je nach Grafikkarte nur bestimmt viele globale Variablen deklariert werden können. Wenn möglich sollte man also mit lokalen Vorlieb nehmen. Unsere Funktion gibt dann natürlich noch via return einen Wert zurück, ''was gemacht werden muss'', sofern man diese nicht als void deklariert hat (entspräche dann einer Prozedur in Pascal). Wird dies nicht getan, so spuckt der Compiler einen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Auch wichtig sind natürlich Kommentare. Erste Variante (Doppelslash) ist auch in der Pascalwelt verfügbar und kommentiert eine einzelne Zeile aus. Die Variante darunter kann man für Kommentarblöcke nutzen (/* .. */) und entspricht den Kommentaren in geschweiften Klammern in Delphi.&lt;br /&gt;
&lt;br /&gt;
Danach kommt dann die '''wichtigste Funktion''' des Shaders, nämlich '''main''', die in keinem Shader fehlen darf. Sie stellt quasi den Programmkörper dar und ist oft auch die einzige Funktion in einem Shader. Sie erhält weder ein Argument, noch gibt sie einen Wert zurück.&lt;br /&gt;
&lt;br /&gt;
Soviel also zum grundlegenden Aufbau eines Shader. Hoffe das jetzt alle die in C nicht so bewandert sind damit klar kommen, und dann bald ihre ersten glSlang-Shader schreiben können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Datentypen==&lt;br /&gt;
&lt;br /&gt;
Obwohl einige Datentypen aus C übernommen wurden, sieht man der Typenliste an, das diese speziell auf den 3D-Bereich zugeschnitten wurde. Variablen müssen vor ihrer Nutzung eindeutig deklariert sein, Typecasting erfolgt über Konstruktoren (dazu später mehr). Folgende Datentypen stehen sowohl im Vertex- als auch Fragmentshader zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|void 	&lt;br /&gt;
|Für Funktionen die keinen Wert zurückgeben&lt;br /&gt;
|-&lt;br /&gt;
|bool 	&lt;br /&gt;
|Konditionaler Typ, entweder true (wahr) oder false (falsch)&lt;br /&gt;
|-&lt;br /&gt;
|int 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenbehafteter Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|uint 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenloser Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|float 	&lt;br /&gt;
|Fließkommaskalar mit Singlegenauigkeit (32 Bit)&lt;br /&gt;
|-&lt;br /&gt;
|vec2 	&lt;br /&gt;
|2-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec3 	&lt;br /&gt;
|3-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec4 	&lt;br /&gt;
|4-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec2 	&lt;br /&gt;
|2-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec3 	&lt;br /&gt;
|3-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec4 	&lt;br /&gt;
|4-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec2 	&lt;br /&gt;
|2-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec2 	&lt;br /&gt;
|2-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec3 	&lt;br /&gt;
|3-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec4 	&lt;br /&gt;
|4-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|mat2 	&lt;br /&gt;
|2x2 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat3 	&lt;br /&gt;
|3x3 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat4 	&lt;br /&gt;
|4x4 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|matMxN 	&lt;br /&gt;
|Matrix mit M Spalten und N Zeilen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse zum Zugriff auf Texturen dar, und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|sampler1D 	&lt;br /&gt;
|Zugriff auf 1D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler2D 	&lt;br /&gt;
|Zugriff auf 2D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler3D 	&lt;br /&gt;
|Zugriff auf 3D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|samplerCube 	&lt;br /&gt;
|Zugriff auf Cubemap&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRect 	&lt;br /&gt;
|Zugriff auf Texturen die nicht 2^n * 2^n entsprechen (&amp;quot;non power-of-two&amp;quot;, NPOT)&lt;br /&gt;
|-&lt;br /&gt;
|sampler1DShadow 	&lt;br /&gt;
|Zugriff auf 1D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DShadow 	&lt;br /&gt;
|Zugriff auf 2D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|samplerCubeShadow&lt;br /&gt;
|Zugriff auf Tiefentextur in einer Cubemap (z.b. für omni-diretionale Lichtquellen)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRectShadow&lt;br /&gt;
|Zugriff auf 2D-NPOT-Tiefentextur &lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|sampler1DArray&lt;br /&gt;
|Zugriff auf ein array aus 1D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArray&lt;br /&gt;
|Zugriff auf ein array aus 2D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler1DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 1D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 2D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|samplerBuffer&lt;br /&gt;
|Zugriff auf eine Puffertextur (1D-Texutr zum Speichern von Pufferobjekten)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMS&lt;br /&gt;
|Zugriff auf eine 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMSArray&lt;br /&gt;
|Zugriff auf einarray aus 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Arrays===&lt;br /&gt;
&lt;br /&gt;
Natürlich unterstützt glSlang auch Arrays, die wie in C deklariert werden und deren Index bei 0 beginnt. Folgendes Array im Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
beginnt also bei Index 0 und endet bei Index 2. Im Gegensatz zu C lassen sich Arrays in glSlang allerdings ''nicht bei der Initialisierung vorbelegen''. Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strukturen===&lt;br /&gt;
&lt;br /&gt;
Neu ggü. ARB_FP/VP ist nun auch die Möglichkeit, Strukturen in einem Shader zu deklarieren. Vor allem die Übersicht komplexerer Shader kann dadurch stark verbessert werden. Strukturen werden wie gewohnt mit dem Schlüsselwort {{INLINE_CODE|struct}} eingeleitet und können dann zur Typisierung von Variablen genutzt werden. Folgendes Beispiel dürfte die Nutzung verdeutlichen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct light&lt;br /&gt;
{&lt;br /&gt;
    bool active;&lt;br /&gt;
    float intensity;&lt;br /&gt;
    vec3 position;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
LightSource[i].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Typenqualifzierer==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur Typendeklaration kann eine Variable noch einen Typenqualifizerer vorangestellt bekommen, der an den Anfang der Deklaration gehört.&lt;br /&gt;
&lt;br /&gt;
* '''const'''&lt;br /&gt;
: Festgelegte (nur lesen) Konstante bzw. nur lesbarer Funktionsparameter.&lt;br /&gt;
&lt;br /&gt;
* '''uniform'''&lt;br /&gt;
: Ein den ganzen Shader über gleichbleibender Wert, der eine Schnittstelle zwischen dem Shader und der OpenGL-Anwendung darstellt. Ein Uniformwert wird in der Hauptanwendung an den entsprechenden Shader übergeben und kann dort dann genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* '''attribute'''&lt;br /&gt;
: Nur lesbare Werte die eine Verbindung zwischen dem Shader und der OpenGL-VertexAPI darstellen (z.B. VertexParameter eines VertexArrays). Natürlich nur in einem Vertex Shader nutzbar.&lt;br /&gt;
&lt;br /&gt;
* '''varying'''&lt;br /&gt;
: Stellt die Verbindung zwischen einem Vertex- und einem FragmentShader dar. Werden im VertexShader geschrieben und dann perspektivisch korrekt über die Primitive interpoliert, um dann im Fragment Shader gelesen werden zu können. Nutzbar sind hier nur die Typen float, vec2, vec3, vec4, mat2, mat3 und mat4, Strukturen und andere Datentypen können nicht varying sein. Die Namen einer varying-Variable müssen sowohl im VertexShader als auch im FragmentShader gleich sein.&lt;br /&gt;
&lt;br /&gt;
* '''in'''&lt;br /&gt;
: Für Variablen die an eine Funktion übergeben und dort ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* '''out'''&lt;br /&gt;
: Für Variablen die von einer Funktion nach außen zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
* '''inout'''&lt;br /&gt;
: Für Variablen die sowohl an eine Funktion übergeben als auch von dieser zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um obige Auflistung nicht leer im Raum stehen zu lassen zeige ich ein paar Beispiele die hoffentlich zum Verständnis beitragen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Vertexnormale soll an einen FragmenShader (interpoliert) übergeben werden :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
VertexNormal = normalize(MV_IT * gl_Normal);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Uniformparameter zur nachträglichen Farbänderung der Szene wird im Programm übergeben :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im Programm :&lt;br /&gt;
&lt;br /&gt;
 glUniform4fARB(glSlang_GetUniLoc(ProgramObject, 'GlobalColor'), Col[0], Col[1], Col[2], Col[3]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Beispiel C=== &lt;br /&gt;
Konstante zur festen Farbänderung :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
const vec4 ColorBias = vec4(0.2, 0.3, 0.0, 0.0);&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = ColorBias * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Konstruktoren==&lt;br /&gt;
&lt;br /&gt;
Um in einem Shader ''Vektoren'' oder ''Matrizen'' mit Werten zu belegen, gibt es sogenannte Konstruktoren (nicht zu verwechseln mit z.B. Klassenkonstruktoren unter Delphi), die im Endeffekt nichts anderes als Funktionen zur Vorbelegung von Vektoren oder Matrizen darstellen. Dabei trägt der Konstruktor den selben Namen wie die Typendeklaration, also lässt sich eine Variable vom Typ {{INLINE_CODE|vec4}} mit dem Konstruktor {{INLINE_CODE|vec4(float, float, float, float)}} initialisieren.&lt;br /&gt;
&lt;br /&gt;
Allerdings hat man sich recht viel Mühe bei dieser Konstruktorgeschichte gemacht, so dass man einen vec4 nicht unbedingt mit einem {{INLINE_CODE|vec4}}-Konstruktor vorbelegen muss, sondern es vielseitige Möglichkeiten gibt. Um dies zu verdeutlichen gibts ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(1.0, 0.0, 0.0, 0.0);&lt;br /&gt;
vec4 Color = vec4(MyVec3, 1.0);&lt;br /&gt;
vec4 Color = vec4(MyVec2_A, MyVec2_B);&lt;br /&gt;
&lt;br /&gt;
vec3 LVec  = vec3(MyVec4);&lt;br /&gt;
vec2 Tmp   = vec2(MyVec3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trotz der recht wenigen Beispiele sollte schnell erkennbar sein, das man hier wirklich sehr viele Kombinationsmöglichkeiten hat, die dann gültig sind ''wenn man mindestens auf die benötigte Anzahl der Argumente kommt''. Im vorletzten Beispiel wird z.B. ein 3-Komponentenvektor aus einem 4-Komponentenvektor initialisiert. Das erzeugt keinen Fehler, sondern führt dazu das {{INLINE_CODE|vec3.x, vec3.y, vec3.z}} aus MyVec4 übernommen werden und MyVec4.w einfach ignoriert wird.&lt;br /&gt;
&lt;br /&gt;
Das Umkehrbeispiel, also&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
funktioniert allerdings nicht, da hier die Zahl der benötigten Argumente nicht erreicht wird. In diesem Falle müsste es dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
heissen.&lt;br /&gt;
&lt;br /&gt;
Obiges gilt natürlich auch für ''Matrixkonstruktoren'', hier sind z.B. folgende Konstuktoren denkbar, obwohl eigentlich alle Möglichkeiten nutzbar sind, ''solange die benötigte Zahl an Argumenten erreicht wird'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
mat4 MyMatrix = mat4(MyVec4, MyVec4, MyVec4, MyVec4);&lt;br /&gt;
mat2 MyMatrix = mat4(1.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 1.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 1.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixkomponenten==&lt;br /&gt;
&lt;br /&gt;
Was natürlich in keiner Shadersprache fehlen darf, ist der leichte Zugriff auf die einzelnen Komponenten eines Vektors. glSlang bietet, je nach Anwendungsgebiet gleich drei Namensets für den Zugriff auf die Komponenten eines solchen Vektors, welches Set man nutzen will bleibt natürlich frei und ist unabhängig von der Deklaration eines Vektors. Man sollte nur darauf achten, beim gleichzeitigen Zugriff auf mehrere Komponenten im gleichen Namenset zu verbleiben :&lt;br /&gt;
&lt;br /&gt;
* {x, y, z, w}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Punkte, Normale oder sonstige Vertexdaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {r, g, b, a}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Farbwerte repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {s, t, p, q}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Texturkoordinaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
Ein paar Beispiele zur Unterstreichung des oben gesagten :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
v4.rgba = vec4(1.0, 0.0, 0.0, 0.0);  // gültig&lt;br /&gt;
v4.rgzw = vec4(1.0, 1.0, 1.0, 2.0);  // Ungültig, da verschiedenen Namensets&lt;br /&gt;
v2.rgb  = vec3(1.0, 2.0, 1.0);       // Ungültig, da vec2 nur r+g besitzt&lt;br /&gt;
v2.xx   = vec2(5.0, 3.0);            // Ungültig, da 2 mal gleiche Komponente&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch der Zugriff auf die Komponenten einer Matrix geht leicht von der Hand. Namensets wie bei den Vektoren gibt es hier natürlich keine, aber folgende Beispiele sollen den Zugriff aufzeigen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
MyMat4[2]    = vec4(1.0); // Setzt die 3.Zeile der Matrix komplett auf 1.0&lt;br /&gt;
MyMat4[3][3] = 3.5;       // Setzt das Element unren rechts auf 3.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Matrixelemente ausserhalb ihrer Dimension (also z.B. MyMat4[4][4]) liefert unvorhersehabre Ergebnise, also sollte man auf diese Fälle prüfen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixoperationen==&lt;br /&gt;
&lt;br /&gt;
Wie von C gewohnt sind in glSlang so ziemlich alle Operatoren die man auf Matrizen oder Vektoren anwenden kann überladen, so das man nicht umständlich über selbstgeschriebene Funktionen kombinieren muss. Darüber hinaus ist es in den meisten Fällen auch möglich ohne Konvertierung Fließkommawerte mit kompletten Matrizen oder Vektoren zu kombinieren. Folgende Beispiele zeigen einige der vielfältigen Kombinationsmöglichkeiten auf :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
float factor;&lt;br /&gt;
&lt;br /&gt;
vec3 dest = source + factor; &lt;br /&gt;
&lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = source.x + factor;&lt;br /&gt;
dest.y = source.y + factor;&lt;br /&gt;
dest.z = source.z + factor;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
mat3  MyMat;&lt;br /&gt;
 &lt;br /&gt;
dest = source * MyMat; &lt;br /&gt;
 &lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = dot(source, MyMat[0]);&lt;br /&gt;
dest.y = dot(source, MyMat[1]);&lt;br /&gt;
dest.z = dot(source, MyMat[2]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier sind die Möglichkeiten fast unbeschränkt und zeigen wieder wie flexibel glSlang ausgelegt ist. &lt;br /&gt;
&lt;br /&gt;
==Operatoren==&lt;br /&gt;
&lt;br /&gt;
glSlang bietet (momentan) folgende Operatoren, die Liste ist nach ihrer Gewichtung sortiert (Anfang = höchste). Alle ''reservierten'' Operatoren werden erst in kommender Hardware/glSlang-Versionen nutzbar sein :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div  align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Operatorklasse  	&lt;br /&gt;
!Operatoren  	&lt;br /&gt;
!Assoziation&lt;br /&gt;
|-&lt;br /&gt;
|Gruppering 	&lt;br /&gt;
|() 	&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
|Arrayindizierung&amp;lt;br&amp;gt;Funktionsaufrufe und Konstruktoren&amp;lt;br&amp;gt;Strukturfeldwahl und Swizzle&amp;lt;br&amp;gt;Postinkrement und -dekrement&amp;lt;br&amp;gt; 	&lt;br /&gt;
|[]&amp;lt;br&amp;gt;()&amp;lt;br&amp;gt;.&amp;lt;br&amp;gt;++ -- 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Prefixinkrement- und dekrement&amp;lt;br&amp;gt;Einheitlich (~ reserviert) 	&lt;br /&gt;
| ++ --&amp;lt;br&amp;gt; + - ~ ! 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Mulitplikation (% reserviert) 	&lt;br /&gt;
|* / % 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Additiv 	&lt;br /&gt;
| + - 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises Verschieben (reserviert) 	&lt;br /&gt;
|&amp;lt;&amp;lt;  &amp;gt;&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Relation 	&lt;br /&gt;
|&amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;= 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Vergleich 	&lt;br /&gt;
|==  != 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises AND (reserviert) 	&lt;br /&gt;
|&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises XOR (reserviert) 	&lt;br /&gt;
|^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises OR (reserviert) 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches AND 	&lt;br /&gt;
|&amp;amp;&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches XOR 	&lt;br /&gt;
|^^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches OR 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Auswahl 	&lt;br /&gt;
|?: 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Zuweisung&amp;lt;br&amp;gt;Arithmetrische Zuweisung&amp;lt;br&amp;gt;(Modulis, Shift und bitweise Op. reserviert) 	&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;+= -=  *=  /=  %=&amp;lt;/nowiki&amp;gt; &amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;&amp;lt;&amp;lt;=  &amp;gt;&amp;gt;= &amp;amp;=  ^=  |=&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Aufzählung 	&lt;br /&gt;
|, 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von Hochsprachen ist u.A. die Möglichkeit oft genutzte Codeteile in Funktionen (bzw. auch Prozeduren unter Pascal) zu verpacken um so Flexibilität als auch Übersichtlichkeit zu steigern. Wer schonmal was in C geschrieben hat, der wird sich jetzt sicherlich kein Kopfzerbrechen machen müssen. Funktionen werden in glSlang genauso nach folgendem Prinzip deklariert :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
RückgabeTyp FunktionsName(Typ0 Argument0, Typ1, Argument1, ... , TypN, ArgumentN)&lt;br /&gt;
 {&lt;br /&gt;
 return RückgabeWert;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, außerdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach außen übergeben soll, muss dieses Argument mit dem Typenqualifizierer out (Siehe Kapitel 4.2) versehen werden. ''Arrays'' können nur als Eingabeargumente übergeben werden und dürfen nich dimensioniert als Argument verwendet werden, sondern müssen mit leeren Klammern argumentiert werden.&lt;br /&gt;
Ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void MeineFunktion(float EingabeWert; out float AusgabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 AusgabeWert = EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach außen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float MeineFunktion(float EingabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 return EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bietet genau die selbe Funktionalität wie das Beispiel darüber. Allerdings wird hier der berechnete Wert als Ergebnis der Funktion zurückgeliefert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float VektorSumme(float v[])&lt;br /&gt;
 {&lt;br /&gt;
 return v[0]+v[1]+v[2]+v[3];&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt darf ein Array als Argument keine Dimensionierung enthalten. Wenn man der Funktion also ein Array übergibt, sollte man vorher drauf achten das es entsprechend der in der Funktion genutzten Indizes dimensioniert wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==if-Anweisung==&lt;br /&gt;
&lt;br /&gt;
Selektion über eine if-Anweisung darf auch in keiner Hochsprache fehlen. Genauso wie in C oder Delphi erwartet auch hier die If-Anweisung einen boolschen Ausdruck (Wahr oder Falsch) und wird dann ausgeführt (wahr) bzw. verzweigt auf ein (wenn vorhanden) else (falsch). Verschachtelung ist wie erwartet auch möglich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis : ''' &lt;br /&gt;
Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten im Fragmentshader kein Early-Out, was zur Folge hat das bei einer If-Anweisung immer alle Zweige ausgeführt werden. Am Ende wird dann aber nur ein Ergebnis geschrieben, die anderen verworfen. Auf solchen Karten bringen If-Anweisungen also im Normalfall keine Geschwindigkeitssteigerung, sondern oft eher das Gegenteil.&lt;br /&gt;
Neuere SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall, da hier dynamische Verzweigungen und auch Early-Out von der Hardware implementiert werden.&lt;br /&gt;
&lt;br /&gt;
==Schleifen==&lt;br /&gt;
&lt;br /&gt;
Auch Schleifen, ein wichtiges Konzept jeder Hochsprache haben ihren Weg in glSlang gefunden. Unterstützt werden folgende Schleifentypen :&lt;br /&gt;
&lt;br /&gt;
* '''for'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
do&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
 while (Durchlaufbedingung)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hinweis :''' Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten Schleifen nicht in Hardware. Schleifen werden dann beim Kompilieren vom Treiber entrollt, wodurch natürlich Shader mit weitaus mehr Instruktionen als erwartet generiert werden. Von daher sollte man auf solchen Karten möglichst auf Schleifen verzichten, oder diese nur recht kurz halten. Bei SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Variablen, Attribute und Konstanten=&lt;br /&gt;
Nachdem wir uns nun lange genug mit den minderinterssanten Elementen der glSlang-Syntax beschäftigt haben, gehts jetzt endlich an die wirklich interessanten Dinge. Wie schon ARB_VP/ARB_FP bringt auch glSlang jede Menge eingabauter Variablen, Attribute und Konstanten mit, deren Aliase sie recht leicht identifizierbar machen (ganz im Gegensatz zum Indexgewusel bei den DX-Shadern).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Vertex Shader==&lt;br /&gt;
Exklusiv im Vertex Shader stehen die folgenden Variablen zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Position    muss geschrieben werden&lt;br /&gt;
:Dieser Variable '''muss''' im Vertexshader ein Wert zugewiesen werden, wird dies nicht getan ist das Ergebnis (sprich die Position des Vertex) undefiniert. Vorgesehen ist diese Variable für die ''homogene Position des Vertex'' und wird u.a. zum Clipping und Culling verwendet. Sie darf natürlich auch (mehrfach) geschrieben und ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* float gl_PointSize    kann geschrieben werden&lt;br /&gt;
:Diese Variable wurde dazu vorgesehen um dort im VertexShader die Punktgröße in Pixeln hineinzuschreiben.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_ClipVertex    kann geschrieben werden&lt;br /&gt;
:Falls genutzt, sollten hier die Vertexkoordinaten die im Zusammenhang mit benutzerdefinierten Clippingplanes genutzt werden abgelegt werden. Wichtig ist, das gl_ClipVertex im selben Koordinatenraum wie die Clippingplane definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Attribute im Vertex Shader==&lt;br /&gt;
&lt;br /&gt;
Folgende Attribute stehen nur im Vertex Shader zur Verfügung und '''können nur gelesen werden''' :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Color&lt;br /&gt;
: Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_SecondaryColor&lt;br /&gt;
:Sekundärer Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_Normal&lt;br /&gt;
:Normale des Vertex.&lt;br /&gt;
* vec4 gl_Vertex&lt;br /&gt;
:Koordinaten des Vertex;&lt;br /&gt;
* vec4 gl_MultiTexCoord0..7&lt;br /&gt;
:Texturkoordinaten auf Textureinheit 0..7.&lt;br /&gt;
* float gl_FogCoord&lt;br /&gt;
:Nebelkoordinate des Vertex. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Fragment Shader==&lt;br /&gt;
&lt;br /&gt;
Im Fragment Shader sind folgende Variablen exklusiv nutzbar :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragColor&lt;br /&gt;
: Speichert den Farbwert des Fragmentes, der von folgenden Funktionen der festen Pipeline genutzt wird. Wird dieser Variable nichts zugewiesen, so ist ihr Inhalt undefiniert und darauf aufbauende Ergebnisse ebenfalls.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragData[0..15]&lt;br /&gt;
: Ersetzt gl_FragColor bei der Verwendung von multiplen Rendertargets. &lt;br /&gt;
&lt;br /&gt;
* float gl_FragDepth&lt;br /&gt;
: Durch schreiben dieser Variable kann man den von der festen Funktionspipeline ermittelten Tiefenwert überspringen, der mit {{INLINE_CODE|gl_FragCoord.z}} ausgelesen werden kann. Wird dieser Wert nicht geschrieben, nutzen folgende Funktionen der Pipeline den vorher fest berechneten Wert.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragCoord    nur lesen&lt;br /&gt;
: In dieser Variable ist die Position des Fragmentes relativ zur Fensterposition im Format x,y,z,1/w abgelegt, wobei z den von der festen Funktionspipeline berechneten Tiefenwert enthält.&lt;br /&gt;
&lt;br /&gt;
* bool gl_FrontFacing    nur lesen&lt;br /&gt;
: Gibt an ob das Fragment zu einer nach vorne zeigenden Primitive gehört (=true). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bezug auf {{INLINE_CODE|gl_FragColor}} und {{INLINE_CODE|gl_FragDepth}} sei noch anzumerken das diese ''nicht'' in den Wertebereich 0..1 gebracht werden müssen, da dies später durch die feste Funktionspipeline automatisch gemacht wird.&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Varyings==&lt;br /&gt;
&lt;br /&gt;
Wie bereits in Kapitel 4.2 erwähnt, stellen Varyings eine Schnittstelle zwischen dem Vertex und dem Fragment Shader dar. Sie werden im Vertex Shader geschrieben und können dann im Fragment Shader ausgelesen werden, ohne das die folgenden Varyings dafür explizit deklariert werden müssen :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontColor&lt;br /&gt;
: Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackColor&lt;br /&gt;
: Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_TexCoord[x]&lt;br /&gt;
: Texturkoordinaten des Vertex auf Textureinheit x, wobei x die von der Hardware zur Verfügung gestellte Zahl der Textureinheiten-1 nicht überschreiten darf.&lt;br /&gt;
&lt;br /&gt;
* float gl_FogFragCoord&lt;br /&gt;
: Nebelkoordinate des Fragmentes. &lt;br /&gt;
&lt;br /&gt;
Die Varyings {{INLINE_CODE|gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor}} und {{INLINE_CODE|gl_BackSecondaryColor}} können im FragmentShader nur unter den Aliases gl_Color bzw. gl_SecondaryColor gelesen werden. Welcher Wert des Vertex Shaders im Fragment Shader dort eingesetzt wird ist abhängig davon ob das Fragment zu einer nach vorne oder nach hinten zeigenden Primitive gehört.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Konstanten==&lt;br /&gt;
Auch diverse Konstanten wurden definiert um darauf schnell im Shader zugreifen zu können. In den Klammern stehen die von einer GL-Implementation als Mindestanforderung anzubietenden Werte. Alle Konstanten sind sowohl im Vertex als auch im Fragment Shader abrufbar :&lt;br /&gt;
&lt;br /&gt;
: OpenGL 1.0/1.2 :&lt;br /&gt;
* int gl_MaxLights (8)&lt;br /&gt;
* int gl_MaxClipPlanes (6)&lt;br /&gt;
* int gl_MaxTextureUnits (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: ARB_Fragment_Program :&lt;br /&gt;
* int gl_MaxTextureCoordsARB (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Vertex_Shader :&lt;br /&gt;
* int gl_MaxVertexAttributesGL2 (16)&lt;br /&gt;
* int gl_MaxVertexUniformFloatsGL2 (512)&lt;br /&gt;
* int gl_MaxVaryingFloatsGL2 (32)&lt;br /&gt;
* int gl_MaxVertexTextureUnitsGL2 (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Fragment_Shader :&lt;br /&gt;
* int gl_MaxFragmentTextureUnitsGL2 (2)&lt;br /&gt;
* int gl_MaxFragmentUniformFloatsGL2 (64)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Uniformvariablen==&lt;br /&gt;
&lt;br /&gt;
Um den Zugriff auf OpenGL-Staten zu vereinfachen wurden in glSlang diverse Uniformvariablen zur direkten Verwendung im Shader eingebaut. Wie gewohnt wurden auch hier sinnvolle Namen verwendet, so dass eine tiefere Erklärung unnötig sein dürfte :&lt;br /&gt;
&lt;br /&gt;
* mat4 gl_ModelViewMatrix&lt;br /&gt;
* mat4 gl_ProjectionMatrix&lt;br /&gt;
* mat4 gl_ModelViewProjectionMatrix&lt;br /&gt;
* mat3 gl_NormalMatrix&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die invertierten und anschließend transponierten oberen 3x3 Werte der {{INLINE_CODE|gl_ModelViewMatrix}}.&lt;br /&gt;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
* float gl_NormalScale&lt;br /&gt;
: Gibt den unter OpenGL festgelegten Faktor zur Skalierung der Normalen zurück.&lt;br /&gt;
&lt;br /&gt;
* struct gl_DepthRangeParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_DepthRangeParameters&lt;br /&gt;
{&lt;br /&gt;
 float near;&lt;br /&gt;
 float far;&lt;br /&gt;
 float diff;&lt;br /&gt;
};&lt;br /&gt;
gl_DepthRangeParameters gl_DepthRange;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_PointParameters&lt;br /&gt;
{&lt;br /&gt;
 float size;&lt;br /&gt;
 float sizeMin;&lt;br /&gt;
 float sizeMax;&lt;br /&gt;
 float fadeThresholdSize;&lt;br /&gt;
 float distanceConstantAttenuation;&lt;br /&gt;
 float distanceLinearAttenuation;&lt;br /&gt;
 float distanceQuadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_PointParameters gl_Point;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_MaterialParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 emission;&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 float shininess;&lt;br /&gt;
};&lt;br /&gt;
gl_MaterialParameters gl_FrontMaterial;&lt;br /&gt;
gl_MaterialParameters gl_BackMaterial;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightSourceParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 vec4 position;&lt;br /&gt;
 vec4 halfVector;&lt;br /&gt;
 vec3 spotDirection;&lt;br /&gt;
 float spotExponent;&lt;br /&gt;
 float spotCutoff;&lt;br /&gt;
 float spotCosCutoff;&lt;br /&gt;
 float constantAttenuation;&lt;br /&gt;
 float linearAttenuation;&lt;br /&gt;
 float quadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_LightSourceParameters gl_LightSource[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelParameters gl_LightModel;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 sceneColor;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelProducts gl_FrontLightModelProduct;&lt;br /&gt;
gl_LightModelProducts gl_BackLightModelProduct;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
};&lt;br /&gt;
gl_LightProducts gl_FrontLightProduct[gl_MaxLights];&lt;br /&gt;
gl_LightProducts gl_BackLightProduct[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* vec4 gl_TextureEnvColor[gl_MaxFragmentTextureUnitsGL2]&lt;br /&gt;
* vec4 gl_EyePlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
*struct gl_FogParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_FogParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 color;&lt;br /&gt;
 float density;&lt;br /&gt;
 float start;&lt;br /&gt;
 float end;&lt;br /&gt;
 float scale;&lt;br /&gt;
};&lt;br /&gt;
gl_FogParameters gl_Fog;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese recht umfangreiche GL-Stateliste sollte eigentlich jeden Bedarf decken und momentan gibts kaum einen OpenGL-Status den man so nicht in einem Shader abfragen bzw. nutzen kann.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Funktionen=&lt;br /&gt;
glSlang ist mit diversen Skalar- und Vektorfunktionen ausgestattet, die teilweise (idealerweise) sogar direkt in der Hardware ausgeführt werden, weshalb einer fertigen Funktion ggü. gleichwertigen eigenen Berechnungen immer der Vorzug zu geben ist.&lt;br /&gt;
{{Hinweis| ''genType'' kann vom Type float, vec2, vec3 oder vec4 sein, ''mat'' vom Typ mat2, mat3 oder mat4.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie und Winkel==&lt;br /&gt;
Alle übergebenen Winkel sollten, soweit nicht anders vermerkt, in Radien angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* genType radians (genType degrees)&lt;br /&gt;
: Wandelt von Grad nach Radien. &lt;br /&gt;
* genType degrees (genType radians)&lt;br /&gt;
: Wandelt von Radien nach Grad.&lt;br /&gt;
* genType sin (genType x)&lt;br /&gt;
: Gibt den Sinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType x)&lt;br /&gt;
: Gibt den Kosinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType x)&lt;br /&gt;
: Gibt den Tangens von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType asin (genType x)&lt;br /&gt;
: Liefert den Arcsinus von x zurück, also den Winkel dessen Sinus x ergeben würde.&lt;br /&gt;
* genType acos (genType x)&lt;br /&gt;
: Liefert den Arckosinus von x zurück, also den Winkel dessen Cosinus x ergeben würde.&lt;br /&gt;
* genType atan (genType y, genType x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x/y ergeben würde.&lt;br /&gt;
* genType atan (genType y_over_x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x über y ergeben würde.&lt;br /&gt;
&lt;br /&gt;
==Hyperbolisch==&lt;br /&gt;
* genType sinh (genType x)&lt;br /&gt;
: Gibt den Sinus Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) * 0.5; )&lt;br /&gt;
* genType cosh (genType x)&lt;br /&gt;
: Gibt den Kosinus Hyperbolicus von x zurück. (return = (exp(x) + exp(-x)) * 0.5; )&lt;br /&gt;
* genType tanh (genType x)&lt;br /&gt;
: Gibt den Tangens Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) / (exp(x) + exp(-x)); )&lt;br /&gt;
* genType asinh (genType angle)&lt;br /&gt;
: Gibt den Areasinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x + 1.0)); )&lt;br /&gt;
* genType acosh (genType angle)&lt;br /&gt;
: Gibt den Areakosinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x - 1.0)); )&lt;br /&gt;
* genType atanh (genType x)&lt;br /&gt;
: Gibt den Areatangens Hyperbolicus von x zurück. (return = log((1.0 + x) / (1.0 - x)) * 0.5; )&lt;br /&gt;
&lt;br /&gt;
==Exponentiell==&lt;br /&gt;
* genType pow (genType x, genType y)&lt;br /&gt;
: Gibt x hoch y zurück.&lt;br /&gt;
* genType exp (genType x)&lt;br /&gt;
: Gibt e(Eulerischezahl ≈ 2.7182) hoch x zurück.&lt;br /&gt;
* genType log (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis e(Eulerischezahl ≈ 2.7182) von x zurück.&lt;br /&gt;
* genType exp2 (genType x)&lt;br /&gt;
: Gibt 2 hoch x zurück.&lt;br /&gt;
* genType log2 (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis 2 von x zurück.&lt;br /&gt;
* genType sqrt (genType x)&lt;br /&gt;
: Gibt die Wurzel von x zurück.&lt;br /&gt;
* genType inversesqrt (genType x)&lt;br /&gt;
: Gibt die umgekehrte Wurzel von x zurück.&lt;br /&gt;
&lt;br /&gt;
==Standardfunktionen==&lt;br /&gt;
* genType abs (genType x)&lt;br /&gt;
: Liefert den absoluten Wert von x zurück.&lt;br /&gt;
* genType sign (genType x)&lt;br /&gt;
: Gibt -1.0 zurück, wenn x &amp;lt; 0.0, 0.0 wenn x = 0.0 und 1.0 wenn x &amp;gt; 0.0.&lt;br /&gt;
* genType roundeven(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. Bei &amp;quot;.5&amp;quot; Werten wird zur nächsten geraden Zahl gerundet.&lt;br /&gt;
* genType round(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. &amp;quot;.5&amp;quot; Werte werden je nach Implementation anders behandelt.&lt;br /&gt;
* genType trunc(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert dessen Absoluterwert nicht größer ist als der Absolutewert von x&lt;br /&gt;
* genType floor (genType x)&lt;br /&gt;
: Gibt denn größten Integerwert zurück, der kleiner oder gleich x ist.&lt;br /&gt;
* genType ceil (genType x)&lt;br /&gt;
: Gibt den kleinsten Integerwert zurück, der größer oder gleich x ist.&lt;br /&gt;
* genType fract (genType x)&lt;br /&gt;
: Gibt den Nachkommateil von x zurück.&lt;br /&gt;
* genType mod (genType x, float y) &lt;br /&gt;
* genType mod (genType x, genType y)&lt;br /&gt;
: Gibt den Modulus zurück. (result = x - y * floor(x / y)) &lt;br /&gt;
* genType min (genType x, genType y) &lt;br /&gt;
* genType min (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn y &amp;lt; x, ansonsten x. &lt;br /&gt;
* genType max (genType x, genType y) &lt;br /&gt;
* genType max (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn x &amp;lt; y, ansonsten x. &lt;br /&gt;
* genType clamp (genType x, genType minVal, genType maxVal) &lt;br /&gt;
* genType clamp (genType x, float minVal, float maxVal)&lt;br /&gt;
: Zwängt x in den Bereich minVal ... maxVal .  (return = min(minVal, max(maxVal, x)))&lt;br /&gt;
* genType mix (genType x, genType y, genType a)&lt;br /&gt;
* genType mix (genType x, genType y, float a)&lt;br /&gt;
: Liefert den linearen Blend zwischen x und y zurück. (result = x * (1 - a) + y * a) &lt;br /&gt;
* genType step (genType edge, genType x)&lt;br /&gt;
* genType step (float edge, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt; edge, ansonsten 1.0. &lt;br /&gt;
* genType smoothstep (genType edge0, genType edge1, genType x)&lt;br /&gt;
* genType smoothstep (float edge0, float edge1, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge0 und 1.0 wenn x &amp;gt;= edge1. Dazwischen wird eine weiche Hermite Interpolation durchgeführt.&lt;br /&gt;
  float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);&lt;br /&gt;
  result = t * t * (3.0 - 2.0 * t)&lt;br /&gt;
&lt;br /&gt;
==Geometrie==&lt;br /&gt;
* float length (genType x)&lt;br /&gt;
: Gibt die Länge des Vektors x (= sqrt(x[0]² + x[1]² + ... + x[n]²) zurück. &lt;br /&gt;
* float distance (genType p0, genType p1)&lt;br /&gt;
: Gibt die Distanz zwischen den zwei Vektoren p0 un p1 (= length(p0-p1)) zurück. &lt;br /&gt;
* float dot (genType x, genType y)&lt;br /&gt;
: Gibt das Punktprodukt von x und y zurück (=x[0]*y[0] + x[1]*y[1] + ... + x[n]*y[n]). &lt;br /&gt;
* vec3 cross (vec3 x, vec3 y)&lt;br /&gt;
: Gibt das Kreuzprodukt von x und y zurück. &lt;br /&gt;
* genType normalize (genType x)&lt;br /&gt;
: Normalisiert den Vektor x auf die Länge 1. &lt;br /&gt;
* vec4 ftransform()&lt;br /&gt;
: Nur im Vertex Shader. Die Funktion stellt sicher, das das eingehende Vertex haargenau so transformiert wird wie in der festen Funktionspipeline. gl_Position = ftransform() wird dann also gebraucht, wenn in mehreren Durchgängen sowohl im Shader als auch in der festen Pipeline gerendert wird, um sicherzustellen das in beiden Fällen die gleiche Vertexposition herauskommt. &lt;br /&gt;
* genType faceforward (genType N, genType I, genType Nref)&lt;br /&gt;
: Gibt einen nach vorne zeigenden Vektor N zurück. (If dot(NRef, I) &amp;lt; 0 return N else return -N) &lt;br /&gt;
* genType reflect (genType l, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (result = l - 2.0 * dot(N,I) * N; )&lt;br /&gt;
* genType refract (genType l, genType N, float eta)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N mit dem Brechungsindex eta gebrochenen Vektor l zurück. &lt;br /&gt;
::gentype k = 1.0 - eta * eta * (1.0 - dot(N, l) * dot(N, l))&lt;br /&gt;
::if (k &amp;lt; 0.0)&lt;br /&gt;
:::result = 0.0&lt;br /&gt;
::else &lt;br /&gt;
:::result = eta * l - (eta * dot(N, l) * sqrt(k)) * N&lt;br /&gt;
&lt;br /&gt;
==Matrixfunktionen==&lt;br /&gt;
* mat matrixCompMult (mat x, mat y)&lt;br /&gt;
: Multipliziert Matrix X mit Matrix Y komponentenweise. Um eine normale lineare Matrixmultiplikation durchzuführen, sollte der &amp;quot;*&amp;quot;-Operator genutzt werden.&lt;br /&gt;
* mat transpose (mat m)&lt;br /&gt;
: Gibt die transponierte Matrix von m zurück.&lt;br /&gt;
* mat invert (mat m)&lt;br /&gt;
: Gibt die invertierte Matrix von m zurück. Also die Matrix, die mit m multipliziert die Normalmatrix ergeben würde.&lt;br /&gt;
* mat outerProduct(vec c, vec r)&lt;br /&gt;
: Gibt eine eine Matrix als Ergebnis der linearen (return[m, n] = c[m] * r[n])-Operation zurück.&lt;br /&gt;
&lt;br /&gt;
==Vektorvergleiche==&lt;br /&gt;
Die meisten Vektorvergleichsfunktionen liefern als Ergebnis einen boolvektor zurück, da die Vergleiche per Komponente stattfinden. Wenn man also x = vec4(1.0, 3.0, 0.0, 0.0) mit y = vec4(2.0, 1.5, 1.5, 0.0) via lessThan(x, y) vergleicht, erhält man als Ergebnis bvec(true, false, true, false).&lt;br /&gt;
&lt;br /&gt;
* bvec lessThan (vec x, vec y)&lt;br /&gt;
* bvec lessThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt; y zurück. &lt;br /&gt;
* bvec lessThanEqual (vec x, vec y)&lt;br /&gt;
* bvec lessThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt;= y zurück. &lt;br /&gt;
* bvec greaterThan (vec x, vec y)&lt;br /&gt;
* bvec greaterThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt; y zurück. &lt;br /&gt;
* bvec greaterThanEqual (vec x, vec y)&lt;br /&gt;
* bvec greaterThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt;= y zurück. &lt;br /&gt;
* bvec equal (vec x, vec y)&lt;br /&gt;
* bvec equal (ivec x, ivec y)&lt;br /&gt;
* bvec equal (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x == y zurück. &lt;br /&gt;
* bvec notEqual (vec x, vec y)&lt;br /&gt;
* bvec notEqual (ivec x, ivec y)&lt;br /&gt;
* bvec notEqual (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x != y zurück. &lt;br /&gt;
* bool any (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn mindestens eine der Komponenten von x true ist.&lt;br /&gt;
* bool all (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn alle Komponenten von x true sind. &lt;br /&gt;
* bvec not (bvec x)&lt;br /&gt;
: Liefert die logische Negation von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Texturenzugriffe==&lt;br /&gt;
&lt;br /&gt;
Diese wichtige Funktionskategorie dient dazu, Werte aus einer an eine Textureinheit gebundenen Textur zu ermitteln. Die Texturenzugriffe können sowohl im Vertex (!) als auch im Fragment Shader ausgeführt werden, wobei der optionale Parameter bias im Vertex Shader ignoriert wird. Allerdings gibt es zusätzlich Funktionen die auf &amp;quot;Lod&amp;quot; enden und nur im Vertex Shader genutzt werden dürfen um eben dieses Manko zu umgehen. Funktionen mit dem Suffix &amp;quot;Proj&amp;quot; geben einen projizierten Texturenwert zurück.&lt;br /&gt;
&lt;br /&gt;
: '''1D-Texturen :'''&lt;br /&gt;
* vec4 texture1D (sampler1D sampler, float coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 texture1DLod (sampler1D sampler, float coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''2D-Texturen :'''&lt;br /&gt;
* vec4 texture2D (sampler2D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''3D-Texturen :'''&lt;br /&gt;
* vec4 texture3D (sampler3D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture3DProj (sampler3D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture3DProjLod (sampler3D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Cubemap :'''&lt;br /&gt;
* vec4 textureCube (samplerCube sampler, vec3 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
*vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Tiefentextur (Shadowmap) :'''&lt;br /&gt;
* vec4 shadow1D (sampler1DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow2D (sampler2DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
* vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow1DProjLod (sampler1DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
* vec4 shadow2DProjLod (sampler2DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Texturegröße :'''&lt;br /&gt;
Mit den textureSize-Befehlen kann die Größe einer Textur bestimmt werden, wobei lod das Mipmaplevel angibt:&lt;br /&gt;
*int textureSize(sampler1D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2D sampler, int lod)&lt;br /&gt;
*ivec3 textureSize(sampler3D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(samplerCube sampler, int lod)&lt;br /&gt;
*int textureSize(sampler1DShadow sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2DShadow sampler, int lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie bereits eingangs gesagt ist dieses Kapitel ein sehr wichtiges, denn eine 3D-Szene ohne Texturen ist heute kaum denkbar. Darüber hinaus lassen sich durch Texturenzugriffe recht viele interessante Sachen machen, z.B. ein einfacher Blurfilter oder das freie überblenden bestimmter Texturenteile. Deshalb führe ich hier kurz ein paar Beispiele an, welche die Nutzung dieser Funktionen verdeutlichen sollen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Eine Textur gebunden die einfach ausgegeben werden soll&lt;br /&gt;
&lt;br /&gt;
''Im Vertex Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
Der Vertex Shader ist recht minimal. Neben der homogenen Vertexposition leiten wir hier nur die im OpenGL-Programm angegebenen Texturkoordinaten weiter. ''Dies ist aber unbedingt nötig!'' Ohne die letzte Zeile hätten wir im Fragment Shader keine gültigen Texturkoordinaten auf TMU0, was in einer Fehldarstellung enden würde.&lt;br /&gt;
&lt;br /&gt;
''im Fragment Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSampler;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(texSampler, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zuerst deklarieren wir hier einen 2D-Texturensampler, wichtig : '''Texturensampler müssen IMMER als uniform deklariert werden!''' In der Hauptfunktion weisen wir dann einfach den über die Funktion texture2D aus unserer gebundenen Textur ausgelesenen Farbwert, anhand der vom Vertex Shader übergebenen Texturkoordinaten, zu.&lt;br /&gt;
{{Vorlage:Hinweis|Der Uniform-Integer für den Sampler referenziert '''nicht''' den Namen (die ID) des Texturobjektes, sondern die Nummer der Texturunit.}}&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Zwei Texturen, jeweils auf TMU0 und TMU1. Fragmentfarbe soll eine Multiplikation der beiden Texturen darstellen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielfall (der recht häufig vorkommt) müssen wir im Programm festlegen, ''welcher Sampler welche Textureinheit adressiert'', genau deshalb müssen die Texturensampler auch als uniform deklariert werden. Die Standardtextureneinheit eines Samplers ist TMU0, was in unserem Falle natürlich nicht brauchbar ist. Also müssen wir unserem zweiten Textursampler im Programm mitteilen das er seine Daten aus TMU1 beziehen soll :&lt;br /&gt;
&lt;br /&gt;
 glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&lt;br /&gt;
Dies ist also unbedingt zu machen, sobald ein Texturensampler eine Textureinheit &amp;gt; GL_TEXTURE_0 adressieren will. Die Textureneinheit des Samplers lässt sich also nicht im Shader selbst festlegen. Der Fragment Shader ist nun allerdings schnell hergeleitet (Vertex Shader verändert sich nicht, da TMU1 die Texturkoordinaten auch von TMU0 bezieht) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
im Fragment Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSamplerTMU0;&lt;br /&gt;
uniform sampler2D texSamplerTMU1;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_FragColor = texture2D(texSamplerTMU0, vec2(gl_TexCoord[0])) *&lt;br /&gt;
                   texture2D(texSamplerTMU1, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich [[GLSL noise|Noisefunktionen]] nutzen, mit deren Hilfe sich eine gewisse &amp;quot;Zufälligkeit&amp;quot; simulieren lässt (wirklich zufällige Werte sind es natürlich nicht). Ein zurückgegebener Wert liegt dabei immer im Bereich [-1..1] und ist immer bei gleichem Eigabewert auch immer gleich. Die Verwendung empfiehlt sich derzeit allerdings eher nicht, da nur die 3DLabs Treiber die Funktionen unterstützen und eine Noisetextur wahrscheinlich performanter ist.&lt;br /&gt;
&lt;br /&gt;
* float noise1 (genType x)&lt;br /&gt;
* vec2 noise2 (genType x)&lt;br /&gt;
* vec3 noise3 (genType x)&lt;br /&gt;
* vec4 noise4 (genType x)&lt;br /&gt;
&lt;br /&gt;
==Discard==&lt;br /&gt;
Eigentlich keine Funktion, sondern eine Abbruchbedingung '''nur im Fragment Shader'''. Das Schlüsselwort {{INLINE_CODE|discard}} verwirft das aktuell bearbeitete Fragment und beendet gleichzeitig den Shader. Es kann z.B. genutzt werden um Alphamasking manuell durchzuführen.&lt;br /&gt;
Man sollte dabei jedoch beachten dass ein Großteil der aktuellen Hardware kein &amp;quot;early-out&amp;quot; (frühes Beenden) im Fragmentshader unterstützt. Wenn dort also ein {{INLINE_CODE|discard}} auftaucht, wird trotzdem auch der Code danach ausgeführt und einfach verworfen. Einen Geschwindigkeitsvorteil durch diesen Befehl wird man also erst auf neueren Karten feststellen, die dieses Faeature auch so unterstützen wie es angedacht war. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispielshader=&lt;br /&gt;
Wen bis hierhin nicht der Mut verlassen hat, und wer aufmerksam gelesen hat, dürfte jetzt also zumindest in der Lage sein kleinere Shader in glSlang zu schreiben und diese auch im Programm zu nutzen. Ich habe im Themenbereich &amp;quot;glSlang&amp;quot; versucht alle Bereiche der Shadersprache selbst anzusprechen und hoffe das auch brauchbar rübergebracht zu haben. Um oben erlerntes (hoffe ich doch mal) nochmal zu vertiefen werde ich jetzt (wie ich das bereits bei meinem ARB_VP-Tutorial getan habe) einen simplen Beispielshader (Vertex und Fragment Shader) auseinanderpflücken um so u.a. auch die Programmstruktur für alle die in C nicht so bewandert sind zu erörtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Vertex Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_FrontColor   = gl_Color * GlobalColor;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie gesagt recht simpel. Angefangen wird mit der Deklaration einer globalen Uniformvariable namens {{INLINE_CODE|GlobalColor}}. Wie wir uns erinnern gibt der Typenqualifizierer uniform an, das wir den Wert dieser Variable (ein 4-Komponentenvektor, da Farbwerte aus R,G,B und A bestehen) in unserem Programm an den Shader übermitteln.&lt;br /&gt;
&lt;br /&gt;
Danach gehts ohne Umwege direkt in unsere Hauptfunktion, da wir im Vertex Shader keine anderen Funktionen benötigen. Dort berechnen wir zuerst die homogene Position unseres Vertex, die sich aus der eingehenden Vertexposition multipliziert mit der Modelansichtsmatrix ergibt. Wie schonmal gesagt '''muss diesem Wert etwas zugewiesen werden''', da sonst alle darauf aufbauenden Funktionen unvorhersehbare Ergebnisse liefern.&lt;br /&gt;
Außerdem wollen wir die Frontfarbe unseres Vertex jedesmal mit der im Programm übergebenen GlobalColor multiplizieren, so dass wir den Farbwert der gesamten Szene aus unserem Programm heraus manipulieren können. Zu guterletzt geben wir dann noch unsere aus der festen Funktionspipeline erhaltenen Texturkoordinaten auf Textureinheit 0 weiter. Wenn im Fragmentshader Texturkoordinaten verwendet werden, '''muss das getan werden'''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Fragment Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
uniform sampler2D Texture2;&lt;br /&gt;
uniform sampler2D Texture3;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec2 TexCoord = vec2( gl_TexCoord[0] );&lt;br /&gt;
 vec4 RGB      = texture2D( Texture0, TexCoord );&lt;br /&gt;
&lt;br /&gt;
 gl_FragColor  = texture2D(Texture1, TexCoord) * RGB.r +&lt;br /&gt;
                 texture2D(Texture2, TexCoord) * RGB.g +&lt;br /&gt;
                 texture2D(Texture3, TexCoord) * RGB.b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier passiert nicht wirklich viel Großartiges. Wir deklarieren beim Shaderanfang zuerst vier Texturensampler, da wir insgesamt vier verschiedene Texturen im Shader auslesen wollen, eine Verlaufstextur und drei Oberflächentexturen. Auch hier sei wieder gesagt das man Sampler '''immer als uniform deklarieren muss'''. In der Hauptfunktion deklarieren wir dann einen Farbvektor, der auch direkt einen Farbwert aus Textureinheit 0 zugewiesen bekommt. Auf Textureinheit 0 haben wir ihm Hauptprogramm eine Verlaufstextur gebunden, die angibt wie die drei folgenden Texturen ineinander geblendet werden.&lt;br /&gt;
Danach schreiben wir dann den Farbwert des Fragmentes, der '''im Fragment Shader ausgegeben werden muss'''. Der besteht wie einfach zu erkennen aus Farbwert von Textureinheit 1 * Rotwert von Textureinheit 0 + Farbwert von Textureinheit 2 * Grünwert von Textureinheit 0 + Farbwert von Textureinheit 3 * Blauwert von Textureinheit 0. So ist z.B. an Stellen an denen in der Verlaufstextur reines blau liegt nur die dritte Textur sichtbar.&lt;br /&gt;
&lt;br /&gt;
So viel also zu unserem kleinen Beispielshader. Er ist weder besonders toll noch besonders sinnvoll, sollte aber auch eher dazu dienen euch glSlang ein wenig zu veranschaulichen, was mir hoffentlich gelungen ist.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr in den vorangegangenen Kapiteln zumindest ein wenig aufgepasst habt, dann könnt ihr euch vor eurem inneren Auge hoffentlich vortstellen was der Shader macht : Er blendet drei Texturen weich anhand der Verlaufstextur ineinander über. Sowas kann man z.B. für ein Terrain nutzen, um dieses anhand einer Farbtextur zu texturieren. Für alle, die damit Probleme haben hier zwei Bilder die den Shader veranschaulichen. Links die Verlaufstextur, die angibt wo welche Textur wie stark gewichtet wird und rechts dann das Ergebnis :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; [[BILD:GLSL_sample_shader_a.jpg]] [[BILD:GLSL_sample_shader_b.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post Mortem=&lt;br /&gt;
Das wars also, meine &amp;quot;Einführung&amp;quot; in die OpenGL Shader Sprache. Ich hoffe es hat euch nicht gelangweilt und auch die von mir zur Verfügung gestellten Informationen haben euch hoffentlich ausgereicht. Mit der Veröffentlichung dieser Einführung geht übrigens auch die Eröffnung eines Shaderforums hier auf der DGL einher, in der ihr dann also fleissig Fragen zum Thema stellen oder eure Shader präsentieren könnt. In diesem Post Mortem gehe ich jetzt noch kurz auf die Zukunft von glSlang ein und zeige ein paar Screenshots (damit die Augen entspannen können), bevor ihr euch dann selbst in die Shaderwelt stürzen könnt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
Anbei ein paar exemplarische Screenshots. Da man mit GLSL aber alle möglichen Effekte berechnen kann (u.a. auch 1:1 die feste Funktionspipeline) ist es hier unmöglich einen Überblick aller möglichen Techniken zu geben.&lt;br /&gt;
&lt;br /&gt;
[[Datei:tut_glsl_eigenershader_01.png]] [[Datei:tut_glsl_eigenershader_02.png]] [[Datei:tut_glsl_eigenershader_03.png]]&lt;br /&gt;
&lt;br /&gt;
Wie im ersten (und dritten) Screenshot zu sehen ist es natürlich auch möglich mehrere Techniken innerhalb einer Szene zu nutzen. Hier sind letztendlich bis auf Hardwarelimitationen keine Grenzen gesetzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Als dieses Tutorial geschrieben wurde, war noch nicht ganz abzusehen dass bzw. ob sich GLSL auch durchsetzen würde. ARB-Shadr und NVidias cG waren damals die Platzhirsche, aber inzwischen werden ARB-Shader nicht mehr genutzt (und auch schon länger nicht mehr weiterentwickelt) und auch NVidia setzt primär auf GLSL. GLSL wird permanent weiterenwtickelt und Hersteller können dank des flexiblen Extensionsystems auch in GLSL eigene Extensions offenlegen um die aktuellsten Features (wie z.b. den Tesselator auf aktuellen ATI-Karten) nutzen zu können. GLSL gilt inzwischen auch offizielle die Shadersprache für OpenGL und wird permanent an die neusten technischen Entwicklungen im Grafikkartenbereich angepasst.&lt;br /&gt;
&lt;br /&gt;
Wer also unter OpenGL etwas mit Shadern machen möchte, kommt an GLSL nicht vorbei!&lt;br /&gt;
&lt;br /&gt;
Also viel Spaß beim Experimentieren und Shaderschreiben! Und nicht vergessen : Wir wollen sehen was ihr so treibt,&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_glsl2]]}}&lt;br /&gt;
[[Kategorie:Tutorial|GLSL]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25667</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25667"/>
				<updated>2012-04-21T11:02:46Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Standardfunktionen */ Kleinere Anpassungen &amp;amp; Formel für smoothstep&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Einleitung=&lt;br /&gt;
Hallo und willkommen bei meiner &amp;quot;Einführung&amp;quot; in GLSL (kurz für &amp;quot;Open'''GL''' '''S'''hading '''L'''anguage&amp;quot;), der offiziellen Hochlevel-Shadersprache von OpenGL. In diesem umfangreichen Dokument werde ich versuchen, sowohl auf die Nutzung (sprich das Laden und Anhängen von Shadern im Quellcode), als auch auf die Programmierung von Shadern selbst einzugehen, inklusive aller Sprachelemente der OpenGL Shadersprache. Es wird also auch recht viele Informationen zu der C-ähnlichen Programmstruktur und den von GLSL angebotenen Variablen und Attributen gehen. Am Ende dieser Einführung sollten alle die, die sich für das Thema interessieren, in der Lage sein, zumindest einfach Shader zu schreiben und auch in ihren Programmen zu nutzen. Außerdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von Khronoes veröffentlichten Shaderspezifikationen, und damit als alltägliches Nachschlagewerk, dienen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Wie auch schon mein ARB_VP-Tutorial richtet sich auch diese Einführung aufgrund ihrer Thematik eher an die fortgeschritteneren GL-Programmierer und neben sehr guten GL-Kenntnissen sollten sich alle, die sich daran versuchen wollen, mit den technischen Hintergründen der GL, wie z.B. dem Aufbau der Renderpipeline auskennen. Weiterhin sind C-Kenntnisse absolut erforderlich, da die Shader ja in einer an ANSI-C angelehnten Syntax geschrieben werden. Auch Begriffsdefinitionen zu Vertex oder Fragment werden zum Verständis dieser Einführung benötigt. Wer also noch am Anfang seiner GL-Karriere steht, dem wird dieses Dokument nicht viel nützen. Ganz nebenbei solltet ihr auch noch eine gehörige Portion Zeit (am besten nen kompletten Nachmittag) mitbringen, denn die folgende Kost ist nicht nur umfangreich, sondern auch manchmal recht schwer verdaulich.&lt;br /&gt;
&lt;br /&gt;
=Was ist GLSL?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei GLSL um eine Shadersprache, also um eine Hochsprache, in der man die programmierbaren Teile aktueller Grafikbeschleuniger nach eigenem Belieben programmieren kann. Sie stellt quasi den Nachfolger zu den in Assembler geschriebenen Vertex- und Fragmentprogrammen ([[GL_ARB_vertex_program]]/[[GL_ARB_fragment_program]]) dar und basiert auf ANSI C, erweitert um Vektor- und Matrixtypen sowie einige C++-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
Die in GLSL geschriebenen Programme nennen sich, angepasst an die Terminologie von RenderMan und DirectX, [[Shader]] (im Gegensatz zu &amp;quot;Programme&amp;quot; bei ARB_VP/FP) und werden entweder auf Eckpunkte (VertexShader), Fragmente (FragmentShader) angewendet, oder (neuerdings, ab Shadermodell 4.0) auch genutzt um Geometrie zu erstellen (Geometryshader). Andere Teile der Renderpipeline (z.B. die Rasterisierung) können momentan noch nicht durch Shader beeinflusst werden, was allerdings in Zukunft noch kommen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
GLSL wurde 2005 mit OpenGL 1.5 eingeführt. Während es in Sachen Treiber- und Hardwareunterstützung anfänglich noch dürftig aussah, wird man inzwischen keine Grafikkarte mehr kaufen können die nicht zumindest Vertex- und Fragmentshader beherscht. Geometrieshader hingegen sind relativ neu und wurden erst mit Shadermodell 4.0 eingeführt, hier ist es also unter Umständen noch möglich dass selbst aktuelle Treiber/Karten keine Geometrieshader beherrschen.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt man auch einen passenden OpenGL-Header der die für GLSL nötigen Funktionen exportiert. Ich verweise dazu auf unseren eigenen OpenGL-Header [[DGLOpenGL.pas]], der peermanent auf dem aktuellsten Stand gehalten wird und auch Support für Geometrieshader mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
&lt;br /&gt;
Die GL-Shadersprache &amp;quot;besteht&amp;quot; in ihrer aktuellen Version aus folgenden Extensions, fürs Verständnis wäre es nicht schlecht, wenn ihr euch zumindest die Einleitungen dazu durchlest :&lt;br /&gt;
* [[GL_ARB_shader_objects]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shader_objects.txt Originalspezifikation])&lt;br /&gt;
: Definiert die API-Aufrufe, die zum Erstellen, Kompilieren, Linken, Anhängen und Aktivieren von Shader- und Programmobjekten nötig sind. &lt;br /&gt;
* [[GL_ARB_vertex_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Vertexebene hinzu. &lt;br /&gt;
* [[GL_ARB_fragment_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Fragmentebene hinzu. &lt;br /&gt;
* [[GL_ARB_shading_language_100]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shading_language_100.txt Originalspezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis''' : Seit OpenGL 2.0 ist GLSL Teil des Kerns. Wenn die Karte also OpenGL 2.0 unterstützt, dann unterstützt sie auch (zumindest in Software) Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sprachversionen==&lt;br /&gt;
&lt;br /&gt;
Neben der OpenGL-Version und dem vorhandenen Shadermodell (das eher an DirectX ausgerichtet ist), bietet auch GLSL verschiedene Versionen, die entsprechend erweiterte Funktionalität bieten.&lt;br /&gt;
&lt;br /&gt;
Auslesen kann man die verfürgbare GLSL-Version wie folgt:&lt;br /&gt;
&lt;br /&gt;
 glGetString(GL_SHADING_LANGUAGE_VERSION)&lt;br /&gt;
&lt;br /&gt;
Erst ab Version 1.4. kann man davon ausgehen dass GLSL alle Features des Shadermodells 4.0 liefert, ab 1.3 grob gesagt Shadermodell 3.0 (bei GLSL lässt sich das leider nicht so leicht unterteilen).&lt;br /&gt;
&lt;br /&gt;
Außerdem kann man seinem Shader eine Versionsnummer verpassen. Sollte der Shadercompiler (also Treiber bzw. Hardware) diese Version nicht unterstützen, gibt dieser eine Fehlermeldung heraus:&lt;br /&gt;
&lt;br /&gt;
 #version 1.50 &lt;br /&gt;
&lt;br /&gt;
''(Hinweis: Muss am Anfang des Shaders stehen)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&lt;br /&gt;
&lt;br /&gt;
Im Zuge der Vereinheitlichung der GL wird immer häufiger in Objekte gekapselt, deren API dann auch aneinander angelehnt ist. Ziel ist, dabei die Programmierung der GL uniform zu machen, so dass z.B. zwischen dem Erstellen und Verwalten eines Vertex-Buffer-Objektes oder eines Shader-Objektes kaum ein Unterschied besteht (demnächst kommen dann auch Pixel-Buffer-Objekte dazu). Mit glSlang wurden dann im Zuge dieser Aktion zwei neue Objekte eingeführt, deren Definition ihr euch unbedingt einprägen solltet:&lt;br /&gt;
&lt;br /&gt;
* '''Programmobjekt'''&lt;br /&gt;
:Ein Objekt, an das die Shader später angebunden werden. Bietet Funktionalität zum Linken der Shader und prüft dabei die Kompatibilität zwischen Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
* '''Shaderobjekt'''&lt;br /&gt;
:Dieses Objekt verwaltet den Quellcodestring eines Shaders und ist entweder vom Typ '''GL_VERTEX_SHADER''', '''GL_FRAGMENT_SHADER_ARB''' oder '''GL_GEOMETRY_SHADER'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
&lt;br /&gt;
Die Shadersprache ist keinesfalls final und es wurden bereits diverse Ausdrücke für zukünftige Verwendung reserviert, denn ein Ziel bei ihrer Entwicklung war es, sie so zukunftsorientiert zu gestalten, dass auch Grafikkarten der nächsten und übernächsten Generation voll ausgenutzt werden können. Damit einher geht die Tatsache, dass sich die Spezifikationen in Zukunft ändern/erweitern werden, weshalb man da immer einen Blick hineinwerfen sollte. Die Anlaufstelle dafür ist die [http://www.opengl.org/documentation/specs/ Spezifikationenliste auf OpenGL.org].&lt;br /&gt;
&lt;br /&gt;
=GLSL im Programm=&lt;br /&gt;
Bevor wir uns mit der Syntax von glSlang beschäftigen, zeige ich euch erstmal, wie ihr Shader in euer Programm einbindet und nutzt. Warum das zuerst? Ganz einfach deshalb, weil ihr dann das, was ihr im glSlang-Syntaxteil lernt, direkt in eurer Testanwendung verwenden könnt. Hoffe diese Entscheidung klingt logisch und findet Anklang.&lt;br /&gt;
&lt;br /&gt;
Zuerst benötigen wir natürlich unsere Objekte. Zum einen ein ''Programmobjekt'', an das unsere Shader gebunden werden, und zwei ''Shaderobjekte'', die den Quellcode unseres Vertex bzw. Fragment Shaders aufnehmen. Dazu wurde eigens der neue &amp;quot;Datentyp&amp;quot; {{INLINE_CODE|glHandle}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandle;&lt;br /&gt;
 VertexShaderObject   : GLhandle;&lt;br /&gt;
 FragmentShaderObject : GLhandle;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dieser Deklaration können wir dann damit beginnen unsere Objekte zu erstellen. Den Anfang macht das Programmobjekt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        := glCreateProgram;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgram]] erstellt uns oben ein leeres Programmobjekt und gibt ein gültiges Handle darauf zurück.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Erstellung unseres Vertex bzw. Fragment Shaders :&lt;br /&gt;
&lt;br /&gt;
 VertexShaderObject   := glCreateShader(GL_VERTEX_SHADER);&lt;br /&gt;
 FragmentShaderObject := glCreateShader(GL_FRAGMENT_SHADER);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShader]] dient zur Generierung eines leeren Shaderobjektes. Momentan unterstützt diese Funktion VertexShader und FragmentShader.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun also zwei gültige Shaderobjekte haben, wollen wir diese auch mit entsprechendem Quellcode versorgen :&lt;br /&gt;
&lt;br /&gt;
 glShaderSource(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSource(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSource]] setzen wir den Quellcode eines Shaderobjektes ''komplett'' neu. Zum Laden des Quellcodes bietet sich unter Delphi übrigens eine TStringList geradezu an. Es sollte beachtet werden, dass der Quellcode zu diesem Zeitpunkt ''nicht geparst'' wird, also keine Fehleruntersuchung stattfindet.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode wurde jetzt also an unsere Shaderobjekte gebunden und sollte dann natürlich auch noch kompiliert werden :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 glCompileShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShader]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der Shadercompiler (je nach Treiber) recht detaillierte Infos aus. Wie man an diese Infos kommt könnt ihr gleich nachlesen.&lt;br /&gt;
&lt;br /&gt;
Wenn unsere Shader dann kompiliert werden konnten, ist es Zeit, diese an unser anfangs erstelltes Programmobjekt anzuhängen :&lt;br /&gt;
&lt;br /&gt;
 glAttachShader(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachShader(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehängt wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteShader(VertexShaderObject);&lt;br /&gt;
 glDeleteShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Schluß müssen wir dann noch unsere ans Programmobjekt gebundenen Shader linken :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShader]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgram]] die angehangenen Shader zu einem ausführbaren Shader gelinkt. Folgende Bedingungen führen zu einem '''Linkerfehler''':&lt;br /&gt;
&lt;br /&gt;
* Die Zahl der von der Implementation unterstützten Attributvariablen wurde überschritten&lt;br /&gt;
* Der Speicherplatz für Uniformvariablen wurde überschritten&lt;br /&gt;
* Die Zahl der von der Implementation angebotenen Sampler wurde überschritten&lt;br /&gt;
* Die main-Funktion fehlt&lt;br /&gt;
* Die Liste der Varying-Variablen des Vertexshaders stimmt nicht mit der des Fragmentshaders überein&lt;br /&gt;
* Funktions- oder Variablenname nicht gefunden&lt;br /&gt;
* Eine gemeinsame Globale ist mit unterschiedlichen Werten oder Typen initialisiert worden&lt;br /&gt;
* Zwei Sampler unterschiedlichen Typs zeigen auf die selbe Textureneinheit&lt;br /&gt;
* Ein oder mehrere angehangene(r) Shader wurden nicht erfolgreich kompiliert&lt;br /&gt;
&lt;br /&gt;
Die Nutzung von glSlang im eigenen Programm ist wie oben erkennbar also nicht wirklich schwer und innerhalb kurzer Zeit realisiert. Natürlich ist es auch möglich z.B. nur einen VertexShader oder nur einen FragmentShader an ein Programmobjekt zu binden.&lt;br /&gt;
&lt;br /&gt;
Noch eine kleine Notiz zum Löschen der Shader mittel [[glDeleteShader]] : Da Shader(objekte) einen Referenzzähler besitzen und erst gelöscht werden wenn diese nirgendwo mehr benötigt werden, ist es nicht falsch diese vor dem Linkvorgang zu löschen. Allerdings spielt es letztendlich keine Rolle ob die Löschanweisung vorher der nachher ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fehlererkennung==&lt;br /&gt;
Natürlich wird es ohne Fehlerausgabe recht schwer, etwaige Probleme in einem Vertex- oder Fragmentshader zu finden. Doch auch in diesem Bereich wurde glSlang recht gut durchdacht und es wurden zwei Funktionen eingeführt, welche im Zusammenspiel die Fehlersuche recht einfach machen, nämlich [[glGetShaderInfoLog]] und [[glGetShader]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH}}. Erstere Funktion liefert uns einen Logstring, während uns letztere Funktion dessen Länge angibt. Der Logstring wird verändert, sobald ein Shader kompiliert oder ein Programm gelinkt wird.&lt;br /&gt;
&lt;br /&gt;
Um die Ausgabe dieses Logs so einfach wie möglich zu machen, bietet es sich an beide in einer einfach Funktion unterzubringen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function glSlang_GetInfoLog(pShader: GLHandleARB): String;&lt;br /&gt;
var&lt;br /&gt;
  blen, slen: GLInt;&lt;br /&gt;
  InfoLog: PGLCharARB;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  glGetShaderiv(glObject, GL_INFO_LOG_LENGTH , @blen);&lt;br /&gt;
  if blen &amp;gt; 1 then&lt;br /&gt;
  begin&lt;br /&gt;
    GetMem(InfoLog, blen * SizeOf(GLCharARB));&lt;br /&gt;
    glGetShaderInfoLog(pShader, blen, slen, InfoLog);&lt;br /&gt;
    Result := PChar(InfoLog);&lt;br /&gt;
    Dispose(InfoLog);&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist recht leicht erklärt : Zuerst lassen wir uns über {{INLINE_CODE|glGetShaderiv}} mitteilen wie lang der aktuelle Infolog ist. Sollte dort tatsächlich etwas drinstehen (blen &amp;gt; 1), dann lassen wir uns dessen Inhalt via {{INLINE_CODE|glGetShaderInfoLog}} in {{INLINE_CODE|InfoLog}} ausgeben und liefern diesen als Ergebnis zurück.&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt wird nur nach dem Kompilieren eines Shaders bzw. dem Linken eines Programmobjektes ein Infolog erstellt. Es bietet sich dadurch an, direkt danach einen solchen Aufruf zu machen :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 ShowMessage(glSlang_GetInfoLog(VertexShaderObject));&lt;br /&gt;
&lt;br /&gt;
Wenn unser Vertex Shader komplett fehlerfrei kompiliert werden konnte, dann sehen wir als Ergebnis nur einen leeren Dialog. Ist dies nicht der Fall, so werden wir vom Treiber mit recht detaillierten Fehlerinformationen &amp;quot;belohnt&amp;quot;, z.B. so :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL_error_vshader.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch das Infolog nach dem Linken des Programmobjektes dürfte, selbst wenn keine Fehler vorkommen, recht interessant sein, das sieht dann nämlich so aus :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL info programobject.jpg]]&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen, wird uns nach dem erfolgreichen Linken auch gesagt, ob und welcher Shader in Hardware bzw. Software läuft. Für Debuggingzwecke sicherlich eine mehr als brauchbare Information.&lt;br /&gt;
&lt;br /&gt;
==Shader benutzen==&lt;br /&gt;
Um den Shader auch für die nächsten Polygone zu benutzen oder Uniformparameter übergeben zu können, ruft man die Funktion&lt;br /&gt;
 glUseProgramt(ProgramObject);&lt;br /&gt;
um alle Shader zu deaktivieren, ruft man dieselbe Funktion mit dem Parameter 0.&lt;br /&gt;
&lt;br /&gt;
==Parameterübergabe==&lt;br /&gt;
Uniformparameter (mehr dazu später) stellen die Schnittstelle zwischen eurem Programm und dem Shader dar, werden also genutzt um Daten aus dem Programm heraus an einen Shader zu übergeben. Zur Übergabe dieser Parameter bietet OpenGL diverse Funktionen, die alle Abkömmlinge von [[glUniform]] sind. Während mit {{INLINE_CODE|glUniform4f}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fv}} ganze Matrizen schnell und einfach übergeben. Außerdem gibt es nun die Möglichkeit Uniformparameter direkt über ihren Namen, statt wie unter ARB_FP/VP über einen festen Index zu adressieren. Die Funktion [[glGetUniformLocationARB]] gibt anhand des übergebenen Parameternamens dessen Position zurück. Man kann also ganz einfach über den Namen drauf zugreifen :&lt;br /&gt;
&lt;br /&gt;
 glUniform3f(glGetUniformLocation(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1i(glGetUniformLocation(ProgramObject, PGLCharARB('texSamplerTMU3')), 3);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier, das man je nach Parametertyp auch die passende Anzahl von Argumenten übergibt. Also für einen 4-Komponenten Floatvektor {{INLINE_CODE|glUniform4fARB}} und für einen einfachen Integerwert (z.B. Textureinheit für einen Sampler) glUnifrom1iARB. Auch nicht vergessen dürft ihr, das die Namen der Parameter genauso wie im Shader geschrieben werden müssen, also Groß- und Kleinschreibung beachtet werden muß.&lt;br /&gt;
&lt;br /&gt;
=Die Shadersprache=&lt;br /&gt;
&lt;br /&gt;
Nachdem wir uns mit der Einbindung der glSlang-Shader in unser Programm beschäftigt haben, wollen wir uns in den folgenden Kapiteln um die Sprachelemente von glSlang kümmern. Wie schon gesagt basiert glSlang auf ANSI-C, wurde allerdings um speziell auf den Zielbereich angepasste Vektor- und Matrixtypen und einige C++-Features wie das freie deklarieren von Variablen an jeder Stelle und das Funktionsüberladen auf Basis des Argumenttyps erweitert. Wer sich ein wenig mit C/C++ auskennt sollte also in der nun folgenden Materie keine Probleme bekommen.&lt;br /&gt;
&lt;br /&gt;
'''Obligatorische Hinweise für verwöhnte Delphi-Nutzer : '''&lt;br /&gt;
*Wie von C/C++ her gewohnt, spielt auch in glSlang die Groß- und Kleinschreibung eine wichtige Rolle, also bitte achtet darauf. gl_Position ist eine komplett andere Variable als z.B. gl_position.&lt;br /&gt;
*Es findet keine automatische Typenkonvertierung statt. Das bedeutet also das float MyFloat = 1 ungültig ist und es in dem Falle float MyFloat = 1.0 heissen muss. Typecasts müssen also immer manuell stattfinden, z.B. MyFloat = float(MyInt).&lt;br /&gt;
&lt;br /&gt;
'''Kleine Programmstrukturkunde für C-Unkundige :'''&amp;lt;br&amp;gt;&lt;br /&gt;
Da sicherlich einige Delpher nie richtig was mit C gemacht haben, zeige ich mal anhand eines kleinen Beispieles (das auf keinen Fall nen brauchbaren Shader darstellt) den grundlegenden Aufbau eines glSlang-Shaders, der natürlich dem Aufbau eines C-Programmes stark ähnelt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 VariableA;&lt;br /&gt;
float VariableB;&lt;br /&gt;
vec3  VariableC;&lt;br /&gt;
const float KonstanteA = 256.0;&lt;br /&gt;
&lt;br /&gt;
float MyFunction(vec4 ArgumentA)&lt;br /&gt;
{&lt;br /&gt;
    float FunktionsVariableA = float(5.0);&lt;br /&gt;
&lt;br /&gt;
    return float(ArgumentA * (FunktionsVariableA + KonstanteA));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Ich bin ein Kommentar&lt;br /&gt;
/* Und ich auch */&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
    gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht doch recht bekannt aus, unser Programmaufbau. Delphi und C haben ja so einige Grundlagen gleich, darunter auch der ungefähre Programmaufbau. Ausserhalb jeglicher Funktionen legen wir am Programmanfang unsere Variablen, Konstanten und Attribute fest, die dann ''global'' nutzbar sind, also in jeder Funktion.&lt;br /&gt;
&lt;br /&gt;
Darunter deklarieren wir dann eine kleine Funktion. Wie auch bei den Variablendeklarationen wird hier der Rückgabetyp nicht wie bei Pascal nach dem Funktionsnamen untergebracht, sondern davor. Innerhalb der Funktion können dann wieder Variablen deklariert werden, die dann allerdings ''lokal'', also nur in dieser Funktion nutzbar sind. Vorteil dieser Deklaration ist die Tatsache, dass je nach Grafikkarte nur bestimmt viele globale Variablen deklariert werden können. Wenn möglich sollte man also mit lokalen Vorlieb nehmen. Unsere Funktion gibt dann natürlich noch via return einen Wert zurück, ''was gemacht werden muss'', sofern man diese nicht als void deklariert hat (entspräche dann einer Prozedur in Pascal). Wird dies nicht getan, so spuckt der Compiler einen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Auch wichtig sind natürlich Kommentare. Erste Variante (Doppelslash) ist auch in der Pascalwelt verfügbar und kommentiert eine einzelne Zeile aus. Die Variante darunter kann man für Kommentarblöcke nutzen (/* .. */) und entspricht den Kommentaren in geschweiften Klammern in Delphi.&lt;br /&gt;
&lt;br /&gt;
Danach kommt dann die '''wichtigste Funktion''' des Shaders, nämlich '''main''', die in keinem Shader fehlen darf. Sie stellt quasi den Programmkörper dar und ist oft auch die einzige Funktion in einem Shader. Sie erhält weder ein Argument, noch gibt sie einen Wert zurück.&lt;br /&gt;
&lt;br /&gt;
Soviel also zum grundlegenden Aufbau eines Shader. Hoffe das jetzt alle die in C nicht so bewandert sind damit klar kommen, und dann bald ihre ersten glSlang-Shader schreiben können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Datentypen==&lt;br /&gt;
&lt;br /&gt;
Obwohl einige Datentypen aus C übernommen wurden, sieht man der Typenliste an, das diese speziell auf den 3D-Bereich zugeschnitten wurde. Variablen müssen vor ihrer Nutzung eindeutig deklariert sein, Typecasting erfolgt über Konstruktoren (dazu später mehr). Folgende Datentypen stehen sowohl im Vertex- als auch Fragmentshader zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|void 	&lt;br /&gt;
|Für Funktionen die keinen Wert zurückgeben&lt;br /&gt;
|-&lt;br /&gt;
|bool 	&lt;br /&gt;
|Konditionaler Typ, entweder true (wahr) oder false (falsch)&lt;br /&gt;
|-&lt;br /&gt;
|int 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenbehafteter Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|uint 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenloser Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|float 	&lt;br /&gt;
|Fließkommaskalar mit Singlegenauigkeit (32 Bit)&lt;br /&gt;
|-&lt;br /&gt;
|vec2 	&lt;br /&gt;
|2-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec3 	&lt;br /&gt;
|3-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec4 	&lt;br /&gt;
|4-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec2 	&lt;br /&gt;
|2-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec3 	&lt;br /&gt;
|3-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec4 	&lt;br /&gt;
|4-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec2 	&lt;br /&gt;
|2-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec2 	&lt;br /&gt;
|2-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec3 	&lt;br /&gt;
|3-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec4 	&lt;br /&gt;
|4-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|mat2 	&lt;br /&gt;
|2x2 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat3 	&lt;br /&gt;
|3x3 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat4 	&lt;br /&gt;
|4x4 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|matMxN 	&lt;br /&gt;
|Matrix mit M Spalten und N Zeilen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse zum Zugriff auf Texturen dar, und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|sampler1D 	&lt;br /&gt;
|Zugriff auf 1D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler2D 	&lt;br /&gt;
|Zugriff auf 2D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler3D 	&lt;br /&gt;
|Zugriff auf 3D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|samplerCube 	&lt;br /&gt;
|Zugriff auf Cubemap&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRect 	&lt;br /&gt;
|Zugriff auf Texturen die nicht 2^n * 2^n entsprechen (&amp;quot;non power-of-two&amp;quot;, NPOT)&lt;br /&gt;
|-&lt;br /&gt;
|sampler1DShadow 	&lt;br /&gt;
|Zugriff auf 1D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DShadow 	&lt;br /&gt;
|Zugriff auf 2D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|samplerCubeShadow&lt;br /&gt;
|Zugriff auf Tiefentextur in einer Cubemap (z.b. für omni-diretionale Lichtquellen)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRectShadow&lt;br /&gt;
|Zugriff auf 2D-NPOT-Tiefentextur &lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|sampler1DArray&lt;br /&gt;
|Zugriff auf ein array aus 1D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArray&lt;br /&gt;
|Zugriff auf ein array aus 2D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler1DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 1D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 2D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|samplerBuffer&lt;br /&gt;
|Zugriff auf eine Puffertextur (1D-Texutr zum Speichern von Pufferobjekten)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMS&lt;br /&gt;
|Zugriff auf eine 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMSArray&lt;br /&gt;
|Zugriff auf einarray aus 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Arrays===&lt;br /&gt;
&lt;br /&gt;
Natürlich unterstützt glSlang auch Arrays, die wie in C deklariert werden und deren Index bei 0 beginnt. Folgendes Array im Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
beginnt also bei Index 0 und endet bei Index 2. Im Gegensatz zu C lassen sich Arrays in glSlang allerdings ''nicht bei der Initialisierung vorbelegen''. Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strukturen===&lt;br /&gt;
&lt;br /&gt;
Neu ggü. ARB_FP/VP ist nun auch die Möglichkeit, Strukturen in einem Shader zu deklarieren. Vor allem die Übersicht komplexerer Shader kann dadurch stark verbessert werden. Strukturen werden wie gewohnt mit dem Schlüsselwort {{INLINE_CODE|struct}} eingeleitet und können dann zur Typisierung von Variablen genutzt werden. Folgendes Beispiel dürfte die Nutzung verdeutlichen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct light&lt;br /&gt;
{&lt;br /&gt;
    bool active;&lt;br /&gt;
    float intensity;&lt;br /&gt;
    vec3 position;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
LightSource[i].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Typenqualifzierer==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur Typendeklaration kann eine Variable noch einen Typenqualifizerer vorangestellt bekommen, der an den Anfang der Deklaration gehört.&lt;br /&gt;
&lt;br /&gt;
* '''const'''&lt;br /&gt;
: Festgelegte (nur lesen) Konstante bzw. nur lesbarer Funktionsparameter.&lt;br /&gt;
&lt;br /&gt;
* '''uniform'''&lt;br /&gt;
: Ein den ganzen Shader über gleichbleibender Wert, der eine Schnittstelle zwischen dem Shader und der OpenGL-Anwendung darstellt. Ein Uniformwert wird in der Hauptanwendung an den entsprechenden Shader übergeben und kann dort dann genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* '''attribute'''&lt;br /&gt;
: Nur lesbare Werte die eine Verbindung zwischen dem Shader und der OpenGL-VertexAPI darstellen (z.B. VertexParameter eines VertexArrays). Natürlich nur in einem Vertex Shader nutzbar.&lt;br /&gt;
&lt;br /&gt;
* '''varying'''&lt;br /&gt;
: Stellt die Verbindung zwischen einem Vertex- und einem FragmentShader dar. Werden im VertexShader geschrieben und dann perspektivisch korrekt über die Primitive interpoliert, um dann im Fragment Shader gelesen werden zu können. Nutzbar sind hier nur die Typen float, vec2, vec3, vec4, mat2, mat3 und mat4, Strukturen und andere Datentypen können nicht varying sein. Die Namen einer varying-Variable müssen sowohl im VertexShader als auch im FragmentShader gleich sein.&lt;br /&gt;
&lt;br /&gt;
* '''in'''&lt;br /&gt;
: Für Variablen die an eine Funktion übergeben und dort ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* '''out'''&lt;br /&gt;
: Für Variablen die von einer Funktion nach außen zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
* '''inout'''&lt;br /&gt;
: Für Variablen die sowohl an eine Funktion übergeben als auch von dieser zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um obige Auflistung nicht leer im Raum stehen zu lassen zeige ich ein paar Beispiele die hoffentlich zum Verständnis beitragen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Vertexnormale soll an einen FragmenShader (interpoliert) übergeben werden :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
VertexNormal = normalize(MV_IT * gl_Normal);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Uniformparameter zur nachträglichen Farbänderung der Szene wird im Programm übergeben :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im Programm :&lt;br /&gt;
&lt;br /&gt;
 glUniform4fARB(glSlang_GetUniLoc(ProgramObject, 'GlobalColor'), Col[0], Col[1], Col[2], Col[3]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Beispiel C=== &lt;br /&gt;
Konstante zur festen Farbänderung :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
const vec4 ColorBias = vec4(0.2, 0.3, 0.0, 0.0);&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = ColorBias * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Konstruktoren==&lt;br /&gt;
&lt;br /&gt;
Um in einem Shader ''Vektoren'' oder ''Matrizen'' mit Werten zu belegen, gibt es sogenannte Konstruktoren (nicht zu verwechseln mit z.B. Klassenkonstruktoren unter Delphi), die im Endeffekt nichts anderes als Funktionen zur Vorbelegung von Vektoren oder Matrizen darstellen. Dabei trägt der Konstruktor den selben Namen wie die Typendeklaration, also lässt sich eine Variable vom Typ {{INLINE_CODE|vec4}} mit dem Konstruktor {{INLINE_CODE|vec4(float, float, float, float)}} initialisieren.&lt;br /&gt;
&lt;br /&gt;
Allerdings hat man sich recht viel Mühe bei dieser Konstruktorgeschichte gemacht, so dass man einen vec4 nicht unbedingt mit einem {{INLINE_CODE|vec4}}-Konstruktor vorbelegen muss, sondern es vielseitige Möglichkeiten gibt. Um dies zu verdeutlichen gibts ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(1.0, 0.0, 0.0, 0.0);&lt;br /&gt;
vec4 Color = vec4(MyVec3, 1.0);&lt;br /&gt;
vec4 Color = vec4(MyVec2_A, MyVec2_B);&lt;br /&gt;
&lt;br /&gt;
vec3 LVec  = vec3(MyVec4);&lt;br /&gt;
vec2 Tmp   = vec2(MyVec3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trotz der recht wenigen Beispiele sollte schnell erkennbar sein, das man hier wirklich sehr viele Kombinationsmöglichkeiten hat, die dann gültig sind ''wenn man mindestens auf die benötigte Anzahl der Argumente kommt''. Im vorletzten Beispiel wird z.B. ein 3-Komponentenvektor aus einem 4-Komponentenvektor initialisiert. Das erzeugt keinen Fehler, sondern führt dazu das {{INLINE_CODE|vec3.x, vec3.y, vec3.z}} aus MyVec4 übernommen werden und MyVec4.w einfach ignoriert wird.&lt;br /&gt;
&lt;br /&gt;
Das Umkehrbeispiel, also&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
funktioniert allerdings nicht, da hier die Zahl der benötigten Argumente nicht erreicht wird. In diesem Falle müsste es dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
heissen.&lt;br /&gt;
&lt;br /&gt;
Obiges gilt natürlich auch für ''Matrixkonstruktoren'', hier sind z.B. folgende Konstuktoren denkbar, obwohl eigentlich alle Möglichkeiten nutzbar sind, ''solange die benötigte Zahl an Argumenten erreicht wird'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
mat4 MyMatrix = mat4(MyVec4, MyVec4, MyVec4, MyVec4);&lt;br /&gt;
mat2 MyMatrix = mat4(1.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 1.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 1.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixkomponenten==&lt;br /&gt;
&lt;br /&gt;
Was natürlich in keiner Shadersprache fehlen darf, ist der leichte Zugriff auf die einzelnen Komponenten eines Vektors. glSlang bietet, je nach Anwendungsgebiet gleich drei Namensets für den Zugriff auf die Komponenten eines solchen Vektors, welches Set man nutzen will bleibt natürlich frei und ist unabhängig von der Deklaration eines Vektors. Man sollte nur darauf achten, beim gleichzeitigen Zugriff auf mehrere Komponenten im gleichen Namenset zu verbleiben :&lt;br /&gt;
&lt;br /&gt;
* {x, y, z, w}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Punkte, Normale oder sonstige Vertexdaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {r, g, b, a}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Farbwerte repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {s, t, p, q}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Texturkoordinaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
Ein paar Beispiele zur Unterstreichung des oben gesagten :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
v4.rgba = vec4(1.0, 0.0, 0.0, 0.0);  // gültig&lt;br /&gt;
v4.rgzw = vec4(1.0, 1.0, 1.0, 2.0);  // Ungültig, da verschiedenen Namensets&lt;br /&gt;
v2.rgb  = vec3(1.0, 2.0, 1.0);       // Ungültig, da vec2 nur r+g besitzt&lt;br /&gt;
v2.xx   = vec2(5.0, 3.0);            // Ungültig, da 2 mal gleiche Komponente&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch der Zugriff auf die Komponenten einer Matrix geht leicht von der Hand. Namensets wie bei den Vektoren gibt es hier natürlich keine, aber folgende Beispiele sollen den Zugriff aufzeigen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
MyMat4[2]    = vec4(1.0); // Setzt die 3.Zeile der Matrix komplett auf 1.0&lt;br /&gt;
MyMat4[3][3] = 3.5;       // Setzt das Element unren rechts auf 3.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Matrixelemente ausserhalb ihrer Dimension (also z.B. MyMat4[4][4]) liefert unvorhersehabre Ergebnise, also sollte man auf diese Fälle prüfen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixoperationen==&lt;br /&gt;
&lt;br /&gt;
Wie von C gewohnt sind in glSlang so ziemlich alle Operatoren die man auf Matrizen oder Vektoren anwenden kann überladen, so das man nicht umständlich über selbstgeschriebene Funktionen kombinieren muss. Darüber hinaus ist es in den meisten Fällen auch möglich ohne Konvertierung Fließkommawerte mit kompletten Matrizen oder Vektoren zu kombinieren. Folgende Beispiele zeigen einige der vielfältigen Kombinationsmöglichkeiten auf :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
float factor;&lt;br /&gt;
&lt;br /&gt;
vec3 dest = source + factor; &lt;br /&gt;
&lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = source.x + factor;&lt;br /&gt;
dest.y = source.y + factor;&lt;br /&gt;
dest.z = source.z + factor;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
mat3  MyMat;&lt;br /&gt;
 &lt;br /&gt;
dest = source * MyMat; &lt;br /&gt;
 &lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = dot(source, MyMat[0]);&lt;br /&gt;
dest.y = dot(source, MyMat[1]);&lt;br /&gt;
dest.z = dot(source, MyMat[2]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier sind die Möglichkeiten fast unbeschränkt und zeigen wieder wie flexibel glSlang ausgelegt ist. &lt;br /&gt;
&lt;br /&gt;
==Operatoren==&lt;br /&gt;
&lt;br /&gt;
glSlang bietet (momentan) folgende Operatoren, die Liste ist nach ihrer Gewichtung sortiert (Anfang = höchste). Alle ''reservierten'' Operatoren werden erst in kommender Hardware/glSlang-Versionen nutzbar sein :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div  align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Operatorklasse  	&lt;br /&gt;
!Operatoren  	&lt;br /&gt;
!Assoziation&lt;br /&gt;
|-&lt;br /&gt;
|Gruppering 	&lt;br /&gt;
|() 	&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
|Arrayindizierung&amp;lt;br&amp;gt;Funktionsaufrufe und Konstruktoren&amp;lt;br&amp;gt;Strukturfeldwahl und Swizzle&amp;lt;br&amp;gt;Postinkrement und -dekrement&amp;lt;br&amp;gt; 	&lt;br /&gt;
|[]&amp;lt;br&amp;gt;()&amp;lt;br&amp;gt;.&amp;lt;br&amp;gt;++ -- 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Prefixinkrement- und dekrement&amp;lt;br&amp;gt;Einheitlich (~ reserviert) 	&lt;br /&gt;
| ++ --&amp;lt;br&amp;gt; + - ~ ! 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Mulitplikation (% reserviert) 	&lt;br /&gt;
|* / % 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Additiv 	&lt;br /&gt;
| + - 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises Verschieben (reserviert) 	&lt;br /&gt;
|&amp;lt;&amp;lt;  &amp;gt;&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Relation 	&lt;br /&gt;
|&amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;= 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Vergleich 	&lt;br /&gt;
|==  != 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises AND (reserviert) 	&lt;br /&gt;
|&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises XOR (reserviert) 	&lt;br /&gt;
|^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises OR (reserviert) 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches AND 	&lt;br /&gt;
|&amp;amp;&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches XOR 	&lt;br /&gt;
|^^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches OR 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Auswahl 	&lt;br /&gt;
|?: 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Zuweisung&amp;lt;br&amp;gt;Arithmetrische Zuweisung&amp;lt;br&amp;gt;(Modulis, Shift und bitweise Op. reserviert) 	&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;+= -=  *=  /=  %=&amp;lt;/nowiki&amp;gt; &amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;&amp;lt;&amp;lt;=  &amp;gt;&amp;gt;= &amp;amp;=  ^=  |=&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Aufzählung 	&lt;br /&gt;
|, 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von Hochsprachen ist u.A. die Möglichkeit oft genutzte Codeteile in Funktionen (bzw. auch Prozeduren unter Pascal) zu verpacken um so Flexibilität als auch Übersichtlichkeit zu steigern. Wer schonmal was in C geschrieben hat, der wird sich jetzt sicherlich kein Kopfzerbrechen machen müssen. Funktionen werden in glSlang genauso nach folgendem Prinzip deklariert :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
RückgabeTyp FunktionsName(Typ0 Argument0, Typ1, Argument1, ... , TypN, ArgumentN)&lt;br /&gt;
 {&lt;br /&gt;
 return RückgabeWert;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, außerdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach außen übergeben soll, muss dieses Argument mit dem Typenqualifizierer out (Siehe Kapitel 4.2) versehen werden. ''Arrays'' können nur als Eingabeargumente übergeben werden und dürfen nich dimensioniert als Argument verwendet werden, sondern müssen mit leeren Klammern argumentiert werden.&lt;br /&gt;
Ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void MeineFunktion(float EingabeWert; out float AusgabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 AusgabeWert = EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach außen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float MeineFunktion(float EingabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 return EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bietet genau die selbe Funktionalität wie das Beispiel darüber. Allerdings wird hier der berechnete Wert als Ergebnis der Funktion zurückgeliefert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float VektorSumme(float v[])&lt;br /&gt;
 {&lt;br /&gt;
 return v[0]+v[1]+v[2]+v[3];&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt darf ein Array als Argument keine Dimensionierung enthalten. Wenn man der Funktion also ein Array übergibt, sollte man vorher drauf achten das es entsprechend der in der Funktion genutzten Indizes dimensioniert wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==if-Anweisung==&lt;br /&gt;
&lt;br /&gt;
Selektion über eine if-Anweisung darf auch in keiner Hochsprache fehlen. Genauso wie in C oder Delphi erwartet auch hier die If-Anweisung einen boolschen Ausdruck (Wahr oder Falsch) und wird dann ausgeführt (wahr) bzw. verzweigt auf ein (wenn vorhanden) else (falsch). Verschachtelung ist wie erwartet auch möglich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis : ''' &lt;br /&gt;
Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten im Fragmentshader kein Early-Out, was zur Folge hat das bei einer If-Anweisung immer alle Zweige ausgeführt werden. Am Ende wird dann aber nur ein Ergebnis geschrieben, die anderen verworfen. Auf solchen Karten bringen If-Anweisungen also im Normalfall keine Geschwindigkeitssteigerung, sondern oft eher das Gegenteil.&lt;br /&gt;
Neuere SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall, da hier dynamische Verzweigungen und auch Early-Out von der Hardware implementiert werden.&lt;br /&gt;
&lt;br /&gt;
==Schleifen==&lt;br /&gt;
&lt;br /&gt;
Auch Schleifen, ein wichtiges Konzept jeder Hochsprache haben ihren Weg in glSlang gefunden. Unterstützt werden folgende Schleifentypen :&lt;br /&gt;
&lt;br /&gt;
* '''for'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
do&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
 while (Durchlaufbedingung)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hinweis :''' Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten Schleifen nicht in Hardware. Schleifen werden dann beim Kompilieren vom Treiber entrollt, wodurch natürlich Shader mit weitaus mehr Instruktionen als erwartet generiert werden. Von daher sollte man auf solchen Karten möglichst auf Schleifen verzichten, oder diese nur recht kurz halten. Bei SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Variablen, Attribute und Konstanten=&lt;br /&gt;
Nachdem wir uns nun lange genug mit den minderinterssanten Elementen der glSlang-Syntax beschäftigt haben, gehts jetzt endlich an die wirklich interessanten Dinge. Wie schon ARB_VP/ARB_FP bringt auch glSlang jede Menge eingabauter Variablen, Attribute und Konstanten mit, deren Aliase sie recht leicht identifizierbar machen (ganz im Gegensatz zum Indexgewusel bei den DX-Shadern).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Vertex Shader==&lt;br /&gt;
Exklusiv im Vertex Shader stehen die folgenden Variablen zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Position    muss geschrieben werden&lt;br /&gt;
:Dieser Variable '''muss''' im Vertexshader ein Wert zugewiesen werden, wird dies nicht getan ist das Ergebnis (sprich die Position des Vertex) undefiniert. Vorgesehen ist diese Variable für die ''homogene Position des Vertex'' und wird u.a. zum Clipping und Culling verwendet. Sie darf natürlich auch (mehrfach) geschrieben und ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* float gl_PointSize    kann geschrieben werden&lt;br /&gt;
:Diese Variable wurde dazu vorgesehen um dort im VertexShader die Punktgröße in Pixeln hineinzuschreiben.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_ClipVertex    kann geschrieben werden&lt;br /&gt;
:Falls genutzt, sollten hier die Vertexkoordinaten die im Zusammenhang mit benutzerdefinierten Clippingplanes genutzt werden abgelegt werden. Wichtig ist, das gl_ClipVertex im selben Koordinatenraum wie die Clippingplane definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Attribute im Vertex Shader==&lt;br /&gt;
&lt;br /&gt;
Folgende Attribute stehen nur im Vertex Shader zur Verfügung und '''können nur gelesen werden''' :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Color&lt;br /&gt;
: Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_SecondaryColor&lt;br /&gt;
:Sekundärer Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_Normal&lt;br /&gt;
:Normale des Vertex.&lt;br /&gt;
* vec4 gl_Vertex&lt;br /&gt;
:Koordinaten des Vertex;&lt;br /&gt;
* vec4 gl_MultiTexCoord0..7&lt;br /&gt;
:Texturkoordinaten auf Textureinheit 0..7.&lt;br /&gt;
* float gl_FogCoord&lt;br /&gt;
:Nebelkoordinate des Vertex. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Fragment Shader==&lt;br /&gt;
&lt;br /&gt;
Im Fragment Shader sind folgende Variablen exklusiv nutzbar :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragColor&lt;br /&gt;
: Speichert den Farbwert des Fragmentes, der von folgenden Funktionen der festen Pipeline genutzt wird. Wird dieser Variable nichts zugewiesen, so ist ihr Inhalt undefiniert und darauf aufbauende Ergebnisse ebenfalls.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragData[0..15]&lt;br /&gt;
: Ersetzt gl_FragColor bei der Verwendung von multiplen Rendertargets. &lt;br /&gt;
&lt;br /&gt;
* float gl_FragDepth&lt;br /&gt;
: Durch schreiben dieser Variable kann man den von der festen Funktionspipeline ermittelten Tiefenwert überspringen, der mit {{INLINE_CODE|gl_FragCoord.z}} ausgelesen werden kann. Wird dieser Wert nicht geschrieben, nutzen folgende Funktionen der Pipeline den vorher fest berechneten Wert.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragCoord    nur lesen&lt;br /&gt;
: In dieser Variable ist die Position des Fragmentes relativ zur Fensterposition im Format x,y,z,1/w abgelegt, wobei z den von der festen Funktionspipeline berechneten Tiefenwert enthält.&lt;br /&gt;
&lt;br /&gt;
* bool gl_FrontFacing    nur lesen&lt;br /&gt;
: Gibt an ob das Fragment zu einer nach vorne zeigenden Primitive gehört (=true). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bezug auf {{INLINE_CODE|gl_FragColor}} und {{INLINE_CODE|gl_FragDepth}} sei noch anzumerken das diese ''nicht'' in den Wertebereich 0..1 gebracht werden müssen, da dies später durch die feste Funktionspipeline automatisch gemacht wird.&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Varyings==&lt;br /&gt;
&lt;br /&gt;
Wie bereits in Kapitel 4.2 erwähnt, stellen Varyings eine Schnittstelle zwischen dem Vertex und dem Fragment Shader dar. Sie werden im Vertex Shader geschrieben und können dann im Fragment Shader ausgelesen werden, ohne das die folgenden Varyings dafür explizit deklariert werden müssen :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontColor&lt;br /&gt;
: Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackColor&lt;br /&gt;
: Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_TexCoord[x]&lt;br /&gt;
: Texturkoordinaten des Vertex auf Textureinheit x, wobei x die von der Hardware zur Verfügung gestellte Zahl der Textureinheiten-1 nicht überschreiten darf.&lt;br /&gt;
&lt;br /&gt;
* float gl_FogFragCoord&lt;br /&gt;
: Nebelkoordinate des Fragmentes. &lt;br /&gt;
&lt;br /&gt;
Die Varyings {{INLINE_CODE|gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor}} und {{INLINE_CODE|gl_BackSecondaryColor}} können im FragmentShader nur unter den Aliases gl_Color bzw. gl_SecondaryColor gelesen werden. Welcher Wert des Vertex Shaders im Fragment Shader dort eingesetzt wird ist abhängig davon ob das Fragment zu einer nach vorne oder nach hinten zeigenden Primitive gehört.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Konstanten==&lt;br /&gt;
Auch diverse Konstanten wurden definiert um darauf schnell im Shader zugreifen zu können. In den Klammern stehen die von einer GL-Implementation als Mindestanforderung anzubietenden Werte. Alle Konstanten sind sowohl im Vertex als auch im Fragment Shader abrufbar :&lt;br /&gt;
&lt;br /&gt;
: OpenGL 1.0/1.2 :&lt;br /&gt;
* int gl_MaxLights (8)&lt;br /&gt;
* int gl_MaxClipPlanes (6)&lt;br /&gt;
* int gl_MaxTextureUnits (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: ARB_Fragment_Program :&lt;br /&gt;
* int gl_MaxTextureCoordsARB (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Vertex_Shader :&lt;br /&gt;
* int gl_MaxVertexAttributesGL2 (16)&lt;br /&gt;
* int gl_MaxVertexUniformFloatsGL2 (512)&lt;br /&gt;
* int gl_MaxVaryingFloatsGL2 (32)&lt;br /&gt;
* int gl_MaxVertexTextureUnitsGL2 (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Fragment_Shader :&lt;br /&gt;
* int gl_MaxFragmentTextureUnitsGL2 (2)&lt;br /&gt;
* int gl_MaxFragmentUniformFloatsGL2 (64)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Uniformvariablen==&lt;br /&gt;
&lt;br /&gt;
Um den Zugriff auf OpenGL-Staten zu vereinfachen wurden in glSlang diverse Uniformvariablen zur direkten Verwendung im Shader eingebaut. Wie gewohnt wurden auch hier sinnvolle Namen verwendet, so dass eine tiefere Erklärung unnötig sein dürfte :&lt;br /&gt;
&lt;br /&gt;
* mat4 gl_ModelViewMatrix&lt;br /&gt;
* mat4 gl_ProjectionMatrix&lt;br /&gt;
* mat4 gl_ModelViewProjectionMatrix&lt;br /&gt;
* mat3 gl_NormalMatrix&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die invertierten und anschließend transponierten oberen 3x3 Werte der {{INLINE_CODE|gl_ModelViewMatrix}}.&lt;br /&gt;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
* float gl_NormalScale&lt;br /&gt;
: Gibt den unter OpenGL festgelegten Faktor zur Skalierung der Normalen zurück.&lt;br /&gt;
&lt;br /&gt;
* struct gl_DepthRangeParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_DepthRangeParameters&lt;br /&gt;
{&lt;br /&gt;
 float near;&lt;br /&gt;
 float far;&lt;br /&gt;
 float diff;&lt;br /&gt;
};&lt;br /&gt;
gl_DepthRangeParameters gl_DepthRange;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_PointParameters&lt;br /&gt;
{&lt;br /&gt;
 float size;&lt;br /&gt;
 float sizeMin;&lt;br /&gt;
 float sizeMax;&lt;br /&gt;
 float fadeThresholdSize;&lt;br /&gt;
 float distanceConstantAttenuation;&lt;br /&gt;
 float distanceLinearAttenuation;&lt;br /&gt;
 float distanceQuadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_PointParameters gl_Point;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_MaterialParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 emission;&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 float shininess;&lt;br /&gt;
};&lt;br /&gt;
gl_MaterialParameters gl_FrontMaterial;&lt;br /&gt;
gl_MaterialParameters gl_BackMaterial;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightSourceParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 vec4 position;&lt;br /&gt;
 vec4 halfVector;&lt;br /&gt;
 vec3 spotDirection;&lt;br /&gt;
 float spotExponent;&lt;br /&gt;
 float spotCutoff;&lt;br /&gt;
 float spotCosCutoff;&lt;br /&gt;
 float constantAttenuation;&lt;br /&gt;
 float linearAttenuation;&lt;br /&gt;
 float quadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_LightSourceParameters gl_LightSource[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelParameters gl_LightModel;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 sceneColor;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelProducts gl_FrontLightModelProduct;&lt;br /&gt;
gl_LightModelProducts gl_BackLightModelProduct;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
};&lt;br /&gt;
gl_LightProducts gl_FrontLightProduct[gl_MaxLights];&lt;br /&gt;
gl_LightProducts gl_BackLightProduct[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* vec4 gl_TextureEnvColor[gl_MaxFragmentTextureUnitsGL2]&lt;br /&gt;
* vec4 gl_EyePlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
*struct gl_FogParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_FogParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 color;&lt;br /&gt;
 float density;&lt;br /&gt;
 float start;&lt;br /&gt;
 float end;&lt;br /&gt;
 float scale;&lt;br /&gt;
};&lt;br /&gt;
gl_FogParameters gl_Fog;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese recht umfangreiche GL-Stateliste sollte eigentlich jeden Bedarf decken und momentan gibts kaum einen OpenGL-Status den man so nicht in einem Shader abfragen bzw. nutzen kann.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Funktionen=&lt;br /&gt;
glSlang ist mit diversen Skalar- und Vektorfunktionen ausgestattet, die teilweise (idealerweise) sogar direkt in der Hardware ausgeführt werden, weshalb einer fertigen Funktion ggü. gleichwertigen eigenen Berechnungen immer der Vorzug zu geben ist.&lt;br /&gt;
{{Hinweis| ''genType'' kann vom Type float, vec2, vec3 oder vec4 sein, ''mat'' vom Typ mat2, mat3 oder mat4.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie und Winkel==&lt;br /&gt;
Alle übergebenen Winkel sollten, soweit nicht anders vermerkt, in Radien angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* genType radians (genType degrees)&lt;br /&gt;
: Wandelt von Grad nach Radien. &lt;br /&gt;
* genType degrees (genType radians)&lt;br /&gt;
: Wandelt von Radien nach Grad.&lt;br /&gt;
* genType sin (genType x)&lt;br /&gt;
: Gibt den Sinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType x)&lt;br /&gt;
: Gibt den Kosinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType x)&lt;br /&gt;
: Gibt den Tangens von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType asin (genType x)&lt;br /&gt;
: Liefert den Arcsinus von x zurück, also den Winkel dessen Sinus x ergeben würde.&lt;br /&gt;
* genType acos (genType x)&lt;br /&gt;
: Liefert den Arckosinus von x zurück, also den Winkel dessen Cosinus x ergeben würde.&lt;br /&gt;
* genType atan (genType y, genType x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x/y ergeben würde.&lt;br /&gt;
* genType atan (genType y_over_x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x über y ergeben würde.&lt;br /&gt;
&lt;br /&gt;
==Hyperbolisch==&lt;br /&gt;
* genType sinh (genType x)&lt;br /&gt;
: Gibt den Sinus Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) * 0.5; )&lt;br /&gt;
* genType cosh (genType x)&lt;br /&gt;
: Gibt den Kosinus Hyperbolicus von x zurück. (return = (exp(x) + exp(-x)) * 0.5; )&lt;br /&gt;
* genType tanh (genType x)&lt;br /&gt;
: Gibt den Tangens Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) / (exp(x) + exp(-x)); )&lt;br /&gt;
* genType asinh (genType angle)&lt;br /&gt;
: Gibt den Areasinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x + 1.0)); )&lt;br /&gt;
* genType acosh (genType angle)&lt;br /&gt;
: Gibt den Areakosinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x - 1.0)); )&lt;br /&gt;
* genType atanh (genType x)&lt;br /&gt;
: Gibt den Areatangens Hyperbolicus von x zurück. (return = log((1.0 + x) / (1.0 - x)) * 0.5; )&lt;br /&gt;
&lt;br /&gt;
==Exponentiell==&lt;br /&gt;
* genType pow (genType x, genType y)&lt;br /&gt;
: Gibt x hoch y zurück.&lt;br /&gt;
* genType exp (genType x)&lt;br /&gt;
: Gibt e(Eulerischezahl ≈ 2.7182) hoch x zurück.&lt;br /&gt;
* genType log (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis e(Eulerischezahl ≈ 2.7182) von x zurück.&lt;br /&gt;
* genType exp2 (genType x)&lt;br /&gt;
: Gibt 2 hoch x zurück.&lt;br /&gt;
* genType log2 (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis 2 von x zurück.&lt;br /&gt;
* genType sqrt (genType x)&lt;br /&gt;
: Gibt die Wurzel von x zurück.&lt;br /&gt;
* genType inversesqrt (genType x)&lt;br /&gt;
: Gibt die umgekehrte Wurzel von x zurück.&lt;br /&gt;
&lt;br /&gt;
==Standardfunktionen==&lt;br /&gt;
* genType abs (genType x)&lt;br /&gt;
: Liefert den absoluten Wert von x zurück.&lt;br /&gt;
* genType sign (genType x)&lt;br /&gt;
: Gibt -1.0 zurück, wenn x &amp;lt; 0.0, 0.0 wenn x = 0.0 und 1.0 wenn x &amp;gt; 0.0.&lt;br /&gt;
* genType roundeven(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. Bei &amp;quot;.5&amp;quot; Werten wird zur nächsten geraden Zahl gerundet.&lt;br /&gt;
* genType round(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert und gibt diesen zuück. &amp;quot;.5&amp;quot; Werte werden je nach Implementation anders behandelt.&lt;br /&gt;
* genType trunc(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integerwert dessen Absoluterwert nicht größer ist als der Absolutewert von x&lt;br /&gt;
* genType floor (genType x)&lt;br /&gt;
: Gibt denn größten Integerwert zurück, der kleiner oder gleich x ist.&lt;br /&gt;
* genType ceil (genType x)&lt;br /&gt;
: Gibt den kleinsten Integerwert zurück, der größer oder gleich x ist.&lt;br /&gt;
* genType fract (genType x)&lt;br /&gt;
: Gibt den Nachkommateil von x zurück.&lt;br /&gt;
* genType mod (genType x, float y) &lt;br /&gt;
* genType mod (genType x, genType y)&lt;br /&gt;
: Gibt den Modulus zurück. (result = x - y * floor(x / y)) &lt;br /&gt;
* genType min (genType x, genType y) &lt;br /&gt;
* genType min (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn y &amp;lt; x, ansonsten x. &lt;br /&gt;
* genType max (genType x, genType y) &lt;br /&gt;
* genType max (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn x &amp;lt; y, ansonsten x. &lt;br /&gt;
* genType clamp (genType x, genType minVal, genType maxVal) &lt;br /&gt;
* genType clamp (genType x, float minVal, float maxVal)&lt;br /&gt;
: Zwängt x in den Bereich minVal ... maxVal .  (return = min(minVal, max(maxVal, x)))&lt;br /&gt;
* genType mix (genType x, genType y, genType a)&lt;br /&gt;
* genType mix (genType x, genType y, float a)&lt;br /&gt;
: Liefert den linearen Blend zwischen x und y zurück. (result = x * (1 - a) + y * a) &lt;br /&gt;
* genType step (genType edge, genType x)&lt;br /&gt;
* genType step (float edge, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt; edge, ansonsten 1.0. &lt;br /&gt;
* genType smoothstep (genType edge0, genType edge1, genType x)&lt;br /&gt;
* genType smoothstep (float edge0, float edge1, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge0 und 1.0 wenn x &amp;gt;= edge1. Dazwischen wird eine weiche Hermite Interpolation durchgeführt.&lt;br /&gt;
(&lt;br /&gt;
  float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);&lt;br /&gt;
  result = t * t * (3.0 - 2.0 * t)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
==Geometrie==&lt;br /&gt;
* float length (genType x)&lt;br /&gt;
: Gibt die Länge des Vektors x (= sqrt(x[0]² + x[1]² + ... + x[n]²) zurück. &lt;br /&gt;
* float distance (genType p0, genType p1)&lt;br /&gt;
: Gibt die Distanz zwischen den zwei Vektoren p0 un p1 (= length(p0-p1)) zurück. &lt;br /&gt;
* float dot (genType x, genType y)&lt;br /&gt;
: Gibt das Punktprodukt von x und y zurück (=x[0]*y[0] + x[1]*y[1] + ... + x[n]*y[n]). &lt;br /&gt;
* vec3 cross (vec3 x, vec3 y)&lt;br /&gt;
: Gibt das Kreuzprodukt von x und y zurück. &lt;br /&gt;
* genType normalize (genType x)&lt;br /&gt;
: Normalisiert den Vektor x auf die Länge 1. &lt;br /&gt;
* vec4 ftransform()&lt;br /&gt;
: Nur im Vertex Shader. Die Funktion stellt sicher, das das eingehende Vertex haargenau so transformiert wird wie in der festen Funktionspipeline. gl_Position = ftransform() wird dann also gebraucht, wenn in mehreren Durchgängen sowohl im Shader als auch in der festen Pipeline gerendert wird, um sicherzustellen das in beiden Fällen die gleiche Vertexposition herauskommt. &lt;br /&gt;
* genType faceforward (genType N, genType I, genType Nref)&lt;br /&gt;
: Gibt einen nach vorne zeigenden Vektor N zurück. (If dot(NRef, I) &amp;lt; 0 return N else return -N) &lt;br /&gt;
* genType reflect (genType l, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (result = l - 2.0 * dot(N,I) * N; )&lt;br /&gt;
* genType refract (genType l, genType N, float eta)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N mit dem Brechungsindex eta gebrochenen Vektor l zurück. &lt;br /&gt;
::gentype k = 1.0 - eta * eta * (1.0 - dot(N, l) * dot(N, l))&lt;br /&gt;
::if (k &amp;lt; 0.0)&lt;br /&gt;
:::result = 0.0&lt;br /&gt;
::else &lt;br /&gt;
:::result = eta * l - (eta * dot(N, l) * sqrt(k)) * N&lt;br /&gt;
&lt;br /&gt;
==Matrixfunktionen==&lt;br /&gt;
* mat matrixCompMult (mat x, mat y)&lt;br /&gt;
: Multipliziert Matrix X mit Matrix Y komponentenweise. Um eine normale lineare Matrixmultiplikation durchzuführen, sollte der &amp;quot;*&amp;quot;-Operator genutzt werden.&lt;br /&gt;
* mat transpose (mat m)&lt;br /&gt;
: Gibt die transponierte Matrix von m zurück.&lt;br /&gt;
* mat invert (mat m)&lt;br /&gt;
: Gibt die invertierte Matrix von m zurück. Also die Matrix, die mit m multipliziert die Normalmatrix ergeben würde.&lt;br /&gt;
* mat outerProduct(vec c, vec r)&lt;br /&gt;
: Gibt eine eine Matrix als Ergebnis der linearen (return[m, n] = c[m] * r[n])-Operation zurück.&lt;br /&gt;
&lt;br /&gt;
==Vektorvergleiche==&lt;br /&gt;
Die meisten Vektorvergleichsfunktionen liefern als Ergebnis einen boolvektor zurück, da die Vergleiche per Komponente stattfinden. Wenn man also x = vec4(1.0, 3.0, 0.0, 0.0) mit y = vec4(2.0, 1.5, 1.5, 0.0) via lessThan(x, y) vergleicht, erhält man als Ergebnis bvec(true, false, true, false).&lt;br /&gt;
&lt;br /&gt;
* bvec lessThan (vec x, vec y)&lt;br /&gt;
* bvec lessThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt; y zurück. &lt;br /&gt;
* bvec lessThanEqual (vec x, vec y)&lt;br /&gt;
* bvec lessThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt;= y zurück. &lt;br /&gt;
* bvec greaterThan (vec x, vec y)&lt;br /&gt;
* bvec greaterThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt; y zurück. &lt;br /&gt;
* bvec greaterThanEqual (vec x, vec y)&lt;br /&gt;
* bvec greaterThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt;= y zurück. &lt;br /&gt;
* bvec equal (vec x, vec y)&lt;br /&gt;
* bvec equal (ivec x, ivec y)&lt;br /&gt;
* bvec equal (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x == y zurück. &lt;br /&gt;
* bvec notEqual (vec x, vec y)&lt;br /&gt;
* bvec notEqual (ivec x, ivec y)&lt;br /&gt;
* bvec notEqual (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x != y zurück. &lt;br /&gt;
* bool any (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn mindestens eine der Komponenten von x true ist.&lt;br /&gt;
* bool all (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn alle Komponenten von x true sind. &lt;br /&gt;
* bvec not (bvec x)&lt;br /&gt;
: Liefert die logische Negation von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Texturenzugriffe==&lt;br /&gt;
&lt;br /&gt;
Diese wichtige Funktionskategorie dient dazu, Werte aus einer an eine Textureinheit gebundenen Textur zu ermitteln. Die Texturenzugriffe können sowohl im Vertex (!) als auch im Fragment Shader ausgeführt werden, wobei der optionale Parameter bias im Vertex Shader ignoriert wird. Allerdings gibt es zusätzlich Funktionen die auf &amp;quot;Lod&amp;quot; enden und nur im Vertex Shader genutzt werden dürfen um eben dieses Manko zu umgehen. Funktionen mit dem Suffix &amp;quot;Proj&amp;quot; geben einen projizierten Texturenwert zurück.&lt;br /&gt;
&lt;br /&gt;
: '''1D-Texturen :'''&lt;br /&gt;
* vec4 texture1D (sampler1D sampler, float coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 texture1DLod (sampler1D sampler, float coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''2D-Texturen :'''&lt;br /&gt;
* vec4 texture2D (sampler2D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''3D-Texturen :'''&lt;br /&gt;
* vec4 texture3D (sampler3D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture3DProj (sampler3D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture3DProjLod (sampler3D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Cubemap :'''&lt;br /&gt;
* vec4 textureCube (samplerCube sampler, vec3 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
*vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Tiefentextur (Shadowmap) :'''&lt;br /&gt;
* vec4 shadow1D (sampler1DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow2D (sampler2DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
* vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow1DProjLod (sampler1DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
* vec4 shadow2DProjLod (sampler2DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Texturegröße :'''&lt;br /&gt;
Mit den textureSize-Befehlen kann die Größe einer Textur bestimmt werden, wobei lod das Mipmaplevel angibt:&lt;br /&gt;
*int textureSize(sampler1D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2D sampler, int lod)&lt;br /&gt;
*ivec3 textureSize(sampler3D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(samplerCube sampler, int lod)&lt;br /&gt;
*int textureSize(sampler1DShadow sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2DShadow sampler, int lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie bereits eingangs gesagt ist dieses Kapitel ein sehr wichtiges, denn eine 3D-Szene ohne Texturen ist heute kaum denkbar. Darüber hinaus lassen sich durch Texturenzugriffe recht viele interessante Sachen machen, z.B. ein einfacher Blurfilter oder das freie überblenden bestimmter Texturenteile. Deshalb führe ich hier kurz ein paar Beispiele an, welche die Nutzung dieser Funktionen verdeutlichen sollen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Eine Textur gebunden die einfach ausgegeben werden soll&lt;br /&gt;
&lt;br /&gt;
''Im Vertex Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
Der Vertex Shader ist recht minimal. Neben der homogenen Vertexposition leiten wir hier nur die im OpenGL-Programm angegebenen Texturkoordinaten weiter. ''Dies ist aber unbedingt nötig!'' Ohne die letzte Zeile hätten wir im Fragment Shader keine gültigen Texturkoordinaten auf TMU0, was in einer Fehldarstellung enden würde.&lt;br /&gt;
&lt;br /&gt;
''im Fragment Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSampler;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(texSampler, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zuerst deklarieren wir hier einen 2D-Texturensampler, wichtig : '''Texturensampler müssen IMMER als uniform deklariert werden!''' In der Hauptfunktion weisen wir dann einfach den über die Funktion texture2D aus unserer gebundenen Textur ausgelesenen Farbwert, anhand der vom Vertex Shader übergebenen Texturkoordinaten, zu.&lt;br /&gt;
{{Vorlage:Hinweis|Der Uniform-Integer für den Sampler referenziert '''nicht''' den Namen (die ID) des Texturobjektes, sondern die Nummer der Texturunit.}}&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Zwei Texturen, jeweils auf TMU0 und TMU1. Fragmentfarbe soll eine Multiplikation der beiden Texturen darstellen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielfall (der recht häufig vorkommt) müssen wir im Programm festlegen, ''welcher Sampler welche Textureinheit adressiert'', genau deshalb müssen die Texturensampler auch als uniform deklariert werden. Die Standardtextureneinheit eines Samplers ist TMU0, was in unserem Falle natürlich nicht brauchbar ist. Also müssen wir unserem zweiten Textursampler im Programm mitteilen das er seine Daten aus TMU1 beziehen soll :&lt;br /&gt;
&lt;br /&gt;
 glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&lt;br /&gt;
Dies ist also unbedingt zu machen, sobald ein Texturensampler eine Textureinheit &amp;gt; GL_TEXTURE_0 adressieren will. Die Textureneinheit des Samplers lässt sich also nicht im Shader selbst festlegen. Der Fragment Shader ist nun allerdings schnell hergeleitet (Vertex Shader verändert sich nicht, da TMU1 die Texturkoordinaten auch von TMU0 bezieht) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
im Fragment Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSamplerTMU0;&lt;br /&gt;
uniform sampler2D texSamplerTMU1;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_FragColor = texture2D(texSamplerTMU0, vec2(gl_TexCoord[0])) *&lt;br /&gt;
                   texture2D(texSamplerTMU1, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich [[GLSL noise|Noisefunktionen]] nutzen, mit deren Hilfe sich eine gewisse &amp;quot;Zufälligkeit&amp;quot; simulieren lässt (wirklich zufällige Werte sind es natürlich nicht). Ein zurückgegebener Wert liegt dabei immer im Bereich [-1..1] und ist immer bei gleichem Eigabewert auch immer gleich. Die Verwendung empfiehlt sich derzeit allerdings eher nicht, da nur die 3DLabs Treiber die Funktionen unterstützen und eine Noisetextur wahrscheinlich performanter ist.&lt;br /&gt;
&lt;br /&gt;
* float noise1 (genType x)&lt;br /&gt;
* vec2 noise2 (genType x)&lt;br /&gt;
* vec3 noise3 (genType x)&lt;br /&gt;
* vec4 noise4 (genType x)&lt;br /&gt;
&lt;br /&gt;
==Discard==&lt;br /&gt;
Eigentlich keine Funktion, sondern eine Abbruchbedingung '''nur im Fragment Shader'''. Das Schlüsselwort {{INLINE_CODE|discard}} verwirft das aktuell bearbeitete Fragment und beendet gleichzeitig den Shader. Es kann z.B. genutzt werden um Alphamasking manuell durchzuführen.&lt;br /&gt;
Man sollte dabei jedoch beachten dass ein Großteil der aktuellen Hardware kein &amp;quot;early-out&amp;quot; (frühes Beenden) im Fragmentshader unterstützt. Wenn dort also ein {{INLINE_CODE|discard}} auftaucht, wird trotzdem auch der Code danach ausgeführt und einfach verworfen. Einen Geschwindigkeitsvorteil durch diesen Befehl wird man also erst auf neueren Karten feststellen, die dieses Faeature auch so unterstützen wie es angedacht war. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispielshader=&lt;br /&gt;
Wen bis hierhin nicht der Mut verlassen hat, und wer aufmerksam gelesen hat, dürfte jetzt also zumindest in der Lage sein kleinere Shader in glSlang zu schreiben und diese auch im Programm zu nutzen. Ich habe im Themenbereich &amp;quot;glSlang&amp;quot; versucht alle Bereiche der Shadersprache selbst anzusprechen und hoffe das auch brauchbar rübergebracht zu haben. Um oben erlerntes (hoffe ich doch mal) nochmal zu vertiefen werde ich jetzt (wie ich das bereits bei meinem ARB_VP-Tutorial getan habe) einen simplen Beispielshader (Vertex und Fragment Shader) auseinanderpflücken um so u.a. auch die Programmstruktur für alle die in C nicht so bewandert sind zu erörtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Vertex Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_FrontColor   = gl_Color * GlobalColor;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie gesagt recht simpel. Angefangen wird mit der Deklaration einer globalen Uniformvariable namens {{INLINE_CODE|GlobalColor}}. Wie wir uns erinnern gibt der Typenqualifizierer uniform an, das wir den Wert dieser Variable (ein 4-Komponentenvektor, da Farbwerte aus R,G,B und A bestehen) in unserem Programm an den Shader übermitteln.&lt;br /&gt;
&lt;br /&gt;
Danach gehts ohne Umwege direkt in unsere Hauptfunktion, da wir im Vertex Shader keine anderen Funktionen benötigen. Dort berechnen wir zuerst die homogene Position unseres Vertex, die sich aus der eingehenden Vertexposition multipliziert mit der Modelansichtsmatrix ergibt. Wie schonmal gesagt '''muss diesem Wert etwas zugewiesen werden''', da sonst alle darauf aufbauenden Funktionen unvorhersehbare Ergebnisse liefern.&lt;br /&gt;
Außerdem wollen wir die Frontfarbe unseres Vertex jedesmal mit der im Programm übergebenen GlobalColor multiplizieren, so dass wir den Farbwert der gesamten Szene aus unserem Programm heraus manipulieren können. Zu guterletzt geben wir dann noch unsere aus der festen Funktionspipeline erhaltenen Texturkoordinaten auf Textureinheit 0 weiter. Wenn im Fragmentshader Texturkoordinaten verwendet werden, '''muss das getan werden'''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Fragment Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
uniform sampler2D Texture2;&lt;br /&gt;
uniform sampler2D Texture3;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec2 TexCoord = vec2( gl_TexCoord[0] );&lt;br /&gt;
 vec4 RGB      = texture2D( Texture0, TexCoord );&lt;br /&gt;
&lt;br /&gt;
 gl_FragColor  = texture2D(Texture1, TexCoord) * RGB.r +&lt;br /&gt;
                 texture2D(Texture2, TexCoord) * RGB.g +&lt;br /&gt;
                 texture2D(Texture3, TexCoord) * RGB.b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier passiert nicht wirklich viel Großartiges. Wir deklarieren beim Shaderanfang zuerst vier Texturensampler, da wir insgesamt vier verschiedene Texturen im Shader auslesen wollen, eine Verlaufstextur und drei Oberflächentexturen. Auch hier sei wieder gesagt das man Sampler '''immer als uniform deklarieren muss'''. In der Hauptfunktion deklarieren wir dann einen Farbvektor, der auch direkt einen Farbwert aus Textureinheit 0 zugewiesen bekommt. Auf Textureinheit 0 haben wir ihm Hauptprogramm eine Verlaufstextur gebunden, die angibt wie die drei folgenden Texturen ineinander geblendet werden.&lt;br /&gt;
Danach schreiben wir dann den Farbwert des Fragmentes, der '''im Fragment Shader ausgegeben werden muss'''. Der besteht wie einfach zu erkennen aus Farbwert von Textureinheit 1 * Rotwert von Textureinheit 0 + Farbwert von Textureinheit 2 * Grünwert von Textureinheit 0 + Farbwert von Textureinheit 3 * Blauwert von Textureinheit 0. So ist z.B. an Stellen an denen in der Verlaufstextur reines blau liegt nur die dritte Textur sichtbar.&lt;br /&gt;
&lt;br /&gt;
So viel also zu unserem kleinen Beispielshader. Er ist weder besonders toll noch besonders sinnvoll, sollte aber auch eher dazu dienen euch glSlang ein wenig zu veranschaulichen, was mir hoffentlich gelungen ist.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr in den vorangegangenen Kapiteln zumindest ein wenig aufgepasst habt, dann könnt ihr euch vor eurem inneren Auge hoffentlich vortstellen was der Shader macht : Er blendet drei Texturen weich anhand der Verlaufstextur ineinander über. Sowas kann man z.B. für ein Terrain nutzen, um dieses anhand einer Farbtextur zu texturieren. Für alle, die damit Probleme haben hier zwei Bilder die den Shader veranschaulichen. Links die Verlaufstextur, die angibt wo welche Textur wie stark gewichtet wird und rechts dann das Ergebnis :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; [[BILD:GLSL_sample_shader_a.jpg]] [[BILD:GLSL_sample_shader_b.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post Mortem=&lt;br /&gt;
Das wars also, meine &amp;quot;Einführung&amp;quot; in die OpenGL Shader Sprache. Ich hoffe es hat euch nicht gelangweilt und auch die von mir zur Verfügung gestellten Informationen haben euch hoffentlich ausgereicht. Mit der Veröffentlichung dieser Einführung geht übrigens auch die Eröffnung eines Shaderforums hier auf der DGL einher, in der ihr dann also fleissig Fragen zum Thema stellen oder eure Shader präsentieren könnt. In diesem Post Mortem gehe ich jetzt noch kurz auf die Zukunft von glSlang ein und zeige ein paar Screenshots (damit die Augen entspannen können), bevor ihr euch dann selbst in die Shaderwelt stürzen könnt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
Anbei ein paar exemplarische Screenshots. Da man mit GLSL aber alle möglichen Effekte berechnen kann (u.a. auch 1:1 die feste Funktionspipeline) ist es hier unmöglich einen Überblick aller möglichen Techniken zu geben.&lt;br /&gt;
&lt;br /&gt;
[[Datei:tut_glsl_eigenershader_01.png]] [[Datei:tut_glsl_eigenershader_02.png]] [[Datei:tut_glsl_eigenershader_03.png]]&lt;br /&gt;
&lt;br /&gt;
Wie im ersten (und dritten) Screenshot zu sehen ist es natürlich auch möglich mehrere Techniken innerhalb einer Szene zu nutzen. Hier sind letztendlich bis auf Hardwarelimitationen keine Grenzen gesetzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Als dieses Tutorial geschrieben wurde, war noch nicht ganz abzusehen dass bzw. ob sich GLSL auch durchsetzen würde. ARB-Shadr und NVidias cG waren damals die Platzhirsche, aber inzwischen werden ARB-Shader nicht mehr genutzt (und auch schon länger nicht mehr weiterentwickelt) und auch NVidia setzt primär auf GLSL. GLSL wird permanent weiterenwtickelt und Hersteller können dank des flexiblen Extensionsystems auch in GLSL eigene Extensions offenlegen um die aktuellsten Features (wie z.b. den Tesselator auf aktuellen ATI-Karten) nutzen zu können. GLSL gilt inzwischen auch offizielle die Shadersprache für OpenGL und wird permanent an die neusten technischen Entwicklungen im Grafikkartenbereich angepasst.&lt;br /&gt;
&lt;br /&gt;
Wer also unter OpenGL etwas mit Shadern machen möchte, kommt an GLSL nicht vorbei!&lt;br /&gt;
&lt;br /&gt;
Also viel Spaß beim Experimentieren und Shaderschreiben! Und nicht vergessen : Wir wollen sehen was ihr so treibt,&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_glsl2]]}}&lt;br /&gt;
[[Kategorie:Tutorial|GLSL]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25660</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25660"/>
				<updated>2012-03-24T14:24:01Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: /* Geometrie */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Einleitung=&lt;br /&gt;
Hallo und willkommen bei meiner &amp;quot;Einführung&amp;quot; in GLSL (kurz für &amp;quot;Open'''GL''' '''S'''hading '''L'''anguage&amp;quot;), der offiziellen Hochlevel-Shadersprache von OpenGL. In diesem umfangreichen Dokument werde ich versuchen, sowohl auf die Nutzung (sprich das Laden und Anhängen von Shadern im Quellcode), als auch auf die Programmierung von Shadern selbst einzugehen, inklusive aller Sprachelemente der OpenGL Shadersprache. Es wird also auch recht viele Informationen zu der C-ähnlichen Programmstruktur und den von GLSL angebotenen Variablen und Attributen gehen. Am Ende dieser Einführung sollten alle die, die sich für das Thema interessieren, in der Lage sein, zumindest einfach Shader zu schreiben und auch in ihren Programmen zu nutzen. Außerdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von Khronoes veröffentlichten Shaderspezifikationen, und damit als alltägliches Nachschlagewerk, dienen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Wie auch schon mein ARB_VP-Tutorial richtet sich auch diese Einführung aufgrund ihrer Thematik eher an die fortgeschritteneren GL-Programmierer und neben sehr guten GL-Kenntnissen sollten sich alle, die sich daran versuchen wollen, mit den technischen Hintergründen der GL, wie z.B. dem Aufbau der Renderpipeline auskennen. Weiterhin sind C-Kenntnisse absolut erforderlich, da die Shader ja in einer an ANSI-C angelehnten Syntax geschrieben werden. Auch Begriffsdefinitionen zu Vertex oder Fragment werden zum Verständis dieser Einführung benötigt. Wer also noch am Anfang seiner GL-Karriere steht, dem wird dieses Dokument nicht viel nützen. Ganz nebenbei solltet ihr auch noch eine gehörige Portion Zeit (am besten nen kompletten Nachmittag) mitbringen, denn die folgende Kost ist nicht nur umfangreich, sondern auch manchmal recht schwer verdaulich.&lt;br /&gt;
&lt;br /&gt;
=Was ist GLSL?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei GLSL um eine Shadersprache, also um eine Hochsprache, in der man die programmierbaren Teile aktueller Grafikbeschleuniger nach eigenem Belieben programmieren kann. Sie stellt quasi den Nachfolger zu den in Assembler geschriebenen Vertex- und Fragmentprogrammen ([[GL_ARB_vertex_program]]/[[GL_ARB_fragment_program]]) dar und basiert auf ANSI C, erweitert um Vektor- und Matrixtypen sowie einige C++-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
Die in GLSL geschriebenen Programme nennen sich, angepasst an die Terminologie von RenderMan und DirectX, [[Shader]] (im Gegensatz zu &amp;quot;Programme&amp;quot; bei ARB_VP/FP) und werden entweder auf Eckpunkte (VertexShader), Fragmente (FragmentShader) angewendet, oder (neuerdings, ab Shadermodell 4.0) auch genutzt um Geometrie zu erstellen (Geometryshader). Andere Teile der Renderpipeline (z.B. die Rasterisierung) können momentan noch nicht durch Shader beeinflusst werden, was allerdings in Zukunft noch kommen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
GLSL wurde 2005 mit OpenGL 1.5 eingeführt. Während es in Sachen Treiber- und Hardwareunterstützung anfänglich noch dürftig aussah, wird man inzwischen keine Grafikkarte mehr kaufen können die nicht zumindest Vertex- und Fragmentshader beherscht. Geometrieshader hingegen sind relativ neu und wurden erst mit Shadermodell 4.0 eingeführt, hier ist es also unter Umständen noch möglich dass selbst aktuelle Treiber/Karten keine Geometrieshader beherrschen.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt man auch einen passenden OpenGL-Header der die für GLSL nötigen Funktionen exportiert. Ich verweise dazu auf unseren eigenen OpenGL-Header [[DGLOpenGL.pas]], der peermanent auf dem aktuellsten Stand gehalten wird und auch Support für Geometrieshader mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
&lt;br /&gt;
Die GL-Shadersprache &amp;quot;besteht&amp;quot; in ihrer aktuellen Version aus folgenden Extensions, fürs Verständnis wäre es nicht schlecht, wenn ihr euch zumindest die Einleitungen dazu durchlest :&lt;br /&gt;
* [[GL_ARB_shader_objects]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shader_objects.txt Originalspezifikation])&lt;br /&gt;
: Definiert die API-Aufrufe, die zum Erstellen, Kompilieren, Linken, Anhängen und Aktivieren von Shader- und Programmobjekten nötig sind. &lt;br /&gt;
* [[GL_ARB_vertex_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Vertexebene hinzu. &lt;br /&gt;
* [[GL_ARB_fragment_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Fragmentebene hinzu. &lt;br /&gt;
* [[GL_ARB_shading_language_100]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shading_language_100.txt Originalspezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis''' : Seit OpenGL 2.0 ist GLSL Teil des Kerns. Wenn die Karte also OpenGL 2.0 unterstützt, dann unterstützt sie auch (zumindest in Software) Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sprachversionen==&lt;br /&gt;
&lt;br /&gt;
Neben der OpenGL-Version und dem vorhandenen Shadermodell (das eher an DirectX ausgerichtet ist), bietet auch GLSL verschiedene Versionen, die entsprechend erweiterte Funktionalität bieten.&lt;br /&gt;
&lt;br /&gt;
Auslesen kann man die verfürgbare GLSL-Version wie folgt:&lt;br /&gt;
&lt;br /&gt;
 glGetString(GL_SHADING_LANGUAGE_VERSION)&lt;br /&gt;
&lt;br /&gt;
Erst ab Version 1.4. kann man davon ausgehen dass GLSL alle Features des Shadermodells 4.0 liefert, ab 1.3 grob gesagt Shadermodell 3.0 (bei GLSL lässt sich das leider nicht so leicht unterteilen).&lt;br /&gt;
&lt;br /&gt;
Außerdem kann man seinem Shader eine Versionsnummer verpassen. Sollte der Shadercompiler (also Treiber bzw. Hardware) diese Version nicht unterstützen, gibt dieser eine Fehlermeldung heraus:&lt;br /&gt;
&lt;br /&gt;
 #version 1.50 &lt;br /&gt;
&lt;br /&gt;
''(Hinweis: Muss am Anfang des Shaders stehen)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&lt;br /&gt;
&lt;br /&gt;
Im Zuge der Vereinheitlichung der GL wird immer häufiger in Objekte gekapselt, deren API dann auch aneinander angelehnt ist. Ziel ist, dabei die Programmierung der GL uniform zu machen, so dass z.B. zwischen dem Erstellen und Verwalten eines Vertex-Buffer-Objektes oder eines Shader-Objektes kaum ein Unterschied besteht (demnächst kommen dann auch Pixel-Buffer-Objekte dazu). Mit glSlang wurden dann im Zuge dieser Aktion zwei neue Objekte eingeführt, deren Definition ihr euch unbedingt einprägen solltet:&lt;br /&gt;
&lt;br /&gt;
* '''Programmobjekt'''&lt;br /&gt;
:Ein Objekt, an das die Shader später angebunden werden. Bietet Funktionalität zum Linken der Shader und prüft dabei die Kompatibilität zwischen Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
* '''Shaderobjekt'''&lt;br /&gt;
:Dieses Objekt verwaltet den Quellcodestring eines Shaders und ist entweder vom Typ '''GL_VERTEX_SHADER''', '''GL_FRAGMENT_SHADER_ARB''' oder '''GL_GEOMETRY_SHADER'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
&lt;br /&gt;
Die Shadersprache ist keinesfalls final und es wurden bereits diverse Ausdrücke für zukünftige Verwendung reserviert, denn ein Ziel bei ihrer Entwicklung war es, sie so zukunftsorientiert zu gestalten, dass auch Grafikkarten der nächsten und übernächsten Generation voll ausgenutzt werden können. Damit einher geht die Tatsache, dass sich die Spezifikationen in Zukunft ändern/erweitern werden, weshalb man da immer einen Blick hineinwerfen sollte. Die Anlaufstelle dafür ist die [http://www.opengl.org/documentation/specs/ Spezifikationenliste auf OpenGL.org].&lt;br /&gt;
&lt;br /&gt;
=GLSL im Programm=&lt;br /&gt;
Bevor wir uns mit der Syntax von glSlang beschäftigen, zeige ich euch erstmal, wie ihr Shader in euer Programm einbindet und nutzt. Warum das zuerst? Ganz einfach deshalb, weil ihr dann das, was ihr im glSlang-Syntaxteil lernt, direkt in eurer Testanwendung verwenden könnt. Hoffe diese Entscheidung klingt logisch und findet Anklang.&lt;br /&gt;
&lt;br /&gt;
Zuerst benötigen wir natürlich unsere Objekte. Zum einen ein ''Programmobjekt'', an das unsere Shader gebunden werden, und zwei ''Shaderobjekte'', die den Quellcode unseres Vertex bzw. Fragment Shaders aufnehmen. Dazu wurde eigens der neue &amp;quot;Datentyp&amp;quot; {{INLINE_CODE|glHandle}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandle;&lt;br /&gt;
 VertexShaderObject   : GLhandle;&lt;br /&gt;
 FragmentShaderObject : GLhandle;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dieser Deklaration können wir dann damit beginnen unsere Objekte zu erstellen. Den Anfang macht das Programmobjekt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        := glCreateProgram;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgram]] erstellt uns oben ein leeres Programmobjekt und gibt ein gültiges Handle darauf zurück.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Erstellung unseres Vertex bzw. Fragment Shaders :&lt;br /&gt;
&lt;br /&gt;
 VertexShaderObject   := glCreateShader(GL_VERTEX_SHADER);&lt;br /&gt;
 FragmentShaderObject := glCreateShader(GL_FRAGMENT_SHADER);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShader]] dient zur Generierung eines leeren Shaderobjektes. Momentan unterstützt diese Funktion VertexShader und FragmentShader.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun also zwei gültige Shaderobjekte haben, wollen wir diese auch mit entsprechendem Quellcode versorgen :&lt;br /&gt;
&lt;br /&gt;
 glShaderSource(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSource(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSource]] setzen wir den Quellcode eines Shaderobjektes ''komplett'' neu. Zum Laden des Quellcodes bietet sich unter Delphi übrigens eine TStringList geradezu an. Es sollte beachtet werden, dass der Quellcode zu diesem Zeitpunkt ''nicht geparst'' wird, also keine Fehleruntersuchung stattfindet.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode wurde jetzt also an unsere Shaderobjekte gebunden und sollte dann natürlich auch noch kompiliert werden :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 glCompileShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShader]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der Shadercompiler (je nach Treiber) recht detaillierte Infos aus. Wie man an diese Infos kommt könnt ihr gleich nachlesen.&lt;br /&gt;
&lt;br /&gt;
Wenn unsere Shader dann kompiliert werden konnten, ist es Zeit, diese an unser anfangs erstelltes Programmobjekt anzuhängen :&lt;br /&gt;
&lt;br /&gt;
 glAttachShader(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachShader(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehängt wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteShader(VertexShaderObject);&lt;br /&gt;
 glDeleteShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Schluß müssen wir dann noch unsere ans Programmobjekt gebundenen Shader linken :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShader]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgram]] die angehangenen Shader zu einem ausführbaren Shader gelinkt. Folgende Bedingungen führen zu einem '''Linkerfehler''':&lt;br /&gt;
&lt;br /&gt;
* Die Zahl der von der Implementation unterstützten Attributvariablen wurde überschritten&lt;br /&gt;
* Der Speicherplatz für Uniformvariablen wurde überschritten&lt;br /&gt;
* Die Zahl der von der Implementation angebotenen Sampler wurde überschritten&lt;br /&gt;
* Die main-Funktion fehlt&lt;br /&gt;
* Die Liste der Varying-Variablen des Vertexshaders stimmt nicht mit der des Fragmentshaders überein&lt;br /&gt;
* Funktions- oder Variablenname nicht gefunden&lt;br /&gt;
* Eine gemeinsame Globale ist mit unterschiedlichen Werten oder Typen initialisiert worden&lt;br /&gt;
* Zwei Sampler unterschiedlichen Typs zeigen auf die selbe Textureneinheit&lt;br /&gt;
* Ein oder mehrere angehangene(r) Shader wurden nicht erfolgreich kompiliert&lt;br /&gt;
&lt;br /&gt;
Die Nutzung von glSlang im eigenen Programm ist wie oben erkennbar also nicht wirklich schwer und innerhalb kurzer Zeit realisiert. Natürlich ist es auch möglich z.B. nur einen VertexShader oder nur einen FragmentShader an ein Programmobjekt zu binden.&lt;br /&gt;
&lt;br /&gt;
Noch eine kleine Notiz zum Löschen der Shader mittel [[glDeleteShader]] : Da Shader(objekte) einen Referenzzähler besitzen und erst gelöscht werden wenn diese nirgendwo mehr benötigt werden, ist es nicht falsch diese vor dem Linkvorgang zu löschen. Allerdings spielt es letztendlich keine Rolle ob die Löschanweisung vorher der nachher ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fehlererkennung==&lt;br /&gt;
Natürlich wird es ohne Fehlerausgabe recht schwer, etwaige Probleme in einem Vertex- oder Fragmentshader zu finden. Doch auch in diesem Bereich wurde glSlang recht gut durchdacht und es wurden zwei Funktionen eingeführt, welche im Zusammenspiel die Fehlersuche recht einfach machen, nämlich [[glGetShaderInfoLog]] und [[glGetShader]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH}}. Erstere Funktion liefert uns einen Logstring, während uns letztere Funktion dessen Länge angibt. Der Logstring wird verändert, sobald ein Shader kompiliert oder ein Programm gelinkt wird.&lt;br /&gt;
&lt;br /&gt;
Um die Ausgabe dieses Logs so einfach wie möglich zu machen, bietet es sich an beide in einer einfach Funktion unterzubringen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function glSlang_GetInfoLog(pShader: GLHandleARB): String;&lt;br /&gt;
var&lt;br /&gt;
  blen, slen: GLInt;&lt;br /&gt;
  InfoLog: PGLCharARB;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  glGetShaderiv(glObject, GL_INFO_LOG_LENGTH , @blen);&lt;br /&gt;
  if blen &amp;gt; 1 then&lt;br /&gt;
  begin&lt;br /&gt;
    GetMem(InfoLog, blen * SizeOf(GLCharARB));&lt;br /&gt;
    glGetShaderInfoLog(pShader, blen, slen, InfoLog);&lt;br /&gt;
    Result := PChar(InfoLog);&lt;br /&gt;
    Dispose(InfoLog);&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist recht leicht erklärt : Zuerst lassen wir uns über {{INLINE_CODE|glGetShaderiv}} mitteilen wie lang der aktuelle Infolog ist. Sollte dort tatsächlich etwas drinstehen (blen &amp;gt; 1), dann lassen wir uns dessen Inhalt via {{INLINE_CODE|glGetShaderInfoLog}} in {{INLINE_CODE|InfoLog}} ausgeben und liefern diesen als Ergebnis zurück.&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt wird nur nach dem Kompilieren eines Shaders bzw. dem Linken eines Programmobjektes ein Infolog erstellt. Es bietet sich dadurch an, direkt danach einen solchen Aufruf zu machen :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 ShowMessage(glSlang_GetInfoLog(VertexShaderObject));&lt;br /&gt;
&lt;br /&gt;
Wenn unser Vertex Shader komplett fehlerfrei kompiliert werden konnte, dann sehen wir als Ergebnis nur einen leeren Dialog. Ist dies nicht der Fall, so werden wir vom Treiber mit recht detaillierten Fehlerinformationen &amp;quot;belohnt&amp;quot;, z.B. so :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL_error_vshader.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch das Infolog nach dem Linken des Programmobjektes dürfte, selbst wenn keine Fehler vorkommen, recht interessant sein, das sieht dann nämlich so aus :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL info programobject.jpg]]&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen, wird uns nach dem erfolgreichen Linken auch gesagt, ob und welcher Shader in Hardware bzw. Software läuft. Für Debuggingzwecke sicherlich eine mehr als brauchbare Information.&lt;br /&gt;
&lt;br /&gt;
==Shader benutzen==&lt;br /&gt;
Um den Shader auch für die nächsten Polygone zu benutzen oder Uniformparameter übergeben zu können, ruft man die Funktion&lt;br /&gt;
 glUseProgramt(ProgramObject);&lt;br /&gt;
um alle Shader zu deaktivieren, ruft man dieselbe Funktion mit dem Parameter 0.&lt;br /&gt;
&lt;br /&gt;
==Parameterübergabe==&lt;br /&gt;
Uniformparameter (mehr dazu später) stellen die Schnittstelle zwischen eurem Programm und dem Shader dar, werden also genutzt um Daten aus dem Programm heraus an einen Shader zu übergeben. Zur Übergabe dieser Parameter bietet OpenGL diverse Funktionen, die alle Abkömmlinge von [[glUniform]] sind. Während mit {{INLINE_CODE|glUniform4f}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fv}} ganze Matrizen schnell und einfach übergeben. Außerdem gibt es nun die Möglichkeit Uniformparameter direkt über ihren Namen, statt wie unter ARB_FP/VP über einen festen Index zu adressieren. Die Funktion [[glGetUniformLocationARB]] gibt anhand des übergebenen Parameternamens dessen Position zurück. Man kann also ganz einfach über den Namen drauf zugreifen :&lt;br /&gt;
&lt;br /&gt;
 glUniform3f(glGetUniformLocation(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1i(glGetUniformLocation(ProgramObject, PGLCharARB('texSamplerTMU3')), 3);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier, das man je nach Parametertyp auch die passende Anzahl von Argumenten übergibt. Also für einen 4-Komponenten Floatvektor {{INLINE_CODE|glUniform4fARB}} und für einen einfachen Integerwert (z.B. Textureinheit für einen Sampler) glUnifrom1iARB. Auch nicht vergessen dürft ihr, das die Namen der Parameter genauso wie im Shader geschrieben werden müssen, also Groß- und Kleinschreibung beachtet werden muß.&lt;br /&gt;
&lt;br /&gt;
=Die Shadersprache=&lt;br /&gt;
&lt;br /&gt;
Nachdem wir uns mit der Einbindung der glSlang-Shader in unser Programm beschäftigt haben, wollen wir uns in den folgenden Kapiteln um die Sprachelemente von glSlang kümmern. Wie schon gesagt basiert glSlang auf ANSI-C, wurde allerdings um speziell auf den Zielbereich angepasste Vektor- und Matrixtypen und einige C++-Features wie das freie deklarieren von Variablen an jeder Stelle und das Funktionsüberladen auf Basis des Argumenttyps erweitert. Wer sich ein wenig mit C/C++ auskennt sollte also in der nun folgenden Materie keine Probleme bekommen.&lt;br /&gt;
&lt;br /&gt;
'''Obligatorische Hinweise für verwöhnte Delphi-Nutzer : '''&lt;br /&gt;
*Wie von C/C++ her gewohnt, spielt auch in glSlang die Groß- und Kleinschreibung eine wichtige Rolle, also bitte achtet darauf. gl_Position ist eine komplett andere Variable als z.B. gl_position.&lt;br /&gt;
*Es findet keine automatische Typenkonvertierung statt. Das bedeutet also das float MyFloat = 1 ungültig ist und es in dem Falle float MyFloat = 1.0 heissen muss. Typecasts müssen also immer manuell stattfinden, z.B. MyFloat = float(MyInt).&lt;br /&gt;
&lt;br /&gt;
'''Kleine Programmstrukturkunde für C-Unkundige :'''&amp;lt;br&amp;gt;&lt;br /&gt;
Da sicherlich einige Delpher nie richtig was mit C gemacht haben, zeige ich mal anhand eines kleinen Beispieles (das auf keinen Fall nen brauchbaren Shader darstellt) den grundlegenden Aufbau eines glSlang-Shaders, der natürlich dem Aufbau eines C-Programmes stark ähnelt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 VariableA;&lt;br /&gt;
float VariableB;&lt;br /&gt;
vec3  VariableC;&lt;br /&gt;
const float KonstanteA = 256.0;&lt;br /&gt;
&lt;br /&gt;
float MyFunction(vec4 ArgumentA)&lt;br /&gt;
{&lt;br /&gt;
    float FunktionsVariableA = float(5.0);&lt;br /&gt;
&lt;br /&gt;
    return float(ArgumentA * (FunktionsVariableA + KonstanteA));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Ich bin ein Kommentar&lt;br /&gt;
/* Und ich auch */&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
    gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht doch recht bekannt aus, unser Programmaufbau. Delphi und C haben ja so einige Grundlagen gleich, darunter auch der ungefähre Programmaufbau. Ausserhalb jeglicher Funktionen legen wir am Programmanfang unsere Variablen, Konstanten und Attribute fest, die dann ''global'' nutzbar sind, also in jeder Funktion.&lt;br /&gt;
&lt;br /&gt;
Darunter deklarieren wir dann eine kleine Funktion. Wie auch bei den Variablendeklarationen wird hier der Rückgabetyp nicht wie bei Pascal nach dem Funktionsnamen untergebracht, sondern davor. Innerhalb der Funktion können dann wieder Variablen deklariert werden, die dann allerdings ''lokal'', also nur in dieser Funktion nutzbar sind. Vorteil dieser Deklaration ist die Tatsache, dass je nach Grafikkarte nur bestimmt viele globale Variablen deklariert werden können. Wenn möglich sollte man also mit lokalen Vorlieb nehmen. Unsere Funktion gibt dann natürlich noch via return einen Wert zurück, ''was gemacht werden muss'', sofern man diese nicht als void deklariert hat (entspräche dann einer Prozedur in Pascal). Wird dies nicht getan, so spuckt der Compiler einen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Auch wichtig sind natürlich Kommentare. Erste Variante (Doppelslash) ist auch in der Pascalwelt verfügbar und kommentiert eine einzelne Zeile aus. Die Variante darunter kann man für Kommentarblöcke nutzen (/* .. */) und entspricht den Kommentaren in geschweiften Klammern in Delphi.&lt;br /&gt;
&lt;br /&gt;
Danach kommt dann die '''wichtigste Funktion''' des Shaders, nämlich '''main''', die in keinem Shader fehlen darf. Sie stellt quasi den Programmkörper dar und ist oft auch die einzige Funktion in einem Shader. Sie erhält weder ein Argument, noch gibt sie einen Wert zurück.&lt;br /&gt;
&lt;br /&gt;
Soviel also zum grundlegenden Aufbau eines Shader. Hoffe das jetzt alle die in C nicht so bewandert sind damit klar kommen, und dann bald ihre ersten glSlang-Shader schreiben können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Datentypen==&lt;br /&gt;
&lt;br /&gt;
Obwohl einige Datentypen aus C übernommen wurden, sieht man der Typenliste an, das diese speziell auf den 3D-Bereich zugeschnitten wurde. Variablen müssen vor ihrer Nutzung eindeutig deklariert sein, Typecasting erfolgt über Konstruktoren (dazu später mehr). Folgende Datentypen stehen sowohl im Vertex- als auch Fragmentshader zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|void 	&lt;br /&gt;
|Für Funktionen die keinen Wert zurückgeben&lt;br /&gt;
|-&lt;br /&gt;
|bool 	&lt;br /&gt;
|Konditionaler Typ, entweder true (wahr) oder false (falsch)&lt;br /&gt;
|-&lt;br /&gt;
|int 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenbehafteter Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|uint 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenloser Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|float 	&lt;br /&gt;
|Fließkommaskalar mit Singlegenauigkeit (32 Bit)&lt;br /&gt;
|-&lt;br /&gt;
|vec2 	&lt;br /&gt;
|2-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec3 	&lt;br /&gt;
|3-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec4 	&lt;br /&gt;
|4-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec2 	&lt;br /&gt;
|2-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec3 	&lt;br /&gt;
|3-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec4 	&lt;br /&gt;
|4-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec2 	&lt;br /&gt;
|2-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec2 	&lt;br /&gt;
|2-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec3 	&lt;br /&gt;
|3-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec4 	&lt;br /&gt;
|4-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|mat2 	&lt;br /&gt;
|2x2 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat3 	&lt;br /&gt;
|3x3 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat4 	&lt;br /&gt;
|4x4 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|matMxN 	&lt;br /&gt;
|Matrix mit M Spalten und N Zeilen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse zum Zugriff auf Texturen dar, und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|sampler1D 	&lt;br /&gt;
|Zugriff auf 1D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler2D 	&lt;br /&gt;
|Zugriff auf 2D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler3D 	&lt;br /&gt;
|Zugriff auf 3D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|samplerCube 	&lt;br /&gt;
|Zugriff auf Cubemap&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRect 	&lt;br /&gt;
|Zugriff auf Texturen die nicht 2^n * 2^n entsprechen (&amp;quot;non power-of-two&amp;quot;, NPOT)&lt;br /&gt;
|-&lt;br /&gt;
|sampler1DShadow 	&lt;br /&gt;
|Zugriff auf 1D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DShadow 	&lt;br /&gt;
|Zugriff auf 2D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|samplerCubeShadow&lt;br /&gt;
|Zugriff auf Tiefentextur in einer Cubemap (z.b. für omni-diretionale Lichtquellen)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRectShadow&lt;br /&gt;
|Zugriff auf 2D-NPOT-Tiefentextur &lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|sampler1DArray&lt;br /&gt;
|Zugriff auf ein array aus 1D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArray&lt;br /&gt;
|Zugriff auf ein array aus 2D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler1DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 1D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 2D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|samplerBuffer&lt;br /&gt;
|Zugriff auf eine Puffertextur (1D-Texutr zum Speichern von Pufferobjekten)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMS&lt;br /&gt;
|Zugriff auf eine 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMSArray&lt;br /&gt;
|Zugriff auf einarray aus 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Arrays===&lt;br /&gt;
&lt;br /&gt;
Natürlich unterstützt glSlang auch Arrays, die wie in C deklariert werden und deren Index bei 0 beginnt. Folgendes Array im Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
beginnt also bei Index 0 und endet bei Index 2. Im Gegensatz zu C lassen sich Arrays in glSlang allerdings ''nicht bei der Initialisierung vorbelegen''. Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strukturen===&lt;br /&gt;
&lt;br /&gt;
Neu ggü. ARB_FP/VP ist nun auch die Möglichkeit, Strukturen in einem Shader zu deklarieren. Vor allem die Übersicht komplexerer Shader kann dadurch stark verbessert werden. Strukturen werden wie gewohnt mit dem Schlüsselwort {{INLINE_CODE|struct}} eingeleitet und können dann zur Typisierung von Variablen genutzt werden. Folgendes Beispiel dürfte die Nutzung verdeutlichen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct light&lt;br /&gt;
{&lt;br /&gt;
    bool active;&lt;br /&gt;
    float intensity;&lt;br /&gt;
    vec3 position;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
LightSource[i].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Typenqualifzierer==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur Typendeklaration kann eine Variable noch einen Typenqualifizerer vorangestellt bekommen, der an den Anfang der Deklaration gehört.&lt;br /&gt;
&lt;br /&gt;
* '''const'''&lt;br /&gt;
: Festgelegte (nur lesen) Konstante bzw. nur lesbarer Funktionsparameter.&lt;br /&gt;
&lt;br /&gt;
* '''uniform'''&lt;br /&gt;
: Ein den ganzen Shader über gleichbleibender Wert, der eine Schnittstelle zwischen dem Shader und der OpenGL-Anwendung darstellt. Ein Uniformwert wird in der Hauptanwendung an den entsprechenden Shader übergeben und kann dort dann genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* '''attribute'''&lt;br /&gt;
: Nur lesbare Werte die eine Verbindung zwischen dem Shader und der OpenGL-VertexAPI darstellen (z.B. VertexParameter eines VertexArrays). Natürlich nur in einem Vertex Shader nutzbar.&lt;br /&gt;
&lt;br /&gt;
* '''varying'''&lt;br /&gt;
: Stellt die Verbindung zwischen einem Vertex- und einem FragmentShader dar. Werden im VertexShader geschrieben und dann perspektivisch korrekt über die Primitive interpoliert, um dann im Fragment Shader gelesen werden zu können. Nutzbar sind hier nur die Typen float, vec2, vec3, vec4, mat2, mat3 und mat4, Strukturen und andere Datentypen können nicht varying sein. Die Namen einer varying-Variable müssen sowohl im VertexShader als auch im FragmentShader gleich sein.&lt;br /&gt;
&lt;br /&gt;
* '''in'''&lt;br /&gt;
: Für Variablen die an eine Funktion übergeben und dort ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* '''out'''&lt;br /&gt;
: Für Variablen die von einer Funktion nach außen zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
* '''inout'''&lt;br /&gt;
: Für Variablen die sowohl an eine Funktion übergeben als auch von dieser zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um obige Auflistung nicht leer im Raum stehen zu lassen zeige ich ein paar Beispiele die hoffentlich zum Verständnis beitragen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Vertexnormale soll an einen FragmenShader (interpoliert) übergeben werden :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
VertexNormal = normalize(MV_IT * gl_Normal);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Uniformparameter zur nachträglichen Farbänderung der Szene wird im Programm übergeben :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im Programm :&lt;br /&gt;
&lt;br /&gt;
 glUniform4fARB(glSlang_GetUniLoc(ProgramObject, 'GlobalColor'), Col[0], Col[1], Col[2], Col[3]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Beispiel C=== &lt;br /&gt;
Konstante zur festen Farbänderung :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
const vec4 ColorBias = vec4(0.2, 0.3, 0.0, 0.0);&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = ColorBias * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Konstruktoren==&lt;br /&gt;
&lt;br /&gt;
Um in einem Shader ''Vektoren'' oder ''Matrizen'' mit Werten zu belegen, gibt es sogenannte Konstruktoren (nicht zu verwechseln mit z.B. Klassenkonstruktoren unter Delphi), die im Endeffekt nichts anderes als Funktionen zur Vorbelegung von Vektoren oder Matrizen darstellen. Dabei trägt der Konstruktor den selben Namen wie die Typendeklaration, also lässt sich eine Variable vom Typ {{INLINE_CODE|vec4}} mit dem Konstruktor {{INLINE_CODE|vec4(float, float, float, float)}} initialisieren.&lt;br /&gt;
&lt;br /&gt;
Allerdings hat man sich recht viel Mühe bei dieser Konstruktorgeschichte gemacht, so dass man einen vec4 nicht unbedingt mit einem {{INLINE_CODE|vec4}}-Konstruktor vorbelegen muss, sondern es vielseitige Möglichkeiten gibt. Um dies zu verdeutlichen gibts ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(1.0, 0.0, 0.0, 0.0);&lt;br /&gt;
vec4 Color = vec4(MyVec3, 1.0);&lt;br /&gt;
vec4 Color = vec4(MyVec2_A, MyVec2_B);&lt;br /&gt;
&lt;br /&gt;
vec3 LVec  = vec3(MyVec4);&lt;br /&gt;
vec2 Tmp   = vec2(MyVec3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trotz der recht wenigen Beispiele sollte schnell erkennbar sein, das man hier wirklich sehr viele Kombinationsmöglichkeiten hat, die dann gültig sind ''wenn man mindestens auf die benötigte Anzahl der Argumente kommt''. Im vorletzten Beispiel wird z.B. ein 3-Komponentenvektor aus einem 4-Komponentenvektor initialisiert. Das erzeugt keinen Fehler, sondern führt dazu das {{INLINE_CODE|vec3.x, vec3.y, vec3.z}} aus MyVec4 übernommen werden und MyVec4.w einfach ignoriert wird.&lt;br /&gt;
&lt;br /&gt;
Das Umkehrbeispiel, also&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
funktioniert allerdings nicht, da hier die Zahl der benötigten Argumente nicht erreicht wird. In diesem Falle müsste es dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
heissen.&lt;br /&gt;
&lt;br /&gt;
Obiges gilt natürlich auch für ''Matrixkonstruktoren'', hier sind z.B. folgende Konstuktoren denkbar, obwohl eigentlich alle Möglichkeiten nutzbar sind, ''solange die benötigte Zahl an Argumenten erreicht wird'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
mat4 MyMatrix = mat4(MyVec4, MyVec4, MyVec4, MyVec4);&lt;br /&gt;
mat2 MyMatrix = mat4(1.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 1.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 1.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixkomponenten==&lt;br /&gt;
&lt;br /&gt;
Was natürlich in keiner Shadersprache fehlen darf, ist der leichte Zugriff auf die einzelnen Komponenten eines Vektors. glSlang bietet, je nach Anwendungsgebiet gleich drei Namensets für den Zugriff auf die Komponenten eines solchen Vektors, welches Set man nutzen will bleibt natürlich frei und ist unabhängig von der Deklaration eines Vektors. Man sollte nur darauf achten, beim gleichzeitigen Zugriff auf mehrere Komponenten im gleichen Namenset zu verbleiben :&lt;br /&gt;
&lt;br /&gt;
* {x, y, z, w}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Punkte, Normale oder sonstige Vertexdaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {r, g, b, a}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Farbwerte repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {s, t, p, q}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Texturkoordinaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
Ein paar Beispiele zur Unterstreichung des oben gesagten :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
v4.rgba = vec4(1.0, 0.0, 0.0, 0.0);  // gültig&lt;br /&gt;
v4.rgzw = vec4(1.0, 1.0, 1.0, 2.0);  // Ungültig, da verschiedenen Namensets&lt;br /&gt;
v2.rgb  = vec3(1.0, 2.0, 1.0);       // Ungültig, da vec2 nur r+g besitzt&lt;br /&gt;
v2.xx   = vec2(5.0, 3.0);            // Ungültig, da 2 mal gleiche Komponente&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch der Zugriff auf die Komponenten einer Matrix geht leicht von der Hand. Namensets wie bei den Vektoren gibt es hier natürlich keine, aber folgende Beispiele sollen den Zugriff aufzeigen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
MyMat4[2]    = vec4(1.0); // Setzt die 3.Zeile der Matrix komplett auf 1.0&lt;br /&gt;
MyMat4[3][3] = 3.5;       // Setzt das Element unren rechts auf 3.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Matrixelemente ausserhalb ihrer Dimension (also z.B. MyMat4[4][4]) liefert unvorhersehabre Ergebnise, also sollte man auf diese Fälle prüfen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixoperationen==&lt;br /&gt;
&lt;br /&gt;
Wie von C gewohnt sind in glSlang so ziemlich alle Operatoren die man auf Matrizen oder Vektoren anwenden kann überladen, so das man nicht umständlich über selbstgeschriebene Funktionen kombinieren muss. Darüber hinaus ist es in den meisten Fällen auch möglich ohne Konvertierung Fließkommawerte mit kompletten Matrizen oder Vektoren zu kombinieren. Folgende Beispiele zeigen einige der vielfältigen Kombinationsmöglichkeiten auf :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
float factor;&lt;br /&gt;
&lt;br /&gt;
vec3 dest = source + factor; &lt;br /&gt;
&lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = source.x + factor;&lt;br /&gt;
dest.y = source.y + factor;&lt;br /&gt;
dest.z = source.z + factor;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
mat3  MyMat;&lt;br /&gt;
 &lt;br /&gt;
dest = source * MyMat; &lt;br /&gt;
 &lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = dot(source, MyMat[0]);&lt;br /&gt;
dest.y = dot(source, MyMat[1]);&lt;br /&gt;
dest.z = dot(source, MyMat[2]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier sind die Möglichkeiten fast unbeschränkt und zeigen wieder wie flexibel glSlang ausgelegt ist. &lt;br /&gt;
&lt;br /&gt;
==Operatoren==&lt;br /&gt;
&lt;br /&gt;
glSlang bietet (momentan) folgende Operatoren, die Liste ist nach ihrer Gewichtung sortiert (Anfang = höchste). Alle ''reservierten'' Operatoren werden erst in kommender Hardware/glSlang-Versionen nutzbar sein :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div  align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Operatorklasse  	&lt;br /&gt;
!Operatoren  	&lt;br /&gt;
!Assoziation&lt;br /&gt;
|-&lt;br /&gt;
|Gruppering 	&lt;br /&gt;
|() 	&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
|Arrayindizierung&amp;lt;br&amp;gt;Funktionsaufrufe und Konstruktoren&amp;lt;br&amp;gt;Strukturfeldwahl und Swizzle&amp;lt;br&amp;gt;Postinkrement und -dekrement&amp;lt;br&amp;gt; 	&lt;br /&gt;
|[]&amp;lt;br&amp;gt;()&amp;lt;br&amp;gt;.&amp;lt;br&amp;gt;++ -- 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Prefixinkrement- und dekrement&amp;lt;br&amp;gt;Einheitlich (~ reserviert) 	&lt;br /&gt;
| ++ --&amp;lt;br&amp;gt; + - ~ ! 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Mulitplikation (% reserviert) 	&lt;br /&gt;
|* / % 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Additiv 	&lt;br /&gt;
| + - 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises Verschieben (reserviert) 	&lt;br /&gt;
|&amp;lt;&amp;lt;  &amp;gt;&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Relation 	&lt;br /&gt;
|&amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;= 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Vergleich 	&lt;br /&gt;
|==  != 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises AND (reserviert) 	&lt;br /&gt;
|&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises XOR (reserviert) 	&lt;br /&gt;
|^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises OR (reserviert) 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches AND 	&lt;br /&gt;
|&amp;amp;&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches XOR 	&lt;br /&gt;
|^^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches OR 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Auswahl 	&lt;br /&gt;
|?: 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Zuweisung&amp;lt;br&amp;gt;Arithmetrische Zuweisung&amp;lt;br&amp;gt;(Modulis, Shift und bitweise Op. reserviert) 	&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;+= -=  *=  /=  %=&amp;lt;/nowiki&amp;gt; &amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;&amp;lt;&amp;lt;=  &amp;gt;&amp;gt;= &amp;amp;=  ^=  |=&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Aufzählung 	&lt;br /&gt;
|, 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von Hochsprachen ist u.A. die Möglichkeit oft genutzte Codeteile in Funktionen (bzw. auch Prozeduren unter Pascal) zu verpacken um so Flexibilität als auch Übersichtlichkeit zu steigern. Wer schonmal was in C geschrieben hat, der wird sich jetzt sicherlich kein Kopfzerbrechen machen müssen. Funktionen werden in glSlang genauso nach folgendem Prinzip deklariert :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
RückgabeTyp FunktionsName(Typ0 Argument0, Typ1, Argument1, ... , TypN, ArgumentN)&lt;br /&gt;
 {&lt;br /&gt;
 return RückgabeWert;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, außerdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach außen übergeben soll, muss dieses Argument mit dem Typenqualifizierer out (Siehe Kapitel 4.2) versehen werden. ''Arrays'' können nur als Eingabeargumente übergeben werden und dürfen nich dimensioniert als Argument verwendet werden, sondern müssen mit leeren Klammern argumentiert werden.&lt;br /&gt;
Ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void MeineFunktion(float EingabeWert; out float AusgabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 AusgabeWert = EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach außen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float MeineFunktion(float EingabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 return EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bietet genau die selbe Funktionalität wie das Beispiel darüber. Allerdings wird hier der berechnete Wert als Ergebnis der Funktion zurückgeliefert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float VektorSumme(float v[])&lt;br /&gt;
 {&lt;br /&gt;
 return v[0]+v[1]+v[2]+v[3];&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt darf ein Array als Argument keine Dimensionierung enthalten. Wenn man der Funktion also ein Array übergibt, sollte man vorher drauf achten das es entsprechend der in der Funktion genutzten Indizes dimensioniert wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==if-Anweisung==&lt;br /&gt;
&lt;br /&gt;
Selektion über eine if-Anweisung darf auch in keiner Hochsprache fehlen. Genauso wie in C oder Delphi erwartet auch hier die If-Anweisung einen boolschen Ausdruck (Wahr oder Falsch) und wird dann ausgeführt (wahr) bzw. verzweigt auf ein (wenn vorhanden) else (falsch). Verschachtelung ist wie erwartet auch möglich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis : ''' &lt;br /&gt;
Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten im Fragmentshader kein Early-Out, was zur Folge hat das bei einer If-Anweisung immer alle Zweige ausgeführt werden. Am Ende wird dann aber nur ein Ergebnis geschrieben, die anderen verworfen. Auf solchen Karten bringen If-Anweisungen also im Normalfall keine Geschwindigkeitssteigerung, sondern oft eher das Gegenteil.&lt;br /&gt;
Neuere SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall, da hier dynamische Verzweigungen und auch Early-Out von der Hardware implementiert werden.&lt;br /&gt;
&lt;br /&gt;
==Schleifen==&lt;br /&gt;
&lt;br /&gt;
Auch Schleifen, ein wichtiges Konzept jeder Hochsprache haben ihren Weg in glSlang gefunden. Unterstützt werden folgende Schleifentypen :&lt;br /&gt;
&lt;br /&gt;
* '''for'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
do&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
 while (Durchlaufbedingung)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hinweis :''' Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten Schleifen nicht in Hardware. Schleifen werden dann beim Kompilieren vom Treiber entrollt, wodurch natürlich Shader mit weitaus mehr Instruktionen als erwartet generiert werden. Von daher sollte man auf solchen Karten möglichst auf Schleifen verzichten, oder diese nur recht kurz halten. Bei SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Variablen, Attribute und Konstanten=&lt;br /&gt;
Nachdem wir uns nun lange genug mit den minderinterssanten Elementen der glSlang-Syntax beschäftigt haben, gehts jetzt endlich an die wirklich interessanten Dinge. Wie schon ARB_VP/ARB_FP bringt auch glSlang jede Menge eingabauter Variablen, Attribute und Konstanten mit, deren Aliase sie recht leicht identifizierbar machen (ganz im Gegensatz zum Indexgewusel bei den DX-Shadern).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Vertex Shader==&lt;br /&gt;
Exklusiv im Vertex Shader stehen die folgenden Variablen zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Position    muss geschrieben werden&lt;br /&gt;
:Dieser Variable '''muss''' im Vertexshader ein Wert zugewiesen werden, wird dies nicht getan ist das Ergebnis (sprich die Position des Vertex) undefiniert. Vorgesehen ist diese Variable für die ''homogene Position des Vertex'' und wird u.a. zum Clipping und Culling verwendet. Sie darf natürlich auch (mehrfach) geschrieben und ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* float gl_PointSize    kann geschrieben werden&lt;br /&gt;
:Diese Variable wurde dazu vorgesehen um dort im VertexShader die Punktgröße in Pixeln hineinzuschreiben.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_ClipVertex    kann geschrieben werden&lt;br /&gt;
:Falls genutzt, sollten hier die Vertexkoordinaten die im Zusammenhang mit benutzerdefinierten Clippingplanes genutzt werden abgelegt werden. Wichtig ist, das gl_ClipVertex im selben Koordinatenraum wie die Clippingplane definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Attribute im Vertex Shader==&lt;br /&gt;
&lt;br /&gt;
Folgende Attribute stehen nur im Vertex Shader zur Verfügung und '''können nur gelesen werden''' :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Color&lt;br /&gt;
: Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_SecondaryColor&lt;br /&gt;
:Sekundärer Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_Normal&lt;br /&gt;
:Normale des Vertex.&lt;br /&gt;
* vec4 gl_Vertex&lt;br /&gt;
:Koordinaten des Vertex;&lt;br /&gt;
* vec4 gl_MultiTexCoord0..7&lt;br /&gt;
:Texturkoordinaten auf Textureinheit 0..7.&lt;br /&gt;
* float gl_FogCoord&lt;br /&gt;
:Nebelkoordinate des Vertex. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Fragment Shader==&lt;br /&gt;
&lt;br /&gt;
Im Fragment Shader sind folgende Variablen exklusiv nutzbar :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragColor&lt;br /&gt;
: Speichert den Farbwert des Fragmentes, der von folgenden Funktionen der festen Pipeline genutzt wird. Wird dieser Variable nichts zugewiesen, so ist ihr Inhalt undefiniert und darauf aufbauende Ergebnisse ebenfalls.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragData[0..15]&lt;br /&gt;
: Ersetzt gl_FragColor bei der Verwendung von multiplen Rendertargets. &lt;br /&gt;
&lt;br /&gt;
* float gl_FragDepth&lt;br /&gt;
: Durch schreiben dieser Variable kann man den von der festen Funktionspipeline ermittelten Tiefenwert überspringen, der mit {{INLINE_CODE|gl_FragCoord.z}} ausgelesen werden kann. Wird dieser Wert nicht geschrieben, nutzen folgende Funktionen der Pipeline den vorher fest berechneten Wert.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragCoord    nur lesen&lt;br /&gt;
: In dieser Variable ist die Position des Fragmentes relativ zur Fensterposition im Format x,y,z,1/w abgelegt, wobei z den von der festen Funktionspipeline berechneten Tiefenwert enthält.&lt;br /&gt;
&lt;br /&gt;
* bool gl_FrontFacing    nur lesen&lt;br /&gt;
: Gibt an ob das Fragment zu einer nach vorne zeigenden Primitive gehört (=true). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bezug auf {{INLINE_CODE|gl_FragColor}} und {{INLINE_CODE|gl_FragDepth}} sei noch anzumerken das diese ''nicht'' in den Wertebereich 0..1 gebracht werden müssen, da dies später durch die feste Funktionspipeline automatisch gemacht wird.&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Varyings==&lt;br /&gt;
&lt;br /&gt;
Wie bereits in Kapitel 4.2 erwähnt, stellen Varyings eine Schnittstelle zwischen dem Vertex und dem Fragment Shader dar. Sie werden im Vertex Shader geschrieben und können dann im Fragment Shader ausgelesen werden, ohne das die folgenden Varyings dafür explizit deklariert werden müssen :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontColor&lt;br /&gt;
: Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackColor&lt;br /&gt;
: Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_TexCoord[x]&lt;br /&gt;
: Texturkoordinaten des Vertex auf Textureinheit x, wobei x die von der Hardware zur Verfügung gestellte Zahl der Textureinheiten-1 nicht überschreiten darf.&lt;br /&gt;
&lt;br /&gt;
* float gl_FogFragCoord&lt;br /&gt;
: Nebelkoordinate des Fragmentes. &lt;br /&gt;
&lt;br /&gt;
Die Varyings {{INLINE_CODE|gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor}} und {{INLINE_CODE|gl_BackSecondaryColor}} können im FragmentShader nur unter den Aliases gl_Color bzw. gl_SecondaryColor gelesen werden. Welcher Wert des Vertex Shaders im Fragment Shader dort eingesetzt wird ist abhängig davon ob das Fragment zu einer nach vorne oder nach hinten zeigenden Primitive gehört.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Konstanten==&lt;br /&gt;
Auch diverse Konstanten wurden definiert um darauf schnell im Shader zugreifen zu können. In den Klammern stehen die von einer GL-Implementation als Mindestanforderung anzubietenden Werte. Alle Konstanten sind sowohl im Vertex als auch im Fragment Shader abrufbar :&lt;br /&gt;
&lt;br /&gt;
: OpenGL 1.0/1.2 :&lt;br /&gt;
* int gl_MaxLights (8)&lt;br /&gt;
* int gl_MaxClipPlanes (6)&lt;br /&gt;
* int gl_MaxTextureUnits (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: ARB_Fragment_Program :&lt;br /&gt;
* int gl_MaxTextureCoordsARB (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Vertex_Shader :&lt;br /&gt;
* int gl_MaxVertexAttributesGL2 (16)&lt;br /&gt;
* int gl_MaxVertexUniformFloatsGL2 (512)&lt;br /&gt;
* int gl_MaxVaryingFloatsGL2 (32)&lt;br /&gt;
* int gl_MaxVertexTextureUnitsGL2 (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Fragment_Shader :&lt;br /&gt;
* int gl_MaxFragmentTextureUnitsGL2 (2)&lt;br /&gt;
* int gl_MaxFragmentUniformFloatsGL2 (64)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Uniformvariablen==&lt;br /&gt;
&lt;br /&gt;
Um den Zugriff auf OpenGL-Staten zu vereinfachen wurden in glSlang diverse Uniformvariablen zur direkten Verwendung im Shader eingebaut. Wie gewohnt wurden auch hier sinnvolle Namen verwendet, so dass eine tiefere Erklärung unnötig sein dürfte :&lt;br /&gt;
&lt;br /&gt;
* mat4 gl_ModelViewMatrix&lt;br /&gt;
* mat4 gl_ProjectionMatrix&lt;br /&gt;
* mat4 gl_ModelViewProjectionMatrix&lt;br /&gt;
* mat3 gl_NormalMatrix&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die invertierten und anschließend transponierten oberen 3x3 Werte der {{INLINE_CODE|gl_ModelViewMatrix}}.&lt;br /&gt;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
* float gl_NormalScale&lt;br /&gt;
: Gibt den unter OpenGL festgelegten Faktor zur Skalierung der Normalen zurück.&lt;br /&gt;
&lt;br /&gt;
* struct gl_DepthRangeParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_DepthRangeParameters&lt;br /&gt;
{&lt;br /&gt;
 float near;&lt;br /&gt;
 float far;&lt;br /&gt;
 float diff;&lt;br /&gt;
};&lt;br /&gt;
gl_DepthRangeParameters gl_DepthRange;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_PointParameters&lt;br /&gt;
{&lt;br /&gt;
 float size;&lt;br /&gt;
 float sizeMin;&lt;br /&gt;
 float sizeMax;&lt;br /&gt;
 float fadeThresholdSize;&lt;br /&gt;
 float distanceConstantAttenuation;&lt;br /&gt;
 float distanceLinearAttenuation;&lt;br /&gt;
 float distanceQuadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_PointParameters gl_Point;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_MaterialParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 emission;&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 float shininess;&lt;br /&gt;
};&lt;br /&gt;
gl_MaterialParameters gl_FrontMaterial;&lt;br /&gt;
gl_MaterialParameters gl_BackMaterial;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightSourceParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 vec4 position;&lt;br /&gt;
 vec4 halfVector;&lt;br /&gt;
 vec3 spotDirection;&lt;br /&gt;
 float spotExponent;&lt;br /&gt;
 float spotCutoff;&lt;br /&gt;
 float spotCosCutoff;&lt;br /&gt;
 float constantAttenuation;&lt;br /&gt;
 float linearAttenuation;&lt;br /&gt;
 float quadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_LightSourceParameters gl_LightSource[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelParameters gl_LightModel;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 sceneColor;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelProducts gl_FrontLightModelProduct;&lt;br /&gt;
gl_LightModelProducts gl_BackLightModelProduct;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
};&lt;br /&gt;
gl_LightProducts gl_FrontLightProduct[gl_MaxLights];&lt;br /&gt;
gl_LightProducts gl_BackLightProduct[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* vec4 gl_TextureEnvColor[gl_MaxFragmentTextureUnitsGL2]&lt;br /&gt;
* vec4 gl_EyePlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
*struct gl_FogParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_FogParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 color;&lt;br /&gt;
 float density;&lt;br /&gt;
 float start;&lt;br /&gt;
 float end;&lt;br /&gt;
 float scale;&lt;br /&gt;
};&lt;br /&gt;
gl_FogParameters gl_Fog;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese recht umfangreiche GL-Stateliste sollte eigentlich jeden Bedarf decken und momentan gibts kaum einen OpenGL-Status den man so nicht in einem Shader abfragen bzw. nutzen kann.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Funktionen=&lt;br /&gt;
glSlang ist mit diversen Skalar- und Vektorfunktionen ausgestattet, die teilweise (idealerweise) sogar direkt in der Hardware ausgeführt werden, weshalb einer fertigen Funktion ggü. gleichwertigen eigenen Berechnungen immer der Vorzug zu geben ist.&lt;br /&gt;
{{Hinweis| ''genType'' kann vom Type float, vec2, vec3 oder vec4 sein, ''mat'' vom Typ mat2, mat3 oder mat4.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie und Winkel==&lt;br /&gt;
Alle übergebenen Winkel sollten, soweit nicht anders vermerkt, in Radien angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* genType radians (genType degrees)&lt;br /&gt;
: Wandelt von Grad nach Radien. &lt;br /&gt;
* genType degrees (genType radians)&lt;br /&gt;
: Wandelt von Radien nach Grad.&lt;br /&gt;
* genType sin (genType x)&lt;br /&gt;
: Gibt den Sinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType x)&lt;br /&gt;
: Gibt den Kosinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType x)&lt;br /&gt;
: Gibt den Tangens von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType asin (genType x)&lt;br /&gt;
: Liefert den Arcsinus von x zurück, also den Winkel dessen Sinus x ergeben würde.&lt;br /&gt;
* genType acos (genType x)&lt;br /&gt;
: Liefert den Arckosinus von x zurück, also den Winkel dessen Cosinus x ergeben würde.&lt;br /&gt;
* genType atan (genType y, genType x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x/y ergeben würde.&lt;br /&gt;
* genType atan (genType y_over_x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x über y ergeben würde.&lt;br /&gt;
&lt;br /&gt;
==Hyperbolisch==&lt;br /&gt;
* genType sinh (genType x)&lt;br /&gt;
: Gibt den Sinus Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) * 0.5; )&lt;br /&gt;
* genType cosh (genType x)&lt;br /&gt;
: Gibt den Kosinus Hyperbolicus von x zurück. (return = (exp(x) + exp(-x)) * 0.5; )&lt;br /&gt;
* genType tanh (genType x)&lt;br /&gt;
: Gibt den Tangens Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) / (exp(x) + exp(-x)); )&lt;br /&gt;
* genType asinh (genType angle)&lt;br /&gt;
: Gibt den Areasinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x + 1.0)); )&lt;br /&gt;
* genType acosh (genType angle)&lt;br /&gt;
: Gibt den Areakosinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x - 1.0)); )&lt;br /&gt;
* genType atanh (genType x)&lt;br /&gt;
: Gibt den Areatangens Hyperbolicus von x zurück. (return = log((1.0 + x) / (1.0 - x)) * 0.5; )&lt;br /&gt;
&lt;br /&gt;
==Exponentiell==&lt;br /&gt;
* genType pow (genType x, genType y)&lt;br /&gt;
: Gibt x hoch y zurück.&lt;br /&gt;
* genType exp (genType x)&lt;br /&gt;
: Gibt e(Eulerischezahl ≈ 2.7182) hoch x zurück.&lt;br /&gt;
* genType log (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis e(Eulerischezahl ≈ 2.7182) von x zurück.&lt;br /&gt;
* genType exp2 (genType x)&lt;br /&gt;
: Gibt 2 hoch x zurück.&lt;br /&gt;
* genType log2 (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis 2 von x zurück.&lt;br /&gt;
* genType sqrt (genType x)&lt;br /&gt;
: Gibt die Wurzel von x zurück.&lt;br /&gt;
* genType inversesqrt (genType x)&lt;br /&gt;
: Gibt die umgekehrte Wurzel von x zurück.&lt;br /&gt;
&lt;br /&gt;
==Standardfunktionen==&lt;br /&gt;
* genType abs (genType x)&lt;br /&gt;
: Liefert den absoluten Wert von x zurück.&lt;br /&gt;
* genType sign (genType x)&lt;br /&gt;
: Gibt -1.0 zurück, wenn x &amp;lt; 0.0, 0.0 wenn x = 0.0 und 1.0 wenn x &amp;gt; 0.0.&lt;br /&gt;
* genType roundeven(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integervalue und gibt diesen zuück. Bei &amp;quot;.5&amp;quot; Werten wird zur nächsten geraden Zahl gerundet.&lt;br /&gt;
* genType round(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integervalue und gibt diesen zuück. &amp;quot;.5&amp;quot; Werten werden je nach Implementation anders behandelt.&lt;br /&gt;
* genType trunc(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integervalue dessen Absoluterwert nicht größer ist als der Absolutewert von x&lt;br /&gt;
* genType floor (genType x)&lt;br /&gt;
: Gibt denn nächsten Integerwert zurück, der kleiner oder gleich x ist.&lt;br /&gt;
* genType ceil (genType x)&lt;br /&gt;
: Gibt den nächsten Integerwert zurück, der größer oder gleich x ist.&lt;br /&gt;
* genType fract (genType x)&lt;br /&gt;
: Gibt den Nachkommateil von x zurück.&lt;br /&gt;
* genType mod (genType x, float y) &lt;br /&gt;
* genType mod (genType x, genType y)&lt;br /&gt;
: Gibt den Modulus zurück. (=x-y * floor(x/y)) &lt;br /&gt;
* genType min (genType x, genType y) &lt;br /&gt;
* genType min (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn y &amp;lt; x, ansonsten x. &lt;br /&gt;
* genType max (genType x, genType y) &lt;br /&gt;
* genType max (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn x &amp;lt; y, ansonsten x. &lt;br /&gt;
* genType clamp (genType x, genType minVal, genType maxVal) &lt;br /&gt;
* genType clamp (genType x, float minVal, float maxVal)&lt;br /&gt;
: Zwängt x in den Bereich minVal..maxVal.  (return = min(minVal, max(maxVal, x)))&lt;br /&gt;
* genType mix (genType x, genType y, genType a)&lt;br /&gt;
* genType mix (genType x, genType y, float a)&lt;br /&gt;
: Liefert den linearen Blend zwischen x und y zurück. (= x * (1-a) + y * a) &lt;br /&gt;
* genType step (genType edge, genType x)&lt;br /&gt;
* genType step (float edge, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt; edge, ansonsten 1.0. &lt;br /&gt;
* genType smoothstep (genType edge0, genType edge1, genType x)&lt;br /&gt;
* genType smoothstep (float edge0, float edge1, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge0 und 1.0 wenn x &amp;gt;= edge1. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt.&lt;br /&gt;
&lt;br /&gt;
==Geometrie==&lt;br /&gt;
* float length (genType x)&lt;br /&gt;
: Gibt die Länge des Vektors x (= sqrt(x[0]² + x[1]² + ... + x[n]²) zurück. &lt;br /&gt;
* float distance (genType p0, genType p1)&lt;br /&gt;
: Gibt die Distanz zwischen den zwei Vektoren p0 un p1 (= length(p0-p1)) zurück. &lt;br /&gt;
* float dot (genType x, genType y)&lt;br /&gt;
: Gibt das Punktprodukt von x und y zurück (=x[0]*y[0] + x[1]*y[1] + ... + x[n]*y[n]). &lt;br /&gt;
* vec3 cross (vec3 x, vec3 y)&lt;br /&gt;
: Gibt das Kreuzprodukt von x und y zurück. &lt;br /&gt;
* genType normalize (genType x)&lt;br /&gt;
: Normalisiert den Vektor x auf die Länge 1. &lt;br /&gt;
* vec4 ftransform()&lt;br /&gt;
: Nur im Vertex Shader. Die Funktion stellt sicher, das das eingehende Vertex haargenau so transformiert wird wie in der festen Funktionspipeline. gl_Position = ftransform() wird dann also gebraucht, wenn in mehreren Durchgängen sowohl im Shader als auch in der festen Pipeline gerendert wird, um sicherzustellen das in beiden Fällen die gleiche Vertexposition herauskommt. &lt;br /&gt;
* genType faceforward (genType N, genType I, genType Nref)&lt;br /&gt;
: Gibt einen nach vorne zeigenden Vektor N zurück. (If dot(NRef, I) &amp;lt; 0 return N else return -N) &lt;br /&gt;
* genType reflect (genType l, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (result = l - 2.0 * dot(N,I) * N; )&lt;br /&gt;
* genType refract (genType l, genType N, float eta)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N mit dem Brechungsindex eta gebrochenen Vektor l zurück. &lt;br /&gt;
::gentype k = 1.0 - eta * eta * (1.0 - dot(N, l) * dot(N, l))&lt;br /&gt;
::if (k &amp;lt; 0.0)&lt;br /&gt;
:::result = 0.0&lt;br /&gt;
::else &lt;br /&gt;
:::result = eta * l - (eta * dot(N, l) * sqrt(k)) * N&lt;br /&gt;
&lt;br /&gt;
==Matrixfunktionen==&lt;br /&gt;
* mat matrixCompMult (mat x, mat y)&lt;br /&gt;
: Multipliziert Matrix X mit Matrix Y komponentenweise. Um eine normale lineare Matrixmultiplikation durchzuführen, sollte der &amp;quot;*&amp;quot;-Operator genutzt werden.&lt;br /&gt;
* mat transpose (mat m)&lt;br /&gt;
: Gibt die transponierte Matrix von m zurück.&lt;br /&gt;
* mat invert (mat m)&lt;br /&gt;
: Gibt die invertierte Matrix von m zurück. Also die Matrix, die mit m multipliziert die Normalmatrix ergeben würde.&lt;br /&gt;
* mat outerProduct(vec c, vec r)&lt;br /&gt;
: Gibt eine eine Matrix als Ergebnis der linearen (return[m, n] = c[m] * r[n])-Operation zurück.&lt;br /&gt;
&lt;br /&gt;
==Vektorvergleiche==&lt;br /&gt;
Die meisten Vektorvergleichsfunktionen liefern als Ergebnis einen boolvektor zurück, da die Vergleiche per Komponente stattfinden. Wenn man also x = vec4(1.0, 3.0, 0.0, 0.0) mit y = vec4(2.0, 1.5, 1.5, 0.0) via lessThan(x, y) vergleicht, erhält man als Ergebnis bvec(true, false, true, false).&lt;br /&gt;
&lt;br /&gt;
* bvec lessThan (vec x, vec y)&lt;br /&gt;
* bvec lessThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt; y zurück. &lt;br /&gt;
* bvec lessThanEqual (vec x, vec y)&lt;br /&gt;
* bvec lessThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt;= y zurück. &lt;br /&gt;
* bvec greaterThan (vec x, vec y)&lt;br /&gt;
* bvec greaterThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt; y zurück. &lt;br /&gt;
* bvec greaterThanEqual (vec x, vec y)&lt;br /&gt;
* bvec greaterThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt;= y zurück. &lt;br /&gt;
* bvec equal (vec x, vec y)&lt;br /&gt;
* bvec equal (ivec x, ivec y)&lt;br /&gt;
* bvec equal (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x == y zurück. &lt;br /&gt;
* bvec notEqual (vec x, vec y)&lt;br /&gt;
* bvec notEqual (ivec x, ivec y)&lt;br /&gt;
* bvec notEqual (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x != y zurück. &lt;br /&gt;
* bool any (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn mindestens eine der Komponenten von x true ist.&lt;br /&gt;
* bool all (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn alle Komponenten von x true sind. &lt;br /&gt;
* bvec not (bvec x)&lt;br /&gt;
: Liefert die logische Negation von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Texturenzugriffe==&lt;br /&gt;
&lt;br /&gt;
Diese wichtige Funktionskategorie dient dazu, Werte aus einer an eine Textureinheit gebundenen Textur zu ermitteln. Die Texturenzugriffe können sowohl im Vertex (!) als auch im Fragment Shader ausgeführt werden, wobei der optionale Parameter bias im Vertex Shader ignoriert wird. Allerdings gibt es zusätzlich Funktionen die auf &amp;quot;Lod&amp;quot; enden und nur im Vertex Shader genutzt werden dürfen um eben dieses Manko zu umgehen. Funktionen mit dem Suffix &amp;quot;Proj&amp;quot; geben einen projizierten Texturenwert zurück.&lt;br /&gt;
&lt;br /&gt;
: '''1D-Texturen :'''&lt;br /&gt;
* vec4 texture1D (sampler1D sampler, float coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 texture1DLod (sampler1D sampler, float coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''2D-Texturen :'''&lt;br /&gt;
* vec4 texture2D (sampler2D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''3D-Texturen :'''&lt;br /&gt;
* vec4 texture3D (sampler3D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture3DProj (sampler3D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture3DProjLod (sampler3D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Cubemap :'''&lt;br /&gt;
* vec4 textureCube (samplerCube sampler, vec3 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
*vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Tiefentextur (Shadowmap) :'''&lt;br /&gt;
* vec4 shadow1D (sampler1DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow2D (sampler2DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
* vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow1DProjLod (sampler1DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
* vec4 shadow2DProjLod (sampler2DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Texturegröße :'''&lt;br /&gt;
Mit den textureSize-Befehlen kann die Größe einer Textur bestimmt werden, wobei lod das Mipmaplevel angibt:&lt;br /&gt;
*int textureSize(sampler1D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2D sampler, int lod)&lt;br /&gt;
*ivec3 textureSize(sampler3D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(samplerCube sampler, int lod)&lt;br /&gt;
*int textureSize(sampler1DShadow sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2DShadow sampler, int lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie bereits eingangs gesagt ist dieses Kapitel ein sehr wichtiges, denn eine 3D-Szene ohne Texturen ist heute kaum denkbar. Darüber hinaus lassen sich durch Texturenzugriffe recht viele interessante Sachen machen, z.B. ein einfacher Blurfilter oder das freie überblenden bestimmter Texturenteile. Deshalb führe ich hier kurz ein paar Beispiele an, welche die Nutzung dieser Funktionen verdeutlichen sollen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Eine Textur gebunden die einfach ausgegeben werden soll&lt;br /&gt;
&lt;br /&gt;
''Im Vertex Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
Der Vertex Shader ist recht minimal. Neben der homogenen Vertexposition leiten wir hier nur die im OpenGL-Programm angegebenen Texturkoordinaten weiter. ''Dies ist aber unbedingt nötig!'' Ohne die letzte Zeile hätten wir im Fragment Shader keine gültigen Texturkoordinaten auf TMU0, was in einer Fehldarstellung enden würde.&lt;br /&gt;
&lt;br /&gt;
''im Fragment Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSampler;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(texSampler, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zuerst deklarieren wir hier einen 2D-Texturensampler, wichtig : '''Texturensampler müssen IMMER als uniform deklariert werden!''' In der Hauptfunktion weisen wir dann einfach den über die Funktion texture2D aus unserer gebundenen Textur ausgelesenen Farbwert, anhand der vom Vertex Shader übergebenen Texturkoordinaten, zu.&lt;br /&gt;
{{Vorlage:Hinweis|Der Uniform-Integer für den Sampler referenziert '''nicht''' den Namen (die ID) des Texturobjektes, sondern die Nummer der Texturunit.}}&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Zwei Texturen, jeweils auf TMU0 und TMU1. Fragmentfarbe soll eine Multiplikation der beiden Texturen darstellen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielfall (der recht häufig vorkommt) müssen wir im Programm festlegen, ''welcher Sampler welche Textureinheit adressiert'', genau deshalb müssen die Texturensampler auch als uniform deklariert werden. Die Standardtextureneinheit eines Samplers ist TMU0, was in unserem Falle natürlich nicht brauchbar ist. Also müssen wir unserem zweiten Textursampler im Programm mitteilen das er seine Daten aus TMU1 beziehen soll :&lt;br /&gt;
&lt;br /&gt;
 glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&lt;br /&gt;
Dies ist also unbedingt zu machen, sobald ein Texturensampler eine Textureinheit &amp;gt; GL_TEXTURE_0 adressieren will. Die Textureneinheit des Samplers lässt sich also nicht im Shader selbst festlegen. Der Fragment Shader ist nun allerdings schnell hergeleitet (Vertex Shader verändert sich nicht, da TMU1 die Texturkoordinaten auch von TMU0 bezieht) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
im Fragment Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSamplerTMU0;&lt;br /&gt;
uniform sampler2D texSamplerTMU1;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_FragColor = texture2D(texSamplerTMU0, vec2(gl_TexCoord[0])) *&lt;br /&gt;
                   texture2D(texSamplerTMU1, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich [[GLSL noise|Noisefunktionen]] nutzen, mit deren Hilfe sich eine gewisse &amp;quot;Zufälligkeit&amp;quot; simulieren lässt (wirklich zufällige Werte sind es natürlich nicht). Ein zurückgegebener Wert liegt dabei immer im Bereich [-1..1] und ist immer bei gleichem Eigabewert auch immer gleich. Die Verwendung empfiehlt sich derzeit allerdings eher nicht, da nur die 3DLabs Treiber die Funktionen unterstützen und eine Noisetextur wahrscheinlich performanter ist.&lt;br /&gt;
&lt;br /&gt;
* float noise1 (genType x)&lt;br /&gt;
* vec2 noise2 (genType x)&lt;br /&gt;
* vec3 noise3 (genType x)&lt;br /&gt;
* vec4 noise4 (genType x)&lt;br /&gt;
&lt;br /&gt;
==Discard==&lt;br /&gt;
Eigentlich keine Funktion, sondern eine Abbruchbedingung '''nur im Fragment Shader'''. Das Schlüsselwort {{INLINE_CODE|discard}} verwirft das aktuell bearbeitete Fragment und beendet gleichzeitig den Shader. Es kann z.B. genutzt werden um Alphamasking manuell durchzuführen.&lt;br /&gt;
Man sollte dabei jedoch beachten dass ein Großteil der aktuellen Hardware kein &amp;quot;early-out&amp;quot; (frühes Beenden) im Fragmentshader unterstützt. Wenn dort also ein {{INLINE_CODE|discard}} auftaucht, wird trotzdem auch der Code danach ausgeführt und einfach verworfen. Einen Geschwindigkeitsvorteil durch diesen Befehl wird man also erst auf neueren Karten feststellen, die dieses Faeature auch so unterstützen wie es angedacht war. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispielshader=&lt;br /&gt;
Wen bis hierhin nicht der Mut verlassen hat, und wer aufmerksam gelesen hat, dürfte jetzt also zumindest in der Lage sein kleinere Shader in glSlang zu schreiben und diese auch im Programm zu nutzen. Ich habe im Themenbereich &amp;quot;glSlang&amp;quot; versucht alle Bereiche der Shadersprache selbst anzusprechen und hoffe das auch brauchbar rübergebracht zu haben. Um oben erlerntes (hoffe ich doch mal) nochmal zu vertiefen werde ich jetzt (wie ich das bereits bei meinem ARB_VP-Tutorial getan habe) einen simplen Beispielshader (Vertex und Fragment Shader) auseinanderpflücken um so u.a. auch die Programmstruktur für alle die in C nicht so bewandert sind zu erörtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Vertex Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_FrontColor   = gl_Color * GlobalColor;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie gesagt recht simpel. Angefangen wird mit der Deklaration einer globalen Uniformvariable namens {{INLINE_CODE|GlobalColor}}. Wie wir uns erinnern gibt der Typenqualifizierer uniform an, das wir den Wert dieser Variable (ein 4-Komponentenvektor, da Farbwerte aus R,G,B und A bestehen) in unserem Programm an den Shader übermitteln.&lt;br /&gt;
&lt;br /&gt;
Danach gehts ohne Umwege direkt in unsere Hauptfunktion, da wir im Vertex Shader keine anderen Funktionen benötigen. Dort berechnen wir zuerst die homogene Position unseres Vertex, die sich aus der eingehenden Vertexposition multipliziert mit der Modelansichtsmatrix ergibt. Wie schonmal gesagt '''muss diesem Wert etwas zugewiesen werden''', da sonst alle darauf aufbauenden Funktionen unvorhersehbare Ergebnisse liefern.&lt;br /&gt;
Außerdem wollen wir die Frontfarbe unseres Vertex jedesmal mit der im Programm übergebenen GlobalColor multiplizieren, so dass wir den Farbwert der gesamten Szene aus unserem Programm heraus manipulieren können. Zu guterletzt geben wir dann noch unsere aus der festen Funktionspipeline erhaltenen Texturkoordinaten auf Textureinheit 0 weiter. Wenn im Fragmentshader Texturkoordinaten verwendet werden, '''muss das getan werden'''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Fragment Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
uniform sampler2D Texture2;&lt;br /&gt;
uniform sampler2D Texture3;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec2 TexCoord = vec2( gl_TexCoord[0] );&lt;br /&gt;
 vec4 RGB      = texture2D( Texture0, TexCoord );&lt;br /&gt;
&lt;br /&gt;
 gl_FragColor  = texture2D(Texture1, TexCoord) * RGB.r +&lt;br /&gt;
                 texture2D(Texture2, TexCoord) * RGB.g +&lt;br /&gt;
                 texture2D(Texture3, TexCoord) * RGB.b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier passiert nicht wirklich viel Großartiges. Wir deklarieren beim Shaderanfang zuerst vier Texturensampler, da wir insgesamt vier verschiedene Texturen im Shader auslesen wollen, eine Verlaufstextur und drei Oberflächentexturen. Auch hier sei wieder gesagt das man Sampler '''immer als uniform deklarieren muss'''. In der Hauptfunktion deklarieren wir dann einen Farbvektor, der auch direkt einen Farbwert aus Textureinheit 0 zugewiesen bekommt. Auf Textureinheit 0 haben wir ihm Hauptprogramm eine Verlaufstextur gebunden, die angibt wie die drei folgenden Texturen ineinander geblendet werden.&lt;br /&gt;
Danach schreiben wir dann den Farbwert des Fragmentes, der '''im Fragment Shader ausgegeben werden muss'''. Der besteht wie einfach zu erkennen aus Farbwert von Textureinheit 1 * Rotwert von Textureinheit 0 + Farbwert von Textureinheit 2 * Grünwert von Textureinheit 0 + Farbwert von Textureinheit 3 * Blauwert von Textureinheit 0. So ist z.B. an Stellen an denen in der Verlaufstextur reines blau liegt nur die dritte Textur sichtbar.&lt;br /&gt;
&lt;br /&gt;
So viel also zu unserem kleinen Beispielshader. Er ist weder besonders toll noch besonders sinnvoll, sollte aber auch eher dazu dienen euch glSlang ein wenig zu veranschaulichen, was mir hoffentlich gelungen ist.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr in den vorangegangenen Kapiteln zumindest ein wenig aufgepasst habt, dann könnt ihr euch vor eurem inneren Auge hoffentlich vortstellen was der Shader macht : Er blendet drei Texturen weich anhand der Verlaufstextur ineinander über. Sowas kann man z.B. für ein Terrain nutzen, um dieses anhand einer Farbtextur zu texturieren. Für alle, die damit Probleme haben hier zwei Bilder die den Shader veranschaulichen. Links die Verlaufstextur, die angibt wo welche Textur wie stark gewichtet wird und rechts dann das Ergebnis :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; [[BILD:GLSL_sample_shader_a.jpg]] [[BILD:GLSL_sample_shader_b.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post Mortem=&lt;br /&gt;
Das wars also, meine &amp;quot;Einführung&amp;quot; in die OpenGL Shader Sprache. Ich hoffe es hat euch nicht gelangweilt und auch die von mir zur Verfügung gestellten Informationen haben euch hoffentlich ausgereicht. Mit der Veröffentlichung dieser Einführung geht übrigens auch die Eröffnung eines Shaderforums hier auf der DGL einher, in der ihr dann also fleissig Fragen zum Thema stellen oder eure Shader präsentieren könnt. In diesem Post Mortem gehe ich jetzt noch kurz auf die Zukunft von glSlang ein und zeige ein paar Screenshots (damit die Augen entspannen können), bevor ihr euch dann selbst in die Shaderwelt stürzen könnt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
Anbei ein paar exemplarische Screenshots. Da man mit GLSL aber alle möglichen Effekte berechnen kann (u.a. auch 1:1 die feste Funktionspipeline) ist es hier unmöglich einen Überblick aller möglichen Techniken zu geben.&lt;br /&gt;
&lt;br /&gt;
[[Datei:tut_glsl_eigenershader_01.png]] [[Datei:tut_glsl_eigenershader_02.png]] [[Datei:tut_glsl_eigenershader_03.png]]&lt;br /&gt;
&lt;br /&gt;
Wie im ersten (und dritten) Screenshot zu sehen ist es natürlich auch möglich mehrere Techniken innerhalb einer Szene zu nutzen. Hier sind letztendlich bis auf Hardwarelimitationen keine Grenzen gesetzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Als dieses Tutorial geschrieben wurde, war noch nicht ganz abzusehen dass bzw. ob sich GLSL auch durchsetzen würde. ARB-Shadr und NVidias cG waren damals die Platzhirsche, aber inzwischen werden ARB-Shader nicht mehr genutzt (und auch schon länger nicht mehr weiterentwickelt) und auch NVidia setzt primär auf GLSL. GLSL wird permanent weiterenwtickelt und Hersteller können dank des flexiblen Extensionsystems auch in GLSL eigene Extensions offenlegen um die aktuellsten Features (wie z.b. den Tesselator auf aktuellen ATI-Karten) nutzen zu können. GLSL gilt inzwischen auch offizielle die Shadersprache für OpenGL und wird permanent an die neusten technischen Entwicklungen im Grafikkartenbereich angepasst.&lt;br /&gt;
&lt;br /&gt;
Wer also unter OpenGL etwas mit Shadern machen möchte, kommt an GLSL nicht vorbei!&lt;br /&gt;
&lt;br /&gt;
Also viel Spaß beim Experimentieren und Shaderschreiben! Und nicht vergessen : Wir wollen sehen was ihr so treibt,&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_glsl2]]}}&lt;br /&gt;
[[Kategorie:Tutorial|GLSL]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Bomberman1&amp;diff=25659</id>
		<title>Tutorial Bomberman1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Bomberman1&amp;diff=25659"/>
				<updated>2012-03-21T14:59:18Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausser -&amp;gt; Außer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Bomberman.gif|left]]&lt;br /&gt;
=Wir programmieren einen Bombermanklon! &amp;lt;br&amp;gt; &amp;lt;br&amp;gt; Teil 1 : Die Codebasis und der Editor=&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Ave, und willkommen zu meinem zweiten Tutorial, dem Anfang einer Tutorialserie!&lt;br /&gt;
&lt;br /&gt;
Neben Tetris gehört ''Bomberman'' wohl zu einem der erfolgreichsten Spielkonzepte der Videospielgeschichte, wurde es doch auf fast jede Plattform und dazu noch in diversen Varianten (es existieren über 30 Bombermanspiele) umgesetzt. Der Erfolg dieses Spielkonzepts liegt (wie auch bei Tetris) in seinem recht einfachen, aber dennoch fesselndem Spielprinzip in dem es darum geht die Mitspieler durch geschicktes Platzieren von Bomben aus den Rennen zu werfen und als letzter auf dem Spielfeld zu stehen. (Mehr Infos zum Thema Bomberman gibts u.a. hier : [http://www.bomberman.info http://www.bomberman.info])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
[[Bild:Bomberman nes 1985.jpg|NES (1985)]][[Bild:Bomberman snes 1993.jpg|MegaDrive (1993)]][[Bild:Bomberman neogeo 1997.jpg|NeoGeo (1997)]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und gerade wegen der Einfachheit dieses Spielprinzips ist ein Bombermanklon gradezu prädestiniert um als Grundlage für eine kleine Tutorialserie zum Thema Spieleprogrammierung zu dienen. Während Anfängern ein recht einfacher Einstieg in die Spieleprogrammierung geboten wird, bietet es fortgeschritteneren Programmierern sehr viel Freiraum zur Weiterentwicklung.&lt;br /&gt;
In dieser mehrteiligen Serie werde ich von Anfang an und auf auch für Einsteiger (für die die Tutorials auch gedacht sind) geeignete Art und Weise zeigen wie man einen Bombermanklon und den dazugehörenden Editor von Grund auf programmiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In diesem ersten Teil der Serie werden wir die vom Editor und dem Spiel verwendete Codebasis erstellen und widmen uns dann später im dem Editor und seinen Eigenheiten.&lt;br /&gt;
&lt;br /&gt;
Am Ende wird der geneigte Leser einen vollständen Karteneditor zum Erstellen einfacher Bombermankarten fertiggestellt haben, mit dessen Hilfe wir dann die Karten für den im zweiten Tutorial entwickelten Bombermanklons erstellen können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Realisiert wird das Ganze natürlich in Delphi und OpenGL. Später wird dann noch FMOD als Soundlibrary zu den beiden stoßen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
Was ich in diesem Tutorial allerdings nicht erklären werde, und was natürlich benötigt wird, sind zum einen '''Kenntnisse in Object Pascal''' (dazu gibts nicht nur sehr viele gute Tuts, sondern v.a. auch die Anleitung zu Delphi bzw. dessen Hilfedatei), und '''grundlegende OpenGL-Kenntnisse''' zu Themen wie Rotation und Bewegung, Zeichnen von geometrischen Objekten und Texturemapping. Zu diesen Themen gibts hier auf DGL ja jede Menge guter Tutorials.&lt;br /&gt;
Wer mit diesen Voraussetzungen ausgestattet ist, der sollte in dieser Tutorialserie auf keine Problem stoßen und kann sich schonmal auf einen brauchbaren Bombermanklon freuen, den er im Anschluß dann fleißig verbessern und erweitern kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Das Ziel==&lt;br /&gt;
&lt;br /&gt;
Am Ende dieser Tutorialserie wird ein ausgewachsener 3D-Bombermanklon mit diversen Spezieleffekten wie Alphamasking, Partikelsystemen, fulminanten Explosionen und Soundausgabe stehen, der sich vor seinen Vorbildern nicht zu verstecken braucht.&lt;br /&gt;
Und praktisch nebenbei (oder vornedran ;-)) wird dann noch ein leistungsstarker Editor mit einem einfach zu nutzenden Dateiformat entwickelt, mit dessen Hilfe in Windeseile neue Karten erstellt werden können.&lt;br /&gt;
Ziel dieser Tutorialserie ist nicht unbedingt der perfekte Bombermanklon, sondern es geht mir eher darum den Einsteigern unter den Leser neben einem guten Programmierstil auch noch wichtige Grundlagen für die Entwicklung eines Spiels mitzugeben. Denn was bei einem kleinen Projekt schon nützlich ist, kann sich bei einem großen Projekt schnell als große Hilfe erweisen.&lt;br /&gt;
&lt;br /&gt;
Eventuell (hängt zum großen Teil auch vom Feedback der Leser ab) werde ich sogar noch ein Tutorial hinterherschieben, das unseren Klon noch im Mehrspielerfähigkeiten mittels LAN erweitert.&lt;br /&gt;
&lt;br /&gt;
Viel Spaß also beim Bombenlegen...[[Bild:Bomberman anim.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Die Codebasis==&lt;br /&gt;
&lt;br /&gt;
Wie die Überschrift es schon erahnen lässt, widmen wir uns zu allererst der Codebasis. Die Codebasis nennt sich deshalb so, weil sie grundlegende Funktionen und Klassen zur Verfügung stellt die sowohl vom Editor als später auch vom Spiel genutzt werden. Bezeichnen kann man das natürlich auch als Engine, doch dieser Begriff ist in meinen Augen falsch, da ich unter Engine ein viel komplexeres Grundgerüst verstehe, als dies bei einem Bombermanklon benötigt wird.&lt;br /&gt;
&lt;br /&gt;
Diese Codebasis besteht zu Beginn nur aus einigen wenigen Dingen, wird aber im Verlaufe der Tutorialserie ständig erweitert und ist Dreh- und Angelpunkt unseres Bombermanklons.&lt;br /&gt;
In diesem Tut stellt unsere Codebasis (die sich in der Datei '''global.pas''' befindet) folgende Objekte zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
===Einen Texturenmanager (TTextureManager)===&lt;br /&gt;
Viele von euch werden ihre Texturen bisher wohl auf einfache Art und Weise über ein (meist dynamisches) {{INLINE_CODE|array of glUInt}} &amp;quot;verwaltet&amp;quot; haben, und haben dann beim Programmstart alle Texturen per Hand in dieses array eingelesen haben. Nicht nur das dass Laden der Texturen auf diese Art und Weise recht umständlich war und bei jeder neuen Textur der Quellcode geändert werden musste, nein auch der Zugriff auf die Texturen beim Zeichnen der Szene war umständlich und geschah auf die Weise {{INLINE_CODE|[[glBindTexture]](GL_TEXTURE_2D, Textur[3])}}. Dadurch war man immer gezwungen, sich zu vergewissern dass Textur Nr.3 auch die richtige Textur war.&lt;br /&gt;
&lt;br /&gt;
Bei unserem Bombermanklon wollen wir diesen Fehler nicht machen, und haben auch nicht vor bei jeder neuen Textur den Quellcode ändern zu müssen. Das ist nicht nur für den Programmierer selbst komfortabler, sondern auch für die Spieler, die die Karten mit eigenen Texturen verschönern wollen.&lt;br /&gt;
&lt;br /&gt;
Deshalb schreiben wir uns einen kleinen aber sehr nützlichen Texturenmanager, mit dessen Hilfe wir alle Texturen in einem Verzeichnis zur Laufzeit in den Texturenpool laden können, und der Texturen nicht anhand ihrer Position im array bindet, sondern auf diese mit einer Stringlist über deren Namen zugreift. So wird z.b. aus dem {{INLINE_CODE|glBindTexture(GL_TEXTURE_2D, Textur[3])}} ein einfaches und leichter durchschaubares {{INLINE_CODE|TextureManager.BindTexture('steinwand1.tga')}}.&lt;br /&gt;
&lt;br /&gt;
Um uns nicht mit dem Laden verschiedener Formate herumschlagen zu müssen, benutzen wir zum Umwandeln der Texturen die '''glBMP-Bibliothek''' von [http://delphigl.cfxweb.net http://delphigl.cfxweb.net] in einer von mir um einige nützliche Dinge erweiterten Variante (ist im Download zu diesem Tutorial natürlich enthalten).&lt;br /&gt;
&lt;br /&gt;
Unser Texturmanager besteht aus folgenden Prozeduren und Variablen:&lt;br /&gt;
&lt;br /&gt;
*Texture : array of TglBMP&lt;br /&gt;
:In diesem dynamischen array werden alle geladenen Texturen abgelegt.&lt;br /&gt;
&lt;br /&gt;
*TextureName : THashedStringList&lt;br /&gt;
:In dieser StringList werden die Texturennamen abgelegt, über die der Texturenmanager später die Texturen im {{INLINE_CODE|Texturearray}} addressiert. Hier wird statt einer herkömmlichen {{INLINE_CODE|TStringList}} eine {{INLINE_CODE|THashedStringList}} verwendet, da diese bei häufigen Suchvorgängen (was bei vielen Texturenwechseln der Fall ist) und besonders bei großen Datenmengen schneller als die herkömmliche {{INLINE_CODE|TStringList}} ist.&lt;br /&gt;
:'''Hinweis für Nutzer von Delphiversionen &amp;lt; 6:'''&lt;br /&gt;
:In diesen Delphiversionen existiert der Typ {{INLINE_CODE|THashedStringList}} nicht. Dadruch seid ihr gezwungen doch eine normale {{INLINE_CODE|TStringList}} zu verwenden. &lt;br /&gt;
&lt;br /&gt;
*constructor Create&lt;br /&gt;
:Erstellt und initialisiert den Texturenmanager.&lt;br /&gt;
&lt;br /&gt;
*destructor Destroy&lt;br /&gt;
:Deinitialisiert und entfernt den Texturenmanager aus dem Speicher.&lt;br /&gt;
&lt;br /&gt;
*procedure AddTexturesInDir(pDirName, pFileMask : String)&lt;br /&gt;
:Fügt dem Texturenpool alle im Verzeichnis {{INLINE_CODE|pDirName}} liegenden Texturen mit der in {{INLINE_CODE|pFileMask}} angegebenen Endung hinzu.&lt;br /&gt;
&lt;br /&gt;
*procedure AddTexture(pFileName, pTextureName : String)&lt;br /&gt;
:Fügt dem Texturenpool die aus der Datei {{INLINE_CODE|pFileName}} geladene Textur unter dem Namen {{INLINE_CODE|pTextureName}} hinzu.&lt;br /&gt;
&lt;br /&gt;
*procedure BindTexture(pTextureName : String)&lt;br /&gt;
:Sucht die Textur mit dem Namen {{INLINE_CODE|pTextureName}} im Texturenpool und bindet diese an das {{INLINE_CODE|GL_TEXTURE_2D}}-Ziel. Wurde die Textur nicht gefunden, wird für das Texturemapping deaktiviert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie man also sehen kann steckt hinter einem Texturenmanager nicht sonderlich viel Arbeit, er erleichtert einem das Leben allerdings erheblich. Besonders wenn man später Dinge wie Alphamasking einbringen will, muss man nicht mehr umständlich im Zeichencode rumwühlen, sondern man muss einfach nur noch die {{INLINE_CODE|BindTexture}}-Routine ein wenig abändern. Alles in allem also ein nützliches Hilfsmittel das in keinem OpenGL-Projekt fehlen sollte.&lt;br /&gt;
&lt;br /&gt;
===Das Spielfeld (TMap)===&lt;br /&gt;
Der nächste Baustein unserer Codebasis repräsentiert das Spielfeld auf dem die Aktion stattfindet. Viel zu bieten hat diese Klasse momentan, außer einer Zeichenprozedur und einige Editorprozeduren noch nicht viel, was sich aber in naher Zukunft noch ändern wird.&lt;br /&gt;
&lt;br /&gt;
Hier also Prozeduren und Variablen des Spielfelds :&lt;br /&gt;
&lt;br /&gt;
*PlayGround : array of array of TFieldType&lt;br /&gt;
:Diese Variable repräsentiert das eigentliche Spielfeld und ist ein zweidimensionales array vom Typ {{INLINE_CODE|TFieldType}}, dessen Definition die Eigenschaften eines Spielfelds festlegt und so aussieht :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;TFieldType = record&lt;br /&gt;
  Texture  : String;&lt;br /&gt;
  FType    : Byte;&lt;br /&gt;
  FSpecial : Byte;&lt;br /&gt;
 end;&amp;lt;/source&amp;gt;&lt;br /&gt;
:{{INLINE_CODE|Textur}} steht für den Namen der diesem Feld zugewiesenen Textur, während {{INLINE_CODE|FType}} angibt ob es sich um ein Bodenteil, einen festen Block oder einen zerstörbaren Block handelt. Natürlich ist diese Variable frei erweiterbar (was später auch noch ausgiebig getan wird), und man könnte hier quasi unendlich viele Feldtypen mit den tollsten Eigenschaften (z.B. bewegliche Blöcke) definieren. {{INLINE_CODE|FSpecial}} gibt letztendlich noch an, ob dieses Feld noch eine besondere Eigenschaft, wie z.B. einen Spielerstart enthält.&lt;br /&gt;
&lt;br /&gt;
*DefaultFieldTexture : String&lt;br /&gt;
:In dieser Variable wird die Standardtextur festgelegt, die einem Feld zugewiesen wird, nachdem ein darauf befindlicher sprengbarer Block zerstört wurde.&lt;br /&gt;
&lt;br /&gt;
*procedure SetSize(pSize : Integer)&lt;br /&gt;
:Legt die in {{INLINE_CODE|pSize}} angegebene Spielfeldgröße fest, und tut nichts anderes als das dynamisches {{INLINE_CODE|PlayGround}}-array in seiner Größe mittels {{INLINE_CODE|SetLength}} zu verändern.&lt;br /&gt;
&lt;br /&gt;
*procedure FillBorder(pTexture : String;pFieldType : Integer)&lt;br /&gt;
:Füllt den Rand des Spielfelds mit der in {{INLINE_CODE|pTexture}} angegebenen Textur und dem in {{INLINE_CODE|pFieldType}} angegebenen Feldtyp.&lt;br /&gt;
&lt;br /&gt;
*procedure FillGround(pTexture : String;pFieldType : Integer)&lt;br /&gt;
:Füllt das Spielfeld (exklusive dem Rand) mit der in {{INLINE_CODE|pTexture}} angegebenen Textur und dem in {{INLINE_CODE|pFieldType}} angegebenen Feldtyp&lt;br /&gt;
&lt;br /&gt;
*procedure Draw;&lt;br /&gt;
:Wie der Prozedurenname bereits erahnen lässt, wird in dieser Prozedur das komplette Spielfeld gezeichnet. Diese Prozedur spielt daher also ein Hauptrolle in unserem Bombermanprojekt.&lt;br /&gt;
:Da in der Grundversion unseres Editors nichts weiter getan wird, als die Felder in einer {{INLINE_CODE|for..do}}-Schleife zu zeichnen, bedarf der Quellcode wohl kaum detaillierter Beschreibungen. Eine Zeile dürfte den Anfänger in der Leserschaft jedoch etwas unbekannt vorkommen, weshalb ich diese hier etwas detaillierter erkläre :&lt;br /&gt;
:*glLoadName(OpenGLID)&lt;br /&gt;
::Mit dieser Zeile legen wir einen &amp;quot;Namen&amp;quot; (Eine Variable vom Typ Cardinal, und nicht etwa wie der leicht irreführende Titel Name zu vermuten lässte einen String) auf den {{INLINE_CODE|NameStack}} von OpenGL, der dann dem nächsten gezeichneten geometrischen Objekt zugewiesen wird. Damit wird dann jedem Feld ein einzigartiger OpenGL-Name zugewiesen.&lt;br /&gt;
::Mit Hilfe dieses OpenGL-Namens kann man dann später mit einer {{INLINE_CODE|[[Selection]]}} genannten Methode herausfinden auf welches Feld der Mauszeiger gerade zeigt. Benötigt wird das Ganze natürlich nur für den Editor. Wie genau dieses Selektionsverfahren realisiert wird, dazu gibts später im Editorkapitel mehr.&lt;br /&gt;
&lt;br /&gt;
*procedure SaveToFile(pFileName : String)&lt;br /&gt;
:Diese Prozedur sichert die Karte in die mit {{INLINE_CODE|pFileName}} angegebene Datei. Dabei wird ein einfach zu lesendes und leicht erweiterbares ASCII-Format verwendet :&lt;br /&gt;
          Dateiversion&lt;br /&gt;
          Größe Der Karte&lt;br /&gt;
          Name der Standardtextur&lt;br /&gt;
          Textur von Feld [1,0]&lt;br /&gt;
          FeldTyp von Feld [1,0]&lt;br /&gt;
          SpezialInfo von Feld [1,0]&lt;br /&gt;
          .&lt;br /&gt;
          .&lt;br /&gt;
          .&lt;br /&gt;
          Textur von Feld [Größe Der Karte-1,Größe Der Karte-1]&lt;br /&gt;
          FeldTyp von Feld [Größe Der Karte-1,Größe Der Karte-1]&lt;br /&gt;
          SpezialInfo von Feld [Größe Der Karte-1,Größe Der Karte-1]&lt;br /&gt;
:Ein binäres Format hätte hier natürlich den Vorteil, das zum einen der Platzbedarf geringer wäre, und es zum anderen auch vor Veränderungen sicher wäre, allerdings wären die alten Karten nach jeder Änderung unbrauchbar.Für ein reines ASCII-Format kann man sich jedoch schnell mal einen Importer schreiben, der ältere Karten in eine neuere Version konvertiert.&lt;br /&gt;
&lt;br /&gt;
*procedure LoadFromFile(pFileName : String)&lt;br /&gt;
:Lädt die Karte aus der in {{INLINE_CODE|pFileName}} angegebene Datei. &lt;br /&gt;
&lt;br /&gt;
Soviel also zu unserer aktuellen Codebasis, die als Grundlage für unseren Editor sowie das Spiel an sich dienen wird. Bis jetzt war ja noch nichts spektakuläres dabei, und selbst die unerfahreneren unter euch sollten bis hierhin keine Probleme gehabt haben.&lt;br /&gt;
Der größte Teil unserer zukünftigen Änderungen werden an der Codebasis stattfinden und vor allem das Kartenobjekt betreffen. Natürlich werden später noch neue Klassen u.a. zur Spielerverwaltung (und evtl. Gegnerverwaltung) hinzukommen, dazu aber mehr in den folgenden Tutorials.&lt;br /&gt;
&lt;br /&gt;
Doch wenden wir uns jetzt dem Editor zu... [[Bild:Bomberman happy.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Editor==&lt;br /&gt;
&lt;br /&gt;
Ein Spiel ist ja bekannterweise nur so gut wie sein Inhalt, der mit Hilfe der entwickelten Tools wie einem Leveleditor erstellt wird. Was nützen die tollsten und modernsten Features oder die ausgeglügelste künstliche Intelligenz, wenn die Level in denen man sich bewegt einfach mies sind...deshalb sollte man sich bei der Entwicklung eines Spiels immer auf seine Tools konzentrieren, und diese so intuitiv und gleichzeitig leistungsfähig wie möglich gestalten, damit man später schnell und einfach guten Gamecontent erstellen kann.&lt;br /&gt;
&lt;br /&gt;
Zum Glück ist diese Thematik bei einem Bombermanklon nicht so brisant wie bei einem Egoshooter á la Doom3, dessen Editor sich vor 3DStudio MAX nicht zu verstecken braucht, aber trotzdem geht einem der Levelbau viel leichter von der Hand wenn man einen einfach zu nutzenden Mapeditor zur Hand hat, statt die Karten für die erste Betaversion seines Spiels mittels Notepad zusammenzubasteln.&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werden wir uns deshalb um einen leicht zu bedienenden Editor kümmern, der grundlegende Fähigkeiten zum Erstellen der Karten und einige brauchbare Tools mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Natürlich wird der Editor mittels der Delphi-VCL realisiert, ist sie doch schliesslich dass was Delphi so groß gemacht hat, und die Entwicklungszeit von Windowsanwendungen signifikant verringert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Bomberman editor1.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wie auf obigem Screenshot zu erkennen basiert die Grundversion unseres Editors auf zwei Fenstern. Im linken Fenster wird das Spielfeld dargestellt, und im rechten befinden sich zum einen Einstellungen bezüglich des zu setztenden Feldes und einige Tools die dem Kartenbauer das Leben erleichtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Quellcode des Editors bietet ansich nichts unbekanntes und dürfte recht leicht verständlich sein. Dennoch werde ich einige relevante Codestellen erläutern :&lt;br /&gt;
&lt;br /&gt;
===OpenGL initialisieren (TForm1.FormCreate)===&lt;br /&gt;
Der Einfachheit halber verwende ich in unserem Bombermanprojekt die {{INLINE_CODE|OpenGL12.pas}} von [http://www.lischke-online.de/ Mike Lischke] in einer minimal abgeänderten Form (betrifft nur das Erstellen des Rendercontext), die dem Projektquellcode natürlich beiliegt.&lt;br /&gt;
&lt;br /&gt;
Diese macht das erstellen eines Rendercontextes zu einem Kinderspiel :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;DC := GetDC(Handle);&lt;br /&gt;
RC := CreateRenderingContext(DC, [opDoubleBuffered], 32, 24, 8, 0, 0, 0, DummyPal);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der ersten Zeile erstellen wir uns vom Handle unseres Fensters einen gültigen DeviceContext vom Typ {{INLINE_CODE|HDC}}, der dann genutzt wird um den OpenGL-Rendercontext zu erstellen.&lt;br /&gt;
&lt;br /&gt;
In der zweiten Zeile erstellen wir einen OpenGL-Context mit Doublebuffering, 32Bit Farbtiefe, 24bittigem Tiefenpuffer und einem 8Bit großen Stencilpuffer, mit dessen Hilfe wir in einem späteren Tutorial Schattenwürfe realisieren werden. Die {{INLINE_CODE|DummyPal}}-Variable ist wie ihr Name schon sagt nur ein Dummy, der nicht benötigt wird, da unser Rendercontext keinen Palettenmodus (256 Farben) nutzt.&lt;br /&gt;
&lt;br /&gt;
Einige Zeilen später werden wir dann einige OpenGL-Werte initialisieren :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glEnable(GL_TEXTURE_2D);&lt;br /&gt;
glEnable(GL_DEPTH_TEST);&lt;br /&gt;
glDepthFunc(GL_LESS);&lt;br /&gt;
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion dieser Zeilen dürfte bekannt sein : Zeile 1 aktiviert zweidimensionales Texturemapping, die Zeilen 2 und 3 legen den Tiefentest fest (aktiviert, und nur Fragmente die weiter vorne liegen durchlassen). Zeile 4 sagt der Grafikkarte dann noch, das sie die best aussehendste Perspektivenkorrektur verwenden soll.&lt;br /&gt;
&lt;br /&gt;
Danach laden wir noch die benötigten Texturen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;TextureManager.AddTexturesInDir('textures', '*.tga');&lt;br /&gt;
for i := 0 to TextureManager.TextureName.Count-1 do&lt;br /&gt;
 Form2.TextureCombo.Items.Add(TextureManager.TextureName[i]);&lt;br /&gt;
ChDir(ExtractFilePath(Application.ExeName));&lt;br /&gt;
&lt;br /&gt;
SetLength(SpecialTex, Length(SpecialTexName));&lt;br /&gt;
for i := Low(SpecialTexName) to High(SpecialTexName) do&lt;br /&gt;
 begin&lt;br /&gt;
 SpecialTex[i] := TglBMP.Create('textures\special\'+SpecialTexName[i]);&lt;br /&gt;
 SpecialTex[i].GenTexture(False, False);&lt;br /&gt;
 end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Block sagen wir dem Texturenmanager das er alle TGA-Dateien im Unterordner {{INLINE_CODE|textures}} in den Texturenpool laden soll. Ich verwende das TGA-Format deshalb, da es eines der wenigen Formate (neben PNG) ist, das einen Alphakanal unterstützt. Mehr zu diesem Alphakanal und seiner Anwendung gibts ineinem späteren Tutorial (Kleiner Hinweis : Alphamasking). Gleichzeitig fügen wir noch alle Texturennamen in die ComboBox im Toolfenster ein, damit wir diese später bequem zuweisen können.&lt;br /&gt;
&lt;br /&gt;
Im zweiten Block laden wir die in der Konstantensektion festgelegten Spezialtexturen die später z.B. genutzt werden um die Startpunkte der Spieler zu kennzeichnen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ihr seit nach diesem etwas langweiligen und nicht besonders anspruchsvollem Ausflug in die Initialisierung des Editors noch wach, denn jetzt kommt etwas schwierigeres...[[Bild:Bomberman wait.gif]]&lt;br /&gt;
&lt;br /&gt;
===Spielfelder mittels des Mauszeigers auswählen (aka Selection)===&lt;br /&gt;
Im Kapitel zur Codebasis hab ich dieses Thema schonmal kurz angeschnitten und euch gezeigt, wie man ein Objekt mittels des Namestacks unter OpenGL &amp;quot;bekannt&amp;quot; macht. Wer mehr zum Thema Selection erfahren will, kann sich ja das Tutorial dazu auf meiner Hompage durchlesen : [http://www.delphigl.de/tutorials/selection_de.html Selection-Tutorial]. (Oder das [[Tutorial_Selection]] hier im Wiki)&lt;br /&gt;
&lt;br /&gt;
Nun stelle ich euch eine (recht kurze, aber knackige) Prozedur vor, die prüft ob und wenn ja, welches dieser auf dem Namestack befindlichen Objekte unter dem Mauszeiger ist. Gemeint ist die Funktion '''GetSelectBufferHit''', die ich euch hier häppchenweise erläutern werde :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;var&lt;br /&gt;
 SelectBuffer : array[0..512] of TGLUInt;&lt;br /&gt;
 Viewport     : TVector4i;&lt;br /&gt;
 Hits,i       : Integer;&lt;br /&gt;
 HitZValue    : TGLUInt;&lt;br /&gt;
 Hit          : TGLUInt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Variablendeklaration dieser Funktion bedarf erstmal einer fundierten Erklärung : Im {{INLINE_CODE|SelectBuffer}}-array werden alle Objekttreffer gespeichert. Jeder Objekttreffer besteht aus vier Werten : Anzahl der Objekte auf dem Namestack zum Zeitpunkt des Treffers, kleinste Z-Koordinate aller Eckpunkte des Objektes, größte Z-Koordinate aller Eckpunkte des Objektes und Name des getroffenen Objektes. Deshalb kann unser SelectBuffer bis zu 128 (512/4) Objekttreffer beinhalten.&lt;br /&gt;
In der Variable Viewport wird der aktuelle OpenGL-Viewport gespeichert, den wir später noch brauchen werden.&lt;br /&gt;
Und mit den Variablen {{INLINE_CODE|Hits, HitZValue}} und {{INLINE_CODE|Hit}} stellen wir am Ende der Funktion in einer Schleife fest welches Objekt nun letztendlich unter dem Mauszeiger liegt.&lt;br /&gt;
&lt;br /&gt;
Kommen wir nun zur eigentlichen Funktion und der in ihr enthaltenen erwähnenswerten Codezeilen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glGetIntegerv(GL_VIEWPORT, @viewport);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mittels dieser Zeile speichern wir den aktuellen Viewport in die vorher dafür definierte Variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glSelectBuffer(512, @SelectBuffer);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hiermit teilen wir OpenGL zum einen die Größe des SelectBuffers und zum anderen dessen Adresse im Speicher mit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRenderMode(GL_SELECT);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt schalten wir in den SelectModus, in dem nichts auf den Bildschirm gerendert wird, aber unser SelectBuffer gefüllt wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glInitNames;&lt;br /&gt;
glPushName(0);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese zwei Zeilen sind unabdingbar, denn sie dienen dazu den Namestack zu initialisieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glMatrixMode(GL_PROJECTION);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
gluPickMatrix(MousePos.x, viewport[3]-MousePos.y, 3.0, 3.0, Viewport);&lt;br /&gt;
gluPerspective(45.0, Form1.ClientWidth/Form1.ClientHeight, 0.1, 2048);&lt;br /&gt;
Form1.DrawScene;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Teil ist sehr wichtig. Hier setzen wir die Ansichtsmatrix so, das (wenn wir im normalen Rendermodus wären) nur der Bereich im 3 Pixel Umkreis um die Mausposition herum gerendert werden würde. Dies dient dazu das nur Objekte im direkten Umkreis der Mausposition in den Selectbuffer gerendert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;Hits      := glRenderMode(GL_RENDER);&lt;br /&gt;
Hit       := High(TGLUInt);&lt;br /&gt;
HitZValue := High(TGLUInt);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zeile schaltet jetzt wieder in den normalen Rendermodus. Allerdings liefert uns OpenGL jetzt (da wir uns vorher im Selectmodus befanden) die Anzahl der getroffenen Objekte zurück. Die zwei nachfolgenden Zeilen initialisieren die Variablen vor, mit deren Hilfe wir später herausfinden welches Objekt dem Mauszeiger am nächsten liegt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;for i := 0 to Hits-1 do&lt;br /&gt;
 if SelectBuffer[(i*4)+1] &amp;lt; HitZValue then&lt;br /&gt;
  begin&lt;br /&gt;
  Hit       := SelectBuffer[(i*4)+3];&lt;br /&gt;
  HitZValue := SelectBuffer[(i*4)+1];&lt;br /&gt;
  end;&lt;br /&gt;
Result := Hit;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mittels der Schleife prüfen wir ob die Z-Koordinaten des neuen Objektes niedriger als die bereits gespeicherte ist (wir erinnern uns : in {{INLINE_CODE|SelectBuffer[(n*4)+1]}} steht die kleinste Z-Koordinate der Eckpunkte dieses Objekts, sprich der dem Betrachter nächste Z-Wert). Wenn dies der Fall ist, übernehmen wir dessen Z-Koordinaten in {{INLINE_CODE|HitZValue}} und dessen Namen in {{INLINE_CODE|Hit}}.&lt;br /&gt;
Am Ende dieser Schleife haben wir dann endlich das Objekt, welches der Kamera am nächsten ist und geben dies im Resultat der Funktion zurück.&lt;br /&gt;
&lt;br /&gt;
Wenns dir jetzt besser geht als unserem kleine Bomberman, dann hast du das Schlimmste bereits überstanden, bei Nichtverstehen nochmal das von mir erwähnte Tut durchlesen...&lt;br /&gt;
&lt;br /&gt;
===Zeichnen der Szene (TForm1.ApplicationEvents1Idle)===&lt;br /&gt;
Bekannterweise gibt es ja jede Menge Möglichkeiten und Stellen an denen man seine Szene zeichnen könnte. Entweder man schreibt sich nen eigenen Loop mittels {{INLINE_CODE|repeat..until}}, machts mit einem Timer (ist übrigens eine sehr schlechte Lösung) oder nimmt ganz einfach den {{INLINE_CODE|OnIdle}}-Event der Form, der über die {{INLINE_CODE|ApplicationEvents}}-Komponente (siehe Komponenten-Tab &amp;quot;Zusätzlich&amp;quot;) zur Vefügung gestellt wird.&lt;br /&gt;
Dieses Ereignis wird eigentlich nicht periodisch aufgerufen, sondern immer nur nach der Abarbeitung einer Fensternachricht. Allerdings kann man dies mit einem kleinen Trick umgehen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;Done := False;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn diese Zeile im {{INLINE_CODE|OnIdle}}-Ereignis aufgerufen wird, verschweigt man Windows ganz einfach das die Anwendung die Nachrichtenschleife durchlaufen hat. Als Folge dessen wird diese Routine permanent durchlaufen, und das OpenGL-Programm hat fast die komplette CPU-Zeit zum Zeichnen der Szene.&lt;br /&gt;
Weitere interessante Zeilen im {{INLINE_CODE|OnIdle}}-Ereignis sind folgende :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;DrawScene;&lt;br /&gt;
SBufferHit := GetSelectBufferHit;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nachdem in der ersten Zeile die Szene gezeichnet wurde, wird der Variable {{INLINE_CODE|SBufferHit}} die Kennung des unter der Maus befindlichen Feldes zugeweisen, so dass man dieses Feld dann in der Zeichneroutine der Karte farblich hervorheben kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;if MouseLeft then&lt;br /&gt;
 if Assigned(SelField) then&lt;br /&gt;
  begin&lt;br /&gt;
  SelField^.Texture := Form2.TextureCombo.Items[Form2.TextureCombo.ItemIndex];&lt;br /&gt;
  SelField^.FType   := Form2.FieldTypeCombo.ItemIndex;&lt;br /&gt;
  end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Codehappen weist dem ausgewählten Feld ({{INLINE_CODE|SelField &amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt; @TFieldType}}) bei gedrückter linker Maustaste die im Toolfenster ausgewählte Textur und den ausgewählten Feldtyp zu. Ist kein Feld unter dem Cursor ({{INLINE_CODE|SelField &amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt; nil}}) dann geschieht nichts, da {{INLINE_CODE|Assigned()}} diesen Fall abfängt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So, geschafft!Das war alles Wichtige zum Quellcode des Editors.Der Rest des Codes ist recht einfach und aufgrund der Dokumentation und ausgiebieger Kommentare im Quelltext dürfte er auch keine Probleme machen... [[Bild:Bomberman cheer.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Abschliessend gibts noch ein paar Worte zur Bedienung des Editors :&lt;br /&gt;
&lt;br /&gt;
:Im 3D-Fenster :&lt;br /&gt;
::Cursortasten : Auf dem Spielfeld scrollen&lt;br /&gt;
::Mausrad : Rein- bzw. rauszoomen&lt;br /&gt;
::Bild rauf/Bild runter : Kamerawinkel verändern&lt;br /&gt;
::Linke Maustaste : Feld unter dem Mauscursor mit der Textur und dem in Form2 gewählten Feldtyp belegen&lt;br /&gt;
::Rechte Maustaste : Kontextmenü mit Spezialfeldern aufrufen&lt;br /&gt;
::+/- : Spielfeld rotieren&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Schlusswort==&lt;br /&gt;
&lt;br /&gt;
Das wars fürs Erste, und ich hoffe das Tutorial hat euch gefallen. Weiterhin hoffe ich natürlich das ihr meiner Tutorialserie bis zum Ende treu bleibt und mich mit Feedback (am besten direkt ins Forum) überschüttert. Anregungen und Kritik (solange konstruktiv) sehe ich nämlich gerne und motivieren mich auch...&lt;br /&gt;
Außerdem interessieren mich eure Modifikationen zum Editor und eure Levelkonstrukte, postet also fleissig Neuerungen, Verbesserungen und gebastelte Level ins Forum, und '''freut euch auf den zweiten Teil der Tutorialreihe!!!'''&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:'''Sascha Willems'''&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_NapalmBomber1_vcl‎|text=Quelltext des Editors mit Windows Binaries}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| - | [[Tutorial_Bomberman2]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Bomberman1]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Prozeduale_B%C3%A4ume&amp;diff=25658</id>
		<title>Prozeduale Bäume</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Prozeduale_B%C3%A4ume&amp;diff=25658"/>
				<updated>2012-03-21T14:58:55Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausser -&amp;gt; Außer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Prozeduale Bäume sind eine tolle Sache für eine größere Umgebung, wenn man dem Spieler nicht immer die selben - von Grafikern erstellten - Bäume vorsetzen möchte. Denn es wäre sehr Aufwändig für einen Wald aus &amp;gt; 10 Bäumen niemals den selben Baum doppelt in einem Bild zu verwenden und somit für den Betrachter die Welt glaubhaft(er) zu gestalten.&lt;br /&gt;
&lt;br /&gt;
=Allgemeine Vorgehensweise=&lt;br /&gt;
Im Unterschied zur Landschaft oder ähnlichen Prozedualen Grafiken sind hier die unterschiedlichen Stufen der Generierung meist auch unterschiedliche Objekttypen. Ausgehend von einem Stamm werden die Äste berechnet, über die Äste die Zweige und schlussendlich werden die Blätter veteilt.&lt;br /&gt;
&lt;br /&gt;
=Bäume mit [[L-Systems]]=&lt;br /&gt;
[[L-Systems]] basieren darauf, aus einem vorgegebenem, primitiven Muster durch rekursives einsetzen dieses Musters in sich selbst ein beliebig komplexes Modell zu erstellen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:LSystemBaum.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
''Mehrere Detailstufen eines Baumes mit L-Systems, generiert mit [http://spanky.triumf.ca/www/fractint/fractint.html Fractint]&lt;br /&gt;
&lt;br /&gt;
[[L-Systems]] wären nur mit stärkeren Modifikationen auch für 3D-Bäume einsetzbar, denn das Verhältnis von Blättern (höchste Stufe) zu Stamm und Ästen (die ersten paar Stufen) lässt sich nur schwer regulieren. Zum generieren von 2D-Texturen eignen sie sich hingegen sehr gut. Für die höchste Stufen werden die Linien durch Blatttexturen ersetzt, für die unteren Stufen eine Holztextur mit entsprechender Dicke. Natürlich sollte der Algorithmus auch noch mit Informationen zur Dicke und ähnlichem gefüttert werden.&lt;br /&gt;
&lt;br /&gt;
=Speedtree Bäume=&lt;br /&gt;
Dies ist nicht der Name eines Algorithmus, sondern eines Produktes. Ich nenne sie deshalb so, da die Idee Bäume auf diese Art zu Generieren meines Wissens nach erstmals in der Middleware Speedtree von [http://www.idvinc.com/ Interactive Data Visualization (IDV), Inc.] umgesetzt wurde. Dieser Text bezieht sich auch sehr stark auf diese Software, jedoch natürlich mehr auf den technischen Aspekt um selbst Bäume dieser Art generieren zu können.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SpeedTrees.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
''mehrere generierte Bäumen des selben Typs mit einem derartigen Algorithmus''&lt;br /&gt;
&lt;br /&gt;
==Generelle Vorgehensweise==&lt;br /&gt;
Bei Speedtree wird der Baum in bis zu 4 unterschiedliche Stufen unterteilt:&lt;br /&gt;
*Stamm&lt;br /&gt;
*beliebige viele Aststufen&lt;br /&gt;
*Zweige&lt;br /&gt;
*Blätter&lt;br /&gt;
Jede Stufe baut auf der vorigen Stufe auf:&lt;br /&gt;
*Äste werden für den Stamm oder für jeden Ast der vorigen Stufe generiert&lt;br /&gt;
*Zweige werden für jeden Ast generiert&lt;br /&gt;
*Blätter werden für jeden Zweig generiert&lt;br /&gt;
Stamm, Äste und Zweige werden grundlegend gleich generiert, jedoch sind bei einem mehr bei einem weniger Informationen nötig.&amp;lt;br&amp;gt;&lt;br /&gt;
Die unterschiedlichen Bäume, die jedoch dennoch ähnlich aussehen und vom selben Baumtyp sind, werden durch Pseudozufallszahlen für nahezu jeden einstellbaren Wert erzeugt. Somit hat nahezu jeder Wert auch eine maximale Abweichung.&lt;br /&gt;
&lt;br /&gt;
==Stamm==&lt;br /&gt;
Stamm gibt es natürlich nur einen. Er wird durch einen Zylinder mit beliebig vielen Unterteilungen in der Höhe und auch im Grundriss (also dem Kreis) definiert. Jeder Punkt dieses Zylinders wird durch verschiedenste Parameter berechnet. Einmalig sind für den Stamm folgende Werte wichtig:&lt;br /&gt;
*Radius&lt;br /&gt;
*Größe&lt;br /&gt;
*Startwinkel&lt;br /&gt;
*Unterteilungen in der Höhe&lt;br /&gt;
*Unterteilungen des Grundrisses&lt;br /&gt;
*Wiederholungen der Textur in der Höhe&lt;br /&gt;
*Wiederholungen der Textur am Grundriss&lt;br /&gt;
*ggf. Gravitation (dient als Multiplikator für alle Neigungen nach unten oder oben)&lt;br /&gt;
Abhängig von der Höhe werden zusätzlich noch folgende Parameter wichtig:&lt;br /&gt;
*Profileinwirkung&lt;br /&gt;
*Radiusmultiplikator (die Dicke des Stammes abhängig von der Höhe, ein Multiplikator für Radius)&lt;br /&gt;
*Neigungswinkel&lt;br /&gt;
*Abweichung&lt;br /&gt;
Aus diesen Parametern lässt sich nahezu jede beliebige, aber dennoch natürlich wirkende Stammform erzeugen. Das Profil gibt hierbei eine zufällige Abweichung für jeden Punkt des Grundrisses an, der jedoch für jeden Punkt des Grundrisses in der Höhe gleich sein sollte. Das Profil eignet sich sehr gut zur Simulation von Wurzeln am unteren Ende des Stammes.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Abweichung gibt eine zufällige Neigung an die zum Neigungswinkel addiert wird.&lt;br /&gt;
Die Punkte des Baumes werden nun wie folgt berechnet (Neigungen vorerst außer Acht gelassen)&lt;br /&gt;
 G = die (2D-)Punkte des Grundrisses (ein Kreis mit Radius 1 und den angegebenen Unterteilungen)&lt;br /&gt;
 Pg = Profileinwirkung in Abhängigkeit der Höhe des Punktes&lt;br /&gt;
 Punkt = ( Pg + Radius * Radiusmultiplikator(Höhe) ) * G&lt;br /&gt;
Dieser Vorgang muss natürliche für jede Höhe durchgeführt werden. In der Höhe wird der Stamm linear unterteilt, demnach ist&lt;br /&gt;
 Höhe von Schicht X = X * (Größe / (Unterteilungen der Höhe - 1) )&lt;br /&gt;
sofern bei den Unterteilungen auch die oberste und die unterste Schicht mit gezählt wird. Die Neigung des Stammes lässt sich sehr gut über [[Matrix|Matrizen]] berechnen. Für jede Höhenschicht wird dabei die Matrix berechnet, in Pseudocode:&lt;br /&gt;
 M = Identitätsmatrix&lt;br /&gt;
 Rotiere M um Z-Achse nach belieben (die Neigung sollte nicht immer in die gleiche Richtung gehen)&lt;br /&gt;
 Für jede Höhenschicht&lt;br /&gt;
  Multipliziere Punkte dieser Höhenschicht mit M&lt;br /&gt;
  Rotiere M um X-Achse um ( Abweichung(Höhe) + Neigungswinkel(Höhe) ) * Gravitation&lt;br /&gt;
  wenn unterste Höhenschicht&lt;br /&gt;
   Rotiere M um X-Achse um Startwinkel&lt;br /&gt;
  Verschiebe M nach oben (Z-Achse) entsprechend der Höhe eines Höhensegmentes&lt;br /&gt;
Rotiere um Z-Achse nach belieben bedeutet hier einen Zufallswert zwischen 0 und 360 Grad.&amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Pseudocode ist zu beachten, das die unterste Schicht keine Neigung erhält. Dies hat den Nachteil dass es bei stärkeren Rotationen nicht ganz so gut aussieht, jedoch den Vorteil, dass jeder Punkt der Grundfläche immer am Boden steht (Höhe 0 hat). Wenn der Untergrund nicht halbwegs eben sein muss, so ist dies jedoch eher egal.&lt;br /&gt;
&lt;br /&gt;
==Äste==&lt;br /&gt;
Äste werden vom Stamm ausgehend generiert. Für die Generierung der Äste werden beim Stamm nun noch weitere Parameter benötigt:&lt;br /&gt;
*Von wo weg (Prozent der Höhe)&lt;br /&gt;
*Bis wo (Prozent der Höhe)&lt;br /&gt;
*Anzahl (Abhängig von der Höhe)&lt;br /&gt;
Die Abhängigkeit der Höhe hat den Vorteil, dass es ein extrem kleiner Baum nicht gleich viele Äste wie ein großer erhält.&amp;lt;br&amp;gt;&lt;br /&gt;
Gleiches gilt jedoch auch für jedes Ast-Level, da es ja mehrere Level geben kann, also benötigt auch jedes Astlevel die selben Informationen zur Generierung der nächsten Ast-Level.&lt;br /&gt;
&lt;br /&gt;
Die Anzahl der Äste ist beispielsweise je 10 Meter in der Länge der Vorgänger-Stufe angegeben. Dadurch kann man die Anzahl sehr leicht bestimmten (Tatsächliche Anzahl = Anzahl * 10 / Länge). Die Generierung der Äste kann nun folgendermaßen erfolgen:&lt;br /&gt;
 Höhe = Random im Bereich [Von wo Weg|Bis wo]&lt;br /&gt;
 M = Matrix der entsprechenden Höhensegmentes zu &amp;lt;Höhe&amp;gt; (des Stammes oder des Astes)&lt;br /&gt;
 HSeg = Höhe des entsprechenden Höhensegmentes (aktuelle Höhe von M)&lt;br /&gt;
 Verschiebe M nach oben um &amp;lt;Höhe&amp;gt; - &amp;lt;HSeg&amp;gt;&lt;br /&gt;
 Rotiere M um Z-Achse nach belieben (damit die Äste in unterschiedliche Richtungen zeigen)&lt;br /&gt;
 Rotiere M um X-Achse entsprechend &amp;lt;Startwinkel(Höhe)&amp;gt;&lt;br /&gt;
Rotiere um Z-Achse nach belieben bedeutet hier einen Zufallswert zwischen 0 und 360 Grad.&amp;lt;br&amp;gt;&lt;br /&gt;
Startwinkel(Höhe) ist hierbei ein Wert der in Abhängigkeit der Höhe/Länge der vorigen Stufe angegeben wird. Abhängig von der Höhe/Länge der vorigen Stufe benötigt man in der zu generierenden Aststufe folgende Informationen:&lt;br /&gt;
*Länge&lt;br /&gt;
*Radius (ein Multiplikator für den Radius der Vorgängerstufe an der entsprechenden Höhe)&lt;br /&gt;
*Startwinkel&lt;br /&gt;
*Graviation (Wiederum ein Multiplikator für Neigungen welcher jedoch bei Ästen sehr viel ausmacht)&lt;br /&gt;
Durch diese Parameter sind die Anfangsparameter die wir auch beim Stamm hatten gegeben, zur Erinnerung:&lt;br /&gt;
*Radius&lt;br /&gt;
*Größe&lt;br /&gt;
*Startwinkel&lt;br /&gt;
*Gravitation&lt;br /&gt;
Auch die anderen Parameter, diese waren:&lt;br /&gt;
*Profil in Abhängigkeit der Höhe&lt;br /&gt;
*Radius in Abhängigkeit der Höhe&lt;br /&gt;
*Winkel in Abhängigkeit der Höhe&lt;br /&gt;
*Abweichung in Abhängigkeit der Höhe&lt;br /&gt;
*Unterteilungen in der Höhe&lt;br /&gt;
*Unterteilungen des Grundrisses&lt;br /&gt;
*Wiederholungen der Textur in der Höhe&lt;br /&gt;
*Wiederholungen der Textur am Grundriss&lt;br /&gt;
werden genau so für jede Aststufe benötigt. Nur das Profil ist für Äste kaum noch relevant, kann aber bei Bedarf ebenfalls verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Die Generierung der Astgeometrie erfolgt genau gleich wie bei einem Stamm, mit sehr geringen Modifikationen:&lt;br /&gt;
*Profil muss nicht mit einberechnet werden&lt;br /&gt;
*Die Anfangsmatrix wird durch die Vorgängerstufe definiert (nicht durch die Identitätsmatrix)&lt;br /&gt;
*Bei den Ästen ist es (im Gegensatz zum Stamm) meist sinnvoll wenn auch das unterste (erste) Längensegment rotiert wird, da dieses im Stamm ist und somit nicht sichtbar sein sollte.&lt;br /&gt;
&lt;br /&gt;
==Zweige==&lt;br /&gt;
Zweige sollen sehr detailiertes, feines Geäst darstellen. Dazu werden teilweise durchsichtige Texturen (Opacity Maps, also mit Alpha 0 oder 255) verwendet.&lt;br /&gt;
&lt;br /&gt;
Zweige werden genau gleich erzeugt wie Äste. Auch die Geometrie wird sehr ähnlich generiert obwohl sie ganz anders aussieht. Hier möchte ich mich also auf die Unterschiede konzentrieren.&lt;br /&gt;
&lt;br /&gt;
Die Geometrie eines Zweiges ist eine beidseitig sichtbare (siehe [[Backface Culling]]), 2D Geometrie, und zwar eine Ebene welche jedoch mehrere Unterteilungen entlang der Länge und auch Krümmungen enthalten kann. Somit werden anstatt eines Kreises als Grundfläche einfach 2 Punkte zur Berechnung verwendet. Für die Breite sind keine Unterteilungen nötig.&lt;br /&gt;
&lt;br /&gt;
Da es sich um eine 2D Geometrie mit einer 2D Textur handelt, sollte das Verhältnis von Länge zu Breite immer gleich sein. Aus diesem Grund fallen alle Berechnungen für den Radius weg, es kommt jedoch ein zusätzlicher Faktor zur Angabe dieses Verhältnisses hinzu (oder er wird aus dem Seitenverhältnis der Textur entnommen).&lt;br /&gt;
&lt;br /&gt;
Dies waren auch schon die beiden wichtigsten Unterschiede und somit sollte das Generieren von Zweigen kein Problem sein wenn man bereits einen Stamm und Äste hat.&lt;br /&gt;
&lt;br /&gt;
==Blätter==&lt;br /&gt;
Eine gute Möglichkeit Blätter zu einem Baum hinzu zu fügen sind spherische [[Billboard]]s. Dabei wird ebenfalls eine teilweise Transparente Textur verwendet welche eine Ansammlung von Blätter dar stellt. Zur Erzeugung können wiederum die Von wo weg- und Bis wo hin Werte der vorigen Stufe verwendet werden. Auch die Anzahl im Verhältnis zur Länge wird in der Vorgängerstufe angegeben. Im Unterschied zu den vorigen Baumteilen werden die Blätter ganz anders, jedoch um einiges einfacher generiert. Es sind nur 2 Parameter notwendig:&lt;br /&gt;
*Größe eines Blattes (da es sich um spherische Billboards handelt sind sie üblicherweise quadratisch)&lt;br /&gt;
*Abstand zum Vorgänger in Abhängigkeit der Länge&lt;br /&gt;
Die Position eines Blattes kann nun gleich wie bei Ästen durch die Matrix des Vorgängers bestimmt werden, mit dem Unterschied das nur 1 Punkt mit dieser Matrix multipliziert werden muss.&lt;br /&gt;
&lt;br /&gt;
==Texturen==&lt;br /&gt;
Die Texturcoordinaten-Berechnung sollte keine Probleme bereiten. Beim Stamm und bei den Ästen werden diese einfach linear entlang der Höhe und um den Grundriss verteilt. Folgende Texturen werden benötigt:&lt;br /&gt;
*Stamm und Äste: eine Kachelbare Rindentextur&lt;br /&gt;
*Zweige: Geäst, natürlich auch mit einem &amp;quot;Stamm&amp;quot; von dem dieses Geäst entspringt&lt;br /&gt;
*Blätter: eine Ansammlung von Blättern.&lt;br /&gt;
&lt;br /&gt;
==Wertabhängige Parameter==&lt;br /&gt;
Es wurden in diesem Artikel sehr häufig Parameter verwendet die von einem anderen Wert abhängig sind (der Höhe oder Länge einer Stufe oder der vorgänger Stufe). Dies ist natürlich ein idealer Anwendungsfall für 2D-Splines. Um den selben Kurveneditor für alle Parameter verwenden zu können, sollten natürlich alle Abfragen in einem Definierten Bereich sein. Im Endeffekt wird jedoch nur eine Funktion benötigt die einen durch den Grafiker festgelegten Wert X für eine Höhe/Länge Y liefert.&lt;br /&gt;
&lt;br /&gt;
==Schlussworte==&lt;br /&gt;
Halbwegs realistisch aussehende, prozedual erstellte Bäume sind eine nicht triviale Angelegenheit, da vor allem schlecht gewählte Zufallswerte sehr viel Auswirkungen auf die Realitätsnähe haben können. Vor allem bei der Erzeugung von Ästen und Zweigen und auch Blättern kann eine weitere Einschränkung des Zufalls äusserst hilfreich sein, da ansonnsten nur etwa 1 von 10 generierten Bäumen brauchbar ist. Die Verteilung der Äste und Zweige ist sehr häufig etwas ungut da sie alle etwa die selbe Höhe besitzen, oder alle etwa in die selbe Richtung zeigen können (was auch sehr häufig der Fall ist). Um dies zu umgehen könnten Beispielsweise hier die Rotation (welche im oberen Code immer durch die Z-Achse ausgedrückt wird) gleichmäßig auf alle erzeugten Äste verteilt werden, was jedoch natürlich wiederum den Zufall und somit die Unterschiede von einem Baum zum anderen einschränkt. Gleiches gilt für die Höhe.&lt;br /&gt;
&lt;br /&gt;
Die Verteilung der Blätter ist ungut, da man bei einer rein zufälligen Verteilung fast 5 mal so viele Blätter für einen schönen Baum benötigt wie wenn man verhindert das 2 Blätter sehr nah beieinander liegen können, dies kann auch im (frei downloadbaren) Editor von Speedtree gut getestet werden. Vor allem bei den Blättern ist es jedoch natürlich eine Frage der Performance bei der Generierung und bei der Darstellung (Kollisionsabfragen bei der Erzeugung oder Brute force bei der Erzeugung wodurch unnötig viele Blätter immer gezeichnet werden müssen).&lt;br /&gt;
&lt;br /&gt;
Bei derartigen Algorithmen muss also ein gutes Mittelmaß zwischen Zufall und Realismus (bzw. Prozentsatz der realistisch wirkenden Bäume) gefunden werden.&lt;br /&gt;
&lt;br /&gt;
Hier möchte ich auch noch kurz auf die hier nicht behandelten Probleme eingehen:&lt;br /&gt;
&lt;br /&gt;
'''[[LOD|Level of Detail]]'''&amp;lt;br&amp;gt;&lt;br /&gt;
Bei den Blättern hat man hier 3 Möglichkeiten:&lt;br /&gt;
#Blätter entfernen indem man sie verkleinert&lt;br /&gt;
#Blätter entfernen indem man sie langsam transparenter macht&lt;br /&gt;
#Blätter einfach entfernen (was jedoch zu [[Popping]] führt)&lt;br /&gt;
Natürlich müssen die restlichen Blätter vergrößert werden wenn Blätter entfernt werden.&lt;br /&gt;
&lt;br /&gt;
Bei den Zweigen und Ästen sieht es ähnlich aus, hier kämen jedoch eventuell noch [[VIPM]]s in Frage.&lt;br /&gt;
&lt;br /&gt;
'''Normalvektor-Berechnung'''&amp;lt;br&amp;gt;&lt;br /&gt;
Die Normalvektor-Berechnung für den Stamm, Äste und für die Zweige dürfte nicht allzu Problematisch sein. Entweder man verwendet die Position des Punktes am Kreis für die Berechnung, oder man berechnet sich die Normalvektoren aus den 3eck-Daten.&lt;br /&gt;
&lt;br /&gt;
Für die Blätter hingegen eignet sich wohl am Besten der Vektor vom Baumzentrum zur Blattposition.&lt;br /&gt;
&lt;br /&gt;
'''Wind'''&amp;lt;br&amp;gt;&lt;br /&gt;
Für die Blätter ist eine Windsimulation sehr einfach zu machen, indem man die Spherischen Billboards ein bisschen hin und her dreht. Für Äste und Zweige hingegen benötigt man wohl [[Vertexprogramm]]e für eine effiziente Implementierung.&lt;br /&gt;
&lt;br /&gt;
'''Kollisionsabfrage'''&amp;lt;br&amp;gt;&lt;br /&gt;
Die Generierung der Kollisionsobjekte kann auf unterschiedliche Weise erfolgen. Man könnte vordefinierte Kollisionsobjekte für jeden Baumtyp verwenden, was jedoch nicht sehr genau ist. Für eine detailiertere Kollisonsabfrage werden natürlich die [[Bounding_Volume|Bounding Volumen]] von Stamm, Ästen, Zweigen und evntl. auch von den Blättern benötigt. Die Berechnung von diesen fällt jedoch nicht in den Bereich der Baum-Generierung.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]]&lt;br /&gt;
[[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_8&amp;diff=25657</id>
		<title>Tutorial Lektion 8</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_8&amp;diff=25657"/>
				<updated>2012-03-21T14:58:35Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausser -&amp;gt; Außer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Das Wesen von Hell und Dunkel - Licht =&lt;br /&gt;
&lt;br /&gt;
== Licht an ==&lt;br /&gt;
&lt;br /&gt;
Hi,&lt;br /&gt;
und wieder melde ich mich mit einem neuen Tutorial zurück. Heutiges Thema: Licht. Ohne Licht wäre die Umwelt dunkel und kein Pflänzchen könnte Zucker mittels Photosynthese erzeugen. Gäbe es kein Licht, so gäbe es die Welt nicht, wie wir sie kennen. Um in den eigenen OpenGL Programmen eine auch nur annähernd realistische Atmosphäre zu erzeugen ist Licht entsprechend unabdingbar. Man kann Szenen dadurch einen düsteren, geheimnisvollen oder auch einen farbenfrohen, fast kitschigen Stil verleihen.&lt;br /&gt;
&lt;br /&gt;
== Arten des Lichts ==&lt;br /&gt;
&lt;br /&gt;
In OpenGL gibt es unterschiedliche Arten des Lichts. Umgebungs-Licht ('''Ambient''') ist eine Art des Lichts, dessen Richtung nicht zu erkennen ist. Es entsteht durch mehrfache Reflexion an Wänden oder anderen Flächen. Entsprechend gut vertreten ist es in Räumen, aber auch in der freien Natur umgibt uns nicht zu wenig davon. An sich ist es das am schwierigsten zu berechnende, aber in vielen Szenen reicht es aus, eine Konstante vorzugeben - so macht es jedenfalls OpenGL.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Diffuses&amp;quot; Licht ('''Diffuse''') dagegen lässt die Richtung aus der es kommt erkennen. Je stärker eine Seite in das Licht gehalten wird, desto heller erscheint die Oberfläche. Je weiter man eine Fläche vom Licht abwendet, desto dunkler wird die Oberfläche. Die eintreffenden Lichtstrahlen werden in alle Richtungen verteilt, so dass die Oberfläche von allen Augenpositionen gleich hell erscheint.&lt;br /&gt;
&lt;br /&gt;
Glanz ('''Specular''') kommt aus einer bestimmten Richtung und tendiert dazu, in einer bestimmten Richtung besonders hell zu erscheinen. Plastik, gebürstetes oder nicht matt lackiertes Metall oder auch geschliffene Edelsteine haben einen hohen Glanzanteil, während Holz, Kohle und Wandfarbe so gar nicht glänzen wollen.&lt;br /&gt;
&lt;br /&gt;
== Materialeigenschaften ==&lt;br /&gt;
&lt;br /&gt;
Der vom Licht erzeugte Eindruck hängt aber nicht nur vom Licht selbst ab, sondern auch vom beleuchteten Material. Eine Kohleplatte wirkt im selben Licht anders, als eine polierte Edelstahloberfläche oder das Blech eines lackierten Autos. Deshalb gibt es in OpenGL die sog. Materialeigenschaften. Sie entsprechen denen des Lichts selbst, nur geben sie den Reflexionsgrad und nicht die Intensität wieder. {{Hinweis|Hier im Wiki findet ihr in der [[Materialsammlung]] eine Auswahl von Parameterwerten.}}&lt;br /&gt;
&lt;br /&gt;
Objekte können nun aber auch selbst Licht emittieren. Deshalb befindet sich unter den Materialeigenschaften zusätzlich noch ein Emissionswert. Ein Objekt mit Emission ist also auch bei kompletter Dunkelheit noch sichtbar, so z.B. die grüne Leuchtdiode an meinen Boxen, wenn ich die Rollläden geschlossen habe. Schade nur, dass OpenGL dieses emittierte Licht nicht auch auf andere Objekte überträgt :-(.&lt;br /&gt;
&lt;br /&gt;
== Normalen ==&lt;br /&gt;
&lt;br /&gt;
OpenGL berechnet die Farbe des Lichts, das auf ein Objekt trifft mit Hilfe der Richtung aus der das Licht kommt und der Ausrichtung der Oberfläche eines Vertex. Nun stellt sich die Frage: in welche Richtung zeigt denn die Oberfläche? Wir können bei der Übergabe der Vertexdaten einfach mit [[glNormal]]x die Normalen angeben. Die Länge des Normalenvektors sollte 1 sein. Bei einer Kugel entspricht die Normale übrigens immer der Richtung des Mittelpunktes zum betrachteten Vertex. Für kompliziertere Gegenstände gibt es weiter unten ein paar Tipps zum Berechnen der Normalen auf &amp;quot;Nachbarschaftsbasis&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Erste Lichtstrahlen ==&lt;br /&gt;
&lt;br /&gt;
=== Licht an ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_test.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Es wird Zeit. Machen wir erste Gehversuche mit OpenGL Licht! Wir brauchen dazu nicht viel zu tun. Mit glEnable(GL_LIGHTING) schalten wir die Lichtberechnung scharf und müssen dann eine Lichtquelle aktivieren. Das geht mit glEnable(GL_LIGHTx) (Zur Information: OpenGL Implementationen müssen 8 Lichter unterstützen. Es gibt aber Implementationen, die hier mehr zu bieten haben. Um Zugriff auf alle vorhandenen Lichter zu erhalten, genügt es zu GL_LIGHT0 einen entsprechenden Wert zu addieren. GL_LIGHT0+8 wäre dann z.B. das 9. Licht).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LIGHTING);&lt;br /&gt;
  glEnable(GL_LIGHT0);&lt;br /&gt;
  glEnable(GL_COLOR_MATERIAL);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sonnenbrand erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der nächste Schritt besteht darin, die Eigenschaften der Lichtquelle(n) an OpenGL weiterzureichen. Dies läuft immer mit der Funktion '''[[glLight]]x'''. Sie nimmt 3 Parameter: '''light''': Die Lichtquelle die gerade eingestellt wird. '''pname''': Die Eigenschaft, die wir manipulieren möchten. '''params''': Der neue Wert der Eigenschaft.&lt;br /&gt;
&lt;br /&gt;
Mit '''pname''' dürfen wir aus einer ganzen Sammlung von Eigenschaften schöpfen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! Eigenschaft&lt;br /&gt;
! Standard Wert&lt;br /&gt;
! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| GL_AMBIENT || 0.0, 0.0, 0.0, 1.0 || Ambienter RGBA Anteil des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_DIFFUSE || 1.0, 1.0, 1.0, 1.0 || Diffuser RGBA Anteil des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPECULAR || 1.0, 1.0, 1.0, 1.0 || Glanz RGBA Anteil des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_POSITION || 0.0, 0.0, 1.0, 0.0 || Koordinaten des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPOT_DIRECTION || 0.0, 0.0, -1.0 || Richtung des Spotlights&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPOT_EXPONENT || 0.0 || Spotlight-Exponent&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPOT_CUTOFF || 180.0 || Spotlight Sperrwinkel&lt;br /&gt;
|-&lt;br /&gt;
| GL_xxx_ATTENUATION || ... || Abschwächung des Lichtes mit der Entfernung&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Materialeigenschaften übergeben ===&lt;br /&gt;
&lt;br /&gt;
Das gleiche Spielchen müssen wir mit den Materialeigenschaften treiben. Diesmal ist die Funktion '''[[glMaterial]]x''' der Dreh und Angelpunkt. Die Parameterfolge ist die gleiche wie bei '''[[glLight]]x'''.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! Eigenschaft&lt;br /&gt;
! Standard Wert&lt;br /&gt;
! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| GL_AMBIENT || 0.2, 0.2, 0.2, 1.0 || RGBA Reflexionsgrad von ambientem Licht&lt;br /&gt;
|-&lt;br /&gt;
| GL_DIFFUSE || 0.8, 0.8, 0.8, 1.0 || RGBA Reflexionsgrad von diffusem Licht&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPECULAR || 0.0, 0.0, 0.0, 1.0 || RGBA Glanzreflexionsgrad des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_SHININESS || 0.0 || Glanz-Exponent&lt;br /&gt;
|-&lt;br /&gt;
| GL_EMISSION || 0.0, 0.0, 0.0, 1.0 || RGBA Emission des Materials&lt;br /&gt;
|-&lt;br /&gt;
| GL_COLOR_INDEXES || 0, 1, 1 || Ambient, diffuse, specular Farbindices&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Beispiellicht ===&lt;br /&gt;
&lt;br /&gt;
Das Beispiel mit den Kugeln wurde mit folgendem Code erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure TStationarySphereState.RenderState;&lt;br /&gt;
  const&lt;br /&gt;
    mat_specular   : Array[0..3] of GlFloat = (1.0, 1.0, 1.0, 1.0);&lt;br /&gt;
    mat_shininess  : Array[0..0] of GlFloat = (50.0);&lt;br /&gt;
    mat_ambient    : Array[0..3] of GlFloat = (0.4, 0.4, 0.4, 1.0);&lt;br /&gt;
    mat_diffuse    : Array[0..3] of GlFloat = (0.4, 0.8, 0.4, 1.0);&lt;br /&gt;
&lt;br /&gt;
    light_position : Array[0..3] of GlFloat = (10.0, 10.0, 0.0, 1.0);&lt;br /&gt;
    light_ambient  : Array[0..3] of GlFloat = (0.8, 0.8, 0.8, 1.0);&lt;br /&gt;
    light_diffuse  : Array[0..3] of GlFloat = (0.8, 0.8, 0.8, 1.0);&lt;br /&gt;
&lt;br /&gt;
  begin&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_SPECULAR,  @mat_specular[0]);&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_SHININESS, @mat_shininess[0]);&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_AMBIENT,   @mat_ambient[0]);&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   @mat_diffuse[0]);&lt;br /&gt;
&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_AMBIENT,  @light_ambient[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  @light_diffuse[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_POSITION, @light_position[0]);&lt;br /&gt;
&lt;br /&gt;
    glEnable(GL_COLOR_MATERIAL);&lt;br /&gt;
    glEnable(GL_LIGHTING);&lt;br /&gt;
    glEnable(GL_LIGHT0);&lt;br /&gt;
     ...Szene Rendern...&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Etwas schwächer bitte ==&lt;br /&gt;
&lt;br /&gt;
Viele Lichtquellen werden mit der Entfernung schwächer. Bei unserer Sonne tritt dieser Effekt so gut wie nicht auf, bei kleinen Funzeln dagegen ist recht bald die maximale Leuchtweite erreicht. Diesen Effekt können wir auch mit OpenGL nachahmen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_attenuation.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Auf diesem Bild ist schön zu erkennen, dass die Kugeln rechts oben heller sind als die links unten, welche weiter von der Lichtquelle entfernt sind (wer nichts sieht, spiele doch mal bitte mit dem [[Farbraum#Grundlegende_Bildschirmkalibrierung|Kontrast und der Helligkeit]] des Monitors - ich kann nicht versprechen, dass der Effekt auf jedem Monitor so schön wie auf meinem herauskommt). Wie wird nun dieser Effekt erzeugt?&lt;br /&gt;
&lt;br /&gt;
OpenGL kennt einen sog. Attenuation Factor:&lt;br /&gt;
&lt;br /&gt;
Attenuation Factor = 1 / (k&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; + k&amp;lt;sub&amp;gt;l&amp;lt;/sub&amp;gt;*d + k&amp;lt;sub&amp;gt;q&amp;lt;/sub&amp;gt;*d*d)&lt;br /&gt;
&lt;br /&gt;
* d = Entfernung zwischen dem berechneten Vertex und der Lichtquelle&lt;br /&gt;
* k&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; = GL_CONSTANT_ATTENUATION&lt;br /&gt;
* k&amp;lt;sub&amp;gt;l&amp;lt;/sub&amp;gt; = GL_LINEAR_ATTENUATION&lt;br /&gt;
* k&amp;lt;sub&amp;gt;q&amp;lt;/sub&amp;gt; = GL_QUADRATIC_ATTENUATION&lt;br /&gt;
&lt;br /&gt;
Dieser wird Faktor bei der Lichtberechnung einfach mit den Lichtstärken multipliziert, so dass das Licht stärker oder schwächer wird. Übergeben werden die Werte wieder mittels '''[[glLight]]x''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0);&lt;br /&gt;
  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.001);&lt;br /&gt;
  glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.004);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Das Positionsproblem ==&lt;br /&gt;
&lt;br /&gt;
Lichter sind unterschiedlich - Manche sind fest an den Kopf des Betrachters gekoppelt, andere irgendwo in der Szene platziert und wieder andere sind unendlich weit entfernt und ihr Licht trifft parallel auf die Gegenstände. All dies will simuliert werden. OpenGL hält es parat. Uns kommt auch noch zugute, dass OpenGL die Übergabe der Licht Position genauso behandelt wie die eines Vertex und entsprechend durch die Modelview Matrix jagt.&lt;br /&gt;
&lt;br /&gt;
=== Unendlich weit entfernte Lichter ===&lt;br /&gt;
&lt;br /&gt;
Das Universum, die Milchstraße, der äußere Ring, unser Sonnensystem, die Sonne und unsere Erde. Das Licht, das unsere Sonne ausstrahlt und bei uns auf der Erde ankommt, trifft uns in nahezu parallelen Lichtstrahlen. Damit verhält sich die Sonne wie eine unendlich entfernte Lichtquelle. Wenn wir eine solche Lichtquelle angeben wollen, ist also nicht ihre Position interessant (wobei das auch ginge), sondern allein die Richtung aus der das Licht kommt. Wie? Wir setzen die w-Koordinate(=die letzte Koordinate) der Position auf 0. Unsere unendlich weit entfernte Lichtquelle ist komplett. Sinnigerweise ist dann im übrigens auch Attenuation abgeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== Stationäre Lichtquellen ===&lt;br /&gt;
&lt;br /&gt;
Lichtquellen, die an einer bestimmten Stelle in der Szene stehen, müssen mit der Kamerabewegung mitgeschoben werden. Entsprechend wird das Licht angegeben werden, bevor die Modelviewmatrix durch Objekte verschoben wird, aber nachdem die Kamera initialisiert wurde.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
  //..glRotatef, glTransaltef.. für die Kamera&lt;br /&gt;
  glLightfv(GL_LIGHT0, GL_POSITION, @position[0]);&lt;br /&gt;
  glPushMatrix;&lt;br /&gt;
    //..glRotatef, glTransaltef.. für die Objekte&lt;br /&gt;
    DrawObjekts;&lt;br /&gt;
  glPopMatrix;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Relatives Licht ===&lt;br /&gt;
&lt;br /&gt;
Wollen wir stattdessen unsere Lichtquelle relativ zu einem bestimmten Objekt bewegen, so müssen wir ein wenig anders vorgehen: Erst die Modelviewmatrix so bearbeiten, dass wir das Objekt zeichnen könnten, vor dem Zeichen selbst jedoch die Matrixfunktion für das Licht ausführen und die Lichtposition übergeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  //..glRotatef, glTransaltef, glMultMatrix, etc...&lt;br /&gt;
  glPushMatrix;&lt;br /&gt;
    glRotatef(Drehung, 0.0, 1.0, 0.0);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_POSITION, @position[0]);&lt;br /&gt;
  glPopMatrix;&lt;br /&gt;
  DrawObject;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lichtquellen, die an der Kamera kleben ===&lt;br /&gt;
&lt;br /&gt;
Wenn eine Lichtquelle immer relativ zum Betrachter sein soll(wenn also das Licht z. B. feste am Kopf montiert ist, wie bei einem Minenarbeiter), so langt es die Position des Lichts zu definieren, bevor die Modelviewmatrix mit der Kameraposition und Drehung bearbeitet wurde:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
  glLightfv(GL_LIGHT0, GL_POSITION, @position[0]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Spot an! ==&lt;br /&gt;
&lt;br /&gt;
Wer kennt sie nicht, die Spotlights? Im Fernsehen und Theater oft gebraucht, aber auch im realen Leben, z.B. bei Taschenlampen, Suchscheinwerfern (etwa noch keinen in der Hand gehabt? Ich schon :-) ), etc. oft zu sehen. Leider benötigt man nicht selten eine ganze Schar von ihnen, wozu sich die OpenGL Lichter nur schlecht eignen - aus der Patsche hilft da oft [[Blending]] oder andere Techniken. Wenn man mit entsprechenden Projektions-Techniken noch keine Erfahrungen hat, müssen die OpenGL-Lichter dann aber doch wieder herhalten.&lt;br /&gt;
&lt;br /&gt;
=== Parameter setzen ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_spotlight.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Schauen wir uns die Lichtparameter für Spotlights an: '''GL_SPOT_DIRECTION''' gibt die Richtung an, in die das Spotlicht zeigt. Diese lässt sich wieder mit Hilfe geschickter Platzierung im Code durch die Modelviewmatrix jagen um den gewünschten Effekt zu erzielen - wie immer eben. '''GL_SPOT_CUTOFF''' gibt den Winkel an, der zwischen Richtung und max. Auswurf besteht. Zuletzt gibt es noch den '''GL_SPOT_EXPONENT''', der beschreibt, wie stark die Lichtstärke nach außen hin abnimmt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
const&lt;br /&gt;
    light_position : Array[0..3] of GlFloat = (0.0, 10.0, 0.0, 1.0);&lt;br /&gt;
    light0_ambient  : Array[0..3] of GlFloat = (0.8, 0.0, 0.0, 1.0);&lt;br /&gt;
    light0_diffuse  : Array[0..3] of GlFloat = (0.8, 0.0, 0.0, 1.0);&lt;br /&gt;
  var&lt;br /&gt;
    LightDirection : Array[0..2] of GlFloat;&lt;br /&gt;
  begin&lt;br /&gt;
    LightDirection[0] := Sin(Position)/2;&lt;br /&gt;
    LightDirection[1] := -1.0;&lt;br /&gt;
    LightDirection[2] := 0.0;&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, @LightDirection[0]);&lt;br /&gt;
&lt;br /&gt;
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 10.0);&lt;br /&gt;
    glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 50.0);&lt;br /&gt;
&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_AMBIENT,  @light0_ambient[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  @light0_diffuse[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_POSITION, @light_position[0]);&lt;br /&gt;
    glEnable(GL_LIGHT0);&lt;br /&gt;
    glEnable(GL_LIGHTING);&lt;br /&gt;
    //...&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zur besseren Illustration ein Bild&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_spots_highres.gif|center]]&lt;br /&gt;
&lt;br /&gt;
== glLightModel? ==&lt;br /&gt;
&lt;br /&gt;
Bislang haben wir einen Befehl völlig außer Acht gelassen: '''[[glLightModel]]x'''. Er nimmt zwei Parameter: '''pname''' und '''param''':&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! Eigenschaft&lt;br /&gt;
! Standard Wert&lt;br /&gt;
! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| GL_LIGHT_MODEL_AMBIENT&lt;br /&gt;
| 0.2, 0.2, 0.2, 1.0&lt;br /&gt;
| Abientes RGBA Licht der gesamten Szene&lt;br /&gt;
|-&lt;br /&gt;
| GL_LIGHT_MODEL_LOCAL_VIEWER&lt;br /&gt;
| 0.0 oder GL_FALSE&lt;br /&gt;
|Lokaler oder unendlicher Viewport. Wirkt bei Specular Reflexionen:&lt;br /&gt;
;GL_FALSE: Die Richtung von Betrachter zu Vertex wird nur 1 mal berechnet und bleibt damit für alle Vertices konstant.&lt;br /&gt;
;GL_TRUE: Die Richtung Betrachter zu Vertex wird für jedes Vertex neu berechnet, was in einem realistischeren Anblick endet.&lt;br /&gt;
|-&lt;br /&gt;
| GL_LIGHT_MODEL_TWO_SIDE&lt;br /&gt;
| 0.0 oder GL_FALSE&lt;br /&gt;
| Einseitiges oder doppelseitiges Lighting&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Das Vertexproblem ==&lt;br /&gt;
&lt;br /&gt;
Die Benutzung von Licht muss bislang auf euch sehr einfach gewirkt haben. Aber der eine oder andere wird es vielleicht schon herausgelesen haben: OpenGL Licht wird per Vertex und nicht per Pixel berechnet. Das Problem dabei ist, dass sich mit der Auflösung des Objekts das Aussehen des Lichts stark ändern kann. Bei diffusem und ambientem Licht spielt das kaum eine Rolle. Specular und Spotlights reagieren empfindlich. Die schönen Rundungen, die diese Lichtarten häufig ausbilden, können  verschandelt werden. Die Ergebnisse sind nicht mehr wirklich rund, vielmehr eckig und kantig. Ihr glaubt mir nicht? Dann schaut nicht zu genau hin:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_spots_lowres.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Und was lernen wir draus? Schönes Licht braucht viele Vertices.&lt;br /&gt;
&lt;br /&gt;
== Normalen die 2. ==&lt;br /&gt;
&lt;br /&gt;
=== Länge = 1? ===&lt;br /&gt;
&lt;br /&gt;
Kommen wir also nun wie versprochen noch einmal zu den Normalen zurück. Normalen, die mit [[glNormal|glNormalx]] angegeben werden, werden, abgesehen von Verschiebungen, wie Vertices mit der Modelview Matrix multipliziert. Normalen sollten für korrekte Lichtberechnung normiert sein, dass heißt die Länge 1 haben (ist sie länger, so erscheint das Objekt heller, ist sie kürzer, so wird das Objekt dunkler). Ist mit der Multiplikation mit der Modelviewmatrix auch eine Skalierung verbunden, so haben wir ein Problem, denn die Länge ist nicht mehr 1. Um das zu beheben, kann vermittels '''[[glEnable]](GL_NORMALIZE)''' OpenGL angewiesen werden, die Normalen selbst auf Länge eins zu skalieren. Aber Achtung: Das kostet Rechenleistung. Allerdings kostet selber berechnen vermutlich noch mehr.&lt;br /&gt;
&lt;br /&gt;
=== Einfache Normalen ===&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Berechnung von Normalen ganz einfach. So bei Kugeln. Die Richtung die der Mittelpunkt zu irgendeinem Vertex auf der Oberfläche beschreibt, ist gleich der Richtung der Normalen - sie muss nur noch normiert werden. Bei Flächen auf den Achsen muss unsereins auch nicht groß nachdenken, wie denn die passende Normale auszusehen hat. Aber wie ist es, wenn unser betrachteter Körper keine so einfache Oberfläche hat? Was dann?&lt;br /&gt;
&lt;br /&gt;
=== Normalenberechnung per Dreieck ===&lt;br /&gt;
&lt;br /&gt;
Will man anhand von Dreiecksdaten Normalen erzeugen, so muss man mal wieder zur Mathematik rüberschauen - die haben das ideale Werkzeug dafür: Das [[Vektorprodukt|Vektor-Kreuzprodukt]]. Um die Normale der Fläche beschrieben durch die 3 Ecken V&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;, V&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;, V&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt; zu bekommen, braucht man nur zu rechnen:&lt;br /&gt;
&lt;br /&gt;
N = (V&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; - V&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;)x(V&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; - V&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Wenn wir das für jedes Polygon durchziehen, dann können wir für jeweils 3 Vertices die Normale angeben. Das schaut ein bisschen eckig aus, bringt uns unserem Ziel aber gewaltig näher. Erinnert irgendwie an die ersten Spiele, die mit Licht arbeiteten... Flatshading war schon was schönes, aber OpenGL kann mehr, wie wir bereits an den Kugeln gesehen haben.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_normalen_flat.gif|center]]&lt;br /&gt;
&lt;br /&gt;
'''Und nicht vergessen:''' Die Normalen sollten noch auf die Länge 1 gebracht werden, siehe [[Normale]].&lt;br /&gt;
&lt;br /&gt;
=== Normalen glätten ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_normalen_smooth.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Um die Polygone nun ein wenig unsichtbarer zu machen, gibt es ein einfaches Hilfsmittel: Man nehme die direkt anliegenden Flächennormalen um ein Vertex, bilde den Durchschnitt und voilà: Unser Objekt schaut schon runder aus. An einigen Stellen sollte man damit aber vorsichtig walten: Geht es einmal wirklich scharf um eine spitze Kante, so schaut diese Abrundung vermutlich etwas seltsam und abnormal aus. Also: Nicht einfach drauflos abrunden. Da bei komplexeren Objekten jeder vermutlich sowieso einen 3D Modeller verwendet, bei dem man das etwas feinfühlig kontrollieren kann, sollte das kein größeres Problem sein - jeder der seinen eigenen Modeller schreibt, muss sich natürlich etwas einfallen lassen - nützlich erweist sich hier das [[Standard_Skalarprodukt|Skalarprodukt]], da man damit den Winkel zwischen zwei Normalen bestimmen kann. Ist der Winkel zu groß, kann es sich nicht um eine Rundung handeln und wir haben es mit einer Kante zu tun - zumindest solange unsere Polygondaten halbwegs fein aufgelöst sind.&lt;br /&gt;
&lt;br /&gt;
== Das etwas andere Licht ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_RoteRinge.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Mit OpenGLs Standardmethode einen Beleuchtungseffekt zu erzielen, ist natürlich nicht der Weisheit letzter Schluss. Ein anderer Trick drängt sich bei entsprechendem Wissen über die Möglichkeiten geradezu auf: Environment Mapping, oder im folgendem speziell Sphere Mapping. Den entstehenden Effekt kann man mit einer perfekten Spiegelung vergleichen. Das einzige was wir tun müssen, ist OpenGL anzuweisen, die Texturkoordinaten selbst zu berechnen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);&lt;br /&gt;
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);&lt;br /&gt;
    glEnable(GL_TEXTURE_GEN_S);&lt;br /&gt;
    glEnable(GL_TEXTURE_GEN_T);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das wars schon, wir benötigen nur noch eine Sphere Map:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_lightmap.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wenn man das ganze nun noch mit [[Multitexturing]] verknüpft, so kann man eine Texturlage für die normale Textur verwenden und die 2. für das Licht. Eine rote Spheremap erzeugt aber rotes Licht, gell... Happy Coding ;-)&lt;br /&gt;
&lt;br /&gt;
== Licht aus ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glDisable(GL_LIGHTING)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und wieder ist eines meiner Tutorials am Ende. Wenn ich mich nicht irre, ist's die Nummer 11. Wer gibt mir den verdienten Schnaps aus? Na? Keine Freiwilligen? Schade :-( . In jedem Fall hast Du es jetzt erst einmal hinter Dir und kannst Dich ganz entspannt zurücklehnen - oder, was mir besser gefallen würde: Ein paar OpenGL-Programme mit Lichtunterstützung schreiben und uns das Ergebnis als IOTW oder als solches einsenden. Ersatzweise tut's auch etwas freundliches Feedback - das lasst ihr nämlich allesamt immer sehr missen, was das Team zurecht schade findet. Also lasst uns nicht hängen, sondern gebt von euch, was euch an den Tutorials gefällt und was nicht.&lt;br /&gt;
&lt;br /&gt;
und jetzt:&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
'''[[Benutzer:Delphic|Delphic]]&lt;br /&gt;
&amp;amp; Co-Autor [[Benutzer:Traude|Traude]]'''&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 7]] | [[Tutorial 2D]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lektion8]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glPixelMap&amp;diff=25656</id>
		<title>glPixelMap</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glPixelMap&amp;diff=25656"/>
				<updated>2012-03-21T14:58:18Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausser -&amp;gt; Außer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glPixelMap =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glPixelMap''' - stellt eine Pixeltransferkarte (pixel transfer map) ein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glPixelMapfv'''(''map'': TGLenum; ''mapsize'': TGLsizei; const ''values'': PGLfloat);&lt;br /&gt;
 procedure '''glPixelMapuiv'''(''map'': TGLenum; ''mapsize'': TGLsizei; const ''values'': PGLuint);&lt;br /&gt;
 procedure '''glPixelMapusv'''(''map'': TGLenum; ''mapsize'': TGLsizei;&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;''map''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;Bestimmt den symbolischen Kartennamen. Muss einer der folgenden sein:&amp;lt;br&amp;gt;&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_I, GL_PIXEL_MAP_S_TO_S, GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G, GL_PIXEL_MAP_I_TO_B, GL_PIXEL_MAP_I_TO_A, GL_PIXEL_MAP_R_TO_R, GL_PIXEL_MAP_G_TO_G, GL_PIXEL_MAP_B_TO_B,''' oder '''GL_PIXEL_MAP_A_TO_A'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''mapsize''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;Bestimmt die Größe der ausgewählten Karte.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''values''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;Ist ein Feld mit ''mapsize'' Werten.&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;
'''glPixelMap''' erstellt Übersetzungstabellen oder Karten die von [[glDrawPixels]], [[glReadPixels]], [[glCopyPixels]], [[glTexImage1D]], und [[glTexImage2D]] benutzt werden.&lt;br /&gt;
Die Nutzung dieser Karten wird ausführlich im Artikel [[glTexImage2D]] besprochen. In Auszügen finden Sie auch in den Artikeln zu den Pixel und Textur Befehlen weitere Informationen.&lt;br /&gt;
'''In diesem Artikel wird nur die Erstellung der Karten besprochen.'''&lt;br /&gt;
&lt;br /&gt;
''map'' ist ein symbolischer Kartenname der eine der 10 Karten für die Bearbeitung auswählt.&lt;br /&gt;
''mapsize'' bestimmt die Anzahl der Einträge in die Karte. &lt;br /&gt;
''values'' ist ein Zeiger auf ein Feld mit ''mapsize'' Kartenwerten.&lt;br /&gt;
&lt;br /&gt;
Die folgenden 10 Karten existieren.&lt;br /&gt;
&lt;br /&gt;
=== MAPS ===&lt;br /&gt;
[[glPixelMap_Beispiele|Beispiele für die Übertragungen.]]&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_I'''&lt;br /&gt;
: Überträgt Farbindices auf Farbindices.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_S_TO_S''' &lt;br /&gt;
: Überträgt Schablonenindices auf Schablonenindices.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_R'''&lt;br /&gt;
: Überträgt Farbindices auf Rotkomponenten.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_G'''&lt;br /&gt;
: Überträgt Farbindices auf Grünkomponenten.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_B'''&lt;br /&gt;
: Überträgt Farbindices auf Blaukomponenten.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_A'''&lt;br /&gt;
: Überträgt Farbindices auf Alphakomponenten.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_R_TO_R'''&lt;br /&gt;
: Überträgt Rotkomponenten auf Rotkomponenten.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_G_TO_G'''&lt;br /&gt;
: Überträgt Grünkomponenten auf Grünkomponenten.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_B_TO_B'''&lt;br /&gt;
: Überträgt Blaukomponenten auf Blaukomponenten.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_A_TO_A'''&lt;br /&gt;
: Überträgt Alphakomponenten auf Alphakomponenten.&lt;br /&gt;
&lt;br /&gt;
Die Einträge einer Map können als einfach genaue Floats (Delphi: single), unsigned short ints (Delphi: Byte) oder unsigned long ints (Delphi: Cardinal) festgelegt werden. Maps die Farbkomponentenwerte speichern (alle außer '''GL_PIXEL_MAP_I_TO_I''' und '''GL_PIXEL_MAP_S_TO_S'''), bewahren ihre Werte im Fließkommaformat, mit nicht definierter Mantissen- und Exponentengröße. Von '''glPixelMapfv''' festgelegte Fließkommawerte werden direkt in das interne Fließkommaformat dieser Maps konvertiert und dann auf den Intervall [0..1] begrenzt. Unsigned Int-Werte die von '''glPixelMapusv''' oder '''glPixelMapuiv''' festgelegt wurden, werden linear konvertiert so dass die größte abbildbare Integer auf 1.0 gemappt wird und 0 auf 0.0.&lt;br /&gt;
&lt;br /&gt;
Maps die Indices speichern, '''GL_PIXEL_MAP_I_TO_I''' and '''GL_PIXEL_MAP_S_TO_S''', halten ihre Werte im Festkommaformat mit einer unbestimmten Anzahl von Bits rechts vom binären Punkt ''(d.h. die Stellen vor dem Komma sind immer definiert, hinter dem Komma kann die Anzahl der Ziffern aber unterschiedlich sein)''. Fließkommawerte, die von '''glPixelMapusv''' und '''glPixelMapuiv''' gesetzt wurden, bestimmen ganze Integerwerte (alle Ziffern rechts vom binären Punkt sind 0).&lt;br /&gt;
&lt;br /&gt;
Die nachfolgenden Tabellen zeigen die '''Initialisierungszustände''' der einzelnen '''Karten'''.&lt;br /&gt;
Karten die über Farb- oder Schablonenindices indiziert werden, müssen ''mapsize''=2^n (für beliebige n) sein. Ansonsten sind die Ergebnisse undefiniert.&lt;br /&gt;
Die maximale erlaubte Größe für die einzelnen Karten ist implementationsabhängig und kann mit [[glGet]] und dem Argument '''GL_MAX_PIXEL_MAP_TABLE''' bestimmt werden.&lt;br /&gt;
&lt;br /&gt;
Das einzelne Maximum wird auf alle Maps angewendet und beträgt mindestens 32.&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_I'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || Farbindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || Farbindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_S_TO_S'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || Schablonenindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || Schablonenindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_R'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || Farbindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || R&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_G'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || Farbindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || G &lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_B'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || Farbindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || B&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_I_TO_A'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || Farbindex&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || A&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_R_TO_R'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || R&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || R&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_G_TO_G'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || G&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || G&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_B_TO_B'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || B&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || B&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''GL_PIXEL_MAP_A_TO_A'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! '''Lookup Index''' || A&lt;br /&gt;
|-&lt;br /&gt;
! '''Lookup Value''' || A&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungsgröße''' || 1&lt;br /&gt;
|-&lt;br /&gt;
! '''Initialisierungswert''' || 0.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_INVALID_ENUM''' wird generiert wenn ''map'' ein ungültiger Wert übergeben wird. &amp;lt;br&amp;gt;&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert wenn ''mapsize'' negativ oder größer als '''GL_MAX_PIXEL_MAP_TABLE''' ist. &amp;lt;br&amp;gt;&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert wenn ''map'' gleich einem der Werte&lt;br /&gt;
: '''GL_PIXEL_MAP_I_TO_I, GL_PIXEL_MAP_S_TO_S, GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G, GL_PIXEL_MAP_I_TO_B,''' oder '''GL_PIXEL_MAP_I_TO_A,''' ist '''und''' ''mapsize'' keine Power of two größe hat. (''mapsize'' muss = 2^n sein.) &amp;lt;br&amp;gt;&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn '''glPixelMap''' innerhalb eines [[glBegin]]-[[glEnd]] Blocks aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Zugehörige Wertrückgaben ==&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_I_TO_I_SIZE|GL_PIXEL_MAP_I_TO_I_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_S_TO_S_SIZE|GL_PIXEL_MAP_S_TO_S_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_I_TO_R_SIZE|GL_PIXEL_MAP_I_TO_R_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_I_TO_G_SIZE|GL_PIXEL_MAP_I_TO_G_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_I_TO_B_SIZE|GL_PIXEL_MAP_I_TO_B_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_I_TO_A_SIZE|GL_PIXEL_MAP_I_TO_A_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_R_TO_R_SIZE|GL_PIXEL_MAP_R_TO_R_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_G_TO_G_SIZE|GL_PIXEL_MAP_G_TO_G_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_B_TO_B_SIZE|GL_PIXEL_MAP_B_TO_B_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_PIXEL_MAP_A_TO_A_SIZE|GL_PIXEL_MAP_A_TO_A_SIZE]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[glGet]] mit Token [[glGet#GL_MAX_PIXEL_MAP_TABLE|GL_MAX_PIXEL_MAP_TABLE]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glCopyPixels]], [[glDrawPixels]], [[glPixelStore]], [[glPixelTransfer]], [[glReadPixels]], [[glTexImage1D]], [[glTexImage2D]] &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|PixelMap]]&lt;br /&gt;
 [[Kategorie:GL1.0]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glUseProgram&amp;diff=25655</id>
		<title>glUseProgram</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glUseProgram&amp;diff=25655"/>
				<updated>2012-03-21T14:57:59Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausser -&amp;gt; Außer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glUseProgram (glUseProgramObjectARB) =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glUseProgram''' - Aktiviert Shader und ersetzt die passenden Teile der festen Funktionspipeline durch diese.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glUseProgram'''(''programObj'' : GLuint);&lt;br /&gt;
 procedure '''glUseProgramObjectARB'''(''programObj'' : GLHandleARB);&lt;br /&gt;
&lt;br /&gt;
&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;
! ''programObj''&lt;br /&gt;
| Handle des Programmobjektes, dessen kompilierte und gelinkte Shader als Ersatz für die feste Funktionspipeline genutzt werden sollen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
'''glUseProgram''' installiert den Satz der im Programm gebundenen Shader als Teil der aktuellen Renderpipeline. Ein Satz ausführbarer Shader wird in einem Programm erstellt, indem man diese mittels [[glAttachShader]] an das Programmobjekt bindet, diese erfolgreich mit [[glCompileShader]] kompiliert und danach mit [[glLinkProgram]] in das Programmobjekt linkt.&lt;br /&gt;
&lt;br /&gt;
Ein Programmobjekt behinhaltet dann einen ausführbaren Shader der auf dem programmierbaren Vertexprozessor läuft, sobald man ein oder  mehrere Shaderobjekte vom Typ ''GL_VERTEX_SHADER'' erfolgreich kompiliert und gelinkt hat. Entsprechend beinhaltet ein Programmobjekt einen ausführbaren Shader der auf dem programmierbaren Fragmentprozessor läuft, wenn ein oder meherer Shaderobjekte vom Typ ''GL_FRAGMENT_SHADER'' erfolgreich kompiliert und gelinkt wurden.&lt;br /&gt;
&lt;br /&gt;
Das erfolgreiche Installieren eines ausführbaren Shaderprogrammes auf einem programmierbaren Prozessor sorgt dafür, dass die entsprechende feste Funktionspipeline der OpenGL deaktiviert ist. Wenn ein Vertexshader erfolgreich installiert wurde, dann werden folgende Bereiche der festen GL-Funktionspipeline deaktiviert :&lt;br /&gt;
&lt;br /&gt;
*Die Modelansichtsmatrix wird nicht auf Vertexkoordinaten angewandt.&lt;br /&gt;
*Die Projektionsmatrix wird nicht auf Vertexkoordinaten angewandt.&lt;br /&gt;
*Die Texturenmatrix wird nicht auf Texturkoordinaten angewandt.&lt;br /&gt;
*Normale werden nicht in Betrachtungskoordinaten(Eye-Space) transformiert.&lt;br /&gt;
*Normale werden nicht normalisiert bzw. reskaliert.&lt;br /&gt;
*Normalisierung von evaluierten Normalen bei Nutzung von GL_AUTO_NORMAL wird nicht ausgeführt.&lt;br /&gt;
*Texturkoordinaten werden nicht automatisch generiert.&lt;br /&gt;
*Es wird keine per-Vertex Beleuchtung durchgeführt.&lt;br /&gt;
*Farbmaterial-Berechnungen werden nicht durchgeführt.&lt;br /&gt;
*Farbindex-Beleuchtung wird nicht durchgeführt.&lt;br /&gt;
*Primäre und sekundäre Farbwerte werden nicht geclampt. (Deutsche Übersetzung für den Begriff klingt leider zu entfernt --[[Benutzer:Sascha Willems|Sascha Willems]] 12:38, 12. Jul 2004 (CEST))&lt;br /&gt;
*Die obere Liste gilt auch beim Setzen der Rasterposition.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der installierte Vertexshader muss daher jegliche aus obiger Liste benötigte Funktionalität selbst implementieren. Entsprechend werden folgende Teile der festen GL-Funktionspipeline deaktiviert, wenn ein Fragmentshader erfolgreich installiert wurde:&lt;br /&gt;
*Texturumgebung und Texturfunktionen werden nicht angewandt.&lt;br /&gt;
*Textur-Vergleichsmodi werden nicht angewandt.&lt;br /&gt;
*Texturanwendung wird nicht berücksichtigt, außer der Tatsache dass Textureinheiten aktiviert bzw. deaktiviert werden.&lt;br /&gt;
*Farbsumme wird nicht berechnet.&lt;br /&gt;
*Nebel wird nicht berechnet.&lt;br /&gt;
&lt;br /&gt;
Genau wie beim Vertexshader muss auch hier in einem Fragmentshader jegliche Funktionalität, die aus obiger Liste benötigt wird, selbst implementiert werden.&lt;br /&gt;
&lt;br /&gt;
Während ein Programmobjekt aktiv ist, kann eine Anwendung die angehangenen Shaderobjekte verändern, angehangene Shaderobjekte kompilieren, zusätzliche Shaderobjekte anhängen und Shaderobjekte wieder entfernen. Keine dieser Operationen wird den Satz der ausführbaren Shader beeinflussen, die bereits Teil des aktuellen Status sind. Das Neulinken eines Programmobjektes dass in Benutzung ist, führt jedoch dazu dass die neu angehangenen Shader als Teil der Renderpipeline installiert werden, sofern der Linkvorgang erfolgreich war.&lt;br /&gt;
&lt;br /&gt;
Wenn ein Programmobjekt Shader vom Typ ''GL_VERTEX_SHADER'' beinhaltet, aber keine Shaderobjekte vom Typ ''GL_FRAGMENT_SHADER'', dann wird der Vertexshader installiert und für die Fragmentberechnungen die feste GL-Funktionspipeline genutzt. Genau umgekehrt verhält es sich wenn zwar ein Shader vom Typ ''GL_FRAGMENT_SHADER'' vorhanden ist, aber keiner vom Typ ''GL_VERTEX_SHADER''. In diesem Falle wir der Fragmentshader installiert und für die Vertexberechnungen wird die feste Funktionspipeline genutzt. Wenn ein Programm mit der ID 0 gebunden wird, wird sowohl für Vertex- als auch Fragmentberechnungen die feste Funktionspipeline genutzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
Änderungen die an einem Programmobjekt in einem Renderkontext getätigt werden, müssen nicht auch unbedingt Änderungen in einem anderen Renderkontext (der dieses Programmobjekt auch nutzt) hervorrufen, solange dort nicht explizit '''glUseProgram''' aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_INVALID_VALUE''' wenn ''programObj'' weder 0 noch einem gültigen Objekthandle entspricht.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn ''programObj'' nicht vom Typ ''GL_PROGRAM_OBJECT'' ist.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn das Programm nicht installiert werden konnte.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn '''glUseProgram''' zwischen einem [[glBegin]] und dem zugehörigen [[glEnd]] 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 dem Argument ''programObj''.&lt;br /&gt;
&lt;br /&gt;
[[glGetAttachedShaders]] mit dem Argument ''programObj''.&lt;br /&gt;
&lt;br /&gt;
[[glGetActiveAttrib]] mit dem Argument ''programObj''.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glAttachShader]], [[glCompileShader]], [[glDetachShader]], [[glLinkProgram]], [[glValidateProgram]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Hintergrundwissen''' : [[Shader]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[http://developer.3dlabs.com/openGL2/slapi/UseProgramObjectARB.htm Englische Originalversion]  (Copyright 3DLabs Inc.)&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|UseProgramObjectARB]]&lt;br /&gt;
[[Kategorie:SHADER_OBJECTS|UseProgramObject]]&lt;br /&gt;
[[Kategorie:GL3]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glGetCompressedTexImage&amp;diff=25654</id>
		<title>glGetCompressedTexImage</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glGetCompressedTexImage&amp;diff=25654"/>
				<updated>2012-03-21T14:57:33Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glGetCompressedTexImage =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glGetCompressedTexImage''' - liefert ein komprimiertes Texturbild zurück.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glGetCompressedTexImage'''(''target'': TGLenum; ''level'': TGLint;&lt;br /&gt;
                                   ''img'': PGLvoid);&lt;br /&gt;
&lt;br /&gt;
&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;
! ''target''&lt;br /&gt;
| Gibt die Zieltextur an, welche zurückgeliefert werden soll. '''GL_TEXTURE_1D''', '''GL_TEXTURE_2D''' und '''GL_TEXTURE_3D''' werden akzeptiert.&amp;lt;br&amp;gt;&lt;br /&gt;
Für [[Cubemap|Cubemaps]] sind außerdem die symbolischen Konstanten '''GL_TEXTURE_CUBE_MAP_POSITIVE_X''', '''GL_TEXTURE_CUBE_MAP_NEGATIVE_X''', '''GL_TEXTURE_CUBE_MAP_POSITIVE_Y''', '''GL_TEXTURE_CUBE_MAP_NEGATIVE_Y''', '''GL_TEXTURE_CUBE_MAP_POSITIVE_Z''' und '''GL_TEXTURE_CUBE_MAP_NEGATIVE_Z''' erlaubt. &lt;br /&gt;
|-&lt;br /&gt;
! ''level''&lt;br /&gt;
| Gibt den Detailgrad für das gewünschte Bild an. &amp;lt;br&amp;gt;&lt;br /&gt;
Level 0 ist das Basisbild. Level n ist die n-te Mipmap-Reduzierung des Bildes.&lt;br /&gt;
|-&lt;br /&gt;
! ''img''&lt;br /&gt;
| Zeiger auf Speicher, in den die komprimierten Texturdaten geladen werden sollen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
'''glGetCompressedTexImage''' liefert das aktuelle Texturbild über ''img'' zurück. &lt;br /&gt;
Wenn Texturobjekte verwendet werden, so ist es diejenige Textur, welche zuletzt mit [[glBindTexture]] aktiviert wurde.&lt;br /&gt;
&lt;br /&gt;
''target'' bestimmt, ob die gewünschte Textur via [[glCompressedTexImage1D]]('''GL_TEXTURE_1D'''), [[glCompressedTexImage2D]] ('''GL_TEXTURE_2D''', oder [[glCompressedTexImage3D]]('''GL_TEXTURE_3D''') erstellt wurde. &lt;br /&gt;
Zusätzlich ist es möglich [[Cubemap]]-Texturen, die mit [[glCompressedTexImage2D]]('''GL_CUBE_MAP_*''') geladen wurden, zurückzuholen.&lt;br /&gt;
&lt;br /&gt;
''level'' gibt den Detailsgrad (LOD - Level of Detail) für das gewünschte Bild an. Das Format der zurückgelieferten Textur entspricht dem komprimierten Format, das an die Textur beim Laden angegeben wurde. Es kann mit [[glGetTexLevelParameter|glGetTexLevelParameteriv]] und dem Parameter '''GL_TEXTURE_INTERNAL_FORMAT''' abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Um genügend Speicher für das Feld (''img'') zu allokieren, kann mit der Funktion [[glGetTexLevelParameter]] und dem Parameter '''GL_TEXTURE_COMPRESSED_IMAGE_SIZE''' die benötigte Byteanzahl bestimmt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
'''glGetCompressedTexImage''' ist erst ab OpenGL Version 1.3 oder höher nutzbar.&lt;br /&gt;
&lt;br /&gt;
Die Befehle [[glPixelTransfer]] und [[glPixelStore]] werden beim Aufruf von '''glGetCompressedTexImage''' komplett ignoriert.&lt;br /&gt;
&lt;br /&gt;
Wenn während der Ausführung der Funktion ein Fehler ausgelöst wird, werden keine Veränderungen am Inhalt von ''img'' durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_INVALID_ENUM''' wird generiert, wenn ''target'' ein ungültiger Wert übergeben wurde.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''level'' kleiner 0 oder größer ld(max) ist, wobei max der Rückgabewert von '''GL_MAX_TEXTURE_SIZE''' ist (ld = Logarithmus Dualis = Basis 2).&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn '''glGetCompressedTexImage''' innerhalb eines [[glBegin]]-[[glEnd]]-Blocks aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn das interne Format der Textur kein Komprimierungsformat war.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Zugehörige Wertrückgaben ==&lt;br /&gt;
[[glGetTexLevelParameter]] mit Token '''GL_TEXTURE_COMPRESSED_IMAGE_SIZE'''&lt;br /&gt;
&lt;br /&gt;
[[glGetTexLevelParameter]] mit Token '''GL_TEXTURE_INTERNAL_FORMAT'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glCompressedTexImage1D]], [[glCompressedTexImage2D]], [[glCompressedTexImage3D]], [[glCompressedTexSubImage1D]], [[glCompressedTexSubImage2D]], [[glCompressedTexSubImage3D]], [[glGetTexImage]], [[glGetTexLevelParameter]], [[glTexParameter]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|GetCompressedTexImage]]&lt;br /&gt;
[[Kategorie:GL1.3|GetCompressedTexImage]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=shader_texturing(ARB)&amp;diff=25653</id>
		<title>shader texturing(ARB)</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=shader_texturing(ARB)&amp;diff=25653"/>
				<updated>2012-03-21T14:57:16Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Texturing=&lt;br /&gt;
Zurück zur [[Shadersammlung]]&lt;br /&gt;
{|{{Prettytable_B1}} width=100%&lt;br /&gt;
!width=60%|Beschreibung&lt;br /&gt;
!width=20%|Autor&lt;br /&gt;
!width=20%|Version&lt;br /&gt;
|-&lt;br /&gt;
|Einfache Texturierung eines Quads.&lt;br /&gt;
|dj3hut1&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Bilder==&lt;br /&gt;
{|&lt;br /&gt;
|[[Bild:Texarb_notex.png|framed|Quad ohne Textur.]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Texarb_textured.png|framed|Quad mit Textur.]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Beschreibung==&lt;br /&gt;
Dieser Shader texturiert ein Quad.&lt;br /&gt;
&lt;br /&gt;
==Besondere Vorraussetzungen==&lt;br /&gt;
Für die Shader werden nur die Erweiterungen [[GL_ARB_fragment_program]] und [[GL_ARB_vertex_program]] benötigt.&lt;br /&gt;
&lt;br /&gt;
Es muss ein Texturbild geladen und [[glBindTexture | gebunden]] werden. Außerdem sollte man pro Vertex eine gültige [[glTexCoord | Texturkoordinate ]] erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Vertexprogramm&lt;br /&gt;
=== texarb.vp ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;!!ARBvp1.0&lt;br /&gt;
&lt;br /&gt;
ATTRIB iPos = vertex.position;&lt;br /&gt;
&lt;br /&gt;
OUTPUT oPos = result.position;&lt;br /&gt;
&lt;br /&gt;
PARAM mvp[4] = { state.matrix.mvp };&lt;br /&gt;
&lt;br /&gt;
#transform vertex with mvp&lt;br /&gt;
DP4 oPos.x, iPos, mvp[0];&lt;br /&gt;
DP4 oPos.y, iPos, mvp[1];&lt;br /&gt;
DP4 oPos.z, iPos, mvp[2];&lt;br /&gt;
DP4 oPos.w, iPos, mvp[3];&lt;br /&gt;
&lt;br /&gt;
#set texcoord for fragment program&lt;br /&gt;
MOV result.texcoord[0], vertex.texcoord[0];&lt;br /&gt;
&lt;br /&gt;
END&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fragmentprogramm&lt;br /&gt;
=== texarb.fp ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;!!ARBfp1.0&lt;br /&gt;
&lt;br /&gt;
#lookup texture&lt;br /&gt;
TEX result.color, fragment.texcoord[0], texture[0], 2D;&lt;br /&gt;
&lt;br /&gt;
END&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_2D&amp;diff=25652</id>
		<title>Tutorial 2D</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_2D&amp;diff=25652"/>
				<updated>2012-03-21T14:56:59Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=2D mit OpenGL - &amp;quot;Nicht jeder benötigt 3 Dimensionen&amp;quot;=&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
&lt;br /&gt;
Bei der Erwähnung einer API wie OpenGL denken die meisten eigentlich eher an 3D, und sind der festen (aber sehr wohl falschen) Überzeugung eine solche API sei für reine 2D-Anwendung überdimensioniert oder gar ungeeignet. Das dies nicht der Fall ist möchte ich mit diesem (vor allem an Einsteiger gerichtet, denn die Könner wissen wohl was man mit der GL so alles machen kann) Tutorial zeigen und auch gleich mit mehreren praktischen Beispielen aufweisen das 2D mit OpenGL nicht nur möglich ist, sondern auch noch sehr viel einfacher (selbst mit der GDI ist 2D komplizierter) ist und dabei jede Menge Vorteile mit sich bringt.&lt;br /&gt;
&lt;br /&gt;
==Welche Vorteile bringt mir die GL für eine 2D-Anwendung?==&lt;br /&gt;
&lt;br /&gt;
Dies ist wohl das wichtigste Kapitel und sollte zugleich auch mit diversen Vorurteilen und Missverständnissen aufräumen. Denn gerade der 3D-Bereich ist es in dem seit Jahren fast monatlich neue Techniken entworfen werden und der dafür sorgt das v.&amp;amp;nbsp;a. Grafikkarten immer leistungsstärker werden, während der 2D-Bereich seit seligen VLB-Zeiten (= Vesa-Local-Bus, alte Haudegen kennen diese Grafikkartengeneration sicherlich noch) keine Innovationen mehr erlebt hat (und warum auch? Im 2D-Bereich reicht ein gutes Bild zusammen mit passabler Darstellungsgeschwindigkeit).&lt;br /&gt;
&lt;br /&gt;
Deshalb gibt es jetzt gleich mal die wichtigsten Punkte warum man denn gerade OpenGL (D3D würde hier auch zählen, aber das haben wir GL'ler ja nicht so gerne) für die 2D-Darstellung nutzen sollte:&lt;br /&gt;
&lt;br /&gt;
*'''Hardwarebeschleunigung'''&lt;br /&gt;
:Moderne Grafikkarten können inzwischen über 200 Millionen Dreiecke pro Sekunde rendern und besitzen brachiale Füllraten jenseits der 2.000 M(Texel/Pixel)/s. Das bedeutet also das man selbst auf älteren Grafikkarten sehr komplexe 2D-Szenen mit Geschwindigkeiten jenseits der 100 FpS (= Frames per Seconds ~ Bilder pro Sekunde) darstellen kann, während man mit der GDI schon bei einfachen 2D-Grafiken Geschwindigkeitsprobleme bekommen würde.&lt;br /&gt;
&lt;br /&gt;
*'''&amp;quot;Kostenlose&amp;quot; Objektsortierung'''&lt;br /&gt;
:Eine 3D-API braucht einen Tiefenpuffer um zu erkennen ob Fragmente verdeckt sind oder nicht und damit Overdraw zu vermeiden. Eine 2D-Anwendung kann diesen Tiefenpuffer aber auch nutzen, nämlich um Objekte zu sortieren. Man nutzt dann die Z-Koordinate der Objekte (= Tiefenkoordinate) quasi als Layer um zu kennzeichnen welches Objekt auf welcher &amp;quot;Höhe&amp;quot; liegt. Wenn man also z.&amp;amp;nbsp;B. einen 2D-Topdown-Shooter entwickelt bei dem der Spieler mit seinem Flugzeug über den Boden fliegt, dann nutzt man den Z-Puffer um die API (die das dann der Hardware überlässt) seine Objekte sortieren zu lassen. Das Flugzeug bekommt dann einen niedrigen Z-Wert (=oben) und Objekte auf dem Boden einen hohen Tiefenwert (=unten/hinten). Die Sortierung übernimmt dann die Grafikkarte und wir müssen uns darum keine Gedanken machen. Würden wir die Anwendung z.&amp;amp;nbsp;B. über die GDI realisieren, müssten wir diese Objekte selbst entsprechend ihrer Höhe sortieren.&lt;br /&gt;
&lt;br /&gt;
*'''Jede Menge hardwarebeschleunigte Spezialeffekt'''&lt;br /&gt;
:Wie schon oben erwähnt haben im 3D-Bereich innerhalb der letzten Jahre sehr viele Innovationen stattgefunden. Warum sollte man diese also nicht auch für seine 2D-Anwendung nutzen? Klingt logisch und macht auch Sinn! So bietet OpenGL alle Arten von Effekten die auch in einer 2D-Anwendung nützlich sein können. Darunter solche Sachen wie den Alphatest (der dafür sorgt das maskierte Teile eines Objektes transparent sind), Blending und natürlich (auch wenn das jetzt für erfahrene GL'ler sehr trivial klingt) hardwarebeschleunigte Rotation und Skalierung; was zur Folge hat das man seine Objekte nicht für verschiedene Auflösungen in verschiedenen Größen erstellen muss. Für Fortgeschrittene gibt es dann natürlich noch solche Sachen wie Shader, mit denen man Teile der OpenGL-Pipeline durch eigene (kleine) Programme ersetzen kann (entweder in Assemblerform oder aber in der neuen GL-HLSL). Dadurch bietet sich dann ein quasi unendlich großes Spektrum an möglichen Effekten, und das wohlgemerkt alles hardwarebeschleunigt!&lt;br /&gt;
&lt;br /&gt;
*'''Plattformübergreifend'''&lt;br /&gt;
:Auch ein großer Vorteil von OpenGL. Die Tatsache das die GL unter diversen Betriebssystemen verfügbar ist (im Gegensatz zu GDI oder gar DirectX) macht die eigenen Programme recht portabel (einschränkend ist hier halt nur die Verfügbarkeit der genutzten Programmiersprache auf dem passenden OS). Unterstützt werden alle größeren Betriebssysteme wie Windows, Linux, MacOS und Solaris.&lt;br /&gt;
&lt;br /&gt;
:Ganz nebenbei wurde vor kurzem mit [http://www.khronos.org/opengles/2_X/ OpenGL ES] ein mobiler Standard für OpenGL geschaffen, wodurch es dann auch möglich ist auf mobilen Geräten (Handys, PDAs, Handhelds) OpenGL zu nutzen. Und gerade dort sind 2D-Spiele (aufgrund der oft mangelnden Leistung der Geräte) ja noch stark verbreitet.&lt;br /&gt;
&lt;br /&gt;
So viel also zu den wichtigsten Vorteilen zur OpenGL unter 2D. Natürlich gibt es noch weiter Dinge die OpenGL für 2D-Anwendungen attraktiv machen, aber allein die oben genannten Gründe sollten jedermann überzeugt haben. Und alle die wirklich mal wissen wollen wie gut OpenGL denn für solche Anwendungen geeignet ist, sollten sich unbedingt eine neuere Version des MacOS ansehen, denn das benutzt OpenGL zur Darstellung seiner GUI.&lt;br /&gt;
&lt;br /&gt;
==Und welche Nachteile gibt es?==&lt;br /&gt;
&lt;br /&gt;
Nichts was der Mensch bisher erfunden hat (mal abgesehen von der Spaltung des Atoms ;) ) hat nur Vorteile. Genauso sieht es auch aus wenn man die OpenGL für seine 2D-Anwendung nutzen will. Welche genau das sind will ich hier grob auflisten.&lt;br /&gt;
&lt;br /&gt;
*'''Ohne 3D-Beschleuniger mit passenden Treibern geht nichts'''&lt;br /&gt;
:Klingt logisch, oder? OpenGL ist eine 3D-API und da 2D nichts weiter als die (fast vollständige) Vernachlässigung der Z-Koordinate ist, kommen wir um einen 3D-Beschleuniger nicht herum, der dazu auch noch einen Treiber mitbringen muss der OpenGL unterstützt. Allerdings schritt der Fortschritt auf diesem Gebiet der IT-Technik in den letzten Jahren so rasant voran wie sonst nirgendwo, und wir werden nur sehr selten auf Rechner stoßen in denen Hardware agiert die keine 3D-Beschleunigung bietet. Ergänzend dazu sollte allerdings trotzdem immer der neuste Treiber installiert sein, denn besonders die in WindowsXP integrierten Grafikkartentreiber wurden ihrer OpenGL-Funktionalität entraubt (Man riecht hier förmlich die Konkurrenz zwischen D3D und der GL). Also ist dies im Endeffekt ein Nachteil der inzwischen kaum noch halt findet und in Zukunft total vernachlässigt werden kann.&lt;br /&gt;
&lt;br /&gt;
*'''Hardwarelimitationen'''&lt;br /&gt;
:Einer der größten Nachteile einer jeden 3D-API die auf Hardwarebasis arbeitet sind die Limitationen die die Hardware mitbringt. Jeder Grafikkartentyp hat andere, was mitunter dazu führen kann das die selbstverfassten OpenGL-Anwendungen nicht auf allen Rechnern laufen. Da wir uns in diesem Tutorial (2D ist ja recht anspruchslos) allerdings in den Niederungen der OpenGL-Funktionalität bewegen, dürfte es hier kaum Probleme geben. Einzig die Tatsache das vor allem ältere 3D-Beschleuniger mit großen Texturen Probleme haben könnte hier und da Schwierigkeiten machen. Wer aber keine Texturen größer 1024x1024 Pixel nutzt und dazu noch sparend mit dem Speicher der Grafikkarte umgeht (nicht jede Grafikkarte hat 128 Mbyte Grafikspeicher oder gar mehr). Einige Leute werden sich übrigens evtl. dadurch verunsichert fühlen das ihnen jemand gesagt hat, man könnte unter OpenGL nur Texturen nutzen die der Dimension 2^n*2^n entsprechen. Das ist grundlegend korrekt, aber wir nutzen hier einen Texturenloader der [[gluBuildMipMaps]] benutzt um [[MipMaps]] (verschiedene Detailstufen) für unsere Texturen zu erstellen. Diese Funktion schluckt jede Größe (sofern diese kleiner oder gleich dem Hardwarelimit ist) und passt die Texturen dann entsprechend an eben genanntes Limit an, also müssen wir uns um diese so oft erwähnte Limitation keine Sorgen machen. Wer zu dem Thema Hardwarelimitation mehr wissen will, der sollte unbedingt mal auf [http://www.delphi3d.net/ Tom Nuydens Seite] vorbei schauen. Dort gibt es eine riesige Datenbank in der fast alle Grafikkarten mit ihren entsprechenden OpenGL-Fähigkeiten vertreten sind.&lt;br /&gt;
&lt;br /&gt;
*'''Filtering'''&lt;br /&gt;
:Zugleich ein großer Vorteil, aber je nach Situation auch ein Nachteil. OpenGL filtert Texturen (sofern man das via GL_LINEAR so will) bilinear, was man auch tunlichst aktiviert lassen sollte (GL_NEAREST filtert nicht, sieht dann aber auch scheußlich blockig aus). Dadurch wirken Texturn meist etwas verschwommen. Ich für meinen Teil umgehe dies aber ganz einfach, denn in fast jedem Bildbearbeitungsprogramm gibt es eine Funktion mit der man ein Bild scharfzeichnen kann. Das sieht auf den ersten Blick dann zwar überzeichnet aus, aber wenn OpenGL das Bild dann als Textur bilinear filtert, heben sich Filtering und Scharfzeichnung gegenseitig fast auf. Das hat sich in meinen Anwendungen bisher bewährt und ist nicht wirklich viel Aufwand.&lt;br /&gt;
&lt;br /&gt;
Um dieses Kapitel hier abzuschließen sei noch gesagt das man ohne 3D-Beschleuniger nicht unbedingt auf OpenGL verzichten muss. Brian Paul hat mit [http://www.mesa3d.org/ Mesa3D] nämlich ein Projekt am laufen das OpenGL-DLLs zur Verfügung stellen die komplett über die CPU ablaufen. So kann man dann OpenGL-Anwendungen mit einer etwas schnelleren CPU trotz fehlendem 3D-Beschleuniger nutzen, oder auf Funktionen ausprobieren die von der (zu alten) Grafikkarte nicht unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
==Die Grundlagen==&lt;br /&gt;
&lt;br /&gt;
Sollte sich der geneigte Leser nun also doch für die GL entschieden haben, so widmen wir uns dann jetzt den Grundlagen der 2D-Darstellung unter OpenGL. Viele Sachen die man bei einer 3D-Anwendung beachten muss, sind hier eigentlich zu vernachlässigen. Wer also schon mal eine kleine 3D-Anwendung unter OpenGL geschrieben hat wird hier sicherlich keine Problem bekommen. Da sich dieses Tutorial aber an blutige (mhh, lecker) Einsteiger richtet, versuche ich so genau und einfach wie möglich zu erklären was man machen muss und v.&amp;amp;nbsp;a. warum. Genau deshalb habe ich auch für einen Großteil der hier erwähnten Techniken im Download zu diesem Tutorial (siehe unsere Files-Sektion und dort unter VCL-Source) jeweils ein eigenes Beispielprogramm + Quellcode (und natürlich ausgiebigen Kommentaren) geschrieben. Wenn zu dem jeweiligen Kapitel ein solches im Download enthalten ist, dann steht das ''kursiv'' unter der Überschrift des Kapitels.&lt;br /&gt;
&lt;br /&gt;
==Die Projektion==&lt;br /&gt;
&lt;br /&gt;
Wie bekannt (sein sollte), besitzt OpenGL im Groben zwei wichtige Matrizen. Zum einen die Modellansichtsmatrix, in der man im Normalfall seine Szene (egal ob 2D oder 3D) rendert und (für dieses Kapitel wichtiger) die Projektionsmatrix. Diese Matrix lässt sich am besten mit der Linse einer Kamera vergleichen und legt fest wie die Objekte auf den Bildschirm projiziert werden (wer mitdenkt wird jetzt wissen warum diese Matrix so genannt wurde). In einer 3D-Anwendung setzen wir (meist über [[gluPerspective]]) eine Projektionsmatrix die dafür sorgt das unsere Objekte perspektivisch korrekt verzerrt werden (so wie es im echten Leben auch ist). Da Bilder aber mehr als tausend Worte sagen zeige ich das anhand der unteren Bildreihe, die einen Würfel an verschiedenen Positionen auf der X-Achse zeigt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_1.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Der Würfel wurde auf den beiden Bildausschnitten links und rechts jeweils um 40 Einheiten auf der X-Achse verschoben und man kann sehr gut sehen das die Seiten des Würfels perspektivisch verzerrt werden, also weiter entfernte Kanten kleiner erscheinen (wie im realen Leben, das kann man ja prima mit nem würfelähnlichem Objekt nachprüfen). Diese Art der Darstellung ist für 3D gut geeignet, aber für unseren Zweck nicht. Denn wir wollen ja das unser Objekt, egal an welcher Bildschirmposition es sich befindet, gleich aussieht.&lt;br /&gt;
&lt;br /&gt;
Dazu gibt es unter OpenGL den sog. orthogonalen Modus, der dafür sorgt das unser [[Frustum]] (Sichtkegel) nicht wie bei der 3D-Projektion kegelförmig ist (kleine Seite beim Betrachter, große Seite am Ende des Sichtfeldes), sondern wie eine Box aussieht. Für technisch interessierte hier der Vergleich zwischen dem 3D- und dem 2D-Frustum :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_2.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links sehen wir das Frustum (~Sichtbereich) für die orthogonale Projektion (also 2D) und rechts für die perspektivische Projektion (3D). In diesem Tutorial interessieren wir uns wie gesagt für ersteres Frustum, welches sich über die Funktion [[glOrtho]] erstellen lässt. Diese Funktion will von uns die Dimensionen haben die wir unserem Viewport geben wollen. Ich empfehle hier übrigens immer einen festen Wert der einer der gängigen Auflösungen (z.&amp;amp;nbsp;B. 640x480, 800x600) entspricht. Der feste Wert hat übrigens den Vorteil das unsere Anwendung von der vom Nutzer gewählten Bildschirmauflösung unabhängig ist. Wir müssen dann also nicht mehr umrechnen wo unser Objekt jetzt in der gewählten Auflösung wäre und wie groß es dort sein müsste. Dadurch das wir immer die selben virtuellen Koordinaten haben, überlassen wir der GL (bzw. der Grafikkarte) die Umrechnung. Wenn wir also eine virtuelle Auflösung von 640x480 an glOrtho übergeben, und ein Objekt zentriert bei 320x240 rendern, dann wird dieses egal in welcher Auflösung immer in der Mitte des Schirms gerendert. Die Umrechnung macht wie gesagt OpenGl (oder besser gesagt die Grafikkarte). Zusätzlich übergeben wir der Funktion dann noch die Z-Reichweite. Hier kann man beliebig wählen, und muss nicht wie in 3D darauf achten Z-Near und Z-Far so zu wählen das die Auflösung des Tiefenpuffers nicht unnötig verschwendet wird (z.&amp;amp;nbsp;B. mit einem Z-Near von 0.1 oder gar kleiner). Für Z-Near nehme ich gewöhnlich 0 und für Z-Far einen Wert der dafür sorgt das ich alle Objekte so sortieren kann das ihre Z-Position auf einen Integerwert fällt. Als kleines Codebeispiel könnte unsere Projektionsmatrix nun so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glMatrixMode(GL_PROJECTION);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
glViewport(0,0,ClientWidth,ClientHeight);&lt;br /&gt;
glOrtho(0,640,0,480,0,128);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um den optischen Vergleich zur oben erwähnten 3D-Projektion zu zeigen, gibt es wieder ein Bild des Würfels, diesmal allerdings mit 2D-Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_3.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Das sieht auf den ersten Blick zugegeben recht langweilig aus, stellt aber genau den selben Szenenverhalt dar wie die Ansicht ein paar Zeilen weiter oben. Diesmal allerdings mit der gerade besprochenen orthogonalen Ansicht, die als Grundlage für unsere 2D-Projektion dient.&lt;br /&gt;
&lt;br /&gt;
So viel also zur 2D-Projektion und hoffentlich hat das hier jeder verstanden. Die orthogonale Projektion ist ein essentieller Bestandteil einer jeden 2D-Anwendung unter OpenGL und sollte daher allen Interessierten ein Begriff sein. Falls das hier jemandem zu technisch war, im Forum werden weitergehende Fragen gerne beantwortet.&lt;br /&gt;
&lt;br /&gt;
Noch als kleiner Nachtrag: Wer sich mal die Parameter angesehen hat die glOrtho will, wird bemerkt haben das wir in obigem Quellcode (zumindest augescheinlich) Top mit Bottom verwechselt haben (sprich es sollte 0,640,480,0 statt 0,640,0,480) heißen. Das hat allerdings seine Richtigkeit, denn in OpenGL liegt der Ursprung des Koordinatensystems in der unteren linken Bildschirm(oder Fenster)ecke, wobei er bei Windows in der oberen Ecke liegt. Unter OpenGL liegt also quasi der &amp;quot;Boden&amp;quot; oben, genau umgekehrt wie unter Windows. Genau deshalb übergeben wir als &amp;quot;Oben&amp;quot; an glOrtho den eigentlichen Boden des Viewports. Das klingt verwirrend, aber ist im Endeffekt gar nicht so schwer zu behalten, besonders dann nicht wenn man sich folgende Illustration mal näher ansieht:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_11.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Das sollte man immer in Hinterkopf behalten, und unter 3D ist es genauso. Während ein positiver Y-Wert Objekte in einem Windowsfenster nach unten verschiebt, geschieht unter OpenGL genau das Gegenteil. Wer sich mit dieser Tatsache nicht anfreunden kann, der kann auch gerne glOrtho dazu nutzen die 2D-Matrix von OpenGL an die Windowsgegebenheiten anzupassen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glOrtho(0,640,480,0,0,128);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon verhält es sich unter OpenGL genauso wie unter Windows. Positive Y-Koordinaten zeigen nach unten. Allerdings muss man hier dann auch drauf achten die gerenderten Objekte an diese Gegebenheit anzupassen. Man muss diese also quasi auf den Kopf stellen, damit sie mit der neuen Matrix korrekt angezeigt werden. Das geht aber ganz leicht, indem man beim rendern von Quads oder anderen texturierten Primitiven ganz einfach die T-Texturkoordinaten vertauscht.&lt;br /&gt;
&lt;br /&gt;
==Darstellung der 2D-Objekte==&lt;br /&gt;
&lt;br /&gt;
Einige 2D-Interessierte haben sich sicherlich schon mal im Funktionsumfang von OpenGL umgesehen und bemerkt, dass es dort eigentlich gar keine Funktionen gibt um Dinge in 2D zu zeichnen. Auf den ersten Blick sieht das auch wirklich so aus, aber man darf halt nie vergessen dass OpenGL primär für den 3D-Bereich entworfen wurde und sich 2D-Sachen dann nur über 3D-Techniken realisieren lassen. So auch die Darstellung unserer 2D-Objekte, für die wir aus genau diesem Grund eine 3D-Technik anwenden müssen, nämlich das sog. Texturemapping (Den Begriff &amp;quot;Textur&amp;quot; gibt's übrigens auch im deutschen Sprachgebrauch, aber gängiger ist die korrekte Übersetzung &amp;quot;Oberfläche&amp;quot;). Unter OpenGL werden ja alle Objekte aus verschiedenen Primitiventypen zusammengesetzt (Dreiecke, Rechtecke, usw.) und diese Objekte kann man mit einer Textur belegen die dann auf dieser Oberfläche &amp;quot;angezeigt&amp;quot; wird. Diese Textur lädt man im Normalfall aus einer vorher erstellten Bilddatei unter Nutzung eines [[Texture_Loader|Texturenloaders]] (alternativ kann man den sich natürlich auch selbst schreiben), der diese Textur für die Grafikkarte vorbereitet (also z.&amp;amp;nbsp;B. ein BMP-Bild vom BGR-Format ins RGB-Format bringt) und dann auf dieser ablegt. Danach kann diese Textur an jeder Stelle im Programm auf eine Primitve &amp;quot;geklebt&amp;quot; werden, und genauso machen wir das auch in unserer 2D-Anwendung.&lt;br /&gt;
&lt;br /&gt;
Allerdings müssen wir keine komplexen Formen darstellen, da unsere Objekte ja nicht 3D sind, sondern (meistens) schon in einem anderen Programm erstellt (oder vorgerendert wurden) und als Bilddatei abgelegt wurde. Wir laden und stellen dann also nicht die 3D-Daten dieses Modells dar (was bei komplexen 2D-Objekten wohl eh zu viel wäre), sondern kleben diese schon fertige Bilddatei mittels einer Textur auf ein Rechteck (in der GL-Terminologie &amp;quot;Quad&amp;quot; genannt, vom Primitiventyp GL_QUADS). Hoffe mal das kam gut rüber, aber ich verdeutliche dass dann besser nochmal anhand einer kleinen &amp;quot;Bilderserie&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_4.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Oben sei mal kategorisch der Vorgang geschildert um ein vorgerendertes 3D-Objekt als Textur in seine 2D-Anwendung zu bekommen. Rechts sieht man das 3D-Modell, das dann aus der gewünschten Ansicht (im obigen Falle von der Seite) im 3D-Modellierungsprogramm gerendert wird. Dieses Rendering speichert man dann in einem Format ab das der Texturenloader verarbeiten kann, lädt dies in seine OpenGL-Anwendung und stellt dies dann auf z.&amp;amp;nbsp;B. einem Quad dar (siehe letztes Bild). Natürlich spielt es keine Rolle ob man seine 2D-Objekte vorrendert oder diese von Hand zeichnet, wobei den meisten wohl Ersteres besser von der &amp;quot;Hand&amp;quot; geht.&lt;br /&gt;
&lt;br /&gt;
===Welches Bildformat ist das richtige?===&lt;br /&gt;
&lt;br /&gt;
Bevor wir nun weiter auf das Thema eingehen kümmern wir uns um die '''Frage nach dem richtigen Bildformat''' für unsere Texturen. Bildformate gibt's wie Sand am Meer, aber für unseren Zweck eignen sich nur sehr wenige (eigentlich nur ein einziges). Ich zähle die verbreitetsten Formate kurz auf und sag auch warum (oder warum nicht) und wofür man diese verwenden kann:&lt;br /&gt;
&lt;br /&gt;
*'''Joint Photographic Experts Group (*.jpg; *.jpeg)'''&lt;br /&gt;
:Das in den Weiten des WWWs wohl verbreitetste Format ist für Texturen generell eher weniger zu empfehlen, und für 2D-Objekte erst recht nicht. Zum einen ist die in diesem Format genutzte Kompression verlustbehaftet (also verlieren unsere Texturen an Qualität) und außerdem hat dieses Format keine Möglichkeit Transparenzinformationen zu speichern. Diese benötigt man aber für 2D-Objekte, denn im Normalfall wollen wir den Hintergrund des Objektes ja durchsichtig machen (dazu gleich mehr). Also sollte dieses Format nur verwendet werden wenn wir etwas darstellen wollen das sehr viele Details enthält (dann fällt die verlustbehaftete Kompression nicht so stark auf) und keine transparenten Bereiche enthält.&lt;br /&gt;
&lt;br /&gt;
*'''Graphical Interchange Format (*.gif)'''&lt;br /&gt;
:Direkt aus der Steinzeit des IT-Sektors kommt das (im Netz noch weit verbreitet) GIF-Format. Für unsere Zwecke ist es total unbrauchbar. Es ist eine Palettenformat, das maximal 256 verschiedene Farben unterstützt, allerdings inklusive Transparenzinformationen. Aber die maximal 256 Farben und die kaum vorhandene Kompression machen es für unseren Zweck nutzlos. Die Tatsache dass es Animationen unterstützt ist zwar im Internet für kleine animierte Sachen ganz toll, aber hilft uns auch nicht, denn dazu überwiegen die Nachteile zu stark&lt;br /&gt;
&lt;br /&gt;
*'''Portable Network Graphic (*.png)'''&lt;br /&gt;
:Der Nachfolger des GIF-Formates. Eigentlich auch sehr gut für Texturen geeignet, denn neben einem Alphakanal (maximal 8 Bit) und 8 Bit pro Farbkanal unterstützt es auch verlustfreie Kompression (mit einem recht hohen Kompressionsfaktor). Nachteil ist allerdings der Aufbau des Formates, denn der Chunkaufbau macht das Laden recht schwer und bisher gibt es nur Loader die eine DLL-Datei mit sich schleppen. Alternativ kann man auf neuen Betriebssystemen jedoch via GDI+ auch PNG-Dateien direkt laden.&lt;br /&gt;
&lt;br /&gt;
*'''TARGA (*.tga)'''&lt;br /&gt;
:Dieses Format werden sicherlich nicht viele Einsteiger kennen, allerdings ist dies '''''das perfekte Format für unsere Bedürfnisse bzw. Texturen im Allgemeinen'''''. Es kann nämlich bis zu 8 Bit pro Farbkanal (also das was man heute als 32-Bit Farbtiefe bezeichnet) speichern (= 24 Bit für Farben) und dazu noch einen Alphakanal (maximal 8 Bit). Der Alphakanal ist sehr nützlich, denn in ihm kann man die Transparenzinformationen eines Bildes ablegen. Auch viele kommerzielle Titel nutzen dieses Format (u.&amp;amp;nbsp;a. Quake3), und das aus gutem Grund. Kompression wird auch unterstützt, und zwar verlustfrei in Form einer LZW-Kompression. Alles in allem ist das momentan das geeignetste Format für Texturen, zumal so gut wie jedes Bildbearbeitungsprogramm damit umgehen kann. Nebenbei ist dies Format auch recht einfach aufgebaut und damit auch recht leicht einzulesen.&lt;br /&gt;
&lt;br /&gt;
*'''BITMAP (*.bmp)'''&lt;br /&gt;
:Das BMP-Format dürfte sicherlich jedem ein Begriff sein, ist aber genauso wie GIF ein Relikt aus der Steinzeit. Es kann zwar genauso wie das TGA-Format neben den 8 Bits pro Farbkanal auch einen maximal 8 Bits großen Alphakanal anbieten, allerdings kommen damit nur recht wenige Bildbearbeitungprogramme klar. Außerdem sind die Bilddaten hier im BGR-Format abgelegt, statt dem eher üblichem RGB-Format (Red, Green, Blue). Das ist zwar sehr leicht umzuwandeln, bzw. kann mit passender GL-Konstante auch direkt übergeben werden, aber trotzdem ist dieses Format in keinem Falle dem TARGA-Format vorzuziehen.&lt;br /&gt;
&lt;br /&gt;
*'''[[DDS|DirectDraw Surface (*.dds)]]'''&lt;br /&gt;
:Ein sehr neues Format, das den Ursprung (wie am Namen zu erkennen) in Microsofts DirectX-Schnittstelle hat. Es ist ein recht modernes Format, das speziell für die Speicherung von Texturen entwickelt wurde. Allerdings ist das eher was für Fortgeschrittene, denn weder das Laden dieses Formates ist einfach, noch seine Speicherung (selbst teure Bildbearbeitungsprogramme brauchen ein passendes Plugin für DDS und bei der Erstellung des Formates muss man auf bestimmte Sachen achten). Aber ich wollte es hier trotzdem mal erwähnt haben, damit man sieht das es auch spezielle Formate für Texturen gibt, und wenn ihr euch eingearbeitet habt, dann könnt ihr im Forum mehr zu dem Format finden (Mars hat dort auch einen grundlegenden Loader gepostet), denn es ist recht interessant. Es unterstützt feste Kompressionsratios, Mip-Maps, 3D-Texturen, uvm. '''Für fortgeschrittene 3D-Programmierer sollte DDS also das Format der Wahl sein''', denn es wurde als einziges der verbreiteten Bildformate speziell für diesen Bereich konzipiert. Vor allem die Tatsache dass die Kompression dieses Formates von den Grafikkarten direkt unterstützt wird prädestiniert es für diesen Anwendungsfall. So spart man sowohl beim Hochladen als auch beim Rendern viel Busbandbreite, da die GPU die Textur auch intern komprimiert behandelt und spart logischerweise auch VRAM. Man darf sich allerdings nicht vom Platzverbrauch der eigentlichen Datei irrtieren lassen, denn das Kompressionsformat ist fest (z.B. 4:1, 6:1, etc.) statt variable wie u.A. bei JPGs. Aber dafür entspricht dann die Dateigröße exakt der Größe die auch im VRAM belegt wird. Allerdings sollte man hier genau wissen was man tut, da es sehr viele Foramte innerhalb des DDS geben kann (DXT1, DXT3, DXT5, Palette, Fließkomma, etc.) und es durchaus Texturen gibt die durch den festen Kompressionsratio schlecht aussehen können. Ein gutes Beispiel ist hier ein blauer Himmel mit Sonne und Wolken, der durch einen weichen Farbverlauf gekennzeichnet ist. Da bei DXT1/3/5 fest komprimiert wird kann dort die Bildqualität sehr stark leiden. Dann sollte man im DDS unkomprimiert ablegen. Außerdem gibt es inzwischen auch einen recht brauchbaren Loader für DDS in Delphi, und Lossys [[glBitmap]] kann dieses Format auch laden.&lt;br /&gt;
&lt;br /&gt;
Die obige Liste dürfte also einen recht (groben) Überblick über die verbreiteten Bildformate geben, und für dieses Tutorial begnügen wir uns erstmal mit dem TARGA-Format. Das wurde übrigens bereits 1984 erfunden, ist aber trotzdem noch nicht veraltet, sorgt aber dafür das so ziemlich jedes Programm damit umgehen kann.&lt;br /&gt;
&lt;br /&gt;
Wer sich übrigens nicht auf einen fremden Texturenloader verlassen möchte, sondern sich selbst um das Einlesen der Bildformate kümmern will, der sollte mal eine Blick auf [http://www.wotsit.org wotsig.org] werfen, einer recht großen Bibliothek die es sich zur Aufgabe gemacht hat Spezifikationen für Dateiformate zu sammeln. Dort wird man zu jedem der oben gennannten Bildformate eine solche Spezifikation finden, anhand derer man dann selbst Laderoutinen schreiben kann.&lt;br /&gt;
&lt;br /&gt;
===Textur laden===&lt;br /&gt;
&lt;br /&gt;
Auch wenn es ein sehr simples Unterfangen ist eine Textur zu laden, werde ich hier trotzdem nochmal kurz darauf eingehen. Das Tutorial richtet sich ja an Einsteiger, und von daher kann es nicht schaden auch mal kurz zu zeigen wie man so eine Textur lädt. Nutzen tun wir dazu die ''Textures.pas'' (die im Original von Jan Horn stammt. Ein weitere guter Loader ist [[Glbitmap_loader|glBitmap.pas]]), die sich im Download des Beispiels für dieses Tutorial befindet. Der Loader kann JPG, BMP und TGA laden. Außerdem lädt er auch den Alphakanal aus einer TGA-Textur.&lt;br /&gt;
&lt;br /&gt;
Bevor wir die Textur laden können, benötigen wir eine Variable in der wir den Bezeichner der Textur speichern. OpenGL erstellt für alle Ressourcen eindeutige Bezeichner (Bezeichner hier in Form eines Integerwertes, also einer eindeutigen ID), so auch für Texturen. Dieser Bezeichner ist vom Typ glUInt (U=unsinged Int=Integer, also vorzeichenloser Ganzzahlwert, was in Delphi dem Variablentyp ''Cardinal'' entpricht). Deshalb deklarieren wir unseren Texturenbezeichner auch so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;var&lt;br /&gt;
 MyTex : glUInt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir mehrere Texturen laden und verwalten wollen, bietet sich natürlich ein (dynamisches) ''array of glUInt'' an, aber das sind Delphigrundlagen die in diesem Tutorial nichts zu suchen haben.&lt;br /&gt;
&lt;br /&gt;
Das Laden der Textur geht nun dank der ''Textures.pas'' ganz einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;LoadTexture('MeineTextur.tga', MyTex, False);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameter sollten recht logisch sein, der erste gibt den Dateinamen der Textur an, der zweite das Texturobjekt (in das die ID der Textur geschrieben wird) und der letzte Parameter gibt an ob die Textur aus einer dem Programm angehängten Ressource geladen werden soll. Sollte der Ladevorgang erfolgreich gewesen sein, so müsste sich in ''MyTex'' ein Wert &amp;gt; 0 befinden, nämlich der eindeutige Bezeichner dieses Texturenobjektes.&lt;br /&gt;
&lt;br /&gt;
===Textur anwenden===&lt;br /&gt;
&lt;br /&gt;
Wer sich schonmal ein wenig über OpenGL schlau gemacht hat, der wird wissen dass die GL eine Statemachine ist. Das trifft auch auf Texturen zu, denn wenn eine Textur gebunden wurde, wird sie solange auf alle Primitiven angewendet, bis entweder eine andere Textur gebunden wurde oder das Texturemapping über [[glDisable]] abgeschaltet wird. Das hat besonders dann den Vorteil, wenn man viele Objekte mit der gleichen Textur rendern muss, denn Texturenwechsel sind recht kostspielig. Von daher sollte man also bei vielen Objekten eine Sortierung nach Textur vornehmen, dann diese Textur binden und danach dann alle Objekte die diese Textur besitzen rendern.&lt;br /&gt;
&lt;br /&gt;
Doch bevor Texturen überhaupt angezeigt werden, müssen wir OpenGL erstmal mitteilen das es diese auch anzeigen soll. Dazu gibt es die Funktion '''glEnable''', der man mit der Konstante '''GL_TEXTURE_2D''' mitteilt das wir die 2D-Texturierung aktivieren wollen (1D oder 3D-Texturen benötigen wir ja in diesem Tutorial nicht):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glEnable(GL_TEXTURE_2D);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unglaublich einfach, oder? So schnell kann das dank einer gut durchdachten API wie OpenGL gehen. Jetzt wo wir der API erstmal gesagt haben dass wir gerne Texturen sehen möchten, müssen wir auch noch sagen welche Textur als nächstes auf unserer Primitiven gezeigt werden soll. Dazu bindet (~ aktiviert) man das passende Texturobjekt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBindTexture(GL_TEXTURE_2D, MyTex);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Von nun an werden alle folgenden Primitiven solange mit der hinter ''MyTex'' abgelegten Textur gerendert, bis das Texturemapping entweder deaktiviert wird oder wir eine andere Textur binden.&lt;br /&gt;
&lt;br /&gt;
===Transparenz===&lt;br /&gt;
&lt;br /&gt;
Eine wichtige Sache die es noch zu klären gibt ist Transparenz. Oben habe ich ja gesagt das wir unsere Objekte auf Quads kleben (über eine Textur), aber unsere vorgefertigten Objekte nur selten auch genau die Form eines Quads haben. Der Panzer auf der oben gezeigten Textur wird z.&amp;amp;nbsp;B. von sehr viel schwarz umgeben, das wir da natürlich nicht sehen wollen. Aber auch um die Transparenz brauchen wir uns unter OpenGL keine Sorgen zu machen, denn dafür gibt es den sog. Alphakanal der Textur, der angibt welche Teile einer Textur später transparent (oder besser gesagt gar nicht, aber dazu gleich mehr) gezeigt werden sollen. Aus diesem Grund haben wir uns mit dem TGA-Format auch ein Format gewählt das diesen Kanal direkt im Bild speichern kann, sodass wir diesen nicht extra erstellen oder aus einer seperaten Bilddatei laden müssen.&lt;br /&gt;
&lt;br /&gt;
Wie man den Alphakanal nun in die Textur bekommt hängt davon ab wie man seine Textur erstellt. Wer seine Objekte von Hand malt, der muss den Alphakanal im Bildbearbeitungsprogramm selbst erstellen. Wer seine Objekte allerdings vorrendert, der kann diese Arbeit im Normalfall von der 3D-Software erledigen lassen, die Alphainformationen direkt mitexportieren kann. Als kleiner Hinweis sei übrigens gesagt das man beim Rendering des Objektes im 3D-Programm die Kantenglättung deaktivieren muss, da man sonst an den Rändern Artefakte hat (die logischerweise Teile der Hintergrundfarbe enthalten) die dann in der OpenGL-Anwendung zu unschönen Effekten führen. Um das zu verbildlichen hier nochmal unsere Panzertextur, allerdings begleitet vom (im Bildformat gespeichertem) Alphakanal:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_5.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links also unsere Textur und rechts der Alphakanal. Den sieht man normalerweise nicht, aber fast jedes Bildbearbeitungsprogramm gibt einem die Möglichkeit sich diesen anzeigen zu lassen. Wie zu sehen befinden sich in unserem Falle nur zwei Werte im Alphakanal. Und zwar Schwarz (= 0) für komplett transparent und Weiß (= 1) für komplett Sichtbar.&lt;br /&gt;
&lt;br /&gt;
Unter OpenGL nutzen wir jetzt für die Transparenz den [[GlAlphaFunc|Alphatest]]. Transparenz ließe sich auch über Blending realisieren, allerdings hat Blending den Nachteil das man dann die transparenten Objekte nach Tiefe sortieren müsste, da Blending im Framepuffer abläuft und nicht wie der Alphatest auf Fragmentbasis, wo wir uns dann keine Sorge um die Reihenfolge unserer Objekte machen müssen. Wollen wir nun also den Alphakanal der Textur nutzen (natürlich muss dieser vorher im Texturenloader geladen werden, sonst geht's nicht) müssen wir vor dem rendern des mit der Objekttextur belegten Quads den Alphatest aktiveren und festlegen wie der Test auszusehen hat :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glEnable(GL_ALPHA_TEST);&lt;br /&gt;
glAlphaFunc(GL_GREATER, 0.1);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zuerst aktiveren wir also den Alphaest (dazu gibt es die Konstante '''GL_ALPHA_TEST'''), bevor wir dann der GL mittels [[GlAlphaFunc|glAphaFunc]] sagen wie der Test aussehen soll. Der erste Parameter ('''GL_GREATER''') gibt an, das nur Fragmente (also Teile der Textur) gerendert werden sollen deren Alphawert größer ist als der im zweiten Wert angegebene (0.1). Wie auch Farbwerte wird der Alphawert unter OpenGL &amp;quot;geclampt&amp;quot;, also in eine bestimmte Reichweite gebracht, nämlich 0 (= Schwarz) bis 1 (= Weiß). Die 0,1 (statt der 0) als Vergleichswert nehmen wir quasi aus Toleranz. Wenn wir das obige also getan haben, dürften wir auf unserem Quad (sofern der Alphakanal korrekt erstellt und geladen wurde) also nur noch das eigentliche Objekt sehen, und der Hintergrund müsste an den transparenten (Alpha &amp;lt;= 0,1) zu sehen sein:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_6.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links sehen wir unsere Bohne ohne aktiven Alphatest, was zur Folge hat das der eigentlich transparente (schwarze) Teil der Objekttextur den Hintergrund überdeckt. Rechts wuede der Alphatest aktiviert und wir sehen nur den Teil unseres Objektes den wir auch sehen wollen.&lt;br /&gt;
&lt;br /&gt;
===Das Objekt anzeigen===&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun unsere Textur mit passendem Alphakanal geladen haben und den Alphatest auch aktiviert haben, müssen wir schlussendlich noch unser(e) Objekt(e) rendern. Wie schon mehrfach gesagt nutzen wir dazu die GL_QUADS-Primitive. Bei diesem Primitiventyp beschreiben wir mit vier Eckpunkten ein Rechteck (das von der Grafikkarte dann in zwei Dreiecke zerlegt wird), wobei jeder Eckpunkt auch eine Texturkoordinate zugewiesen bekommt. Diese Koordinate gibt an, aus welchem Teil der Textur dieser Eckpunkt seine Bilddaten beziehen soll, und sie wird über das gesamte Quad hinweg interpoliert. Also haben wir in der genauen Mitte des Quads als interpolierte Texturkoordinate das genaue Mittel der übergebenen Texturkoordinaten. Um diese Interpolation müssen wir uns allerdings keine Sorgen machen, das macht die Grafikkarte.&lt;br /&gt;
&lt;br /&gt;
Und in Sachen Texturkoordinaten sind wir auch schnell fertig, denn für den Anfang haben wir pro Textur immer nur ein Objekt (später zeige ich dann wie man mehrere Objekt in eine Textur packt) und müssen dementsprechend auch nur eine 1 (= Ende der Textur) bzw. 0 (= Anfang der Textur vergeben. Wenn man sich das bildlich vorstellt, sieht das dann so aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_7.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Da wir nur mit 2D-Texturen arbeiten, müssen wir pro Eckpunkt auch nur zwei Koordinaten angeben. Und zwar einmal in X-Richtung auf der Textur (unter OpenGL auch S-Richtung genannt, oft auch mit &amp;quot;U&amp;quot; betitelt) und in Y-Richtung (unter OpenGL T-Richtung, oft auch &amp;quot;V&amp;quot; genannt). Wenn S=0 und T=0, bedeutet das also das dieser Eckpunkt seinen [[Texel|Texel]] (wie Pixel, bloß im Bezug auf Texturen) aus der oberen linken Ecke unserer Textur (X=0/Y=0) bezieht, während S=1 und T=1 dafür sorgt das der Eckpunkt sich den Texel in der untersten rechten Ecke der Textur schnappt. Wie bereits oben erwähnt müssen wir uns um den Raum zwischen den vier Eckpunkten nicht kümmern, das wird ja von der Hardware linear interpoliert.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode zu obigem Beispiel sieht dann so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_QUADS);&lt;br /&gt;
 glTexCoord2f(0,0); glVertex3f(-Breite/2, -Höhe/2, -Tiefe);&lt;br /&gt;
 glTexCoord2f(1,0); glVertex3f(+Breite/2, -Höhe/2, -Tiefe);&lt;br /&gt;
 glTexCoord2f(1,1); glVertex3f(+Breite/2, +Höhe/2, -Tiefe);&lt;br /&gt;
 glTexCoord2f(0,1); glVertex3f(-Breite/2, +Höhe/2, -Tiefe);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer obigen Text aufmerksam gelesen hat, sollte eigentlich problemlos verstehen was der Quellcode denn bewirkt. Wer damit Problem hat, der sollte sich das obige Kapitel nochmal unbedingt sorgfältig durchlesen, denn das ist eine sehr wichtige Sache.&lt;br /&gt;
&lt;br /&gt;
Soviel also zu den Grundlagen von 2D unter OpenGL. Wer nämlich hier angelangt ist, sollte zumindest 2D-Objekte unter OpenGL anzeigen können. Evtl. ist es hier angebracht das Tutorial einige Minuten ruhen zu lassen und ein wenig mit dem Erlerntem herumzuprobieren. Danach geht's nämlich mit etwas fortgeschritteneren (aus Sicht des Einsteigers) Themen weiter.&lt;br /&gt;
&lt;br /&gt;
===Die Rolle des Tiefenpuffers===&lt;br /&gt;
&lt;br /&gt;
Trotz der Tatsache dass wir in 2D die dritte Dimension vernachlässigen, bedeutet dies nicht das wir den Tiefenpuffer nicht doch nutzen können. Und zwar nutzen wir diesen in 2D zur hardwarebeschleunigten Sortierung unserer Objekte. In 2D-Anwendungen kann es ja genauso vorkommen das ein Objekt unter (&amp;quot;hinter&amp;quot;) einem anderen liegt und da wäre es ziemlich dumm diese selbst zu sortieren, wo OpenGL uns doch einen Tiefenpuffer anbietet der dies für uns macht.&lt;br /&gt;
&lt;br /&gt;
Genau deshalb haben wir mittels glOrtho auch die Reichweite für unseren Tiefenpuffer angegeben. Haben wir dann auch noch den Tiefentest mittels {{INLINE_CODE|glEnable(GL_DEPTH_TEST)}} und dem passenden Tiefentest via {{INLINE_CODE|[[glDepthFunc]](GL_LESS ''oder'' GL_EQUAL)}} aktiviert, so können wir über die Z-Koordinate unserer Objekte angeben wo die nun genau liegen. Ein Objekt dessen Z-Koordinate also näher an Z-Near ist, wird dann über einem an gleicher Stelle befindlichem Objekt mit einer Z-Koordinate näher an Z-Far gerendert, und zwar egal welches dieser Objekte wir als erstes an die GL übergeben haben.&lt;br /&gt;
&lt;br /&gt;
===Backface Culling===&lt;br /&gt;
&lt;br /&gt;
Auch diese von OpenGL angebotene Funktionalität sollte hier nicht verschwiegen werden. Denn in OpenGL bestehen Flächen immer aus einer Vorder- und Rückseite (wie im echten Leben, ein Blatt Papier hat ja auch zwei Seiten, egal wie dünn es ist), was spätestens dann Sinn macht wenn man bedenkt das man sich in einer 3D-Umgebung ja komplett frei bewegen kann. Doch in unserer 2D-Welt sehen wir immer nur eine Seite unserer Objekte, egal was wir anstellen. Und genau deshalb sollten wir OpenGLs [[Backface Culling]] (zu Deutsch heisst das wörtlich &amp;quot;Rückseiten Ausschluß&amp;quot;, aber solche Fachbegriffe deutsch man auch besser nicht ein) aktivieren, denn ist dies nicht der Fall, so werden alle Berechnungen immer für beide Seiten eines Polygons ausgeführt. Und dabei spielt es keine Rolle welche der Seiten sichtbar ist oder nicht. Wir aktivieren also das Backfaceculling und sagen OpenGL dass die Rückseiten der Primitiven nicht dargestellt werden soll (letzteres könnte man sich sparen, da das die Voreinstellung ist, allerdings sollte man lieber auf Nummer sicher gehen):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glEnable(GL_CULL_FACE);&lt;br /&gt;
glCullFace(GL_BACK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Solltet ihr jetzt übrigens eure Objekte nicht mehr sehen, dann habt ihr die Eckpunkte eurer Primitiven in der falschen Reihenfolge (Standard ist für OpenGL '''GL_CCW''' ('''C'''ounter'''C'''lock'''W'''ise, gegen den Uhrzeigersinn) angegeben. Ich empfehle dann entweder einen Blick ins Reedbook oder in eine der Beispielanwendungen, wo es eine Funktion namens ''DrawQuad'' gibt, die ein korrektes Quad rendert. Bei modernen Grafikkarten sollte das Backface Culling zwar nur recht wenig Performance bringen, aber es wäre trotzdem Performanceverschwendung dieses nette Feature einfach ungenutzt zu lassen.&lt;br /&gt;
&lt;br /&gt;
==Animation==&lt;br /&gt;
Bisher können wir zwar unsere 2D-Objekte mittels texturierter Quads auf dem Bildschirm darstellen, aber das ist natürlich noch recht statisch; und was wäre ein Computerspiel ohne Animationen? Und genau darum kümmern wir uns jetzt. Aber zuerst kurz zum Unterschied &amp;quot;Animation in 3D&amp;quot; und &amp;quot;Animation in 2D&amp;quot;. In 3D ist es normalerweise so, dass man ein 3D-Modell lädt und dann die einzelnen Teile des Modells animiert, sei dies über die GL-Befehle oder Animationsdaten im 3D-Format (Bones, Keyframes). Das bedeutet also das man in 3D quasi unendlich viele Freiheiten hat, denn man kann ja z.&amp;amp;nbsp;B. den Turm eines Panzers über [[glRotate]]f in jeden beliebigen Winkel bringen. In 2D ist das anders, denn da sind ja alle Grafiken vorgefertigt und werden nur abwechselnd auf unsere Quads geklebt. Würden wir dort also den Turm eines vorgefertigten Panzers rotieren lassen wollen, so müssten wir jeden Animationsframe vorfertigen und als Textur laden. Man muss sich also vorher Gedanken drüber machen ob 2D denn im Endeffekt wirklich weniger Aufwand bedeutet. Aber diese Entscheidung muss jeder für sich selbst fällen, weshalb wir uns nun zwei verschiedenen Animationsmöglichkeiten widmen werden.&lt;br /&gt;
&lt;br /&gt;
===Animation über Einzeltexturen===&lt;br /&gt;
''(Projektdatei : openGL2D_demo1)''&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_8.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Die wohl offensichtlichste (und auch einfachste) Art ein 2D-Objekt über Texturen zu animieren, ist über in einzelnen Texturen abgelegte Frames. Besonders aus einem 3D-Animationsprogramm (3D Studio, Maya) geht das besonders einfach. Denn diese Programme können eine Animation als Einzelbilder auf die Platte rendern. Dadurch hat man dann für eine Animation mit 60 Bildern 60 Texturen die dann einfach in ein Array geladen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;var&lt;br /&gt;
 Frame : array of glUInt;&lt;br /&gt;
&lt;br /&gt;
SetLength(Frame, NumFrames);&lt;br /&gt;
for i := 0 to NumFrames-1 do&lt;br /&gt;
 LoadTexture('animframe'+IntToStr(i)+'.tga', Frame[i], False);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das zu animierende Objekt verpasst man dabei mit einem Fließkommawert der den aktuell anzuzeigenden Frame darstellt, und erhöht diesen dann über die Zeit. Beim Rendern des Objektes nutzt man diesen Wert gerundeten (Indizes müssen ja Ganzzahlwerte sein) als Index in das Texturenarray:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBindTexture(GL_TEXTURE_2D,Frame[Round(CurrentFrame)]);&lt;br /&gt;
...&lt;br /&gt;
CurrentFrame := CurrentFrame + 0.025 * TimeFactor;&lt;br /&gt;
if CurrentFrame &amp;gt; Length(Frame) then&lt;br /&gt;
 CurrentFrame := 0;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil dieser Methode ist das man diese Animationen direkt aus seinem 3D-Programm heraus speichern kann und das die Animationen quasi unendlich lange (wobei sowohl Speicherplatz als auch Speicherausbau der Grafikkarte hier limitierende Faktoren sind) sein können. Nachteil ist der hohe Speicherverbrauch, sowohl auf der Platte als auch im Grafikspeicher, sowie die Tatsache das man dann recht oft die Textur wechseln muss.&lt;br /&gt;
&lt;br /&gt;
===Animation in einer einzigen Textur===&lt;br /&gt;
''(Projektdatei: openGL2D_demo2)''&lt;br /&gt;
&lt;br /&gt;
Diese Art der Animation ist wie oben schon angedeutet recht speichersparend und vermindert auch die Zahl der Texturenwechsel. Allerdings ist sie auch aufwendiger zu implementieren und unterliegt einigen Einschränkungen die man bei der Erstellung der Animationstextur berücksichtigen sollte. Statt also jeden Frame der Animation in einer eigenen Datei (und damit später auch Textur, obwohl sich das natürlich auch kombinieren lässt) abzulegen, wird versucht bei dieser Animationsart alle Frames in einem Gitter auf einer Textur anzuordnen.&lt;br /&gt;
&lt;br /&gt;
Wenn man nicht noch mit der Erstellung komplexer Texturkoordinaten rumfuchteln will, dann sollte man drauf achten dass das gewählte Gitter so hoch wie breit ist und die Texturen an diesem Gitter ausgerichtet sind. So habe ich bei dieser Beispieltextur (bevor sie für das Tutorial etwas verkleinert wurde) die Frames in einem Raster von 256x256 Pixeln untergebracht.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Explosion_det.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Zu sehen sind hier alle Animationsframes einer Explosionstextur aus der Beispielanwendung. Diese wurd mit einem entsprechenden Tool generiert, aber kaum ein 3D-Porgramm kann Animationen direkt in eine einzelne Textur exportieren. Hier muss man sich dann mit passenden Plug-Ins oder Drittprogrammen aushelfen.&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Abspielen&amp;quot; dieser Animation ist nun recht einfach, denn wir erinnern uns ja daran das die Texturkoordinaten in OpenGL immer im Bereich 0 bis 1 liegen, unabhängig (es gibt Ausnahmen, aber interessiert hier nicht) von der Größe unserer Textur. Also müssen wir im Endeffekt nur wissen wie viele Spalten und Zeilen unsere Animationstextur enthält um für jeden Frame die passenden Texturkoordinaten errechnen zu können. Um es konkret zu machen nehmen wir obiges Beispiel. Es besteht aus drei Reihen und drei Spalten, wobei die Animationen von links nach rechts durchlaufen. Also bedeutet dies das unser erster Animationsframe bei S=0 / T=0 beginnt und bei S=1/4 / T=1/4 Ende, Frame 2 beginnt dann bei S=1/4 / T=0 und endet bei S=2/3 / T=1/4, usw. Dies zu errechnen sollte als keine Probleme bereiten, genauso wie das Rendern.&lt;br /&gt;
&lt;br /&gt;
Doch dürfen wir die Nachteile dieser Animationsart auch nicht verschweigen. Das es oft schwierig ist (wenn man die Objekte und Animationen sowieso von Hand zeichnet dann natürlich nicht) aus den Animationsframes eine einzelne Textur zu machen habe ich bereits gesagt, aber man muss auch wie immer auf die Hardwarelimitationen achten. Denn wenn man viele Animationen in einer Textur unterbringen will, wird diese oft recht groß und selbst auf modernen Karten sollte die Textur nicht größer als 2048x2048 Pixel sein. Wenn wir also ein Objekt der Größe 256x256 haben, bekommen wir im besten Falle (2048 wird auf älteren Karten entweder nicht machbar sein, deren Grafikkartenspeicher fast ganz aufbrauchen, oder zu langsam sein) 64 Animationsframes auf eine Textur. Alles darüber müsste man dann in eine weitere Textur auslagern, was den Verwaltungsaufwand stark erhöhen würde. Außerdem muss man drauf achten, dass sich die Animationsframes nicht direkt berühren, also das zwischen einem sichtbarer Objektteil in Frame N mindestens ein Pixel Abstand zum sichtbaren Objektteil in Frame N+1 besteht. Denn dadurch das die Textur von OpenGL gefiltert wird, verlaufen Pixel die direkt aneinander liegen ineinander; wodurch dann unschöne Effekte entstehen. Ein weitere (allerdings nicht so gravierender) Nachteil ist die Tatsache dass man solche Animationen nicht über Texturenwiederholung mehrfach auf ein Objekt legen kann. Wenn man bei der erstgenannten Animationsart z.&amp;amp;nbsp;B. statt S=1/T=1 S=2/T=2 nutzt, dann wird dann Animation insgesamt viermal auf dem Quad wiederholt. Da man hier aber über die Texturkoordinaten quasi einen Frame aus der Textur herauspickt ist das nicht möglich, was im Normalfall aber kaum Gewicht haben sollte.&lt;br /&gt;
&lt;br /&gt;
===Rotation und Skalierung===&lt;br /&gt;
''(Projektdatei: openGL2D_demo3)''&lt;br /&gt;
&lt;br /&gt;
Wenn man alles selbst zeichnet (also z.&amp;amp;nbsp;B. mit der GDI arbeitet), dann hat man für die Rotation (oder Skalierung) eines Objektes im Normalfall nur zwei Möglichkeiten: Entweder man schreibt sich eigene Routinen die den Pixelsalat rotieren (was meist langsam ist, solange man es nicht in Assembler schreibt) oder man erstellt Bilddateien auf denen die Objekte schon vorrotiert sind. Erstere Methode ist wie gesagt langsam und sieht hässlich aus (es sei denn man filtert auch noch selbst) und die zweite Methode schränkt einen auf die vorberechneten Drehwinkel ein.&lt;br /&gt;
&lt;br /&gt;
Alle gerade genannten Probleme kann man unter OpenGL dank der hardwarebeschleunigung ad acta legen. Nicht nur dass man dank Hardware unendlich schnell rotieren kann, diese Rotation auch noch frei ist, nein, man bekommt sogar das Filtering dank Hardware umsonst:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_10.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links ist das um 15° gegenüber dem Ausgangsbild gedrehte Raumschiff ohne Filtering zu sehen. Gut ist hier die dadurch entstehende &amp;quot;Körnung&amp;quot; erkennbar, die in Bewegung noch sehr viel unschöner aussieht. Rechts sieht man das gleiche, diesmal allerdings mit Filtering. Der Unterschied dürfte direkt auffallen, und besonders auf hellen Hintergründen ist er noch frapierender. Natürlich sollte man die Grundlagen von OpenGL beherrschen um die Rotation korrekt anwenden zu können, denn folgender Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(45, 0,0,1);&lt;br /&gt;
glTranslatef(320, 240, 0);&lt;br /&gt;
DrawQuad(0,0,0, 256,256);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bewirkt etwas total anderes als folgender Code :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(320, 240, 0);&lt;br /&gt;
glRotatef(45, 0,0,1);&lt;br /&gt;
DrawQuad(0,0,0, 256,256);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer sich die OpenGL-Grundlagen bereits angeeignet hat, der wird sicher schnell erkannt haben wo der Unterschied liegt. Denn in OpenGL bewegt man Objekte nicht direkt, sondern immer nur den Ursprung der Matrix. Ersterer Code rotiert also unsere Matrix um 45° und verschiebt diese dann um 320 Einheiten auf der X- und 240 auf der Y-Achse, was dazu führt das unser Objekt in einem recht großen Kreis um den Ursprung rotiert wird. Der zweite Codeschnippsel hingegen verschiebt unser Objekt an den Punkt 320/240 (in unserem Falle genau die Bildschirmmitte) und rotiert dann dort unser Objekt um die eigene Achse. Das ist auch der Rotationscode den wir im Normalfall nutzen um ein Objekt um sich selbst rotieren zu lassen. In unserer 2D-Anwendung müssen wir auch prinzipiell nur um die Z-Achse rotieren, denn die ragt in OpenGL &amp;quot;in&amp;quot; den Bildschirm hinein. Um das nachzuvollziehen einfach mal den rechten Arm grade ausstrecken und &amp;quot;um&amp;quot; den ausgestreckten Zeigefinger rotieren lassen. Euer Arm stellt dann in diesem Falle die Z-Achse dar.&lt;br /&gt;
&lt;br /&gt;
Das Skalieren eines Objektes gestaltet sich noch leichter, denn hier muss man nichts weiter machen als vor dem Rendern des Quads ein glScalef aufzurufen und diesem dann den Skalierungsfaktor (1=keine Skalierung) pro Achse zu übergeben. Da wir hier allerdings nur in 2D arbeiten sollten wir die Z-Skalierung immer bei 1 belassen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(2,2,1);&lt;br /&gt;
DrawQuad(0,0,0, 256,256);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obiger Quellcode zeichnet unser Objekt in der doppelten Größe (also statt 256x256 Einheiten 512x512 Einheiten groß). Über die Skalierung kann man schön in 2D einen Tiefeneffekt realisieren, zum Beispiel ein Raumschiff das mit einer Skalierung von 0,5 /0,5 / 1 auf einem Träger startet und dann zu Beginn des Levels langsam in Richtung 1 / 1 / 1 skaliert wird. Dadurch wird das Schiff größer und es entsteht beim Betrachter der Eindruck, das Schiff würde hinaufsteigen.&lt;br /&gt;
&lt;br /&gt;
==Scrollen und zoomen==&lt;br /&gt;
''(Projektdatei: openGL2D_demo4)''&lt;br /&gt;
&lt;br /&gt;
Selbst viele kommerzielle 3D-Spiele benötigen oft einen 2D-Teil um solche Sachen wie Übersichtskarten (man will ja gerne wissen wo man hin will) oder evtl. Credits und ähnliche größere 2D-Anzeigen zu tätigen, die oft den ganzen Bildschirm einnehmen oder gar größer sind. Besonders bei solchen Sachen wie z.&amp;amp;nbsp;B. einer großen Übersichtskarte (sei es nun die Strategiekarte für einen Schlachtplatz im Zweiten Weltkrieg, oder die Übersichtskarte eines Fantasyreiches) sind die Vorteile von OpenGL (wie an dem im Download enthaltenem Beispiel zu erkennen) gut ersichtlich. Das Scrollen wird durch einen einfachen Aufruf an [[glTranslate]]f erledigt (um die außerhalb des sichtbaren Bereichs liegenden Teile der Karte muss man sich dabei keine Sorgen machen), während man das vergrößern der Karte (~ zoomen) mit einem einfachem [[glScale]]f vollbringen kann.&lt;br /&gt;
&lt;br /&gt;
Und dank der Hardwarebeschleunigung wird diese Karte schneller angezeigt als man dies von Hand (oder über andere 2D-APIs je tun) könnte. Auf einer halbwegs modernen Grafikkarte sollten locker an die 1000 FpS drin sein.&lt;br /&gt;
&lt;br /&gt;
Nachdem man die Übersichtskarte geladen hat, gestaltet sich das Rendern selbiger als sehr einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBindTexture(GL_TEXTURE_2D, MapTex);&lt;br /&gt;
glTranslatef(MapPos.x, MapPos.y, 0);&lt;br /&gt;
glScalef(MapScale, MapScale, MapScale);&lt;br /&gt;
DrawQuad(0,0,0, MapSize.x,MapSize.y);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht schockierend einfach aus. Mehr braucht es nicht um eine Übersichtskarte zu scrollen und zu zoomen. Allerdings sollte man wie bereits einige Male erwähnt wurde auf die Hardwarelimiationen achten. Wenn die Übersichtskarte also allzu groß sein sollte, dann kann man diese ja ohne Probleme unterteilen und als mehrere Quads rendern. Außer der etwas abgeänderten Positionierung der einzelnen Kartenteile ändert sich aber am Grundprinzip nichts.&lt;br /&gt;
&lt;br /&gt;
==Tiling (Kachelung)==&lt;br /&gt;
''(Projektdatei: openGL2D_demo5)''&lt;br /&gt;
&lt;br /&gt;
Die oben genannte Technik mag zwar gut genug für statische Übersichtskarten sein, aber wenn man eine dynamische Karte aus der Vogelperspektive realisieren will, so kommt man mit einer riesigen vorgefertigten Textur nicht weit. Dafür gibt es dann aber eine Technik namens &amp;quot;Tiling&amp;quot;, was zu Deutsch so viel wie &amp;quot;Kachelung&amp;quot; heißt. Hier hat man ähnlich einem Schachbrett ein zweidimensionales Spielfeld das aus unterschiedlichen Kacheln besteht die als Texturen vorliegen. In einem zweidimensionalem Array wird dann für jedes Feld gespeichert welche Textur zu ihm gehört. Diese Technik ist immer noch recht weit verbreitet (zumindest im Hobbybereich) und für 2D-Spiele aus der Vogelperspektive recht gut geeignet, wobei hier der Großteil der Arbeit eher beim Grafiker als beim Programmierer liegt, denn da die Teils nur Vierecke darstellen müssen Übergänge von z.&amp;amp;nbsp;B. einem Terraintyp zum anderen in die Textur gezeichnet werden. &lt;br /&gt;
&lt;br /&gt;
Das Rendern eines solchen Spielfeldes gestaltet sich dabei sehr einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;for x := 0 to MapWidth-1 do&lt;br /&gt;
 for y := 0 to MapHeight-1 do&lt;br /&gt;
  begin&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, MapTexture[Map[x,y]]);&lt;br /&gt;
  DrawQuad(MapPos.x+x*32, MapPos.y+y*32, 0, 32,32);&lt;br /&gt;
  end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Allerdings ist obige Methode alles andere als optimiert. Das erste (und größte) Problem ist die Tatsache das unabhängig von aktuellen Betrachtungsposition immer die komplette Karte gerendert wird. Bei großen Karten (z.&amp;amp;nbsp;B. 128x128 Kacheln) gehen dann selbst moderne Karten in die Knie. Die Kacheln außerhalb des Sichtbereiches werden zwar von der Grafikkarte nicht gerendert (da sie außerhalb des Viewports liegen), aber müssen dennoch in jedem Frame über den Bus gesendet werden, genauso wie die Texturenwechsel in jedem Frame stattfinden müssen. Das erste Problem lässt sich recht schnell lösen, in dem wir einfach prüfen ob die aktuell zu rendernde Kachel auch im momentan sichtbarem Bereich liegt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(MapScale, MapScale, MapScale);&lt;br /&gt;
for x := 0 to High(Map) do&lt;br /&gt;
 for y := 0 to High(Map[x]) do&lt;br /&gt;
  if (MapPos.x + x*32 &amp;gt;= -16*MapScale) and (MapPos.x + x*32 &amp;lt;= SizeX/MapScale+16) and&lt;br /&gt;
     (MapPos.y + y*32 &amp;gt;= -16*MapScale) and (MapPos.y + y*32 &amp;lt;= SizeY/MapScale+16) then&lt;br /&gt;
      begin&lt;br /&gt;
      glBindTexture(GL_TEXTURE_2D, MapTex[Map[x,y]]);&lt;br /&gt;
      DrawQuad(MapPos.x+x*32, MapPos.y+y*32, 0, 32,32);&lt;br /&gt;
      end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der If-Abfrage, die wir vor dem Rendern einer jeden Kachel machen, prüfen wir jetzt ganz einfach ob die aktuelle Kachel im Sichtfeld liegt. Da wir eine dynamische Karte haben und die Vorteile von OpenGL nutzen wollen, müssen wir bei dieser Abfrage natürlich auch den Zoomfaktor (''MapScale'') und das Scrolling (''MapPos'') mit einbeziehen.&lt;br /&gt;
&lt;br /&gt;
Dank dieser offensichtlichen Optimierung dürften wir jetzt einen starken Performancegewinn von mehreren hundert Prozent sehen, denn sehr viele Texturenwechsel fallen weg und es wird sehr viel weniger Geometrie über den Bus gesendet. Aber natürlich sind wir noch nicht am Ende der Fahnenstange angelangt, denn wie gesagt sind Texturenwechsel recht performancelastig. Also liegt es nahe diese zu optimieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;for t := 0 to High(MapTex) do&lt;br /&gt;
 begin&lt;br /&gt;
 glBindTexture(GL_TEXTURE_2D, MapTex[t]);&lt;br /&gt;
 for x := 0 to High(Map) do&lt;br /&gt;
  for y := 0 to High(Map[x]) do&lt;br /&gt;
   if Map[x,y] = t then&lt;br /&gt;
    if (MapPos.x + x*32 &amp;gt;= -16*MapScale) and (MapPos.x + x*32 &amp;lt;= SizeX/MapScale+16) and&lt;br /&gt;
       (MapPos.y + y*32 &amp;gt;= -16*MapScale) and (MapPos.y + y*32 &amp;lt;= SizeY/MapScale+16) then&lt;br /&gt;
        DrawQuad(MapPos.x+x*32, MapPos.y+y*32, 0, 32,32);&lt;br /&gt;
 end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen haben wir unsere Schleife etwas umgebaut. Wir gehen jetzt in der Hauptschleife durch alle unsere Kacheln (abgelegt in ''MapTex'') und dann für jede Kachel die komplette Karte in beide Dimensionen durch. So binden wir jede Texur nur einmal und rendern dann alle Kacheln die diese Textur nutzen. Das klingt erstmal so (zumindest vom Schleifenaufbau her) als würden wir hier Performance vernichten, denn schliesslich gehen wir jetzt nicht einmal die komplette Karte durch, sondern so viele Male wie wir Kacheltexturen haben. Allerdings ist es meistens so das der CPU-Overhead durch die zusätzlichen Schleifendurchläuft weniger kostet als uns die gesparten Texturenwechsel eingebracht haben. Im Normalfall (es gibt natürlich Situationen wo der CPU-Overhead zu groß wird, z.&amp;amp;nbsp;B. bei wirklich riesigen Karten) sollten wir auch durch diese Optimierung einen Performancezuwachs im zweistelligen Prozentbereich erkennen.&lt;br /&gt;
&lt;br /&gt;
So viel also zum Thema Kachelung. Besonders für kleinere Projekte ist diese Technik ein guter Start und vor allem ist diese Technik leicht umzusetzen. Ist natürlich nicht mehr zeitgemäß, aber bei den meisten Hobbyprojekten geht es ja eher um den Inhalt und nicht nur um das Äußere. &lt;br /&gt;
&lt;br /&gt;
==Spezialeffekte==&lt;br /&gt;
&lt;br /&gt;
Nach diesem langen Marsch sind wir jetzt so ziemlich mit allen im 2D-Bereich verwendeten Techniken durch und können uns nun einem interessanterem Kapitel zuwenden; den Spezialeffekten. Hier ist der eigenen Kreativität natürlich keine (oder kaum, je nach Hardware) Grenze gesetzt, weshalb ich nur einige häufig unter 2D genutzte Effekte erwähnen möchte.&lt;br /&gt;
&lt;br /&gt;
===Beleuchtung (&amp;quot;Per-Pixel&amp;quot;)===&lt;br /&gt;
''(Projektdatei: openGL2D_demo6)''&lt;br /&gt;
&lt;br /&gt;
Beleuchtung ist ja (auch wenn man das nicht so wahrnimmt, da es ja im echten Leben selbstverständlich ist) eine Sache die man in keinem Spiel vernachlässigen sollte. Ohne korrekte Beleuchtung geht viel Atmosphäre flöten, aber besonders in einer 3D-Umgebung ist korrektes Per-Pixel-Licht (die OpenGL-Beleuchtung arbeitet auf Vertexbasis) oft schwer zu implementieren (was dank Shader aber leichter geworden ist). In einer 2D-Umgebung ist das aber zum Glück sehr viel einfacher, denn dort haben wir z.&amp;amp;nbsp;B. im Falle einer 2D-Karte ja keine dritte Dimension um die wir uns kümmern müssten, müssen unsere Lichtquellen also nicht auf die Szene draufprojizieren.&lt;br /&gt;
&lt;br /&gt;
In 2D geht das also ganz einfach und wir machen die Beleuchtung bequem über eine Lichttextur in der die Intensität der Lichtquelle abgelegt ist. Für die Demo habe ich dazu einen einfachen radialen Verlauf gewählt, aber der Fantasie sind da keine Grenzen gesetzt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_12.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Farbinformationen speichern wir nicht in der Textur, denn wir wollen ja dynamisch bleiben und realisieren die Färbung des Lichtes später in unserem Programm über einen [[glColor]]3f  Aufruf. Bevor wir allerdings loslegen, sollten noch ein paar Kleinigkeiten im Bezug auf diese (einfache Form der) Beleuchtung geklärt werden. Damit wir unsere Szene mit einer solchen Textur &amp;quot;beleuchten&amp;quot; können, nutzen wir additives Blending. Das bedeutet also das wir zur Farbe im Framepuffer (der unsere Karte zeigt) den Farbwert in unserer Lichttextur addieren. Dort wo unsere Textur also komplett weiß ist, haben wir auf der Karte die volle Lichtfarbe. Blending hat aber einen Nachteil, der in 3D oft sehr viel Kopfzerbrechen macht, aber in 2D leicht gelöst werden kann: Blending arbeitet &amp;quot;auf&amp;quot; dem Framepuffer, was also bedeutet das OpenGL in diesem Falle nicht für uns sortiert. Wenn wir dann also eine Lichttextur rendern die nahe am Betrachter ist und dahinter (im Raum) eine zweite Lichttextur rendern die weiter entfernt ist, werden wir diese nicht sehen, da im Framepuffer bereits die erste Lichttextur &amp;quot;liegt&amp;quot; (sprich dort der Z-Wert der ersten Textur abgelegt wurde und die Fragmente der zweiten Textur deshalb aufgrund des Z-Tests verworfen werden). Das ist natürlich nicht korrekt, aber in 2D lässt sich dieses Problem mit dem passenden Tiefentest lösen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glDepthFunc(GL_ALWAYS);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normalerweise sollte man diese Tiefenfunktion erst setzen bevor man die Lichtquellen zeichnet, sofern man vorher den Tiefenpuffer nutzen will um die Objekte auf seiner Karte in der Höhe zu sortieren. Denn wie der Name vermuten lässt bewirkt diese Form des Tiefentests das Fragmente (=&amp;quot;Pixel auf Probe&amp;quot;) immer rasterisiert werden, egal ob sie jetzt durch ein bereits im Frampuffer liegendes Fragment verdeckt werden würden oder nicht. Wenn wir mit diesem Tiefentest nun also zwei Lichtquellen übereinander rendern würden, werden diese korrekt angezeigt. Aber wie immer soll euch dieser etwas technisch klingende Text nicht aus dem Konzept bringen, weshalb ich dann hier folgende zwei Bilder reden lasse:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_13.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links sehen wir zwei sich überlappende Lichtquellen mit einem normalerweise verwendetem Tiefentest ('''GL_LEQUAL''' oder '''GL_LESS'''). Dass die grüne Lichtquelle die zweite verdeckt ist reiner Zufall und liegt wohl daran das diese als erstes gerendert wurde. Wie oben gesagt (vereinfacht) steht dann im Z-Puffer drin das an dieser Stelle (des grünen Lichtes) bereits ein Objekt im Z-Puffer liegt. Danach wird dann irgendwann die zweite (blaue) Lichtquelle gerendert, aber die Stellen an denen bereits steht dass dort im Z-Puffer ein Fragment liegt werden nicht mehr gerendert, aufgrund des Tiefentests. Das zweite Bild ist hingegen korrekt, einzig der Tiefentest wurde auf '''GL_ALWAYS''' umgestellt. Dann werden die mit der Lichttextur belegten Quads immer gezeichnet, egal ob sich an der Z-Position bereits ein Fragment befindet oder nicht, und bei Lichtquellen ist das reichlich egal welche zuerst gerendert wird. Denn ob ich jetzt Blau mit Grün addiere, oder Grün mit Blau ist egal, denn beides ergibt im Ende Türkis. Das dürfte dann hoffentlich verstanden worden sein, wenn nicht dann einfach mal das Beispielprogramm öffnen und den Tiefetest wie hier angesprochen ändern; Probieren geht je bekannter weise meist über Studieren.&lt;br /&gt;
&lt;br /&gt;
Abschließend auch noch kurz zum verwendeten Blendmodus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBlendFunc(GL_ONE, GL_ONE);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer sich schon mal ein wenig mit dem Thema Blending beschäftigt hat, wird schnell erkennen was hier abläuft. Sowohl der Quellfaktor als auch der Zielfaktor stehen auf '''GL_ONE''', was bedeutet dass bei unserer Blendoperation die bereits im Framepuffer befindliche Farbe mit der Farbe unseres Lichtes addiert wird (additives Blending genannt). Bei einer grünen Lichtquelle haben wir in der Mitte also RGB = 0/1/0 und wenn wir das dann auf einen Pixel legen würden der halb grau ist (RGB = 0,5/0,5/0,5) hätten wir als Ergebnis RGB = 0,5/1/0,5 (1+0,5 ist eigentlich 1,5 , aber OpenGL zwängt Farbwerte in den Bereich 0..1).&lt;br /&gt;
&lt;br /&gt;
===Texturenverläufe===&lt;br /&gt;
''(Projektdatei: openGL2D_demo7)''&lt;br /&gt;
&lt;br /&gt;
Im Kapitel &amp;quot;Kachelung&amp;quot; habe ich erwähnt, dass es eigentlich Aufgabe des Grafikers ist die Überläufe zwischen zwei unterschiedlichen Kacheln zu erstellen. Allerdings lässt sich das auch mit OpenGL bewerkstelligen, und zwar dank Blending und des Alphakanals. Dazu rendern wir zuerst ein Quad mit der ersten Kachel, und zwar dort wo diese Kachel komplett erscheinen soll mit vollem Alpha (vierter Parameter von [[glColor]]4f = 1) und dort wo später die andere Kachel komplett erscheinen soll mit Alpha = 0. Danach rendern wir an exakt der gleichen Stelle die zweite Kachel, müssen aber natürlich darauf achten das wir den richtigen Tiefentest aktiviert haben damit diese auch sichtbar ist ('''GL_ALWAYS''' oder '''GL_LEQUAL'''), allerdings mit genau umgekehrten Alphawerten und aktiviertem Blending. Fürs Blending nutzen wir als Quellfaktor '''GL_SRC_ALPHA''' und als Zielfaktor dann in logischer Konsequenz '''GL_DST_ALPHA'''. Dadurch wird dann im finalen Ergebnis dort wo die erste Kachel eine Alpha von 1 hat ihr kompletter Farbwert übernommen und dort wo die zweite Kachel einen Alpha von 1 hat deren voller Farbwert. Dazwischen wird in gewohnter Weise interpoliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glDisable(GL_BLEND);&lt;br /&gt;
glBindTexture(GL_TEXTURE_2D, TileA);&lt;br /&gt;
glBegin(gl_Quads);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(0,0); glVertex3f(-128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(1,0); glVertex3f( 128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(1,1); glvertex3f( 128,  128, 0);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(0,1); glvertex3f(-128,  128, 0);&lt;br /&gt;
glEnd;&lt;br /&gt;
&lt;br /&gt;
glEnable(GL_BLEND);&lt;br /&gt;
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);&lt;br /&gt;
glBindTexture(GL_TEXTURE_2D, TileB);&lt;br /&gt;
glBegin(gl_Quads);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(0,0); glVertex3f(-128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(1,0); glVertex3f( 128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(1,1); glVertex3f( 128,  128, 0);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(0,1); glVertex3f(-128,  128, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Allerdings wird das bei komplexeren Kachelübergängen recht aufwendig und endet in jeder Menge Overdraw, da man dann viele Übergänge rendern muss. Aber wer sich mal näher damit beschäftigen will, sollte einen Blick auf das &amp;quot;Verblendet&amp;quot;-Tutorial (Einsteiger) von Phobeus werfen, in dem auch diese Technik hier näher besprochen wird.&lt;br /&gt;
&lt;br /&gt;
===Schatten===&lt;br /&gt;
''(Projektdatei : openGL2D_demo8)''&lt;br /&gt;
&lt;br /&gt;
Im 3D-Bereich sind Schatten eigentlich immer noch die &amp;quot;Königsdisziplin&amp;quot; für jeden Programmierer, besonders wenn diese volumetrisch und vor allem auch korrekt sein sollen. Meist muss man dazu die Szene analysieren, Umrisse von 3D-Objekten generieren und auch noch diverse Spezialfälle beachten (Stichwort &amp;quot;Betrachter im Schattenvolumen&amp;quot;). In unserer heilen 2D-Welt geht das aber schon wie bei der Beleuchtung sehr viel einfacher und hat mit dreidimensionalen Schatten rein gar nichts gemeinsam.&lt;br /&gt;
&lt;br /&gt;
Hier gehen wir nämlich ganz einfach hin und täuschen Schatten vor indem wir unser Objekt (das dazu natürlich einen Alphakanal besitzen muss) mittels {{INLINE_CODE|glColor3f(0, 0, 0)}} schwarz machen und dann unter dem eigentlichen Objekt leicht versetzt (die Richtung des Versatzes kann man je nach Lichteinfall verändern) rendern. Über [[glScalef]] passen wir dann noch die Größe des Schattens an um einfach vermitteln zu können wie hoch sich unser Objekt befindet. Wenn wir also den Schatten eines Spielers rendern, dann kann der genauso groß sein wie der Spieler selbst, aber bei einem Flugzeug das hoch über dem Boden fliegt sollte der Schatten schon etwas verkleinert werden um einen Eindruck von der Flughöhe zu vermitteln.&lt;br /&gt;
&lt;br /&gt;
Rein programmiertechnisch sind Schatten in 2D (auch wenn diese keineswegs physikalisch korrekt sind) also genau das Gegenteil von 3D-Schatten: Einfach und ohne jegliche Hindernisse:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glPushMatrix;&lt;br /&gt;
 glBindTexture(GL_TEXTURE_2D, ShipTex);&lt;br /&gt;
 glEnable(GL_ALPHA_TEST);&lt;br /&gt;
 glAlphaFunc(GL_GREATER, 0.1);&lt;br /&gt;
 glScalef(0.75, 0.75, 0.75);&lt;br /&gt;
 glColor3f(0, 0, 0);&lt;br /&gt;
 DrawQuad(60,-60,1, 256,192);&lt;br /&gt;
glPopMatrix;&lt;br /&gt;
&lt;br /&gt;
glPushMatrix;&lt;br /&gt;
 glColor3f(1, 1, 1);&lt;br /&gt;
 glBindTexture(GL_TEXTURE_2D, ShipTex);&lt;br /&gt;
 glEnable(GL_ALPHA_TEST);&lt;br /&gt;
 glAlphaFunc(GL_GREATER, 0.1);&lt;br /&gt;
 DrawQuad(0,0,0, 256,192);&lt;br /&gt;
glPopMatrix;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Block rendern wir unser Objekt etwas verkleinert und nach unten/rechts versetzt, natürlich komplett schwarz. Danach müssen wir nur noch unser Objekt drüberrendern (in gewohnter Weise) und fertig ist unser Schatten:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_14.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
==Schlusswort==&lt;br /&gt;
&lt;br /&gt;
Das war es also zum Thema 2D in OpenGL. Ich hoffe stark das dieser doch recht ausführliche Bericht so ziemlich alle Bereiche abgedeckt hat und damit auch häufig gestellte Fragen beantwortet. Natürlich war das nicht alles was in diesem Bereich machbar ist, allerdings kann ich hier schlecht auf jeden Effekt eingehen, denn sonst könnte ich das Tutorial gleich als ein einige hundert Seiten starkes Buch verkaufen.&lt;br /&gt;
&lt;br /&gt;
Doch eines sei noch am Schluss gesagt: 2D ist zwar programmiertechnisch fast immer (besonders bei in 3D komplexen Sachen wie Beleuchtung und Schatten) sehr viel einfacher und man kommt dann auch meist schneller ans Ziel, allerdings ist hier die Erstellung des Inhalts meist aufwendiger. Während z.&amp;amp;nbsp;B. ein 3D-Terrain zwar von der Programmierung her aufwendiger ist, muss man dort am Ende nur eine Terraintextur draufkleben und fertig ist die Sache. In 2D muss man dies hingegen über Kacheln lösen und dann für jeden Übergang verschiedene Kacheln in einem Bildbearbeitungsprogramm erstellen. Oder zum Beispiel das in unserem letzten Beispiel verwendete Raumschiff; wenn man das in 3D über ein 3D-Modell animiert (Keyframes), dann ist es kaum Aufwand was am Modell zu verändern (andere Textur, Form ändern), aber in 2D liegen diese Animationen vorberechnet auf der Platte, und sobald man dann was am Raumschiff ändert, müssen auch alle Animationen geändert werden.&lt;br /&gt;
&lt;br /&gt;
Wie so oft im Leben muss man also abwägen was jetzt für die eigene Anwendung richtig ist. Essentiell reicht es sich die Frage ''&amp;quot;Ist es für mich aufwendiger in die 3D-Programmierung einzusteigen, oder es ist es aufwendiger den Content für meine 2D-Anwendung zu erstellen&amp;quot;'' zu beantworten, aber das kann ich euch nicht abnehmen, da müsst ihr selbst drauf antworten können. Außerdem sei noch gesagt das die moderne Generation der Computerspieler inzwischen 3D gewohnt ist, was dazu führt das 2D-Anwendungen dann spielerisch sehr überzeugen müssen.&lt;br /&gt;
&lt;br /&gt;
In dem Sinne also viel Spaß in der zweiten Dimension (die auch Spaß machen) kann. Und vergesst nicht: Ich WILL Feedback zu diesem Tutorial und außerdem will das DGL-Team sehen was ihr so mit unseren Tutorials auf die Beine stellt. Wenn dabei also was halbwegs brauchbares raus gekommen ist, lasst es uns wissen!&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:'''Sascha Willems''' (webmaster AT delphigl.de)&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_opengl2d_vcl|text=Delphi-VCL-Quelltexte und Windows-Binaries zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial Lektion 8]]|[[Tutorial_Matrix2]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|2D]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glCompressedTexImage&amp;diff=25651</id>
		<title>glCompressedTexImage</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glCompressedTexImage&amp;diff=25651"/>
				<updated>2012-03-21T14:56:44Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glCompressedTexImage =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glCompressedTexImage''' - Lädt eine komprimierte Textur direkt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Spezifikation ==&lt;br /&gt;
 procedure '''glCompressedTexImage1D'''(''target'': TGLenum; ''level'': TGLint;&lt;br /&gt;
                                  ''internalformat'': TGLenum; ''width'': TGLsizei;&lt;br /&gt;
                                  ''border'': TGLint; ''imageSize'': TGLsizei;&lt;br /&gt;
                                  '''const''' ''data'': PGLvoid); &amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glCompressedTexImage2D'''(''target'': TGLenum; ''level'': TGLint;&lt;br /&gt;
                                  ''internalformat'': TGLenum; ''width'': TGLsizei;&lt;br /&gt;
                                  ''height'': TGLsizei; ''border'': TGLint;&lt;br /&gt;
                                  ''imageSize'': TGLsizei; '''const''' ''data'': PGLvoid); &amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glCompressedTexImage3D'''(''target'': TGLenum; ''level'': TGLint;&lt;br /&gt;
                                  ''internalformat'': TGLenum; ''width'': TGLsizei;&lt;br /&gt;
                                  ''height: TGLsizei; ''depth'': TGLsizei;&lt;br /&gt;
                                  ''border'': TGLint; ''imageSize'': TGLsizei;&lt;br /&gt;
                                  '''const''' ''data'': PGLvoid); &amp;lt;br&amp;gt;&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;
! ''target''&lt;br /&gt;
| Gibt die Zieltextur an. Muss für '''glCompressedTexImage1D''' '''GL_TEXTURE_1D''', für '''glCompressedTexImage2D''' '''GL_TEXTURE_2D''' und für '''glCompressedTexImage3D''' '''GL_TEXTURE_3D''' sein. Für [[Cubemap|Cubemaps]] sind außerdem die symbolischen Konstanten '''GL_TEXTURE_CUBE_MAP_POSITIVE_X''', '''GL_TEXTURE_CUBE_MAP_NEGATIVE_X''', '''GL_TEXTURE_CUBE_MAP_POSITIVE_Y''', '''GL_TEXTURE_CUBE_MAP_NEGATIVE_Y''', '''GL_TEXTURE_CUBE_MAP_POSITIVE_Z''' und '''GL_TEXTURE_CUBE_MAP_NEGATIVE_Z''' erlaubt. &lt;br /&gt;
|-&lt;br /&gt;
! ''level''&lt;br /&gt;
| Gibt den Detailgrad für die gewünschte Textur an. &amp;lt;br&amp;gt;&lt;br /&gt;
''level'' '''0''' ist das Basisbild. Level n ist die n-te [[MipMaps|Mipmap]]-Reduzierung der Textur.&lt;br /&gt;
|-&lt;br /&gt;
! ''internalformat''&lt;br /&gt;
| Internes Format der komprimierten Texturdaten. Z.B. eine der symbolischen Konstanten '''GL_COMPRESSED_RGB_S3TC_DXT1''', '''GL_COMPRESSED_RGBA_S3TC_DXT1''', '''GL_COMPRESSED_RGBA_S3TC_DXT3''' oder '''GL_COMPRESSED_RGBA_S3TC_DXT5''' falls die [[OpenGL-Extensions|Extension]] [[GL_EXT_texture_compression_s3tc]] unterstützt wird.&lt;br /&gt;
|-&lt;br /&gt;
! ''width'',&lt;br /&gt;
| Breite = Anzahl der Pixel pro Zeile &amp;lt;br&amp;gt; muss als Wert 2^n (+ 2 * (border) ) für n Integerwerte haben.&lt;br /&gt;
|-&lt;br /&gt;
! ''height'',&lt;br /&gt;
| Höhe = Anzahl der Zeilen &amp;lt;br&amp;gt; muss als Wert 2^n (+ 2 * (border) ) für n Integerwerte haben&lt;br /&gt;
|-&lt;br /&gt;
! ''depth'',&lt;br /&gt;
| Tiefe = Anzahl der &amp;quot;Scheiben&amp;quot; &amp;lt;br&amp;gt; muss als Wert 2^n (+ 2 * (border) ) für n Integerwerte haben&lt;br /&gt;
|-&lt;br /&gt;
! ''border'',&lt;br /&gt;
| Pixelbreite des Texturrahmens. (0 für keinen Rahmen)&lt;br /&gt;
|-&lt;br /&gt;
! ''imageSize''&lt;br /&gt;
| Anzahl der Bytes der komprimierten Daten.&lt;br /&gt;
|-&lt;br /&gt;
! ''_data''&lt;br /&gt;
| Die komprimierten Texturdaten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die Befehle '''glCompressedTexImage*D''' werden benutzt, um Texturdaten direkt in komprimierter Form zu laden.&lt;br /&gt;
Diese Funktion wurde in OpenGL ab Version 1.3 eingeführt, um das Laden von Texturen zu verkürzen und um mehr Texturen auf der Grafikkarte abspeichern zu können.&lt;br /&gt;
&lt;br /&gt;
Die Syntax der einzelnen Funktionen ist ähnlich wie bei den korrespondierenden Funktionen zu [[glTexImage1D]], [[glTexImage2D]] bzw. [[glTexImage3D]].&lt;br /&gt;
&lt;br /&gt;
Mit den Parametern ''width'', ''height'' und ''depth'' kann die Breite, Höhe und Tiefe der Textur angegeben werden.&lt;br /&gt;
&lt;br /&gt;
''internalFormat'' definiert das Format, mit dem die Texturdaten intern abgespeichert werden sollen, zur Zeit werden jedoch von OpenGL noch keine komprimierten Formate unterstützt.&lt;br /&gt;
&lt;br /&gt;
Bisher ist es nur möglich über [[OpenGL-Extensions|Extensions]], wie z.B. [[GL_EXT_texture_compression_s3tc]], komprimierte Texturformate anzugeben :&lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGB_S3TC_DXT1'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente ist immer 1.0. &lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGBA_S3TC_DXT1'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente ist entweder 1.0 oder 0.0.&lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGBA_S3TC_DXT3'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente wird mit 4 Bits gespeichert.&lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGBA_S3TC_DXT5'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente ist gewichtetes Mittel von 8-Bit Werten.&lt;br /&gt;
&lt;br /&gt;
Mit ''border'' wird die Breite des Rahmens der Textur in Pixel festgelegt.&lt;br /&gt;
Obwohl bei den Befehlen [[glTexImage1D]], [[glTexImage2D]] bzw. [[glTexImage3D]] die Rahmenbreiten 0, 1 und 2 Pixel auf jeden Fall unterstützt werden, muss dies bei komprimierten Texturformaten nicht unbedingt der Fall sein.&lt;br /&gt;
&lt;br /&gt;
Über den Parameter ''imageSize'' gibt man die genaue Anzahl der Bytes an, die mit ''_data'' an die Funktion übergeben werden.&lt;br /&gt;
&lt;br /&gt;
Um eine geladene Textur in OpenGL zu nutzen ist auf jeden Fall noch die entsprechende Aktivierung mit [[glEnable]]('''GL_TEXTURE_1D''', '''GL_TEXTURE_2D''' oder '''GL_TEXTURE_3D''') nötig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
'''glCompressedTexImage''' ist erst ab OpenGL Version 1.3 oder höher nutzbar.&lt;br /&gt;
&lt;br /&gt;
Mit [[glGetIntegerv]] und dem Parameter '''GL_COMPRESSED_TEXTURE_FORMATS''' kann ermittelt werden, welche komprimierten Texturformate von der OpenGL-Implementation unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
[[glPixelStore]] und [[glPixelTransfer]] beeinflussen nicht das Dekodieren einer komprimierten Textur.&lt;br /&gt;
&lt;br /&gt;
Entsprechen die an die Funktion übergebenen Daten nicht dem Komprimierungformat, so verhält sich der Aufruf von '''glCompressedTexImage''' undefiniert.&lt;br /&gt;
&lt;br /&gt;
Es ist darauf zu achten, das die Komprimierungsformate nicht für alle Zieltexturen unterstützt werden müssen (die meisten Komprimierungsformat unterstützen nur zweidimensionale Texturen).&lt;br /&gt;
Nähere Informationen findet man in der Spezifikation der jeweiligen Extension.&lt;br /&gt;
&lt;br /&gt;
Texturierung hat im Farbindexmodus keinen Effekt.&lt;br /&gt;
&lt;br /&gt;
Keine Fehlermeldungen werden generiert, wenn man beim Aufruf von '''glCompressedTexImage''' folgende Punkte beachtet :&lt;br /&gt;
* ''_data'' zeigt auf Daten, die man über die Funktion [[glGetCompressedTexImage]] bekommen hat.&lt;br /&gt;
* ''target'', ''level'' und ''internalformat'' stimmen mit den Parametern ''target'', ''level'' und ''format'' von [[glGetCompressedTexImage]] überein.&lt;br /&gt;
* ''width'', ''height'', ''depth'', ''border'', ''internalformat'' und ''imageSize'' stimmen mit den Werten überein die man über die Funktion [[glGetTexLevelParameter]] mit den Parametern '''GL_TEXTURE_WIDTH''', '''GL_TEXTURE_HEIGHT''', '''GL_TEXTURE_DEPTH''', '''GL_TEXTURE_BORDER''', '''GL_TEXTURE_INTERNAL_FORMAT''' und '''GL_TEXTURE_COMPRESSED_IMAGE_SIZE''' bekommt, nachdem [[glGetCompressedTexImage]] aufgerufen wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_ENUM''' wird generiert, wenn ''target'' nicht '''GL_TEXTURE_1D, GL_TEXTURE_2D''' oder '''GL_TEXTURE_3D''' ist. (entsprechend der benutzten Funktion)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_ENUM''' wird generiert, wenn ''internalformat'' kein von der OpenGL-Implementierung unterstütztes komprimiertes Format ist. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''level'' kleiner 0 oder größer ld(max) ist, wobei max der Rückgabewert von '''GL_MAX_TEXTURE_SIZE''' ist. (ld = Logarithmus Dualis = Basis 2). &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''width'', ''height'' bzw. ''depth'' (je nach Funktion) kleiner als 0 oder größer als 2 + '''GL_MAX_TEXTURE_SIZE''' ist, oder die Bedingung  2^k + 2 * (border) (k=Integerwerte) nicht erfüllt. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''imageSize'' nicht der Anzahl der Bytes entspricht, die mit ''_data'' übergeben wurden.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn die übergebenen Daten nicht dem mit ''internalformat'' angegebenem Komprimierungsformat übereinstimmen.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''border'' keinen zulässigen Wert hat.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn eine '''glCompressedTexImage'''-Funktion in einem [[glBegin]]- und [[glEnd]]-Block aufgerufen wird. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn das Komprimierungsformat nicht für die mit ''target'' angegebene Zieltextur unterstützt wird.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn ''border'' &amp;gt; 0 und keine Texturränder vom Komprimierungsformat unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
== Zugehörige Wertrückgaben ==&lt;br /&gt;
[[glGetCompressedTexImage]]&lt;br /&gt;
&lt;br /&gt;
[[glGetTexLevelParameter]]&lt;br /&gt;
&lt;br /&gt;
[[glIsEnabled]] mit dem Token [[glIsEnabled#GL_TEXTURE_1D|GL_TEXTURE_1D]], [[glIsEnabled#GL_TEXTURE_2D|GL_TEXTURE_2D]] bzw. [[glIsEnabled#GL_TEXTURE_3D|GL_TEXTURE_3D]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glCompressedTexSubImage1D]], [[glCompressedTexSubImage2D]], [[glCompressedTexSubImage3D]], [[glGetCompressedTexImage]], [[glTexCoord]], [[glTexEnv]], [[glTexGen]], [[glTexImage1D]], [[glTexImage2D]], [[glTexImage3D]], [[glTexParameter]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|CompressedTexImage]]&lt;br /&gt;
[[Kategorie:GL1.3|CompressedTexImage]]&lt;br /&gt;
[[Kategorie:GL3|CompressedTexImage]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Quaternion&amp;diff=25650</id>
		<title>Quaternion</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Quaternion&amp;diff=25650"/>
				<updated>2012-03-21T14:54:51Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hamiltonsche Quaternionen ==&lt;br /&gt;
&lt;br /&gt;
=== Übersicht ===&lt;br /&gt;
Quaternionen bilden ein 4D-Zahlensystem ähnlich dem 2D-Zahlensystem der Komplexen Zahlen, jedoch sind sie bei der Multiplikation nicht kommutativ ( d.h. für Quaternionen q1, q2 gilt nicht immer: q1*q2 = q2*q1 ). Sie werden häufig zur Darstellung und einfachen Berechnung von Isometrien (Drehungen) im 3D-Raum verwendet, wobei sie hier deutlich anschaulicher sind als unitäre Matrizen (Rotationsmatrizen).&lt;br /&gt;
&lt;br /&gt;
=== Definition ===&lt;br /&gt;
Ein Quaternion q hat folgende, eindeutige Gestalt:&lt;br /&gt;
 q = a + b*i + c*j + d*k,&lt;br /&gt;
wobei a, b, c, d reele Zahlen darstellen und i, j, k Imaginäre Zahlen mit den Eigenschaften:&lt;br /&gt;
 i*i=j*j=k*k=-1&lt;br /&gt;
 i*j = k = -j*i&lt;br /&gt;
 j*k = i = -k*j&lt;br /&gt;
 k*i = j = -i*k&lt;br /&gt;
Die Quaternionen H bilden also einen 4-Dimensionalen Raum in den Komponenten a, b, c, d.&lt;br /&gt;
Man trennt dabei häufig den 3D-Raum der reinen Quaternionen V der Form v = b*i + c*j + d*k heraus.&lt;br /&gt;
&lt;br /&gt;
=== Grundlegende Arithmetik ===&lt;br /&gt;
&lt;br /&gt;
==== Addition ====&lt;br /&gt;
Die Addition zweier Quaternionen geschieht komponentenweise, also:&lt;br /&gt;
 q = a + bi+ cj + dk&lt;br /&gt;
 r = e + fi+ gj + hk&lt;br /&gt;
 q + r = (a + e) + (b + f)i + (c + g)j + (d + h)k&lt;br /&gt;
&lt;br /&gt;
==== Multiplikation ====&lt;br /&gt;
Die Multiplikation zweier Quaternionen geschieht wie auf den reelen Zahlen gewohnt mit gedachten Variablen i, j, k, wobei die oben definierten Eigenschaften zum Einsatz kommen:&lt;br /&gt;
 q*r = (a + bi+ cj + dk)*(e + fi+ gj + hk) =&lt;br /&gt;
     = ae + afi + agj + ahk  &lt;br /&gt;
       + bie + bifi + bigj + bihk&lt;br /&gt;
       + cje + cjfi + cjgj + cjhk&lt;br /&gt;
       + dke + dkfi + dkgj + dkhk&lt;br /&gt;
     = (a * e - b * f  - c * g - d * h)&lt;br /&gt;
       + (a * f + b * e + c * h - d * g)i&lt;br /&gt;
       + (a * g - b * h + c * e + d * f)j&lt;br /&gt;
       + (a * h + b * g - c * f + d * e)k &lt;br /&gt;
Man beachte im Allgemeinen: '''q*r &amp;lt;&amp;gt; r*q''' !&lt;br /&gt;
&lt;br /&gt;
==== Konjugation ====&lt;br /&gt;
Die Konjugation ist definiert durch:&lt;br /&gt;
 konj(q) = a - bi - cj - dk,&lt;br /&gt;
also die Inversion des Vorzeichens der Imaginären Anteile i, j, k.&lt;br /&gt;
Es lässt sich leicht zeigen, dass gilt:&lt;br /&gt;
 konj(konj(q)) = q&lt;br /&gt;
 konj(q*p) = konj(p)* konj(q)&lt;br /&gt;
 konj(q + p) = konj(q) + konj(p)&lt;br /&gt;
&lt;br /&gt;
==== Norm / Betrag ====&lt;br /&gt;
Die Norm ||q|| eines Quaternions Q ist definiert als:&lt;br /&gt;
  ||q|| = Sqrt(a*a + b*b + c*c + d*d) = Sqrt(q*konj(q))&lt;br /&gt;
&lt;br /&gt;
==== Inversion ====&lt;br /&gt;
Mit den obigen Funktionen lässt sich sehr leicht ein Quaternion h zu q berechnen, so dass gilt: h*q=q*h=1, denn:&lt;br /&gt;
 ||q||^2 = q * konj(q)&lt;br /&gt;
 &amp;lt;=&amp;gt; &lt;br /&gt;
 1 = (q * konj(q)) / ||q||&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
 h := konj(q) / ||q||&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
 =&amp;gt; 1 = q * h&lt;br /&gt;
Und weil offensichtlich ||q|| = ||konj(q)|| gilt, folgt &lt;br /&gt;
 ||q||&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; = ||konj(q)||&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; = konj(q)*konj(konj(q)) = konj(q)*q&lt;br /&gt;
Und damit:&lt;br /&gt;
 1 = h * q.&lt;br /&gt;
h ist also das multiplikativ invers zu q: h = q&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Injektion der Reelen und Komplexen Zahlen ===&lt;br /&gt;
Die reellen Zahlen lassen sich injektiv in die Quaternionen abbilden:&lt;br /&gt;
 x -&amp;gt; x + 0*i + 0*j + 0*k&lt;br /&gt;
Entsprechend für die komplexen Zahlen:&lt;br /&gt;
 x + y*i -&amp;gt; x+ y*i + 0*j + 0*k&lt;br /&gt;
Die zugehörigen Rechenregeln bleiben dabei erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Isometrien auf Quaternionen ===&lt;br /&gt;
==== Isometrien auf H ====&lt;br /&gt;
Die Isometrien der Quaternionen auf sich selbst (also die Isometrien des 4D-Raumes) lassen sich in Quaternionen beschreiben durch zwei Quaternionen P,Q, mit ||P||=||Q|| = 1 und den Abbildungen      &lt;br /&gt;
 &amp;amp;phi;(P,Q,.): H -&amp;gt; H,&lt;br /&gt;
 x -&amp;gt; &amp;amp;phi;(P,Q,x) := P*x*konj(Q) = P*x*Q&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;amp;psi;(P,Q,.): H -&amp;gt; H&lt;br /&gt;
 x -&amp;gt; &amp;amp;psi;(P,Q,x) := P*konj(x)*konj(Q) = P*konj(x)*Q&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei gilt für Quaternionen P',Q' mit ||P'||=||Q'||=1:&lt;br /&gt;
 &amp;amp;phi;(P,Q,&amp;amp;phi;(P',Q',.)) = &amp;amp;phi;(P*P',Q*Q',.)&lt;br /&gt;
 &amp;amp;phi;(P,Q,&amp;amp;psi;(P',Q',.)) = &amp;amp;psi;(P*P',Q*Q',.)&lt;br /&gt;
&lt;br /&gt;
 &amp;amp;psi;(P,Q,&amp;amp;psi;(P',Q',.)) = &amp;amp;phi;(P*Q',Q*P',.)&lt;br /&gt;
 &amp;amp;psi;(P,Q,&amp;amp;phi;(P',Q',.)) = &amp;amp;psi;(P*Q',Q*P',.),&lt;br /&gt;
was man ohne weiteres ausrechnen kann.&lt;br /&gt;
 &lt;br /&gt;
==== Isometrien auf V ====&lt;br /&gt;
Der Fall der Isometrien auf den reinen Quaternionen V (siehe Definition) ist der für die 3D Grafik interessante Fall. Sie stellen die Rotationen auf V dar und das in einer besonders leicht lesbaren Form. Sei also Q eine Quaternion der Norm 1, dann gehört dazu eine Isometrie auf V:&lt;br /&gt;
 &amp;amp;phi;(Q,.): V -&amp;gt; V&lt;br /&gt;
 x -&amp;gt; &amp;amp;phi;(Q,x) := &amp;amp;phi;(Q,Q,x) = Q*x*konj(Q) = Q*x*Q&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;,&lt;br /&gt;
wobei offensichtlich &amp;amp;phi;(-Q,.) = &amp;amp;phi;(Q,.), Q und -Q beschreiben also die selbe Drehung.&lt;br /&gt;
Und entsprechnd der Rechenregeln für &amp;amp;phi; auf H (siehe oben) gilt mit einem Quaternion Q' mit ||Q'||=1:&lt;br /&gt;
 &amp;amp;phi;(Q, &amp;amp;phi;(Q', x)) = Q*Q'*x*konj(Q')*konj(Q) = (Q*Q')*x*konj(Q*Q') = &amp;amp;phi;(Q*Q',x)&lt;br /&gt;
&lt;br /&gt;
Man kann Q sehr leicht zerlegen in:&lt;br /&gt;
 Q = cos(&amp;amp;alpha;) + sin(&amp;amp;alpha;)*P, 0&amp;lt;=&amp;amp;alpha;&amp;lt;=&amp;amp;pi;, P aus V, ||P|| = 1,&lt;br /&gt;
wobei dann &amp;amp;phi;(Q,x) eine Drehung von x (man beachte, dass dabei x aus V ist) um den Winkel 2*&amp;amp;alpha; um die Achse P darstellt.&lt;br /&gt;
&lt;br /&gt;
== Einige Implementationsdetails ==&lt;br /&gt;
Am besten speichert man ein Quaternion duch speichern der 4 Komponenten in einem Array (Reihenfolge: realteil, i, j, k - Komponente, bzw. a,b,c,d):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;    public sealed class Quaternion : ILinearTransformation&lt;br /&gt;
    {&lt;br /&gt;
        private double[] coords = new double[4];&amp;lt;/source&amp;gt;&lt;br /&gt;
Ein besonders spannender Konstruktor für Quaternion ist der, der &amp;quot;rotations-Quaternionen&amp;quot; erstellt. Übergeben wird also ein Vektor, der die Drehachse beschreibt, sowie ein passender Winkel:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        public Quaternion(double alpha, Vertex3 rotAxis)&lt;br /&gt;
        {&lt;br /&gt;
            alpha = (2.0*Math.PI/(360.0*2.0))* alpha;&lt;br /&gt;
&lt;br /&gt;
            coords[0] = 1.0;&lt;br /&gt;
            if (rotAxis.Magnitude &amp;lt; double.Epsilon)&lt;br /&gt;
                return;&lt;br /&gt;
            &lt;br /&gt;
            rotAxis.Normalize();&lt;br /&gt;
            double c = Math.Cos(alpha), s = Math.Sin(alpha);&lt;br /&gt;
            coords[0] = c; coords[1] = rotAxis[0] * s;&lt;br /&gt;
            coords[2] = rotAxis[1] * s; coords[3] = rotAxis[2] * s;&lt;br /&gt;
        }&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese Funktion ergibt sich ganz einfach aus der obigen Formel:&lt;br /&gt;
 Q = cos(&amp;amp;alpha;) + sin(&amp;amp;alpha;)*P, 0&amp;lt;=&amp;amp;alpha;&amp;lt;=&amp;amp;pi;, P aus V, ||P|| = 1,&lt;br /&gt;
denn d.h. der Realteil der Drehung muss auf cos(&amp;amp;alpha;) gesetzt werden und die Drehachse wird mit sin(&amp;amp;alpha;) multipliziert und in den reinen Imaginärteil gesteckt (die Komponenten i,j,k werden gerade zu x,y,z im Koordinatensystem).&lt;br /&gt;
&lt;br /&gt;
Außerdem sollte man die wesentlichen Operationen implementeiren, etwa:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        public Quaternion Conjugate()&lt;br /&gt;
        {&lt;br /&gt;
            return new Quaternion(coords[0], -coords[1], -coords[2], -coords[3]);&lt;br /&gt;
        }&amp;lt;/source&amp;gt;&lt;br /&gt;
Die Konjugation dreht also wie oben definiert gerade die Vorzeichen der Imaginärteile um.&lt;br /&gt;
&lt;br /&gt;
Genauso implementiert man die anderen Operationen nach:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt; ...&lt;br /&gt;
        public static Quaternion Multiply(Quaternion q1, Quaternion q2)&lt;br /&gt;
        {&lt;br /&gt;
            if (q1 == null) throw new ArgumentNullException(&amp;quot;q1&amp;quot;);&lt;br /&gt;
            if (q2 == null) throw new ArgumentNullException(&amp;quot;q2&amp;quot;);&lt;br /&gt;
            Quaternion result = new Quaternion();&lt;br /&gt;
            result.coords[0] = q1.coords[0] * q2.coords[0]&lt;br /&gt;
                                - q1.coords[1] * q2.coords[1]&lt;br /&gt;
                                - q1.coords[2] * q2.coords[2]&lt;br /&gt;
                                - q1.coords[3] * q2.coords[3];&lt;br /&gt;
            result.coords[1] = q1.coords[0] * q2.coords[1]&lt;br /&gt;
                                + q1.coords[1] * q2.coords[0]&lt;br /&gt;
                                + q1.coords[2] * q2.coords[3]&lt;br /&gt;
                                - q1.coords[3] * q2.coords[2];&lt;br /&gt;
            result.coords[2] = q1.coords[0] * q2.coords[2]&lt;br /&gt;
                                - q1.coords[1] * q2.coords[3]&lt;br /&gt;
                                + q1.coords[2] * q2.coords[0]&lt;br /&gt;
                                + q1.coords[3] * q2.coords[1];&lt;br /&gt;
            result.coords[3] = q1.coords[0] * q2.coords[3]&lt;br /&gt;
                                + q1.coords[1] * q2.coords[2]&lt;br /&gt;
                                - q1.coords[2] * q2.coords[1]&lt;br /&gt;
                                + q1.coords[3] * q2.coords[0];&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
 ...&lt;br /&gt;
        public Quaternion Inverse()&lt;br /&gt;
        {&lt;br /&gt;
            double mag = Magnitude;&lt;br /&gt;
            mag = mag * mag;&lt;br /&gt;
            if (mag == 0.0) return null;&lt;br /&gt;
            return Conjugate().Scale(1.0 / mag);&lt;br /&gt;
        }&amp;lt;/source&amp;gt;&lt;br /&gt;
Besonders spannend ist sicherlich auch das Anwenden eines Rotations-Quaternions auf ein Vertex. Diese Funktion entsteht, wenn man die oben genannte Funktion &amp;amp;phi; explizit aufschreibt und ausrechnet. Es ergibt sich dabei eine wenig spannende, aber sehr ausladende Rechnung, um am Ende alles richtig ausmultipliziert und nach komponente sortiert zu haben (nicht vergessen: man darf dabei nur reele Zahlen miteinander Tauschen, sowie reele Zahlen mit i,j,k. i,j,k aber letztere nie miteinander, sonst stimmen die Vorzeichen nicht! Um ein Produkt aus i,j,k loszuwerden verwendet man die Tabelle, welche unter der Definition der Quaternionen gegeben ist -- die Multiplikation war nicht kommutativ:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        public Vertex3 Apply(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            Vertex3 result = new Vertex3();&lt;br /&gt;
            double v0 = v[0];&lt;br /&gt;
            double v1 = v[1];&lt;br /&gt;
            double v2 = v[2];&lt;br /&gt;
            double a00 = coords[0] * coords[0];&lt;br /&gt;
            double a01 = coords[0] * coords[1];&lt;br /&gt;
            double a02 = coords[0] * coords[2];&lt;br /&gt;
            double a03 = coords[0] * coords[3];&lt;br /&gt;
            double a11 = coords[1] * coords[1];&lt;br /&gt;
            double a12 = coords[1] * coords[2];&lt;br /&gt;
            double a13 = coords[1] * coords[3];&lt;br /&gt;
            double a22 = coords[2] * coords[2];&lt;br /&gt;
            double a23 = coords[2] * coords[3];&lt;br /&gt;
            double a33 = coords[3] * coords[3];&lt;br /&gt;
            result[0] = v0 * (+a00 + a11 - a22 - a33) &lt;br /&gt;
                + 2 * (a12 * v1 + a13 * v2 + a02 * v2 - a03 * v1);&lt;br /&gt;
            result[1] = v1 * (+a00 - a11 + a22 - a33) &lt;br /&gt;
                + 2 * (a12 * v0 + a23 * v2 + a03 * v0 - a01 * v2);&lt;br /&gt;
            result[2] = v2 * (+a00 - a11 - a22 + a33) &lt;br /&gt;
                + 2 * (a13 * v0 + a23 * v1 - a02 * v0 + a01 * v1);&lt;br /&gt;
            return result;&lt;br /&gt;
        }&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einsatz von Quaternionen in der 3D-Grafik ==&lt;br /&gt;
Warum also sind Quaternionen nützlich in der 3D Grafik? &lt;br /&gt;
* Man kann sie einsetzen, um Rotationen platzsparend zu speichern. In einigen Anwendungen werden pro Objekt eine Rotationsmatrix samt Translation gespeichert, um die Ausrichtung eines Objektes zu beschreiben. Das ergibt 16 Werte pro Objekt. Nimmt man stattdessen Quaternionen (mit Norm 1) und einen Translationsvektor, ergeben sich 4+3=7 Werte, also weniger als die Hälfte.&lt;br /&gt;
* Multipliziert man Quaternionen mit Quaternionen, &amp;quot;dreht also das Objekt weiter&amp;quot;, ergeben sich 4x4=16 Multiplikationen und Additionen. Bei Rotationsmatrizen benötigt man mind. 3x3x3=27 Multiplikationen.&lt;br /&gt;
* Wendet man Quaternionen auf ein Vertex an (die entsprechen im obigen den Quaternionen V), dann kommt man auf 18 Multiplikationen. Bei Rotationsmatrizen sind es mind. 9. &lt;br /&gt;
* Will man Quaternionen (Norm 1) invertieren, muss man die drei i,j,k Komponenten mit einem minus versehen. Rotationsmatrizen werden durch systematisches vertauschen von 6 Werten [[Techniken zur Matrixinversion|invertiert]].&lt;br /&gt;
* Will man aus einem Quaternion eine Rotationsmatrix machen, etwa um sie per [[glLoadMatrix]] and OpenGl zu übergeben, benötigt man (indem man das Quaternionen einzeln mit i,j und k multipliziert, also den Einheitsvektoren) benötigt man 3*14 Multiplikationen. Matrizen kommen ohne Bearbeitung aus.&lt;br /&gt;
* Quaternionen beschreiben Rotationen  Q = cos(&amp;amp;alpha;) + sin(&amp;amp;alpha;)*P, 0&amp;lt;=&amp;amp;alpha;&amp;lt;=&amp;amp;pi;, P aus V, ||P|| = 1, also durch Rotationswinkel &amp;amp;alpha; und Drehachse P und sind damit auf einen Blick anschaulicher als eine Rotationsmatrix.&lt;br /&gt;
&lt;br /&gt;
Quaternionen sind also insbesondere dann nützlich, wenn man viele Objekte mit wenig Speicherplatz ablegen möchte und stark rekursiv abhängige Drehungen von den Objekten untereinander hat (etwa Finger an Hand an Unterarm an Oberarm an Schulter an Körper) und man damit viel rechnen muss. Zum reinen Darstellen sind sie dagegen Kontraproduktiv, da man sie zur Übergabe an OpenGl erst umrechnen muss. Dies entfällt bei manch anderen Render-Techniken, etwa Raytracing.&lt;br /&gt;
&lt;br /&gt;
=== Umstieg Matrizen Quaternionen ===&lt;br /&gt;
Da OpenGl Grafiker oft bereits einges an Erfahrung mit Matrizen haben, nur ein paar kleine Anmerkungen, wie beide Welten zusammenhängen.&lt;br /&gt;
&lt;br /&gt;
* Gespeichert werden die 4 Komponenten (a,b,c,d) des Quaternion, geschrieben immer als a + bi + cj + dk.&lt;br /&gt;
* Die Einheitsmatrix wird durch das Einheitsquaternion 1 + 0i + 0j + 0k ausgedrückt.&lt;br /&gt;
* Rotationen sind die Quaternionen mit Norm 1.&lt;br /&gt;
* Ein Vektor (x,y,z) wird in der Quaternionenwelt zu v := 0 + xi + yj + zk. Rotationsquaternionen Q werden dann angewendet durch Q*v*konj(Q). Siehe Implementationsdetails &amp;quot;Vertex3 Apply(Vertex3 v)&amp;quot;.&lt;br /&gt;
* Um Quaternionen an OpenGl zu übergeben, müssen die &amp;quot;Einheitsvektoren&amp;quot; 1i,1j,1k einzeln wie Vertices gerechnet werden, also Q*i*konj(Q), Q*j*konj(Q), Q*k*konj(Q). Wenn man dazu &amp;quot;Vertex3 Apply(Vertex3 v)&amp;quot; ein wenig abändert und wiederverwertbare Ergebnisse aufhebt, kann man viele Rechnungen sparen. Das Ergebnis setzt man dann als Spalten in die Matrix ein  und kann dann übergeben werden.&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Kamera1&amp;diff=25649</id>
		<title>Tutorial Kamera1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Kamera1&amp;diff=25649"/>
				<updated>2012-03-21T14:54:33Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Dreht sich das Universum um uns und andere philosophische Fragen=&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Sicherlich standen schon einige von euch vor dem Problem, wie man denn eine Kamera in OpenGl implementieren könnte. Es stellen sich einem dabei viele Probleme, z.B. wie kann ich die Kamera auf ein Objekt ausrichten. Oder wie sieht es mit Billboarding aus? Die Liste kann fast unendlich erweitert werden. Ich werde versuchen, ein paar dieser Probleme zu lösen und vielleicht schaffe ich es sogar, den Einen oder Anderen dazu zu bringen, selbst eigene Kameratechnische Probleme zu lösen.&lt;br /&gt;
&lt;br /&gt;
Wer SchodMC's Objekt xxx Tutorials gelesen hat, hat übrigens schon einiges an Vorwissen, das er hier prima wiederverwerten kann. Ich kann die Lektüre dieser gut gelungenen Werke vor dem Weiterlesen nur wärmstens empfehlen.&lt;br /&gt;
&lt;br /&gt;
==Die Kamera Analogie==&lt;br /&gt;
Dreht sich die Erde um die Sonne oder die Sonne um die Erde? Ist euch bewusst, dass diese Frage eigentlich nicht zu beantworten ist? Tatsächlich macht es, wenn man richtig darüber nachdenkt keinen Unterschied. Das könnt ihr selber überprüfen: Geht vor eure Haustür und stellt euch hin (pfui, es regnet - nein, macht es doch lieber drinnen). Dreht euch einmal im Kreis. Was habt ihr gesehen? Habt ihr euch nun im Universum gedreht oder das ganze Unviversum um euch herum? Eine seltsame Frage? ... Vielleicht hat`s der Ein oder Andere schon bemerkt... Für den Mensch der sich da grad im Regen gedreht hat, wäre beides denkbar. Tatsächlich macht es für das Auge keinen Unterschied. Es handelt sich nur um ein philosophisches Problem, besonders eines der westlich geprägten Welt, das ihr zu überwinden habt. Alles dreht sich um euch, nicht ihr darin. Also: Dreht ihr euch nach rechts, ist das gleichbedeutend damit, dass sich das Univerum unter euren Füssen nach links gedreht hat. Noch Fragen?&lt;br /&gt;
&lt;br /&gt;
In der Hoffnung euch jetzt alle komplett verwirrt zu haben, mache ich jetzt einfach mal weiter.&lt;br /&gt;
&lt;br /&gt;
==Darstellung von Objekten==&lt;br /&gt;
Bevor wir irgendwelche Objekte zeichnen, müssen wir uns erst einmal eine Welt ausdenken. Der zweite Punkt ist dann, zu definieren, wie diese Objekte dargestellt werden sollen. Mir sind unterschiedliche Ideen gekommen, die sich alle mit mehr oder weniger Aufwand realisieren lassen.&lt;br /&gt;
&lt;br /&gt;
Letztendlich habe ich mich an einer Weltraumszene festgehängt. Hier lässt sich so einiges zeigen. Besonderen dank an [http://www.delphigl.de Sascha Willems], der - freundlich wie er ist - gestattete, einen Satz seiner Texturen einzusetzen und gleich noch ein Paar Orte verriet, an denen man gute Sonnensystem-Texturen finden kann.&lt;br /&gt;
&lt;br /&gt;
Kommen wir nun zu den Objekten selbst. Wir wollen hier ein wenig OOP verwenden. Das bietet sich an, da es in unserem Fall vorteilhaft ist, einige Objekte voneinander abzuleiten zu können. Alle Objekte müssen 2 Eigenschaften besitzen: Position und Rotationsmatrix:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;  type&lt;br /&gt;
    //Basis Objekt&lt;br /&gt;
    TObjekt = class&lt;br /&gt;
    private&lt;br /&gt;
    public&lt;br /&gt;
      ObjektName : String;&lt;br /&gt;
      Rotation  : THomogeneousMatrix;&lt;br /&gt;
      Position  : TVertex;&lt;br /&gt;
      constructor Create; virtual;&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um die Planeten darzustellen, werden unterschiedliche Nachfolger dieses Objektes verwendet. Ich will auf diese nicht weiter eingehen, da sie an sich nichts mit unserem eigentlichem Interessensgebiet zu tun haben - den Kameras.&lt;br /&gt;
&lt;br /&gt;
==Das Kameraobjekt==&lt;br /&gt;
Bevor wir uns daran machen, über die Implementierung nachzudenken, sollten wir überlegen, was wir eigentlich haben wollen. Eine Kamera, das ist klar. Was soll sie können? Sie soll einmal aus der Sicht des Objektes schauen können, ein Objekt fest in den Blick nehmen und auch eine freie Ansicht bieten (Freie Bewegungen sind bislang nicht in den Beispielsource mit eingebaut. Eine freie Ansicht hingegen schon - steuerbar mit dem Joystick). Wir wollen aber keine stationäre Kamera, sondern eine die sich gleich noch mehr oder weniger automatisch bewegt.&lt;br /&gt;
&lt;br /&gt;
Wir brauchen außerdem die Möglichkeit, unterschiedliche Modi einzustellen und Zielobjekte festzulegen. Nicht zu vergessen auch eine Funktion, die eine Kameramatrix erzeugt und diese auch noch gleich an OpenGL weitergibt.&lt;br /&gt;
&lt;br /&gt;
Dies sollte uns für den Anfang erst einmal genügen. Fangen wir also an, uns die gewünschte Kamera zu bauen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    TLookMode = (lmFree, lmObjektSight, lmLookAtObjekt);&lt;br /&gt;
    TMoveMode = (mmFree, mmAttatched);&lt;br /&gt;
    TKamera = class(TObjekt)&lt;br /&gt;
    private&lt;br /&gt;
    public&lt;br /&gt;
      LookMode : TLookMode; //Ansichtsmodus&lt;br /&gt;
      MoveMode : TMoveMode; //Bewegungsmodus&lt;br /&gt;
&lt;br /&gt;
      LookTarget, MoveTarget : TKugel; //Ansichtsziel und Bewegungsziel&lt;br /&gt;
&lt;br /&gt;
      procedure UseMatrix; virtual; //Kamera-Matrix einsetzen&lt;br /&gt;
      constructor Create; override;&lt;br /&gt;
      procedure ResetView; //Ansicht zurücksetzen&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
==Implementation der Kameramodi==&lt;br /&gt;
===lmFree und lmObjektSight===&lt;br /&gt;
&lt;br /&gt;
Diese Modi haben einige Gemeinsamkeiten. lmObjektSight steht für die Blickrichtung, die ein Objekt hat, lmFree ist die frei wählbare Variante. Häufig gleichen sich diese Modi, wenn man z.B. das Objekt von dem aus man in die Welt schaut gleich auch vom Spieler gesteuert wird. Von der Implementierung her sind sie fast Identisch. Das Problem besteht darin, dass die Kameramatrix genau anders herum drehen muss, als wie das Objekt gedreht ist (siehe Kamera Analogie). Die Mathematiker haben das Problem für uns schon gelöst - mit invertierten Matrizen. Wir müssen also nicht einmal das Rad neu erfinden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    procedure TKamera.UseMatrix;&lt;br /&gt;
    var&lt;br /&gt;
      RotMatrix : THomogeneousMatrix;&lt;br /&gt;
      Pos : TVertex;&lt;br /&gt;
&lt;br /&gt;
    begin&lt;br /&gt;
      //Ansichten&lt;br /&gt;
      case LookMode of&lt;br /&gt;
        lmFree     : begin&lt;br /&gt;
                       RotMatrix := Rotation;&lt;br /&gt;
                       InvertMatrix(RotMatrix)&lt;br /&gt;
                     end;&lt;br /&gt;
        lmObjektSight: begin&lt;br /&gt;
                         Assert(Assigned(LookTarget));&lt;br /&gt;
                         Rotation := LookTarget.Rotation;&lt;br /&gt;
                         RotMatrix := Rotation;&lt;br /&gt;
                         InvertMatrix(RotMatrix)&lt;br /&gt;
                       end&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      //Bewegungen&lt;br /&gt;
      case MoveMode of&lt;br /&gt;
        mmFree     : begin&lt;br /&gt;
                       Pos := Position&lt;br /&gt;
                     end;&lt;br /&gt;
        mmAttatched : begin&lt;br /&gt;
                       Assert(Assigned(MoveTarget));&lt;br /&gt;
                       Position := MoveTarget.Position;&lt;br /&gt;
                       Pos := Position;&lt;br /&gt;
                     end;&lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
      //Matrix einlegen&lt;br /&gt;
      glLoadMatrixf(@RotMatrix[0,0]);&lt;br /&gt;
      glTranslatef(-Pos[0], -Pos[1], -Pos[2])&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
War doch schon mal gar nicht so schwer, oder? &lt;br /&gt;
&lt;br /&gt;
===lmLookAtObjekt===&lt;br /&gt;
Nun wollen wir ein Objekt in den Fokus der Kamera nehmen. Voraussetzung ist, dass wir bereits die Koordinaten unserer Kamera kennen, denn sonst können wir nicht bestimmen, in welcher Richtung das Objekt liegt.&lt;br /&gt;
&lt;br /&gt;
Wir müssen uns entscheiden: Wollen wir eine komplett neue Matrix erstellen, oder wollen wir die bereits bestehende Rotationsmatrix verwenden und sie so manipulieren, dass die Kamera auf das Objekt ausgerichtet ist? Ich habe mich für letztere Variante entschieden, da man dieses Wissen in Spielen auch anderorts wiederverwerten kann.&lt;br /&gt;
&lt;br /&gt;
Kommen wir also zur Idee, die hinter unserem Problem steckt: Ich hab eine Rotationsmatrix und die Globale Richtung von unserem Objekt zu unserem Zielpunkt. Drehen wir nun diese Globale Richtung in das lokale Koordinatensystem unseres Objektes, so können wir die Winkel errechnen, die nötig sind, um unsere Kamera auf das Ziel auszurichten.&lt;br /&gt;
&lt;br /&gt;
'''Das Problem:''' Ein Problem, das sich mir beim Nachdenken über diese Idee gestellt hat, ist, dass die Blickrichtung von OpenGl immer in die negative Z-Richtung geht. An sich wird das Problem nicht wesentlich schwieriger, man muss nur an ein paar geschickten Stellen ein Minus verteilen, bzw. Minuend und Subtrahend vertauschen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir einmal davon aus, dass wir die globale Richtung in die lokale transformiert haben. Wie kommen wir nun an unsere Rotationsmatrix? Bzw. wie kommen wir an die benötigten Kosinus- und Sinuswerte? Zuerst wollen wir um die y-Achse drehen. Deshalb können wir den y-Wert der lokalen Richung erst einmal außer Acht lassen. Setzen wir diesen auf 0 und normalisieren unseren Vektor. Wir erhalten dadurch einen Vektor auf dem Einheitskreis - Vorteil: wir müssen unseren Sinus und Cosinus nicht kompliziert errechnen, denn wir haben ihn bereits. Keine Arbeit mehr für uns. Matrix erzeugen und wir haben fertig.&lt;br /&gt;
&lt;br /&gt;
Jetzt haben wir die Kamera um die y-Achse ausgerichtet. Es fehlt noch die x-Achse. Wir haben bereits einiges an Vorarbeit geleistet. Wir können ganz einfach den Winkel zwischen der lokalen Richtung und dem Vektor auf dem Einheitskreis von vorhin berechnen. Sind beides Einheitsvektoren, so ist das Skalarprodukt(zu Englisch Dotproduct) der Kosinus des gesuchten Winkels. Wie sicher Einigen bekannt ist, gilt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;'''Cos²(α) + Sin²(α) = 1'''&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir kennen also auch den Wert des Sinus. Nur das Vorzeichen ist uns dann noch unbekannt. Dies ergibt sich aber daraus, ob der y-Wert der lokalen Richtung positiv oder negativ ist.&lt;br /&gt;
&lt;br /&gt;
Ich würde sagen Problem gelöst, hier der passende Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    procedure LockTarget(Target : TObjekt);&lt;br /&gt;
    var&lt;br /&gt;
      InvMatrix, M1, M2 : THomogeneousMatrix;&lt;br /&gt;
      ObjektPosition : TVertex;&lt;br /&gt;
&lt;br /&gt;
      Cos, Sin : Single;&lt;br /&gt;
      xzEbenenPosition : TVertex;&lt;br /&gt;
    begin&lt;br /&gt;
      try&lt;br /&gt;
        InvMatrix := Rotation;&lt;br /&gt;
        InvertMatrix(InvMatrix);&lt;br /&gt;
&lt;br /&gt;
        //Globale Objekt Position&lt;br /&gt;
        ObjektPosition := VectorSubtract(Position, Target.Position);&lt;br /&gt;
        //In lokale Koordinaten drehen&lt;br /&gt;
        ObjektPosition := VectorTransform(ObjektPosition, InvMatrix);&lt;br /&gt;
&lt;br /&gt;
        xzEbenenPosition[0] := ObjektPosition[0];&lt;br /&gt;
        xzEbenenPosition[1] := 0;&lt;br /&gt;
        xzEbenenPosition[2] := ObjektPosition[2];&lt;br /&gt;
        if not((xzEbenenPosition[0] = 0.0) and (xzEbenenPosition[2] = 0.0)) then&lt;br /&gt;
        begin&lt;br /&gt;
          NormalizeVector(xzEbenenPosition);&lt;br /&gt;
          M1 := CreateRotationMatrixY(xzEbenenPosition[0], xzEbenenPosition[2])&lt;br /&gt;
        end&lt;br /&gt;
        else&lt;br /&gt;
          M1 := IdentityHmgMatrix;&lt;br /&gt;
&lt;br /&gt;
        NormalizeVector(ObjektPosition);&lt;br /&gt;
        Cos := VectorDotProduct(xzEbenenPosition, ObjektPosition);&lt;br /&gt;
        Sin := Sqrt(1- Cos*Cos);&lt;br /&gt;
&lt;br /&gt;
        if (ObjektPosition[1] &amp;gt; 0.0) then&lt;br /&gt;
          Sin := - Sin;&lt;br /&gt;
        M2 := CreateRotationMatrixX(Sin, Cos);&lt;br /&gt;
&lt;br /&gt;
        RotMatrix := MatrixMultiply(M1, M2);&lt;br /&gt;
        Rotation := MatrixMultiply(RotMatrix, Rotation);&lt;br /&gt;
        RotMatrix := Rotation;&lt;br /&gt;
        InvertMatrix(RotMatrix)&lt;br /&gt;
      except&lt;br /&gt;
        RotMatrix := IdentityHmgMatrix&lt;br /&gt;
      end&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorwärts, Rückwärts, Links, Rechts, Hoch, Runter==&lt;br /&gt;
Eine in Ego Shootern als Strafen bezeichnete Art sich zu bewegen, ist das Bewegen der Kamera in eine bestimmte Richtung, die von der Ausrichtung der Kamera abhängt. Dies beschreibt ein recht häufig auftretendes Problem im Zusammenhang mit Kameras. An sich ist es nicht weiter schwer, z.B. entspricht links Strafen dem Bewegen entlang der negativen x-Achse im lokalen Koordinatensystem der Kamera. Will man also die Position der Kamera in dieser Art manipulieren, so erstellt man einfach einen Vektor, der in der zur Kamera lokalen Richtung zeigt (im Beispiel also: [-1, 0,0]). Dann dreht man mit Hilfe der Rotationsmatrix der Kamera diesen Vektor ins globale Koordinatensystem und addiert ihn zum Positionsvektor der Kamera. (Allen denen es nicht aufgefallen ist: Das war eine Kurzfassung der Mathematik in SchodMCs &amp;quot;Objekt gedreht und dennoch nach vorne bewegt&amp;quot; Tutorial).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Billboarding==&lt;br /&gt;
Eine weitere Kameraspezifische Sache ist das Billboarding. Das Problem stellt sich einem, wenn man eine Partikelengine schreibt und die Polygone immer parallel zur Kamera ausgerichtet sein sollen. Man muss hierfür einfach die Rotation aus der Matrix entfernen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    procedure Billboard;&lt;br /&gt;
    const&lt;br /&gt;
      NewModelView : Array[0..11] of TGLFloat =&lt;br /&gt;
        (1,0,0,0,0,1,0,0,0,0,1,0);&lt;br /&gt;
    var&lt;br /&gt;
      Modelview : Array[0..15] of TGLFloat;&lt;br /&gt;
&lt;br /&gt;
    begin&lt;br /&gt;
      // Modelview Matrix holen&lt;br /&gt;
      glGetFloatv(GL_MODELVIEW_MATRIX , @Modelview[0]);&lt;br /&gt;
      Move(NewModelView[0], ModelView[0], SizeOf(NewModelview));&lt;br /&gt;
      glLoadMatrixf(@Modelview[0])&lt;br /&gt;
    end;&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
Der Renderer des Kameratutorials könnte dann so abgeändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;    ...&lt;br /&gt;
    //Kamera initialisieren&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
    Kamera.UseMatrix;&lt;br /&gt;
&lt;br /&gt;
    //Planeten rendern&lt;br /&gt;
    for I := Low(Planeten) to High(Planeten) do&lt;br /&gt;
      if i &amp;lt;&amp;gt; 3 then&lt;br /&gt;
      Planeten[I].Render;&lt;br /&gt;
&lt;br /&gt;
    with Planeten[3] do&lt;br /&gt;
      glTranslatef(Position[0], Position[1], Position[2]);&lt;br /&gt;
&lt;br /&gt;
    Billboard;&lt;br /&gt;
&lt;br /&gt;
    glBegin(GL_QUADS);&lt;br /&gt;
      glVertex3f(-10, -10, 0);&lt;br /&gt;
      glVertex3f(10, -10, 0);&lt;br /&gt;
      glVertex3f(10, 10, 0);&lt;br /&gt;
      glVertex3f(-10, 10, 0);&lt;br /&gt;
    glEnd();&lt;br /&gt;
    ...&amp;lt;/source&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
Ich habe jetzt beschlossen, dass ich hier einmal aufhöre. Das Geschreibe ist doch recht anstrengend und ich will euch doch nicht alle Ideen vorwegnehmen. Deshalb wünsch ich euch jetzt viel Spass beim Rumprobieren&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
:'''Delphic'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nachtrag===&lt;br /&gt;
:Weitere Hinweise zum erstellen von Kameraklassen findet ihr im Artikel [[Kamera (1)]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_kameras_src_vcl|text=Beispiel-Quelltext (Delphi)}}&lt;br /&gt;
* {{ArchivLink|file=tut_kameras_exe|text=Beispiel-Programm}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial TexFilter]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Kamera1]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Skyboxen&amp;diff=25648</id>
		<title>Tutorial Skyboxen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Skyboxen&amp;diff=25648"/>
				<updated>2012-03-21T14:54:13Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Skyboxen=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Teil 1: Die Texturen mit Terragen erzeugen==&lt;br /&gt;
Dieser Teil des Tutorials beschäftigt sich mit dem Erstellen der für eine Skybox benötigten Texturen mit Hilfe des Programms [http://www.planetside.co.uk/terragen Terragen]. Sie sollten jedoch grundlegende Kenntnisse über dieses Programm besitzen, da ich nicht zu sehr ins Detail gehen werde. Ich werde nur die Schritte erklären, die nötig sind, um ein grundlegendes Terrain zu erstellen und die Skybox zu rendern. Sie sollten also zuerst besser das Online-Tutorial zu Terragen lesen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn Terragen gestartet wird, erscheint die Oberfläche wie abgebildet:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox01.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wir bechäftigen uns zuerst mit dem rechten Fenster, um unsere Landschaft zu generieren. Wählen Sie es aus und klicken sie auf den &amp;quot;Generate Terrain&amp;quot;-Button, um den folgenden Dialog zu öffnen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox02.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In der Auswahlbox &amp;quot;Method&amp;quot; kann die zur Landschaftsgenerierung genutzte Methode gewählt werden, die mit den Optionen auf der rechten Seite noch angepasst werden kann. Ich habe mich dazu entschieden, für dieses Tutorial einen Canyon zu generieren. Klicken Sie nach ihrer Wahl auf &amp;quot;Generate Terrain&amp;quot; und Sie werden Ihre neu generierte Landschaft im &amp;quot;Landscape&amp;quot;-Dialog sehen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox03.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn Ihnen das generierte Terrain nicht gefällt, können Sie es mit den oberen drei Buttons nachträglich anpassen.&lt;br /&gt;
&lt;br /&gt;
Der Punkt, von dem drei Linien ausgehen, ist die Position des Betrachters. Mit einem Linksklick kann man dessen Position und mit einem Rechtsklick dessen Blickpunkt ändern.&lt;br /&gt;
Jetzt ist es Zeit die Oberflächentextur zu wählen. Sie könnten zwar selbst eine generieren, da dies jedoch sehr zeitintensiv ist ,habe ich mich dazu entschieden, eine der mit Terragen gelieferten Vorlagen zu öffnen. Klicken Sie dazu auf den &amp;quot;Open...&amp;quot;-Button in der &amp;quot;Surface Map&amp;quot;-Sektion des Dialogs und wählen Sie eine Vorlage aus. Natürlich kann diese im Nachhinein noch abgeändert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und jetzt zum &amp;quot;Rendering&amp;quot;-Dialog:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox04.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Oben links können Sie eine Vorschau Ihrer Landschaft sehen, welche mit dem &amp;quot;Render Preview&amp;quot;-Button aktualisiert werden kann. Aber benutzen Sie nicht die höchste Detailstufe, nur um die Vorschau zu rendern, da dies sonst relativ lange dauern kann. Diese Detailstufe sollte nur zum endgültigen Rendern genutzt werden, während für das Preview die mittlere Stufe ausreicht.&lt;br /&gt;
&lt;br /&gt;
Unter &amp;quot;Image Size&amp;quot; können Sie die Größe Ihrer Skyboxtexturen wählen. Für eine Skybox sollten Höhe und Breite gleich sein. Ich habe 512x512 Pixel gewählt, so das die Skybox später detailliert genug aussieht, um einen realisitschen Eindruck zu vermitteln. Aber vergessen Sie nicht, das größere Texturen mehr Speicher benötigen und Performance kosten.&lt;br /&gt;
Bevor Sie die Skybox rendern können, müssen noch einige Einstellungen geändert werden, um das benötigte 90° Sichtfeld zu erhalten. Klicken Sie auf &amp;quot;Camera Settings&amp;quot; um den folgenden Dialog zu öffnen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox05.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für das korrekte Sichtfeld müssen Sie den &amp;quot;Zoom&amp;quot;-Wert auf 1 setzen. Danach können Sie diesen Dialog auch schon wieder schliessen und zum &amp;quot;Rendering Control&amp;quot;-Dialog wechseln. Setzen Sie dort alle Werte für die Kameraausrichtung (&amp;quot;Camera orientation&amp;quot;) auf 0.&lt;br /&gt;
Nachdem Sie den Detailschieber auf Maxmimum gesetzt haben- sind Sie Bereit die Texturen zu rendern. Der erste Teil wird bei einer Kopfausrichtung (&amp;quot;head orientation&amp;quot;) von 0° generiert und stellt ihr hinteres Bild dar. Das rechte wird bei 90°, das vordere bei 180° und das linke bei 270° gerendert.&lt;br /&gt;
Setzen Sie die Kopfausrichtung jetzt wieder auf 0° und den &amp;quot;Pitch&amp;quot; auf 90°, um den Himmel zu rendern, also ihr oberes Bild. Die untere Textur für die Skybox wird bei einem &amp;quot;Pitch&amp;quot; von -90° gerendert.&lt;br /&gt;
Die hier von mir gewählten Namen sind natürlich unverbindlich und an das Beispielprogramm angepasst.&lt;br /&gt;
&lt;br /&gt;
Hier die 6 Texturen meiner Skybox:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
{|rules=&amp;quot;all&amp;quot; border = &amp;quot;1&amp;quot;&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox10.jpg]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox06.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox07.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox08.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox09.jpg]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox11.jpg]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Teil 2 - Nutzung der Skybox in OpenGL==&lt;br /&gt;
Nachdem Sie nun ihre Skyboxtexturen generiert haben, ist es Zeit, sie in Ihrer OpenGL-Anwendung zu nutzen. Ich werde hier nicht die Grundschritte zur Erstellung eines Renderkontextes oder zur Darstellung von Dreiecken zeigen. Wenn Sie darüber mehr wissen wollen, suchen sie eine der diversen OpenGL Seiten mit Tutorials zu diesen Themen auf.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 1 - Die Texturen laden===&lt;br /&gt;
Texturen mit der TglBMP Klasse zu laden ist sehr leicht. Der Einfachheit halber bevorzuge ich es, alle Texturen der Skybox in einem Array zu organisieren. Außerdem nutze ich lokal in der Ladeprozedur ein Array in dem alle Dateinamen abgelegt sind, so dass die Texturen leicht in einer Schleife geladen werden können:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure TGLForm.LoadSkyBox;&lt;br /&gt;
const&lt;br /&gt;
 SkyBoxName : array[0..5] of String = ('BK', 'FR', 'DN', 'UP', 'LF', 'RT');&lt;br /&gt;
var&lt;br /&gt;
 i : Integer;&lt;br /&gt;
begin&lt;br /&gt;
for i := 0 to High(SkyBoxTexture) do&lt;br /&gt;
 begin&lt;br /&gt;
 SkyBoxTexture[i] := TGLBmp.Create;&lt;br /&gt;
 SkyBoxTexture[i].LoadImage(SkyBoxName[i]+'.jpg');&lt;br /&gt;
 SkyBoxTexture[i].SetTextureWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);&lt;br /&gt;
 SkyBoxTexture[i].GenTexture(False, False);&lt;br /&gt;
 end;&lt;br /&gt;
GenerateSkyBox(256, 256, 256);&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das global deklarierte SkyBoxTexture-Array beinhaltet unsere sechs Texturen und im lokal deklarierten SkyBoxName-Array befinden sich alle zugehörigen Dateinamen für jede Textur, so dass Sie die Ladeprozedur ganz einfach an Ihre Namenskonventionen anpassen können.&lt;br /&gt;
Zuerst laden wir die Texturen in einer Schleife. Dabei muss jedesmal die TglBMP Klasse erstellt werden, dann wird die Bilddatei geladen und der Texturewrap auf GL_CLAMP_TO_EDGE für die S und die T Koordinate gesetzt. Dies ist nötig damit unsere Kanten passend aneinandergefügt werden.&lt;br /&gt;
&lt;br /&gt;
Beachten Sie auch, dass ich die GenTexture-Prozedur der TglBMP-Klasse abgeändert habe. Ihr werden jetzt zwei Parameter vom Typ BOOLEAN übergeben, wobei der erste angibt, ob die Textur im komprimierten S3-Format geladen gibt und der zweite, ob das anisotropische Filtering genutzt werden soll. Wenn Sie diese Eigenschaften nutzen wollen, müssen Sie sich jedoch zuerst davon versichern, dass die Grafikkarte diese unterstützt.&lt;br /&gt;
&lt;br /&gt;
Sie sollten jedoch davon absehen, Ihre Skybox Texturen komprimiert zu laden weil dadurch die Qualität stark herabgesetzt werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 2 - Die Displayliste erstellen===&lt;br /&gt;
Nachdem die Texturen geladen wurden, generieren wir die Displayliste für unsere Skybox. Wie Sie bereits wissen sollten, sind Displaylisten um ein Vielfaches schneller, als die Quads in jedem Frame neu zu zeichnen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure TGLForm.GenerateSkyBox(pWidth, pHeight, pLength : TGLFloat);&lt;br /&gt;
var&lt;br /&gt;
 px,py,pz : TGLFloat;&lt;br /&gt;
begin&lt;br /&gt;
List := glGenLists(1);&lt;br /&gt;
glNewList(List, GL_COMPILE);&lt;br /&gt;
 px := - pWidth  / 2;&lt;br /&gt;
 py := - pHeight / 2;&lt;br /&gt;
 pz := - pLength / 2;&lt;br /&gt;
 SkyBoxTexture[0].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py,           pz);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py,           pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[1].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px,          py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px,          py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px + pWidth, py,           pz + pLength);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[2].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py, pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[3].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[4].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px, py,           pz);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px, py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[5].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px + pWidth, py,           pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
glEndList;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieser Teil des Quelltextes ist sehr einfach zu verstehen. Die Variablen px, py und pz werden genutzt, um die Skybox zu zentrieren. Dann wird ein Quader mit den Kantenlängen pWidth, pHeight und pLength und den zugehörigen Texturen in unsere Displayliste kompiliert. Der erste Quad ist die hintere Seite, der zweite die vordere Seite, der dritte ist der Boden, der vierte der Deckel, der fünfte die linke Seite und der letzte ist die rechte Seite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 3 - Die Skybox zeichnen===&lt;br /&gt;
Bevor wir die Skybox nun zeichnen '''deaktivieren wir das Schreiben in den Tiefenpuffer''' via [[glDepthMask]]. So vermeiden wir dass später gerenderte Objekte durch den von der Skybox geschriebenen Tiefenwert betroffen werden :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glDepthMask(False);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Aufgerufen wird die Skybox nun über ihre Displayliste :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
glClear(GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
glRotatef(xrot, 1, 0, 0);&lt;br /&gt;
glRotatef(yrot, 0, 1, 0);&lt;br /&gt;
glCallList(List);&lt;br /&gt;
SwapBuffers(FDC);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einleitend wechseln wir in die Modelansichtsmatrix und laden dort die Grundmatrix. Dann muss nur der Tiefenpuffer gelöscht (und eventuell andere verwendete Puffer) werden, den Farbpuffer müssen Sie nicht mehr löschen, da die Skybox den ganzen Schirm füllt. Jetzt muss unsere Matrix nur noch entsprechend dem Sichtwinkel des Betrachters rotiert werden, bevor unsere Displayliste aufgerufen wird. An die Spielerposition wird hier natürlich nicht transformiert, da die Skybox ja unendlich weit vom Spieler entfernt sein soll.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dem Rendern der Skybox müssen wir das Schreiben in den Tiefenpuffer natürlich wieder aktivieren :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glDepthMask(True);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Kleiner Hinweis :'' Wer möchte kann die beiden [[glDepthMask]]-Aufrufe natürlich auch direkt in der oben erstellten Displayliste ablegen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jetzt könnte zusätzlich noch eine animierte Wolkenschicht wie in Quake3 oder Unreal zu sehen hinzugefügt werden. Eine Alternative zu einer Skybox sind übrigens [[Skydome]]s, die mittels passender Formeln (und evtl. auch [[Shader]]n) dynamischer gestaltet werden können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hinweise==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Größe der Texturen===&lt;br /&gt;
Je nach Anwendung bzw. Blickrichtung des Betrachters nimmt die Skybox einen recht großen Platz auf dem Schirm bei, wodurch Qualitätsunterschiede hier direkt sichtbar sind. Daher sollte eine entsprechend hohe Auflösung gewählt werden, also 1024x1024 und höher. Man benötigt zwar 6 solch großer Texturen (die untere Textur kann man sich aber evtl. je nach Szenario sparen) die allerdings auch trotz solch hoher Auflösung in den Speicher moderner Grafikkarten passen sollten.&lt;br /&gt;
&lt;br /&gt;
===Texturenkompression===&lt;br /&gt;
Bereits seit mehreren Jahren können 3D-Beschleuniger Texturen in einem Format mit fester Kompressionsrate ablegen und nutzen, wodurch sowohl Grafikkartenspeicher als auch Bandbreite gespart wird. Allerdings wirkt sich diese besonders bei Texturen mit langen Farbverläufen bzw. Übergängen (wie bei Skyboxen oft der Fall) negativ aus und ist i.d.R. auch direkt erkennbar, wie auf folgendem Bild sichtbar ist :&lt;br /&gt;
[[Bild:Tutorial_skyboxen_texcomp.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
Die Verschlechterung des Bildes auf der rechten Seite sollte leicht erkennbar sein. Wenn man die Texturen dann auch noch als JPG abgelegt hat und dort bereits komprimiert hat (auch bei 100% Qualitätseinstellung komprimiert JPG immernoch) verschlechtert sich das Gesamtbild nochmals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprogramm==&lt;br /&gt;
Und zu guter Letzt noch ein Bild unserer Skybox aus dem Demoprogramm:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox12.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hinweis:&lt;br /&gt;
Für diesen Screenshot habe ich 512x512 Pixel große Texturen genutzt, während die Texturen im Download nur 256x256 Pixel groß sind!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
[http://www.delphigl.de/files/skyboxtut.zip Die Skyboxdemo (inklusive Quellcode) herunterladen]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Autor: [[Benutzer:Sascha_Willems|Sascha Willems]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Terrain3]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Tutorial3]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glCompressedTexSubImage&amp;diff=25647</id>
		<title>glCompressedTexSubImage</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glCompressedTexSubImage&amp;diff=25647"/>
				<updated>2012-03-21T14:53:51Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glCompressedTexSubImage =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glCompressedTexSubImage''' - modifiziert den Teilbereich einer komprimierten Textur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Spezifikation ==&lt;br /&gt;
 procedure '''glCompressedTexSubImage1D'''(''target'': TGLenum; ''level'': TGLint;&lt;br /&gt;
                                     ''xoffset'': TGLint; ''width'': TGLsizei;&lt;br /&gt;
                                     ''format'': TGLenum; ''imageSize'': TGLsizei;&lt;br /&gt;
                                     '''const''' ''data'': PGLvoid); &amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glCompressedTexSubImage2D'''(''target'': TGLenum; ''level'': TGLint;&lt;br /&gt;
                                     ''xoffset'': TGLint; ''yoffset'': TGLint;&lt;br /&gt;
                                     ''width'': TGLsizei; ''height'': TGLsizei;&lt;br /&gt;
                                     ''format'': TGLenum; ''imageSize'': TGLsizei;&lt;br /&gt;
                                     '''const''' ''data'': PGLvoid); &amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glCompressedTexSubImage3D'''(''target'': TGLenum; ''level'': TGLint;&lt;br /&gt;
                                     ''xoffset'': TGLint; ''yoffset'': TGLint;&lt;br /&gt;
                                     ''zoffset'': TGLint; ''width'': TGLsizei;&lt;br /&gt;
                                     ''height'': TGLsizei; ''depth'': TGLsizei;&lt;br /&gt;
                                     ''format'': TGLenum; ''imageSize'': TGLsizei;&lt;br /&gt;
                                     '''const''' ''data'': PGLvoid); &amp;lt;br&amp;gt;&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;
! ''target''&lt;br /&gt;
| Gibt die Zieltextur an. Muss für '''glCompressedTexSubImage1D''' '''GL_TEXTURE_1D''', für '''glCompressedTexSubImage2D''' '''GL_TEXTURE_2D''' und für '''glCompressedTexSubImage3D''' '''GL_TEXTURE_3D''' sein. Für [[Cubemap|Cubemaps]] sind außerdem die symbolischen Konstanten '''GL_TEXTURE_CUBE_MAP_POSITIVE_X''', '''GL_TEXTURE_CUBE_MAP_NEGATIVE_X''', '''GL_TEXTURE_CUBE_MAP_POSITIVE_Y''', '''GL_TEXTURE_CUBE_MAP_NEGATIVE_Y''', '''GL_TEXTURE_CUBE_MAP_POSITIVE_Z''' und '''GL_TEXTURE_CUBE_MAP_NEGATIVE_Z''' erlaubt. &lt;br /&gt;
|-&lt;br /&gt;
! ''level''&lt;br /&gt;
| Gibt den Detailgrad der zu modifizierenden Textur an. &amp;lt;br&amp;gt;&lt;br /&gt;
''level'' '''0''' ist das Basisbild. Level n ist die n-te [[MipMaps|Mipmap]]-Reduzierung der Textur.&lt;br /&gt;
|-&lt;br /&gt;
! ''xoffset''&lt;br /&gt;
| Offset der bestehenden Textur in x-Richtung, von der aus die Modifizierung beginnen soll.&lt;br /&gt;
|-&lt;br /&gt;
! ''yoffset''&lt;br /&gt;
| Offset der bestehenden Textur in y-Richtung, von der aus die Modifizierung beginnen soll.&lt;br /&gt;
|-&lt;br /&gt;
! ''zoffset''&lt;br /&gt;
| Offset der bestehenden Textur in z-Richtung (Tiefe), von der aus die Modifzierung beginnen soll.&lt;br /&gt;
|-&lt;br /&gt;
! ''width'',&lt;br /&gt;
| Breite der Subtextur.&lt;br /&gt;
|-&lt;br /&gt;
! ''height'',&lt;br /&gt;
| Höhe der Subtextur.&lt;br /&gt;
|-&lt;br /&gt;
! ''depth'',&lt;br /&gt;
| Tiefe der Subtextur.&lt;br /&gt;
|-&lt;br /&gt;
! ''format''&lt;br /&gt;
| Internes Format der komprimierten Texturdaten. Z.B. eine der symbolischen Konstanten '''GL_COMPRESSED_RGB_S3TC_DXT1''', '''GL_COMPRESSED_RGBA_S3TC_DXT1''', '''GL_COMPRESSED_RGBA_S3TC_DXT3''' oder '''GL_COMPRESSED_RGBA_S3TC_DXT5''' falls die [[OpenGL-Extensions|Extension]] [[GL_EXT_texture_compression_s3tc]] unterstützt wird.&lt;br /&gt;
|-&lt;br /&gt;
! ''imageSize''&lt;br /&gt;
| Anzahl der Bytes der komprimierten Daten.&lt;br /&gt;
|-&lt;br /&gt;
! ''_data''&lt;br /&gt;
| Die komprimierten Texturdaten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die Befehle '''glCompressedSubTexImage*D''' werden benutzt, um Teilbereiche bestehender Texturen zu überschreiben, die mit [[glCompressedTexImage]] geladen wurden.&lt;br /&gt;
&lt;br /&gt;
Die Syntax der einzelnen Funktionen ist ähnlich wie bei den korrespondierenden Funktionen zu [[glTexSubImage]].&lt;br /&gt;
&lt;br /&gt;
Mit den Parametern ''xoffset'', ''yoffset'', ''zoffset'' werden die Koordinaten angegeben, ab der die zu modifizierende Textur überschrieben wird.&lt;br /&gt;
&lt;br /&gt;
Die Breite, Höhe und Tiefe der Subtextur werden mit den Parametern ''width'', ''height'' und ''depth'' übergeben.&lt;br /&gt;
&lt;br /&gt;
''format'' definiert das Format, mit dem die Texturdaten intern abgespeichert werden sollen, und sollten mit dem Format der zu überschreibenden Textur übereinstimmen.&lt;br /&gt;
&lt;br /&gt;
Zur Zeit werden von OpenGL noch keine komprimierten Formate unterstützt.&lt;br /&gt;
Bisher ist es nur möglich über [[OpenGL-Extensions|Extensions]], wie z.B. [[GL_EXT_texture_compression_s3tc]], komprimierte Texturformate anzugeben :&lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGB_S3TC_DXT1'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente ist immer 1.0. &lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGBA_S3TC_DXT1'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente ist entweder 1.0 oder 0.0.&lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGBA_S3TC_DXT3'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente wird mit 4 Bits gespeichert.&lt;br /&gt;
&lt;br /&gt;
'''GL_COMPRESSED_RGBA_S3TC_DXT5'''&lt;br /&gt;
: RGB-Daten werden komprimiert, Alpha-Komponente ist gewichtetes Mittel von 8-Bit Werten.&lt;br /&gt;
&lt;br /&gt;
Über den Parameter ''imageSize'' gibt man die genaue Anzahl der Bytes an, die mit ''_data'' an die Funktion übergeben werden.&lt;br /&gt;
&lt;br /&gt;
Um eine geladene Textur in OpenGL zu nutzen ist auf jeden Fall noch die entsprechende Aktivierung mit [[glEnable]]('''GL_TEXTURE_1D''', '''GL_TEXTURE_2D''' oder '''GL_TEXTURE_3D''') nötig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
'''glCompressedTexSubImage''' ist erst ab OpenGL Version 1.3 oder höher nutzbar.&lt;br /&gt;
&lt;br /&gt;
Mit [[glGetIntegerv]] und dem Parameter '''GL_COMPRESSED_TEXTURE_FORMATS''' kann ermittelt werden, welche komprimierten Texturformate von der OpenGL-Implementation unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
[[glPixelStore]] und [[glPixelTransfer]] beeinflussen nicht das Dekodieren einer komprimierten Textur.&lt;br /&gt;
&lt;br /&gt;
Entsprechen die an die Funktion übergebenen Daten nicht dem Komprimierungformat, so verhält sich der Aufruf von '''glCompressedTexSubImage''' undefiniert.&lt;br /&gt;
&lt;br /&gt;
Der Zustand von [[Texel]] ausserhalb des zu modifizierenden Bereiches ist undefiniert.&lt;br /&gt;
&lt;br /&gt;
Es ist darauf zu achten, dass die Komprimierungsformate nicht für alle Zieltexturen unterstützt werden müssen (die meisten Komprimierungsformate unterstützen nur zweidimensionale Texturen).&lt;br /&gt;
Nähere Informationen findet man in der Spezifikation der jeweiligen Extension.&lt;br /&gt;
&lt;br /&gt;
Texturierung hat im Farbindexmodus keinen Effekt.&lt;br /&gt;
&lt;br /&gt;
Keine Fehlermeldungen werden generiert, wenn man beim Aufruf von '''glCompressedTexSubImage''' folgende Punkte beachtet :&lt;br /&gt;
* ''_data'' zeigt auf Daten, die man über die Funktion [[glGetCompressedTexImage]] bekommen hat.&lt;br /&gt;
* ''target'', ''level'' und ''format'' stimmen mit den Parametern ''target'', ''level'' und ''format'' von [[glGetCompressedImage]] überein.&lt;br /&gt;
* ''width'', ''height'', ''depth'', ''format'' und ''imageSize'' stimmen mit den Werten überein, die man über die Funktion [[glGetTexLevelParameter]] mit den Parametern '''GL_TEXTURE_WIDTH''', '''GL_TEXTURE_HEIGHT''', '''GL_TEXTURE_DEPTH''', '''GL_TEXTURE_INTERNAL_FORMAT''' und '''GL_TEXTURE_COMPRESSED_IMAGE_SIZE''' bekommt, nachdem [[glGetCompressedTexImage]] aufgerufen wurde.&lt;br /&gt;
* ''width'', ''height'', ''depth'' und ''format'' stimmen mit den Werten überein, die man über die Funktion [[glGetTexLevelParameter]] mit den Parametern '''GL_TEXTURE_WIDTH''', '''GL_TEXTURE_HEIGHT''', '''GL_TEXTURE_DEPTH''' und '''GL_TEXTURE_INTERNAL_FORMAT''' und der zu überschreibenden Textur-Detailstufe bekommt.&lt;br /&gt;
* ''xoffset'', ''yoffset'' und ''zoffset'' haben alle den Wert -b, wobei b der Rückgabewert der Funktion [[glGetTexLevelParameter]] mit dem Parameter '''GL_TEXTURE_BORDER''' und der zu überschreibenden Textur-Detailstufe ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_ENUM''' wird generiert, wenn ''target'' nicht '''GL_TEXTURE_1D, GL_TEXTURE_2D''' oder '''GL_TEXTURE_3D''' ist. (entsprechend der benutzten Funktion)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_ENUM''' wird generiert, wenn ''format'' kein von der OpenGL-Implementierung unterstütztes komprimiertes Format ist. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''level'' kleiner 0 oder größer ld(max) ist, wobei max der Rückgabewert von '''GL_MAX_TEXTURE_SIZE''' ist. (ld = Logarithmus Dualis = Basis 2). &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''width'', ''height'' bzw. ''depth'' (je nach Funktion) kleiner als 0 oder größer als 2 + '''GL_MAX_TEXTURE_SIZE''' ist, oder die Bedingung  2^k + 2 * (border) (k=Integerwerte) nicht erfüllt. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''imageSize'' nicht der Anzahl der Bytes entspricht, die mit ''_data'' übergeben wurden.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn die übergebenen Daten nicht dem mit ''format'' angegebenem Komprimierungsformat übereinstimmen.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_VALUE''' wird generiert, wenn ''width'' und ''height'' nicht mit dem Format der Daten von ''_data'' übereinstimmen (zu viel oder zu wenig Daten).&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn eine '''glCompressedTexSubImage'''-Funktion in einem [[glBegin]]- und [[glEnd]]-Block aufgerufen wird. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn das Komprimierungsformat nicht für die mit ''target'' angegebene Zieltextur unterstützt wird.&lt;br /&gt;
&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert, wenn ''format'' nicht mit ''internalformat'' der zu überschreibenden Textur übereinstimmt.&lt;br /&gt;
&lt;br /&gt;
== Zugehörige Wertrückgaben ==&lt;br /&gt;
[[glGetCompressedTexImage]]&lt;br /&gt;
&lt;br /&gt;
[[glGetTexLevelParameter]]&lt;br /&gt;
&lt;br /&gt;
[[glIsEnabled]] mit dem Token [[glIsEnabled#GL_TEXTURE_1D|GL_TEXTURE_1D]], [[glIsEnabled#GL_TEXTURE_2D|GL_TEXTURE_2D]] bzw. [[glIsEnabled#GL_TEXTURE_3D|GL_TEXTURE_3D]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glCompressedTexImage1D]], [[glCompressedTexImage2D]], [[glCompressedTexImage3D]], [[glGetCompressedTexImage]], [[glTexCoord]], [[glTexEnv]], [[glTexGen]], [[glTexImage1D]], [[glTexImage2D]], [[glTexImage3D]], [[glTexParameter]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|CompressedTexSubImage]]&lt;br /&gt;
[[Kategorie:GL1.3|CompressedTexSubImage]]&lt;br /&gt;
[[Kategorie:GL3|CompressedTexSubImage]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=25646</id>
		<title>DGL Projekte</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=25646"/>
				<updated>2012-03-21T14:53:33Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
Willkommen in der '''[[DelphiGL|DGL]] Projekte Ecke'''!&lt;br /&gt;
[[Bild:ProjekteEcke.png|center]]&lt;br /&gt;
Auf dieser Seite findet ihr Projekte von '''Mitgliedern von [http://DelphiGL.com DelphiGL.com]''',  welche als '''&amp;quot;für die Benutzung freigegeben&amp;quot;''' gewertet wurden.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wichtiges zuerst==&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|'''Rechtliches:''' Die Software wurde von Mitgliedern von DelphiGL.com in ihrer Freizeit geschrieben. Es kann deshalb für die angebotene Software keinerlei Garantie gegeben werden. Unsere Mitglieder geben allerdings ihr Bestes damit die hier angebotene Software euch Spass ohne Reue beschehrt. Aus rechtlichen Gründen gilt wie bei allen Angeboten von DelphiGL.com: Download und Nutzung auf eigene Gefahr.}}&lt;br /&gt;
&lt;br /&gt;
===Eigene Projekte vorstellen===&lt;br /&gt;
Falls ihr selbst Mitglied von DelphiGL.com seid und ein Projekt habt welches ihr als &amp;quot;benutzbar&amp;quot; bezeichnet (und idealerweise schon bei DelphiGL.com in der Projekte-Sektion vorgestellt habt), dann könnt ihr es hier veröffentlichen.&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Bitte sortiert eure Spiele '''alphabetisch''' in die Kategorien ein.}}&lt;br /&gt;
&lt;br /&gt;
===Auszeichnungen===&lt;br /&gt;
Einige Projekte wurden mit einem oder mehreren [[DGL_Award]]s ausgezeichnet. Mit dem DGL Award ehrt die DelphiGL Community vorbildliche Projekte und Engagement in der Community.&lt;br /&gt;
&lt;br /&gt;
==Spiele==&lt;br /&gt;
Viele, um nicht zu sagen die meisten, DGL-Mitglieder widmen sich dem Thema Spiele. Was dabei an respektablen Ergebnissen entstanden ist könnt ihr in dieser Rubrik sehen.&lt;br /&gt;
&lt;br /&gt;
===3D Shooter und Labyrinth Spiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Action===&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_asteroids.jpg|framed|center|Link: '''[[Projekt_Asteroids|Asteroids]]''']]&lt;br /&gt;
&lt;br /&gt;
|Asteroids ist ein Remake des alten Klassikers &amp;quot;Comet&amp;quot;. Ziel des Spiels ist es so viel Asteroiden wie möglich zu zerstören um dadurch möglichst viele Punkte zusammeln, ohne dabei von den herum fliegenden Trümmern getroffen zu werden. &lt;br /&gt;
&lt;br /&gt;
An einem Spiel können bis zu 4 Spieler gleichzeitig teilnehmen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Magellan|Magellan]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_napalmbomber.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=90 Napalmbomber3D Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|NapalmBomber3D ist wie der Titel schon vermuten lässt ein 3D-Klon des bekannten Bombermanspielprinzips.Dieses hochbrisante und fesselnde Spiel besticht durch seine tolle Grafik die natürlich mittels OpenGL realisiert wurde.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zum Spiel gibt es natürlich auch noch einen Karteneditor mit dem sich in Windeseile eigenen Maps erstellen lassen.&lt;br /&gt;
&lt;br /&gt;
Neben inzwischen über 50.000 Downloads (im Schnitt sind es immernoch &amp;gt; 400 pro Monat) und diversen sehr guten Reviews hat es das Spiel sogar auf die PC-Action Ausgabe 07/2004 geschafft.&lt;br /&gt;
&lt;br /&gt;
''([[Tutorial#Spieletutorials_und_Softwareentwicklung|Hier]] findet ihr 2 Tutorials mit denen ihr dieses tolle Spielchen nachbauen könnt.)''&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:PE2.jpg|thumb|center|168px|Link: '''[http://ziz.delphigl.com/pereff_download.php Perniciei Effector]''']]&lt;br /&gt;
|Ein typischer Weltraum Shooter mit 2D Steuerung aber 3D Grafik. Ziel des Spiels ist es in der Highscore möglichst hoch zu klettern. Dies erreicht man durch die passende Auswahl des Raumschiffes zu beginn und die vielen Items, die die Gegner verlieren.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Ziz|Ziz]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Brett-, Denk- und Kartenspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Balance.jpg|thumb|center|168px|Link: '''[[Projekt_Balance|Balance]]''']]&lt;br /&gt;
|Durch geschicktes erhöhen von Ladungen werden Kettenreaktionen ausgelöst mithilfe derer man das gesammte Spielfeld erobert. Das Spiel ist Mehrsprachig (Deutsch/Englisch) und enthält einen Einzelspieler und zwei Multiplayer-Modi (HotSeat u. LAN).&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Flash|Kevin Fleischer aka Flash]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Projekt_Hex_Change_Screenshot.jpg|thumb|center|168px|Link: '''[[Projekt_Hex-Change|Hex-Change]]''']]&lt;br /&gt;
|2 Spieler konkurrieren um die Felder auf einer Hexagon Fläche. Das Spiel enthält einen Einzelspieler- (gegen KI) und einen &amp;quot;Hot-Seat&amp;quot;-Mehrspielermodus.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:H.A.S.E.|H.A.S.E.]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Reaktions- und Geschicklichkeitsspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_beanmachine.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=86 Bean Machine Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|&amp;quot;Bean Machine&amp;quot; basiert auf dem Sega MegaDrive-Klassiker &amp;quot;Dr.Robotnik's Mean Bean Machine&amp;quot; (ausserhalb Europas auch als &amp;quot;Puyo Puyo&amp;quot; bekannt) und spielt sich somit ähnlich wie Tetris.&lt;br /&gt;
Auch dieses Klassikerremake spielt sich fast genauso wie die Vorlage, allerdings gibt es dank OpenGL recht aufwendige Grafiken, natürlich gewohnt komplett in 3D.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_confusingball.jpg|framed|center|Link: '''[[Projekt_ConfusingBall|Confusing Ball]]''']]&lt;br /&gt;
&lt;br /&gt;
|In &amp;quot;Confusing Ball&amp;quot; steuert man einen Ball durch ein 3D Labyrinth, in dem die Gesetze der Physik neu definiert werden müssen. Um ins Ziel eines Levels zu gelangen benötigt man einen gewissen Orientierungssinn und ein gutes räumliches Vorstellungsvermögen.&lt;br /&gt;
Nebenher muss man ja auch noch die Münzen einsammeln, und den Bomben aus dem Weg gehen. Frei verschiebbare Steine erhöhen den Schwierigkeitsgrad.  &lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:MatReno|MatReno]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Heiliger Damm.jpg|thumb|center|168px|Link: '''[[Projekt Heiliger_Damm|Heiliger Damm]]''']]&lt;br /&gt;
&lt;br /&gt;
|&amp;quot;Heiliger Damm&amp;quot; ist ein Geschicklichkeitsspiel passend zum G8-Treffen 2007 in Heiligendamm. Der Spieler übernimmt die Aufgabe, den &amp;quot;heiligen Damm&amp;quot; (eine Oase in der Wüste) vor den Globalisierungsgegner zu schützen. Dies erreicht er, indem er mit der Maus Linien (Zäune) zieht.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:GTA-Place|Fabian Gärtner / GTA-Place]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Simulationen===&lt;br /&gt;
====Wirtschaftssimulationen/Manager====&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:PBM2_Kdr.jpg|thumb|center|168px|Link: '''[[Projekt_PBM2|PBall Manager 2]]''']]&lt;br /&gt;
&lt;br /&gt;
|Der PBall Manager 2 ist ein Sportmanager in welchem man in die Rolle des Trainers/Managers eines von 96 PBall Teams aus ganz Europa schlüpft. PBall selbst ist eine fiktive Sportart welche ähnlich Fußball ist.&lt;br /&gt;
&lt;br /&gt;
Im Spiel hat man die Kontrolle über alle Abläufe: Von der Aufstellung über Spielerkäufe bis hin zum Stadionausbau liegt alles in der Hand des Spielers. Doch auch die eigene Karriere kann voran getrieben werden indem man zu anderen Clubs wechselt.&lt;br /&gt;
&lt;br /&gt;
Das Ziel aller PBaller ist der Liga-Meister-Pokal indem die besten Clubs der 4 Europäischen Ligen um den Titel spielen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Flash|Kevin Fleischer alias Flash]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Flugsimulationen====&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Rennsimulationen====&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strategie===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:planeto7.jpg|thumb|center|168px|Link: '''[http://nilsbeckmann.de/ Planeto]''']]&lt;br /&gt;
&lt;br /&gt;
|Planeto ist ein rundenbasiertes Science-Fiction Strategiespiel. Du landest auf einem unbekannten Planeten. Deine Aufgabe ist es, diesen zu erkunden, Rohstoffe zu sichern und die militärische Vorherrschaft zu behaupten. Spieler können gegen Computerspieler antreten oder untereinander simultan übers Netzwerk und Internet. Zur Auswahl stehen mehr als 400 Einheiten, Forschungen und Aufwertungen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Nils Beckmann|Nils Beckmann]]&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:projektw_wiki_projektecke.jpg|thumb|center|168px|Link: '''[http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;]''']]&lt;br /&gt;
&lt;br /&gt;
|Projekt &amp;quot;W&amp;quot; ist ein runden-basierendes Strategiespiel, dessen Ziel die Erlangung der Weltherrschaft ist. Der Spieler kann sich für eine der fünf neuen großen Nationen entscheiden, und muss diese dann zum Sieg über alle anderen Nationen führen.&lt;br /&gt;
&lt;br /&gt;
Dazu muss man seine Regionen verwalten, dort Gebäude bauen und auf wichtige Faktoren achten. Man baut zudem militärische Einheiten und gliedert diese in Divisionen um damit das eigene Territorium zu verteidigen, bzw. gegnerische Regionen einzunehmen. Zusätzlich kann man Technologien erforschen, die u.A. neue Gebäude und Militäreinheiten freischalten. Auch Spionage und Sabotage spielen eine wichtige Rolle, so kann man z.B. mit Hilfe eines eingeschleusten Spions an wichtige Informationen gelangen oder die Stromversorgung einer Region lahmlegen.&lt;br /&gt;
&lt;br /&gt;
Neben dem Einzelspielermodus, in dem man gegen die KI bestehen muss, gibt es auch einen Hotseatmodus, bei dem mehrere Spieler an einem Rechner gegeneinander antreten können. Präsentiert wirds wie gewohnt in schicker 3D-Grafik, und auf passender Hardware wird das Ganze noch mit Shadern garniert.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Effekte==&lt;br /&gt;
Für den optischen Anspruch eines Spiels haben Spezialeffekte große Bedeutung. Was beim einfachen Feuer beim Abschießen einer virtuellen Kugel anfängt, kann sich über plastischen Nebel bis zu imposanten, realistischen Blitzen ziehen.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Pic6.jpg|thumb|center|168px|Link: '''[http://sourceforge.net/projects/fireblade/ FireBlade]''']]&lt;br /&gt;
&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Project_OTY08.png|center&lt;br /&gt;
rect 0 0 100 40 [[DGL_Award#Best_Project_Award]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|FireBlade ist ein flexibles und leistungsstarkes Partikelsystem auf OpenGL-Basis. Sie ist sehr effizient im Bezug auf Tiefensortierung, Speichermanagement, Ansprechbarkeit und Erweiterbarkeit, und lässt sich durch die Art und Weise, wie Effekte beschrieben werden, sehr gut vor allem in größere Projekte einbringen. Dabei eignet sie sich sowohl für 2D als auch für 3D-Anwendungen. Highlights sind zum Beispiel die integrierte, problemlos erweiterbare Kollisionsabfrage, ein breites, ebenfalls erweiterbares Emitter-Set und ein einfacher, aber sehr effizienter Manager, der die Performance gerade für viele Effekte enorm steigern kann. Alle Eigenschaften, selbst die Textur- und Raumkoordinaten der einzelnen Billboard-Vertices sind manipulierbar.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Kyro|Sebastian Wagner alias Kyro]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Bibliotheken==&lt;br /&gt;
Diese Rubrik enthält Bibliotheken, die die Grafikprogrammierung vereinfachen und dem Spiele-/Anwendungsentwickler helfend unter die Arme greifen.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:AndorraLogo.png|thumb|center|168px|Link: '''[http://andorra.sourceforge.net/ Andorra 2D]''']]&lt;br /&gt;
&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Useful_OTY08.png|center&lt;br /&gt;
rect 0 0 100 40 [[DGL_Award#Most_Useful_Project_Award]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|Andorra 2D ist eine flexible Lösung um 2D-Spiele oder Anwendungen zu entwickeln. Durch den durchdachten Aufbau des Engine-Kerns ist Andorra 2D komplett von der Grafikschnittstelle und dem Betriebssystem getrennt. Eine Anbindung an OpenGL und Direct3D, sowie Unterstützung für Windows und Linux 32/64 Bit sind gegeben. Andorra 2D ist einfach zu verwenden und erlaubt es auch Einsteigern schnell erste Ergebnisse auf den Bildschirm auszugeben. Andererseits wendet es sich mit Features wie Shadern auch an fortgeschrittene Benutzer.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Igel457|Andreas Stöckel alias Igel457]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:AudorraLogo.png|thumb|center|168px|Link: '''[http://audorra.sourceforge.net/ Audorra]''']]&lt;br /&gt;
|Audorra ist eine Bibliothek zur Wiedergabe von 3D-Positionalem Audio und vor allem für den Einsatz in Spielen gedacht. Durch den modularen Aufbau kann es - die richtigen Audio-Backends (&amp;quot;Driver&amp;quot;) und Decoder vorrausgesetzt - auf fast jeder Plattform eingesetzt werden. Der verwendete 3D-Audio-Softwarerenderer garantiert gleiche Ergbnisse und unterstützt Effekte wie Phasenverschiebung und Dopplereffekt. Mehr über das Projekt gibt es auch im [http://www.delphigl.com/forum/viewtopic.php?f=13&amp;amp;t=8819 Forumsthread] zu erfahren.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Igel457|Andreas Stöckel alias Igel457]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Tools==&lt;br /&gt;
Diese Rubrik enthält Werkzeuge, die man benutzt um Inhalte zu erstellen.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Beei.png|thumb|center|168px|Link: '''[http://projects.blender.org/projects/beei/ Blender External Engine Interface]''']]&lt;br /&gt;
|BEEI steht für Blender External Engine Interface und dient als Schnittstelle für externe Renderer und Gameengines.&lt;br /&gt;
Der externe Renderer oder Gameengine muss in Form einer .dll oder .so Datei vorliegen und die von der Schnittstelle erwarteten Funktionen bieten. Das Plugin wird dann von Blender geladen und befindet sich dann im Speicher von Blender.&lt;br /&gt;
Nun kann man z.B. mit OpenGL Renderbefehle ausführen und diese werden dann im Space von Blender dargestellt.&lt;br /&gt;
Man hat zugriff auf die Blender Daten und kann sie lesen oder schreiben, wobei das Lesen die sichere Art ist und zum schreiben Python und BEEI Boardmittel verwendet werden sollten. Das Testplugin ist ein frühes Framework von Karmarama.&lt;br /&gt;
Es zeigt die Blenderdaten wie der interne Blenderrenderer mit der ausnahme, dass ein Entity mit dem Namen Glow als Pfeil dargestellt wird. BEEI bietet neben der schnittstelle noch zugriff auf die Blender UI elemente, um eigene Toolfenster zu erstellen. Der tiefere Sinn liegt im WYSIWYG und erlaubt ein wesentlich leichteres erstellen von Content aller Art.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|Thomas Kunze&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:xenorate.png|thumb|center|160px|Link: '''[http://www.xenorate.com Xenorate Media Player]''']]&lt;br /&gt;
|Xenorate Media player ist ein konfortabler multimedia player welches sehr viele medienformate beherscht.&lt;br /&gt;
Es unterstützt DVD, VCD/SVCD, Video/Audio Dateien und kann Livestreams abspielen + aufnehmen.&lt;br /&gt;
&lt;br /&gt;
Mit einem integriertem audio system (basierend auf BASS) kann es einige audio formate &amp;quot;out-of-the-box&amp;quot; abspielen:&lt;br /&gt;
MP3, OGG, FLAC, MPC, M4A, AAC, AC3, WAV, ...&lt;br /&gt;
&lt;br /&gt;
Xenorate enthält ein mächtiges video system welches directshow nutzt um dvd und video content abzuspielen.&lt;br /&gt;
Es unterstützt interne und externe untertitel sowie mehrere ton spuren. &lt;br /&gt;
Um jede mögliche filter kombination abzuspielen (DirectShow Graph) hat Xenorate eine DirectShow Script Engine (basierend auf BeroScript).&lt;br /&gt;
&lt;br /&gt;
Es gibt außerdem noch ein eigenes Codec Pack welches alle notwendingen codecs enthält die man heutzutage benötigt.&lt;br /&gt;
&lt;br /&gt;
Entwickelt wurde das Projekt 1999 mit Borland Delphi 2-7 und hat mittlerweile 250.000 zeilen code erreicht.&lt;br /&gt;
Komplett auf Userwünschen abgestimmt enthält es eine sehr grosse Palette an features wie z.b.&lt;br /&gt;
&lt;br /&gt;
- Eine sehr schnelle statische eigene skin engine basierend auf TBitmap.&lt;br /&gt;
- Ein dynamisches shortcut system mit multimedia keys unterstützung.&lt;br /&gt;
- Intelligente untertitel erkennung&lt;br /&gt;
- Media information erkennung&lt;br /&gt;
- Vollständiger playlist editor mit ID3 v1/v2 unterstützung.&lt;br /&gt;
- Unicode support (WideString)&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|Torsten Sailer&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_2D&amp;diff=25645</id>
		<title>Tutorial 2D</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_2D&amp;diff=25645"/>
				<updated>2012-03-21T14:53:16Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=2D mit OpenGL - &amp;quot;Nicht jeder benötigt 3 Dimensionen&amp;quot;=&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
&lt;br /&gt;
Bei der Erwähnung einer API wie OpenGL denken die meisten eigentlich eher an 3D, und sind der festen (aber sehr wohl falschen) Überzeugung eine solche API sei für reine 2D-Anwendung überdimensioniert oder gar ungeeignet. Das dies nicht der Fall ist möchte ich mit diesem (vor allem an Einsteiger gerichtet, denn die Könner wissen wohl was man mit der GL so alles machen kann) Tutorial zeigen und auch gleich mit mehreren praktischen Beispielen aufweisen das 2D mit OpenGL nicht nur möglich ist, sondern auch noch sehr viel einfacher (selbst mit der GDI ist 2D komplizierter) ist und dabei jede Menge Vorteile mit sich bringt.&lt;br /&gt;
&lt;br /&gt;
==Welche Vorteile bringt mir die GL für eine 2D-Anwendung?==&lt;br /&gt;
&lt;br /&gt;
Dies ist wohl das wichtigste Kapitel und sollte zugleich auch mit diversen Vorurteilen und Missverständnissen aufräumen. Denn gerade der 3D-Bereich ist es in dem seit Jahren fast monatlich neue Techniken entworfen werden und der dafür sorgt das v.&amp;amp;nbsp;a. Grafikkarten immer leistungsstärker werden, während der 2D-Bereich seit seligen VLB-Zeiten (= Vesa-Local-Bus, alte Haudegen kennen diese Grafikkartengeneration sicherlich noch) keine Innovationen mehr erlebt hat (und warum auch? Im 2D-Bereich reicht ein gutes Bild zusammen mit passabler Darstellungsgeschwindigkeit).&lt;br /&gt;
&lt;br /&gt;
Deshalb gibt es jetzt gleich mal die wichtigsten Punkte warum man denn gerade OpenGL (D3D würde hier auch zählen, aber das haben wir GL'ler ja nicht so gerne) für die 2D-Darstellung nutzen sollte:&lt;br /&gt;
&lt;br /&gt;
*'''Hardwarebeschleunigung'''&lt;br /&gt;
:Moderne Grafikkarten können inzwischen über 200 Millionen Dreiecke pro Sekunde rendern und besitzen brachiale Füllraten jenseits der 2.000 M(Texel/Pixel)/s. Das bedeutet also das man selbst auf älteren Grafikkarten sehr komplexe 2D-Szenen mit Geschwindigkeiten jenseits der 100 FpS (= Frames per Seconds ~ Bilder pro Sekunde) darstellen kann, während man mit der GDI schon bei einfachen 2D-Grafiken Geschwindigkeitsprobleme bekommen würde.&lt;br /&gt;
&lt;br /&gt;
*'''&amp;quot;Kostenlose&amp;quot; Objektsortierung'''&lt;br /&gt;
:Eine 3D-API braucht einen Tiefenpuffer um zu erkennen ob Fragmente verdeckt sind oder nicht und damit Overdraw zu vermeiden. Eine 2D-Anwendung kann diesen Tiefenpuffer aber auch nutzen, nämlich um Objekte zu sortieren. Man nutzt dann die Z-Koordinate der Objekte (= Tiefenkoordinate) quasi als Layer um zu kennzeichnen welches Objekt auf welcher &amp;quot;Höhe&amp;quot; liegt. Wenn man also z.&amp;amp;nbsp;B. einen 2D-Topdown-Shooter entwickelt bei dem der Spieler mit seinem Flugzeug über den Boden fliegt, dann nutzt man den Z-Puffer um die API (die das dann der Hardware überlässt) seine Objekte sortieren zu lassen. Das Flugzeug bekommt dann einen niedrigen Z-Wert (=oben) und Objekte auf dem Boden einen hohen Tiefenwert (=unten/hinten). Die Sortierung übernimmt dann die Grafikkarte und wir müssen uns darum keine Gedanken machen. Würden wir die Anwendung z.&amp;amp;nbsp;B. über die GDI realisieren, müssten wir diese Objekte selbst entsprechend ihrer Höhe sortieren.&lt;br /&gt;
&lt;br /&gt;
*'''Jede Menge hardwarebeschleunigte Spezialeffekt'''&lt;br /&gt;
:Wie schon oben erwähnt haben im 3D-Bereich innerhalb der letzten Jahre sehr viele Innovationen stattgefunden. Warum sollte man diese also nicht auch für seine 2D-Anwendung nutzen? Klingt logisch und macht auch Sinn! So bietet OpenGL alle Arten von Effekten die auch in einer 2D-Anwendung nützlich sein können. Darunter solche Sachen wie den Alphatest (der dafür sorgt das maskierte Teile eines Objektes transparent sind), Blending und natürlich (auch wenn das jetzt für erfahrene GL'ler sehr trivial klingt) hardwarebeschleunigte Rotation und Skalierung; was zur Folge hat das man seine Objekte nicht für verschiedene Auflösungen in verschiedenen Größen erstellen muss. Für Fortgeschrittene gibt es dann natürlich noch solche Sachen wie Shader, mit denen man Teile der OpenGL-Pipeline durch eigene (kleine) Programme ersetzen kann (entweder in Assemblerform oder aber in der neuen GL-HLSL). Dadurch bietet sich dann ein quasi unendlich großes Spektrum an möglichen Effekten, und das wohlgemerkt alles hardwarebeschleunigt!&lt;br /&gt;
&lt;br /&gt;
*'''Plattformübergreifend'''&lt;br /&gt;
:Auch ein großer Vorteil von OpenGL. Die Tatsache das die GL unter diversen Betriebssystemen verfügbar ist (im Gegensatz zu GDI oder gar DirectX) macht die eigenen Programme recht portabel (einschränkend ist hier halt nur die Verfügbarkeit der genutzten Programmiersprache auf dem passenden OS). Unterstützt werden alle größeren Betriebssysteme wie Windows, Linux, MacOS und Solaris.&lt;br /&gt;
&lt;br /&gt;
:Ganz nebenbei wurde vor kurzem mit [http://www.khronos.org/opengles/2_X/ OpenGL ES] ein mobiler Standard für OpenGL geschaffen, wodurch es dann auch möglich ist auf mobilen Geräten (Handys, PDAs, Handhelds) OpenGL zu nutzen. Und gerade dort sind 2D-Spiele (aufgrund der oft mangelnden Leistung der Geräte) ja noch stark verbreitet.&lt;br /&gt;
&lt;br /&gt;
So viel also zu den wichtigsten Vorteilen zur OpenGL unter 2D. Natürlich gibt es noch weiter Dinge die OpenGL für 2D-Anwendungen attraktiv machen, aber allein die oben genannten Gründe sollten jedermann überzeugt haben. Und alle die wirklich mal wissen wollen wie gut OpenGL denn für solche Anwendungen geeignet ist, sollten sich unbedingt eine neuere Version des MacOS ansehen, denn das benutzt OpenGL zur Darstellung seiner GUI.&lt;br /&gt;
&lt;br /&gt;
==Und welche Nachteile gibt es?==&lt;br /&gt;
&lt;br /&gt;
Nichts was der Mensch bisher erfunden hat (mal abgesehen von der Spaltung des Atoms ;) ) hat nur Vorteile. Genauso sieht es auch aus wenn man die OpenGL für seine 2D-Anwendung nutzen will. Welche genau das sind will ich hier grob auflisten.&lt;br /&gt;
&lt;br /&gt;
*'''Ohne 3D-Beschleuniger mit passenden Treibern geht nichts'''&lt;br /&gt;
:Klingt logisch, oder? OpenGL ist eine 3D-API und da 2D nichts weiter als die (fast vollständige) Vernachlässigung der Z-Koordinate ist, kommen wir um einen 3D-Beschleuniger nicht herum, der dazu auch noch einen Treiber mitbringen muss der OpenGL unterstützt. Allerdings schritt der Fortschritt auf diesem Gebiet der IT-Technik in den letzten Jahren so rasant voran wie sonst nirgendwo, und wir werden nur sehr selten auf Rechner stoßen in denen Hardware agiert die keine 3D-Beschleunigung bietet. Ergänzend dazu sollte allerdings trotzdem immer der neuste Treiber installiert sein, denn besonders die in WindowsXP integrierten Grafikkartentreiber wurden ihrer OpenGL-Funktionalität entraubt (Man riecht hier förmlich die Konkurrenz zwischen D3D und der GL). Also ist dies im Endeffekt ein Nachteil der inzwischen kaum noch halt findet und in Zukunft total vernachlässigt werden kann.&lt;br /&gt;
&lt;br /&gt;
*'''Hardwarelimitationen'''&lt;br /&gt;
:Einer der größten Nachteile einer jeden 3D-API die auf Hardwarebasis arbeitet sind die Limitationen die die Hardware mitbringt. Jeder Grafikkartentyp hat andere, was mitunter dazu führen kann das die selbstverfassten OpenGL-Anwendungen nicht auf allen Rechnern laufen. Da wir uns in diesem Tutorial (2D ist ja recht anspruchslos) allerdings in den Niederungen der OpenGL-Funktionalität bewegen, dürfte es hier kaum Probleme geben. Einzig die Tatsache das vor allem ältere 3D-Beschleuniger mit großen Texturen Probleme haben könnte hier und da Schwierigkeiten machen. Wer aber keine Texturen größer 1024x1024 Pixel nutzt und dazu noch sparend mit dem Speicher der Grafikkarte umgeht (nicht jede Grafikkarte hat 128 Mbyte Grafikspeicher oder gar mehr). Einige Leute werden sich übrigens evtl. dadurch verunsichert fühlen das ihnen jemand gesagt hat, man könnte unter OpenGL nur Texturen nutzen die der Dimension 2^n*2^n entsprechen. Das ist grundlegend korrekt, aber wir nutzen hier einen Texturenloader der [[gluBuildMipMaps]] benutzt um [[MipMaps]] (verschiedene Detailstufen) für unsere Texturen zu erstellen. Diese Funktion schluckt jede Größe (sofern diese kleiner oder gleich dem Hardwarelimit ist) und passt die Texturen dann entsprechend an eben genanntes Limit an, also müssen wir uns um diese so oft erwähnte Limitation keine Sorgen machen. Wer zu dem Thema Hardwarelimitation mehr wissen will, der sollte unbedingt mal auf [http://www.delphi3d.net/ Tom Nuydens Seite] vorbei schauen. Dort gibt es eine riesige Datenbank in der fast alle Grafikkarten mit ihren entsprechenden OpenGL-Fähigkeiten vertreten sind.&lt;br /&gt;
&lt;br /&gt;
*'''Filtering'''&lt;br /&gt;
:Zugleich ein großer Vorteil, aber je nach Situation auch ein Nachteil. OpenGL filtert Texturen (sofern man das via GL_LINEAR so will) bilinear, was man auch tunlichst aktiviert lassen sollte (GL_NEAREST filtert nicht, sieht dann aber auch scheußlich blockig aus). Dadurch wirken Texturn meist etwas verschwommen. Ich für meinen Teil umgehe dies aber ganz einfach, denn in fast jedem Bildbearbeitungsprogramm gibt es eine Funktion mit der man ein Bild scharfzeichnen kann. Das sieht auf den ersten Blick dann zwar überzeichnet aus, aber wenn OpenGL das Bild dann als Textur bilinear filtert, heben sich Filtering und Scharfzeichnung gegenseitig fast auf. Das hat sich in meinen Anwendungen bisher bewährt und ist nicht wirklich viel Aufwand.&lt;br /&gt;
&lt;br /&gt;
Um dieses Kapitel hier abzuschließen sei noch gesagt das man ohne 3D-Beschleuniger nicht unbedingt auf OpenGL verzichten muss. Brian Paul hat mit [http://www.mesa3d.org/ Mesa3D] nämlich ein Projekt am laufen das OpenGL-DLLs zur Verfügung stellen die komplett über die CPU ablaufen. So kann man dann OpenGL-Anwendungen mit einer etwas schnelleren CPU trotz fehlendem 3D-Beschleuniger nutzen, oder auf Funktionen ausprobieren die von der (zu alten) Grafikkarte nicht unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
==Die Grundlagen==&lt;br /&gt;
&lt;br /&gt;
Sollte sich der geneigte Leser nun also doch für die GL entschieden haben, so widmen wir uns dann jetzt den Grundlagen der 2D-Darstellung unter OpenGL. Viele Sachen die man bei einer 3D-Anwendung beachten muss, sind hier eigentlich zu vernachlässigen. Wer also schon mal eine kleine 3D-Anwendung unter OpenGL geschrieben hat wird hier sicherlich keine Problem bekommen. Da sich dieses Tutorial aber an blutige (mhh, lecker) Einsteiger richtet, versuche ich so genau und einfach wie möglich zu erklären was man machen muss und v.&amp;amp;nbsp;a. warum. Genau deshalb habe ich auch für einen Großteil der hier erwähnten Techniken im Download zu diesem Tutorial (siehe unsere Files-Sektion und dort unter VCL-Source) jeweils ein eigenes Beispielprogramm + Quellcode (und natürlich ausgiebigen Kommentaren) geschrieben. Wenn zu dem jeweiligen Kapitel ein solches im Download enthalten ist, dann steht das ''kursiv'' unter der Überschrift des Kapitels.&lt;br /&gt;
&lt;br /&gt;
==Die Projektion==&lt;br /&gt;
&lt;br /&gt;
Wie bekannt (sein sollte), besitzt OpenGL im Groben zwei wichtige Matrizen. Zum einen die Modellansichtsmatrix, in der man im Normalfall seine Szene (egal ob 2D oder 3D) rendert und (für dieses Kapitel wichtiger) die Projektionsmatrix. Diese Matrix lässt sich am besten mit der Linse einer Kamera vergleichen und legt fest wie die Objekte auf den Bildschirm projiziert werden (wer mitdenkt wird jetzt wissen warum diese Matrix so genannt wurde). In einer 3D-Anwendung setzen wir (meist über [[gluPerspective]]) eine Projektionsmatrix die dafür sorgt das unsere Objekte perspektivisch korrekt verzerrt werden (so wie es im echten Leben auch ist). Da Bilder aber mehr als tausend Worte sagen zeige ich das anhand der unteren Bildreihe, die einen Würfel an verschiedenen Positionen auf der X-Achse zeigt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_1.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Der Würfel wurde auf den beiden Bildausschnitten links und rechts jeweils um 40 Einheiten auf der X-Achse verschoben und man kann sehr gut sehen das die Seiten des Würfels perspektivisch verzerrt werden, also weiter entfernte Kanten kleiner erscheinen (wie im realen Leben, das kann man ja prima mit nem würfelähnlichem Objekt nachprüfen). Diese Art der Darstellung ist für 3D gut geeignet, aber für unseren Zweck nicht. Denn wir wollen ja das unser Objekt, egal an welcher Bildschirmposition es sich befindet, gleich aussieht.&lt;br /&gt;
&lt;br /&gt;
Dazu gibt es unter OpenGL den sog. orthogonalen Modus, der dafür sorgt das unser [[Frustum]] (Sichtkegel) nicht wie bei der 3D-Projektion kegelförmig ist (kleine Seite beim Betrachter, große Seite am Ende des Sichtfeldes), sondern wie eine Box aussieht. Für technisch interessierte hier der Vergleich zwischen dem 3D- und dem 2D-Frustum :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_2.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links sehen wir das Frustum (~Sichtbereich) für die orthogonale Projektion (also 2D) und rechts für die perspektivische Projektion (3D). In diesem Tutorial interessieren wir uns wie gesagt für ersteres Frustum, welches sich über die Funktion [[glOrtho]] erstellen lässt. Diese Funktion will von uns die Dimensionen haben die wir unserem Viewport geben wollen. Ich empfehle hier übrigens immer einen festen Wert der einer der gängigen Auflösungen (z.&amp;amp;nbsp;B. 640x480, 800x600) entspricht. Der feste Wert hat übrigens den Vorteil das unsere Anwendung von der vom Nutzer gewählten Bildschirmauflösung unabhängig ist. Wir müssen dann also nicht mehr umrechnen wo unser Objekt jetzt in der gewählten Auflösung wäre und wie groß es dort sein müsste. Dadurch das wir immer die selben virtuellen Koordinaten haben, überlassen wir der GL (bzw. der Grafikkarte) die Umrechnung. Wenn wir also eine virtuelle Auflösung von 640x480 an glOrtho übergeben, und ein Objekt zentriert bei 320x240 rendern, dann wird dieses egal in welcher Auflösung immer in der Mitte des Schirms gerendert. Die Umrechnung macht wie gesagt OpenGl (oder besser gesagt die Grafikkarte). Zusätzlich übergeben wir der Funktion dann noch die Z-Reichweite. Hier kann man beliebig wählen, und muss nicht wie in 3D darauf achten Z-Near und Z-Far so zu wählen das die Auflösung des Tiefenpuffers nicht unnötig verschwendet wird (z.&amp;amp;nbsp;B. mit einem Z-Near von 0.1 oder gar kleiner). Für Z-Near nehme ich gewöhnlich 0 und für Z-Far einen Wert der dafür sorgt das ich alle Objekte so sortieren kann das ihre Z-Position auf einen Integerwert fällt. Als kleines Codebeispiel könnte unsere Projektionsmatrix nun so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glMatrixMode(GL_PROJECTION);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
glViewport(0,0,ClientWidth,ClientHeight);&lt;br /&gt;
glOrtho(0,640,0,480,0,128);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um den optischen Vergleich zur oben erwähnten 3D-Projektion zu zeigen, gibt es wieder ein Bild des Würfels, diesmal allerdings mit 2D-Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_3.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Das sieht auf den ersten Blick zugegeben recht langweilig aus, stellt aber genau den selben Szenenverhalt dar wie die Ansicht ein paar Zeilen weiter oben. Diesmal allerdings mit der gerade besprochenen orthogonalen Ansicht, die als Grundlage für unsere 2D-Projektion dient.&lt;br /&gt;
&lt;br /&gt;
So viel also zur 2D-Projektion und hoffentlich hat das hier jeder verstanden. Die orthogonale Projektion ist ein essentieller Bestandteil einer jeden 2D-Anwendung unter OpenGL und sollte daher allen Interessierten ein Begriff sein. Falls das hier jemandem zu technisch war, im Forum werden weitergehende Fragen gerne beantwortet.&lt;br /&gt;
&lt;br /&gt;
Noch als kleiner Nachtrag: Wer sich mal die Parameter angesehen hat die glOrtho will, wird bemerkt haben das wir in obigem Quellcode (zumindest augescheinlich) Top mit Bottom verwechselt haben (sprich es sollte 0,640,480,0 statt 0,640,0,480) heißen. Das hat allerdings seine Richtigkeit, denn in OpenGL liegt der Ursprung des Koordinatensystems in der unteren linken Bildschirm(oder Fenster)ecke, wobei er bei Windows in der oberen Ecke liegt. Unter OpenGL liegt also quasi der &amp;quot;Boden&amp;quot; oben, genau umgekehrt wie unter Windows. Genau deshalb übergeben wir als &amp;quot;Oben&amp;quot; an glOrtho den eigentlichen Boden des Viewports. Das klingt verwirrend, aber ist im Endeffekt gar nicht so schwer zu behalten, besonders dann nicht wenn man sich folgende Illustration mal näher ansieht:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_11.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Das sollte man immer in Hinterkopf behalten, und unter 3D ist es genauso. Während ein positiver Y-Wert Objekte in einem Windowsfenster nach unten verschiebt, geschieht unter OpenGL genau das Gegenteil. Wer sich mit dieser Tatsache nicht anfreunden kann, der kann auch gerne glOrtho dazu nutzen die 2D-Matrix von OpenGL an die Windowsgegebenheiten anzupassen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glOrtho(0,640,480,0,0,128);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schon verhält es sich unter OpenGL genauso wie unter Windows. Positive Y-Koordinaten zeigen nach unten. Allerdings muss man hier dann auch drauf achten die gerenderten Objekte an diese Gegebenheit anzupassen. Man muss diese also quasi auf den Kopf stellen, damit sie mit der neuen Matrix korrekt angezeigt werden. Das geht aber ganz leicht, indem man beim rendern von Quads oder anderen texturierten Primitiven ganz einfach die T-Texturkoordinaten vertauscht.&lt;br /&gt;
&lt;br /&gt;
==Darstellung der 2D-Objekte==&lt;br /&gt;
&lt;br /&gt;
Einige 2D-Interessierte haben sich sicherlich schon mal im Funktionsumfang von OpenGL umgesehen und bemerkt, dass es dort eigentlich gar keine Funktionen gibt um Dinge in 2D zu zeichnen. Auf den ersten Blick sieht das auch wirklich so aus, aber man darf halt nie vergessen dass OpenGL primär für den 3D-Bereich entworfen wurde und sich 2D-Sachen dann nur über 3D-Techniken realisieren lassen. So auch die Darstellung unserer 2D-Objekte, für die wir aus genau diesem Grund eine 3D-Technik anwenden müssen, nämlich das sog. Texturemapping (Den Begriff &amp;quot;Textur&amp;quot; gibt's übrigens auch im deutschen Sprachgebrauch, aber gängiger ist die korrekte Übersetzung &amp;quot;Oberfläche&amp;quot;). Unter OpenGL werden ja alle Objekte aus verschiedenen Primitiventypen zusammengesetzt (Dreiecke, Rechtecke, usw.) und diese Objekte kann man mit einer Textur belegen die dann auf dieser Oberfläche &amp;quot;angezeigt&amp;quot; wird. Diese Textur lädt man im Normalfall aus einer vorher erstellten Bilddatei unter Nutzung eines [[Texture_Loader|Texturenloaders]] (alternativ kann man den sich natürlich auch selbst schreiben), der diese Textur für die Grafikkarte vorbereitet (also z.&amp;amp;nbsp;B. ein BMP-Bild vom BGR-Format ins RGB-Format bringt) und dann auf dieser ablegt. Danach kann diese Textur an jeder Stelle im Programm auf eine Primitve &amp;quot;geklebt&amp;quot; werden, und genauso machen wir das auch in unserer 2D-Anwendung.&lt;br /&gt;
&lt;br /&gt;
Allerdings müssen wir keine komplexen Formen darstellen, da unsere Objekte ja nicht 3D sind, sondern (meistens) schon in einem anderen Programm erstellt (oder vorgerendert wurden) und als Bilddatei abgelegt wurde. Wir laden und stellen dann also nicht die 3D-Daten dieses Modells dar (was bei komplexen 2D-Objekten wohl eh zu viel wäre), sondern kleben diese schon fertige Bilddatei mittels einer Textur auf ein Rechteck (in der GL-Terminologie &amp;quot;Quad&amp;quot; genannt, vom Primitiventyp GL_QUADS). Hoffe mal das kam gut rüber, aber ich verdeutliche dass dann besser nochmal anhand einer kleinen &amp;quot;Bilderserie&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_4.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Oben sei mal kategorisch der Vorgang geschildert um ein vorgerendertes 3D-Objekt als Textur in seine 2D-Anwendung zu bekommen. Rechts sieht man das 3D-Modell, das dann aus der gewünschten Ansicht (im obigen Falle von der Seite) im 3D-Modellierungsprogramm gerendert wird. Dieses Rendering speichert man dann in einem Format ab das der Texturenloader verarbeiten kann, lädt dies in seine OpenGL-Anwendung und stellt dies dann auf z.&amp;amp;nbsp;B. einem Quad dar (siehe letztes Bild). Natürlich spielt es keine Rolle ob man seine 2D-Objekte vorrendert oder diese von Hand zeichnet, wobei den meisten wohl Ersteres besser von der &amp;quot;Hand&amp;quot; geht.&lt;br /&gt;
&lt;br /&gt;
===Welches Bildformat ist das richtige?===&lt;br /&gt;
&lt;br /&gt;
Bevor wir nun weiter auf das Thema eingehen kümmern wir uns um die '''Frage nach dem richtigen Bildformat''' für unsere Texturen. Bildformate gibt's wie Sand am Meer, aber für unseren Zweck eignen sich nur sehr wenige (eigentlich nur ein einziges). Ich zähle die verbreitetsten Formate kurz auf und sag auch warum (oder warum nicht) und wofür man diese verwenden kann:&lt;br /&gt;
&lt;br /&gt;
*'''Joint Photographic Experts Group (*.jpg; *.jpeg)'''&lt;br /&gt;
:Das in den Weiten des WWWs wohl verbreitetste Format ist für Texturen generell eher weniger zu empfehlen, und für 2D-Objekte erst recht nicht. Zum einen ist die in diesem Format genutzte Kompression verlustbehaftet (also verlieren unsere Texturen an Qualität) und außerdem hat dieses Format keine Möglichkeit Transparenzinformationen zu speichern. Diese benötigt man aber für 2D-Objekte, denn im Normalfall wollen wir den Hintergrund des Objektes ja durchsichtig machen (dazu gleich mehr). Also sollte dieses Format nur verwendet werden wenn wir etwas darstellen wollen das sehr viele Details enthält (dann fällt die verlustbehaftete Kompression nicht so stark auf) und keine transparenten Bereiche enthält.&lt;br /&gt;
&lt;br /&gt;
*'''Graphical Interchange Format (*.gif)'''&lt;br /&gt;
:Direkt aus der Steinzeit des IT-Sektors kommt das (im Netz noch weit verbreitet) GIF-Format. Für unsere Zwecke ist es total unbrauchbar. Es ist eine Palettenformat, das maximal 256 verschiedene Farben unterstützt, allerdings inklusive Transparenzinformationen. Aber die maximal 256 Farben und die kaum vorhandene Kompression machen es für unseren Zweck nutzlos. Die Tatsache dass es Animationen unterstützt ist zwar im Internet für kleine animierte Sachen ganz toll, aber hilft uns auch nicht, denn dazu überwiegen die Nachteile zu stark&lt;br /&gt;
&lt;br /&gt;
*'''Portable Network Graphic (*.png)'''&lt;br /&gt;
:Der Nachfolger des GIF-Formates. Eigentlich auch sehr gut für Texturen geeignet, denn neben einem Alphakanal (maximal 8 Bit) und 8 Bit pro Farbkanal unterstützt es auch verlustfreie Kompression (mit einem recht hohen Kompressionsfaktor). Nachteil ist allerdings der Aufbau des Formates, denn der Chunkaufbau macht das Laden recht schwer und bisher gibt es nur Loader die eine DLL-Datei mit sich schleppen. Alternativ kann man auf neuen Betriebssystemen jedoch via GDI+ auch PNG-Dateien direkt laden.&lt;br /&gt;
&lt;br /&gt;
*'''TARGA (*.tga)'''&lt;br /&gt;
:Dieses Format werden sicherlich nicht viele Einsteiger kennen, allerdings ist dies '''''das perfekte Format für unsere Bedürfnisse bzw. Texturen im Allgemeinen'''''. Es kann nämlich bis zu 8 Bit pro Farbkanal (also das was man heute als 32-Bit Farbtiefe bezeichnet) speichern (= 24 Bit für Farben) und dazu noch einen Alphakanal (maximal 8 Bit). Der Alphakanal ist sehr nützlich, denn in ihm kann man die Transparenzinformationen eines Bildes ablegen. Auch viele kommerzielle Titel nutzen dieses Format (u.&amp;amp;nbsp;a. Quake3), und das aus gutem Grund. Kompression wird auch unterstützt, und zwar verlustfrei in Form einer LZW-Kompression. Alles in allem ist das momentan das geeignetste Format für Texturen, zumal so gut wie jedes Bildbearbeitungsprogramm damit umgehen kann. Nebenbei ist dies Format auch recht einfach aufgebaut und damit auch recht leicht einzulesen.&lt;br /&gt;
&lt;br /&gt;
*'''BITMAP (*.bmp)'''&lt;br /&gt;
:Das BMP-Format dürfte sicherlich jedem ein Begriff sein, ist aber genauso wie GIF ein Relikt aus der Steinzeit. Es kann zwar genauso wie das TGA-Format neben den 8 Bits pro Farbkanal auch einen maximal 8 Bits großen Alphakanal anbieten, allerdings kommen damit nur recht wenige Bildbearbeitungprogramme klar. Außerdem sind die Bilddaten hier im BGR-Format abgelegt, statt dem eher üblichem RGB-Format (Red, Green, Blue). Das ist zwar sehr leicht umzuwandeln, bzw. kann mit passender GL-Konstante auch direkt übergeben werden, aber trotzdem ist dieses Format in keinem Falle dem TARGA-Format vorzuziehen.&lt;br /&gt;
&lt;br /&gt;
*'''[[DDS|DirectDraw Surface (*.dds)]]'''&lt;br /&gt;
:Ein sehr neues Format, das den Ursprung (wie am Namen zu erkennen) in Microsofts DirectX-Schnittstelle hat. Es ist ein recht modernes Format, das speziell für die Speicherung von Texturen entwickelt wurde. Allerdings ist das eher was für Fortgeschrittene, denn weder das Laden dieses Formates ist einfach, noch seine Speicherung (selbst teure Bildbearbeitungsprogramme brauchen ein passendes Plugin für DDS und bei der Erstellung des Formates muss man auf bestimmte Sachen achten). Aber ich wollte es hier trotzdem mal erwähnt haben, damit man sieht das es auch spezielle Formate für Texturen gibt, und wenn ihr euch eingearbeitet habt, dann könnt ihr im Forum mehr zu dem Format finden (Mars hat dort auch einen grundlegenden Loader gepostet), denn es ist recht interessant. Es unterstützt feste Kompressionsratios, Mip-Maps, 3D-Texturen, uvm. '''Für fortgeschrittene 3D-Programmierer sollte DDS also das Format der Wahl sein''', denn es wurde als einziges der verbreiteten Bildformate speziell für diesen Bereich konzipiert. Vor allem die Tatsache dass die Kompression dieses Formates von den Grafikkarten direkt unterstützt wird prädestiniert es für diesen Anwendungsfall. So spart man sowohl beim Hochladen als auch beim Rendern viel Busbandbreite, da die GPU die Textur auch intern komprimiert behandelt und spart logischerweise auch VRAM. Man darf sich allerdings nicht vom Platzverbrauch der eigentlichen Datei irrtieren lassen, denn das Kompressionsformat ist fest (z.B. 4:1, 6:1, etc.) statt variable wie u.A. bei JPGs. Aber dafür entspricht dann die Dateigröße exakt der Größe die auch im VRAM belegt wird. Allerdings sollte man hier genau wissen was man tut, da es sehr viele Foramte innerhalb des DDS geben kann (DXT1, DXT3, DXT5, Palette, Fließkomma, etc.) und es durchaus Texturen gibt die durch den festen Kompressionsratio schlecht aussehen können. Ein gutes Beispiel ist hier ein blauer Himmel mit Sonne und Wolken, der durch einen weichen Farbverlauf gekennzeichnet ist. Da bei DXT1/3/5 fest komprimiert wird kann dort die Bildqualität sehr stark leiden. Dann sollte man im DDS unkomprimiert ablegen. Außerdem gibt es inzwischen auch einen recht brauchbaren Loader für DDS in Delphi, und Lossys [[glBitmap]] kann dieses Format auch laden.&lt;br /&gt;
&lt;br /&gt;
Die obige Liste dürfte also einen recht (groben) Überblick über die verbreiteten Bildformate geben, und für dieses Tutorial begnügen wir uns erstmal mit dem TARGA-Format. Das wurde übrigens bereits 1984 erfunden, ist aber trotzdem noch nicht veraltet, sorgt aber dafür das so ziemlich jedes Programm damit umgehen kann.&lt;br /&gt;
&lt;br /&gt;
Wer sich übrigens nicht auf einen fremden Texturenloader verlassen möchte, sondern sich selbst um das Einlesen der Bildformate kümmern will, der sollte mal eine Blick auf [http://www.wotsit.org wotsig.org] werfen, einer recht großen Bibliothek die es sich zur Aufgabe gemacht hat Spezifikationen für Dateiformate zu sammeln. Dort wird man zu jedem der oben gennannten Bildformate eine solche Spezifikation finden, anhand derer man dann selbst Laderoutinen schreiben kann.&lt;br /&gt;
&lt;br /&gt;
===Textur laden===&lt;br /&gt;
&lt;br /&gt;
Auch wenn es ein sehr simples Unterfangen ist eine Textur zu laden, werde ich hier trotzdem nochmal kurz darauf eingehen. Das Tutorial richtet sich ja an Einsteiger, und von daher kann es nicht schaden auch mal kurz zu zeigen wie man so eine Textur lädt. Nutzen tun wir dazu die ''Textures.pas'' (die im Original von Jan Horn stammt. Ein weitere guter Loader ist [[Glbitmap_loader|glBitmap.pas]]), die sich im Download des Beispiels für dieses Tutorial befindet. Der Loader kann JPG, BMP und TGA laden. Außerdem lädt er auch den Alphakanal aus einer TGA-Textur.&lt;br /&gt;
&lt;br /&gt;
Bevor wir die Textur laden können, benötigen wir eine Variable in der wir den Bezeichner der Textur speichern. OpenGL erstellt für alle Ressourcen eindeutige Bezeichner (Bezeichner hier in Form eines Integerwertes, also einer eindeutigen ID), so auch für Texturen. Dieser Bezeichner ist vom Typ glUInt (U=unsinged Int=Integer, also vorzeichenloser Ganzzahlwert, was in Delphi dem Variablentyp ''Cardinal'' entpricht). Deshalb deklarieren wir unseren Texturenbezeichner auch so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;var&lt;br /&gt;
 MyTex : glUInt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir mehrere Texturen laden und verwalten wollen, bietet sich natürlich ein (dynamisches) ''array of glUInt'' an, aber das sind Delphigrundlagen die in diesem Tutorial nichts zu suchen haben.&lt;br /&gt;
&lt;br /&gt;
Das Laden der Textur geht nun dank der ''Textures.pas'' ganz einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;LoadTexture('MeineTextur.tga', MyTex, False);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameter sollten recht logisch sein, der erste gibt den Dateinamen der Textur an, der zweite das Texturobjekt (in das die ID der Textur geschrieben wird) und der letzte Parameter gibt an ob die Textur aus einer dem Programm angehängten Ressource geladen werden soll. Sollte der Ladevorgang erfolgreich gewesen sein, so müsste sich in ''MyTex'' ein Wert &amp;gt; 0 befinden, nämlich der eindeutige Bezeichner dieses Texturenobjektes.&lt;br /&gt;
&lt;br /&gt;
===Textur anwenden===&lt;br /&gt;
&lt;br /&gt;
Wer sich schonmal ein wenig über OpenGL schlau gemacht hat, der wird wissen dass die GL eine Statemachine ist. Das trifft auch auf Texturen zu, denn wenn eine Textur gebunden wurde, wird sie solange auf alle Primitiven angewendet, bis entweder eine andere Textur gebunden wurde oder das Texturemapping über [[glDisable]] abgeschaltet wird. Das hat besonders dann den Vorteil, wenn man viele Objekte mit der gleichen Textur rendern muss, denn Texturenwechsel sind recht kostspielig. Von daher sollte man also bei vielen Objekten eine Sortierung nach Textur vornehmen, dann diese Textur binden und danach dann alle Objekte die diese Textur besitzen rendern.&lt;br /&gt;
&lt;br /&gt;
Doch bevor Texturen überhaupt angezeigt werden, müssen wir OpenGL erstmal mitteilen das es diese auch anzeigen soll. Dazu gibt es die Funktion '''glEnable''', der man mit der Konstante '''GL_TEXTURE_2D''' mitteilt das wir die 2D-Texturierung aktivieren wollen (1D oder 3D-Texturen benötigen wir ja in diesem Tutorial nicht):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glEnable(GL_TEXTURE_2D);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unglaublich einfach, oder? So schnell kann das dank einer gut durchdachten API wie OpenGL gehen. Jetzt wo wir der API erstmal gesagt haben dass wir gerne Texturen sehen möchten, müssen wir auch noch sagen welche Textur als nächstes auf unserer Primitiven gezeigt werden soll. Dazu bindet (~ aktiviert) man das passende Texturobjekt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBindTexture(GL_TEXTURE_2D, MyTex);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Von nun an werden alle folgenden Primitiven solange mit der hinter ''MyTex'' abgelegten Textur gerendert, bis das Texturemapping entweder deaktiviert wird oder wir eine andere Textur binden.&lt;br /&gt;
&lt;br /&gt;
===Transparenz===&lt;br /&gt;
&lt;br /&gt;
Eine wichtige Sache die es noch zu klären gibt ist Transparenz. Oben habe ich ja gesagt das wir unsere Objekte auf Quads kleben (über eine Textur), aber unsere vorgefertigten Objekte nur selten auch genau die Form eines Quads haben. Der Panzer auf der oben gezeigten Textur wird z.&amp;amp;nbsp;B. von sehr viel schwarz umgeben, das wir da natürlich nicht sehen wollen. Aber auch um die Transparenz brauchen wir uns unter OpenGL keine Sorgen zu machen, denn dafür gibt es den sog. Alphakanal der Textur, der angibt welche Teile einer Textur später transparent (oder besser gesagt gar nicht, aber dazu gleich mehr) gezeigt werden sollen. Aus diesem Grund haben wir uns mit dem TGA-Format auch ein Format gewählt das diesen Kanal direkt im Bild speichern kann, sodass wir diesen nicht extra erstellen oder aus einer seperaten Bilddatei laden müssen.&lt;br /&gt;
&lt;br /&gt;
Wie man den Alphakanal nun in die Textur bekommt hängt davon ab wie man seine Textur erstellt. Wer seine Objekte von Hand malt, der muss den Alphakanal im Bildbearbeitungsprogramm selbst erstellen. Wer seine Objekte allerdings vorrendert, der kann diese Arbeit im Normalfall von der 3D-Software erledigen lassen, die Alphainformationen direkt mitexportieren kann. Als kleiner Hinweis sei übrigens gesagt das man beim Rendering des Objektes im 3D-Programm die Kantenglättung deaktivieren muss, da man sonst an den Rändern Artefakte hat (die logischerweise Teile der Hintergrundfarbe enthalten) die dann in der OpenGL-Anwendung zu unschönen Effekten führen. Um das zu verbildlichen hier nochmal unsere Panzertextur, allerdings begleitet vom (im Bildformat gespeichertem) Alphakanal:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_5.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links also unsere Textur und rechts der Alphakanal. Den sieht man normalerweise nicht, aber fast jedes Bildbearbeitungsprogramm gibt einem die Möglichkeit sich diesen anzeigen zu lassen. Wie zu sehen befinden sich in unserem Falle nur zwei Werte im Alphakanal. Und zwar Schwarz (= 0) für komplett transparent und Weiß (= 1) für komplett Sichtbar.&lt;br /&gt;
&lt;br /&gt;
Unter OpenGL nutzen wir jetzt für die Transparenz den [[GlAlphaFunc|Alphatest]]. Transparenz ließe sich auch über Blending realisieren, allerdings hat Blending den Nachteil das man dann die transparenten Objekte nach Tiefe sortieren müsste, da Blending im Framepuffer abläuft und nicht wie der Alphatest auf Fragmentbasis, wo wir uns dann keine Sorge um die Reihenfolge unserer Objekte machen müssen. Wollen wir nun also den Alphakanal der Textur nutzen (natürlich muss dieser vorher im Texturenloader geladen werden, sonst geht's nicht) müssen wir vor dem rendern des mit der Objekttextur belegten Quads den Alphatest aktiveren und festlegen wie der Test auszusehen hat :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glEnable(GL_ALPHA_TEST);&lt;br /&gt;
glAlphaFunc(GL_GREATER, 0.1);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zuerst aktiveren wir also den Alphaest (dazu gibt es die Konstante '''GL_ALPHA_TEST'''), bevor wir dann der GL mittels [[GlAlphaFunc|glAphaFunc]] sagen wie der Test aussehen soll. Der erste Parameter ('''GL_GREATER''') gibt an, das nur Fragmente (also Teile der Textur) gerendert werden sollen deren Alphawert größer ist als der im zweiten Wert angegebene (0.1). Wie auch Farbwerte wird der Alphawert unter OpenGL &amp;quot;geclampt&amp;quot;, also in eine bestimmte Reichweite gebracht, nämlich 0 (= Schwarz) bis 1 (= Weiß). Die 0,1 (statt der 0) als Vergleichswert nehmen wir quasi aus Toleranz. Wenn wir das obige also getan haben, dürften wir auf unserem Quad (sofern der Alphakanal korrekt erstellt und geladen wurde) also nur noch das eigentliche Objekt sehen, und der Hintergrund müsste an den transparenten (Alpha &amp;lt;= 0,1) zu sehen sein:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_6.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links sehen wir unsere Bohne ohne aktiven Alphatest, was zur Folge hat das der eigentlich transparente (schwarze) Teil der Objekttextur den Hintergrund überdeckt. Rechts wuede der Alphatest aktiviert und wir sehen nur den Teil unseres Objektes den wir auch sehen wollen.&lt;br /&gt;
&lt;br /&gt;
===Das Objekt anzeigen===&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun unsere Textur mit passendem Alphakanal geladen haben und den Alphatest auch aktiviert haben, müssen wir schlussendlich noch unser(e) Objekt(e) rendern. Wie schon mehrfach gesagt nutzen wir dazu die GL_QUADS-Primitive. Bei diesem Primitiventyp beschreiben wir mit vier Eckpunkten ein Rechteck (das von der Grafikkarte dann in zwei Dreiecke zerlegt wird), wobei jeder Eckpunkt auch eine Texturkoordinate zugewiesen bekommt. Diese Koordinate gibt an, aus welchem Teil der Textur dieser Eckpunkt seine Bilddaten beziehen soll, und sie wird über das gesamte Quad hinweg interpoliert. Also haben wir in der genauen Mitte des Quads als interpolierte Texturkoordinate das genaue Mittel der übergebenen Texturkoordinaten. Um diese Interpolation müssen wir uns allerdings keine Sorgen machen, das macht die Grafikkarte.&lt;br /&gt;
&lt;br /&gt;
Und in Sachen Texturkoordinaten sind wir auch schnell fertig, denn für den Anfang haben wir pro Textur immer nur ein Objekt (später zeige ich dann wie man mehrere Objekt in eine Textur packt) und müssen dementsprechend auch nur eine 1 (= Ende der Textur) bzw. 0 (= Anfang der Textur vergeben. Wenn man sich das bildlich vorstellt, sieht das dann so aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_7.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Da wir nur mit 2D-Texturen arbeiten, müssen wir pro Eckpunkt auch nur zwei Koordinaten angeben. Und zwar einmal in X-Richtung auf der Textur (unter OpenGL auch S-Richtung genannt, oft auch mit &amp;quot;U&amp;quot; betitelt) und in Y-Richtung (unter OpenGL T-Richtung, oft auch &amp;quot;V&amp;quot; genannt). Wenn S=0 und T=0, bedeutet das also das dieser Eckpunkt seinen [[Texel|Texel]] (wie Pixel, bloß im Bezug auf Texturen) aus der oberen linken Ecke unserer Textur (X=0/Y=0) bezieht, während S=1 und T=1 dafür sorgt das der Eckpunkt sich den Texel in der untersten rechten Ecke der Textur schnappt. Wie bereits oben erwähnt müssen wir uns um den Raum zwischen den vier Eckpunkten nicht kümmern, das wird ja von der Hardware linear interpoliert.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode zu obigem Beispiel sieht dann so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBegin(GL_QUADS);&lt;br /&gt;
 glTexCoord2f(0,0); glVertex3f(-Breite/2, -Höhe/2, -Tiefe);&lt;br /&gt;
 glTexCoord2f(1,0); glVertex3f(+Breite/2, -Höhe/2, -Tiefe);&lt;br /&gt;
 glTexCoord2f(1,1); glVertex3f(+Breite/2, +Höhe/2, -Tiefe);&lt;br /&gt;
 glTexCoord2f(0,1); glVertex3f(-Breite/2, +Höhe/2, -Tiefe);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer obigen Text aufmerksam gelesen hat, sollte eigentlich problemlos verstehen was der Quellcode denn bewirkt. Wer damit Problem hat, der sollte sich das obige Kapitel nochmal unbedingt sorgfältig durchlesen, denn das ist eine sehr wichtige Sache.&lt;br /&gt;
&lt;br /&gt;
Soviel also zu den Grundlagen von 2D unter OpenGL. Wer nämlich hier angelangt ist, sollte zumindest 2D-Objekte unter OpenGL anzeigen können. Evtl. ist es hier angebracht das Tutorial einige Minuten ruhen zu lassen und ein wenig mit dem Erlerntem herumzuprobieren. Danach geht's nämlich mit etwas fortgeschritteneren (aus Sicht des Einsteigers) Themen weiter.&lt;br /&gt;
&lt;br /&gt;
===Die Rolle des Tiefenpuffers===&lt;br /&gt;
&lt;br /&gt;
Trotz der Tatsache dass wir in 2D die dritte Dimension vernachlässigen, bedeutet dies nicht das wir den Tiefenpuffer nicht doch nutzen können. Und zwar nutzen wir diesen in 2D zur hardwarebeschleunigten Sortierung unserer Objekte. In 2D-Anwendungen kann es ja genauso vorkommen das ein Objekt unter (&amp;quot;hinter&amp;quot;) einem anderen liegt und da wäre es ziemlich dumm diese selbst zu sortieren, wo OpenGL uns doch einen Tiefenpuffer anbietet der dies für uns macht.&lt;br /&gt;
&lt;br /&gt;
Genau deshalb haben wir mittels glOrtho auch die Reichweite für unseren Tiefenpuffer angegeben. Haben wir dann auch noch den Tiefentest mittels {{INLINE_CODE|glEnable(GL_DEPTH_TEST)}} und dem passenden Tiefentest via {{INLINE_CODE|[[glDepthFunc]](GL_LESS ''oder'' GL_EQUAL)}} aktiviert, so können wir über die Z-Koordinate unserer Objekte angeben wo die nun genau liegen. Ein Objekt dessen Z-Koordinate also näher an Z-Near ist, wird dann über einem an gleicher Stelle befindlichem Objekt mit einer Z-Koordinate näher an Z-Far gerendert, und zwar egal welches dieser Objekte wir als erstes an die GL übergeben haben.&lt;br /&gt;
&lt;br /&gt;
===Backface Culling===&lt;br /&gt;
&lt;br /&gt;
Auch diese von OpenGL angebotene Funktionalität sollte hier nicht verschwiegen werden. Denn in OpenGL bestehen Flächen immer aus einer Vorder- und Rückseite (wie im echten Leben, ein Blatt Papier hat ja auch zwei Seiten, egal wie dünn es ist), was spätestens dann Sinn macht wenn man bedenkt das man sich in einer 3D-Umgebung ja komplett frei bewegen kann. Doch in unserer 2D-Welt sehen wir immer nur eine Seite unserer Objekte, egal was wir anstellen. Und genau deshalb sollten wir OpenGLs [[Backface Culling]] (zu Deutsch heisst das wörtlich &amp;quot;Rückseiten Ausschluß&amp;quot;, aber solche Fachbegriffe deutsch man auch besser nicht ein) aktivieren, denn ist dies nicht der Fall, so werden alle Berechnungen immer für beide Seiten eines Polygons ausgeführt. Und dabei spielt es keine Rolle welche der Seiten sichtbar ist oder nicht. Wir aktivieren also das Backfaceculling und sagen OpenGL dass die Rückseiten der Primitiven nicht dargestellt werden soll (letzteres könnte man sich sparen, da das die Voreinstellung ist, allerdings sollte man lieber auf Nummer sicher gehen):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glEnable(GL_CULL_FACE);&lt;br /&gt;
glCullFace(GL_BACK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Solltet ihr jetzt übrigens eure Objekte nicht mehr sehen, dann habt ihr die Eckpunkte eurer Primitiven in der falschen Reihenfolge (Standard ist für OpenGL '''GL_CCW''' ('''C'''ounter'''C'''lock'''W'''ise, gegen den Uhrzeigersinn) angegeben. Ich empfehle dann entweder einen Blick ins Reedbook oder in eine der Beispielanwendungen, wo es eine Funktion namens ''DrawQuad'' gibt, die ein korrektes Quad rendert. Bei modernen Grafikkarten sollte das Backface Culling zwar nur recht wenig Performance bringen, aber es wäre trotzdem Performanceverschwendung dieses nette Feature einfach ungenutzt zu lassen.&lt;br /&gt;
&lt;br /&gt;
==Animation==&lt;br /&gt;
Bisher können wir zwar unsere 2D-Objekte mittels texturierter Quads auf dem Bildschirm darstellen, aber das ist natürlich noch recht statisch; und was wäre ein Computerspiel ohne Animationen? Und genau darum kümmern wir uns jetzt. Aber zuerst kurz zum Unterschied &amp;quot;Animation in 3D&amp;quot; und &amp;quot;Animation in 2D&amp;quot;. In 3D ist es normalerweise so, dass man ein 3D-Modell lädt und dann die einzelnen Teile des Modells animiert, sei dies über die GL-Befehle oder Animationsdaten im 3D-Format (Bones, Keyframes). Das bedeutet also das man in 3D quasi unendlich viele Freiheiten hat, denn man kann ja z.&amp;amp;nbsp;B. den Turm eines Panzers über [[glRotate]]f in jeden beliebigen Winkel bringen. In 2D ist das anders, denn da sind ja alle Grafiken vorgefertigt und werden nur abwechselnd auf unsere Quads geklebt. Würden wir dort also den Turm eines vorgefertigten Panzers rotieren lassen wollen, so müssten wir jeden Animationsframe vorfertigen und als Textur laden. Man muss sich also vorher Gedanken drüber machen ob 2D denn im Endeffekt wirklich weniger Aufwand bedeutet. Aber diese Entscheidung muss jeder für sich selbst fällen, weshalb wir uns nun zwei verschiedenen Animationsmöglichkeiten widmen werden.&lt;br /&gt;
&lt;br /&gt;
===Animation über Einzeltexturen===&lt;br /&gt;
''(Projektdatei : openGL2D_demo1)''&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_8.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Die wohl offensichtlichste (und auch einfachste) Art ein 2D-Objekt über Texturen zu animieren, ist über in einzelnen Texturen abgelegte Frames. Besonders aus einem 3D-Animationsprogramm (3D Studio, Maya) geht das besonders einfach. Denn diese Programme können eine Animation als Einzelbilder auf die Platte rendern. Dadurch hat man dann für eine Animation mit 60 Bildern 60 Texturen die dann einfach in ein Array geladen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;var&lt;br /&gt;
 Frame : array of glUInt;&lt;br /&gt;
&lt;br /&gt;
SetLength(Frame, NumFrames);&lt;br /&gt;
for i := 0 to NumFrames-1 do&lt;br /&gt;
 LoadTexture('animframe'+IntToStr(i)+'.tga', Frame[i], False);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das zu animierende Objekt verpasst man dabei mit einem Fließkommawert der den aktuell anzuzeigenden Frame darstellt, und erhöht diesen dann über die Zeit. Beim Rendern des Objektes nutzt man diesen Wert gerundeten (Indizes müssen ja Ganzzahlwerte sein) als Index in das Texturenarray:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBindTexture(GL_TEXTURE_2D,Frame[Round(CurrentFrame)]);&lt;br /&gt;
...&lt;br /&gt;
CurrentFrame := CurrentFrame + 0.025 * TimeFactor;&lt;br /&gt;
if CurrentFrame &amp;gt; Length(Frame) then&lt;br /&gt;
 CurrentFrame := 0;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil dieser Methode ist das man diese Animationen direkt aus seinem 3D-Programm heraus speichern kann und das die Animationen quasi unendlich lange (wobei sowohl Speicherplatz als auch Speicherausbau der Grafikkarte hier limitierende Faktoren sind) sein können. Nachteil ist der hohe Speicherverbrauch, sowohl auf der Platte als auch im Grafikspeicher, sowie die Tatsache das man dann recht oft die Textur wechseln muss.&lt;br /&gt;
&lt;br /&gt;
===Animation in einer einzigen Textur===&lt;br /&gt;
''(Projektdatei: openGL2D_demo2)''&lt;br /&gt;
&lt;br /&gt;
Diese Art der Animation ist wie oben schon angedeutet recht speichersparend und vermindert auch die Zahl der Texturenwechsel. Allerdings ist sie auch aufwendiger zu implementieren und unterliegt einigen Einschränkungen die man bei der Erstellung der Animationstextur berücksichtigen sollte. Statt also jeden Frame der Animation in einer eigenen Datei (und damit später auch Textur, obwohl sich das natürlich auch kombinieren lässt) abzulegen, wird versucht bei dieser Animationsart alle Frames in einem Gitter auf einer Textur anzuordnen.&lt;br /&gt;
&lt;br /&gt;
Wenn man nicht noch mit der Erstellung komplexer Texturkoordinaten rumfuchteln will, dann sollte man drauf achten dass das gewählte Gitter so hoch wie breit ist und die Texturen an diesem Gitter ausgerichtet sind. So habe ich bei dieser Beispieltextur (bevor sie für das Tutorial etwas verkleinert wurde) die Frames in einem Raster von 256x256 Pixeln untergebracht.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Explosion_det.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Zu sehen sind hier alle Animationsframes einer Explosionstextur aus der Beispielanwendung. Diese wurd mit einem entsprechenden Tool generiert, aber kaum ein 3D-Porgramm kann Animationen direkt in eine einzelne Textur exportieren. Hier muss man sich dann mit passenden Plug-Ins oder Drittprogrammen aushelfen.&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Abspielen&amp;quot; dieser Animation ist nun recht einfach, denn wir erinnern uns ja daran das die Texturkoordinaten in OpenGL immer im Bereich 0 bis 1 liegen, unabhängig (es gibt Ausnahmen, aber interessiert hier nicht) von der Größe unserer Textur. Also müssen wir im Endeffekt nur wissen wie viele Spalten und Zeilen unsere Animationstextur enthält um für jeden Frame die passenden Texturkoordinaten errechnen zu können. Um es konkret zu machen nehmen wir obiges Beispiel. Es besteht aus drei Reihen und drei Spalten, wobei die Animationen von links nach rechts durchlaufen. Also bedeutet dies das unser erster Animationsframe bei S=0 / T=0 beginnt und bei S=1/4 / T=1/4 Ende, Frame 2 beginnt dann bei S=1/4 / T=0 und endet bei S=2/3 / T=1/4, usw. Dies zu errechnen sollte als keine Probleme bereiten, genauso wie das Rendern.&lt;br /&gt;
&lt;br /&gt;
Doch dürfen wir die Nachteile dieser Animationsart auch nicht verschweigen. Das es oft schwierig ist (wenn man die Objekte und Animationen sowieso von Hand zeichnet dann natürlich nicht) aus den Animationsframes eine einzelne Textur zu machen habe ich bereits gesagt, aber man muss auch wie immer auf die Hardwarelimitationen achten. Denn wenn man viele Animationen in einer Textur unterbringen will, wird diese oft recht groß und selbst auf modernen Karten sollte die Textur nicht größer als 2048x2048 Pixel sein. Wenn wir also ein Objekt der Größe 256x256 haben, bekommen wir im besten Falle (2048 wird auf älteren Karten entweder nicht machbar sein, deren Grafikkartenspeicher fast ganz aufbrauchen, oder zu langsam sein) 64 Animationsframes auf eine Textur. Alles darüber müsste man dann in eine weitere Textur auslagern, was den Verwaltungsaufwand stark erhöhen würde. Ausserdem muss man drauf achten, dass sich die Animationsframes nicht direkt berühren, also das zwischen einem sichtbarer Objektteil in Frame N mindestens ein Pixel Abstand zum sichtbaren Objektteil in Frame N+1 besteht. Denn dadurch das die Textur von OpenGL gefiltert wird, verlaufen Pixel die direkt aneinander liegen ineinander; wodurch dann unschöne Effekte entstehen. Ein weitere (allerdings nicht so gravierender) Nachteil ist die Tatsache dass man solche Animationen nicht über Texturenwiederholung mehrfach auf ein Objekt legen kann. Wenn man bei der erstgenannten Animationsart z.&amp;amp;nbsp;B. statt S=1/T=1 S=2/T=2 nutzt, dann wird dann Animation insgesamt viermal auf dem Quad wiederholt. Da man hier aber über die Texturkoordinaten quasi einen Frame aus der Textur herauspickt ist das nicht möglich, was im Normalfall aber kaum Gewicht haben sollte.&lt;br /&gt;
&lt;br /&gt;
===Rotation und Skalierung===&lt;br /&gt;
''(Projektdatei: openGL2D_demo3)''&lt;br /&gt;
&lt;br /&gt;
Wenn man alles selbst zeichnet (also z.&amp;amp;nbsp;B. mit der GDI arbeitet), dann hat man für die Rotation (oder Skalierung) eines Objektes im Normalfall nur zwei Möglichkeiten: Entweder man schreibt sich eigene Routinen die den Pixelsalat rotieren (was meist langsam ist, solange man es nicht in Assembler schreibt) oder man erstellt Bilddateien auf denen die Objekte schon vorrotiert sind. Erstere Methode ist wie gesagt langsam und sieht hässlich aus (es sei denn man filtert auch noch selbst) und die zweite Methode schränkt einen auf die vorberechneten Drehwinkel ein.&lt;br /&gt;
&lt;br /&gt;
Alle gerade genannten Probleme kann man unter OpenGL dank der hardwarebeschleunigung ad acta legen. Nicht nur dass man dank Hardware unendlich schnell rotieren kann, diese Rotation auch noch frei ist, nein, man bekommt sogar das Filtering dank Hardware umsonst:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_10.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links ist das um 15° gegenüber dem Ausgangsbild gedrehte Raumschiff ohne Filtering zu sehen. Gut ist hier die dadurch entstehende &amp;quot;Körnung&amp;quot; erkennbar, die in Bewegung noch sehr viel unschöner aussieht. Rechts sieht man das gleiche, diesmal allerdings mit Filtering. Der Unterschied dürfte direkt auffallen, und besonders auf hellen Hintergründen ist er noch frapierender. Natürlich sollte man die Grundlagen von OpenGL beherrschen um die Rotation korrekt anwenden zu können, denn folgender Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glRotatef(45, 0,0,1);&lt;br /&gt;
glTranslatef(320, 240, 0);&lt;br /&gt;
DrawQuad(0,0,0, 256,256);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bewirkt etwas total anderes als folgender Code :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glTranslatef(320, 240, 0);&lt;br /&gt;
glRotatef(45, 0,0,1);&lt;br /&gt;
DrawQuad(0,0,0, 256,256);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer sich die OpenGL-Grundlagen bereits angeeignet hat, der wird sicher schnell erkannt haben wo der Unterschied liegt. Denn in OpenGL bewegt man Objekte nicht direkt, sondern immer nur den Ursprung der Matrix. Ersterer Code rotiert also unsere Matrix um 45° und verschiebt diese dann um 320 Einheiten auf der X- und 240 auf der Y-Achse, was dazu führt das unser Objekt in einem recht großen Kreis um den Ursprung rotiert wird. Der zweite Codeschnippsel hingegen verschiebt unser Objekt an den Punkt 320/240 (in unserem Falle genau die Bildschirmmitte) und rotiert dann dort unser Objekt um die eigene Achse. Das ist auch der Rotationscode den wir im Normalfall nutzen um ein Objekt um sich selbst rotieren zu lassen. In unserer 2D-Anwendung müssen wir auch prinzipiell nur um die Z-Achse rotieren, denn die ragt in OpenGL &amp;quot;in&amp;quot; den Bildschirm hinein. Um das nachzuvollziehen einfach mal den rechten Arm grade ausstrecken und &amp;quot;um&amp;quot; den ausgestreckten Zeigefinger rotieren lassen. Euer Arm stellt dann in diesem Falle die Z-Achse dar.&lt;br /&gt;
&lt;br /&gt;
Das Skalieren eines Objektes gestaltet sich noch leichter, denn hier muss man nichts weiter machen als vor dem Rendern des Quads ein glScalef aufzurufen und diesem dann den Skalierungsfaktor (1=keine Skalierung) pro Achse zu übergeben. Da wir hier allerdings nur in 2D arbeiten sollten wir die Z-Skalierung immer bei 1 belassen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(2,2,1);&lt;br /&gt;
DrawQuad(0,0,0, 256,256);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obiger Quellcode zeichnet unser Objekt in der doppelten Größe (also statt 256x256 Einheiten 512x512 Einheiten groß). Über die Skalierung kann man schön in 2D einen Tiefeneffekt realisieren, zum Beispiel ein Raumschiff das mit einer Skalierung von 0,5 /0,5 / 1 auf einem Träger startet und dann zu Beginn des Levels langsam in Richtung 1 / 1 / 1 skaliert wird. Dadurch wird das Schiff größer und es entsteht beim Betrachter der Eindruck, das Schiff würde hinaufsteigen.&lt;br /&gt;
&lt;br /&gt;
==Scrollen und zoomen==&lt;br /&gt;
''(Projektdatei: openGL2D_demo4)''&lt;br /&gt;
&lt;br /&gt;
Selbst viele kommerzielle 3D-Spiele benötigen oft einen 2D-Teil um solche Sachen wie Übersichtskarten (man will ja gerne wissen wo man hin will) oder evtl. Credits und ähnliche größere 2D-Anzeigen zu tätigen, die oft den ganzen Bildschirm einnehmen oder gar größer sind. Besonders bei solchen Sachen wie z.&amp;amp;nbsp;B. einer großen Übersichtskarte (sei es nun die Strategiekarte für einen Schlachtplatz im Zweiten Weltkrieg, oder die Übersichtskarte eines Fantasyreiches) sind die Vorteile von OpenGL (wie an dem im Download enthaltenem Beispiel zu erkennen) gut ersichtlich. Das Scrollen wird durch einen einfachen Aufruf an [[glTranslate]]f erledigt (um die außerhalb des sichtbaren Bereichs liegenden Teile der Karte muss man sich dabei keine Sorgen machen), während man das vergrößern der Karte (~ zoomen) mit einem einfachem [[glScale]]f vollbringen kann.&lt;br /&gt;
&lt;br /&gt;
Und dank der Hardwarebeschleunigung wird diese Karte schneller angezeigt als man dies von Hand (oder über andere 2D-APIs je tun) könnte. Auf einer halbwegs modernen Grafikkarte sollten locker an die 1000 FpS drin sein.&lt;br /&gt;
&lt;br /&gt;
Nachdem man die Übersichtskarte geladen hat, gestaltet sich das Rendern selbiger als sehr einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBindTexture(GL_TEXTURE_2D, MapTex);&lt;br /&gt;
glTranslatef(MapPos.x, MapPos.y, 0);&lt;br /&gt;
glScalef(MapScale, MapScale, MapScale);&lt;br /&gt;
DrawQuad(0,0,0, MapSize.x,MapSize.y);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht schockierend einfach aus. Mehr braucht es nicht um eine Übersichtskarte zu scrollen und zu zoomen. Allerdings sollte man wie bereits einige Male erwähnt wurde auf die Hardwarelimiationen achten. Wenn die Übersichtskarte also allzu groß sein sollte, dann kann man diese ja ohne Probleme unterteilen und als mehrere Quads rendern. Außer der etwas abgeänderten Positionierung der einzelnen Kartenteile ändert sich aber am Grundprinzip nichts.&lt;br /&gt;
&lt;br /&gt;
==Tiling (Kachelung)==&lt;br /&gt;
''(Projektdatei: openGL2D_demo5)''&lt;br /&gt;
&lt;br /&gt;
Die oben genannte Technik mag zwar gut genug für statische Übersichtskarten sein, aber wenn man eine dynamische Karte aus der Vogelperspektive realisieren will, so kommt man mit einer riesigen vorgefertigten Textur nicht weit. Dafür gibt es dann aber eine Technik namens &amp;quot;Tiling&amp;quot;, was zu Deutsch so viel wie &amp;quot;Kachelung&amp;quot; heißt. Hier hat man ähnlich einem Schachbrett ein zweidimensionales Spielfeld das aus unterschiedlichen Kacheln besteht die als Texturen vorliegen. In einem zweidimensionalem Array wird dann für jedes Feld gespeichert welche Textur zu ihm gehört. Diese Technik ist immer noch recht weit verbreitet (zumindest im Hobbybereich) und für 2D-Spiele aus der Vogelperspektive recht gut geeignet, wobei hier der Großteil der Arbeit eher beim Grafiker als beim Programmierer liegt, denn da die Teils nur Vierecke darstellen müssen Übergänge von z.&amp;amp;nbsp;B. einem Terraintyp zum anderen in die Textur gezeichnet werden. &lt;br /&gt;
&lt;br /&gt;
Das Rendern eines solchen Spielfeldes gestaltet sich dabei sehr einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;for x := 0 to MapWidth-1 do&lt;br /&gt;
 for y := 0 to MapHeight-1 do&lt;br /&gt;
  begin&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, MapTexture[Map[x,y]]);&lt;br /&gt;
  DrawQuad(MapPos.x+x*32, MapPos.y+y*32, 0, 32,32);&lt;br /&gt;
  end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Allerdings ist obige Methode alles andere als optimiert. Das erste (und größte) Problem ist die Tatsache das unabhängig von aktuellen Betrachtungsposition immer die komplette Karte gerendert wird. Bei großen Karten (z.&amp;amp;nbsp;B. 128x128 Kacheln) gehen dann selbst moderne Karten in die Knie. Die Kacheln außerhalb des Sichtbereiches werden zwar von der Grafikkarte nicht gerendert (da sie außerhalb des Viewports liegen), aber müssen dennoch in jedem Frame über den Bus gesendet werden, genauso wie die Texturenwechsel in jedem Frame stattfinden müssen. Das erste Problem lässt sich recht schnell lösen, in dem wir einfach prüfen ob die aktuell zu rendernde Kachel auch im momentan sichtbarem Bereich liegt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glScalef(MapScale, MapScale, MapScale);&lt;br /&gt;
for x := 0 to High(Map) do&lt;br /&gt;
 for y := 0 to High(Map[x]) do&lt;br /&gt;
  if (MapPos.x + x*32 &amp;gt;= -16*MapScale) and (MapPos.x + x*32 &amp;lt;= SizeX/MapScale+16) and&lt;br /&gt;
     (MapPos.y + y*32 &amp;gt;= -16*MapScale) and (MapPos.y + y*32 &amp;lt;= SizeY/MapScale+16) then&lt;br /&gt;
      begin&lt;br /&gt;
      glBindTexture(GL_TEXTURE_2D, MapTex[Map[x,y]]);&lt;br /&gt;
      DrawQuad(MapPos.x+x*32, MapPos.y+y*32, 0, 32,32);&lt;br /&gt;
      end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der If-Abfrage, die wir vor dem Rendern einer jeden Kachel machen, prüfen wir jetzt ganz einfach ob die aktuelle Kachel im Sichtfeld liegt. Da wir eine dynamische Karte haben und die Vorteile von OpenGL nutzen wollen, müssen wir bei dieser Abfrage natürlich auch den Zoomfaktor (''MapScale'') und das Scrolling (''MapPos'') mit einbeziehen.&lt;br /&gt;
&lt;br /&gt;
Dank dieser offensichtlichen Optimierung dürften wir jetzt einen starken Performancegewinn von mehreren hundert Prozent sehen, denn sehr viele Texturenwechsel fallen weg und es wird sehr viel weniger Geometrie über den Bus gesendet. Aber natürlich sind wir noch nicht am Ende der Fahnenstange angelangt, denn wie gesagt sind Texturenwechsel recht performancelastig. Also liegt es nahe diese zu optimieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;for t := 0 to High(MapTex) do&lt;br /&gt;
 begin&lt;br /&gt;
 glBindTexture(GL_TEXTURE_2D, MapTex[t]);&lt;br /&gt;
 for x := 0 to High(Map) do&lt;br /&gt;
  for y := 0 to High(Map[x]) do&lt;br /&gt;
   if Map[x,y] = t then&lt;br /&gt;
    if (MapPos.x + x*32 &amp;gt;= -16*MapScale) and (MapPos.x + x*32 &amp;lt;= SizeX/MapScale+16) and&lt;br /&gt;
       (MapPos.y + y*32 &amp;gt;= -16*MapScale) and (MapPos.y + y*32 &amp;lt;= SizeY/MapScale+16) then&lt;br /&gt;
        DrawQuad(MapPos.x+x*32, MapPos.y+y*32, 0, 32,32);&lt;br /&gt;
 end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen haben wir unsere Schleife etwas umgebaut. Wir gehen jetzt in der Hauptschleife durch alle unsere Kacheln (abgelegt in ''MapTex'') und dann für jede Kachel die komplette Karte in beide Dimensionen durch. So binden wir jede Texur nur einmal und rendern dann alle Kacheln die diese Textur nutzen. Das klingt erstmal so (zumindest vom Schleifenaufbau her) als würden wir hier Performance vernichten, denn schliesslich gehen wir jetzt nicht einmal die komplette Karte durch, sondern so viele Male wie wir Kacheltexturen haben. Allerdings ist es meistens so das der CPU-Overhead durch die zusätzlichen Schleifendurchläuft weniger kostet als uns die gesparten Texturenwechsel eingebracht haben. Im Normalfall (es gibt natürlich Situationen wo der CPU-Overhead zu groß wird, z.&amp;amp;nbsp;B. bei wirklich riesigen Karten) sollten wir auch durch diese Optimierung einen Performancezuwachs im zweistelligen Prozentbereich erkennen.&lt;br /&gt;
&lt;br /&gt;
So viel also zum Thema Kachelung. Besonders für kleinere Projekte ist diese Technik ein guter Start und vor allem ist diese Technik leicht umzusetzen. Ist natürlich nicht mehr zeitgemäß, aber bei den meisten Hobbyprojekten geht es ja eher um den Inhalt und nicht nur um das Äußere. &lt;br /&gt;
&lt;br /&gt;
==Spezialeffekte==&lt;br /&gt;
&lt;br /&gt;
Nach diesem langen Marsch sind wir jetzt so ziemlich mit allen im 2D-Bereich verwendeten Techniken durch und können uns nun einem interessanterem Kapitel zuwenden; den Spezialeffekten. Hier ist der eigenen Kreativität natürlich keine (oder kaum, je nach Hardware) Grenze gesetzt, weshalb ich nur einige häufig unter 2D genutzte Effekte erwähnen möchte.&lt;br /&gt;
&lt;br /&gt;
===Beleuchtung (&amp;quot;Per-Pixel&amp;quot;)===&lt;br /&gt;
''(Projektdatei: openGL2D_demo6)''&lt;br /&gt;
&lt;br /&gt;
Beleuchtung ist ja (auch wenn man das nicht so wahrnimmt, da es ja im echten Leben selbstverständlich ist) eine Sache die man in keinem Spiel vernachlässigen sollte. Ohne korrekte Beleuchtung geht viel Atmosphäre flöten, aber besonders in einer 3D-Umgebung ist korrektes Per-Pixel-Licht (die OpenGL-Beleuchtung arbeitet auf Vertexbasis) oft schwer zu implementieren (was dank Shader aber leichter geworden ist). In einer 2D-Umgebung ist das aber zum Glück sehr viel einfacher, denn dort haben wir z.&amp;amp;nbsp;B. im Falle einer 2D-Karte ja keine dritte Dimension um die wir uns kümmern müssten, müssen unsere Lichtquellen also nicht auf die Szene draufprojizieren.&lt;br /&gt;
&lt;br /&gt;
In 2D geht das also ganz einfach und wir machen die Beleuchtung bequem über eine Lichttextur in der die Intensität der Lichtquelle abgelegt ist. Für die Demo habe ich dazu einen einfachen radialen Verlauf gewählt, aber der Fantasie sind da keine Grenzen gesetzt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_12.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Farbinformationen speichern wir nicht in der Textur, denn wir wollen ja dynamisch bleiben und realisieren die Färbung des Lichtes später in unserem Programm über einen [[glColor]]3f  Aufruf. Bevor wir allerdings loslegen, sollten noch ein paar Kleinigkeiten im Bezug auf diese (einfache Form der) Beleuchtung geklärt werden. Damit wir unsere Szene mit einer solchen Textur &amp;quot;beleuchten&amp;quot; können, nutzen wir additives Blending. Das bedeutet also das wir zur Farbe im Framepuffer (der unsere Karte zeigt) den Farbwert in unserer Lichttextur addieren. Dort wo unsere Textur also komplett weiß ist, haben wir auf der Karte die volle Lichtfarbe. Blending hat aber einen Nachteil, der in 3D oft sehr viel Kopfzerbrechen macht, aber in 2D leicht gelöst werden kann: Blending arbeitet &amp;quot;auf&amp;quot; dem Framepuffer, was also bedeutet das OpenGL in diesem Falle nicht für uns sortiert. Wenn wir dann also eine Lichttextur rendern die nahe am Betrachter ist und dahinter (im Raum) eine zweite Lichttextur rendern die weiter entfernt ist, werden wir diese nicht sehen, da im Framepuffer bereits die erste Lichttextur &amp;quot;liegt&amp;quot; (sprich dort der Z-Wert der ersten Textur abgelegt wurde und die Fragmente der zweiten Textur deshalb aufgrund des Z-Tests verworfen werden). Das ist natürlich nicht korrekt, aber in 2D lässt sich dieses Problem mit dem passenden Tiefentest lösen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glDepthFunc(GL_ALWAYS);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normalerweise sollte man diese Tiefenfunktion erst setzen bevor man die Lichtquellen zeichnet, sofern man vorher den Tiefenpuffer nutzen will um die Objekte auf seiner Karte in der Höhe zu sortieren. Denn wie der Name vermuten lässt bewirkt diese Form des Tiefentests das Fragmente (=&amp;quot;Pixel auf Probe&amp;quot;) immer rasterisiert werden, egal ob sie jetzt durch ein bereits im Frampuffer liegendes Fragment verdeckt werden würden oder nicht. Wenn wir mit diesem Tiefentest nun also zwei Lichtquellen übereinander rendern würden, werden diese korrekt angezeigt. Aber wie immer soll euch dieser etwas technisch klingende Text nicht aus dem Konzept bringen, weshalb ich dann hier folgende zwei Bilder reden lasse:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_13.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Links sehen wir zwei sich überlappende Lichtquellen mit einem normalerweise verwendetem Tiefentest ('''GL_LEQUAL''' oder '''GL_LESS'''). Dass die grüne Lichtquelle die zweite verdeckt ist reiner Zufall und liegt wohl daran das diese als erstes gerendert wurde. Wie oben gesagt (vereinfacht) steht dann im Z-Puffer drin das an dieser Stelle (des grünen Lichtes) bereits ein Objekt im Z-Puffer liegt. Danach wird dann irgendwann die zweite (blaue) Lichtquelle gerendert, aber die Stellen an denen bereits steht dass dort im Z-Puffer ein Fragment liegt werden nicht mehr gerendert, aufgrund des Tiefentests. Das zweite Bild ist hingegen korrekt, einzig der Tiefentest wurde auf '''GL_ALWAYS''' umgestellt. Dann werden die mit der Lichttextur belegten Quads immer gezeichnet, egal ob sich an der Z-Position bereits ein Fragment befindet oder nicht, und bei Lichtquellen ist das reichlich egal welche zuerst gerendert wird. Denn ob ich jetzt Blau mit Grün addiere, oder Grün mit Blau ist egal, denn beides ergibt im Ende Türkis. Das dürfte dann hoffentlich verstanden worden sein, wenn nicht dann einfach mal das Beispielprogramm öffnen und den Tiefetest wie hier angesprochen ändern; Probieren geht je bekannter weise meist über Studieren.&lt;br /&gt;
&lt;br /&gt;
Abschließend auch noch kurz zum verwendeten Blendmodus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glBlendFunc(GL_ONE, GL_ONE);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer sich schon mal ein wenig mit dem Thema Blending beschäftigt hat, wird schnell erkennen was hier abläuft. Sowohl der Quellfaktor als auch der Zielfaktor stehen auf '''GL_ONE''', was bedeutet dass bei unserer Blendoperation die bereits im Framepuffer befindliche Farbe mit der Farbe unseres Lichtes addiert wird (additives Blending genannt). Bei einer grünen Lichtquelle haben wir in der Mitte also RGB = 0/1/0 und wenn wir das dann auf einen Pixel legen würden der halb grau ist (RGB = 0,5/0,5/0,5) hätten wir als Ergebnis RGB = 0,5/1/0,5 (1+0,5 ist eigentlich 1,5 , aber OpenGL zwängt Farbwerte in den Bereich 0..1).&lt;br /&gt;
&lt;br /&gt;
===Texturenverläufe===&lt;br /&gt;
''(Projektdatei: openGL2D_demo7)''&lt;br /&gt;
&lt;br /&gt;
Im Kapitel &amp;quot;Kachelung&amp;quot; habe ich erwähnt, dass es eigentlich Aufgabe des Grafikers ist die Überläufe zwischen zwei unterschiedlichen Kacheln zu erstellen. Allerdings lässt sich das auch mit OpenGL bewerkstelligen, und zwar dank Blending und des Alphakanals. Dazu rendern wir zuerst ein Quad mit der ersten Kachel, und zwar dort wo diese Kachel komplett erscheinen soll mit vollem Alpha (vierter Parameter von [[glColor]]4f = 1) und dort wo später die andere Kachel komplett erscheinen soll mit Alpha = 0. Danach rendern wir an exakt der gleichen Stelle die zweite Kachel, müssen aber natürlich darauf achten das wir den richtigen Tiefentest aktiviert haben damit diese auch sichtbar ist ('''GL_ALWAYS''' oder '''GL_LEQUAL'''), allerdings mit genau umgekehrten Alphawerten und aktiviertem Blending. Fürs Blending nutzen wir als Quellfaktor '''GL_SRC_ALPHA''' und als Zielfaktor dann in logischer Konsequenz '''GL_DST_ALPHA'''. Dadurch wird dann im finalen Ergebnis dort wo die erste Kachel eine Alpha von 1 hat ihr kompletter Farbwert übernommen und dort wo die zweite Kachel einen Alpha von 1 hat deren voller Farbwert. Dazwischen wird in gewohnter Weise interpoliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glDisable(GL_BLEND);&lt;br /&gt;
glBindTexture(GL_TEXTURE_2D, TileA);&lt;br /&gt;
glBegin(gl_Quads);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(0,0); glVertex3f(-128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(1,0); glVertex3f( 128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(1,1); glvertex3f( 128,  128, 0);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(0,1); glvertex3f(-128,  128, 0);&lt;br /&gt;
glEnd;&lt;br /&gt;
&lt;br /&gt;
glEnable(GL_BLEND);&lt;br /&gt;
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);&lt;br /&gt;
glBindTexture(GL_TEXTURE_2D, TileB);&lt;br /&gt;
glBegin(gl_Quads);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(0,0); glVertex3f(-128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(1,0); glVertex3f( 128, -128, 0);&lt;br /&gt;
 glColor4f(1,1,1,1); glTexCoord2f(1,1); glVertex3f( 128,  128, 0);&lt;br /&gt;
 glColor4f(1,1,1,0); glTexCoord2f(0,1); glVertex3f(-128,  128, 0);&lt;br /&gt;
glEnd;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Allerdings wird das bei komplexeren Kachelübergängen recht aufwendig und endet in jeder Menge Overdraw, da man dann viele Übergänge rendern muss. Aber wer sich mal näher damit beschäftigen will, sollte einen Blick auf das &amp;quot;Verblendet&amp;quot;-Tutorial (Einsteiger) von Phobeus werfen, in dem auch diese Technik hier näher besprochen wird.&lt;br /&gt;
&lt;br /&gt;
===Schatten===&lt;br /&gt;
''(Projektdatei : openGL2D_demo8)''&lt;br /&gt;
&lt;br /&gt;
Im 3D-Bereich sind Schatten eigentlich immer noch die &amp;quot;Königsdisziplin&amp;quot; für jeden Programmierer, besonders wenn diese volumetrisch und vor allem auch korrekt sein sollen. Meist muss man dazu die Szene analysieren, Umrisse von 3D-Objekten generieren und auch noch diverse Spezialfälle beachten (Stichwort &amp;quot;Betrachter im Schattenvolumen&amp;quot;). In unserer heilen 2D-Welt geht das aber schon wie bei der Beleuchtung sehr viel einfacher und hat mit dreidimensionalen Schatten rein gar nichts gemeinsam.&lt;br /&gt;
&lt;br /&gt;
Hier gehen wir nämlich ganz einfach hin und täuschen Schatten vor indem wir unser Objekt (das dazu natürlich einen Alphakanal besitzen muss) mittels {{INLINE_CODE|glColor3f(0, 0, 0)}} schwarz machen und dann unter dem eigentlichen Objekt leicht versetzt (die Richtung des Versatzes kann man je nach Lichteinfall verändern) rendern. Über [[glScalef]] passen wir dann noch die Größe des Schattens an um einfach vermitteln zu können wie hoch sich unser Objekt befindet. Wenn wir also den Schatten eines Spielers rendern, dann kann der genauso groß sein wie der Spieler selbst, aber bei einem Flugzeug das hoch über dem Boden fliegt sollte der Schatten schon etwas verkleinert werden um einen Eindruck von der Flughöhe zu vermitteln.&lt;br /&gt;
&lt;br /&gt;
Rein programmiertechnisch sind Schatten in 2D (auch wenn diese keineswegs physikalisch korrekt sind) also genau das Gegenteil von 3D-Schatten: Einfach und ohne jegliche Hindernisse:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;glPushMatrix;&lt;br /&gt;
 glBindTexture(GL_TEXTURE_2D, ShipTex);&lt;br /&gt;
 glEnable(GL_ALPHA_TEST);&lt;br /&gt;
 glAlphaFunc(GL_GREATER, 0.1);&lt;br /&gt;
 glScalef(0.75, 0.75, 0.75);&lt;br /&gt;
 glColor3f(0, 0, 0);&lt;br /&gt;
 DrawQuad(60,-60,1, 256,192);&lt;br /&gt;
glPopMatrix;&lt;br /&gt;
&lt;br /&gt;
glPushMatrix;&lt;br /&gt;
 glColor3f(1, 1, 1);&lt;br /&gt;
 glBindTexture(GL_TEXTURE_2D, ShipTex);&lt;br /&gt;
 glEnable(GL_ALPHA_TEST);&lt;br /&gt;
 glAlphaFunc(GL_GREATER, 0.1);&lt;br /&gt;
 DrawQuad(0,0,0, 256,192);&lt;br /&gt;
glPopMatrix;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Block rendern wir unser Objekt etwas verkleinert und nach unten/rechts versetzt, natürlich komplett schwarz. Danach müssen wir nur noch unser Objekt drüberrendern (in gewohnter Weise) und fertig ist unser Schatten:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_2D_illustration_14.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
==Schlusswort==&lt;br /&gt;
&lt;br /&gt;
Das war es also zum Thema 2D in OpenGL. Ich hoffe stark das dieser doch recht ausführliche Bericht so ziemlich alle Bereiche abgedeckt hat und damit auch häufig gestellte Fragen beantwortet. Natürlich war das nicht alles was in diesem Bereich machbar ist, allerdings kann ich hier schlecht auf jeden Effekt eingehen, denn sonst könnte ich das Tutorial gleich als ein einige hundert Seiten starkes Buch verkaufen.&lt;br /&gt;
&lt;br /&gt;
Doch eines sei noch am Schluss gesagt: 2D ist zwar programmiertechnisch fast immer (besonders bei in 3D komplexen Sachen wie Beleuchtung und Schatten) sehr viel einfacher und man kommt dann auch meist schneller ans Ziel, allerdings ist hier die Erstellung des Inhalts meist aufwendiger. Während z.&amp;amp;nbsp;B. ein 3D-Terrain zwar von der Programmierung her aufwendiger ist, muss man dort am Ende nur eine Terraintextur draufkleben und fertig ist die Sache. In 2D muss man dies hingegen über Kacheln lösen und dann für jeden Übergang verschiedene Kacheln in einem Bildbearbeitungsprogramm erstellen. Oder zum Beispiel das in unserem letzten Beispiel verwendete Raumschiff; wenn man das in 3D über ein 3D-Modell animiert (Keyframes), dann ist es kaum Aufwand was am Modell zu verändern (andere Textur, Form ändern), aber in 2D liegen diese Animationen vorberechnet auf der Platte, und sobald man dann was am Raumschiff ändert, müssen auch alle Animationen geändert werden.&lt;br /&gt;
&lt;br /&gt;
Wie so oft im Leben muss man also abwägen was jetzt für die eigene Anwendung richtig ist. Essentiell reicht es sich die Frage ''&amp;quot;Ist es für mich aufwendiger in die 3D-Programmierung einzusteigen, oder es ist es aufwendiger den Content für meine 2D-Anwendung zu erstellen&amp;quot;'' zu beantworten, aber das kann ich euch nicht abnehmen, da müsst ihr selbst drauf antworten können. Außerdem sei noch gesagt das die moderne Generation der Computerspieler inzwischen 3D gewohnt ist, was dazu führt das 2D-Anwendungen dann spielerisch sehr überzeugen müssen.&lt;br /&gt;
&lt;br /&gt;
In dem Sinne also viel Spaß in der zweiten Dimension (die auch Spaß machen) kann. Und vergesst nicht: Ich WILL Feedback zu diesem Tutorial und außerdem will das DGL-Team sehen was ihr so mit unseren Tutorials auf die Beine stellt. Wenn dabei also was halbwegs brauchbares raus gekommen ist, lasst es uns wissen!&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:'''Sascha Willems''' (webmaster AT delphigl.de)&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_opengl2d_vcl|text=Delphi-VCL-Quelltexte und Windows-Binaries zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial Lektion 8]]|[[Tutorial_Matrix2]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|2D]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Cubemap&amp;diff=25644</id>
		<title>Tutorial Cubemap</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Cubemap&amp;diff=25644"/>
				<updated>2012-03-21T14:52:42Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=GL_ARB_Texture_Cube_Map=&lt;br /&gt;
==Ave!==&lt;br /&gt;
&lt;br /&gt;
Und willkommen zu Tutorial Nummer drei in meiner Extension-&amp;quot;Reihe&amp;quot;. Heute beschäftigen wir uns mit der GL_ARB_Texture_Cube_Map-Exension ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture_cube_map.txt Spezifikation]), welche v.a. zur Realisierung von Reflexionen genutzt werden kann (und wird). Beim Cubemapping gibt man nicht wie bisher nur eine einzige Textur als Ziel an, sondern wie der Name vermuten lässt sechs Texturen, die dann einen Würfel (deshalb '''Cube'''mapping) darstellen. Und anstatt dann wie beim normalen Texturzugriff über GL_TEXTURE_*D die Texturkoordinaten zur Positionsermittlung eines Texels zu nutzen, werden dann die Koordinaten s,t und r als Richtungsvektor genutzt, über den dann ermittelt wird welches Texel aus welcher Würfeltextur ausgelesen wird.&lt;br /&gt;
&lt;br /&gt;
Ich geb zu das dies erstmal recht komplex klingt, allerdings wurde mit dieser Extension auch ein neuer Modus zur automatischen Generierung von Cubemap-Texturkoordinaten entworfen, so das die Nutzung von Cubemapping sehr einfach von der Hand gehen sollte.&lt;br /&gt;
&lt;br /&gt;
Um euch etwas anzuspornen hier drei Screenshots des berühmten Teekessels mit aktiver Cubemap-Reflexion (kommt in Bewegung natürlich noch besser daher) :&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap0.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap1.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap2.jpg]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Hardwareunterstützung==&lt;br /&gt;
&lt;br /&gt;
Hardwareseitig wird Cubemapping bereits seit Nvidias GeForce 1 unterstützt und selbst der original RivaTNT wurde dieses Feature über eine treiberseitige Softwareimplementation beigebracht. Von daher kann man diese GL-Funktionalität ruhigen Gewissens als vorhanden ansehen, sofern man sich nicht mit einer Ur-Alt Grafikkarte abgeben will. Wer sich trotzdem mal ein Bild über die Hardwareunterstützung machen will, sollte in diesem [http://www.delphi3d.net/hardware/extsupport.php?extension=GL_ARB_texture_cube_map Eintrag]von Tom Nuydens Seite fündig werden.&lt;br /&gt;
&lt;br /&gt;
==Laden der Cubemap==&lt;br /&gt;
&lt;br /&gt;
Wie anfangs erwähnt besteht die Cubemap aus insgesamt sechs Seiten, die eine Panoramaansicht (=360°) der zu reflektierenden Umgebung darstellen. Erstellen lässt sich sowas eigentlich recht leicht in einem 3D-Modeller, indem man die Szene jeweils um 90° rotiert mit einem FOV von 90° rendert (und dann noch nen Deckel und den Boden). Für dieses Tutorial hab ich mich allerdings der im Nvidia-SDK mitgelieferten Cubemaptexturen bedient. Prinzipiell könnt ihr übrigens auch jede Skybox als Cubemap nutzen, ihr müsst dann aber die ein oder andere Seite erst richtig spiegeln bzw. drehen bevor ihr sie hochladen könnt.&lt;br /&gt;
Da die Texturen jedoch als Cubemap und nicht als einfache 2D-Texturen geladen werden müssen, wurden mit dieser Extension auch neue Texturenziele deklariert, welche die einzelnen Seiten des Würfels repräsentieren. Alle Ziele beginnen mit '''GL_TEXTURE_CUBE_MAP_''', gefolgt von ihrer absoluten Position. Zum leichteren Verständnis präsentiere ich euch diese neuen Ziele (ohne das obigen Präfix) direkt zusammen mit den passenden Texturen, was die Sache verständlicher machen sollte :&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cm_right.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cm_left.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cm_top.jpg]]&lt;br /&gt;
|-&lt;br /&gt;
|POSITIVE_X_ARB (Rechts)&lt;br /&gt;
|NEGATIVE_X_ARB (Links)&lt;br /&gt;
|POSITIVE_Y_ARB (Oben)&lt;br /&gt;
|}&lt;br /&gt;
 	&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cm_bottom.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cm_front.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cm_back.jpg]]&lt;br /&gt;
|-&lt;br /&gt;
|NEGATIVE_Y_ARB (Unten)&lt;br /&gt;
|POSITIVE_Z_ARB (Vorne) &lt;br /&gt;
|NEGATIVE_Z_ARB (Hinten)&lt;br /&gt;
|}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
Anhand obiger Bezeichnungen sollte leicht erkennbar sein, welche der Konstanten für welche Seite des Würfels steht. Wenn ihr einen Blick in den OpenGL-Header werft, werdet ihr übrigens sehen dass das die Werte für diese Konstanten alle nacheinander folgende Zahlenwerte, beginnend bei $8515 darstellen. Das Tolle an dieser Tatsache ist nun, dass wir so unsere Cubemaptexturen ganz leicht in einer Schleife laden können und die Texturnamen in einem einfachen Stringarray übergeben können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
const&lt;br /&gt;
 CubeMapFileName : array[0..5] of String = ('cm_right.tga','cm_left.tga','cm_top.tga',&lt;br /&gt;
                                            'cm_bottom.tga','cm_front.tga','cm_back.tga');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
for i := 0 to 5 do&lt;br /&gt;
 begin&lt;br /&gt;
 Target := GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+i;&lt;br /&gt;
 LoadTexture(CubeMapFileName[i],Cubemap[i], False, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, False);&lt;br /&gt;
 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);&lt;br /&gt;
 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);&lt;br /&gt;
 end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieser Quellcode sollte recht einfach zu begreifen sein, bedarf aber evtl. noch einer kleinen Erklärung. Am Anfang des Schleifenkörpers setze ich die Variable Target auf die zu ladende Seite des Cubemap-Würfels. Diese Variable habe ich der textures.pas von Jan Horn hinzugefügt, da diese in ihrer Originalform nur das Laden von 2D-Texturen ermöglicht. Ihr müsst eurem Texturenlader (egal welchen ihr nutzt) also mitteilen das ihr die Seiten der Cubemap und keine herkömmliche Textur laden wollt. Außerdem setze ich dann noch den Clamp-To-Edge-Modus für alle Texturen, der wie u.a. auch bei einer Skybox dafür sorgt das an den Übergängen keine Kanten entstehen.&lt;br /&gt;
&lt;br /&gt;
''Kleiner Hinweis : Die Cubemaptexturen müssen übrigens alle in der gleichen Größe vorliegen. Außerdem sollte man es mit der Größe nicht übertreiben, zumal man in Spielen eher selten ein Objekt hat das nur reflektiert. Meistens legt man da die Reflexionscubemap via Multitexturing recht schwach auf ein Objekt und da reichen dann auch 128x128 Pixel große Texturen.''&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Alternativ kann man die Texturen auch komfortabel mit dem [[Glbitmap loader|glBitmap-Loader]] laden}}&lt;br /&gt;
&lt;br /&gt;
==Automatische Texturkoordinaten-Generierung==&lt;br /&gt;
&lt;br /&gt;
Einige von euch haben sich vielleicht schonmal die Möglichkeit der automatischen Generierung von Texutrenkoordinaten durch OpenGL zu Nutze gemacht, sei dies weil man sein Terrain schnell texturieren wollte oder weil man etwas auf seine Szene projizieren wollte. Genau diese Möglichkeit werden wir auch nutzen um unsere Refkletions-Cubemap-Texturkoordinaten von OpenGL generieren zu lassen. Zu diesem Zweck bringt uns die '''GL_ARB_Texture_Cube_Map'''-Extension einen neuen TexGenModus, nämlich '''GL_Reflection_Map_ARB'''. Diesen übergeben wir dann für die s,t und r-Koordinate, da beim Cubemapping wie eingangs besprochen ein Richtungsvektor zur Texelermittlung dient, der ja aus drei Komponenten besteht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);&lt;br /&gt;
glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);&lt;br /&gt;
glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);&lt;br /&gt;
glEnable(GL_TEXTURE_GEN_S);&lt;br /&gt;
glEnable(GL_TEXTURE_GEN_T);&lt;br /&gt;
glEnable(GL_TEXTURE_GEN_R);&lt;br /&gt;
glEnable(GL_TEXTURE_CUBE_MAP_ARB);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der letzten Zeile aktivieren wir übrigens noch das Cubemapping. Würden wir das nicht tun,dann würden wir logischerweise auch nichts von unserer Cubemap sehen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Rendern==&lt;br /&gt;
&lt;br /&gt;
Da ihr nun alles nötige getan habt, um die Cubemaptexturen hochzuladen und zu aktiveren, müsst ihr beim Rendern eures Objektes nichts Weiteres mehr machen, denn OpenGL kümmert sich nun dank der automatischen Generierung der Texturkoordinaten um das Anwenden der Cubemap.&lt;br /&gt;
Damit wäre das Theme statische Cubemap-Reflexion auch schon abgeschlossen, und wenn ihr nicht mehr wissen wolltet, dann könnt ihr versuchen dieses Feature mal einzubinden. Alle anderen können gerne noch weiterlesen und sich an den zwei etwas fortgeschritteneren Kapiteln erfreuen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Dynamische Cubemaps==&lt;br /&gt;
&lt;br /&gt;
Euch reicht eine statische Cubemap nicht aus und ihr wollt das sich eure Umgebung in Echtzeit spiegelt? Auch das ist natürlich mit Cubemapping kein Problem. Da der technische Aspekt dahinter aber eher in Richtung RenderToTexture geht, erkläre ich nur kurz das Prinzip dahinter, zumal die Implementation recht einfach sein sollte.&lt;br /&gt;
Um eure Szene dynamisch über die Cubemap zu reflektieren müsst ihr &amp;quot;einfach&amp;quot; nur alle sechs Seiten des Würfels Frame für Frame in die entsprechenden Texturen rendern, dürft dabei allerdings das Objekt das reflektieren soll nicht mitzeichnen. Am besten geht das natürlich in einer einfachen Schleife und indem ihr über ein Array jeweils die Rotation für das aktuelle Cubemap-Face angebt. Nicht vergessen dürft ihr dabei das FOV von genau 90° um einen kompletten Rundumblick zu erhalten.&lt;br /&gt;
Natürlich solltet ihr es auch mit diesem Feature nicht übertreiben, da das Rendern in eine Textur recht leistungshungrig ist und deshalb stark an der Framerate zerren kann. Daher bietet es sich z.B. an die dynamische Cubemap nur alle X-Frames zu aktualisieren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Normalisierungscubemaps==&lt;br /&gt;
&lt;br /&gt;
Eine weiter oft genutzte Möglichkeit zur Verwendung einer Cubemap sind Normalisierungs-Cubemaps. Wie der Namen evtl. bereits vermuten lässt wird die Cubemap hier nicht genutzt um eine Szene zu reflektieren, sondern um Vektoren (also Farbewerte) zu speichern. So enthält jeder Texel der Cubemap dann einen Vektor, über den wir die Normale eines jeden Vektors unseres Objektes anhand des Richtungsvektors (durch die Texturkoordinaten s, t und r angegeben) ermitteln können. Dadurch ist es auch auf Hardware, die keine PixelShader bietet, möglich, Per-Pixel-Normalen zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Die Methode zur Erstellung einer solchen Cubemap ist recht einfach, denn in jedem Texel wird der Vektor zwischen Texelposition und Würfelmitte gespeichert, was dazu führt, dass die Normalisierungscubemap eigentlich immer gleich aussieht. Wer keine Lust hat dazu selbst ne Routine zu schreiben, der kann sich an meinem folgendem Quellcode bedienen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
procedure GenerateNormalisationCubeMap;&lt;br /&gt;
const&lt;br /&gt;
 Offset   = 0.5;&lt;br /&gt;
 Size     = 32;&lt;br /&gt;
 HalfSize = Size div 2;&lt;br /&gt;
var&lt;br /&gt;
 Data       : array[0..Size-1,0..Size-1,0..2] of Byte;&lt;br /&gt;
 TempVector : TglVertex3f;&lt;br /&gt;
 i,j,CFace  : Integer;&lt;br /&gt;
begin&lt;br /&gt;
for CFace := 0 to 5 do&lt;br /&gt;
 begin&lt;br /&gt;
 for i := 0 to High(Data) do&lt;br /&gt;
  for j := 0 to High(Data[i]) do&lt;br /&gt;
   begin&lt;br /&gt;
   // Vektor vom Zentrum des Würfels zum aktuellen Texel berechnen&lt;br /&gt;
   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+CFace of&lt;br /&gt;
    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB : begin&lt;br /&gt;
                                         TempVector.x := HalfSize;&lt;br /&gt;
                                         TempVector.y := -(j+Offset-HalfSize);&lt;br /&gt;
                                         TempVector.z := -(i+Offset-HalfSize);&lt;br /&gt;
                                         end;&lt;br /&gt;
    GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB : begin&lt;br /&gt;
                                         TempVector.x := -HalfSize;&lt;br /&gt;
                                         TempVector.y := -(j+Offset-HalfSize);&lt;br /&gt;
                                         TempVector.z := i+Offset-HalfSize;&lt;br /&gt;
                                         end;&lt;br /&gt;
    GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB : begin&lt;br /&gt;
                                         TempVector.x := i+Offset-HalfSize;&lt;br /&gt;
                                         TempVector.y := HalfSize;&lt;br /&gt;
                                         TempVector.z := j+Offset-HalfSize;&lt;br /&gt;
                                         end;&lt;br /&gt;
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB : begin&lt;br /&gt;
                                         TempVector.x := i+Offset-HalfSize;&lt;br /&gt;
                                         TempVector.y := -HalfSize;&lt;br /&gt;
                                         TempVector.z := -(j+Offset-HalfSize);&lt;br /&gt;
                                         end;&lt;br /&gt;
    GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB : begin&lt;br /&gt;
                                         TempVector.x := i+Offset-HalfSize;&lt;br /&gt;
                                         TempVector.y := -(j+Offset-HalfSize);&lt;br /&gt;
                                         TempVector.z := HalfSize;&lt;br /&gt;
                                         end;&lt;br /&gt;
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB : begin&lt;br /&gt;
                                         TempVector.x := -(i+Offset-HalfSize);&lt;br /&gt;
                                         TempVector.y := -(j+Offset-HalfSize);&lt;br /&gt;
                                         TempVector.z := -HalfSize;&lt;br /&gt;
                                         end;&lt;br /&gt;
    end;&lt;br /&gt;
   // Vektor normalisieren&lt;br /&gt;
   glNormalizeVector(TempVector);&lt;br /&gt;
   // In 0..1-Reichweite packen&lt;br /&gt;
   TempVector := glScaleVector(TempVector,glVertex(0.5,0.5,0.5));&lt;br /&gt;
   TempVector := glAddVector(TempVector,glVertex(0.5,0.5,0.5));&lt;br /&gt;
   // In Cubemap-Face schreiben&lt;br /&gt;
   Data[j,i,0] := Round(TempVector.x*255);&lt;br /&gt;
   Data[j,i,1] := Round(TempVector.y*255);&lt;br /&gt;
   Data[j,i,2] := Round(TempVector.z*255);&lt;br /&gt;
   end;&lt;br /&gt;
 // Cubemap-Face an OpenGL senden&lt;br /&gt;
 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+CFace, 0, GL_RGBA8, Size, Size,&lt;br /&gt;
              0, GL_RGB, GL_UNSIGNED_BYTE, @Data);&lt;br /&gt;
 end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Code dürfte eigentlich keine Verständnisprobleme machen und liefert euch dann als Ergebnis (im VRAM der Grafikkarte) die sechs Seiten der Normalisierungscubemap. Die Größe habe ich auf 32x32 Pixel festgelegt, allerdings ändert sich bei einer Vergrößerung der Texturen rein gar nichts. Für alle die Probleme haben obigen Code zu visualisieren oder sehen wollen wie die Cubemap-Seiten aussehen :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auf unseren beliebten Teekessel angewendet, sieht das dann folgendermaßen aus :&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap_0.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap_1.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap_2.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap_3.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap_4.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Cubemap_cubemap_5.jpg]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wie gut zu erkennen haben wir jetzt quasi für jeden Pixel eine eigene Normale aus der Normalisierungscubemap, und dies ist wohlgemerkt auch auf Grafikkarten ohne Pixelshader möglich.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Cubemap_normcubemap.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
So viel also zum Thema Cubemap und Verwendungszwecke. Ich hab versucht in diesem Tutorial alle häufigen Nutzungsmöglichkeiten abzudecken, was allerdings noch fehlt ist die Nutzung einer Cubemap zu Darstellung von Schatten. Da dieses Thema allerdings sehr komplex ist, habe ich es bewusst nicht reingenommen.&lt;br /&gt;
Hoffe also das Tut war mal wieder lehrreich und auch die Zeit wert!&lt;br /&gt;
&lt;br /&gt;
Wer übrigens eine tiefergehende Beschreibung zu diesem Thema sucht, die auch auf andere Reflexionsmethode eingeht (allerdings in Englisch), sollte sich mal dieses [http://developer.nvidia.com/object/cube_maps.html ausführliche Tutorial von Nvidia] ansehen.&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
Sascha Willems([mailto:webmaster_at_delphigl.de webmaster_at_delphigl.de])&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_Vertexbufferobject]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Cubemap]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25643</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=25643"/>
				<updated>2012-03-21T14:52:19Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Einleitung=&lt;br /&gt;
Hallo und willkommen bei meiner &amp;quot;Einführung&amp;quot; in GLSL (kurz für &amp;quot;Open'''GL''' '''S'''hading '''L'''anguage&amp;quot;), der offiziellen Hochlevel-Shadersprache von OpenGL. In diesem umfangreichen Dokument werde ich versuchen, sowohl auf die Nutzung (sprich das Laden und Anhängen von Shadern im Quellcode), als auch auf die Programmierung von Shadern selbst einzugehen, inklusive aller Sprachelemente der OpenGL Shadersprache. Es wird also auch recht viele Informationen zu der C-ähnlichen Programmstruktur und den von GLSL angebotenen Variablen und Attributen gehen. Am Ende dieser Einführung sollten alle die, die sich für das Thema interessieren, in der Lage sein, zumindest einfach Shader zu schreiben und auch in ihren Programmen zu nutzen. Außerdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von Khronoes veröffentlichten Shaderspezifikationen, und damit als alltägliches Nachschlagewerk, dienen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Wie auch schon mein ARB_VP-Tutorial richtet sich auch diese Einführung aufgrund ihrer Thematik eher an die fortgeschritteneren GL-Programmierer und neben sehr guten GL-Kenntnissen sollten sich alle, die sich daran versuchen wollen, mit den technischen Hintergründen der GL, wie z.B. dem Aufbau der Renderpipeline auskennen. Weiterhin sind C-Kenntnisse absolut erforderlich, da die Shader ja in einer an ANSI-C angelehnten Syntax geschrieben werden. Auch Begriffsdefinitionen zu Vertex oder Fragment werden zum Verständis dieser Einführung benötigt. Wer also noch am Anfang seiner GL-Karriere steht, dem wird dieses Dokument nicht viel nützen. Ganz nebenbei solltet ihr auch noch eine gehörige Portion Zeit (am besten nen kompletten Nachmittag) mitbringen, denn die folgende Kost ist nicht nur umfangreich, sondern auch manchmal recht schwer verdaulich.&lt;br /&gt;
&lt;br /&gt;
=Was ist GLSL?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei GLSL um eine Shadersprache, also um eine Hochsprache, in der man die programmierbaren Teile aktueller Grafikbeschleuniger nach eigenem Belieben programmieren kann. Sie stellt quasi den Nachfolger zu den in Assembler geschriebenen Vertex- und Fragmentprogrammen ([[GL_ARB_vertex_program]]/[[GL_ARB_fragment_program]]) dar und basiert auf ANSI C, erweitert um Vektor- und Matrixtypen sowie einige C++-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
Die in GLSL geschriebenen Programme nennen sich, angepasst an die Terminologie von RenderMan und DirectX, [[Shader]] (im Gegensatz zu &amp;quot;Programme&amp;quot; bei ARB_VP/FP) und werden entweder auf Eckpunkte (VertexShader), Fragmente (FragmentShader) angewendet, oder (neuerdings, ab Shadermodell 4.0) auch genutzt um Geometrie zu erstellen (Geometryshader). Andere Teile der Renderpipeline (z.B. die Rasterisierung) können momentan noch nicht durch Shader beeinflusst werden, was allerdings in Zukunft noch kommen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
GLSL wurde 2005 mit OpenGL 1.5 eingeführt. Während es in Sachen Treiber- und Hardwareunterstützung anfänglich noch dürftig aussah, wird man inzwischen keine Grafikkarte mehr kaufen können die nicht zumindest Vertex- und Fragmentshader beherscht. Geometrieshader hingegen sind relativ neu und wurden erst mit Shadermodell 4.0 eingeführt, hier ist es also unter Umständen noch möglich dass selbst aktuelle Treiber/Karten keine Geometrieshader beherrschen.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt man auch einen passenden OpenGL-Header der die für GLSL nötigen Funktionen exportiert. Ich verweise dazu auf unseren eigenen OpenGL-Header [[DGLOpenGL.pas]], der peermanent auf dem aktuellsten Stand gehalten wird und auch Support für Geometrieshader mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
&lt;br /&gt;
Die GL-Shadersprache &amp;quot;besteht&amp;quot; in ihrer aktuellen Version aus folgenden Extensions, fürs Verständnis wäre es nicht schlecht, wenn ihr euch zumindest die Einleitungen dazu durchlest :&lt;br /&gt;
* [[GL_ARB_shader_objects]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shader_objects.txt Originalspezifikation])&lt;br /&gt;
: Definiert die API-Aufrufe, die zum Erstellen, Kompilieren, Linken, Anhängen und Aktivieren von Shader- und Programmobjekten nötig sind. &lt;br /&gt;
* [[GL_ARB_vertex_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Vertexebene hinzu. &lt;br /&gt;
* [[GL_ARB_fragment_shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_shader.txt Originalspezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Fragmentebene hinzu. &lt;br /&gt;
* [[GL_ARB_shading_language_100]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shading_language_100.txt Originalspezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis''' : Seit OpenGL 2.0 ist GLSL Teil des Kerns. Wenn die Karte also OpenGL 2.0 unterstützt, dann unterstützt sie auch (zumindest in Software) Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sprachversionen==&lt;br /&gt;
&lt;br /&gt;
Neben der OpenGL-Version und dem vorhandenen Shadermodell (das eher an DirectX ausgerichtet ist), bietet auch GLSL verschiedene Versionen, die entsprechend erweiterte Funktionalität bieten.&lt;br /&gt;
&lt;br /&gt;
Auslesen kann man die verfürgbare GLSL-Version wie folgt:&lt;br /&gt;
&lt;br /&gt;
 glGetString(GL_SHADING_LANGUAGE_VERSION)&lt;br /&gt;
&lt;br /&gt;
Erst ab Version 1.4. kann man davon ausgehen dass GLSL alle Features des Shadermodells 4.0 liefert, ab 1.3 grob gesagt Shadermodell 3.0 (bei GLSL lässt sich das leider nicht so leicht unterteilen).&lt;br /&gt;
&lt;br /&gt;
Außerdem kann man seinem Shader eine Versionsnummer verpassen. Sollte der Shadercompiler (also Treiber bzw. Hardware) diese Version nicht unterstützen, gibt dieser eine Fehlermeldung heraus:&lt;br /&gt;
&lt;br /&gt;
 #version 1.50 &lt;br /&gt;
&lt;br /&gt;
''(Hinweis: Muss am Anfang des Shaders stehen)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&lt;br /&gt;
&lt;br /&gt;
Im Zuge der Vereinheitlichung der GL wird immer häufiger in Objekte gekapselt, deren API dann auch aneinander angelehnt ist. Ziel ist, dabei die Programmierung der GL uniform zu machen, so dass z.B. zwischen dem Erstellen und Verwalten eines Vertex-Buffer-Objektes oder eines Shader-Objektes kaum ein Unterschied besteht (demnächst kommen dann auch Pixel-Buffer-Objekte dazu). Mit glSlang wurden dann im Zuge dieser Aktion zwei neue Objekte eingeführt, deren Definition ihr euch unbedingt einprägen solltet:&lt;br /&gt;
&lt;br /&gt;
* '''Programmobjekt'''&lt;br /&gt;
:Ein Objekt, an das die Shader später angebunden werden. Bietet Funktionalität zum Linken der Shader und prüft dabei die Kompatibilität zwischen Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
* '''Shaderobjekt'''&lt;br /&gt;
:Dieses Objekt verwaltet den Quellcodestring eines Shaders und ist entweder vom Typ '''GL_VERTEX_SHADER''', '''GL_FRAGMENT_SHADER_ARB''' oder '''GL_GEOMETRY_SHADER'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ressourcen==&lt;br /&gt;
&lt;br /&gt;
Die Shadersprache ist keinesfalls final und es wurden bereits diverse Ausdrücke für zukünftige Verwendung reserviert, denn ein Ziel bei ihrer Entwicklung war es, sie so zukunftsorientiert zu gestalten, dass auch Grafikkarten der nächsten und übernächsten Generation voll ausgenutzt werden können. Damit einher geht die Tatsache, dass sich die Spezifikationen in Zukunft ändern/erweitern werden, weshalb man da immer einen Blick hineinwerfen sollte. Die Anlaufstelle dafür ist die [http://www.opengl.org/documentation/specs/ Spezifikationenliste auf OpenGL.org].&lt;br /&gt;
&lt;br /&gt;
=GLSL im Programm=&lt;br /&gt;
Bevor wir uns mit der Syntax von glSlang beschäftigen, zeige ich euch erstmal, wie ihr Shader in euer Programm einbindet und nutzt. Warum das zuerst? Ganz einfach deshalb, weil ihr dann das, was ihr im glSlang-Syntaxteil lernt, direkt in eurer Testanwendung verwenden könnt. Hoffe diese Entscheidung klingt logisch und findet Anklang.&lt;br /&gt;
&lt;br /&gt;
Zuerst benötigen wir natürlich unsere Objekte. Zum einen ein ''Programmobjekt'', an das unsere Shader gebunden werden, und zwei ''Shaderobjekte'', die den Quellcode unseres Vertex bzw. Fragment Shaders aufnehmen. Dazu wurde eigens der neue &amp;quot;Datentyp&amp;quot; {{INLINE_CODE|glHandle}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandle;&lt;br /&gt;
 VertexShaderObject   : GLhandle;&lt;br /&gt;
 FragmentShaderObject : GLhandle;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dieser Deklaration können wir dann damit beginnen unsere Objekte zu erstellen. Den Anfang macht das Programmobjekt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        := glCreateProgram;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgram]] erstellt uns oben ein leeres Programmobjekt und gibt ein gültiges Handle darauf zurück.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Erstellung unseres Vertex bzw. Fragment Shaders :&lt;br /&gt;
&lt;br /&gt;
 VertexShaderObject   := glCreateShader(GL_VERTEX_SHADER);&lt;br /&gt;
 FragmentShaderObject := glCreateShader(GL_FRAGMENT_SHADER);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShader]] dient zur Generierung eines leeren Shaderobjektes. Momentan unterstützt diese Funktion VertexShader und FragmentShader.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun also zwei gültige Shaderobjekte haben, wollen wir diese auch mit entsprechendem Quellcode versorgen :&lt;br /&gt;
&lt;br /&gt;
 glShaderSource(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSource(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSource]] setzen wir den Quellcode eines Shaderobjektes ''komplett'' neu. Zum Laden des Quellcodes bietet sich unter Delphi übrigens eine TStringList geradezu an. Es sollte beachtet werden, dass der Quellcode zu diesem Zeitpunkt ''nicht geparst'' wird, also keine Fehleruntersuchung stattfindet.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode wurde jetzt also an unsere Shaderobjekte gebunden und sollte dann natürlich auch noch kompiliert werden :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 glCompileShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShader]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der Shadercompiler (je nach Treiber) recht detaillierte Infos aus. Wie man an diese Infos kommt könnt ihr gleich nachlesen.&lt;br /&gt;
&lt;br /&gt;
Wenn unsere Shader dann kompiliert werden konnten, ist es Zeit, diese an unser anfangs erstelltes Programmobjekt anzuhängen :&lt;br /&gt;
&lt;br /&gt;
 glAttachShader(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachShader(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehängt wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteShader(VertexShaderObject);&lt;br /&gt;
 glDeleteShader(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Schluß müssen wir dann noch unsere ans Programmobjekt gebundenen Shader linken :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgram(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShader]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgram]] die angehangenen Shader zu einem ausführbaren Shader gelinkt. Folgende Bedingungen führen zu einem '''Linkerfehler''':&lt;br /&gt;
&lt;br /&gt;
* Die Zahl der von der Implementation unterstützten Attributvariablen wurde überschritten&lt;br /&gt;
* Der Speicherplatz für Uniformvariablen wurde überschritten&lt;br /&gt;
* Die Zahl der von der Implementation angebotenen Sampler wurde überschritten&lt;br /&gt;
* Die main-Funktion fehlt&lt;br /&gt;
* Die Liste der Varying-Variablen des Vertexshaders stimmt nicht mit der des Fragmentshaders überein&lt;br /&gt;
* Funktions- oder Variablenname nicht gefunden&lt;br /&gt;
* Eine gemeinsame Globale ist mit unterschiedlichen Werten oder Typen initialisiert worden&lt;br /&gt;
* Zwei Sampler unterschiedlichen Typs zeigen auf die selbe Textureneinheit&lt;br /&gt;
* Ein oder mehrere angehangene(r) Shader wurden nicht erfolgreich kompiliert&lt;br /&gt;
&lt;br /&gt;
Die Nutzung von glSlang im eigenen Programm ist wie oben erkennbar also nicht wirklich schwer und innerhalb kurzer Zeit realisiert. Natürlich ist es auch möglich z.B. nur einen VertexShader oder nur einen FragmentShader an ein Programmobjekt zu binden.&lt;br /&gt;
&lt;br /&gt;
Noch eine kleine Notiz zum Löschen der Shader mittel [[glDeleteShader]] : Da Shader(objekte) einen Referenzzähler besitzen und erst gelöscht werden wenn diese nirgendwo mehr benötigt werden, ist es nicht falsch diese vor dem Linkvorgang zu löschen. Allerdings spielt es letztendlich keine Rolle ob die Löschanweisung vorher der nachher ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fehlererkennung==&lt;br /&gt;
Natürlich wird es ohne Fehlerausgabe recht schwer, etwaige Probleme in einem Vertex- oder Fragmentshader zu finden. Doch auch in diesem Bereich wurde glSlang recht gut durchdacht und es wurden zwei Funktionen eingeführt, welche im Zusammenspiel die Fehlersuche recht einfach machen, nämlich [[glGetShaderInfoLog]] und [[glGetShader]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH}}. Erstere Funktion liefert uns einen Logstring, während uns letztere Funktion dessen Länge angibt. Der Logstring wird verändert, sobald ein Shader kompiliert oder ein Programm gelinkt wird.&lt;br /&gt;
&lt;br /&gt;
Um die Ausgabe dieses Logs so einfach wie möglich zu machen, bietet es sich an beide in einer einfach Funktion unterzubringen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;function glSlang_GetInfoLog(pShader: GLHandleARB): String;&lt;br /&gt;
var&lt;br /&gt;
  blen, slen: GLInt;&lt;br /&gt;
  InfoLog: PGLCharARB;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  glGetShaderiv(glObject, GL_INFO_LOG_LENGTH , @blen);&lt;br /&gt;
  if blen &amp;gt; 1 then&lt;br /&gt;
  begin&lt;br /&gt;
    GetMem(InfoLog, blen * SizeOf(GLCharARB));&lt;br /&gt;
    glGetShaderInfoLog(pShader, blen, slen, InfoLog);&lt;br /&gt;
    Result := PChar(InfoLog);&lt;br /&gt;
    Dispose(InfoLog);&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist recht leicht erklärt : Zuerst lassen wir uns über {{INLINE_CODE|glGetShaderiv}} mitteilen wie lang der aktuelle Infolog ist. Sollte dort tatsächlich etwas drinstehen (blen &amp;gt; 1), dann lassen wir uns dessen Inhalt via {{INLINE_CODE|glGetShaderInfoLog}} in {{INLINE_CODE|InfoLog}} ausgeben und liefern diesen als Ergebnis zurück.&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt wird nur nach dem Kompilieren eines Shaders bzw. dem Linken eines Programmobjektes ein Infolog erstellt. Es bietet sich dadurch an, direkt danach einen solchen Aufruf zu machen :&lt;br /&gt;
&lt;br /&gt;
 glCompileShader(VertexShaderObject);&lt;br /&gt;
 ShowMessage(glSlang_GetInfoLog(VertexShaderObject));&lt;br /&gt;
&lt;br /&gt;
Wenn unser Vertex Shader komplett fehlerfrei kompiliert werden konnte, dann sehen wir als Ergebnis nur einen leeren Dialog. Ist dies nicht der Fall, so werden wir vom Treiber mit recht detaillierten Fehlerinformationen &amp;quot;belohnt&amp;quot;, z.B. so :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL_error_vshader.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch das Infolog nach dem Linken des Programmobjektes dürfte, selbst wenn keine Fehler vorkommen, recht interessant sein, das sieht dann nämlich so aus :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL info programobject.jpg]]&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen, wird uns nach dem erfolgreichen Linken auch gesagt, ob und welcher Shader in Hardware bzw. Software läuft. Für Debuggingzwecke sicherlich eine mehr als brauchbare Information.&lt;br /&gt;
&lt;br /&gt;
==Shader benutzen==&lt;br /&gt;
Um den Shader auch für die nächsten Polygone zu benutzen oder Uniformparameter übergeben zu können, ruft man die Funktion&lt;br /&gt;
 glUseProgramt(ProgramObject);&lt;br /&gt;
um alle Shader zu deaktivieren, ruft man dieselbe Funktion mit dem Parameter 0.&lt;br /&gt;
&lt;br /&gt;
==Parameterübergabe==&lt;br /&gt;
Uniformparameter (mehr dazu später) stellen die Schnittstelle zwischen eurem Programm und dem Shader dar, werden also genutzt um Daten aus dem Programm heraus an einen Shader zu übergeben. Zur Übergabe dieser Parameter bietet OpenGL diverse Funktionen, die alle Abkömmlinge von [[glUniform]] sind. Während mit {{INLINE_CODE|glUniform4f}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fv}} ganze Matrizen schnell und einfach übergeben. Außerdem gibt es nun die Möglichkeit Uniformparameter direkt über ihren Namen, statt wie unter ARB_FP/VP über einen festen Index zu adressieren. Die Funktion [[glGetUniformLocationARB]] gibt anhand des übergebenen Parameternamens dessen Position zurück. Man kann also ganz einfach über den Namen drauf zugreifen :&lt;br /&gt;
&lt;br /&gt;
 glUniform3f(glGetUniformLocation(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1i(glGetUniformLocation(ProgramObject, PGLCharARB('texSamplerTMU3')), 3);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier, das man je nach Parametertyp auch die passende Anzahl von Argumenten übergibt. Also für einen 4-Komponenten Floatvektor {{INLINE_CODE|glUniform4fARB}} und für einen einfachen Integerwert (z.B. Textureinheit für einen Sampler) glUnifrom1iARB. Auch nicht vergessen dürft ihr, das die Namen der Parameter genauso wie im Shader geschrieben werden müssen, also Groß- und Kleinschreibung beachtet werden muß.&lt;br /&gt;
&lt;br /&gt;
=Die Shadersprache=&lt;br /&gt;
&lt;br /&gt;
Nachdem wir uns mit der Einbindung der glSlang-Shader in unser Programm beschäftigt haben, wollen wir uns in den folgenden Kapiteln um die Sprachelemente von glSlang kümmern. Wie schon gesagt basiert glSlang auf ANSI-C, wurde allerdings um speziell auf den Zielbereich angepasste Vektor- und Matrixtypen und einige C++-Features wie das freie deklarieren von Variablen an jeder Stelle und das Funktionsüberladen auf Basis des Argumenttyps erweitert. Wer sich ein wenig mit C/C++ auskennt sollte also in der nun folgenden Materie keine Probleme bekommen.&lt;br /&gt;
&lt;br /&gt;
'''Obligatorische Hinweise für verwöhnte Delphi-Nutzer : '''&lt;br /&gt;
*Wie von C/C++ her gewohnt, spielt auch in glSlang die Groß- und Kleinschreibung eine wichtige Rolle, also bitte achtet darauf. gl_Position ist eine komplett andere Variable als z.B. gl_position.&lt;br /&gt;
*Es findet keine automatische Typenkonvertierung statt. Das bedeutet also das float MyFloat = 1 ungültig ist und es in dem Falle float MyFloat = 1.0 heissen muss. Typecasts müssen also immer manuell stattfinden, z.B. MyFloat = float(MyInt).&lt;br /&gt;
&lt;br /&gt;
'''Kleine Programmstrukturkunde für C-Unkundige :'''&amp;lt;br&amp;gt;&lt;br /&gt;
Da sicherlich einige Delpher nie richtig was mit C gemacht haben, zeige ich mal anhand eines kleinen Beispieles (das auf keinen Fall nen brauchbaren Shader darstellt) den grundlegenden Aufbau eines glSlang-Shaders, der natürlich dem Aufbau eines C-Programmes stark ähnelt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 VariableA;&lt;br /&gt;
float VariableB;&lt;br /&gt;
vec3  VariableC;&lt;br /&gt;
const float KonstanteA = 256.0;&lt;br /&gt;
&lt;br /&gt;
float MyFunction(vec4 ArgumentA)&lt;br /&gt;
{&lt;br /&gt;
    float FunktionsVariableA = float(5.0);&lt;br /&gt;
&lt;br /&gt;
    return float(ArgumentA * (FunktionsVariableA + KonstanteA));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Ich bin ein Kommentar&lt;br /&gt;
/* Und ich auch */&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
    gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht doch recht bekannt aus, unser Programmaufbau. Delphi und C haben ja so einige Grundlagen gleich, darunter auch der ungefähre Programmaufbau. Ausserhalb jeglicher Funktionen legen wir am Programmanfang unsere Variablen, Konstanten und Attribute fest, die dann ''global'' nutzbar sind, also in jeder Funktion.&lt;br /&gt;
&lt;br /&gt;
Darunter deklarieren wir dann eine kleine Funktion. Wie auch bei den Variablendeklarationen wird hier der Rückgabetyp nicht wie bei Pascal nach dem Funktionsnamen untergebracht, sondern davor. Innerhalb der Funktion können dann wieder Variablen deklariert werden, die dann allerdings ''lokal'', also nur in dieser Funktion nutzbar sind. Vorteil dieser Deklaration ist die Tatsache, dass je nach Grafikkarte nur bestimmt viele globale Variablen deklariert werden können. Wenn möglich sollte man also mit lokalen Vorlieb nehmen. Unsere Funktion gibt dann natürlich noch via return einen Wert zurück, ''was gemacht werden muss'', sofern man diese nicht als void deklariert hat (entspräche dann einer Prozedur in Pascal). Wird dies nicht getan, so spuckt der Compiler einen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Auch wichtig sind natürlich Kommentare. Erste Variante (Doppelslash) ist auch in der Pascalwelt verfügbar und kommentiert eine einzelne Zeile aus. Die Variante darunter kann man für Kommentarblöcke nutzen (/* .. */) und entspricht den Kommentaren in geschweiften Klammern in Delphi.&lt;br /&gt;
&lt;br /&gt;
Danach kommt dann die '''wichtigste Funktion''' des Shaders, nämlich '''main''', die in keinem Shader fehlen darf. Sie stellt quasi den Programmkörper dar und ist oft auch die einzige Funktion in einem Shader. Sie erhält weder ein Argument, noch gibt sie einen Wert zurück.&lt;br /&gt;
&lt;br /&gt;
Soviel also zum grundlegenden Aufbau eines Shader. Hoffe das jetzt alle die in C nicht so bewandert sind damit klar kommen, und dann bald ihre ersten glSlang-Shader schreiben können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Datentypen==&lt;br /&gt;
&lt;br /&gt;
Obwohl einige Datentypen aus C übernommen wurden, sieht man der Typenliste an, das diese speziell auf den 3D-Bereich zugeschnitten wurde. Variablen müssen vor ihrer Nutzung eindeutig deklariert sein, Typecasting erfolgt über Konstruktoren (dazu später mehr). Folgende Datentypen stehen sowohl im Vertex- als auch Fragmentshader zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|void 	&lt;br /&gt;
|Für Funktionen die keinen Wert zurückgeben&lt;br /&gt;
|-&lt;br /&gt;
|bool 	&lt;br /&gt;
|Konditionaler Typ, entweder true (wahr) oder false (falsch)&lt;br /&gt;
|-&lt;br /&gt;
|int 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenbehafteter Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|uint 	&lt;br /&gt;
|Vorzeichenbehafteter vorzeichenloser Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|float 	&lt;br /&gt;
|Fließkommaskalar mit Singlegenauigkeit (32 Bit)&lt;br /&gt;
|-&lt;br /&gt;
|vec2 	&lt;br /&gt;
|2-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec3 	&lt;br /&gt;
|3-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec4 	&lt;br /&gt;
|4-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec2 	&lt;br /&gt;
|2-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec3 	&lt;br /&gt;
|3-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec4 	&lt;br /&gt;
|4-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec2 	&lt;br /&gt;
|2-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten vorzeichenbehafteter Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec2 	&lt;br /&gt;
|2-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec3 	&lt;br /&gt;
|3-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|uvec4 	&lt;br /&gt;
|4-Komponenten vorzeichenloser Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|mat2 	&lt;br /&gt;
|2x2 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat3 	&lt;br /&gt;
|3x3 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat4 	&lt;br /&gt;
|4x4 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|matMxN 	&lt;br /&gt;
|Matrix mit M Spalten und N Zeilen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse zum Zugriff auf Texturen dar, und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|sampler1D 	&lt;br /&gt;
|Zugriff auf 1D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler2D 	&lt;br /&gt;
|Zugriff auf 2D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler3D 	&lt;br /&gt;
|Zugriff auf 3D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|samplerCube 	&lt;br /&gt;
|Zugriff auf Cubemap&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRect 	&lt;br /&gt;
|Zugriff auf Texturen die nicht 2^n * 2^n entsprechen (&amp;quot;non power-of-two&amp;quot;, NPOT)&lt;br /&gt;
|-&lt;br /&gt;
|sampler1DShadow 	&lt;br /&gt;
|Zugriff auf 1D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DShadow 	&lt;br /&gt;
|Zugriff auf 2D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|samplerCubeShadow&lt;br /&gt;
|Zugriff auf Tiefentextur in einer Cubemap (z.b. für omni-diretionale Lichtquellen)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DRectShadow&lt;br /&gt;
|Zugriff auf 2D-NPOT-Tiefentextur &lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|sampler1DArray&lt;br /&gt;
|Zugriff auf ein array aus 1D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArray&lt;br /&gt;
|Zugriff auf ein array aus 2D-Texturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler1DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 1D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|sampler2DArrayShadow&lt;br /&gt;
|Zugriff auf ein array aus 2D-Tiefentexturen &lt;br /&gt;
|-&lt;br /&gt;
|samplerBuffer&lt;br /&gt;
|Zugriff auf eine Puffertextur (1D-Texutr zum Speichern von Pufferobjekten)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMS&lt;br /&gt;
|Zugriff auf eine 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DMSArray&lt;br /&gt;
|Zugriff auf einarray aus 2D-Textur mit mehreren Samplepunkten (z.b. für Multisampling)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Arrays===&lt;br /&gt;
&lt;br /&gt;
Natürlich unterstützt glSlang auch Arrays, die wie in C deklariert werden und deren Index bei 0 beginnt. Folgendes Array im Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
beginnt also bei Index 0 und endet bei Index 2. Im Gegensatz zu C lassen sich Arrays in glSlang allerdings ''nicht bei der Initialisierung vorbelegen''. Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strukturen===&lt;br /&gt;
&lt;br /&gt;
Neu ggü. ARB_FP/VP ist nun auch die Möglichkeit, Strukturen in einem Shader zu deklarieren. Vor allem die Übersicht komplexerer Shader kann dadurch stark verbessert werden. Strukturen werden wie gewohnt mit dem Schlüsselwort {{INLINE_CODE|struct}} eingeleitet und können dann zur Typisierung von Variablen genutzt werden. Folgendes Beispiel dürfte die Nutzung verdeutlichen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct light&lt;br /&gt;
{&lt;br /&gt;
    bool active;&lt;br /&gt;
    float intensity;&lt;br /&gt;
    vec3 position;&lt;br /&gt;
    vec3 color;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
LightSource[i].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Typenqualifzierer==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur Typendeklaration kann eine Variable noch einen Typenqualifizerer vorangestellt bekommen, der an den Anfang der Deklaration gehört.&lt;br /&gt;
&lt;br /&gt;
* '''const'''&lt;br /&gt;
: Festgelegte (nur lesen) Konstante bzw. nur lesbarer Funktionsparameter.&lt;br /&gt;
&lt;br /&gt;
* '''uniform'''&lt;br /&gt;
: Ein den ganzen Shader über gleichbleibender Wert, der eine Schnittstelle zwischen dem Shader und der OpenGL-Anwendung darstellt. Ein Uniformwert wird in der Hauptanwendung an den entsprechenden Shader übergeben und kann dort dann genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* '''attribute'''&lt;br /&gt;
: Nur lesbare Werte die eine Verbindung zwischen dem Shader und der OpenGL-VertexAPI darstellen (z.B. VertexParameter eines VertexArrays). Natürlich nur in einem Vertex Shader nutzbar.&lt;br /&gt;
&lt;br /&gt;
* '''varying'''&lt;br /&gt;
: Stellt die Verbindung zwischen einem Vertex- und einem FragmentShader dar. Werden im VertexShader geschrieben und dann perspektivisch korrekt über die Primitive interpoliert, um dann im Fragment Shader gelesen werden zu können. Nutzbar sind hier nur die Typen float, vec2, vec3, vec4, mat2, mat3 und mat4, Strukturen und andere Datentypen können nicht varying sein. Die Namen einer varying-Variable müssen sowohl im VertexShader als auch im FragmentShader gleich sein.&lt;br /&gt;
&lt;br /&gt;
* '''in'''&lt;br /&gt;
: Für Variablen die an eine Funktion übergeben und dort ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* '''out'''&lt;br /&gt;
: Für Variablen die von einer Funktion nach außen zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
* '''inout'''&lt;br /&gt;
: Für Variablen die sowohl an eine Funktion übergeben als auch von dieser zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um obige Auflistung nicht leer im Raum stehen zu lassen zeige ich ein paar Beispiele die hoffentlich zum Verständnis beitragen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Vertexnormale soll an einen FragmenShader (interpoliert) übergeben werden :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
VertexNormal = normalize(MV_IT * gl_Normal);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Uniformparameter zur nachträglichen Farbänderung der Szene wird im Programm übergeben :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Im Programm :&lt;br /&gt;
&lt;br /&gt;
 glUniform4fARB(glSlang_GetUniLoc(ProgramObject, 'GlobalColor'), Col[0], Col[1], Col[2], Col[3]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Beispiel C=== &lt;br /&gt;
Konstante zur festen Farbänderung :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
const vec4 ColorBias = vec4(0.2, 0.3, 0.0, 0.0);&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = ColorBias * gl_Color;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Konstruktoren==&lt;br /&gt;
&lt;br /&gt;
Um in einem Shader ''Vektoren'' oder ''Matrizen'' mit Werten zu belegen, gibt es sogenannte Konstruktoren (nicht zu verwechseln mit z.B. Klassenkonstruktoren unter Delphi), die im Endeffekt nichts anderes als Funktionen zur Vorbelegung von Vektoren oder Matrizen darstellen. Dabei trägt der Konstruktor den selben Namen wie die Typendeklaration, also lässt sich eine Variable vom Typ {{INLINE_CODE|vec4}} mit dem Konstruktor {{INLINE_CODE|vec4(float, float, float, float)}} initialisieren.&lt;br /&gt;
&lt;br /&gt;
Allerdings hat man sich recht viel Mühe bei dieser Konstruktorgeschichte gemacht, so dass man einen vec4 nicht unbedingt mit einem {{INLINE_CODE|vec4}}-Konstruktor vorbelegen muss, sondern es vielseitige Möglichkeiten gibt. Um dies zu verdeutlichen gibts ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(1.0, 0.0, 0.0, 0.0);&lt;br /&gt;
vec4 Color = vec4(MyVec3, 1.0);&lt;br /&gt;
vec4 Color = vec4(MyVec2_A, MyVec2_B);&lt;br /&gt;
&lt;br /&gt;
vec3 LVec  = vec3(MyVec4);&lt;br /&gt;
vec2 Tmp   = vec2(MyVec3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trotz der recht wenigen Beispiele sollte schnell erkennbar sein, das man hier wirklich sehr viele Kombinationsmöglichkeiten hat, die dann gültig sind ''wenn man mindestens auf die benötigte Anzahl der Argumente kommt''. Im vorletzten Beispiel wird z.B. ein 3-Komponentenvektor aus einem 4-Komponentenvektor initialisiert. Das erzeugt keinen Fehler, sondern führt dazu das {{INLINE_CODE|vec3.x, vec3.y, vec3.z}} aus MyVec4 übernommen werden und MyVec4.w einfach ignoriert wird.&lt;br /&gt;
&lt;br /&gt;
Das Umkehrbeispiel, also&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
funktioniert allerdings nicht, da hier die Zahl der benötigten Argumente nicht erreicht wird. In diesem Falle müsste es dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
heissen.&lt;br /&gt;
&lt;br /&gt;
Obiges gilt natürlich auch für ''Matrixkonstruktoren'', hier sind z.B. folgende Konstuktoren denkbar, obwohl eigentlich alle Möglichkeiten nutzbar sind, ''solange die benötigte Zahl an Argumenten erreicht wird'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
mat4 MyMatrix = mat4(MyVec4, MyVec4, MyVec4, MyVec4);&lt;br /&gt;
mat2 MyMatrix = mat4(1.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 1.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 1.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixkomponenten==&lt;br /&gt;
&lt;br /&gt;
Was natürlich in keiner Shadersprache fehlen darf, ist der leichte Zugriff auf die einzelnen Komponenten eines Vektors. glSlang bietet, je nach Anwendungsgebiet gleich drei Namensets für den Zugriff auf die Komponenten eines solchen Vektors, welches Set man nutzen will bleibt natürlich frei und ist unabhängig von der Deklaration eines Vektors. Man sollte nur darauf achten, beim gleichzeitigen Zugriff auf mehrere Komponenten im gleichen Namenset zu verbleiben :&lt;br /&gt;
&lt;br /&gt;
* {x, y, z, w}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Punkte, Normale oder sonstige Vertexdaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {r, g, b, a}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Farbwerte repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {s, t, p, q}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Texturkoordinaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
Ein paar Beispiele zur Unterstreichung des oben gesagten :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
v4.rgba = vec4(1.0, 0.0, 0.0, 0.0);  // gültig&lt;br /&gt;
v4.rgzw = vec4(1.0, 1.0, 1.0, 2.0);  // Ungültig, da verschiedenen Namensets&lt;br /&gt;
v2.rgb  = vec3(1.0, 2.0, 1.0);       // Ungültig, da vec2 nur r+g besitzt&lt;br /&gt;
v2.xx   = vec2(5.0, 3.0);            // Ungültig, da 2 mal gleiche Komponente&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch der Zugriff auf die Komponenten einer Matrix geht leicht von der Hand. Namensets wie bei den Vektoren gibt es hier natürlich keine, aber folgende Beispiele sollen den Zugriff aufzeigen :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
MyMat4[2]    = vec4(1.0); // Setzt die 3.Zeile der Matrix komplett auf 1.0&lt;br /&gt;
MyMat4[3][3] = 3.5;       // Setzt das Element unren rechts auf 3.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Matrixelemente ausserhalb ihrer Dimension (also z.B. MyMat4[4][4]) liefert unvorhersehabre Ergebnise, also sollte man auf diese Fälle prüfen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixoperationen==&lt;br /&gt;
&lt;br /&gt;
Wie von C gewohnt sind in glSlang so ziemlich alle Operatoren die man auf Matrizen oder Vektoren anwenden kann überladen, so das man nicht umständlich über selbstgeschriebene Funktionen kombinieren muss. Darüber hinaus ist es in den meisten Fällen auch möglich ohne Konvertierung Fließkommawerte mit kompletten Matrizen oder Vektoren zu kombinieren. Folgende Beispiele zeigen einige der vielfältigen Kombinationsmöglichkeiten auf :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
float factor;&lt;br /&gt;
&lt;br /&gt;
vec3 dest = source + factor; &lt;br /&gt;
&lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = source.x + factor;&lt;br /&gt;
dest.y = source.y + factor;&lt;br /&gt;
dest.z = source.z + factor;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
mat3  MyMat;&lt;br /&gt;
 &lt;br /&gt;
dest = source * MyMat; &lt;br /&gt;
 &lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = dot(source, MyMat[0]);&lt;br /&gt;
dest.y = dot(source, MyMat[1]);&lt;br /&gt;
dest.z = dot(source, MyMat[2]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier sind die Möglichkeiten fast unbeschränkt und zeigen wieder wie flexibel glSlang ausgelegt ist. &lt;br /&gt;
&lt;br /&gt;
==Operatoren==&lt;br /&gt;
&lt;br /&gt;
glSlang bietet (momentan) folgende Operatoren, die Liste ist nach ihrer Gewichtung sortiert (Anfang = höchste). Alle ''reservierten'' Operatoren werden erst in kommender Hardware/glSlang-Versionen nutzbar sein :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div  align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Operatorklasse  	&lt;br /&gt;
!Operatoren  	&lt;br /&gt;
!Assoziation&lt;br /&gt;
|-&lt;br /&gt;
|Gruppering 	&lt;br /&gt;
|() 	&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
|Arrayindizierung&amp;lt;br&amp;gt;Funktionsaufrufe und Konstruktoren&amp;lt;br&amp;gt;Strukturfeldwahl und Swizzle&amp;lt;br&amp;gt;Postinkrement und -dekrement&amp;lt;br&amp;gt; 	&lt;br /&gt;
|[]&amp;lt;br&amp;gt;()&amp;lt;br&amp;gt;.&amp;lt;br&amp;gt;++ -- 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Prefixinkrement- und dekrement&amp;lt;br&amp;gt;Einheitlich (~ reserviert) 	&lt;br /&gt;
| ++ --&amp;lt;br&amp;gt; + - ~ ! 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Mulitplikation (% reserviert) 	&lt;br /&gt;
|* / % 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Additiv 	&lt;br /&gt;
| + - 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises Verschieben (reserviert) 	&lt;br /&gt;
|&amp;lt;&amp;lt;  &amp;gt;&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Relation 	&lt;br /&gt;
|&amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;= 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Vergleich 	&lt;br /&gt;
|==  != 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises AND (reserviert) 	&lt;br /&gt;
|&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises XOR (reserviert) 	&lt;br /&gt;
|^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises OR (reserviert) 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches AND 	&lt;br /&gt;
|&amp;amp;&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches XOR 	&lt;br /&gt;
|^^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches OR 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Auswahl 	&lt;br /&gt;
|?: 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Zuweisung&amp;lt;br&amp;gt;Arithmetrische Zuweisung&amp;lt;br&amp;gt;(Modulis, Shift und bitweise Op. reserviert) 	&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;+= -=  *=  /=  %=&amp;lt;/nowiki&amp;gt; &amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;&amp;lt;&amp;lt;=  &amp;gt;&amp;gt;= &amp;amp;=  ^=  |=&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Aufzählung 	&lt;br /&gt;
|, 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von Hochsprachen ist u.A. die Möglichkeit oft genutzte Codeteile in Funktionen (bzw. auch Prozeduren unter Pascal) zu verpacken um so Flexibilität als auch Übersichtlichkeit zu steigern. Wer schonmal was in C geschrieben hat, der wird sich jetzt sicherlich kein Kopfzerbrechen machen müssen. Funktionen werden in glSlang genauso nach folgendem Prinzip deklariert :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
RückgabeTyp FunktionsName(Typ0 Argument0, Typ1, Argument1, ... , TypN, ArgumentN)&lt;br /&gt;
 {&lt;br /&gt;
 return RückgabeWert;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, außerdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach außen übergeben soll, muss dieses Argument mit dem Typenqualifizierer out (Siehe Kapitel 4.2) versehen werden. ''Arrays'' können nur als Eingabeargumente übergeben werden und dürfen nich dimensioniert als Argument verwendet werden, sondern müssen mit leeren Klammern argumentiert werden.&lt;br /&gt;
Ein paar Beispiele :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void MeineFunktion(float EingabeWert; out float AusgabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 AusgabeWert = EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach außen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float MeineFunktion(float EingabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 return EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bietet genau die selbe Funktionalität wie das Beispiel darüber. Allerdings wird hier der berechnete Wert als Ergebnis der Funktion zurückgeliefert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
float VektorSumme(float v[])&lt;br /&gt;
 {&lt;br /&gt;
 return v[0]+v[1]+v[2]+v[3];&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt darf ein Array als Argument keine Dimensionierung enthalten. Wenn man der Funktion also ein Array übergibt, sollte man vorher drauf achten das es entsprechend der in der Funktion genutzten Indizes dimensioniert wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==if-Anweisung==&lt;br /&gt;
&lt;br /&gt;
Selektion über eine if-Anweisung darf auch in keiner Hochsprache fehlen. Genauso wie in C oder Delphi erwartet auch hier die If-Anweisung einen boolschen Ausdruck (Wahr oder Falsch) und wird dann ausgeführt (wahr) bzw. verzweigt auf ein (wenn vorhanden) else (falsch). Verschachtelung ist wie erwartet auch möglich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis : ''' &lt;br /&gt;
Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten im Fragmentshader kein Early-Out, was zur Folge hat das bei einer If-Anweisung immer alle Zweige ausgeführt werden. Am Ende wird dann aber nur ein Ergebnis geschrieben, die anderen verworfen. Auf solchen Karten bringen If-Anweisungen also im Normalfall keine Geschwindigkeitssteigerung, sondern oft eher das Gegenteil.&lt;br /&gt;
Neuere SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall, da hier dynamische Verzweigungen und auch Early-Out von der Hardware implementiert werden.&lt;br /&gt;
&lt;br /&gt;
==Schleifen==&lt;br /&gt;
&lt;br /&gt;
Auch Schleifen, ein wichtiges Konzept jeder Hochsprache haben ihren Weg in glSlang gefunden. Unterstützt werden folgende Schleifentypen :&lt;br /&gt;
&lt;br /&gt;
* '''for'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
do&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
 while (Durchlaufbedingung)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hinweis :''' Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten Schleifen nicht in Hardware. Schleifen werden dann beim Kompilieren vom Treiber entrollt, wodurch natürlich Shader mit weitaus mehr Instruktionen als erwartet generiert werden. Von daher sollte man auf solchen Karten möglichst auf Schleifen verzichten, oder diese nur recht kurz halten. Bei SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Variablen, Attribute und Konstanten=&lt;br /&gt;
Nachdem wir uns nun lange genug mit den minderinterssanten Elementen der glSlang-Syntax beschäftigt haben, gehts jetzt endlich an die wirklich interessanten Dinge. Wie schon ARB_VP/ARB_FP bringt auch glSlang jede Menge eingabauter Variablen, Attribute und Konstanten mit, deren Aliase sie recht leicht identifizierbar machen (ganz im Gegensatz zum Indexgewusel bei den DX-Shadern).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Vertex Shader==&lt;br /&gt;
Exklusiv im Vertex Shader stehen die folgenden Variablen zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Position    muss geschrieben werden&lt;br /&gt;
:Dieser Variable '''muss''' im Vertexshader ein Wert zugewiesen werden, wird dies nicht getan ist das Ergebnis (sprich die Position des Vertex) undefiniert. Vorgesehen ist diese Variable für die ''homogene Position des Vertex'' und wird u.a. zum Clipping und Culling verwendet. Sie darf natürlich auch (mehrfach) geschrieben und ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* float gl_PointSize    kann geschrieben werden&lt;br /&gt;
:Diese Variable wurde dazu vorgesehen um dort im VertexShader die Punktgröße in Pixeln hineinzuschreiben.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_ClipVertex    kann geschrieben werden&lt;br /&gt;
:Falls genutzt, sollten hier die Vertexkoordinaten die im Zusammenhang mit benutzerdefinierten Clippingplanes genutzt werden abgelegt werden. Wichtig ist, das gl_ClipVertex im selben Koordinatenraum wie die Clippingplane definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Attribute im Vertex Shader==&lt;br /&gt;
&lt;br /&gt;
Folgende Attribute stehen nur im Vertex Shader zur Verfügung und '''können nur gelesen werden''' :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Color&lt;br /&gt;
: Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_SecondaryColor&lt;br /&gt;
:Sekundärer Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_Normal&lt;br /&gt;
:Normale des Vertex.&lt;br /&gt;
* vec4 gl_Vertex&lt;br /&gt;
:Koordinaten des Vertex;&lt;br /&gt;
* vec4 gl_MultiTexCoord0..7&lt;br /&gt;
:Texturkoordinaten auf Textureinheit 0..7.&lt;br /&gt;
* float gl_FogCoord&lt;br /&gt;
:Nebelkoordinate des Vertex. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Fragment Shader==&lt;br /&gt;
&lt;br /&gt;
Im Fragment Shader sind folgende Variablen exklusiv nutzbar :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragColor&lt;br /&gt;
: Speichert den Farbwert des Fragmentes, der von folgenden Funktionen der festen Pipeline genutzt wird. Wird dieser Variable nichts zugewiesen, so ist ihr Inhalt undefiniert und darauf aufbauende Ergebnisse ebenfalls.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragData[0..15]&lt;br /&gt;
: Ersetzt gl_FragColor bei der Verwendung von multiplen Rendertargets. &lt;br /&gt;
&lt;br /&gt;
* float gl_FragDepth&lt;br /&gt;
: Durch schreiben dieser Variable kann man den von der festen Funktionspipeline ermittelten Tiefenwert überspringen, der mit {{INLINE_CODE|gl_FragCoord.z}} ausgelesen werden kann. Wird dieser Wert nicht geschrieben, nutzen folgende Funktionen der Pipeline den vorher fest berechneten Wert.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragCoord    nur lesen&lt;br /&gt;
: In dieser Variable ist die Position des Fragmentes relativ zur Fensterposition im Format x,y,z,1/w abgelegt, wobei z den von der festen Funktionspipeline berechneten Tiefenwert enthält.&lt;br /&gt;
&lt;br /&gt;
* bool gl_FrontFacing    nur lesen&lt;br /&gt;
: Gibt an ob das Fragment zu einer nach vorne zeigenden Primitive gehört (=true). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bezug auf {{INLINE_CODE|gl_FragColor}} und {{INLINE_CODE|gl_FragDepth}} sei noch anzumerken das diese ''nicht'' in den Wertebereich 0..1 gebracht werden müssen, da dies später durch die feste Funktionspipeline automatisch gemacht wird.&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Varyings==&lt;br /&gt;
&lt;br /&gt;
Wie bereits in Kapitel 4.2 erwähnt, stellen Varyings eine Schnittstelle zwischen dem Vertex und dem Fragment Shader dar. Sie werden im Vertex Shader geschrieben und können dann im Fragment Shader ausgelesen werden, ohne das die folgenden Varyings dafür explizit deklariert werden müssen :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontColor&lt;br /&gt;
: Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackColor&lt;br /&gt;
: Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_TexCoord[x]&lt;br /&gt;
: Texturkoordinaten des Vertex auf Textureinheit x, wobei x die von der Hardware zur Verfügung gestellte Zahl der Textureinheiten-1 nicht überschreiten darf.&lt;br /&gt;
&lt;br /&gt;
* float gl_FogFragCoord&lt;br /&gt;
: Nebelkoordinate des Fragmentes. &lt;br /&gt;
&lt;br /&gt;
Die Varyings {{INLINE_CODE|gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor}} und {{INLINE_CODE|gl_BackSecondaryColor}} können im FragmentShader nur unter den Aliases gl_Color bzw. gl_SecondaryColor gelesen werden. Welcher Wert des Vertex Shaders im Fragment Shader dort eingesetzt wird ist abhängig davon ob das Fragment zu einer nach vorne oder nach hinten zeigenden Primitive gehört.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Konstanten==&lt;br /&gt;
Auch diverse Konstanten wurden definiert um darauf schnell im Shader zugreifen zu können. In den Klammern stehen die von einer GL-Implementation als Mindestanforderung anzubietenden Werte. Alle Konstanten sind sowohl im Vertex als auch im Fragment Shader abrufbar :&lt;br /&gt;
&lt;br /&gt;
: OpenGL 1.0/1.2 :&lt;br /&gt;
* int gl_MaxLights (8)&lt;br /&gt;
* int gl_MaxClipPlanes (6)&lt;br /&gt;
* int gl_MaxTextureUnits (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: ARB_Fragment_Program :&lt;br /&gt;
* int gl_MaxTextureCoordsARB (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Vertex_Shader :&lt;br /&gt;
* int gl_MaxVertexAttributesGL2 (16)&lt;br /&gt;
* int gl_MaxVertexUniformFloatsGL2 (512)&lt;br /&gt;
* int gl_MaxVaryingFloatsGL2 (32)&lt;br /&gt;
* int gl_MaxVertexTextureUnitsGL2 (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Fragment_Shader :&lt;br /&gt;
* int gl_MaxFragmentTextureUnitsGL2 (2)&lt;br /&gt;
* int gl_MaxFragmentUniformFloatsGL2 (64)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Uniformvariablen==&lt;br /&gt;
&lt;br /&gt;
Um den Zugriff auf OpenGL-Staten zu vereinfachen wurden in glSlang diverse Uniformvariablen zur direkten Verwendung im Shader eingebaut. Wie gewohnt wurden auch hier sinnvolle Namen verwendet, so dass eine tiefere Erklärung unnötig sein dürfte :&lt;br /&gt;
&lt;br /&gt;
* mat4 gl_ModelViewMatrix&lt;br /&gt;
* mat4 gl_ProjectionMatrix&lt;br /&gt;
* mat4 gl_ModelViewProjectionMatrix&lt;br /&gt;
* mat3 gl_NormalMatrix&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die invertierten und anschließend transponierten oberen 3x3 Werte der {{INLINE_CODE|gl_ModelViewMatrix}}.&lt;br /&gt;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
* float gl_NormalScale&lt;br /&gt;
: Gibt den unter OpenGL festgelegten Faktor zur Skalierung der Normalen zurück.&lt;br /&gt;
&lt;br /&gt;
* struct gl_DepthRangeParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_DepthRangeParameters&lt;br /&gt;
{&lt;br /&gt;
 float near;&lt;br /&gt;
 float far;&lt;br /&gt;
 float diff;&lt;br /&gt;
};&lt;br /&gt;
gl_DepthRangeParameters gl_DepthRange;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_PointParameters&lt;br /&gt;
{&lt;br /&gt;
 float size;&lt;br /&gt;
 float sizeMin;&lt;br /&gt;
 float sizeMax;&lt;br /&gt;
 float fadeThresholdSize;&lt;br /&gt;
 float distanceConstantAttenuation;&lt;br /&gt;
 float distanceLinearAttenuation;&lt;br /&gt;
 float distanceQuadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_PointParameters gl_Point;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_MaterialParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 emission;&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 float shininess;&lt;br /&gt;
};&lt;br /&gt;
gl_MaterialParameters gl_FrontMaterial;&lt;br /&gt;
gl_MaterialParameters gl_BackMaterial;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightSourceParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 vec4 position;&lt;br /&gt;
 vec4 halfVector;&lt;br /&gt;
 vec3 spotDirection;&lt;br /&gt;
 float spotExponent;&lt;br /&gt;
 float spotCutoff;&lt;br /&gt;
 float spotCosCutoff;&lt;br /&gt;
 float constantAttenuation;&lt;br /&gt;
 float linearAttenuation;&lt;br /&gt;
 float quadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_LightSourceParameters gl_LightSource[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelParameters gl_LightModel;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightModelProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 sceneColor;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelProducts gl_FrontLightModelProduct;&lt;br /&gt;
gl_LightModelProducts gl_BackLightModelProduct;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_LightProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
};&lt;br /&gt;
gl_LightProducts gl_FrontLightProduct[gl_MaxLights];&lt;br /&gt;
gl_LightProducts gl_BackLightProduct[gl_MaxLights];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* vec4 gl_TextureEnvColor[gl_MaxFragmentTextureUnitsGL2]&lt;br /&gt;
* vec4 gl_EyePlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
*struct gl_FogParameters&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
struct gl_FogParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 color;&lt;br /&gt;
 float density;&lt;br /&gt;
 float start;&lt;br /&gt;
 float end;&lt;br /&gt;
 float scale;&lt;br /&gt;
};&lt;br /&gt;
gl_FogParameters gl_Fog;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Diese recht umfangreiche GL-Stateliste sollte eigentlich jeden Bedarf decken und momentan gibts kaum einen OpenGL-Status den man so nicht in einem Shader abfragen bzw. nutzen kann.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Funktionen=&lt;br /&gt;
glSlang ist mit diversen Skalar- und Vektorfunktionen ausgestattet, die teilweise (idealerweise) sogar direkt in der Hardware ausgeführt werden, weshalb einer fertigen Funktion ggü. gleichwertigen eigenen Berechnungen immer der Vorzug zu geben ist.&lt;br /&gt;
{{Hinweis| ''genType'' kann vom Type float, vec2, vec3 oder vec4 sein, ''mat'' vom Typ mat2, mat3 oder mat4.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie und Winkel==&lt;br /&gt;
Alle übergebenen Winkel sollten, soweit nicht anders vermerkt, in Radien angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* genType radians (genType degrees)&lt;br /&gt;
: Wandelt von Grad nach Radien. &lt;br /&gt;
* genType degrees (genType radians)&lt;br /&gt;
: Wandelt von Radien nach Grad.&lt;br /&gt;
* genType sin (genType x)&lt;br /&gt;
: Gibt den Sinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType x)&lt;br /&gt;
: Gibt den Kosinus von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType x)&lt;br /&gt;
: Gibt den Tangens von x zurück, wobei x in Radien angegeben wird.&lt;br /&gt;
* genType asin (genType x)&lt;br /&gt;
: Liefert den Arcsinus von x zurück, also den Winkel dessen Sinus x ergeben würde.&lt;br /&gt;
* genType acos (genType x)&lt;br /&gt;
: Liefert den Arckosinus von x zurück, also den Winkel dessen Cosinus x ergeben würde.&lt;br /&gt;
* genType atan (genType y, genType x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x/y ergeben würde.&lt;br /&gt;
* genType atan (genType y_over_x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x über y ergeben würde.&lt;br /&gt;
&lt;br /&gt;
==Hyperbolisch==&lt;br /&gt;
* genType sinh (genType x)&lt;br /&gt;
: Gibt den Sinus Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) * 0.5; )&lt;br /&gt;
* genType cosh (genType x)&lt;br /&gt;
: Gibt den Kosinus Hyperbolicus von x zurück. (return = (exp(x) + exp(-x)) * 0.5; )&lt;br /&gt;
* genType tanh (genType x)&lt;br /&gt;
: Gibt den Tangens Hyperbolicus von x zurück. (return = (exp(x) - exp(-x)) / (exp(x) + exp(-x)); )&lt;br /&gt;
* genType asinh (genType angle)&lt;br /&gt;
: Gibt den Areasinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x + 1.0)); )&lt;br /&gt;
* genType acosh (genType angle)&lt;br /&gt;
: Gibt den Areakosinus Hyperbolicus von x zurück. (return = log(x + sqrt(x * x - 1.0)); )&lt;br /&gt;
* genType atanh (genType x)&lt;br /&gt;
: Gibt den Areatangens Hyperbolicus von x zurück. (return = log((1.0 + x) / (1.0 - x)) * 0.5; )&lt;br /&gt;
&lt;br /&gt;
==Exponentiell==&lt;br /&gt;
* genType pow (genType x, genType y)&lt;br /&gt;
: Gibt x hoch y zurück.&lt;br /&gt;
* genType exp (genType x)&lt;br /&gt;
: Gibt e(Eulerischezahl ≈ 2.7182) hoch x zurück.&lt;br /&gt;
* genType log (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis e(Eulerischezahl ≈ 2.7182) von x zurück.&lt;br /&gt;
* genType exp2 (genType x)&lt;br /&gt;
: Gibt 2 hoch x zurück.&lt;br /&gt;
* genType log2 (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis 2 von x zurück.&lt;br /&gt;
* genType sqrt (genType x)&lt;br /&gt;
: Gibt die Wurzel von x zurück.&lt;br /&gt;
* genType inversesqrt (genType x)&lt;br /&gt;
: Gibt die umgekehrte Wurzel von x zurück.&lt;br /&gt;
&lt;br /&gt;
==Standardfunktionen==&lt;br /&gt;
* genType abs (genType x)&lt;br /&gt;
: Liefert den absoluten Wert von x zurück.&lt;br /&gt;
* genType sign (genType x)&lt;br /&gt;
: Gibt -1.0 zurück, wenn x &amp;lt; 0.0, 0.0 wenn x = 0.0 und 1.0 wenn x &amp;gt; 0.0.&lt;br /&gt;
* genType roundeven(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integervalue und gibt diesen zuück. Bei &amp;quot;.5&amp;quot; Werten wird zur nächsten geraden Zahl gerundet.&lt;br /&gt;
* genType round(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integervalue und gibt diesen zuück. &amp;quot;.5&amp;quot; Werten werden je nach Implementation anders behandelt.&lt;br /&gt;
* genType trunc(genType x)&lt;br /&gt;
: Rundet auf den nächsten Integervalue dessen Absoluterwert nicht größer ist als der Absolutewert von x&lt;br /&gt;
* genType floor (genType x)&lt;br /&gt;
: Gibt denn nächsten Integerwert zurück, der kleiner oder gleich x ist.&lt;br /&gt;
* genType ceil (genType x)&lt;br /&gt;
: Gibt den nächsten Integerwert zurück, der größer oder gleich x ist.&lt;br /&gt;
* genType fract (genType x)&lt;br /&gt;
: Gibt den Nachkommateil von x zurück.&lt;br /&gt;
* genType mod (genType x, float y) &lt;br /&gt;
* genType mod (genType x, genType y)&lt;br /&gt;
: Gibt den Modulus zurück. (=x-y * floor(x/y)) &lt;br /&gt;
* genType min (genType x, genType y) &lt;br /&gt;
* genType min (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn y &amp;lt; x, ansonsten x. &lt;br /&gt;
* genType max (genType x, genType y) &lt;br /&gt;
* genType max (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn x &amp;lt; y, ansonsten x. &lt;br /&gt;
* genType clamp (genType x, genType minVal, genType maxVal) &lt;br /&gt;
* genType clamp (genType x, float minVal, float maxVal)&lt;br /&gt;
: Zwängt x in den Bereich minVal..maxVal.  (return = min(minVal, max(maxVal, x)))&lt;br /&gt;
* genType mix (genType x, genType y, genType a)&lt;br /&gt;
* genType mix (genType x, genType y, float a)&lt;br /&gt;
: Liefert den linearen Blend zwischen x und y zurück. (= x * (1-a) + y * a) &lt;br /&gt;
* genType step (genType edge, genType x)&lt;br /&gt;
* genType step (float edge, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt; edge, ansonsten 1.0. &lt;br /&gt;
* genType smoothstep (genType edge0, genType edge1, genType x)&lt;br /&gt;
* genType smoothstep (float edge0, float edge1, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge0 und 1.0 wenn x &amp;gt;= edge1. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt.&lt;br /&gt;
&lt;br /&gt;
==Geometrie==&lt;br /&gt;
* float length (genType x)&lt;br /&gt;
: Gibt die Länge des Vektors x (= sqrt(x[0]² + x[1]² + ... + x[n]²) zurück. &lt;br /&gt;
* float distance (genType p0, genType p1)&lt;br /&gt;
: Gibt die Distanz zwischen den zwei Vektoren p0 un p1 (= length(p0-p1)) zurück. &lt;br /&gt;
* float dot (genType x, genType y)&lt;br /&gt;
: Gibt das Punktprodukt von x und y zurück (=x[0]*y[0] + x[1]*y[1] + ... + x[n]*y[n]). &lt;br /&gt;
* vec3 cross (vec3 x, vec3 y)&lt;br /&gt;
: Gibt das Kreuzprodukt von x und y zurück. &lt;br /&gt;
* genType normalize (genType x)&lt;br /&gt;
: Normalisiert den Vektor x auf die Länge 1. &lt;br /&gt;
* vec4 ftransform()&lt;br /&gt;
: Nur im Vertex Shader. Die Funktion stellt sicher, das das eingehende Vertex haargenau so transformiert wird wie in der festen Funktionspipeline. gl_Position = ftransform() wird dann also gebraucht, wenn in mehreren Durchgängen sowohl im Shader als auch in der festen Pipeline gerendert wird, um sicherzustellen das in beiden Fällen die gleiche Vertexposition herauskommt. &lt;br /&gt;
* genType faceforward (genType N, genType I, genType Nref)&lt;br /&gt;
: Gibt einen nach vorne zeigenden Vektor N zurück. (If dot(NRef, I) &amp;lt; 0 return N else return -N) &lt;br /&gt;
* genType reflect (genType l, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (result = l - 2.0 * dot(N,I) * N; )&lt;br /&gt;
* genType refract (genType l, genType N, float eta)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N mit dem Brechungsindex eta gebrochenen Vektor l zurück. &lt;br /&gt;
::gentype k = 1.0 - eta * eta * (1.0 - dot(N, l) * dot(N, l))&lt;br /&gt;
::if (k &amp;lt; 0.0)&lt;br /&gt;
:::result = 0.0&lt;br /&gt;
::else &lt;br /&gt;
:::result = eta * l - (eta * dot(N, l) * sqrt(k)) * N)&lt;br /&gt;
&lt;br /&gt;
==Matrixfunktionen==&lt;br /&gt;
* mat matrixCompMult (mat x, mat y)&lt;br /&gt;
: Multipliziert Matrix X mit Matrix Y komponentenweise. Um eine normale lineare Matrixmultiplikation durchzuführen, sollte der &amp;quot;*&amp;quot;-Operator genutzt werden.&lt;br /&gt;
* mat transpose (mat m)&lt;br /&gt;
: Gibt die transponierte Matrix von m zurück.&lt;br /&gt;
* mat invert (mat m)&lt;br /&gt;
: Gibt die invertierte Matrix von m zurück. Also die Matrix, die mit m multipliziert die Normalmatrix ergeben würde.&lt;br /&gt;
* mat outerProduct(vec c, vec r)&lt;br /&gt;
: Gibt eine eine Matrix als Ergebnis der linearen (return[m, n] = c[m] * r[n])-Operation zurück.&lt;br /&gt;
&lt;br /&gt;
==Vektorvergleiche==&lt;br /&gt;
Die meisten Vektorvergleichsfunktionen liefern als Ergebnis einen boolvektor zurück, da die Vergleiche per Komponente stattfinden. Wenn man also x = vec4(1.0, 3.0, 0.0, 0.0) mit y = vec4(2.0, 1.5, 1.5, 0.0) via lessThan(x, y) vergleicht, erhält man als Ergebnis bvec(true, false, true, false).&lt;br /&gt;
&lt;br /&gt;
* bvec lessThan (vec x, vec y)&lt;br /&gt;
* bvec lessThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt; y zurück. &lt;br /&gt;
* bvec lessThanEqual (vec x, vec y)&lt;br /&gt;
* bvec lessThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt;= y zurück. &lt;br /&gt;
* bvec greaterThan (vec x, vec y)&lt;br /&gt;
* bvec greaterThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt; y zurück. &lt;br /&gt;
* bvec greaterThanEqual (vec x, vec y)&lt;br /&gt;
* bvec greaterThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt;= y zurück. &lt;br /&gt;
* bvec equal (vec x, vec y)&lt;br /&gt;
* bvec equal (ivec x, ivec y)&lt;br /&gt;
* bvec equal (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x == y zurück. &lt;br /&gt;
* bvec notEqual (vec x, vec y)&lt;br /&gt;
* bvec notEqual (ivec x, ivec y)&lt;br /&gt;
* bvec notEqual (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x != y zurück. &lt;br /&gt;
* bool any (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn mindestens eine der Komponenten von x true ist.&lt;br /&gt;
* bool all (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn alle Komponenten von x true sind. &lt;br /&gt;
* bvec not (bvec x)&lt;br /&gt;
: Liefert die logische Negation von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Texturenzugriffe==&lt;br /&gt;
&lt;br /&gt;
Diese wichtige Funktionskategorie dient dazu, Werte aus einer an eine Textureinheit gebundenen Textur zu ermitteln. Die Texturenzugriffe können sowohl im Vertex (!) als auch im Fragment Shader ausgeführt werden, wobei der optionale Parameter bias im Vertex Shader ignoriert wird. Allerdings gibt es zusätzlich Funktionen die auf &amp;quot;Lod&amp;quot; enden und nur im Vertex Shader genutzt werden dürfen um eben dieses Manko zu umgehen. Funktionen mit dem Suffix &amp;quot;Proj&amp;quot; geben einen projizierten Texturenwert zurück.&lt;br /&gt;
&lt;br /&gt;
: '''1D-Texturen :'''&lt;br /&gt;
* vec4 texture1D (sampler1D sampler, float coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 texture1DLod (sampler1D sampler, float coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''2D-Texturen :'''&lt;br /&gt;
* vec4 texture2D (sampler2D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''3D-Texturen :'''&lt;br /&gt;
* vec4 texture3D (sampler3D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture3DProj (sampler3D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture3DProjLod (sampler3D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Cubemap :'''&lt;br /&gt;
* vec4 textureCube (samplerCube sampler, vec3 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
*vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Tiefentextur (Shadowmap) :'''&lt;br /&gt;
* vec4 shadow1D (sampler1DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow2D (sampler2DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
* vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow1DProjLod (sampler1DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
* vec4 shadow2DProjLod (sampler2DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Texturegröße :'''&lt;br /&gt;
Mit den textureSize-Befehlen kann die Größe einer Textur bestimmt werden, wobei lod das Mipmaplevel angibt:&lt;br /&gt;
*int textureSize(sampler1D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2D sampler, int lod)&lt;br /&gt;
*ivec3 textureSize(sampler3D sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(samplerCube sampler, int lod)&lt;br /&gt;
*int textureSize(sampler1DShadow sampler, int lod)&lt;br /&gt;
*ivec2 textureSize(sampler2DShadow sampler, int lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie bereits eingangs gesagt ist dieses Kapitel ein sehr wichtiges, denn eine 3D-Szene ohne Texturen ist heute kaum denkbar. Darüber hinaus lassen sich durch Texturenzugriffe recht viele interessante Sachen machen, z.B. ein einfacher Blurfilter oder das freie überblenden bestimmter Texturenteile. Deshalb führe ich hier kurz ein paar Beispiele an, welche die Nutzung dieser Funktionen verdeutlichen sollen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Eine Textur gebunden die einfach ausgegeben werden soll&lt;br /&gt;
&lt;br /&gt;
''Im Vertex Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
Der Vertex Shader ist recht minimal. Neben der homogenen Vertexposition leiten wir hier nur die im OpenGL-Programm angegebenen Texturkoordinaten weiter. ''Dies ist aber unbedingt nötig!'' Ohne die letzte Zeile hätten wir im Fragment Shader keine gültigen Texturkoordinaten auf TMU0, was in einer Fehldarstellung enden würde.&lt;br /&gt;
&lt;br /&gt;
''im Fragment Shader'' :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSampler;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(texSampler, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zuerst deklarieren wir hier einen 2D-Texturensampler, wichtig : '''Texturensampler müssen IMMER als uniform deklariert werden!''' In der Hauptfunktion weisen wir dann einfach den über die Funktion texture2D aus unserer gebundenen Textur ausgelesenen Farbwert, anhand der vom Vertex Shader übergebenen Texturkoordinaten, zu.&lt;br /&gt;
{{Vorlage:Hinweis|Der Uniform-Integer für den Sampler referenziert '''nicht''' den Namen (die ID) des Texturobjektes, sondern die Nummer der Texturunit.}}&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Zwei Texturen, jeweils auf TMU0 und TMU1. Fragmentfarbe soll eine Multiplikation der beiden Texturen darstellen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielfall (der recht häufig vorkommt) müssen wir im Programm festlegen, ''welcher Sampler welche Textureinheit adressiert'', genau deshalb müssen die Texturensampler auch als uniform deklariert werden. Die Standardtextureneinheit eines Samplers ist TMU0, was in unserem Falle natürlich nicht brauchbar ist. Also müssen wir unserem zweiten Textursampler im Programm mitteilen das er seine Daten aus TMU1 beziehen soll :&lt;br /&gt;
&lt;br /&gt;
 glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&lt;br /&gt;
Dies ist also unbedingt zu machen, sobald ein Texturensampler eine Textureinheit &amp;gt; GL_TEXTURE_0 adressieren will. Die Textureneinheit des Samplers lässt sich also nicht im Shader selbst festlegen. Der Fragment Shader ist nun allerdings schnell hergeleitet (Vertex Shader verändert sich nicht, da TMU1 die Texturkoordinaten auch von TMU0 bezieht) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
im Fragment Shader :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D texSamplerTMU0;&lt;br /&gt;
uniform sampler2D texSamplerTMU1;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_FragColor = texture2D(texSamplerTMU0, vec2(gl_TexCoord[0])) *&lt;br /&gt;
                   texture2D(texSamplerTMU1, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich [[GLSL noise|Noisefunktionen]] nutzen, mit deren Hilfe sich eine gewisse &amp;quot;Zufälligkeit&amp;quot; simulieren lässt (wirklich zufällige Werte sind es natürlich nicht). Ein zurückgegebener Wert liegt dabei immer im Bereich [-1..1] und ist immer bei gleichem Eigabewert auch immer gleich. Die Verwendung empfiehlt sich derzeit allerdings eher nicht, da nur die 3DLabs Treiber die Funktionen unterstützen und eine Noisetextur wahrscheinlich performanter ist.&lt;br /&gt;
&lt;br /&gt;
* float noise1 (genType x)&lt;br /&gt;
* vec2 noise2 (genType x)&lt;br /&gt;
* vec3 noise3 (genType x)&lt;br /&gt;
* vec4 noise4 (genType x)&lt;br /&gt;
&lt;br /&gt;
==Discard==&lt;br /&gt;
Eigentlich keine Funktion, sondern eine Abbruchbedingung '''nur im Fragment Shader'''. Das Schlüsselwort {{INLINE_CODE|discard}} verwirft das aktuell bearbeitete Fragment und beendet gleichzeitig den Shader. Es kann z.B. genutzt werden um Alphamasking manuell durchzuführen.&lt;br /&gt;
Man sollte dabei jedoch beachten dass ein Großteil der aktuellen Hardware kein &amp;quot;early-out&amp;quot; (frühes Beenden) im Fragmentshader unterstützt. Wenn dort also ein {{INLINE_CODE|discard}} auftaucht, wird trotzdem auch der Code danach ausgeführt und einfach verworfen. Einen Geschwindigkeitsvorteil durch diesen Befehl wird man also erst auf neueren Karten feststellen, die dieses Faeature auch so unterstützen wie es angedacht war. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispielshader=&lt;br /&gt;
Wen bis hierhin nicht der Mut verlassen hat, und wer aufmerksam gelesen hat, dürfte jetzt also zumindest in der Lage sein kleinere Shader in glSlang zu schreiben und diese auch im Programm zu nutzen. Ich habe im Themenbereich &amp;quot;glSlang&amp;quot; versucht alle Bereiche der Shadersprache selbst anzusprechen und hoffe das auch brauchbar rübergebracht zu haben. Um oben erlerntes (hoffe ich doch mal) nochmal zu vertiefen werde ich jetzt (wie ich das bereits bei meinem ARB_VP-Tutorial getan habe) einen simplen Beispielshader (Vertex und Fragment Shader) auseinanderpflücken um so u.a. auch die Programmstruktur für alle die in C nicht so bewandert sind zu erörtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Vertex Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_FrontColor   = gl_Color * GlobalColor;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie gesagt recht simpel. Angefangen wird mit der Deklaration einer globalen Uniformvariable namens {{INLINE_CODE|GlobalColor}}. Wie wir uns erinnern gibt der Typenqualifizierer uniform an, das wir den Wert dieser Variable (ein 4-Komponentenvektor, da Farbwerte aus R,G,B und A bestehen) in unserem Programm an den Shader übermitteln.&lt;br /&gt;
&lt;br /&gt;
Danach gehts ohne Umwege direkt in unsere Hauptfunktion, da wir im Vertex Shader keine anderen Funktionen benötigen. Dort berechnen wir zuerst die homogene Position unseres Vertex, die sich aus der eingehenden Vertexposition multipliziert mit der Modelansichtsmatrix ergibt. Wie schonmal gesagt '''muss diesem Wert etwas zugewiesen werden''', da sonst alle darauf aufbauenden Funktionen unvorhersehbare Ergebnisse liefern.&lt;br /&gt;
Außerdem wollen wir die Frontfarbe unseres Vertex jedesmal mit der im Programm übergebenen GlobalColor multiplizieren, so dass wir den Farbwert der gesamten Szene aus unserem Programm heraus manipulieren können. Zu guterletzt geben wir dann noch unsere aus der festen Funktionspipeline erhaltenen Texturkoordinaten auf Textureinheit 0 weiter. Wenn im Fragmentshader Texturkoordinaten verwendet werden, '''muss das getan werden'''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Fragment Shader==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;glsl&amp;quot;&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
uniform sampler2D Texture2;&lt;br /&gt;
uniform sampler2D Texture3;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec2 TexCoord = vec2( gl_TexCoord[0] );&lt;br /&gt;
 vec4 RGB      = texture2D( Texture0, TexCoord );&lt;br /&gt;
&lt;br /&gt;
 gl_FragColor  = texture2D(Texture1, TexCoord) * RGB.r +&lt;br /&gt;
                 texture2D(Texture2, TexCoord) * RGB.g +&lt;br /&gt;
                 texture2D(Texture3, TexCoord) * RGB.b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier passiert nicht wirklich viel Großartiges. Wir deklarieren beim Shaderanfang zuerst vier Texturensampler, da wir insgesamt vier verschiedene Texturen im Shader auslesen wollen, eine Verlaufstextur und drei Oberflächentexturen. Auch hier sei wieder gesagt das man Sampler '''immer als uniform deklarieren muss'''. In der Hauptfunktion deklarieren wir dann einen Farbvektor, der auch direkt einen Farbwert aus Textureinheit 0 zugewiesen bekommt. Auf Textureinheit 0 haben wir ihm Hauptprogramm eine Verlaufstextur gebunden, die angibt wie die drei folgenden Texturen ineinander geblendet werden.&lt;br /&gt;
Danach schreiben wir dann den Farbwert des Fragmentes, der '''im Fragment Shader ausgegeben werden muss'''. Der besteht wie einfach zu erkennen aus Farbwert von Textureinheit 1 * Rotwert von Textureinheit 0 + Farbwert von Textureinheit 2 * Grünwert von Textureinheit 0 + Farbwert von Textureinheit 3 * Blauwert von Textureinheit 0. So ist z.B. an Stellen an denen in der Verlaufstextur reines blau liegt nur die dritte Textur sichtbar.&lt;br /&gt;
&lt;br /&gt;
So viel also zu unserem kleinen Beispielshader. Er ist weder besonders toll noch besonders sinnvoll, sollte aber auch eher dazu dienen euch glSlang ein wenig zu veranschaulichen, was mir hoffentlich gelungen ist.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr in den vorangegangenen Kapiteln zumindest ein wenig aufgepasst habt, dann könnt ihr euch vor eurem inneren Auge hoffentlich vortstellen was der Shader macht : Er blendet drei Texturen weich anhand der Verlaufstextur ineinander über. Sowas kann man z.B. für ein Terrain nutzen, um dieses anhand einer Farbtextur zu texturieren. Für alle, die damit Probleme haben hier zwei Bilder die den Shader veranschaulichen. Links die Verlaufstextur, die angibt wo welche Textur wie stark gewichtet wird und rechts dann das Ergebnis :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; [[BILD:GLSL_sample_shader_a.jpg]] [[BILD:GLSL_sample_shader_b.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post Mortem=&lt;br /&gt;
Das wars also, meine &amp;quot;Einführung&amp;quot; in die OpenGL Shader Sprache. Ich hoffe es hat euch nicht gelangweilt und auch die von mir zur Verfügung gestellten Informationen haben euch hoffentlich ausgereicht. Mit der Veröffentlichung dieser Einführung geht übrigens auch die Eröffnung eines Shaderforums hier auf der DGL einher, in der ihr dann also fleissig Fragen zum Thema stellen oder eure Shader präsentieren könnt. In diesem Post Mortem gehe ich jetzt noch kurz auf die Zukunft von glSlang ein und zeige ein paar Screenshots (damit die Augen entspannen können), bevor ihr euch dann selbst in die Shaderwelt stürzen könnt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
Anbei ein paar exemplarische Screenshots. Da man mit GLSL aber alle möglichen Effekte berechnen kann (u.a. auch 1:1 die feste Funktionspipeline) ist es hier unmöglich einen Überblick aller möglichen Techniken zu geben.&lt;br /&gt;
&lt;br /&gt;
[[Datei:tut_glsl_eigenershader_01.png]] [[Datei:tut_glsl_eigenershader_02.png]] [[Datei:tut_glsl_eigenershader_03.png]]&lt;br /&gt;
&lt;br /&gt;
Wie im ersten (und dritten) Screenshot zu sehen ist es natürlich auch möglich mehrere Techniken innerhalb einer Szene zu nutzen. Hier sind letztendlich bis auf Hardwarelimitationen keine Grenzen gesetzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Als dieses Tutorial geschrieben wurde, war noch nicht ganz abzusehen dass bzw. ob sich GLSL auch durchsetzen würde. ARB-Shadr und NVidias cG waren damals die Platzhirsche, aber inzwischen werden ARB-Shader nicht mehr genutzt (und auch schon länger nicht mehr weiterentwickelt) und auch NVidia setzt primär auf GLSL. GLSL wird permanent weiterenwtickelt und Hersteller können dank des flexiblen Extensionsystems auch in GLSL eigene Extensions offenlegen um die aktuellsten Features (wie z.b. den Tesselator auf aktuellen ATI-Karten) nutzen zu können. GLSL gilt inzwischen auch offizielle die Shadersprache für OpenGL und wird permanent an die neusten technischen Entwicklungen im Grafikkartenbereich angepasst.&lt;br /&gt;
&lt;br /&gt;
Wer also unter OpenGL etwas mit Shadern machen möchte, kommt an GLSL nicht vorbei!&lt;br /&gt;
&lt;br /&gt;
Also viel Spaß beim Experimentieren und Shaderschreiben! Und nicht vergessen : Wir wollen sehen was ihr so treibt,&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_glsl2]]}}&lt;br /&gt;
[[Kategorie:Tutorial|GLSL]]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=FAQ&amp;diff=25642</id>
		<title>FAQ</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=FAQ&amp;diff=25642"/>
				<updated>2012-03-21T14:51:17Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= FAQ (Frequently asked Questions) =&lt;br /&gt;
Hier wird auf einige, sehr häufige Fragen eingegangen. Ein solches FAQ soll vor allem verhindern, dass häufig angefragte Themen im Forum wieder und wieder angefragt werden. Ein Großteil dieses FAQs stammt aus unserem alten Foren-FAQ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweis ==&lt;br /&gt;
Dies ist '''kein Wiki-FAQ'''! Fragen bzgl. des Wikis oder dessen Benutzung werden hier also nicht beantwortet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== OpenGL ==&lt;br /&gt;
Fragen und Antworten im Bezug auf häufig angesprochene OpenGL-Themen/Problematiken :&lt;br /&gt;
&lt;br /&gt;
=== OpenGL - Allgemein ===&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Was muss installiert sein damit OpenGL läuft?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Generell muss keine zusätzliche Software oder Bibliothek auf dem Computer des Endanwenders installiert sein. OpenGL wird mit der Installation der Grafikkartentreiber ermöglicht. Sollte also eine ATI- oder NVIDIA-Karte mit aktuellem Treiber vorhanden sein, wird auch OpenGL funktionieren. Die Installation einer aktuellen DirectX-Version haben keinerlei Einfluss auf die Funktionalität von OpenGL, obwohl die Hersteller dazu übergegangen sind Grafikkarten nach DirectX-Versionen zu benennen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' OpenGL läuft auf meinem frisch installierten Win2k/XP System furchtbar langsam?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Microsoft installiert von Haus aus Standard-OpenGL Treiber, die im Software-Modus arbeiten. Entsprechend wird die Grafikkarte im Rechner nicht für die Berechnung von 3D-Szenen verwendet. Installiere den aktuellen Treiber deiner Grafikkarte und das Geschwindigkeitsproblem wird behoben sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Was bedeuten eigentlich diese Buchstaben und Zahlen am Ende der OpenGL Befehle?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Die Buchstaben geben Informationen zum Typ der Parameter an. Mehr Informationen dazu findet ihr unter [[Funktions Anhang]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== OpenGL-Header (Unit) ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Wo gibt es den aktuellsten OpenGL-Header für Delphi?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Das DGL-Interne OpenGL2-Portteam kümmert sich um die aktuellsten OpenGL-Header (momentan bis v2.1), welche [[DGLOpenGL.pas| hier]] zu beziehen sind. In [http://www.delphigl.com/forum/viewtopic.php?t=1863 diesem Forenthread] gibt es immer die neuste Version, so wie Informationen zu Änderungen/Neuerungen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Warum heisst euer Header inzwischen ''[[dglOpenGL.pas]]'' statt wie früher ''OpenGl15.pas''?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Das liegt daran, dass wir uns auch weiterhin um die zur Verfügungstellung der aktuellsten GL-Funktionalität für Delphinutzer kümmern wollen. Und da es ja nach OpenGL 1.5 weitergeht, hätten wir mit jeder neuen GL-Version einen neuen, anders benannten, Header rausbringen müssen. Dadurch würde die Umstellung unnötig komplizierter, weshalb wir uns dazu entschieden haben den Header umzubenennen, so dass man bei einer Aktualisierung nichts am Programm ändern muss.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' In manchen Anwendungen/Tutorials die euren Header benutzen, steht manchmal ein ''GLint'' statt eines ''TGLint'', oder umgekehrt. Welche Schreibvariante ist korrekt?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Das spielt keine Rolle. In unserem Header sind ''GLint'' und ''TGLint'' beide vom gleichen Datentyp. In älteren Headern (z.B. Mike Lischkes ''OpenGL12.pas'') begannen alle OpenGL-Typen mit einem ''T'', was zwar den Programmierstandards für Object Pascal entspricht, aber nicht denen für OpenGL. Deshalb haben wir in unserem Header beide Varianten, also GL-Standard und OP-Standard (mit ''T'' als Präfix) untergebracht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Ich habe früher den mit Delphi gelieferten OpenGL-Header (''OpenGL.pas'') benutzt, und bin auf euren Header umgestiegen. Die Programme lassen sich dann zwar ohne Änderungen kompilieren, aber beim Start erhalte ich eine Zugriffsverletzung an Adresse 0.&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Um unseren Header flexibler zu machen, haben wir in Sachen Initialisierung etwas geändert. Vor dem Aufruf (am besten direkt nach Programmstart) des ersten GL-Befehles, muss erstmal '''InitOpenGL()''' aufgerufen werden, so dass die OpenGL-Funktionszeiger zugewiesen werden. Desweiteren sollte darauf geachtet werden, dass vor dem Aufruf eines glBefehls der Context aktiviert wird. Danach kann ganz normal weitergearbeitet werden. Diese Änderung wurde deshalb getätigt, weil wir mit unserem Header auch das dynamische Laden anderer OpenGL-Implementationen (z.B. MESA) ermöglichen wollten.&lt;br /&gt;
&lt;br /&gt;
=== Diverse ===&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Wie arbeiten Delphi und OpenGL eigentlich zusammen?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' OpenGL ist eine API. Um sie zu benutzen muss auf dem Computer ein OpenGL fähiger Grafikkartentreiber oder zumindest ein Softwareemulator installiert sein (dies ist heutzutage immer der Fall). Um Befehle von Delphi aus an die OpenGL API zu senden benötigt ihr den Oben angesprochenen Header, die [[DGLOpenGL.pas]]. Diesen Header bindet ihr, wie jede Unit auch, über eure '''uses''' Klausel in eurem Programm ein und plötzlich spricht Delphi auch OpenGL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Wie bekomme ich den Gerätekontext (der zum Erstellen eines Renderkontextes nötig ist) eines Windowsobjektes?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Generell kann man den Gerätekontext eines Windowsobjektes anhand der Funktion '''GetDC''', mit dem ''Handle'' des Objektes als Argument ermitteln. Bei VCL-Objekten geht dies meist noch bequemer, nämlich (falls dieses Objekt eine solche Eigenschaft besitzt) über die Eigenschaft ''Objekt.Canvas.Handle''. Hinweise : Wenn man den Gerätekontext mittels GetDC ermittelt hat, sollte man diesen bei Programmende wieder mit ReleaseDC freigeben. Außerdem gibt es einige Objekte (z.B. ''TPaintBox'') auf die nicht gerendert werden kann. Für den Anfang solltet ihr ein [[OpenGL Template]] verwenden, welches sich um so etwas selbst kümmert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Wie kann ich bereits erzeugte Texturen wieder freigeben?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Möchte man Texturen während der Laufzeit aus dem Texturenspeicher entfernen, so ist dies über den Befehl [[glDeleteTextures]] möglich. Man beachte allerdings, dass dies beim Beenden eines Programmes nicht nötig ist, denn sobald ein Renderkontext zerstört wird, werden auch alle zugehörigen Objekte (Texturen, Displayliste, Shader, etc.) gelöscht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Kann ich mit OpenGL auch 2D machen?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' 2D ist nur ein Spezialfall von 3D und kann natürlich mit OpenGL gemacht werden. Es gibt dafür spezielle Befehle die euch im [[Tutorial 2D|2D-Tutorial]] auf DelphiGL.com erklärt werden. Lest trotzdem auch die anderen Einsteigertutorials, denn diese bilden das Fundament auf dem dann das 2D-Tutorial aufbaut. '''''2D ist nicht leichter als 3D! Es ist nur ein bisschen anders.'''''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Warum verschwinden meine Objekte, sobald ich sie auch nur ein wenig nach hinten oder vorne verschiebe, aus meiner 3D-Szene?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Wahrscheinlich ist die nahe- oder ferne Schnittfläche falsch eingestellt. Diese lassen sich über die letzten beiden Parameter (''zNear'' und ''zFar'') der beiden Funktionen [[glOrtho]] und [[gluPerspective]] setzen, die beide eine Projektionsmatrix erstellen. Fällt nun eines der Objekte hinter die ferne bzw. vor die nahe Schnittfläche, wird es entweder abgeschnitten oder verschwindet komplett. Sollte dies der Fall sein, muss man obige Parameter entsprechend anpassen. Hinweis : ''zNear'' muss immer größer 0 sein, im Normalfall versucht man die nahe Schnittfläche allerdings so weit wie möglich hinauszuschieben, um die Auflösung des Tiefenpuffers besser nutzen zu können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Warum seh ich meine Szene nicht?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Es gibt verschiedene Fehler die daran schuld sein könnten.&lt;br /&gt;
:# Die Kamera befindet sich zu nah/im Objekt. -&amp;gt; Vorm zeichnen der Objekte Szene per [[glTranslate]] nach hinten verschieben.&lt;br /&gt;
:# Die Flächen wurden bei aktivierten [[Backfaceculling]] verkehrt herum definiert. -&amp;gt; Deaktivieren des Backfacecullings. Wenn Objekte sichtbar, Eckpunkte in anderer Reihenfolge übergeben.&lt;br /&gt;
:# Die Farbe ist gleich der Hintergrundfarbe und Beleuchtung ist aus. -&amp;gt; Ändern der Farbe mittels [[glColor]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Ich habe Probleme mit einem dieser Themen: Transparenz, Blending, Positionierung, Texturen oder Shadern. Wie bekomme ich die gelöst?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Zu aller erst solltest du nachsehen ob es eine [[Hintergrundwissen#Checklisten|Checkliste]] gibt, welche die Häufigsten Fehlerquellen ausschließt. Falls dies dir nicht hilft, ist das Forum bei DelphiGL.com der richtige Ort für deine Fragen. Wir haben neben dem allgemeinen OpenGL Subforum dort auch einen Shader-Bereich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :'''Wie kann ich die ALT- und F10-Taste abfangen, da diese meien GL-Anwendung pausieren?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Ein Blick in die MS-SDK verrät uns, dass die Tasten ALT und F10 (wie bereits bekannt) für die Aktivierung des Menüs stehen. Windows sendet also bei Betätigung der Taste(n) eine System-Nachricht, in welcher per Parameter definiert ist, dass es um einen Menu-Key handelt.&lt;br /&gt;
: Nachricht: WM_SYSCOMMAND, Parameter: SC_KEYMENU.&lt;br /&gt;
: Nun haben es die Programmierer, welche ein API-Fenster verwenden, leicht. Denn hier wird einfach die Nachricht abgefangen. Aber wie läuft das mit der VCL? Ich bin ja nicht in der Message-Loop drinnen, also was soll ich tun? - Ganz einfach! Delphi bietet eine Möglichkeit an, Prozeduren in die Message-Loop einzubinden. Die Prozedur muss dann folgendermaßen innerhalb der Form definiert sein:&lt;br /&gt;
: &amp;lt;code&amp;gt;procedure [Name](var TheMsg: [Typ Abhängig von der Nachricht]); message [gewünschte Nachricht]&amp;lt;/code&amp;gt;&lt;br /&gt;
: Damit wird die [gewünschte Nachricht] angegebene Message an das Fenster weitergeleitet, in welcher die Prozedur definiert wurde. Nähere infos gibt's in der Delphi-Hilfe.&lt;br /&gt;
: In unserem Fall bedeutet dass (zuerst die Funktion deklarieren)&lt;br /&gt;
: &amp;lt;code&amp;gt;procedure WMSysCommand(var SysCmd: TWMSysCommand); message WM_SYSCOMMAND;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Ein weiterer Blick in die SDK verrät uns, dass Windows als Result 0 erwartet, wenn die System-Nachricht von der Anwenung verarbeitet wurde. Also müssen wird folgender maßen unsere Funktion implementieren:&lt;br /&gt;
&amp;lt;ul&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
 &amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;procedure TMainForm.WMSysCommand(var SysCmd: TWMSysCommand);&lt;br /&gt;
   begin&lt;br /&gt;
   if SysCmd.CmdType = SC_KEYMENU then&lt;br /&gt;
    SysCmd.Result := 0&lt;br /&gt;
   else&lt;br /&gt;
    inherited;&lt;br /&gt;
   end;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
: Es ist dabei sehr wichtig, zu überprüften, ob es sich wirklich um SC_KEYMENU handelt. Denn WM_SYSCOMMAND wird auch bei sämtlichen Fenster-Nachrichten aufgerufen. Wenn wir also einfach alle Nachrichten als verarbeitet definieren, kann das Fenster nicht mehr verschoben, in der Größe verändert oder gar geschlossen werden. Deswegen SysCmd.Result NUR DANN auf 0 setzen wenn es sich wirklich um die SC_KEYMENU Nachricht handelt. Ansonsten den Vorgänger aufrufen (per inherited) und somit die Nachricht and die VCL weiterleiten.&lt;br /&gt;
&lt;br /&gt;
== DGL ==&lt;br /&gt;
Fragen und Antworten im Bezug auf unsere [http://www.delphigl.com Delphi-OpenGL-Community] :&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Ich möchte ein Tutorial für die DGL schreiben, was muss ich tun?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Tutorials von &amp;quot;externen&amp;quot; Leuten nehmen wir natürlich gerne (und haben wir auch schon getan), allerdings solltet ihr einige Sachen beachten, bevor ihr euch dran macht ein Tutorial für uns zu schreiben :&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
# Setze dich zuerst mit einem unserer [http://www.delphigl.com/team.php Teammitglieder] (bzw. aktueller: das [[Team]]) in Verbindung, und frag an ob ein Tutorial zum von dir gewählten Thema überhaupt nützlich/interessant ist.&lt;br /&gt;
# Sollte dies der Fall sein, dann schreibe dein Tutorial, und sende es an das Teammitglied dem du es vorgeschlagen hast. Da die Tutorials hier im Wiki veöffentlich werden, schickt es uns bitte '''nicht als formatiertes HTML-Dokument''' zu, sondern als einfachen TXT. Wenn du ein Beispielprogramm hast, dann schicke es uns bitte mit komplettem Quellcode (mit ALLEN Units die gebraucht werden), sowie vorkompiliert zu. Der Quellcode sollte nach Borland-Standards geschrieben und formatiert sein, und auch ausführlich kommentiert.&lt;br /&gt;
# Wenn sich das Teammitglied die Sache angesehen hat, wird das Tutorial in einem eigens dafür eingerichtetem, internem Forum hochgeladen. Dort hat der Rest des Teams dann ein bis zwei Wochen Zeit es sich auch anzuschauen.&lt;br /&gt;
# Danach gibts dann vom Team her bescheid. Entweder ne Bestätigung dass es hochgeladen wird, oder Verbesserungsvorschläge. Bei letzterem springe wieder zu Punkt 1.&lt;br /&gt;
# Wenn das Tutorial gut und vom Team abgesegnet ist, wird es von einem Teammitglied ins passende Format gebracht und veröffentlicht.&lt;br /&gt;
# Dann gibts natürlich auch Bescheid (per Mail), und nen Newseintrag.&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
''Auch wenn das hier sehr streng klingt braucht ihr euch keine Sorgen zu machen. Wir wollen Tutorials und wir helfen denen die ein interessantes Thema bearbeiten um ein schönes Tutorial draus zu machen. Ein Beispiel für ein Tutorial (bzw. eine Serie) was uns vorgeschlagen wurde: [[Tutorial_Kollision1]].''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Kann ich News auf DGL veröffentlichen?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Jein! Selbstständig News posten ist den [[Team|Moderatoren]] vorbehalten. Da diese aber auch nicht alles mitbekommen, was im Netz vorfällt freuen wir uns über Informationen die sich mit OpenGL, Delphi bzw. Programmierung befassen. &amp;lt;br&amp;gt;&lt;br /&gt;
:Wenn ihr ein eigenes Projekt (vorzugsweise unter Benutzung von OpenGL) fertig gestellt habt, und der Meinung seid die Welt müsse dies erfahren, so könnt ihr ein Bild + Text an einen Moderator senden. Dieser wird dann entscheiden ob es als News taugt, oder zumindest als &amp;quot;Image Of the Week/Day&amp;quot; verwendet werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Kann ich Projekte bei DGL veröffentlichen?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Ja! (Solange sie nicht rechtwiedrig sind.) Entweder ihr nutzt dazu das Projekte Forum bei DelphiGL, oder aber (wenn ihr der Meinung seid , zuwenig für einen Projekte-Thread zu haben) ihr macht einen schönen Screenshot von eurem Projekt und sendet diesen an einen [[Team|Moderator]] (vorzugsweise an den der dafür zuständig ist) als &amp;quot;Image Of The Day&amp;quot;. Außerdem könnt ihr kleine Miniprojekte auch im Off-Topic Bereich zur Diskussion stellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Wer macht die Fragen für den DGL-Poll?&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Die Mitglieder von DelphiGL. In [http://www.delphigl.com/forum/viewtopic.php?t=4903 diesem Thread] im Forum könnt ihr Vorschläge zu Umfragen machen. Es bleibt den zuständigen Moderatoren überlassen, wann eine Umfrage an die Reihe kommt. Je interessanter die Frage, desto eher wird sie gestellt.&lt;br /&gt;
&lt;br /&gt;
==Mathematik==&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Wie berechne ich Schnittpunkte zwischen [...]?'''&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' [[Link#weitere_Links|Hier]] findet ihr das '''CompGeo''' Script von Herrn Dr. Pester (TU Chemnitz) als PDF welches sich mit der Mathematik die 3D APIs zu Grunde liegt beschäftigt.In diesem Script findet ihr verständlich erklärt, wie alle Schnittpunktberechnungen funktionieren. (Als Nachschlagewerk sehr zu empfehlen)&lt;br /&gt;
&lt;br /&gt;
==Delphi==&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Wie kann ich den Pfad meiner Anwendung bestimmen?'''&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Jedem Delphiprogramm (genau wie bei C/C++) werden beim Aufruf Parameter übergeben. Ein Parameter wird in jedem Fall übergeben und zwar der Pfad der Anwendung. Mit folgendem Aufruf könnt ihr euren Programmpfad extrahieren: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;var pfad : string;&lt;br /&gt;
begin&lt;br /&gt;
     pfad := ExtractFilePath(ParamStr(0));&lt;br /&gt;
     //[...]&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sonstiges==&lt;br /&gt;
:&amp;lt;u&amp;gt;'''F :''' Unter welcher Softwarelizens sollte ich meinen Code veröffentlichen?'''&amp;lt;/u&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:'''A :''' Prinzipiell ist erst einmal zu sagen, dass es eine gute Idee ist, überhaupt eine Lizenz anzugeben. Dies bietet deutlich mehr Rechtssicherheit als gar keine Angabe. Eine Empfehlung kann nicht generell vergeben werden, jedoch bietet [http://www.osscc.net/de/licenses.html |dieser Vergleich] einen Anhaltspunkt. Die dort empfohlenen Lizenzen '''Apache 2.0''' sowie '''CDDL'''(Quasinachfolger von Mozillas MPL) sollten in die Entscheidungsfindung einbezogen werden.&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Farbraum&amp;diff=25641</id>
		<title>Farbraum</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Farbraum&amp;diff=25641"/>
				<updated>2012-03-21T14:51:00Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Excellent}}&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
Farbräume dienen der Darstellung von Farben. Üblicherweise werden alle an Monitoren darstellbaren Farben durch 3 Grundtöne codiert. Durch verschieden starke Abstufungen dieser 3 Grundtöne entsteht der Eindruck von verschiedenen Farben. &lt;br /&gt;
&lt;br /&gt;
== Grundlegende Bildschirmkalibrierung ==&lt;br /&gt;
Um die dargestellten Farben an Computermonitoren optimal anzuzeigen, muss der Monitor zuerst kalibriert werden. Für unsere Zwecke soll eine einfache Kalibrierung ausreichen: In professionellem Umfeld kommt es nicht nur auf optimale Farbdarstellung an, sondern auch auf Farbechtheit. Um dies zu erreichen ist nicht ganz billiges Equipment notwendig. Wir wollen uns deshalb auf ein paar Hausmittel beschränken. Tatsächlich sind die meisten Computermonitore derart schlecht eingestellt, dass man bei weitem nicht von guter Farbdarstellung reden kann. Bevor wir also weitermachen, wollen wir diesen Umstand ändern. Zuerst muss der Monitor warm, also mindestens eine Stunde in Betrieb sein, bevor er eingestellt wird. &lt;br /&gt;
&lt;br /&gt;
=== Schwarzpunkt ===&lt;br /&gt;
Macht euer Zimmel dunkel. Alle Beleuchtung muss abgestellt werden. Eventuelle Rolläden werden bitte geschlossen. Stellen wir die Helligkeit des Monitors auf das Minimum und betrachten das untere Bild (wenn Du nach dem dunkelstellen nichts mehr sehen kannst, solltest du den folgenden Teil der Anleitung vorab durchlesen):&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Schwarzpunkt.png|center]]&lt;br /&gt;
&lt;br /&gt;
Stelle die Helligkeit soweit nach oben, bis das schwarze Bild gerade beginnt heller zu erscheinen. Ist dieser Punkt erreicht, dann stelle die Helligkeit wieder ein kleines Stück zurück, so dass es wieder komplett schwarz ist. Wenn das Bild partout nicht hell werden möchte, dann stelle die Helligkeit auf ein erträgliches Maß ( ein zu heller Monitor ist sehr unangenehm für die Augen. Wenn ihr beim längeren arbeiten Augenschmerzen oder Tränen in den Augen bekommt, dann stellt die Helligkeit unbedingt weiter zurück. Soviel ist der optimale Schwarzpunkt nicht wert. ). '''Achtung TFT Benutzer:''' Der Helligkeitsverlauf auf TFT Monitoren ist nicht konstant. Ich empfehle deshalb das Bild mittig zu plazieren.&lt;br /&gt;
&lt;br /&gt;
=== Kontrast und Gamma === &lt;br /&gt;
[[Bild:Farbräume_Kontrast.png|center]]&lt;br /&gt;
&lt;br /&gt;
Betrachtet den obigen Farbverlauf von Schwarz nach Weiß. Alle 24 Felder sind gleich groß. Der erste Übergang von Schwarz nach etwas Helligkeit sollte in etwa so stark ausfallen, wie der von Weiß auf die erste Abstufung. Regelt die Kontrasteinstellung eures Monitores solange bis beide Übergänge tatsächlich sichtbar sind und in etwa gleich stark ausfallen. Die anderen Felder sollten sich dann bereits halbwegs angepasst haben: Der Verlauf erscheint linear. Wenns noch nicht ganz passt, könnt ihr am Monitor den Gammawert noch ein wenig korrigieren ( wenn das der Monitor nicht bietet, benutzt die Einstellungsmöglichkeiten eures Grafikkartentreibers ). &lt;br /&gt;
&lt;br /&gt;
Falls ihr gerne noch etwas mehr Zeit investieren wollt, dann schaut doch mal bei [http://tom.via.de/Fotoseiten/Kalibrierung/kalibrierung.asp Tom Kurpjuweit] oder im [http://de.wikipedia.org/wiki/Gammakorrektur#Gamma-Testgrafik Wikipedia] vorbei. Auf diesen und auf vielen anderen Seiten im Netz wird beschrieben, wie man seinen Monitor einstellen kann - meine Anleitung gehört doch eher zu den primitiven. Falls das Bild des Monitors jetzt eher grau und milchig erscheint, seid ihr wahrscheinlich dem Problem erlegen, dass unsere Augen logarithmische Farbveränderungen bevorzugen und lineare Verläufe eher ungewohnt sind - dann ist es Zeit, sich eine etwas genauere Beschreibung zum Thema Bildschirm-justierung/kalibrierung durchzulesen.&lt;br /&gt;
&lt;br /&gt;
== Physikalische und biologische Grundlagen ==&lt;br /&gt;
Physikalisch besteht Licht aus elektromagnetischen Wellen. Diese haben verschiedene Wellenlaengen und je nach Zusammensetzung entsteht der eine oder der andere Farbeindruck.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Farbspektrum.png|center]] &lt;br /&gt;
&lt;br /&gt;
Das sichtbare Licht hat Wellenlängen zwichen 400nm (Violett) bis 750 nm (Rot). Bei kürzeren Wellenlängen unter 400nm kommen dann Ultra Violette, Röntgen und schließlich Gamma Strahlen. Auf der anderen Seite über 750 nm folgen Infrarot, Mikrowellen, Funkempfang (LW, MW, UKW, ...), usw. Auf dem Monitor lassen sich nicht alle Reinfarben darstellen, seht das obige Bild also eher als Eindruck statt als &amp;quot;so siehts aus&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Da unser Auge nur 3 Grundfarben unterscheiden kann ( manche Menschen können vermutlich sogar vier Farben* unterscheiden, wieder andere dagegen nur zwei - man beachte, dass für Menschen die vier Grundfarben unterscheiden können Monitorbilder nicht optimal sind und so ungewöhnliche Farben anzeigen ), kann man verschiedene Farbeindrücke nicht nur durch verschiedene Wellenlängen erzeugen,  sondern auch durch Mischen und Verlagern der Intensitäten einer Reihe von Grundfarben. So wird am Monitor bekanntlich (additiv) mit Rot, Grün und Blau, auf Printmedien üblicherweise (subtraktiv) mit Cyan, Gelb, Magenta und Schwarz gemischt. Man kann so zwar nicht jede sichtbare Farbe mischen, aber doch so viele, dass ein guter Farbeindruck entsteht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;small&amp;gt;1) Siehe [http://en.wikipedia.org/wiki/Tetrachromacy#Possibility_of_human_tetrachromats Tetrachromatie]. Bisher gibt es für deren Existenz keinen abschließenden Beweis, jedoch deuten einige Forschungsergebnisse auf eine solche Mutation hin.&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Verschiedene Farbräume ==&lt;br /&gt;
=== RGB ===&lt;br /&gt;
Der Rot, Grün, Blau Farbraum ist der Standardfarbraum für Computer und viele andere Bildschirmgeräte. Damit Farben aus anderen Farbräumen auf einem solchen Gerät dargestellt werden können, müssen sie immer zuerst auf diesen Farbraum umgerechnet werden. Er ist neben CMY einer der am wenigsten anschaulichen Farbräume. Farben lassen sich darin nur sehr schlecht identifizieren, sinnvolle Farbmanipulationen sind kaum möglich. Der Vorteil ist jedoch, dass die 3 Grundfarben etwa denen entsprechen, die auch auf unserer Netzhaut am besten erkannt werden - die Folge: höchst brilliante Farben, die einen großen Teil aller sichtbaren Farben abdecken. Den Farbraum kann man sich als dreidimensionalen Würfel am Nullpunkt vorstellen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_RGB.png|center]] &lt;br /&gt;
&lt;br /&gt;
Ausgehend vom Schwarz kann man nach rechts (Rot), nach oben (Grün) oder nach vorne (Blau) laufen und erhält immer hellere Farben. Schließlich gelangt man zum Weiß. Dazu gibt es auch eine weitere Veranschaulichung:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_RGB_additiv.png|center]] &lt;br /&gt;
&lt;br /&gt;
Das Bild beschreibt was pasiert, wenn man die Grundfarben miteinander mischt. In der weißen Mitte sind alle Farben aufgetragen ausserhalb nur eine oder jeweils zwei.&lt;br /&gt;
&lt;br /&gt;
=== CMY ===&lt;br /&gt;
Der Cyan, Magenta, Gelb Farbraum ist dem RGB Farbraum sehr ähnlich. Allerdings ist er für Printmedien konzipiert. Ist keine Farbe aufgetragen erhält man den Hintergrund: meist ein weißes Blatt Papier. Je mehr man von einer Farbe aufträgt, desto weniger scheinen die anderen Farben durch - trägt man also alle Farben auf, bleibt vom ursprünglichen Weiß nichts über und man erhält Schwarz. Da jedoch der Hintergrund im Allgemeinen nicht leuchtet, können Farben nie derart hell erscheinen, wie im RGB Farbraum auf Monitoren - man möge dies bei Anwendung beachten:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_CYM.png|center]] &lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_CYM_subtraktiv.png|center]]&lt;br /&gt;
&lt;br /&gt;
Zum Umrechnen von RGB in CMY ist nicht viel nötig:&lt;br /&gt;
 R = 1-C&lt;br /&gt;
 G = 1-M&lt;br /&gt;
 B = 1-Y&lt;br /&gt;
Und umgekehrt:&lt;br /&gt;
 C = 1 - R&lt;br /&gt;
 M = 1 - G&lt;br /&gt;
 Y = 1 - B&lt;br /&gt;
&lt;br /&gt;
=== CMYK ===&lt;br /&gt;
Der CMYK Farbraum entspricht im wesentlichen dem CMY Farbraum, mit dem Unterschied, dass zusätzlich Schwarz zum Beimischen zur Verfügung steht. Dies kann beim Drucken von sehr dunklen Tönen hilfreich sein und spart außerdem die teure Farbe. In manchen Fällen ist es sogar unumgänglich mit Schwarz zu drucken, wenn sich durch die anderen Druckfarben kein richtiges Schwarz erzeugen lässt (was häufig der Fall ist, u.a. auch bei den meisten Tintenstrahldruckern). &lt;br /&gt;
&lt;br /&gt;
Umrechnen CMYK nach CMY:&lt;br /&gt;
 CMY.C = C * ( 1 - K ) + K&lt;br /&gt;
 CMY.M = M * ( 1 - K ) + K&lt;br /&gt;
 CMY.Y = Y * ( 1 - K ) + K&lt;br /&gt;
&lt;br /&gt;
Umrechnen CMY nach CMYK&lt;br /&gt;
 CMYK.K = min(C,M,Y);&lt;br /&gt;
 if ( CMYK.K == 1 ) { &lt;br /&gt;
   CMYK.C = 0;   &lt;br /&gt;
   CMYK.M = 0;&lt;br /&gt;
   CMYK.Y = 0;&lt;br /&gt;
 } else {&lt;br /&gt;
   CMYK.C = (C-CMYK.K)/(1-CMYK.K);   &lt;br /&gt;
   CMYK.M = (M-CMYK.K)/(1-CMYK.K);   &lt;br /&gt;
   CMYK.Y = (Y-CMYK.K)/(1-CMYK.K);   &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== HSV ===&lt;br /&gt;
Der Hue, Saturation, Value (Farbton, Sättigung, Helligkeit) ist ein Farbraum, der sehr häufig im Einsatz ist. Da der Farbton als solches an einem Kanal zu identifizieren ist, werden viele Bildoperationen, die mit Farbe zu tun haben, in eben diesem Farbraum berechnet. Eine bildliche Vorstellung dieses Farbraums ist sehr viel einfacher, als die des RGB Farbraums. Wie also kann man sich ihn vorzustellen?&lt;br /&gt;
&lt;br /&gt;
Eine gute Möglichket ist als Zylinder. Die Unterseite ist schwarz. Bewegt man sich von der Mitte der Unterseite auf die gegenüberliegende Seite zu, wird es heller. Inmitten der hellen Seite ist Weiß. Geht man von dort nach außen, erhöht sich die Farbsättigung. Geht man dann auf dem Kreis spazieren, bleibt Helligkeit und Sättigung konstant, während sich die Farbe ändert. Dieses Prinzip wird bei vielen Farbauswahldialogen angewendet (Im Beispiel: Paint.NET) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_HSV_auswahl1.png|center]] &lt;br /&gt;
&lt;br /&gt;
Der Kreis stellt die farbige Oberseite des Zylinders dar. Von der Mitte nach außen also die Sättigung, den Umfang entlang die Farbe. Der Balken beschreibt die Helligkeit. Sehr beliebt ist auch die aufgefaltete Variante (MS-Windows Standard Farbauswahl Dialog):&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_HSV_auswahl2.png|center]]&lt;br /&gt;
&lt;br /&gt;
Im quadratischen Feld ist von Links nach Rechts die Farbe, von Unten nach Oben die Sättigung aufgetragen. Der Balken gibt wieder die Helligkeit an. &lt;br /&gt;
&lt;br /&gt;
Es existieren noch viele verschiedene Varianten, die alle mehr oder weniger identisch funktionieren. Wir wollen es bei diesen zwei Beispielen belassen.&lt;br /&gt;
&lt;br /&gt;
Die Farbreihenfolge wird gewöhnlich definiert als Rot, Magenta, Blau, Cyan, Grün, Gelb, Rot. Zwischen den Vollfarben wird linear interpoliert, was zu folgenden Umrechnungen führt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
        // Based on C Code in &amp;quot;Computer Graphics -- Principles and Practice,&amp;quot;&lt;br /&gt;
        // Foley et al, 1996, p. 593.&lt;br /&gt;
        public static RGB HSVToRGB(double h, double s, double v)&lt;br /&gt;
        {&lt;br /&gt;
            double f, hTemp, p,q,t;&lt;br /&gt;
            int i;&lt;br /&gt;
            RGB Result = new RGB();&lt;br /&gt;
            if (s == 0) {&lt;br /&gt;
                //Achromatic&lt;br /&gt;
                Result.R = v;&lt;br /&gt;
                Result.G = v;&lt;br /&gt;
                Result.B = v;&lt;br /&gt;
                return Result;&lt;br /&gt;
            }&lt;br /&gt;
            if (h &amp;lt; 0)&lt;br /&gt;
                h = Math.PI * 2 - h;&lt;br /&gt;
       &lt;br /&gt;
            if (h &amp;gt; 2 * Math.PI)&lt;br /&gt;
                h = h - Math.Truncate(1.0 / (Math.PI * 2) *h)* (Math.PI * 2);&lt;br /&gt;
         &lt;br /&gt;
            hTemp = h / (2*Math.PI / 6);&lt;br /&gt;
            i = (int) Math.Truncate(hTemp);  // largest integer &amp;lt;= h&lt;br /&gt;
            f = hTemp - i;                   // fractional part of h&lt;br /&gt;
     &lt;br /&gt;
            p = v * (1.0 - s);&lt;br /&gt;
            q = v * (1.0 - (s * f));&lt;br /&gt;
            t = v * (1.0 - (s * (1.0 - f)));&lt;br /&gt;
              &lt;br /&gt;
            switch (i) {&lt;br /&gt;
                case 0: { Result.R = v; Result.G = t; Result.B = p; break; }&lt;br /&gt;
                case 1: { Result.R = q; Result.G = v; Result.B = p; break; }&lt;br /&gt;
                case 2: { Result.R = p; Result.G = v; Result.B = t; break; }&lt;br /&gt;
                case 3: { Result.R = p; Result.G = q; Result.B = v; break; }&lt;br /&gt;
                case 4: { Result.R = t; Result.G = p; Result.B = v; break; }&lt;br /&gt;
                case 5: { Result.R = v; Result.G = p; Result.B = q; break; }&lt;br /&gt;
            }&lt;br /&gt;
            return Result;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // Based on C Code in &amp;quot;Computer Graphics -- Principles and Practice,&amp;quot;&lt;br /&gt;
        // Foley et al, 1996, p. 594.&lt;br /&gt;
        public static HSV RGBToHSV(double r, double g, double b)&lt;br /&gt;
        {&lt;br /&gt;
            HSV result = new HSV();&lt;br /&gt;
            double delta, min;&lt;br /&gt;
    &lt;br /&gt;
            min = Math.Min(r, Math.Min(g, b));&lt;br /&gt;
            result.v = Math.Max(r, Math.Max(g, b));&lt;br /&gt;
            delta = result.v - min;&lt;br /&gt;
        &lt;br /&gt;
            // Calculate saturation: saturation is 0 if r, g and b are all 0&lt;br /&gt;
            if (result.v == 0.0)&lt;br /&gt;
                result.s = 0;&lt;br /&gt;
            else&lt;br /&gt;
                result.s = delta / result.v;&lt;br /&gt;
   &lt;br /&gt;
            if (result.s == 0)&lt;br /&gt;
                result.h = 0; //Achromatic&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                if (r == result.v)&lt;br /&gt;
                {   //winkel zw. gelb/magenta&lt;br /&gt;
                    result.h = (g - b) / delta * (2 * Math.PI / 6.0);&lt;br /&gt;
                }&lt;br /&gt;
                else if (g == result.v)&lt;br /&gt;
                {    //zwischen cyan und gelb&lt;br /&gt;
                    result.h = (2 + (b - r) / delta) * (2 * Math.PI / 6.0);&lt;br /&gt;
                }&lt;br /&gt;
                else if (b == result.v)&lt;br /&gt;
                {// ...&lt;br /&gt;
                    result.h = (4 + (r - g) / delta) * (2 * Math.PI / 6.0);&lt;br /&gt;
                }&lt;br /&gt;
                if (result.h &amp;lt; 0)&lt;br /&gt;
                    result.h = result.h + 2 * Math.PI;&lt;br /&gt;
            }&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HSL ===&lt;br /&gt;
Der Hue Saturation Lightness Farbraum ist dem HSV Farbraum sehr ähnlich. Die Definition des Farbtons (Hue) ist identisch, lässt sich also auf die gleiche Weise berechnen. Die anderen Werte berechnen sich aus den RGB Werten wie folgt:&lt;br /&gt;
 MAX = max (R,G,B);&lt;br /&gt;
 MIN = min (R,G,B);&lt;br /&gt;
 &lt;br /&gt;
 L = (1.0/2.0) * (MAX + MIN);&lt;br /&gt;
 if (MIN == MAX) &lt;br /&gt;
 {&lt;br /&gt;
   S = 0&lt;br /&gt;
 } else if (L &amp;lt;= 1.0/2.0) {&lt;br /&gt;
   S = (MAX - MIN) / (2.0*L) &lt;br /&gt;
 } else {&lt;br /&gt;
   // entspr. Fall: L &amp;gt; 1.0/2.0&lt;br /&gt;
   S = (MAX - MIN) / (2.0-2.0*L)  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Man stellt sich den HSV Farbraum gerne als Doppelkonus vor. Die obere Spitze ist weiß, die untere schwarz. Am Rand des Bauches befinden sich die Vollfarben, die zur Mitte hin an Sättigung verlieren (Bild: Wikipedia [EN] von Alexandre Van de Sande. ):&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Color_Cones.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== LAB ===&lt;br /&gt;
Der LAB Farbraum ist einer an das menschliche Sehen angepasster Farbraum. Er umfasst alle vom Auge unterscheidbaren Farben und ein bisschen mehr. Er dient dazu Farbechtheit zu garantieren, was wichtig ist, wenn man z.B. am Bildschirm Bilder bearbeitet und diese am Ende drucken oder auf Fotopapier auslasern lassen möchte, so dass die Vorlage am Monitor dem entspricht, was auf dem Papier landen wird. Er dient dabei nur als Umrechnungsfarbraum, wobei auf die spezifischen Eigenschaften des jeweilig genutzen Gerätes geachtet werden muss.&lt;br /&gt;
&lt;br /&gt;
== Farbraumspaß ==&lt;br /&gt;
Wir wollen uns hier ein wenig mit den Möglichkeiten des HSV Farbraumes vertraut machen und einige Spielereien ausprobieren. &lt;br /&gt;
=== Vergrauen ===&lt;br /&gt;
Im HSV Farbraum kann man ein Bild sehr einfach in ein Graustufenbild umwandeln, indem man die Sättigung auf 0 stellt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Rothsee_farbig.png|center]]&lt;br /&gt;
[[Bild:Farbräume_Rothsee_grau.png|center]]&lt;br /&gt;
&lt;br /&gt;
Wenn einem reines S/W zu langweilig ist, kann man auch ein feste Sättigung und Farbe vorgeben, so dass das Bild eingefärbt wird ( S/W-Foto-Material verändert häufig mit dem Alter ein wenig seine Farbe oder ist von vornherein leicht farbig ). Wer Spaß an dieser Art der Bildbearbeitung findet, kann auch noch die Helligkeit anpassen - Schwarzweißfilme sind nach Wellenlängen unterschiedlich empfindlich. Blau wird auf dem positiv häufig heller wiedergegeben als grün, welches wiederum heller als rot erscheint. Viel Spaß beim ausprobieren (als kleiner Tipp: Schaut doch noch mal nach oben den Farbkreis von Paint.Net an und vergleicht ihn mit dem Bild der Wellenlängen - klar wie man das am einfachsten macht?).&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Rothsee_blackwhitestyle.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Farbkurven ===&lt;br /&gt;
Wer sich einmal mit einem Bildbearbeitungsprogramm auseinandergesetzt hat, wird sie kennen, die Dialoge zum Verändern der Farbkurven. Die Kurven stellen eine Verschiebungsfunktion dar: Hat man z.B. ein Farbkurve für den roten Farbkanal festgelegt, so beschreibt die Farbkurve f an einer Stelle i den Wert, den ein Punkte im roten Farbkanal hat, wenn er vorher den Wert i hatte, also:&lt;br /&gt;
 Punkt.rot = f(Punkt.rot);&lt;br /&gt;
im Bild: GIMP:&lt;br /&gt;
[[Bild:Farbräume_GIMPColorcurvesdialog.png|center]]&lt;br /&gt;
Diese Idee wollen wir uns zu Eigen machen - so ist es im HSV Farbraum nur zu konsequent, nicht Rot/Grün/Blau, bzw. Cyan/Magenta/Gelb sondern die Hue, Saturation und Value Werte zu manipulieren. Und die Sache ein wenig auf die Spitze zu treiben, wollen wir uns nicht nur mit Hue/Hue und den 2 anderen Kurven beschäftigen, sondern auch mit gemischten, bei denen sich anhand der Farbe die Helligkeit oder Sättigung ändert. Vieles ist hier denkbar.&lt;br /&gt;
&lt;br /&gt;
Um es realisieren zu können, benötigt man zuerst einmal eine eigene Dialogbox, die das Bearbeiten von (Farb-)Kurven zulässt. Im wesentlichen dürfte das niemanden hier überfordern - ich empfehle folgende Szenerie: Die Kurve wird mithilfe von Spline-[[Interpolation]] erzeugt. Die Menge der Stützstellen ist im wesentlichen beliebig, für einige Kurven ist es jedoch wichtig, nicht nur natürliche, sondern auch periodische Kurven erzeugen zu können. Genauere Informationen hierzu finden sich in den Literaturangaben.&lt;br /&gt;
&lt;br /&gt;
Die einfachste Art der Kurven ist wie gesagt die, die sich selber beeinflussen. So lassen sich leicht Farben durch andere Farben tauschen, ohne den Rest der Farben zu beeinflussen. Man kann natürlich auch bestimmte Sättigungen hervorheben (also Sättigung/Sättigung statt bei Farben Hue/Hue) oder ähnliches. Als Beispiel wird der Hue-Bereich von Gelb in den von Rot verschoben. Durch feine Abstimmung lässt sich erreichen, dass andere Farben sich dabei nicht verändern (Diesen Effekt kann man noch leicht in Photoshop erreichen, man muss jedoch für jede Farbe getrennt vorgehen, falls man verschiedene Farben verändern möchte: Image/Adjustmennts/Hue-Saturations . Wir können dagegen leicht mehrere Farben auf einmal austauschen.).&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Hue_Hue_mapping.png|center]]&lt;br /&gt;
&lt;br /&gt;
Als Alternative noch eine Sättigung/Sättigung Variante des obigen Bildes. Links wurde die 20. Wurzel aus der Sättigung gezogen, rechts wurde die Sättigung zur 4. Potenz erhoben (dies entspricht einer Erniedrigung bzw. Erhöhung des Sättigungkontrastes). Die einstellbaren Kurven lassen sich dazu natürlich genauso benutzen, aber so sparen wir uns ein paar Bilder ;-)&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Sat_Sat_mapping.png|center]]&lt;br /&gt;
&lt;br /&gt;
Nun wollen wir einmal eine Value/Hue Variante betrachten. Ziel ist es, ein Pixel anhand seines Value den Hue weiterzudrehen. Man trägt im Kurvendialog wie folgt an: In Y-Richtung variiert die Hue, in X-Richtung ist Value von 0 bis 1 angetragen. Zu einer bestimmten Value soll also der Hue um einen bestimmten Winkel weitergedreht werden - vorwärts und rückwärtsdrehen sollte möglich sein. Rechnen könnte man dann:&lt;br /&gt;
&lt;br /&gt;
 Pixel.Hue = Pixel.Hue + Kurve(Pixel.Value);&lt;br /&gt;
&lt;br /&gt;
Da Pixel.Hue dadurch auch negative oder zu große Werte annehmen kann, sollte man sie wieder auf den Berech 0 bis 2*Pi zurückrechnen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Farbräume_Val_Hue_mapping.png|center]]&lt;br /&gt;
&lt;br /&gt;
Im obigen Bild ist die zugrundeliegende Kurve die [http://de.wikipedia.org/wiki/Glockenkurve Gaussche Glockenkurve] mit sigma = 0.29, mu = 0.9, d.h. also, dass bei niedrigen value Werten im wesentlichen keine Veränderung des Hue passiert. Je heller die Szene jedoch wird, desto stärker verschiebt sich der Farbton. Da die Lichtquelle im Hintergrund des Fotos ist, verändern sich die Farben stärker, je weiter hinten sich die Luftballons befinden.&lt;br /&gt;
&lt;br /&gt;
Es lassen sich noch einige weitere Varianten vorstellen, als die, die hier gezeigt wurden. So könnte man anhand einer Hue/Sat Kurve bestimmte Farben vergrauen lassen und andere hervorheben - der Effekt ist sicherlich nicht gänzlich unbekannt. In der Fotografie wird gerne entsprechend manipuliert: Man stelle sich ein Mädchen vor, das eine rote Rose hält. Alle Farben sind grau, nur die Blüte der Rose ist rot - mit Hue/Sat Kurven ist das wirklich sehr leicht zu erreichen.&lt;br /&gt;
&lt;br /&gt;
== Literatur ==&lt;br /&gt;
* [http://www.efg2.com/Lab/Graphics/Colors/index.html Earl F. Glynn II: efg's Palettes and Colors Lab]&lt;br /&gt;
* [http://www.efg2.com/Lab/Library/Color/index.html Earl F. Glynn II: efg's Color Reference Library]&lt;br /&gt;
* [http://www.midnightkite.com/color.html Dan Bruton: Color Science]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Color_model Englische Wikipedia: Color Models. Viele informationen, Veranschaulichungen, Umrechnungsformeln]&lt;br /&gt;
* [http://www.adhocconference.com/cgi-bin/blosxom.cgi/PastShows/MacHack16/2001_papers.html Darrin Cardani: Adventures in HSV Space (als PDF)]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Spline-Interpolation Wikipedia: Spline interpolation]&lt;br /&gt;
* Bronstein, Semendjajew, Musiol, Mühlig: Taschenbuch der Mathematik. 5 Auflage. S.955: 19.7.1 Kubische Splines&lt;br /&gt;
* [http://www.arndt-bruenner.de/mathe/scripts/kubspline.htm Arndt Brünner: Kubische Splines]&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Raytracing_-_Grundlagen_II&amp;diff=25640</id>
		<title>Tutorial Raytracing - Grundlagen II</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Raytracing_-_Grundlagen_II&amp;diff=25640"/>
				<updated>2012-03-21T14:50:39Z</updated>
		
		<summary type="html">&lt;p&gt;Openglerf: Ausserdem -&amp;gt; Außerdem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Raytracing Grundlagen II =&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_teaser.jpg|center]]&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Und weiter geht es mit unsem Raytracing Tutorial. Wir wollen unseren Raytracer nun langsam aber sicher soweit bekommen, dass sich damit etwas ansehnlichere Bilder erzeugen lassen. Wer das [[Tutorial_Raytracing_-_Grundlagen_I|vorangehende Tutorial]] nicht gelesen hat, sollte dies am besten gleich tun - ich will ja nicht alles neu erklären. Womit werden wir uns denn heute beschäftigen? Zuerst werden wir ein erweiterbares Objektmodell für alle Objekte planen und überlegen. Dann wollen wir uns ein wenig mit Phong-Lighting beschäftigen und einige Gedanken in Richtung Transformationen verschwenden. Mit diesem Plan sind wir, so denke ich, erstmal gut beschäftigt.&lt;br /&gt;
&lt;br /&gt;
== Ein schönes Basisobjekt ==&lt;br /&gt;
Wir wollen die Objekte in unsem Raytracer möglichst gleich behandeln können, so dass der eigentliche Raytracing Algorithmus ohne jegliches wissen über die Struktur der Objekte arbeiten kann. Sprich: Wir definieren ein Basisobjekt, von dem anschließend alle weiteren Objekte abgeleitet werden. Was also soll dieses Objekt an Methoden und Eigenschaften zur Verfügung stellen? Jedes Objekt hat sicherlich eine Position, sowie gewissen Materialeigenschaften, die dem Objekt zugewiesen werden. Auch soll das Objekt sauber mit Transformationen umgehen können. Und was natürlich ganz wichtig ist: Wir brauchen eine Methode die prüft, ob sich das Objekt mit dem Strahl schneidet. Über einige dieser Dinge haben wir uns noch keine Gedanken gemacht, entsprechend sollen hierfür nur leere Dummyklassen und Methoden zum Einsatz kommen, die wir erst später realisieren. Damit es nicht vergessen wird: Es ist auch sinnvoll Vater-Kindbeziehungen zu haben um später zusammengesetzte Objekte definieren zu können. Das klingt alles etwas wild, artet in einer großen Menge Code aus, ist aber eigentlich gar nicht so schlimm, wei es sich anhört:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;    /// General Raytracing object in a tracer. All traceable objects must be derivates&lt;br /&gt;
    public abstract class ObjectBase&lt;br /&gt;
    {&lt;br /&gt;
        #region Positioning Variables&lt;br /&gt;
        &lt;br /&gt;
        private Vertex3 pos = new Vertex3();&lt;br /&gt;
        /// The Position of the Object in parental Space&lt;br /&gt;
        public Vertex3 Position&lt;br /&gt;
        {&lt;br /&gt;
            get { return pos; }&lt;br /&gt;
            set { pos = value; /*InvalidateBoundings(true);*/ }&lt;br /&gt;
            // Anm.: InvalidateBoundings brauchen wir jetzt noch &lt;br /&gt;
            // nicht. Wenn man allerdings mit Bounding-Volumes&lt;br /&gt;
            // zu arbeiten beginnt, wird man entsprechende&lt;br /&gt;
            // Funktionalität benötigen. Vorerst gilt: Forget it.&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        private ILinearTransformation ptransformation;&lt;br /&gt;
        /// The Transformation applied to the object&lt;br /&gt;
        public ILinearTransformation Transformation&lt;br /&gt;
        {&lt;br /&gt;
            get&lt;br /&gt;
            {&lt;br /&gt;
                return ptransformation;&lt;br /&gt;
            }&lt;br /&gt;
            set&lt;br /&gt;
            {&lt;br /&gt;
                ptransformation = value;&lt;br /&gt;
                //InvalidateBoundigs(true);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&lt;br /&gt;
        #region Material&lt;br /&gt;
        private Material objMaterial = new StandardMaterial();&lt;br /&gt;
        /// Material assigned to object&lt;br /&gt;
        public Material ObjectMaterial&lt;br /&gt;
        {&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&lt;br /&gt;
        #region Parenting&lt;br /&gt;
        // The parental object&lt;br /&gt;
        private ObjectBase fParent;&lt;br /&gt;
&lt;br /&gt;
        /// The Parent of the object&lt;br /&gt;
        public ObjectBase Parent&lt;br /&gt;
        {&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&lt;br /&gt;
        #region Trans Space Functions&lt;br /&gt;
        public virtual Vertex3 TransSpaceWorldToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Ray TransSpaceWorldToObject(Ray r) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpacePointWorldToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpacePointParentToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Ray TransSpaceParentToObject(Ray r) &lt;br /&gt;
        {&lt;br /&gt;
            Ray ray = r;&lt;br /&gt;
            ray.o -= pos;&lt;br /&gt;
            return ray;&lt;br /&gt;
        }&lt;br /&gt;
        public virtual Vertex3 TransSpaceParentToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpaceObjectToWorld(Vertex3 v) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpacePointObjectToWorld(Vertex3 v) {...}&lt;br /&gt;
        #endregion&lt;br /&gt;
        &lt;br /&gt;
        #region Intersection Tests&lt;br /&gt;
        /// Calculates the first visible intersection. Returns values smaller&lt;br /&gt;
        /// equal zero if there is no intersection. &lt;br /&gt;
        /// param name=&amp;quot;rs&amp;quot;: Global rendersettings&lt;br /&gt;
        /// param name=&amp;quot;ray&amp;quot;: the ray to test for intersection&lt;br /&gt;
        /// param name=&amp;quot;raymindist&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;raymaxdist&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;calcNormals&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;calcTextureCoordinates&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;info&amp;quot;:&lt;br /&gt;
        public abstract int Intersect(RenderSettings rs, Ray ray, double raymindist, double raymaxdist,&lt;br /&gt;
            bool calcNormals, bool calcTextureCoordinates, ref IntersectionInfo info);&lt;br /&gt;
        #endregion&lt;br /&gt;
    }        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Das schaut jetzt tatsächlich etwas wild aus, aber keine Angst. Wir werden das alles der Reihe nach mit Leben füllen. Die Trans-Space-Funktionen werden wir anschließend mit Leben füllen - nur TransSpaceParentToObject kann gleich bestückt werden (wir werden das aber später erweitern müssen). Sie soll Strahlen aus dem Eltern-Raum in den lokalen Raum überführen - für die meisten Objekte bedeutet dies: Die globalen Koordinaten werden in lokale übersetzt, so dass sich unser Objekt genau im Zentrum des Geschehens, d.h. bei (0,0,0), befindet und wir uns dann nie wieder über die Position des Objektes Gedanken machen müssen.&lt;br /&gt;
&lt;br /&gt;
Einen Blick sind auch die Parameter von Intersect wert. rs beschreibt globale Einstellungen des Renderers. Darin könnte man z.B. festlegen, ob Schatten berechnet werden sollen oder nicht. Ihr könnt hier im wesentlichen spazieren führen was ihr wollt, aber diese Option zu haben ist jedenfalls nicht verkehrt. ray dürfte klar sein.&lt;br /&gt;
Dies wird ein Strahl sein, der jeweils in elterlichen Koordinaten gegeben ist, also mithilfe von TransSpaceParentToObject in lokale Koordinaten umgerechnet werden kann. raymindist und raymaxdist beschreiben jeweils Bereich des Strahles, in dem wir nach Überschneidungen suchen sollen - haben wir es mit einem numerisch zu berechnenden Objekt zu tun, kann diese Information bereits sehr viel Geschwindigkeit ausmachen. Beim Schnitt mit Kugeln ist die Sache dagegen weniger wichtig. Essenziell ist, dass beim Aufruf von Intersect sichergestellt sein muss, dass nur dann positive Rückmeldung gemacht wird, wenn die Überschneidung an einer Stelle des Strahles zu finden ist, die größer gleich raymindist ist: Darauf sollte man sich verlassen können. calcNormals und calcTextureCoordinates beschreibt, ob beim Überschneidungstest Informationen über Flächennormalen bzw. Texturkoordinaten erzeugt werden sollen: Bei manchen Objekten ist auch diese Information nur kostspielig zu bekommen und wir wollen es deshalb optional halten. Es bleibt noch der Call by Reference Parameter info. Darin sollen genauere Informationen bezüglich des Schnittes gespeichert werden - etwa lokale Farben, Material, Texturkoordinaten, Schnittposition, etc. (Die Schnittposition könnte man auch direkt zurückgeben, also den Rückgabewert durch einen Float-Typ wie double ersetzen. Seis drum)&lt;br /&gt;
&lt;br /&gt;
Noch schnell ein kleiner Blick in eine mögliche Definition der IntersectionInfo. Darin befindet sich nichts anderes, als wie das, was ich gerade beschrieben habe. Also keine Überraschungen ;-)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;    public struct IntersectionInfo&lt;br /&gt;
    {&lt;br /&gt;
        /// Position on ray where the cut occured&lt;br /&gt;
        public double rayPosition;&lt;br /&gt;
        /// Normal of surface at cut position&lt;br /&gt;
        public Vertex3 normal;&lt;br /&gt;
        /// Texture coordinates&lt;br /&gt;
        public Vertex3 texture;&lt;br /&gt;
        /// Material of surface at intersection position&lt;br /&gt;
        public Material material;&lt;br /&gt;
        /// The local color of the intersection. This must be optional&lt;br /&gt;
        /// for all materials!!! Some Objects may always return black here.&lt;br /&gt;
        public Color localColor;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Transformationen ==&lt;br /&gt;
Wir wollen uns nun um Transformationen kümmern. Was also sind Transformationen? Wer mit OpenGl vertraut ist, kennt sie sie ganz gut: Es handelt sich um genau das, was man mit den Funktionen [[glTranslate]], [[glRotate]], [[glScale]], usw. bewirken kann. Verschiebungen haben wir bereits durch die Position des Objektes abgehakt, wir können uns hier also auf Dinge wie Scheerungen, Rotationen usw. beschränken. Wer Nachholbedarf in diesen Themen hat, der sollte sich jetzt hier darum kümmern, dieses Defizit etwas zu mildern. Da DelphiGl aber schon eine Weile existiert, finden sich fast alle nötigen Informationen in Tutorias oder Wiki-Artikeln: [[Matrix]],&lt;br /&gt;
[[Tutorial_Nachsitzen|Nachsitzen]], [[Tutorial_Matrix2|Matrix 2]], [[Quaternion]]. Auch die Wikipedia ist hier in der [http://de.wikipedia.org/wiki/Kategorie:Lineare_Algebra Kategorie Lineare Algebra] gut ausgestattet, um weitere Informationen einzuholen.&lt;br /&gt;
Wer hoch in den Code des Basis-Objektes schaut, dem wird auffallen, dass Transformationen durch das Interface ILinearTransformation definiert sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    /// Defines a linear Trafo&lt;br /&gt;
    public interface ILinearTransformation&lt;br /&gt;
    {&lt;br /&gt;
        /// Applys the Trafo to v&lt;br /&gt;
        Vertex3 Apply(Vertex3 v);&lt;br /&gt;
        /// Applys the inverse Trafo to v&lt;br /&gt;
        Vertex3 ApplyInverse(Vertex3 v);&lt;br /&gt;
&lt;br /&gt;
        /// Conversion of the Trafo to Matrix3x3&lt;br /&gt;
        Matrix3x3 ConvertTo3x3();&lt;br /&gt;
        /// Conversion of the Inverse Trafo to Matrix3x3 &lt;br /&gt;
        Matrix3x3 ConvertInverseTo3x3();&lt;br /&gt;
&lt;br /&gt;
        /// Right Mulltiplication of factor with this to a new, returned ILinearTransformation.&lt;br /&gt;
        /// Probably the trafos are converted to a LinearTransformationMatrix, but if both&lt;br /&gt;
        /// trafos are of the same type, its a good idea to multiply them together.&lt;br /&gt;
        ILinearTransformation MultiplyWithLinear(ILinearTransformation factor);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So kann man ohne weiteres Quaternionen und Matrizen wild nebeneinander verwenden. Mit der Methode MultiplyWithLinear kann man dann auch verschiedene Multiplikationen miteinander verknüpfen. So kann man Quaternionen einfach mit Quaternionen multiplizieren und gemischtes, wenn etwa Quaternionen mit Matrizen multipliziert werden, in Matrizen umwandeln:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
        #region ILinearTransformation Members&lt;br /&gt;
&lt;br /&gt;
        /// Rotates a Vertex3 through the Quaternion - this should be normalized!&lt;br /&gt;
        public Vertex3 Apply(Vertex3 v) {...}&lt;br /&gt;
        /// Rotates a Vertex3 against the Quaternion. A normalized Quaternion is assumed!&lt;br /&gt;
        public Vertex3 ApplyInverse(Vertex3 v) {...}&lt;br /&gt;
&lt;br /&gt;
        /// Converts the Quaternion to a 3x3 Matrix&lt;br /&gt;
        public Matrix3x3 ConvertTo3x3()&lt;br /&gt;
        {&lt;br /&gt;
            Matrix3x3 result = new Matrix3x3();&lt;br /&gt;
            result.sp0 = Apply(new Vertex3(1.0, 0.0, 0.0));&lt;br /&gt;
            result.sp1 = Apply(new Vertex3(0.0, 1.0, 0.0));&lt;br /&gt;
            result.sp2 = Apply(new Vertex3(0.0, 0.0, 1.0));&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /// Converts the Inverse Quaternion to a 3x3 Matrix&lt;br /&gt;
        public Matrix3x3 ConvertInverseTo3x3()&lt;br /&gt;
        {&lt;br /&gt;
            Matrix3x3 result = new Matrix3x3();&lt;br /&gt;
            result.sp0 = ApplyInverse(new Vertex3(1.0, 0.0, 0.0));&lt;br /&gt;
            result.sp1 = ApplyInverse(new Vertex3(0.0, 1.0, 0.0));&lt;br /&gt;
            result.sp2 = ApplyInverse(new Vertex3(0.0, 0.0, 1.0));&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /// Multiply the Quaternion with another trafo. If its a Quaternion, this and factor&lt;br /&gt;
        /// will be multiplied together, otherwise a LinearTransformationMatrix is generated.&lt;br /&gt;
        public ILinearTransformation MultiplyWithLinear(ILinearTransformation factor)&lt;br /&gt;
        {&lt;br /&gt;
            if (factor == null) return this;&lt;br /&gt;
            Quaternion fac = factor as Quaternion;&lt;br /&gt;
            if (fac != null)&lt;br /&gt;
            {&lt;br /&gt;
                return Multiply(fac);&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                // factor is not wenn known to us, we need a new LinearTransformationMatrix&lt;br /&gt;
                Matrix3x3 lin = ConvertTo3x3() * factor.ConvertTo3x3();&lt;br /&gt;
                Matrix3x3 inv = factor.ConvertInverseTo3x3() * ConvertInverseTo3x3();&lt;br /&gt;
                return new LinearTransformationMatrix(lin, inv, factor.Operator2Norm() * Operator2Norm());&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
An diesem Beispiel aus meinem Quaternioncode kann man folgendes sehen: Die Funktionen ConvertTo3x3 und ConvertInverseTo3x3 berechnen jeweils die zum Quaternion gehörenden, äquivalenten Matrizen ( Man erinnere sich an den Satz, den ich bereits im Nachhilfe Tutorial zitiert habe: Die Spalten sp&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; der Matrix sind die Bilder der Einheitsvektoren. Dann dürfte sofort klar sein, was hier passiert ). In MultiplyWithLinear wird dann einfach geprüft, ob die Transformation mit der rechts multipliziert wird, ein Quaternion ist. Dann wird einfach Quaternion-Multiplikation durchgeführt, ansonsten werden sowohl der Faktor als auch das betrachtete Quaternion in 3x3 Matrizen umgewandelt und in einer LinearTransformationMatrix abgelegt - welches natürlich ILinearTransformation implementiert und immer die Transformationsmatrix und ihr Inverses bereithält.&lt;br /&gt;
&lt;br /&gt;
Damit ihr nicht ewig rumrechnen müsst (es handelt sich nämlich um eine schrecklich langwierige und ekelige Rechnerei: Ich habe etwa 2 Stunden gebraucht, bis das Ergebnis endlich fehlerfrei und brauchbar auf 2 DIN-A4 Blättern verteilt da stand), wenn ihr Quaternionen implementiert noch ein paar kleine Methoden des Quaternions. Den Rest werdet ihr dann wohl aus dem [[Quaternion|Quaternionen-Artikel]] selbst in kurzer Zeit zusammenstöpseln können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        // &amp;quot;Coordinates&amp;quot; of the Quaternion. &lt;br /&gt;
        // coords[0] is the real component, coords[1] the i comp., ...&lt;br /&gt;
        private double[] coords = new double[4];&lt;br /&gt;
&lt;br /&gt;
        /// Creates a rotation Quaternion&lt;br /&gt;
        public Quaternion(double alpha, Vertex3 rotAxis)&lt;br /&gt;
        {&lt;br /&gt;
            alpha = (2.0*Math.PI/(360.0*2.0))* alpha;&lt;br /&gt;
&lt;br /&gt;
            coords[0] = 1.0;&lt;br /&gt;
            if (rotAxis.Magnitude &amp;lt; double.Epsilon)&lt;br /&gt;
            {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            rotAxis.Normalize();&lt;br /&gt;
            double c, s;&lt;br /&gt;
            c = Math.Cos(alpha); s = Math.Sin(alpha);&lt;br /&gt;
            coords[0] = c; coords[1] = rotAxis[0] * s; &lt;br /&gt;
            coords[2] = rotAxis[1] * s; coords[3] = rotAxis[2] * s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /// Rotates a Vertex3 through the Quaternion - this should be normalized!&lt;br /&gt;
        public Vertex3 Apply(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            Vertex3 result = new Vertex3();&lt;br /&gt;
            double v0 = v[0]; double v1 = v[1]; double v2 = v[2];&lt;br /&gt;
            double a00 = coords[0] * coords[0];&lt;br /&gt;
            double a01 = coords[0] * coords[1];&lt;br /&gt;
            double a02 = coords[0] * coords[2];&lt;br /&gt;
            double a03 = coords[0] * coords[3];&lt;br /&gt;
            double a11 = coords[1] * coords[1];&lt;br /&gt;
            double a12 = coords[1] * coords[2];&lt;br /&gt;
            double a13 = coords[1] * coords[3];&lt;br /&gt;
            double a22 = coords[2] * coords[2];&lt;br /&gt;
            double a23 = coords[2] * coords[3];&lt;br /&gt;
            double a33 = coords[3] * coords[3];&lt;br /&gt;
            result[0] = v0 * (+a00 + a11 - a22 - a33)&lt;br /&gt;
                + 2 * (a12 * v1 + a13 * v2 + a02 * v2 - a03 * v1);&lt;br /&gt;
            result[1] = v1 * (+a00 - a11 + a22 - a33)&lt;br /&gt;
                + 2 * (a12 * v0 + a23 * v2 + a03 * v0 - a01 * v2);&lt;br /&gt;
            result[2] = v2 * (+a00 - a11 - a22 + a33)&lt;br /&gt;
                + 2 * (a13 * v0 + a23 * v1 - a02 * v0 + a01 * v1);&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
        /// Rotates a Vertex3 against the Quaternion. A normalized Quaternion is assumed!&lt;br /&gt;
        public Vertex3 ApplyInverse(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            Vertex3 result = new Vertex3();&lt;br /&gt;
            double v0 = v[0];&lt;br /&gt;
            double v1 = v[1];&lt;br /&gt;
            double v2 = v[2];&lt;br /&gt;
            // Like Apply. We only konjugate the im. factors&lt;br /&gt;
            double a00 = coords[0] * coords[0];&lt;br /&gt;
            double a01 = -coords[0] * coords[1];&lt;br /&gt;
            double a02 = -coords[0] * coords[2];&lt;br /&gt;
            double a03 = -coords[0] * coords[3];&lt;br /&gt;
            double a11 = +coords[1] * coords[1];&lt;br /&gt;
            double a12 = +coords[1] * coords[2];&lt;br /&gt;
            double a13 = +coords[1] * coords[3];&lt;br /&gt;
            double a22 = +coords[2] * coords[2];&lt;br /&gt;
            double a23 = +coords[2] * coords[3];&lt;br /&gt;
            double a33 = +coords[3] * coords[3];&lt;br /&gt;
            result[0] = v0 * (+a00 + a11 - a22 - a33)&lt;br /&gt;
                + 2 * (a12 * v1 + a13 * v2 + a02 * v2 - a03 * v1);&lt;br /&gt;
            result[1] = v1 * (+a00 - a11 + a22 - a33) &lt;br /&gt;
                + 2 * (a12 * v0 + a23 * v2 + a03 * v0 - a01 * v2);&lt;br /&gt;
            result[2] = v2 * (+a00 - a11 - a22 + a33) &lt;br /&gt;
                + 2 * (a13 * v0 + a23 * v1 - a02 * v0 + a01 * v1);&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Wer ein Quaternion mithilfe des angegebenen Konstruktors erstellt, erhält ein Rotationsquaternion der Norm 1. Genau das, was für die Funktionen Apply und ApplyInverse notwendig ist, damit sie das tun, was sie sollen. Damit soll ersteinmal der Faulheit beim Rechnen und dem Copy&amp;amp;Paste genüge getan sein. Und wehe ich entdecke irgendwann Raytracer, die Objekte nur rotieren können statt beliebige [[Matrix|Matrizen]] zu vertragen ;-) Am Ende bleibt es natürlich euch überlassen. Wenn ihr wollt, könnt ihr all das auch allein durch Matrizen implementieren und euch den Umweg über das Quaternion ersparen - allerdings sieht man einem Quaternion schneller an was es bewirkt, als einer Matrix.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir einen kleinen Ausflug in Richtung Quaternionen und Transformationen hinter uns gebracht haben, könnte man hoffen, dass wir jetzt endlich mit dem abstrakten Kram aufhören und wir bald mal wieder ein paar neue Bilder zu Gesicht bekommen. Soweit ist es leider noch nicht. Ich möchte zwischendrin den Schlachtplan für die nächsten Minuten bekannt geben: Wir werden jetzt die Punkte in den Trans-Space-Funktionen der Basisklasse füllen, um uns dann dem Licht durch Phong-Lighting über den Umweg der Normalen zu widmen. Beginnen wir also mit der Funktion TransSpaceParentToObject, welche Strahlen des elterlichen Raumes in den lokalen Raum transformieren soll. Wenn man nun an die Kameraanalogie denkt, wie sie etwa im [[Tutorial_Kamera1|Kamera Tutorial]] beschrieben ist, dann wissen wir, dass wir die auf das Objekt angewendete Transformation einfach nur umkehren müssen. Denkt man dann noch daran, dass wir erreichen wollen, dass das Objekt im lokalen Raum am Ursprung befinden soll, ist die Implementation schnell naheliegend: Den Ursprung des Strahles müssen wir erst um die Position verschieben und dann invers transformieren. Bei der Richtung genügt es, diese invers zu transformieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
        public virtual Ray TransSpaceParentToObject(Ray r)&lt;br /&gt;
        {&lt;br /&gt;
            Ray ray = r;&lt;br /&gt;
            ray.Origin -= pos;&lt;br /&gt;
            if (ptransformation != null)&lt;br /&gt;
            {&lt;br /&gt;
                ray.Origin = ptransformation.ApplyInverse(ray.Origin);&lt;br /&gt;
                ray.Direction = ptransformation.ApplyInverse(ray.Direction);&lt;br /&gt;
            }&lt;br /&gt;
            return ray;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei dieser Überlegung fallen auch gleich die Funktionen TransSpacePointParentToObject, welche einen Punkt in die lokalen Koordinaten überträgt und die Entsprechende Funktion TransSpaceParentToObject für Richtungen ab. Das ganze können wir natürlich auch in die andere Richtung machen: Bislang ist mir aber noch kein Grund eingefallen, dies zu tun. Wichtig dagegen ist es, Richtungen in Weltkoordinaten umzurechnen, da wir dies für die Normalen später benötigen werden. Dies erreichen wir leicht, wenn wir ausnutzen, dass Objekte immer ihre Eltern kennen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        public virtual Vertex3 TransSpaceObjectToWorld(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            if (ptransformation != null)&lt;br /&gt;
            {&lt;br /&gt;
                v = ptransformation.Apply(v);&lt;br /&gt;
            }&lt;br /&gt;
            if (fParent != null)&lt;br /&gt;
            {&lt;br /&gt;
                v = fParent.TransSpaceObjectToWorld(v);&lt;br /&gt;
            }&lt;br /&gt;
            return v;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die entsprechende Funktion für Punkte solltet ihr der Übung halber selbst schreiben. Mit den genannten Zweien kommen wir auf jeden Fall erst einmal aus - ich bin mir gar nicht sicher, ob in meinem eigenen Raytracer je die Anderen zum Einsatz gekommen sind. Naja, es schadet jedenfalls nicht, wenn sie da sind.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_RaytracingII_spherenormals.jpg|right|framed|Visualisierung der Normalen]]&lt;br /&gt;
Um nun mit dem Licht weiter machen zu können, müssen wir die Intersect-Funktionen für Kugeln und Ebenen um Normalenerzeugung erweitern. Wir dürfen nicht vergessen, diese dann in den World-Space zu transformieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        /// Calculates the World-Space normal for a surface point&lt;br /&gt;
        protected Vertex3 CalcNormal(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            Vertex3 normal = TransSpaceObjectToWorld(v);&lt;br /&gt;
            normal.Normalize();&lt;br /&gt;
            return normal;&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        public override int Intersect(RenderSettings rs, Ray ray, &lt;br /&gt;
            double raymindist, double raymaxdist, bool calcNormals, &lt;br /&gt;
            bool calcTextureCoordinates, ref IntersectionInfo info)&lt;br /&gt;
        {&lt;br /&gt;
            Ray osray = TransSpaceParentToObject(ray);&lt;br /&gt;
&lt;br /&gt;
            double a, b, c;&lt;br /&gt;
            a = osray.d.DotDot; b = 2 * (osray.o * osray.d);&lt;br /&gt;
            c = osray.o.DotDot - sphereRadius * sphereRadius;&lt;br /&gt;
&lt;br /&gt;
            double t1, t2;&lt;br /&gt;
            int roots = GeoMath.CalcQuadricRoots(a, b, c, out t1, out t2);&lt;br /&gt;
&lt;br /&gt;
            // roots are sorted so check only for tr2&lt;br /&gt;
            if (roots &amp;gt; 0 &amp;amp;&amp;amp; t2 &amp;gt;= raymindist &amp;amp;&amp;amp; t1 &amp;lt;= raymaxdist)&lt;br /&gt;
            {&lt;br /&gt;
                info = new IntersectionInfo();&lt;br /&gt;
                Vertex3 v; info.material = ObjectMaterial;&lt;br /&gt;
&lt;br /&gt;
                info.rayPosition = t1;&lt;br /&gt;
                if (t1 &amp;gt;= raymindist)&lt;br /&gt;
                {&lt;br /&gt;
                    v = osray.Evaluate(t1);&lt;br /&gt;
                    if (calcNormals) info.normal = CalcNormal(v);&lt;br /&gt;
                    if (calcTextureCoordinates) &lt;br /&gt;
                        info.texture = GeoMath.SphereCoordinates(v);&lt;br /&gt;
                    return 1;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                v = osray.Evaluate(t2);&lt;br /&gt;
                if (calcNormals) info.normal = CalcNormal(v);&lt;br /&gt;
                if (calcTextureCoordinates) &lt;br /&gt;
                    info.texture = GeoMath.SphereCoordinates(v);&lt;br /&gt;
                info.rayPosition = t2;&lt;br /&gt;
                return 1;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                return -1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Phong Licht ==&lt;br /&gt;
[[Bild:Tutorial_RaytracingII_phong.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wir sind soweit. Die ersten hübscheren Bilder aus unserem Raytracer sind greifbar nahe. Wir müssen uns im wesentlichen nur noch mit Phong Licht beschäftigen, um aus unserem Raytracer mehr herauszuquetschen. Das Phong-Beleuchtungsmodell ist ein sehr einfaches Modell, um Licht zu simulieren. Es ist physikalisch ziemlich falsch: Durch Hinzufügen von Objekten in einen physikalischen Raum, die sich lichttechnisch nach dem Phong Modell verhalten, wird i.A. die vorhandene Lichtenergie erhöht. Das ist sehr tragisch, wenn man globale Beleuchtungsmethoden verwendet, aber fürs erste ist es ein sehr gut aussehendes und leicht zu  berechnendes Modell. Wir wollen uns also von dieser Anomalität nicht beunruhigen lassen und uns nur daran erinnern, wenn wir einmal globale Beleuchtungsmethoden einführen wollen. Jedem sollte das Phong Modell wohl vertraut sein, da es das Standard-Modell in OpenGl ist. Wer hier noch Nachholbedarf hat, schaue doch einmal im [[Beleuchtung|Beleuchtungs-Artikel]] oder [http://www.delphi3d.net/articles/viewarticle.php?article=phong.htm in Tom Nuydens': Phong For Dummies]. &lt;br /&gt;
&lt;br /&gt;
Jedenfalls, wenn wir jedem Objekt ein Material mit den Koeffizienten aus dem Phong-Modell zugeordnet haben, dann können wir mithilfe einer IntersectionInfo für Strahl/Objekt-Schnittpunkte und aller Lichtquellen leicht die zugehörige Farbe bestimmen. An der Stelle, wo wir also im Tiefentracer den Grauwert bestimmten, bestimmen wir&lt;br /&gt;
jetzt den zugehörigen Farbwert über unser Material: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;public RaytraceImage ( int width , int height )&lt;br /&gt;
{&lt;br /&gt;
    for ( int x = 0; x &amp;lt; width; x++) {&lt;br /&gt;
        for ( int y = 0 ; y &amp;lt; height; y++) {&lt;br /&gt;
            Ray shoot = ShootRay (x , y);&lt;br /&gt;
            double maxdist = double.Infinity;&lt;br /&gt;
            &lt;br /&gt;
            IntersectionInfo cinfo = new IntersectionInfo();;&lt;br /&gt;
            IntersectionInfo iinfo = new IntersectionInfo();&lt;br /&gt;
            &lt;br /&gt;
            foreach (ObjectBase obj in SichtbareObjekte) {&lt;br /&gt;
                if (obj.Intersect(rs, shoot, 0, maxdist, true, true, ref cinfo) &amp;gt; 0 &lt;br /&gt;
                  &amp;amp;&amp;amp; cinfo.rayPosition &amp;lt; maxdist) iinfo = cinfo;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            if (maxdist &amp;lt; double.Infinity &amp;amp;&amp;amp; iinfo.material != null) {&lt;br /&gt;
                SetColor(x, y, iinfo.Material.GetColor(iinfo));&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                SetColor(x, y, BackgroundColor);   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Abschluss ==&lt;br /&gt;
Da habt ihr euch ja durch ein dickes Ding gequält ( besonders wenn ihr im Bereich Transformationen oder Phong noch Nachholbedarf hattet, hats sicher eine Weile gedauert ). Gratulation. Langsam wird das Raytracing ja interessant und die Szenen sind nicht mehr ganz so langweilig. Es bleibt aber immer noch genügend Stoff für ein weiteres Grundlagen Tutorial: In Planung sind hier ein paar Worte bezüglich Reflexionen, Schatten und ein paar weiteren Objekten wie Dreiecken (das impliziert eine Lehrstunde in Sachen Phong Shading), Boxen und Zylinder. Dazu sollten wir außerdem unseren Raytracer umbauen: Er wird in eine eigene Tracer-Klasse ausgelagert werden, um so schnell die Wahl zwischen verschiedenen Raytracern zu haben. Stay tuned.&lt;br /&gt;
&lt;br /&gt;
'''Delphic'''&lt;/div&gt;</summary>
		<author><name>Openglerf</name></author>	</entry>

	</feed>