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

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glUnmapBuffer&amp;diff=21134</id>
		<title>glUnmapBuffer</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glUnmapBuffer&amp;diff=21134"/>
				<updated>2008-02-24T02:48:25Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Name */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glMapBuffer =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glUnmapBuffer''' - Ermöglicht es andern Befehlen wieder auf den Buffer zuzugreifen, in dem es ihn vom Client zurückholt.&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 function '''glUnmapBuffer'''(''target'' : TGLenum)  : TGLboolean&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;
! ''target'' &lt;br /&gt;
|  Mögliche Werte: '''GL_ARRAY_BUFFER''' oder '''GL_ELEMENT_ARRAY_BUFFER'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Ein mit [[glMapBuffer]] in den Client Adressraum übertragener Buffer, wird wieder zurückgeholt, damit OpenGL Befehle wieder auf ihn zugreifen können. Der Pointer vom [[glMapBuffer]] Aufruf wird dadurch ungültig. Der GL_BUFFER_MAPPED Status des Objektes wechselt auf FALSE, der Status GL_BUFFER_MAP_POINTER wechselt zu NULL (in C++).&lt;br /&gt;
&lt;br /&gt;
Der Befehl '''glMapBuffer''' gibt TRUE zurück, wenn der Buffer nicht beschädigt wurde, wärend er sich im Client Adressraum befandt. Andernfalls wird FALSE zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn sich der Buffer bereits nicht mehr im Client Adressraum befindet. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[glBindBuffer]], [[glBufferData]], [[glBufferSubData]], [[glDeleteBuffers]], [[glGenBuffers]], [[glGetBufferParameter]], [[glGetBufferPointerv]], [[glGetBufferSubData]], [[glIsBuffer]], [[glMapBuffer]]&lt;br /&gt;
[[Kategorie:GL|UnmapBuffer]]&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glUnmapBuffer&amp;diff=21133</id>
		<title>glUnmapBuffer</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glUnmapBuffer&amp;diff=21133"/>
				<updated>2008-02-24T02:47:50Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Delphi-Spezifikation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glMapBuffer =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glMapBuffer''' - Ermöglicht es andern Befehlen wieder auf den Buffer zuzugreifen, in dem es ihn vom Client zurückholt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 function '''glUnmapBuffer'''(''target'' : TGLenum)  : TGLboolean&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;
! ''target'' &lt;br /&gt;
|  Mögliche Werte: '''GL_ARRAY_BUFFER''' oder '''GL_ELEMENT_ARRAY_BUFFER'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Ein mit [[glMapBuffer]] in den Client Adressraum übertragener Buffer, wird wieder zurückgeholt, damit OpenGL Befehle wieder auf ihn zugreifen können. Der Pointer vom [[glMapBuffer]] Aufruf wird dadurch ungültig. Der GL_BUFFER_MAPPED Status des Objektes wechselt auf FALSE, der Status GL_BUFFER_MAP_POINTER wechselt zu NULL (in C++).&lt;br /&gt;
&lt;br /&gt;
Der Befehl '''glMapBuffer''' gibt TRUE zurück, wenn der Buffer nicht beschädigt wurde, wärend er sich im Client Adressraum befandt. Andernfalls wird FALSE zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
'''GL_INVALID_OPERATION''' wird generiert wenn sich der Buffer bereits nicht mehr im Client Adressraum befindet. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[glBindBuffer]], [[glBufferData]], [[glBufferSubData]], [[glDeleteBuffers]], [[glGenBuffers]], [[glGetBufferParameter]], [[glGetBufferPointerv]], [[glGetBufferSubData]], [[glIsBuffer]], [[glMapBuffer]]&lt;br /&gt;
[[Kategorie:GL|UnmapBuffer]]&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20537</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=20537"/>
				<updated>2007-05-15T02:08:43Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Vorwort */&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 will 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 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 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 werden 4 Vector MADDs (Multiplikation und Addition) benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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 ein 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 muss die 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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20536</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=20536"/>
				<updated>2007-05-14T23:46:41Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Externe Links */&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. 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 will 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 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 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 werden 4 Vector MADDs (Multiplikation und Addition) benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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 ein 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 muss die 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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20535</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=20535"/>
				<updated>2007-05-14T23:45:44Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Technik */&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. 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 will 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 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 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 werden 4 Vector MADDs (Multiplikation und Addition) benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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 ein 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 muss die 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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20534</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=20534"/>
				<updated>2007-05-14T23:18:55Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* 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. 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 will 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 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;
==Technik==&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 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;
===Matrix basierende Boneanimation===&lt;br /&gt;
&lt;br /&gt;
Zum gewichten werden pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20533</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=20533"/>
				<updated>2007-05-14T23:16:13Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Gewichten der Bones */&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. 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 will 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 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;
==Technik==&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 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;
===Matrix basierende Boneanimation===&lt;br /&gt;
&lt;br /&gt;
Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20532</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=20532"/>
				<updated>2007-05-14T23:15:21Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: &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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20531</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=20531"/>
				<updated>2007-05-14T23:14:22Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Gewichten der Bones */&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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20530</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=20530"/>
				<updated>2007-05-14T23:13:34Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Quaternionen im Vertexshader */&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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;
 	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_ProjectionMatrix * (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; cast&lt;br /&gt;
 	&lt;br /&gt;
	N = m3 * gl_Normal); &lt;br /&gt;
	//T = 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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20529</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=20529"/>
				<updated>2007-05-14T23:09:11Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Quaternionen im Vertexshader */&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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;
 	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_ProjectionMatrix * (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; cast&lt;br /&gt;
 	&lt;br /&gt;
	N = m3 * gl_Normal); &lt;br /&gt;
	//T = 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;/glsl&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;glsl&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;/glsl&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;glsl&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_ProjectionMatrix * vert; &lt;br /&gt;
 &lt;br /&gt;
	N = qrot(quaternion, gl_Normal); &lt;br /&gt;
	//T = 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;/glsl&amp;gt;&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20528</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=20528"/>
				<updated>2007-05-14T23:01:43Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Quaternionen im Vertexshader */&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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;
 	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_ProjectionMatrix * (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; cast&lt;br /&gt;
 	&lt;br /&gt;
	N = m3 * gl_Normal); &lt;br /&gt;
	//T = 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;/glsl&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. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&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;
&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20527</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=20527"/>
				<updated>2007-05-14T22:58:22Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Gewichten der Bones */&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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann:&lt;br /&gt;
&amp;lt;glsl&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;
 	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_ProjectionMatrix * (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; cast&lt;br /&gt;
 	&lt;br /&gt;
	N = m3 * gl_Normal); &lt;br /&gt;
	//T = 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;/glsl&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. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&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;
&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20526</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=20526"/>
				<updated>2007-05-14T22:56:07Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: &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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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]); //on nvidia cards remove the int() cast &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); // on nvidia cards &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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann. &lt;br /&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. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&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;
&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20525</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=20525"/>
				<updated>2007-05-14T22:51:10Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Quaternionen im Vertexshader */&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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann. &lt;br /&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. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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;
 N = gl_NormalMatrix * (mat3(mat) * gl_Normal); &lt;br /&gt;
 //T = gl_NormalMatrix * (mat3(mat) * Tangent); &lt;br /&gt;
 //B = cross (T,N); &lt;br /&gt;
 gl_TexCoord[0] = gl_MultiTexCoord0; &lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&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;
&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20524</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=20524"/>
				<updated>2007-05-14T22:50:08Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Quaternionen im Vertexshader */&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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann. &lt;br /&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. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&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[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;
 N = gl_NormalMatrix * (mat3(mat) * gl_Normal); &lt;br /&gt;
 //T = gl_NormalMatrix * (mat3(mat) * Tangent); &lt;br /&gt;
 //B = cross (T,N); &lt;br /&gt;
 gl_TexCoord[0] = gl_MultiTexCoord0; &lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/glsl&amp;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;
&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20523</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=20523"/>
				<updated>2007-05-14T22:48:58Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: &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. 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 will 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 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;
==Technik==&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 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;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann, prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 4 Vector MADDs (Multiplikation und Addition) benötigt. Insgesamt werden 16 Vector MADD instructions benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Als Optimierung kann es sinvoll sein die Modelviewmatrix mit den Bonematrizen zu multiplizieren, da so der Vertexshader entlasted werden kann. &lt;br /&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. &lt;br /&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[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;
 N = gl_NormalMatrix * (mat3(mat) * gl_Normal); &lt;br /&gt;
 //T = gl_NormalMatrix * (mat3(mat) * Tangent); &lt;br /&gt;
 //B = cross (T,N); &lt;br /&gt;
 gl_TexCoord[0] = gl_MultiTexCoord0; &lt;br /&gt;
 } &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;
&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 für&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=20522</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=20522"/>
				<updated>2007-05-14T22:12:43Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Kompression der Matrizen */&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. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 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 oder drei Float4 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 die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von [[Quaternion|Quaternionen]] im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern.&lt;br /&gt;
Eine gepackte Matrix kommt mit 8 Floats aus. Für Quarternionen wäre mit zusätzlichem Translationsteil 7 Floats nötig. Einen wirklichenSinn machen Quarternionen im Vertexshader also definitiv nicht&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Überlagerung meherer Animationen===&lt;br /&gt;
&lt;br /&gt;
Sicher werden am Anfang statische Posen ausreichen. Jedoch ist es mit einer Matrixmultiplikation pro Bone möglich zwei Posen zu überlagern. z.B. kann man so verschiedene Posen einer Hand an einen Arm binden. In diesem Fall müssen die Matrizen der Handanimation mit den Matrizen der Körperanimation Multipliziert werden.&lt;br /&gt;
Alle von der Teilanimation nicht betroffenen Matrizen müssen dabei einheitsmatrizen entsprechen, damit die Multiplikation keine Auswirkung hat.&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Blenderexporter&amp;diff=19941</id>
		<title>Blenderexporter</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Blenderexporter&amp;diff=19941"/>
				<updated>2006-12-16T12:53:54Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Daten für Indizierte VBOs exportieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Hier werde ich einige Codeschnipsel zeigen, mit denen man sich einen eigenen Blenderexporter bauen kann. Der Schwerpunkt liegt dabei darauf, die Daten so vorzubereiten, dass sie direkt als VertexBufferObjekt in die Grafikkarte hochgeladen werden können.&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial, soll kein festes Format beschreiben. Es ist sowohl möglich die Daten sauber in XML zu kapseln, als auch ganz dirty mal eben ein Includierbares C oder Pascalfile zu erzeugen. Der Compiler wird einen dafür aber mit erheblich längeren compelierungszeiten bestrafen.&lt;br /&gt;
&lt;br /&gt;
Prinzipell bin ich der Meinung, das eine eigene Engine nicht zwangshaft mit einem Universalformat wie Collada verwendet werden muss. Auch beliebte Formate wie 3DS haben gewaltige Nachteile, da sie nicht alle Daten speichern können, die beim Arbeiten mit Shadern benötigt werden. 3DS ist eine gut wahl, solang man nicht viel mehr als Vertices, Normals und UV Coordinaten benötigt. Sobald Bones Vertexgruppen, TBN Matrizen und möglicherweise weitere eigene Daten gespeichert werden müssen gibt es große Probleme.&lt;br /&gt;
&lt;br /&gt;
==Aufbau eines Exporters==&lt;br /&gt;
&lt;br /&gt;
Jeder Blenderexporter verfügt über einen Header, in dem Daten stehen, wie er in die Menüstruktur eingefügt wird. Anschließen folgt der Python code. Näheres dazu steht in den Wikibooks.&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
#!BPY&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Name: 'DGL Wiki'&lt;br /&gt;
Blender: 241&lt;br /&gt;
Group: 'Export'&lt;br /&gt;
Tooltip: 'DGL Wiki Exporter'&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import Blender&lt;br /&gt;
&lt;br /&gt;
#Hier werden zusätzliche Funktionen eingefügt, die zum schreiben benötigt werden&lt;br /&gt;
&lt;br /&gt;
def write(filename):&lt;br /&gt;
  out = file(filename, 'w')&lt;br /&gt;
  obj = Blender.Object.GetSelected()[0]&lt;br /&gt;
  msh = obj.getData()&lt;br /&gt;
&lt;br /&gt;
  #hier wird Code eingefügt, der die zu exportierende Daten schreibt&lt;br /&gt;
&lt;br /&gt;
  out.close()&lt;br /&gt;
Blender.Window.FileSelector(write, &amp;quot;Export&amp;quot;)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
code getestet&lt;br /&gt;
&lt;br /&gt;
Wichtig ist, das man bei Python die Einrückungen beachtet. Als erstes wird eine Funktion definiert, die vom Fileexportdialog aus aufgerufen wird. Dabei wird der Filename als Argument übergeben. Die folgenden Zeilen öffnen ein File zum schreiben und hohlen sich die Meshdaten des erstem selektiertem Objektes.&lt;br /&gt;
Starten tut das Script eigendlich erst in der letzten Zeile, die den Exportdialog aufruft.&lt;br /&gt;
&lt;br /&gt;
==Vorbereiten der Daten==&lt;br /&gt;
&lt;br /&gt;
Da OpenGL nicht gut auf die gemischten Quads und Triangles klar kommt ist es sehr Sinnvoll sie gleich am Anfang vor dem Exportieren umzuwandeln:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
def quad2tri(msh):&lt;br /&gt;
  flist=[]&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    if (len(face.v)==3):&lt;br /&gt;
      flist += [face]&lt;br /&gt;
    else:&lt;br /&gt;
      d1 =(msh.verts[face.v[0].index].co.x - msh.verts[face.v[2].index].co.x) ** 2 &lt;br /&gt;
      d1+=(msh.verts[face.v[0].index].co.y - msh.verts[face.v[2].index].co.y) ** 2 &lt;br /&gt;
      d1+=(msh.verts[face.v[0].index].co.z - msh.verts[face.v[2].index].co.z) ** 2 &lt;br /&gt;
      d2 =(msh.verts[face.v[1].index].co.x - msh.verts[face.v[3].index].co.x) ** 2 &lt;br /&gt;
      d2+=(msh.verts[face.v[1].index].co.y - msh.verts[face.v[3].index].co.y) ** 2 &lt;br /&gt;
      d2+=(msh.verts[face.v[1].index].co.z - msh.verts[face.v[3].index].co.z) ** 2 &lt;br /&gt;
      if (d1&amp;lt;d2):&lt;br /&gt;
        flist += [Blender.NMesh.Face([face.v[0],face.v[1],face.v[2]])]&lt;br /&gt;
	flist[len(flist)-1].uv=[face.uv[0],face.uv[1],face.uv[2]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[0],face.col[1],face.col[2]]&lt;br /&gt;
        flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
	&lt;br /&gt;
	flist += [Blender.NMesh.Face([face.v[0],face.v[2],face.v[3]])]&lt;br /&gt;
        flist[len(flist)-1].uv=[face.uv[0],face.uv[2],face.uv[3]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[0],face.col[1],face.col[2]]&lt;br /&gt;
	flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
      else:&lt;br /&gt;
	flist += [Blender.NMesh.Face([face.v[0],face.v[1],face.v[3]])]&lt;br /&gt;
        flist[len(flist)-1].uv=[face.uv[0],face.uv[1],face.uv[3]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[0],face.col[1],face.col[3]]&lt;br /&gt;
	flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
	&lt;br /&gt;
	flist += [Blender.NMesh.Face([face.v[1],face.v[2],face.v[3]])]&lt;br /&gt;
        flist[len(flist)-1].uv=[face.uv[1],face.uv[2],face.uv[3]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[1],face.col[2],face.col[3]]&lt;br /&gt;
	flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
  msh.faces=flist&lt;br /&gt;
  return msh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Das Prinzip ist Relativ leicht zu verstehen. &amp;quot;flist&amp;quot; ist eine Liste in der die neuen Dreiecke zwischengespeichert werden. Dreiecke werden einfach kopiert. Bei Quads wird die kürzere Diagonale zum Teilen gesucht und aus den Daten des Quads zwei neue Triangles erzeugt. Zum Schluss wird  noch die temporäre Liste im Mesh gespeichert und as ganze zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
==Exportieren der Daten==&lt;br /&gt;
&lt;br /&gt;
hier beschreiben ich wie man die wichtigsten Daten exportieren kann. Um ein anderes Format zu erhalten, müssen die Stings entsprechend angepasst werden. Eine neue Zeile erhält man durch &amp;quot;\n&amp;quot; In den Beispielen werde ich mich weitgehend an Werten gekapselt in einem XMLformat halten. Durch simple Modifikationen sind auch andere Formate kein problem.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Möglichkeiten die Vertexdaten zu speichern: Interleaved oder getrennte Blöcke. Beim interleaved Format verliert man die Flexibilität und die Daten werden noch unübersichtlicher. Ein Geschwindigkeitsgewinn ist auch nicht zu erwarten.&lt;br /&gt;
&lt;br /&gt;
In einigen Codestücken wird auffallen, das die Convertierung von Quads nach Triangles immer wieder vorgenommen wird. In einem komplettem Exporten macht es durchaus Sinn, alle Daten erst zu sammel, dann zu sortieren, umwandeln und erst zum Schluss zu schreiben. Dabei wäre es allerdings nicht mehr möglich einzelne Beispiele zu liefern.&lt;br /&gt;
&lt;br /&gt;
Eine besonder Problematik ist, dass Blender Quads beforzugt, jedoch Quads und Triangles gemischt vorliegen können. Um diese Mischung zu vermeiden sollte man entweder den Exporter so schreiben, dass er die Quads in 3 Triangles zerlegt oder vor dem Exportieren alle Quads in Triangles umwandelt und Speichert (Intern bleiben die Daten sonst anscheined immer noch Quads)&lt;br /&gt;
&lt;br /&gt;
Einfachen Text, der keine zu exportierenden Daten enhält lässt sich so in die Datei schreiben. Hier ein möglicher begin der XML Datei:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;yes&amp;quot;?&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier wieder die Einrückung. Sie muss genauso weit eingerück sein wie die vorige Zeile, oder weiter eingerück werden wenn es sich um eine Schleife handelt.&lt;br /&gt;
&lt;br /&gt;
Eine kleines Problem kann entstehen, wenn die letzte Zeile eines Datensatzes kein Komma enthalten darf. Der einfachste Weg ist eine Dummyzeile mit Nullwerten anzuhängen.&lt;br /&gt;
&lt;br /&gt;
===Name des Objektes und Anzahl der Vertices===&lt;br /&gt;
&lt;br /&gt;
In einem XML format ist es nicht alzuwichtig den Objektnamen aus Blender zu behalten. Jedoch kann es sehr nützlich sein wenn man andere Formate schreibt oder mehrere Objekte in einer Datei speichert. Wir bringen diese Daten einfach im VBO Tag unter, welches alle unsere Vertexdaten kapseln wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
 out.write('&amp;lt;vbo name=&amp;quot;%s&amp;quot; verts=&amp;quot;%i&amp;quot; type=&amp;quot;GL_TRIANGLE&amp;quot;&amp;gt;\n' % (msh.name, len(msh.faces)*3))&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Schluss sollte noch folgende Zeile angehängt werden um den VBO tag wieder zu schließen:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;/vbo&amp;gt;') &lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Vertices===&lt;br /&gt;
Da man den Index eines Vertexarray nicht in einem VBO verpacken kann. Ist es besser die Triangles nicht indiziert in einem VBO zu speichern. Der Speicherbedarf ist hier allerdings höher. Trotz der erhöten Datenmenge scheint diese Variante schneller zu sein, da hier keine Arrays vom Prozessor abgearbeitet werden müssen.&lt;br /&gt;
Unter der Annahme, das nur Triangles vorhanden sind, reicht dieser Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
 out.write('&amp;lt;vertices comp=&amp;quot;3&amp;quot;&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
      out.write( ' %f %f %f' % (msh.verts[vert.index].co.x, msh.verts[vert.index].co.y, msh.verts[vert.index].co.z))&lt;br /&gt;
    out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/vertices&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Textur-Koordinaten===&lt;br /&gt;
&lt;br /&gt;
Kaum schwerer als die Vertexdaten sind die Texturkoordinaten zu exportieren. Da die Texturkoordinaten innerhalb der Faces gespeichert werden. Sinvollerweise überprüfen wir voher noch ob überhaupt Texturdaten vorhanden sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  if (msh.hasFaceUV()==1):&lt;br /&gt;
    out.write('&amp;lt;texturecoords comp=&amp;quot;2&amp;quot;&amp;gt;\n')&lt;br /&gt;
    for face in msh.faces:&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f %f %f %f\n' % (face.uv[0][0],face.uv[0][1],face.uv[1][0],face.uv[1][1],face.uv[2][0],face.uv[2][1]) )&lt;br /&gt;
    out.write('&amp;lt;/texturecoords&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Normals===&lt;br /&gt;
&lt;br /&gt;
Normalvektoren sind in Blender sowohl per Vertex als auch per Face abgespeichert. Abhängig, davon ob eine Fläche als Smooth (per Vertex) oder Solid (per Face) dargestellt wird, werden die die entsprechenden Normalvektoren ausgewählt. Damit auch Klötze mit Kanten dargestellt werden können müssen beide Fälle berücksichtigt werden. Im Fall Solid müssen für alle Vertices der Fläche der Normalvektor der Fläche verwendet werden. Im Fall Smooth muss hier der Normalvektor der Vertices benutz werden.&lt;br /&gt;
Auf keinen Fall sollte man nun die Vervielfachung der Vertices als Problem ansehen, da die verschiedenen Normalvektoren, diesen Nachteil wieder volkommen ausgleichen.&lt;br /&gt;
 &lt;br /&gt;
Tip: Da ganze Flächen als Solid keinerlei Optische Rundungen zulassen, ist der einzige Weg, echte Kanten an runden Objekten zu erzeugen in dem man das Mesch an der Stelle splittet. Leider muss man zum Splitten einen vollständigen Edgeloop auswählen. An Stellen die nicht kantig sein sollen muss man dann beide Vertices Makieren und mit &amp;quot;remove doubles&amp;quot; vereinen. &lt;br /&gt;
&lt;br /&gt;
Auch hier ersst einmal ein einfaches Beispiel was haufig schon genügen sollte:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;normals&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
     for vert in face.v:&lt;br /&gt;
        out.write( ' %f, %f, %f,' % (msh.verts[vert.index].no.x, msh.verts[vert.index].no.y, msh.verts[vert.index].no.z) )&lt;br /&gt;
     out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/normals&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besser wird es, wenn Smooth/Solid berücksichtigt wird. &lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;normals&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f' % (msh.verts[vert.index].no.x, msh.verts[vert.index].no.y, msh.verts[vert.index].no.z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f, %f, %f,' % (face.no.x, face.no.y, face.no.z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/normals&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Tangenvektor / TBN Matrix ===&lt;br /&gt;
&lt;br /&gt;
Ohne die TBN Matrix lässt sich in den shadern kein sinvolles Bumpmapping durchführen. Weder Dot3, Offset, Parallax  noch &lt;br /&gt;
Reliefmapping sind ohne TBN Matrix möglich.&lt;br /&gt;
Eine TBN Matrix besteht aus drei Vektoren, die den Texturespace aufspannen:&lt;br /&gt;
&lt;br /&gt;
Normal&lt;br /&gt;
&lt;br /&gt;
Er steht immer Senkrecht zur Oberfläche. Er entspricht genau dem Normalvektor wie wir ihn kennen.&lt;br /&gt;
Beim Paralax und Reliefmapping repräsentiert seine Länge den Masstab für die dritte Texturkoordinate (Im Editor wäre sie W, auch wenn die Texturkoordinaten in OpenGL s, t, p und q sind).&lt;br /&gt;
&lt;br /&gt;
Tangent&lt;br /&gt;
&lt;br /&gt;
Er liegt tangential auf der Textur und ist dort zur U Achse ausgerichtet. Wieder einmal kann man überlegen ob es nun beteutet Senktrecht zum Normal oder Parallel zu Fläche des Dreieckes. Wer keine Kopfschmerzen hat macht sich welche.&lt;br /&gt;
&lt;br /&gt;
Bitangent&lt;br /&gt;
&lt;br /&gt;
Häufig wird er auch Binormal genannt, jedoch beschreibt Bitangent die Funktion besser. Er ist wie der Tangent tangential zur V Achse der Textur ausgerichtet.&lt;br /&gt;
Wer meint Bitangent lässt sich durch das Kreutzprodukt von Normal und Tangend berechnen, hat nur recht wenn die Textur keine Scherung enthällt.&lt;br /&gt;
&lt;br /&gt;
So lange die Textur nicht verzert wird, ist eine normalisierte TBN Matrix problemlos verwendbar, wenn jedoch die Tiefenkomponente der Textur nicht auf kubischen Texeln basiert, ist es sinvoller die Korrektur im Shader vorzunehmen, als die Komonenten dern TBN Matrix zu verzerren.&lt;br /&gt;
&lt;br /&gt;
Da ich es jetzt anscheinend verstanden habe wie ich die zusätzlichen komponenten der TBN Matrix berechnen kann. Kommt hier der Code zum erzeugen der Tangent und Bitangentvektoren pro Face und Vertex:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
def createFaceTan(msh):&lt;br /&gt;
  ftan = []&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    tan = msh.verts[face.v[2].index].co - msh.verts[face.v[0].index].co&lt;br /&gt;
    if (face.uv[2][1] != face.uv[1][1]):&lt;br /&gt;
      m = (face.uv[2][1]-face.uv[0][1])/(face.uv[2][1]-face.uv[1][1])&lt;br /&gt;
      tan += (msh.verts[face.v[1].index].co - msh.verts[face.v[2].index].co) * m&lt;br /&gt;
    tan.normalize()&lt;br /&gt;
    ftan += [tan]&lt;br /&gt;
  return ftan&lt;br /&gt;
&lt;br /&gt;
def createFaceBit(msh):&lt;br /&gt;
  fbit = []&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    bit = msh.verts[face.v[1].index].co - msh.verts[face.v[0].index].co&lt;br /&gt;
    if (face.uv[1][0] != face.uv[2][0]):&lt;br /&gt;
      m = (face.uv[1][0]-face.uv[0][0])/(face.uv[1][0]-face.uv[2][0])&lt;br /&gt;
      bit += (msh.verts[face.v[2].index].co - msh.verts[face.v[1].index].co) * m&lt;br /&gt;
    bit.normalize()&lt;br /&gt;
    fbit += [bit]&lt;br /&gt;
  return fbit&lt;br /&gt;
&lt;br /&gt;
def interpolate(msh,ftan):&lt;br /&gt;
  vtan = []&lt;br /&gt;
  for vert in msh.verts:&lt;br /&gt;
    vtan += [Blender.NMesh.Vert().co]&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    if (face.smooth == 1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        vtan[vert.index] += ftan[vert.index]&lt;br /&gt;
  for i in range(0,len(msh.verts)):&lt;br /&gt;
    vtan[i].normalize()&lt;br /&gt;
  return vtan	&lt;br /&gt;
&lt;br /&gt;
ftan = createFaceTan(msh)&lt;br /&gt;
vtan = interpolate(msh,ftan)&lt;br /&gt;
fbit = createFaceBit(msh)&lt;br /&gt;
vbit = interpolate(msh,fbit)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Hier noch der Link zum Artikel wo ich die Berechnung erkläre:&lt;br /&gt;
http://wiki.delphigl.com/index.php/TBN_Matrix&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit folgenden Codeschnipseln, lassen sich Tangent, Bitanget und die TBN Matrix ausgeben. Sinvoll ist es natürlich nur die Einzelkomponenten zusätzlich zum Normalvektor zu schreiben oder die TBN Matrix ohne Normalen zu verwenden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;tan&amp;gt;\n')&lt;br /&gt;
  for i in range(0,len(msh.faces)):&lt;br /&gt;
    face = msh.faces[i]&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f' % (vtan[vert.index].x, vtan[vert.index].y, vtan[vert.index].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f %f %f' % (ftan[i].x, ftan[i].y, ftan[i].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/tan&amp;gt;\n')&lt;br /&gt;
  &lt;br /&gt;
  out.write('&amp;lt;bit&amp;gt;\n')&lt;br /&gt;
  for i in range(0,len(msh.faces)):&lt;br /&gt;
    face = msh.faces[i]&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f' % (vbit[vert.index].x, vbit[vert.index].y, vbit[vert.index].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f %f %f' % (fbit[i].x, fbit[i].y, fbit[i].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/bit&amp;gt;\n')&lt;br /&gt;
  &lt;br /&gt;
  out.write('&amp;lt;tbn&amp;gt;\n')&lt;br /&gt;
  for i in range(0,len(msh.faces)):&lt;br /&gt;
    face = msh.faces[i]&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
	out.write( ' %f %f %f' % (vtan[vert.index].x, vtan[vert.index].y, vtan[vert.index].z))&lt;br /&gt;
        out.write( ' %f %f %f' % (vbit[vert.index].x, vbit[vert.index].y, vbit[vert.index].z))&lt;br /&gt;
        out.write( ' %f %f %f\n' % (msh.verts[vert.index].no.x, msh.verts[vert.index].no.y, msh.verts[vert.index].no.z))&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f %f %f' % (ftan[i].x, ftan[i].y, ftan[i].z))&lt;br /&gt;
        out.write( ' %f %f %f' % (fbit[i].x, fbit[i].y, fbit[i].z))&lt;br /&gt;
	out.write( ' %f %f %f\n' % (face.no[0], face.no[1], face.no[2]))&lt;br /&gt;
  out.write('&amp;lt;/tbn&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Warnung: Die Vektoren scheinen alle Senkrecht zu einander zu stehen, jedoch ist noch nicht überprüft ob die Matrizen wirklich brauchbar sind. Es wäre durchaus möglich, dass noch komponenten verdreht oder gespiegelt sind.&lt;br /&gt;
&lt;br /&gt;
Aufgrund des Mangels an Atributevariablen, ist es nicht sehr Sinvoll die volle TBN Matrix zu übergeben. Sinvoller ist es nur den Tangendvektor (Bitangent kann durch ein Kreutzprodukt neu berechnet werden) oder den Tangentvektor zumammen mit dem Bitangentvektor als Atribute zu übergeben.&lt;br /&gt;
&lt;br /&gt;
===Vertuxgruppen / Bones ===&lt;br /&gt;
&lt;br /&gt;
Ohne Vertexgruppen und Bones lassen sich keine Animationen mit Hilfe des Vertexshaders realisieren. Diesen Teil können alle überspringen, die keine Vertexshader zum Animieren benutzen wollen. &lt;br /&gt;
Die Daten liegen in Blender in einer für Vertexshader leicht unbrauchbaren Form vor und müssen etwas aufbereitet werden. In jeder Vertexgruppe, auf die man auch noch über Ihren Namen zugreifen muss, liegt eine Liste mit der Vertexnummer und der Gewichtung.&lt;br /&gt;
Für einen Vertexshader benötigen wir pro Vertex einen Index, der die Vertexgruppe/Bone beschreibt und die Gewichtung. Außerdem müssen wir uns voher entscheiden, wie viele Bones wir maximal pro Vertex berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
Bei Mangel an &amp;quot;attribute&amp;quot; Variablen macht es Sinn, die Gewichtung (muss kleiner als 1 sein) mit den Indizies zu addieren. Im Shader könnte man die dann wieder herausrechnen. Auf heutiger Hardware sind 16 Atribute Variablen möglich.&lt;br /&gt;
&lt;br /&gt;
Als erstes den Codeblock zum aufbereiten der Daten. Es ist wichtig, dass die Variable num_of_vertexgroups.val die erwünschte Anzahl von Vertexgruppen enthällt:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  vertGroupData = []&lt;br /&gt;
  groups = msh.getVertGroupNames()&lt;br /&gt;
  for vert in msh.verts:&lt;br /&gt;
    list = []&lt;br /&gt;
    count = 1&lt;br /&gt;
    for group in groups:&lt;br /&gt;
      if (len(msh.getVertsFromGroup(group,0,[vert.index]))==1):&lt;br /&gt;
        list += [(msh.getVertsFromGroup(group,1,[vert.index])[0][1],count)]&lt;br /&gt;
      count += 1&lt;br /&gt;
      list.sort()&lt;br /&gt;
      list.reverse()&lt;br /&gt;
      for i in range(0,num_of_vertexgroups.val):&lt;br /&gt;
        list += [(0.0, 0)]&lt;br /&gt;
      vertGroupData += [(list[0:num_of_vertexgroups.val])]&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Hinweis: Es gibt noch mit getVertexInfluences() eine bessere Methode zum ermitteln welche Vertexgruppe zu einem Vertex gehöhrt. Dann wäre jedoch der einsatz eines Dictonarys nötig.&lt;br /&gt;
 &lt;br /&gt;
Nun noch der Code zum schreiben:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;vertexgroups comp=&amp;quot;%i&amp;quot;&amp;gt;\n&amp;lt;weight&amp;gt;\n' % num_of_vertexgroups.val)&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
      for group in vertGroupData[vert.index]:&lt;br /&gt;
        out.write( ' %f' % (group[0]))&lt;br /&gt;
    out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/weight&amp;gt;\n&amp;lt;index&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
      for group in vertGroupData[vert.index]:&lt;br /&gt;
        out.write( ' %i' % (group[1]))&lt;br /&gt;
    out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/index&amp;gt;\n&amp;lt;/vertexgroups&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Optimierung der Daten==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir uns Hauptsachlich damit beschäftig wie wir die Daten aus der Blenderstruktur auszulesen und in ein Vertexbufferobjekt kompatible daten unzuformen. Wen die Modelle größer werden oder komplette Level in Blender realisiert werden sollen macht es Sinn die Daten so umzusortieren, das Triangles mit ähnlichen Eigenschaften wie Ort oder Ausrichtung nah im Vertexbufferobjekt beieinander liegen.&lt;br /&gt;
&lt;br /&gt;
===Octree===&lt;br /&gt;
&lt;br /&gt;
Beim Octree werden nur die Teile gerender, bei denen voher bekannt ist, dass sie sichtbar sind, leider ist die Baumstruktur eines Octtrees auf dem erstem Blick völlig inkompatibel zu dem linearem Verlauf des Vertexbuffersobjektes. &lt;br /&gt;
&lt;br /&gt;
Um die Faces in den Octree einzusortieren muss von jedem der Schwerpunkt berechnet werden. Die Position im Octree wird mit einer art Hashfunktion berechnet, die erst aus den X Y und Z Koordinaten Integerwerte von 0 bis 1023 bildet und deren Bits so zusammensortiert, dass ein einziger Wert von 0 bis 2^30-1 ensteht. Nach dem die Faces sortiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
def octree(msh):&lt;br /&gt;
  # Boundingbox for Octree. &lt;br /&gt;
  # Warnung: bei mehreren VBOs sollte die gleiche Boundingbox verwendet werden,&lt;br /&gt;
  # damit nur einmal auf sichbarkeit überprüft werden muss&lt;br /&gt;
  mini = msh.verts[0].co * 1.0&lt;br /&gt;
  maxi = msh.verts[0].co * 1.0&lt;br /&gt;
  for vert in msh.verts:&lt;br /&gt;
    mini.x = minimum (mini.x,vert.co.x)&lt;br /&gt;
    mini.y = minimum (mini.y,vert.co.y)&lt;br /&gt;
    mini.z = minimum (mini.z,vert.co.z)&lt;br /&gt;
    maxi.x = maximum (maxi.x,vert.co.x)&lt;br /&gt;
    maxi.y = maximum (maxi.y,vert.co.y)&lt;br /&gt;
    maxi.z = maximum (maxi.z,vert.co.z)&lt;br /&gt;
  size = max (maxi.x-mini.x,maxi.y-mini.y,maxi.z-mini.z)&lt;br /&gt;
  #Hashberechnung&lt;br /&gt;
  optindex = []&lt;br /&gt;
  count = 0&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    center = msh.verts[0].co * 0.0&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
       center += msh.verts[vert.index].co&lt;br /&gt;
    #range 0.0 ... 1.0&lt;br /&gt;
    center *= 1.0 /( len(face.v) * size * 2.0)&lt;br /&gt;
    center.x += 0.5&lt;br /&gt;
    center.y += 0.5&lt;br /&gt;
    center.z += 0.5&lt;br /&gt;
    ix = int (center.x * 1023)&lt;br /&gt;
    iy = int (center.y * 1023)&lt;br /&gt;
    iz = int (center.z * 1023)&lt;br /&gt;
    sortby  = (ix&amp;amp;512)&amp;lt;&amp;lt;18 | (ix&amp;amp;256)&amp;lt;&amp;lt;16 |(ix&amp;amp;128)&amp;lt;&amp;lt;14 | (ix&amp;amp;64)&amp;lt;&amp;lt;12 |(ix&amp;amp;32)&amp;lt;&amp;lt;10 | (ix&amp;amp;16)&amp;lt;&amp;lt;8 |(ix&amp;amp;8)&amp;lt;&amp;lt;6 | (ix&amp;amp;4)&amp;lt;&amp;lt;4 |(ix&amp;amp;2)&amp;lt;&amp;lt;2 | (ix&amp;amp;1)&amp;lt;&amp;lt;0&lt;br /&gt;
    sortby |= (iy&amp;amp;512)&amp;lt;&amp;lt;19 | (iy&amp;amp;256)&amp;lt;&amp;lt;17 |(iy&amp;amp;128)&amp;lt;&amp;lt;15 | (iy&amp;amp;64)&amp;lt;&amp;lt;13 |(iy&amp;amp;32)&amp;lt;&amp;lt;11 | (iy&amp;amp;16)&amp;lt;&amp;lt;9 |(iy&amp;amp;8)&amp;lt;&amp;lt;7 | (iy&amp;amp;4)&amp;lt;&amp;lt;5 |(iy&amp;amp;2)&amp;lt;&amp;lt;3 | (iy&amp;amp;1)&amp;lt;&amp;lt;1&lt;br /&gt;
    sortby |= (iz&amp;amp;512)&amp;lt;&amp;lt;20 | (iz&amp;amp;256)&amp;lt;&amp;lt;18 |(iz&amp;amp;128)&amp;lt;&amp;lt;16 | (iz&amp;amp;64)&amp;lt;&amp;lt;14 |(iz&amp;amp;32)&amp;lt;&amp;lt;12 | (iz&amp;amp;16)&amp;lt;&amp;lt;10|(iz&amp;amp;8)&amp;lt;&amp;lt;8 | (iz&amp;amp;4)&amp;lt;&amp;lt;6 |(iz&amp;amp;2)&amp;lt;&amp;lt;4 | (iz&amp;amp;1)&amp;lt;&amp;lt;2&lt;br /&gt;
    optindex += [(sortby,count)]&lt;br /&gt;
    count += 1&lt;br /&gt;
  #Umsortierung der Daten&lt;br /&gt;
  optindex.sort()&lt;br /&gt;
  flist=[]&lt;br /&gt;
  for i in optindex:&lt;br /&gt;
    flist += [msh.faces[i[1]]]&lt;br /&gt;
  msh.faces=flist&lt;br /&gt;
  #Hier sollten noch die Verwaltungsdaten für den Octree geschrieben werden&lt;br /&gt;
  #Diese Code fehl allderings noch&lt;br /&gt;
&lt;br /&gt;
  return msh&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Diese Funktion sollte dierekt nach dem umwandeln der Quads in Triangles aufgerufen werden, da die Reihfolge der Triangles geändert wird.&lt;br /&gt;
&lt;br /&gt;
Prinzipiell gibt es für jedes würfelförmige Volumen nur eine Start und Stopindexnummer die beim Rendern übergeben werden muss:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
glDrawArrays( GL_TRIANGLES, start, stop - start);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Grundsätz sollte beachtet werden, dass es bei der Verwendung von VBOs möglichst viele Triangles auf einmal gerendert werden sollen.  Wo die untergrenze Pro volumen liegt lässt sich schwer sagen, es mach aber Sinn, diese jenseits der 1000-10000 anzusetzten.&lt;br /&gt;
&lt;br /&gt;
===Vorsortierung nach Vertexgruppen/Bones===&lt;br /&gt;
&lt;br /&gt;
Es ist zwar noch kein Algoritmus zum sortieren vorhanden, jedoch ist es bei animierten Modellen sinnvoll möglichst ganze Bones auf einmal abzuarbeiten, da ein Bone ganze 12 Uniform Floats im Vertexshader verbraucht (9 für eine Rotationsmatrix und 3 für das Gelenk). Laut GLSL Spezifikation soll man minimal 512 davon haben, was maximal 40 Bones entspricht. Dummerweise scheint es so als wenn einige Grafikkarten nur 256 Uniform Floats zur Verfügung stellen, was zur Folge hat, das nur noch 20 Bones möglich wären.&lt;br /&gt;
Eine primitive Optimierung wäre nur einen halbes Model zu speichen. und für die zweite hälfte das gleiche Mesh gespiegelt mit neuen Bones zu verwenden.&lt;br /&gt;
&lt;br /&gt;
Die Sinvollste Variante ist die schon erzeugten Vertexgruppendaten zum Sortieren zu benutzen: Die Gruppe mit der höchsten Gewichtung wird zum einsortieren benutzt. Alle Vertices die nicht in einer Gruppe sind, landen in einer extra gruppe. Diese Gruppen werde nun so umsortiert, dass Gruppen mit gegenseitigem Einfluss na beieinander landen. und Vertexgruppen die sih nicht beeinflussen weit von einander im VBO entfernt liegen.&lt;br /&gt;
&lt;br /&gt;
==Daten für Indizierte VBOs exportieren==&lt;br /&gt;
&lt;br /&gt;
Lange Zeit hab ich dieses Thema umgangen da der export relativ komplex ist. Alle Daten aus Blender müssen komplett neu umgeornet und neu indiziert werden, da Blender die Texturkoordinaten nicht per Vertex, sondern per Face abspeichert. Als Beispiel wird diesmal ein vereinfachter OBJ exporter dienen, der allerdings um tangentvektoren ergänst wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
#!BPY&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Name: 'VBO Wiki'&lt;br /&gt;
Blender: 241&lt;br /&gt;
Group: 'Export'&lt;br /&gt;
Tooltip: 'VBO Wiki Exporter 3 C version'&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import Blender&lt;br /&gt;
from Blender import NMesh&lt;br /&gt;
from Blender.BGL import *&lt;br /&gt;
from Blender.Draw import *&lt;br /&gt;
import math&lt;br /&gt;
from math import *&lt;br /&gt;
&lt;br /&gt;
#leicht verständliche funktion jedoch sehr ineffezient&lt;br /&gt;
def lfind(liste,key):&lt;br /&gt;
    for i in range(0, len(liste)):&lt;br /&gt;
	if liste[i]==key: return i&lt;br /&gt;
&lt;br /&gt;
def write(filename):&lt;br /&gt;
  global num_of_vertexgroups,TBNMenu,Optimise&lt;br /&gt;
  filename=replace(filename,&amp;quot;.blend&amp;quot;,&amp;quot;.obj&amp;quot;)&lt;br /&gt;
  out = file(filename, 'w')&lt;br /&gt;
  &lt;br /&gt;
  objs = Blender.Object.GetSelected()&lt;br /&gt;
  if (len(objs)==0):&lt;br /&gt;
    objs = Blender.Object.Get()&lt;br /&gt;
  #eigendlich nur 1 durchlauf sinnvoll&lt;br /&gt;
  for obj in objs:&lt;br /&gt;
    if (obj.getType()=='Mesh'):&lt;br /&gt;
    &lt;br /&gt;
      msh = obj.getData()&lt;br /&gt;
      # quad2tri könnte von obern hier eingesetzt werden&lt;br /&gt;
      # msh = quad2tri(msh)&lt;br /&gt;
      raw_index = []&lt;br /&gt;
      for face in msh.faces:&lt;br /&gt;
        for i in range (0,len (face.v)):&lt;br /&gt;
           vert = []&lt;br /&gt;
	   vert += [face.v[i].index]&lt;br /&gt;
	   vert += [face.uv[i][0]]&lt;br /&gt;
	   vert += [face.uv[i][1]]&lt;br /&gt;
	   raw_index += [vert]&lt;br /&gt;
&lt;br /&gt;
      raw_index.sort()&lt;br /&gt;
      last =raw_index[-1]&lt;br /&gt;
      for i in range(len(raw_index)-2, -1, -1):&lt;br /&gt;
       if last==raw_index[i]:&lt;br /&gt;
	 del raw_index[i]&lt;br /&gt;
       else: last=raw_index[i]&lt;br /&gt;
     &lt;br /&gt;
      out.write('g Index\n')&lt;br /&gt;
      &lt;br /&gt;
      for i in raw_index:&lt;br /&gt;
	 v = msh.verts[i[0]].co&lt;br /&gt;
         out.write('v %f %f %f\n' % (v.x,v.y,v.z))&lt;br /&gt;
      &lt;br /&gt;
      for i in raw_index:&lt;br /&gt;
	 v = msh.verts[i[0]].no&lt;br /&gt;
         out.write('vn %f %f %f\n' % (v.x,v.y,v.z))&lt;br /&gt;
      &lt;br /&gt;
      for i in raw_index:&lt;br /&gt;
	 out.write('vt %f %f\n' % (i[1],i[2]))&lt;br /&gt;
&lt;br /&gt;
      tan = [Blender.Mathutils.Vector(0,0,0) for i in range(0,len(raw_index))]&lt;br /&gt;
      for face in msh.faces:&lt;br /&gt;
        v1 = face.v[1].co - face.v[0].co &lt;br /&gt;
	v2 = face.v[2].co - face.v[0].co&lt;br /&gt;
	t1 = face.uv[1][1] - face.uv[0][1]&lt;br /&gt;
	t2 = face.uv[2][1] - face.uv[0][1]&lt;br /&gt;
	&lt;br /&gt;
	sdir = v1 * t2 - v2 * t1 &lt;br /&gt;
	sdir.normalize()&lt;br /&gt;
	for i in range (0,len (face.v)):&lt;br /&gt;
	  vert = [face.v[i].index,face.uv[i][0],face.uv[i][1]]&lt;br /&gt;
	  tan[lfind(raw_index, vert)] += sdir&lt;br /&gt;
      &lt;br /&gt;
      for i in range (0,len(raw_index)):&lt;br /&gt;
	 normal = msh.verts[raw_index[i][0]].no&lt;br /&gt;
	 otan = tan[i] - normal *  Blender.Mathutils.DotVecs( tan[i], normal )&lt;br /&gt;
	 otan.normalize()&lt;br /&gt;
	 out.write('tan %f %f %f\n' % (otan.x,otan.y,otan.z))&lt;br /&gt;
&lt;br /&gt;
      for face in msh.faces:&lt;br /&gt;
        out.write('f')&lt;br /&gt;
	for i in range (0,len (face.v)):&lt;br /&gt;
	   vert = [face.v[i].index,face.uv[i][0],face.uv[i][1]]&lt;br /&gt;
  	   out.write(' %i' % (lfind(raw_index, vert)))&lt;br /&gt;
	out.write('\n')&lt;br /&gt;
	&lt;br /&gt;
  out.close()&lt;br /&gt;
  Exit()&lt;br /&gt;
&lt;br /&gt;
#Blender.Window.FileSelector(write, &amp;quot;Export&amp;quot;)&lt;br /&gt;
write (&amp;quot;out.obj&amp;quot;)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Zusätzliche Optionen Abfragen==&lt;br /&gt;
&lt;br /&gt;
Ein Exporter ist schön, etwas unschön ist es bis jetzt, das die Ausgabe immer statisch nach dem gleichem Schema erfolgt. Um bestimmte Optionen aktivirbar und deaktivirbar zu machen, ist es nötig einen Dialog zu öffene, dessen eingaben in globalen Variablen abgelegt werden. Aus codetechnischer sicht ist es einfacher die Optionen vor dem Filedialog abzufragen.&lt;br /&gt;
Damit ein Dialog verwendet werden kann sind ein paar Änderungen am Code nötig.&lt;br /&gt;
&lt;br /&gt;
Folgende Funktionen und globale Variablen müssen eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
num_of_vertexgroups = Create(4)&lt;br /&gt;
TMenu = Create(1)&lt;br /&gt;
EVENT_NOEVENT = 1&lt;br /&gt;
EVENT_EXPORT  = 2&lt;br /&gt;
EVENT_CANCEL  = 3&lt;br /&gt;
&lt;br /&gt;
def draw():&lt;br /&gt;
  global num_of_vertexgroups,TMenu&lt;br /&gt;
  global EVENT_NOEVENT,EVENT_EXPORT&lt;br /&gt;
  glClear(GL_COLOR_BUFFER_BIT)&lt;br /&gt;
  glRasterPos2d(10, 125)&lt;br /&gt;
  Text(&amp;quot;DGL Exporter Options&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  TMemu = Menu(&amp;quot;Normal|Normal+Tangent|TBN-Matrix&amp;quot;,EVENT_NOEVENT,10,75,210,18,  1)&lt;br /&gt;
  num_of_vertexgroups= Number(&amp;quot;No of Vertgroups: &amp;quot;, EVENT_NOEVENT, 10, 55, 210, 18,num_of_vertexgroups.val, 0, 10, &amp;quot;Number of Vertgroups per Vertex&amp;quot;);&lt;br /&gt;
  Button(&amp;quot;Export&amp;quot;,EVENT_EXPORT, 140, 10, 80, 18)&lt;br /&gt;
  Button(&amp;quot;Cancel&amp;quot;,EVENT_CANCEL, 10, 10, 80, 18)&lt;br /&gt;
  &lt;br /&gt;
def event(evt, val):&lt;br /&gt;
   if (evt == QKEY and not val): &lt;br /&gt;
      Exit()&lt;br /&gt;
&lt;br /&gt;
def bevent(evt):&lt;br /&gt;
  global EVENT_NOEVENT,EVENT_EXPORT&lt;br /&gt;
  if (evt== EVENT_EXPORT): &lt;br /&gt;
    Blender.Window.FileSelector(write, &amp;quot;Export&amp;quot;)&lt;br /&gt;
  elif (evt == EVENT_CANCEL):&lt;br /&gt;
    Exit()&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Code noch nicht fertig&lt;br /&gt;
&lt;br /&gt;
Die letzte Zeile, welche den Filedialog geöffnet hat, wird durch folgende ersetzt:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
Register(draw, event, bevent)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit die write funktion keine Endloschleife verursacht, sollte sie noch um Exit() ergänst werden.&lt;br /&gt;
&lt;br /&gt;
==Externe Links==&lt;br /&gt;
&lt;br /&gt;
http://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro/Advanced_Tutorials/Python_Scripting/Export_scripts&lt;br /&gt;
[[Kategorie:Anleitung]]&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Blenderexporter&amp;diff=19940</id>
		<title>Blenderexporter</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Blenderexporter&amp;diff=19940"/>
				<updated>2006-12-16T12:46:42Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Zusätzliche Optionen Abfragen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Hier werde ich einige Codeschnipsel zeigen, mit denen man sich einen eigenen Blenderexporter bauen kann. Der Schwerpunkt liegt dabei darauf, die Daten so vorzubereiten, dass sie direkt als VertexBufferObjekt in die Grafikkarte hochgeladen werden können.&lt;br /&gt;
&lt;br /&gt;
Dieses Tutorial, soll kein festes Format beschreiben. Es ist sowohl möglich die Daten sauber in XML zu kapseln, als auch ganz dirty mal eben ein Includierbares C oder Pascalfile zu erzeugen. Der Compiler wird einen dafür aber mit erheblich längeren compelierungszeiten bestrafen.&lt;br /&gt;
&lt;br /&gt;
Prinzipell bin ich der Meinung, das eine eigene Engine nicht zwangshaft mit einem Universalformat wie Collada verwendet werden muss. Auch beliebte Formate wie 3DS haben gewaltige Nachteile, da sie nicht alle Daten speichern können, die beim Arbeiten mit Shadern benötigt werden. 3DS ist eine gut wahl, solang man nicht viel mehr als Vertices, Normals und UV Coordinaten benötigt. Sobald Bones Vertexgruppen, TBN Matrizen und möglicherweise weitere eigene Daten gespeichert werden müssen gibt es große Probleme.&lt;br /&gt;
&lt;br /&gt;
==Aufbau eines Exporters==&lt;br /&gt;
&lt;br /&gt;
Jeder Blenderexporter verfügt über einen Header, in dem Daten stehen, wie er in die Menüstruktur eingefügt wird. Anschließen folgt der Python code. Näheres dazu steht in den Wikibooks.&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
#!BPY&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Name: 'DGL Wiki'&lt;br /&gt;
Blender: 241&lt;br /&gt;
Group: 'Export'&lt;br /&gt;
Tooltip: 'DGL Wiki Exporter'&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import Blender&lt;br /&gt;
&lt;br /&gt;
#Hier werden zusätzliche Funktionen eingefügt, die zum schreiben benötigt werden&lt;br /&gt;
&lt;br /&gt;
def write(filename):&lt;br /&gt;
  out = file(filename, 'w')&lt;br /&gt;
  obj = Blender.Object.GetSelected()[0]&lt;br /&gt;
  msh = obj.getData()&lt;br /&gt;
&lt;br /&gt;
  #hier wird Code eingefügt, der die zu exportierende Daten schreibt&lt;br /&gt;
&lt;br /&gt;
  out.close()&lt;br /&gt;
Blender.Window.FileSelector(write, &amp;quot;Export&amp;quot;)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
code getestet&lt;br /&gt;
&lt;br /&gt;
Wichtig ist, das man bei Python die Einrückungen beachtet. Als erstes wird eine Funktion definiert, die vom Fileexportdialog aus aufgerufen wird. Dabei wird der Filename als Argument übergeben. Die folgenden Zeilen öffnen ein File zum schreiben und hohlen sich die Meshdaten des erstem selektiertem Objektes.&lt;br /&gt;
Starten tut das Script eigendlich erst in der letzten Zeile, die den Exportdialog aufruft.&lt;br /&gt;
&lt;br /&gt;
==Vorbereiten der Daten==&lt;br /&gt;
&lt;br /&gt;
Da OpenGL nicht gut auf die gemischten Quads und Triangles klar kommt ist es sehr Sinnvoll sie gleich am Anfang vor dem Exportieren umzuwandeln:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
def quad2tri(msh):&lt;br /&gt;
  flist=[]&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    if (len(face.v)==3):&lt;br /&gt;
      flist += [face]&lt;br /&gt;
    else:&lt;br /&gt;
      d1 =(msh.verts[face.v[0].index].co.x - msh.verts[face.v[2].index].co.x) ** 2 &lt;br /&gt;
      d1+=(msh.verts[face.v[0].index].co.y - msh.verts[face.v[2].index].co.y) ** 2 &lt;br /&gt;
      d1+=(msh.verts[face.v[0].index].co.z - msh.verts[face.v[2].index].co.z) ** 2 &lt;br /&gt;
      d2 =(msh.verts[face.v[1].index].co.x - msh.verts[face.v[3].index].co.x) ** 2 &lt;br /&gt;
      d2+=(msh.verts[face.v[1].index].co.y - msh.verts[face.v[3].index].co.y) ** 2 &lt;br /&gt;
      d2+=(msh.verts[face.v[1].index].co.z - msh.verts[face.v[3].index].co.z) ** 2 &lt;br /&gt;
      if (d1&amp;lt;d2):&lt;br /&gt;
        flist += [Blender.NMesh.Face([face.v[0],face.v[1],face.v[2]])]&lt;br /&gt;
	flist[len(flist)-1].uv=[face.uv[0],face.uv[1],face.uv[2]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[0],face.col[1],face.col[2]]&lt;br /&gt;
        flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
	&lt;br /&gt;
	flist += [Blender.NMesh.Face([face.v[0],face.v[2],face.v[3]])]&lt;br /&gt;
        flist[len(flist)-1].uv=[face.uv[0],face.uv[2],face.uv[3]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[0],face.col[1],face.col[2]]&lt;br /&gt;
	flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
      else:&lt;br /&gt;
	flist += [Blender.NMesh.Face([face.v[0],face.v[1],face.v[3]])]&lt;br /&gt;
        flist[len(flist)-1].uv=[face.uv[0],face.uv[1],face.uv[3]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[0],face.col[1],face.col[3]]&lt;br /&gt;
	flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
	&lt;br /&gt;
	flist += [Blender.NMesh.Face([face.v[1],face.v[2],face.v[3]])]&lt;br /&gt;
        flist[len(flist)-1].uv=[face.uv[1],face.uv[2],face.uv[3]]&lt;br /&gt;
	flist[len(flist)-1].col=[face.col[1],face.col[2],face.col[3]]&lt;br /&gt;
	flist[len(flist)-1].smooth=face.smooth&lt;br /&gt;
  msh.faces=flist&lt;br /&gt;
  return msh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Das Prinzip ist Relativ leicht zu verstehen. &amp;quot;flist&amp;quot; ist eine Liste in der die neuen Dreiecke zwischengespeichert werden. Dreiecke werden einfach kopiert. Bei Quads wird die kürzere Diagonale zum Teilen gesucht und aus den Daten des Quads zwei neue Triangles erzeugt. Zum Schluss wird  noch die temporäre Liste im Mesh gespeichert und as ganze zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
==Exportieren der Daten==&lt;br /&gt;
&lt;br /&gt;
hier beschreiben ich wie man die wichtigsten Daten exportieren kann. Um ein anderes Format zu erhalten, müssen die Stings entsprechend angepasst werden. Eine neue Zeile erhält man durch &amp;quot;\n&amp;quot; In den Beispielen werde ich mich weitgehend an Werten gekapselt in einem XMLformat halten. Durch simple Modifikationen sind auch andere Formate kein problem.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Möglichkeiten die Vertexdaten zu speichern: Interleaved oder getrennte Blöcke. Beim interleaved Format verliert man die Flexibilität und die Daten werden noch unübersichtlicher. Ein Geschwindigkeitsgewinn ist auch nicht zu erwarten.&lt;br /&gt;
&lt;br /&gt;
In einigen Codestücken wird auffallen, das die Convertierung von Quads nach Triangles immer wieder vorgenommen wird. In einem komplettem Exporten macht es durchaus Sinn, alle Daten erst zu sammel, dann zu sortieren, umwandeln und erst zum Schluss zu schreiben. Dabei wäre es allerdings nicht mehr möglich einzelne Beispiele zu liefern.&lt;br /&gt;
&lt;br /&gt;
Eine besonder Problematik ist, dass Blender Quads beforzugt, jedoch Quads und Triangles gemischt vorliegen können. Um diese Mischung zu vermeiden sollte man entweder den Exporter so schreiben, dass er die Quads in 3 Triangles zerlegt oder vor dem Exportieren alle Quads in Triangles umwandelt und Speichert (Intern bleiben die Daten sonst anscheined immer noch Quads)&lt;br /&gt;
&lt;br /&gt;
Einfachen Text, der keine zu exportierenden Daten enhält lässt sich so in die Datei schreiben. Hier ein möglicher begin der XML Datei:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;yes&amp;quot;?&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier wieder die Einrückung. Sie muss genauso weit eingerück sein wie die vorige Zeile, oder weiter eingerück werden wenn es sich um eine Schleife handelt.&lt;br /&gt;
&lt;br /&gt;
Eine kleines Problem kann entstehen, wenn die letzte Zeile eines Datensatzes kein Komma enthalten darf. Der einfachste Weg ist eine Dummyzeile mit Nullwerten anzuhängen.&lt;br /&gt;
&lt;br /&gt;
===Name des Objektes und Anzahl der Vertices===&lt;br /&gt;
&lt;br /&gt;
In einem XML format ist es nicht alzuwichtig den Objektnamen aus Blender zu behalten. Jedoch kann es sehr nützlich sein wenn man andere Formate schreibt oder mehrere Objekte in einer Datei speichert. Wir bringen diese Daten einfach im VBO Tag unter, welches alle unsere Vertexdaten kapseln wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
 out.write('&amp;lt;vbo name=&amp;quot;%s&amp;quot; verts=&amp;quot;%i&amp;quot; type=&amp;quot;GL_TRIANGLE&amp;quot;&amp;gt;\n' % (msh.name, len(msh.faces)*3))&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Schluss sollte noch folgende Zeile angehängt werden um den VBO tag wieder zu schließen:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;/vbo&amp;gt;') &lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Vertices===&lt;br /&gt;
Da man den Index eines Vertexarray nicht in einem VBO verpacken kann. Ist es besser die Triangles nicht indiziert in einem VBO zu speichern. Der Speicherbedarf ist hier allerdings höher. Trotz der erhöten Datenmenge scheint diese Variante schneller zu sein, da hier keine Arrays vom Prozessor abgearbeitet werden müssen.&lt;br /&gt;
Unter der Annahme, das nur Triangles vorhanden sind, reicht dieser Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
 out.write('&amp;lt;vertices comp=&amp;quot;3&amp;quot;&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
      out.write( ' %f %f %f' % (msh.verts[vert.index].co.x, msh.verts[vert.index].co.y, msh.verts[vert.index].co.z))&lt;br /&gt;
    out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/vertices&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Textur-Koordinaten===&lt;br /&gt;
&lt;br /&gt;
Kaum schwerer als die Vertexdaten sind die Texturkoordinaten zu exportieren. Da die Texturkoordinaten innerhalb der Faces gespeichert werden. Sinvollerweise überprüfen wir voher noch ob überhaupt Texturdaten vorhanden sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  if (msh.hasFaceUV()==1):&lt;br /&gt;
    out.write('&amp;lt;texturecoords comp=&amp;quot;2&amp;quot;&amp;gt;\n')&lt;br /&gt;
    for face in msh.faces:&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f %f %f %f\n' % (face.uv[0][0],face.uv[0][1],face.uv[1][0],face.uv[1][1],face.uv[2][0],face.uv[2][1]) )&lt;br /&gt;
    out.write('&amp;lt;/texturecoords&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Normals===&lt;br /&gt;
&lt;br /&gt;
Normalvektoren sind in Blender sowohl per Vertex als auch per Face abgespeichert. Abhängig, davon ob eine Fläche als Smooth (per Vertex) oder Solid (per Face) dargestellt wird, werden die die entsprechenden Normalvektoren ausgewählt. Damit auch Klötze mit Kanten dargestellt werden können müssen beide Fälle berücksichtigt werden. Im Fall Solid müssen für alle Vertices der Fläche der Normalvektor der Fläche verwendet werden. Im Fall Smooth muss hier der Normalvektor der Vertices benutz werden.&lt;br /&gt;
Auf keinen Fall sollte man nun die Vervielfachung der Vertices als Problem ansehen, da die verschiedenen Normalvektoren, diesen Nachteil wieder volkommen ausgleichen.&lt;br /&gt;
 &lt;br /&gt;
Tip: Da ganze Flächen als Solid keinerlei Optische Rundungen zulassen, ist der einzige Weg, echte Kanten an runden Objekten zu erzeugen in dem man das Mesch an der Stelle splittet. Leider muss man zum Splitten einen vollständigen Edgeloop auswählen. An Stellen die nicht kantig sein sollen muss man dann beide Vertices Makieren und mit &amp;quot;remove doubles&amp;quot; vereinen. &lt;br /&gt;
&lt;br /&gt;
Auch hier ersst einmal ein einfaches Beispiel was haufig schon genügen sollte:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;normals&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
     for vert in face.v:&lt;br /&gt;
        out.write( ' %f, %f, %f,' % (msh.verts[vert.index].no.x, msh.verts[vert.index].no.y, msh.verts[vert.index].no.z) )&lt;br /&gt;
     out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/normals&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Besser wird es, wenn Smooth/Solid berücksichtigt wird. &lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;normals&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f' % (msh.verts[vert.index].no.x, msh.verts[vert.index].no.y, msh.verts[vert.index].no.z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f, %f, %f,' % (face.no.x, face.no.y, face.no.z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/normals&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Tangenvektor / TBN Matrix ===&lt;br /&gt;
&lt;br /&gt;
Ohne die TBN Matrix lässt sich in den shadern kein sinvolles Bumpmapping durchführen. Weder Dot3, Offset, Parallax  noch &lt;br /&gt;
Reliefmapping sind ohne TBN Matrix möglich.&lt;br /&gt;
Eine TBN Matrix besteht aus drei Vektoren, die den Texturespace aufspannen:&lt;br /&gt;
&lt;br /&gt;
Normal&lt;br /&gt;
&lt;br /&gt;
Er steht immer Senkrecht zur Oberfläche. Er entspricht genau dem Normalvektor wie wir ihn kennen.&lt;br /&gt;
Beim Paralax und Reliefmapping repräsentiert seine Länge den Masstab für die dritte Texturkoordinate (Im Editor wäre sie W, auch wenn die Texturkoordinaten in OpenGL s, t, p und q sind).&lt;br /&gt;
&lt;br /&gt;
Tangent&lt;br /&gt;
&lt;br /&gt;
Er liegt tangential auf der Textur und ist dort zur U Achse ausgerichtet. Wieder einmal kann man überlegen ob es nun beteutet Senktrecht zum Normal oder Parallel zu Fläche des Dreieckes. Wer keine Kopfschmerzen hat macht sich welche.&lt;br /&gt;
&lt;br /&gt;
Bitangent&lt;br /&gt;
&lt;br /&gt;
Häufig wird er auch Binormal genannt, jedoch beschreibt Bitangent die Funktion besser. Er ist wie der Tangent tangential zur V Achse der Textur ausgerichtet.&lt;br /&gt;
Wer meint Bitangent lässt sich durch das Kreutzprodukt von Normal und Tangend berechnen, hat nur recht wenn die Textur keine Scherung enthällt.&lt;br /&gt;
&lt;br /&gt;
So lange die Textur nicht verzert wird, ist eine normalisierte TBN Matrix problemlos verwendbar, wenn jedoch die Tiefenkomponente der Textur nicht auf kubischen Texeln basiert, ist es sinvoller die Korrektur im Shader vorzunehmen, als die Komonenten dern TBN Matrix zu verzerren.&lt;br /&gt;
&lt;br /&gt;
Da ich es jetzt anscheinend verstanden habe wie ich die zusätzlichen komponenten der TBN Matrix berechnen kann. Kommt hier der Code zum erzeugen der Tangent und Bitangentvektoren pro Face und Vertex:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
def createFaceTan(msh):&lt;br /&gt;
  ftan = []&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    tan = msh.verts[face.v[2].index].co - msh.verts[face.v[0].index].co&lt;br /&gt;
    if (face.uv[2][1] != face.uv[1][1]):&lt;br /&gt;
      m = (face.uv[2][1]-face.uv[0][1])/(face.uv[2][1]-face.uv[1][1])&lt;br /&gt;
      tan += (msh.verts[face.v[1].index].co - msh.verts[face.v[2].index].co) * m&lt;br /&gt;
    tan.normalize()&lt;br /&gt;
    ftan += [tan]&lt;br /&gt;
  return ftan&lt;br /&gt;
&lt;br /&gt;
def createFaceBit(msh):&lt;br /&gt;
  fbit = []&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    bit = msh.verts[face.v[1].index].co - msh.verts[face.v[0].index].co&lt;br /&gt;
    if (face.uv[1][0] != face.uv[2][0]):&lt;br /&gt;
      m = (face.uv[1][0]-face.uv[0][0])/(face.uv[1][0]-face.uv[2][0])&lt;br /&gt;
      bit += (msh.verts[face.v[2].index].co - msh.verts[face.v[1].index].co) * m&lt;br /&gt;
    bit.normalize()&lt;br /&gt;
    fbit += [bit]&lt;br /&gt;
  return fbit&lt;br /&gt;
&lt;br /&gt;
def interpolate(msh,ftan):&lt;br /&gt;
  vtan = []&lt;br /&gt;
  for vert in msh.verts:&lt;br /&gt;
    vtan += [Blender.NMesh.Vert().co]&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    if (face.smooth == 1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        vtan[vert.index] += ftan[vert.index]&lt;br /&gt;
  for i in range(0,len(msh.verts)):&lt;br /&gt;
    vtan[i].normalize()&lt;br /&gt;
  return vtan	&lt;br /&gt;
&lt;br /&gt;
ftan = createFaceTan(msh)&lt;br /&gt;
vtan = interpolate(msh,ftan)&lt;br /&gt;
fbit = createFaceBit(msh)&lt;br /&gt;
vbit = interpolate(msh,fbit)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Hier noch der Link zum Artikel wo ich die Berechnung erkläre:&lt;br /&gt;
http://wiki.delphigl.com/index.php/TBN_Matrix&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit folgenden Codeschnipseln, lassen sich Tangent, Bitanget und die TBN Matrix ausgeben. Sinvoll ist es natürlich nur die Einzelkomponenten zusätzlich zum Normalvektor zu schreiben oder die TBN Matrix ohne Normalen zu verwenden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;tan&amp;gt;\n')&lt;br /&gt;
  for i in range(0,len(msh.faces)):&lt;br /&gt;
    face = msh.faces[i]&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f' % (vtan[vert.index].x, vtan[vert.index].y, vtan[vert.index].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f %f %f' % (ftan[i].x, ftan[i].y, ftan[i].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/tan&amp;gt;\n')&lt;br /&gt;
  &lt;br /&gt;
  out.write('&amp;lt;bit&amp;gt;\n')&lt;br /&gt;
  for i in range(0,len(msh.faces)):&lt;br /&gt;
    face = msh.faces[i]&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
        out.write( ' %f %f %f' % (vbit[vert.index].x, vbit[vert.index].y, vbit[vert.index].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f %f %f' % (fbit[i].x, fbit[i].y, fbit[i].z))&lt;br /&gt;
      out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/bit&amp;gt;\n')&lt;br /&gt;
  &lt;br /&gt;
  out.write('&amp;lt;tbn&amp;gt;\n')&lt;br /&gt;
  for i in range(0,len(msh.faces)):&lt;br /&gt;
    face = msh.faces[i]&lt;br /&gt;
    if (face.smooth==1):&lt;br /&gt;
      for vert in face.v:&lt;br /&gt;
	out.write( ' %f %f %f' % (vtan[vert.index].x, vtan[vert.index].y, vtan[vert.index].z))&lt;br /&gt;
        out.write( ' %f %f %f' % (vbit[vert.index].x, vbit[vert.index].y, vbit[vert.index].z))&lt;br /&gt;
        out.write( ' %f %f %f\n' % (msh.verts[vert.index].no.x, msh.verts[vert.index].no.y, msh.verts[vert.index].no.z))&lt;br /&gt;
    else:&lt;br /&gt;
      for vert in range(0,3):&lt;br /&gt;
        out.write( ' %f %f %f' % (ftan[i].x, ftan[i].y, ftan[i].z))&lt;br /&gt;
        out.write( ' %f %f %f' % (fbit[i].x, fbit[i].y, fbit[i].z))&lt;br /&gt;
	out.write( ' %f %f %f\n' % (face.no[0], face.no[1], face.no[2]))&lt;br /&gt;
  out.write('&amp;lt;/tbn&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Warnung: Die Vektoren scheinen alle Senkrecht zu einander zu stehen, jedoch ist noch nicht überprüft ob die Matrizen wirklich brauchbar sind. Es wäre durchaus möglich, dass noch komponenten verdreht oder gespiegelt sind.&lt;br /&gt;
&lt;br /&gt;
Aufgrund des Mangels an Atributevariablen, ist es nicht sehr Sinvoll die volle TBN Matrix zu übergeben. Sinvoller ist es nur den Tangendvektor (Bitangent kann durch ein Kreutzprodukt neu berechnet werden) oder den Tangentvektor zumammen mit dem Bitangentvektor als Atribute zu übergeben.&lt;br /&gt;
&lt;br /&gt;
===Vertuxgruppen / Bones ===&lt;br /&gt;
&lt;br /&gt;
Ohne Vertexgruppen und Bones lassen sich keine Animationen mit Hilfe des Vertexshaders realisieren. Diesen Teil können alle überspringen, die keine Vertexshader zum Animieren benutzen wollen. &lt;br /&gt;
Die Daten liegen in Blender in einer für Vertexshader leicht unbrauchbaren Form vor und müssen etwas aufbereitet werden. In jeder Vertexgruppe, auf die man auch noch über Ihren Namen zugreifen muss, liegt eine Liste mit der Vertexnummer und der Gewichtung.&lt;br /&gt;
Für einen Vertexshader benötigen wir pro Vertex einen Index, der die Vertexgruppe/Bone beschreibt und die Gewichtung. Außerdem müssen wir uns voher entscheiden, wie viele Bones wir maximal pro Vertex berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
Bei Mangel an &amp;quot;attribute&amp;quot; Variablen macht es Sinn, die Gewichtung (muss kleiner als 1 sein) mit den Indizies zu addieren. Im Shader könnte man die dann wieder herausrechnen. Auf heutiger Hardware sind 16 Atribute Variablen möglich.&lt;br /&gt;
&lt;br /&gt;
Als erstes den Codeblock zum aufbereiten der Daten. Es ist wichtig, dass die Variable num_of_vertexgroups.val die erwünschte Anzahl von Vertexgruppen enthällt:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  vertGroupData = []&lt;br /&gt;
  groups = msh.getVertGroupNames()&lt;br /&gt;
  for vert in msh.verts:&lt;br /&gt;
    list = []&lt;br /&gt;
    count = 1&lt;br /&gt;
    for group in groups:&lt;br /&gt;
      if (len(msh.getVertsFromGroup(group,0,[vert.index]))==1):&lt;br /&gt;
        list += [(msh.getVertsFromGroup(group,1,[vert.index])[0][1],count)]&lt;br /&gt;
      count += 1&lt;br /&gt;
      list.sort()&lt;br /&gt;
      list.reverse()&lt;br /&gt;
      for i in range(0,num_of_vertexgroups.val):&lt;br /&gt;
        list += [(0.0, 0)]&lt;br /&gt;
      vertGroupData += [(list[0:num_of_vertexgroups.val])]&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Hinweis: Es gibt noch mit getVertexInfluences() eine bessere Methode zum ermitteln welche Vertexgruppe zu einem Vertex gehöhrt. Dann wäre jedoch der einsatz eines Dictonarys nötig.&lt;br /&gt;
 &lt;br /&gt;
Nun noch der Code zum schreiben:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
  out.write('&amp;lt;vertexgroups comp=&amp;quot;%i&amp;quot;&amp;gt;\n&amp;lt;weight&amp;gt;\n' % num_of_vertexgroups.val)&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
      for group in vertGroupData[vert.index]:&lt;br /&gt;
        out.write( ' %f' % (group[0]))&lt;br /&gt;
    out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/weight&amp;gt;\n&amp;lt;index&amp;gt;\n')&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
      for group in vertGroupData[vert.index]:&lt;br /&gt;
        out.write( ' %i' % (group[1]))&lt;br /&gt;
    out.write('\n')&lt;br /&gt;
  out.write('&amp;lt;/index&amp;gt;\n&amp;lt;/vertexgroups&amp;gt;\n')&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Optimierung der Daten==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir uns Hauptsachlich damit beschäftig wie wir die Daten aus der Blenderstruktur auszulesen und in ein Vertexbufferobjekt kompatible daten unzuformen. Wen die Modelle größer werden oder komplette Level in Blender realisiert werden sollen macht es Sinn die Daten so umzusortieren, das Triangles mit ähnlichen Eigenschaften wie Ort oder Ausrichtung nah im Vertexbufferobjekt beieinander liegen.&lt;br /&gt;
&lt;br /&gt;
===Octree===&lt;br /&gt;
&lt;br /&gt;
Beim Octree werden nur die Teile gerender, bei denen voher bekannt ist, dass sie sichtbar sind, leider ist die Baumstruktur eines Octtrees auf dem erstem Blick völlig inkompatibel zu dem linearem Verlauf des Vertexbuffersobjektes. &lt;br /&gt;
&lt;br /&gt;
Um die Faces in den Octree einzusortieren muss von jedem der Schwerpunkt berechnet werden. Die Position im Octree wird mit einer art Hashfunktion berechnet, die erst aus den X Y und Z Koordinaten Integerwerte von 0 bis 1023 bildet und deren Bits so zusammensortiert, dass ein einziger Wert von 0 bis 2^30-1 ensteht. Nach dem die Faces sortiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
def octree(msh):&lt;br /&gt;
  # Boundingbox for Octree. &lt;br /&gt;
  # Warnung: bei mehreren VBOs sollte die gleiche Boundingbox verwendet werden,&lt;br /&gt;
  # damit nur einmal auf sichbarkeit überprüft werden muss&lt;br /&gt;
  mini = msh.verts[0].co * 1.0&lt;br /&gt;
  maxi = msh.verts[0].co * 1.0&lt;br /&gt;
  for vert in msh.verts:&lt;br /&gt;
    mini.x = minimum (mini.x,vert.co.x)&lt;br /&gt;
    mini.y = minimum (mini.y,vert.co.y)&lt;br /&gt;
    mini.z = minimum (mini.z,vert.co.z)&lt;br /&gt;
    maxi.x = maximum (maxi.x,vert.co.x)&lt;br /&gt;
    maxi.y = maximum (maxi.y,vert.co.y)&lt;br /&gt;
    maxi.z = maximum (maxi.z,vert.co.z)&lt;br /&gt;
  size = max (maxi.x-mini.x,maxi.y-mini.y,maxi.z-mini.z)&lt;br /&gt;
  #Hashberechnung&lt;br /&gt;
  optindex = []&lt;br /&gt;
  count = 0&lt;br /&gt;
  for face in msh.faces:&lt;br /&gt;
    center = msh.verts[0].co * 0.0&lt;br /&gt;
    for vert in face.v:&lt;br /&gt;
       center += msh.verts[vert.index].co&lt;br /&gt;
    #range 0.0 ... 1.0&lt;br /&gt;
    center *= 1.0 /( len(face.v) * size * 2.0)&lt;br /&gt;
    center.x += 0.5&lt;br /&gt;
    center.y += 0.5&lt;br /&gt;
    center.z += 0.5&lt;br /&gt;
    ix = int (center.x * 1023)&lt;br /&gt;
    iy = int (center.y * 1023)&lt;br /&gt;
    iz = int (center.z * 1023)&lt;br /&gt;
    sortby  = (ix&amp;amp;512)&amp;lt;&amp;lt;18 | (ix&amp;amp;256)&amp;lt;&amp;lt;16 |(ix&amp;amp;128)&amp;lt;&amp;lt;14 | (ix&amp;amp;64)&amp;lt;&amp;lt;12 |(ix&amp;amp;32)&amp;lt;&amp;lt;10 | (ix&amp;amp;16)&amp;lt;&amp;lt;8 |(ix&amp;amp;8)&amp;lt;&amp;lt;6 | (ix&amp;amp;4)&amp;lt;&amp;lt;4 |(ix&amp;amp;2)&amp;lt;&amp;lt;2 | (ix&amp;amp;1)&amp;lt;&amp;lt;0&lt;br /&gt;
    sortby |= (iy&amp;amp;512)&amp;lt;&amp;lt;19 | (iy&amp;amp;256)&amp;lt;&amp;lt;17 |(iy&amp;amp;128)&amp;lt;&amp;lt;15 | (iy&amp;amp;64)&amp;lt;&amp;lt;13 |(iy&amp;amp;32)&amp;lt;&amp;lt;11 | (iy&amp;amp;16)&amp;lt;&amp;lt;9 |(iy&amp;amp;8)&amp;lt;&amp;lt;7 | (iy&amp;amp;4)&amp;lt;&amp;lt;5 |(iy&amp;amp;2)&amp;lt;&amp;lt;3 | (iy&amp;amp;1)&amp;lt;&amp;lt;1&lt;br /&gt;
    sortby |= (iz&amp;amp;512)&amp;lt;&amp;lt;20 | (iz&amp;amp;256)&amp;lt;&amp;lt;18 |(iz&amp;amp;128)&amp;lt;&amp;lt;16 | (iz&amp;amp;64)&amp;lt;&amp;lt;14 |(iz&amp;amp;32)&amp;lt;&amp;lt;12 | (iz&amp;amp;16)&amp;lt;&amp;lt;10|(iz&amp;amp;8)&amp;lt;&amp;lt;8 | (iz&amp;amp;4)&amp;lt;&amp;lt;6 |(iz&amp;amp;2)&amp;lt;&amp;lt;4 | (iz&amp;amp;1)&amp;lt;&amp;lt;2&lt;br /&gt;
    optindex += [(sortby,count)]&lt;br /&gt;
    count += 1&lt;br /&gt;
  #Umsortierung der Daten&lt;br /&gt;
  optindex.sort()&lt;br /&gt;
  flist=[]&lt;br /&gt;
  for i in optindex:&lt;br /&gt;
    flist += [msh.faces[i[1]]]&lt;br /&gt;
  msh.faces=flist&lt;br /&gt;
  #Hier sollten noch die Verwaltungsdaten für den Octree geschrieben werden&lt;br /&gt;
  #Diese Code fehl allderings noch&lt;br /&gt;
&lt;br /&gt;
  return msh&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Diese Funktion sollte dierekt nach dem umwandeln der Quads in Triangles aufgerufen werden, da die Reihfolge der Triangles geändert wird.&lt;br /&gt;
&lt;br /&gt;
Prinzipiell gibt es für jedes würfelförmige Volumen nur eine Start und Stopindexnummer die beim Rendern übergeben werden muss:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
glDrawArrays( GL_TRIANGLES, start, stop - start);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Grundsätz sollte beachtet werden, dass es bei der Verwendung von VBOs möglichst viele Triangles auf einmal gerendert werden sollen.  Wo die untergrenze Pro volumen liegt lässt sich schwer sagen, es mach aber Sinn, diese jenseits der 1000-10000 anzusetzten.&lt;br /&gt;
&lt;br /&gt;
===Vorsortierung nach Vertexgruppen/Bones===&lt;br /&gt;
&lt;br /&gt;
Es ist zwar noch kein Algoritmus zum sortieren vorhanden, jedoch ist es bei animierten Modellen sinnvoll möglichst ganze Bones auf einmal abzuarbeiten, da ein Bone ganze 12 Uniform Floats im Vertexshader verbraucht (9 für eine Rotationsmatrix und 3 für das Gelenk). Laut GLSL Spezifikation soll man minimal 512 davon haben, was maximal 40 Bones entspricht. Dummerweise scheint es so als wenn einige Grafikkarten nur 256 Uniform Floats zur Verfügung stellen, was zur Folge hat, das nur noch 20 Bones möglich wären.&lt;br /&gt;
Eine primitive Optimierung wäre nur einen halbes Model zu speichen. und für die zweite hälfte das gleiche Mesh gespiegelt mit neuen Bones zu verwenden.&lt;br /&gt;
&lt;br /&gt;
Die Sinvollste Variante ist die schon erzeugten Vertexgruppendaten zum Sortieren zu benutzen: Die Gruppe mit der höchsten Gewichtung wird zum einsortieren benutzt. Alle Vertices die nicht in einer Gruppe sind, landen in einer extra gruppe. Diese Gruppen werde nun so umsortiert, dass Gruppen mit gegenseitigem Einfluss na beieinander landen. und Vertexgruppen die sih nicht beeinflussen weit von einander im VBO entfernt liegen.&lt;br /&gt;
&lt;br /&gt;
==Daten für Indizierte VBOs exportieren==&lt;br /&gt;
&lt;br /&gt;
Lange Zeit hab ich dieses Thema umgangen da der export relativ komplex ist. Alle Daten aus Blender müssen komplett neu umgeornet und neu indiziert werden, da Blender die Texturkoordinaten nicht per Vertex, sondern per Face abspeichert. Als Beispiel wird diesmal ein vereinfachter OBJ exporter dienen, der allerdings um tangentvektoren ergänst wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
#!BPY&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Name: 'VBO Wiki'&lt;br /&gt;
Blender: 241&lt;br /&gt;
Group: 'Export'&lt;br /&gt;
Tooltip: 'VBO Wiki Exporter 3 C version'&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import Blender&lt;br /&gt;
from Blender import NMesh&lt;br /&gt;
from Blender.BGL import *&lt;br /&gt;
from Blender.Draw import *&lt;br /&gt;
import math&lt;br /&gt;
from math import *&lt;br /&gt;
&lt;br /&gt;
def lfind(liste,key):&lt;br /&gt;
    for i in range(0, len(liste)):&lt;br /&gt;
	if liste[i]==key: return i&lt;br /&gt;
&lt;br /&gt;
def write(filename):&lt;br /&gt;
  global num_of_vertexgroups,TBNMenu,Optimise&lt;br /&gt;
  # filename=replace(filename,&amp;quot;.blend&amp;quot;,&amp;quot;.obj&amp;quot;)&lt;br /&gt;
  out = file(filename, 'w')&lt;br /&gt;
  &lt;br /&gt;
  objs = Blender.Object.GetSelected()&lt;br /&gt;
  if (len(objs)==0):&lt;br /&gt;
    objs = Blender.Object.Get()&lt;br /&gt;
  for obj in objs:&lt;br /&gt;
    if (obj.getType()=='Mesh'):&lt;br /&gt;
    &lt;br /&gt;
      msh = obj.getData()&lt;br /&gt;
    &lt;br /&gt;
      #      msh = quad2tri(msh)&lt;br /&gt;
      raw_index = []&lt;br /&gt;
   &lt;br /&gt;
      for face in msh.faces:&lt;br /&gt;
        for i in range (0,len (face.v)):&lt;br /&gt;
           vert = []&lt;br /&gt;
	   vert += [face.v[i].index]&lt;br /&gt;
	   vert += [face.uv[i][0]]&lt;br /&gt;
	   vert += [face.uv[i][1]]&lt;br /&gt;
	   raw_index += [vert]&lt;br /&gt;
	   &lt;br /&gt;
      print len(raw_index)   &lt;br /&gt;
      #print raw_index&lt;br /&gt;
      raw_index.sort()&lt;br /&gt;
      last =raw_index[-1]&lt;br /&gt;
      for i in range(len(raw_index)-2, -1, -1):&lt;br /&gt;
       if last==raw_index[i]:&lt;br /&gt;
	 del raw_index[i]&lt;br /&gt;
       else: last=raw_index[i]&lt;br /&gt;
&lt;br /&gt;
      print len(raw_index)&lt;br /&gt;
   &lt;br /&gt;
      out.write('g Index\n')&lt;br /&gt;
      &lt;br /&gt;
      for i in raw_index:&lt;br /&gt;
	 v = msh.verts[i[0]].co&lt;br /&gt;
         out.write('v %f %f %f\n' % (v.x,v.y,v.z))&lt;br /&gt;
      &lt;br /&gt;
      for i in raw_index:&lt;br /&gt;
	 v = msh.verts[i[0]].no&lt;br /&gt;
         out.write('vn %f %f %f\n' % (v.x,v.y,v.z))&lt;br /&gt;
      &lt;br /&gt;
      for i in raw_index:&lt;br /&gt;
	 out.write('vt %f %f\n' % (i[1],i[2]))&lt;br /&gt;
&lt;br /&gt;
      tan = [Blender.Mathutils.Vector(0,0,0) for i in range(0,len(raw_index))]&lt;br /&gt;
      for face in msh.faces:&lt;br /&gt;
        v1 = face.v[1].co - face.v[0].co &lt;br /&gt;
	v2 = face.v[2].co - face.v[0].co&lt;br /&gt;
	s1 = face.uv[1][0] - face.uv[0][0]&lt;br /&gt;
	t1 = face.uv[1][1] - face.uv[0][1]&lt;br /&gt;
	s2 = face.uv[2][0] - face.uv[0][0]&lt;br /&gt;
	t2 = face.uv[2][1] - face.uv[0][1]&lt;br /&gt;
	&lt;br /&gt;
	sdir = v1 * t2 - v2 * t1 &lt;br /&gt;
	#sdir = Blender.Mathutils.Vector(0,0,1)&lt;br /&gt;
	sdir.normalize()&lt;br /&gt;
	for i in range (0,len (face.v)):&lt;br /&gt;
	  vert = [face.v[i].index,face.uv[i][0],face.uv[i][1]]&lt;br /&gt;
	  tan[lfind(raw_index, vert)] += sdir&lt;br /&gt;
      &lt;br /&gt;
      for i in range (0,len(raw_index)):&lt;br /&gt;
	 #tan[i].normalize&lt;br /&gt;
	 normal = msh.verts[raw_index[i][0]].no&lt;br /&gt;
	 otan = tan[i] - normal *  Blender.Mathutils.DotVecs( tan[i], normal )&lt;br /&gt;
	 #otan = tan[i]&lt;br /&gt;
	 otan.normalize()&lt;br /&gt;
	 out.write('tan %f %f %f\n' % (otan.x,otan.y,otan.z))&lt;br /&gt;
&lt;br /&gt;
      for face in msh.faces:&lt;br /&gt;
        out.write('f')&lt;br /&gt;
	for i in range (0,len (face.v)):&lt;br /&gt;
	   vert = [face.v[i].index,face.uv[i][0],face.uv[i][1]]&lt;br /&gt;
  	   out.write(' %i' % (lfind(raw_index, vert)))&lt;br /&gt;
	out.write('\n')&lt;br /&gt;
	&lt;br /&gt;
  out.close()&lt;br /&gt;
  Exit()&lt;br /&gt;
&lt;br /&gt;
#Blender.Window.FileSelector(write, &amp;quot;Export&amp;quot;)&lt;br /&gt;
write (&amp;quot;dummy.obj&amp;quot;)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Zusätzliche Optionen Abfragen==&lt;br /&gt;
&lt;br /&gt;
Ein Exporter ist schön, etwas unschön ist es bis jetzt, das die Ausgabe immer statisch nach dem gleichem Schema erfolgt. Um bestimmte Optionen aktivirbar und deaktivirbar zu machen, ist es nötig einen Dialog zu öffene, dessen eingaben in globalen Variablen abgelegt werden. Aus codetechnischer sicht ist es einfacher die Optionen vor dem Filedialog abzufragen.&lt;br /&gt;
Damit ein Dialog verwendet werden kann sind ein paar Änderungen am Code nötig.&lt;br /&gt;
&lt;br /&gt;
Folgende Funktionen und globale Variablen müssen eingefügt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
num_of_vertexgroups = Create(4)&lt;br /&gt;
TMenu = Create(1)&lt;br /&gt;
EVENT_NOEVENT = 1&lt;br /&gt;
EVENT_EXPORT  = 2&lt;br /&gt;
EVENT_CANCEL  = 3&lt;br /&gt;
&lt;br /&gt;
def draw():&lt;br /&gt;
  global num_of_vertexgroups,TMenu&lt;br /&gt;
  global EVENT_NOEVENT,EVENT_EXPORT&lt;br /&gt;
  glClear(GL_COLOR_BUFFER_BIT)&lt;br /&gt;
  glRasterPos2d(10, 125)&lt;br /&gt;
  Text(&amp;quot;DGL Exporter Options&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  TMemu = Menu(&amp;quot;Normal|Normal+Tangent|TBN-Matrix&amp;quot;,EVENT_NOEVENT,10,75,210,18,  1)&lt;br /&gt;
  num_of_vertexgroups= Number(&amp;quot;No of Vertgroups: &amp;quot;, EVENT_NOEVENT, 10, 55, 210, 18,num_of_vertexgroups.val, 0, 10, &amp;quot;Number of Vertgroups per Vertex&amp;quot;);&lt;br /&gt;
  Button(&amp;quot;Export&amp;quot;,EVENT_EXPORT, 140, 10, 80, 18)&lt;br /&gt;
  Button(&amp;quot;Cancel&amp;quot;,EVENT_CANCEL, 10, 10, 80, 18)&lt;br /&gt;
  &lt;br /&gt;
def event(evt, val):&lt;br /&gt;
   if (evt == QKEY and not val): &lt;br /&gt;
      Exit()&lt;br /&gt;
&lt;br /&gt;
def bevent(evt):&lt;br /&gt;
  global EVENT_NOEVENT,EVENT_EXPORT&lt;br /&gt;
  if (evt== EVENT_EXPORT): &lt;br /&gt;
    Blender.Window.FileSelector(write, &amp;quot;Export&amp;quot;)&lt;br /&gt;
  elif (evt == EVENT_CANCEL):&lt;br /&gt;
    Exit()&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
Code noch nicht fertig&lt;br /&gt;
&lt;br /&gt;
Die letzte Zeile, welche den Filedialog geöffnet hat, wird durch folgende ersetzt:&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
Register(draw, event, bevent)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit die write funktion keine Endloschleife verursacht, sollte sie noch um Exit() ergänst werden.&lt;br /&gt;
&lt;br /&gt;
==Externe Links==&lt;br /&gt;
&lt;br /&gt;
http://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro/Advanced_Tutorials/Python_Scripting/Export_scripts&lt;br /&gt;
[[Kategorie:Anleitung]]&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19742</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=19742"/>
				<updated>2006-10-09T15:30:58Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Kompression der Matrizen */&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. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 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 oder drei Float4 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 die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern.&lt;br /&gt;
Eine gepackte Matrix kommt mit 8 Floats aus. Für Quarternionen wäre mit zusätzlichem Translationsteil 7 Floats nötig. Einen wirklichenSinn machen Quarternionen im Vertexshader also definitiv nicht&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Überlagerung meherer Animationen===&lt;br /&gt;
&lt;br /&gt;
Sicher werden am Anfang statische Posen ausreichen. Jedoch ist es mit einer Matrixmultiplikation pro Bone möglich zwei Posen zu überlagern. z.B. kann man so verschiedene Posen einer Hand an einen Arm binden. In diesem Fall müssen die Matrizen der Handanimation mit den Matrizen der Körperanimation Multipliziert werden.&lt;br /&gt;
Alle von der Teilanimation nicht betroffenen Matrizen müssen dabei einheitsmatrizen entsprechen, damit die Multiplikation keine Auswirkung hat.&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19741</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=19741"/>
				<updated>2006-10-09T15:24:08Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Quaternionen im Vertexshader */&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. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 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 oder drei Float4 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 die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern.&lt;br /&gt;
Eine gepackte Matrix kommt mit 8 Floats aus. Für Quarternionen wäre mit zusätzlichem Translationsteil 7 Floats nötig. Einen wirklichenSinn machen Quarternionen im Vertexshader also definitiv nicht&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19740</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=19740"/>
				<updated>2006-10-09T15:22:18Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Limits */&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. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 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 oder drei Float4 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 die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19739</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=19739"/>
				<updated>2006-10-09T15:16:56Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Grundlagen */&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. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19738</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=19738"/>
				<updated>2006-10-09T15:14:00Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Vorwort */&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. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl2&amp;diff=19737</id>
		<title>Tutorial glsl2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl2&amp;diff=19737"/>
				<updated>2006-10-08T23:09:37Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* GLSL  Ergänzungen und Beispiele */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GLSL  Ergänzungen und Beispiele =&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
Willkommen zu meinem zweiten Tutorial für die DelphiGL-Community. Da ich kein Freund großer Worte bin (was auch mein Deutsch-Kursleiter immer bemängelt ;) ) werde ich so schnell wie möglich mit dem Wichtigen beginnen. Ich werde nur schnell einiges anmerken:&lt;br /&gt;
Dieses Tutorial sollte nicht als zweiter Teil zu Sascha Willems hervorragendem ersten GLSL-Tutorial angesehen werden, sondern eher als Anhang verstanden werden. Auf keinen Fall empfiehlt es sich, sofort mit diesem Tutorial in die Materie einzusteigen. Arbeitet es einfach direkt nach dem ersten  durch als ob dieses gar nicht aufgehört hat. Zweitens soll in diesem Tutorial im Gegensatz mehr der praktische Part überwiegen. Nach der doch etwas trockenen Materie, die Sascha meiner Meinung nach exzellent aufgearbeitet hat ist etwas Praxis und Anwendung gefragt. Drittens wollte ich noch anmerken, dass ich dieses Tutorial eher als Sammlung mehrerer kleiner Tutorials als ein Großes ansehe. Die einzelnen Teile werden nur bedingt aufeinander aufbauen.&lt;br /&gt;
&lt;br /&gt;
== Ergänzungen ==&lt;br /&gt;
Im Laufe meiner eigenen, ersten Schritte im Bereich der [[Shader]]entwicklung sind mir selbst einige Dinge aufgefallen, die nicht ganz unerwähnt bleiben sollten, da sie schnell für Frust sorgen können:&lt;br /&gt;
&lt;br /&gt;
Die NVidia-Treiber und ihre Pendants von ATI sind unterschiedlich tolerant was die Compilierung der Shader-Quellcodes angeht. Aus Kompatibilitätsgründen empfehle ich durchgehend für Zahlen, die in eine Float-Variable hineingerechnet werden, keine Integerwerte zu verwenden. Ganz konkret: &lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
float TestVariable = 1.0 / 2 &lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
ist den offiziellen Spezifikationen nach nicht zulässig. Die zwei muss wenn dann als Float (2.0) geschrieben werden. NVidia-Karten werden zwar beim Starten weder eine Warnung noch einen Fehler anzeigen, ATI-Karten weisen den Shader dagegen jedoch strikt zurück. Gewöhnt es euch deswegen an, einfach so gut wie immer &lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
float TestVariable = 1.0 / 2.0&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
zu schreiben.&lt;br /&gt;
&lt;br /&gt;
Da OpenGL eine Statemachine ist bleiben die Shader, wenn sie einmal per [[glUseProgramObjectARB]](LichtShader) aktiviert wurden, solange aktiv bis sie wieder per glUseProgramObjectARB(0) deaktiviert werden. Ihr könnt wirklich verdammt viel Rechenzeit sparen, wenn Ihr die Shader-Programme nur auf gewollte Objekte anwendet.&lt;br /&gt;
&lt;br /&gt;
Bei Shadern ist eine Struktur extrem wichtig, um das Ganze übersichtlich zu halten. Glaubt es mir! Vor allem am Anfang werdet ihr bei etwas komplexeren Shadern nur schwer den Überblick behalten können. Überlegt euch vielleicht ein System, wann ihr Variablen deklariert, wie ihr kommentiert usw. Shader sind hochmathematisch und oft hat man bald vergessen was eine Zeile bewirken soll, weil ihr so taktisch gerechnet habt. Dann könnte ein Hinweis nicht schaden.&lt;br /&gt;
&lt;br /&gt;
In Shadern gibt es sowas Schönes, dass schimpft sich Interpolation von varying Variablen. Durch Interpolation werden Berechungen, die im Vertexshader auf einzelne Vertices angewendet werden, automatisch im Fragmentshader für jedes Fragment angewendet.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel: &lt;br /&gt;
&lt;br /&gt;
Wenn ihr im Vertexshader die Variable ''pos'' mit der Vertexposition belegt, dann hat sie beim Auslesen im Fragmentshader die genaue Position des Fragments. Genauso verhält es sich beispielsweise mit Texturkoordinaten. Es hat mir ganz schön Kopfzerbrechen bereitet bis ich das verstanden hatte. Eventuell ist meine Erklärung lückenhaft oder schlicht falsch. Bis jetzt hat es mir aber noch keine Probleme bereitet.&lt;br /&gt;
&lt;br /&gt;
Wer C++ kennt, der wird natürlich wissen, dass man andere Source-Files per ''#include'' einbinden kann. Damit kann man seine Shader sehr schön strukturieren.&lt;br /&gt;
&lt;br /&gt;
Noch ein paar Informationen zu [[glUniform]] bzw. [[glVertexAttrib]] die einem sehr viel Kopfzerbrechen sparen können. Bildlich gesprochen bezieht sich glUniform nämlich auf ganze Polygone, hat seinen Platz also vor [[glBegin]]. Wird es in einem glBegin/glEnd-Block eingesetzt wird zwar kein Fehler angezeigt aber die Werte werden einfach nicht übergeben. Natürlich braucht man auch eine Funktion wie glVertexAttrib, die Werte für einen Vertex setzt. Diese Funktion kann dann ruhig auf jeden Vertex mit anderen Werten angewendet werden. Einen kleinen Nachteil gibt es aber trotzdem. Sobald ihr  glVertexAttrib verwendet, werden [[glVertex]], [[glNormal]] und [[glTexCoord]] nutzlos. Diese Funktionen machen eigentlich auch nichts anderes als Vertexattribute zu setzen. Nun hat man die Wahl. Entweder man übergibt auch Position, Normalen und Texturkoordinaten über glVertexAttrib oder man wendet Trick 17 an und übergibt Vertexattribute mit Multitexturkoordinaten. Die kann man dann im Shader ganz bequem auslesen. Vielen Dank an Lars Middendorf für diesen Tipp!&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
=== Ein Shader, der die Hardware T&amp;amp;L- Einheit simuliert ===&lt;br /&gt;
Fangen wir mit einer einfachen Aufgabe an. Dem schrittweisen Aufbau eines Shaders, der eigentlich nichts anderes macht als das, was OpenGL ohne Shader auch machen würde. Ziemlich sinnlos ;). Aber ich glaube als Übung bietet sich das recht schön an. Beginnen wir mit dem leeren Shader, der nur das Nötigste enthält:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Fragmentshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = 1.0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Wer in Saschas Tutorial aufgepasst hat, dem dürfte klar sein, dass dieser Vertexshader jeden Vertex an seine Position setzt und der Fragmentshader jedes zu einem Polygon gehörende [[Pixel]] weiss einfärbt. Nun kommt schon der nächste Schritt: Wir färben das Polygon nicht mehr weiss sondern mit der Farbe, die wir in OpenGL immer per [[glColor]] angeben. Ein kurzer Blick in die Referenz offenbart uns die vordeklarierte Variable ''gl_FrontColor''. Dieser übergeben wir jetzt im Vertexshader den Wert ''gl_Color''. Das ist die Farbe, die wir im Programmcode per glColor angegeben haben:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;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;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Im [[Fragment]]shader lesen wir den Wert, den wir im Vertexshader an ''gl_FrontColor'' gegeben haben, wieder mit ''gl_Color'' aus.&lt;br /&gt;
&lt;br /&gt;
Fragmentshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = gl_Color;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
[[bild:Tutimg_glsl_ext_schritt1.jpg|256px]]&lt;br /&gt;
&lt;br /&gt;
Voilà! Das ist ja schon einmal ein schöner Anfang. Aber in welchem 3D-Programm gibt es bloß einfarbige Polygone? Also müssen wir jetzt noch Texturen hinzufügen. Erst einmal arbeiten wir nur mit einer Textureinheit. Wie gewohnt ladet ihr eine Textur, bindet diese per [[glBindTexture]] und weist ihr Koordinaten zu. Den Vertexshader lassen wir jetzt erst einmal die Texturkoordinaten auslesen:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Diese Koordinate wird dann interpoliert und der Fragmentshader liest dann für jedes Fragment mit diesen Koordinaten die Textur aus und gibt ''gl_FragColor'' die Farbe. Dazu deklarieren wir am Anfang eine uniform-Variable für die Textur. Vorerst übergeben wir aus dem Programmcode dieser Variable keinen Wert. Ich werde später darauf zurückkommen. Sie teilt dem Fragmentshader nur mit in welcher Textureinheit er nach der Textur suchen soll. In diesem Fall ist der Wert also 0, bzw. ein Pointer auf die Textur in der Einheit 0. Fragt mich aber nicht, warum man diesen Wert nicht direkt eingeben kann O_o!&lt;br /&gt;
&lt;br /&gt;
Fragmentshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(Texture0, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
[[bild:Tutimg_glsl_ext_schritt2.jpg|256px]]&lt;br /&gt;
&lt;br /&gt;
Sieht ja schon einmal recht ansehnlich aus. Ohne viele Umschweife komme ich gleich zum [[Multitexturing]]. Dazu müssen wir zuerst in unseren Programmcode gehen. Hier belegen wir zwei Textureinheiten mit....ja...mit Texturen (immer diese verdammten Wiederholungen, mein Deutschkursleiter würde mich hauen). Danach kommt wieder etwas Spezifisches zu Shadern: &lt;br /&gt;
Wir weisen den uniform-Variablen (''uniform sampler2D Texture0'') im Shader ihre Textureinheit zu.&lt;br /&gt;
&lt;br /&gt;
Programmcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;glActiveTexture(GL_TEXTURE0);&lt;br /&gt;
glBindTexture(GL_TEXTURE_2D, Textur);&lt;br /&gt;
glActiveTexture(GL_TEXTURE1);&lt;br /&gt;
glBindTexture(GL_TEXTURE_2D, Textur2);&lt;br /&gt;
&lt;br /&gt;
glUniform1iARB(glGetUniformLocationARB(shader, 'Texture0'), 0);&lt;br /&gt;
glUniform1iARB(glGetUniformLocationARB(shader, 'Texture1'), 1);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun geht es wieder ab in den Shadercode. Wieder übergeben wir hier nur die Texturkoordinaten. Wenn für die unterschiedlichen Textureinheiten dieselben Texturkoordinaten gesetzt wurden würde der Shader von vorhin ausreichen. So spart man sich eine Zeile. Soviel zur Optimierung ;).&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&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;
 gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Im Fragmentshader auch nichts wirklich Neues. Wir binden die zweite Textur ein und bringen sie mit ''gl_FragColor'' ins Spiel. Ich hab im Beispielcode einfach mal beide Texturen multipliziert aber ihr könnt damit eigentlich anstellen was ihr wollt. Probiert einfach mal ein paar Sachen aus!&lt;br /&gt;
&lt;br /&gt;
Fragmentshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
 void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(Texture0, vec2(gl_TexCoord[0]))&lt;br /&gt;
              * texture2D(Texture1, vec2(gl_TexCoord[1]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
[[bild:Tutimg_glsl_ext_schritt3.jpg|256px]]&lt;br /&gt;
&lt;br /&gt;
Sodala, is ja schon was. *überleg* was gehört denn noch zur Standard-OGL-Ausrüstung? Hmm, achja, Licht! OpenGL arbeitet ja normalerweise nur mit Per-Vertex-Berechnungen. Das wird schon ein bisschen anspruchsvoller. Wir werden ein wenig Mathematik betreiben müssen. Aber das werden wir schon wuppen! Außerdem ist mir aufgefallen, dass wenn man das ganze selber gemacht hat man das OpenGL-Licht auch gleich viel besser versteht. Als erstes empfehle ich euch einen Blick in folgendes Dokument von Tom Nuydens:&lt;br /&gt;
[http://www.delphi3d.net/articles/viewarticle.php?article=phong.htm Phong For Dummies]&lt;br /&gt;
&lt;br /&gt;
In diesem Dokument erhaltet ihr einen Einblick in das derzeit meist verwendete Beleuchtungsmodell. Es ist nicht perfekt realistisch, kommt dem aber recht nahe und ist sehr ressourcensparend. Wichtig ist für uns hier nur der Diffuse-Term. Diese Gleichung sagt uns im Prinzip nur, ob ein Vertex beleuchtet wird oder nicht. Außerdem werden die Ränder schön gefadet. Mit Per-Pixel-Lighting kommt dann später noch der Specular-Term dazu, der die Oberfläche glänzen lässt. Weil die Glanzfläche so klein ist macht das hier aber noch keinen Sinn, denn die Wahrscheinlichkeit, dass sie auf ein Vertex fällt ist ziemlich gering.&lt;br /&gt;
&lt;br /&gt;
Nun aber ran an die Arbeit. Als erstes baut ihr in eurem Programmcode die Standard-OpenGL-Beleuchtung ganz ohne Shader ein und schaut, ob es funktioniert. Damit können mögliche Fehler nur noch am Shadercode liegen. Dann bindet ihr den Shader ein. Für die Berechnung brauchen wir zwei Vektoren: Den Vektor von unserem Vertex zur Lichtquelle und die Flächennormale. Um Ersteren zu berechnen, multiplizieren wir die Position unseres Vertex mit der Modelviewmatrix und subtrahieren das Ergebnis von der Position der Lichtquelle (''gl_LightSource[0].position''):&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 ...&lt;br /&gt;
 vec3 Position = vec3(gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
 vec3 Light = vec3(normalize(vec3(gl_LightSource[0].position) - Position));&lt;br /&gt;
 ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Die Flächennormale können wir im Vertexshader jedoch nicht berechnen, da dieser nur mit einzelnen Vertices arbeiten kann, für die Berechnung aber mindestens drei notwendig sind. Also berechnen wir sie im Programmcode. Wie das geht, steht in folgendem DGL-Tutorial: [[Tutorial_Lineare_Algebra|Lineare Algebra]].&lt;br /&gt;
Im Programmcode übergebt ihr die Normale wie gewohnt per glNormal und im Shader lesen wir sie dann ganz einfach mit ''gl_Normal'' aus. Die Normale multiplizieren wir noch schnell mit der Normalmatrix:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
vec3 Normal = normalize(gl_NormalMatrix * gl_Normal);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Nun können wir endlich die Beleuchtung berechnen. Wie der ein oder andere bereits wissen dürfte, setzt sich die Beleuchtung in dem von unserem verwendeten Modell aus dem Ambient- und dem Diffuse-Term zusammen. Der Ambient-Term bestimmt eigentlich nur was für eine Farbe ein Pixel haben soll, der überhaupt nicht beleuchtet wird. Den berechnen wir einfach indem wir den Ambient-Wert der Lichtquelle mit dem des Materials multiplizieren:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
vec3 Ambient = vec3(gl_FrontMaterial.ambient) * vec3(gl_LightSource[0].ambient);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
So. Nun kommt der Clou des Ganzen: Wir berechnen den Diffuse-Term! Aus dem oben verlinkten Dokument von Delphi3D.net holen wir uns folgende Formel:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
...   &lt;br /&gt;
Diffuse = max(dot(Normal, Light), 0.0);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Die Funktion ''dot'' berechnet eigentlich nur den Kosinus des Winkels zwischen den beiden Vektoren Normal und Light (mehr dazu in o.g. Tutorial von DGL). Dadurch bekommen wir automatisch einen nichtlinearen Verlauf der Beleuchtung. ''max'' vergleicht die Werte x und y und liefert automatisch den höheren der beiden zurück. So erreichen wir, dass wir keinen Wert kleiner 0 bekommen. Damit auch das diffuse Licht eine Farbe bekommt multiplizieren wir noch schnell mit den jeweiligen Farben der Lichtquelle und des Materials:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
Diffuse *= gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Dann weisen wir gl_FrontColor nur noch die Werte zu, die wir berechnet haben und geben dem Ganzen noch eine vierte Dimension:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = vec4(Diffuse + Ambient, 1.0);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Nun noch schnell im Fragmenthader gl_FragColor einen Wert zuweisen:&lt;br /&gt;
&lt;br /&gt;
Fragmentshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = gl_Color;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Die Anfangs erwähnte Interpolation sorgt automatisch dafür, dass die Farbe von Vertex zu Vertex schön weich verläuft.&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_glsl_ext_schritt4.jpg|256px]]&lt;br /&gt;
&lt;br /&gt;
Warum die Farben nicht ganz mit der OpenGL-hauseigenen Beleuchtung zusammenpassen, kann ich leider nicht sagen. Zum Abschluss möchte ich euch gerne noch zeigen, wie ihr per Shader Cubemaps einbaut, vor allem für so schöne Effekte, wie spiegelndes Wasser solltet ihr diese Technik schon beherrschen. Da ich euch nicht mit dem Laden der Cubemap langweiligen will, fangen wir in der Renderprozedur an. Ein geeigneter Loader für die Texturen wäre beispielsweise eine modifizierte Version von Lossy eX' [[glbitmap_loader|glBitmap]].&lt;br /&gt;
Im Quelltext binden wir einfach die Cubemap für die [[glbitmap_loader|glBitmap]] üblich mit FCubeMap.Bind;&lt;br /&gt;
Das Objekt, auf welches draufprojeziert werden soll muss Texturkoordinaten und eine Normale haben. Das sollte eigentlich kein Problem sein. Nun kommt der Shader dran. Wir deklarieren wieder eine uniform-Textur, diesmal aber nicht ''sampler2D'' sondern ''samplerCube''. Eigentlich logisch. Um jetzt für jedes Pixel unseres Polygons den geeigneten Wert aus der Cubemap auszulesen nehmen wir die normale Texturkoordinate und addieren die Flächennormale dazu. Dass ergibt wiederum eine dreidimensionale Texturkoordinate, die wir in die Shaderfunktion ''textureCube'' einlesen, die sich fast genauso wie ''texture2D'' benutzen lässt:&lt;br /&gt;
&lt;br /&gt;
Fragmentshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform samplerCube Texture0;&lt;br /&gt;
&lt;br /&gt;
varying vec3 normal;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec3 TexCoord = vec3(gl_TexCoord[0]);&lt;br /&gt;
 gl_FragColor= textureCube(Texture0, normal + TexCoord);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
[[bild:Tutimg_glsl_ext_schritt5.jpg|256px]]&lt;br /&gt;
&lt;br /&gt;
Damit haben wir unsere selbstprogrammierte Hardware T&amp;amp;L-Einheit schon fertig! War doch gar nicht so schlimm. Im Folgenden entfernen wir uns dann ein bisschen von der herkömmlichen Programmiererei und machen mal ein paar schöne Effekte.&lt;br /&gt;
&lt;br /&gt;
=== Per-Pixel-Lighting ===&lt;br /&gt;
Ein wirklich schöner Effekt, den man auch in Spielen bisher recht selten sieht. &lt;br /&gt;
Eigentlich haben wir im Per-Vertex-Lighting schon alles gemacht. Wir müssen nun nur unsere Berechnungen, die wir Per-Vertex durchgeführt haben, in den Fragmentshader verlegen. Und dann berechnen wir noch den Specularwert, der angibt wie sich das Licht spiegelt und zurückgeworfen bzw. dem Betrachter zugeworfen wird. Um diesen Wert zu berechnen gibt es zwei Lösungsmöglichkeiten, die sich aber nicht sehr unterscheiden. Es handelt sich um sogenanntes Phong bzw Blinn-Phong Lighting. Wir werden Phong-Lighting einbauen, das Blinn-Phong könnt ihr ja als Übungsaufgabe machen ;). Die geometrischen Grundlagen findet ihr wieder in oben genanntem Artikel von Delphi3D.&lt;br /&gt;
Für uns wichtig sind folgende Formeln:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 Reflected = 2 * (Normal  Light) * Normal - Light            //wird unten mittels der &lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
glSlang eigenen Funktion reflect berechnet&lt;br /&gt;
&lt;br /&gt;
und&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 Specular = SpecularLight * SpecularMaterial * pow(max(dot(Reflected, Eye), 0), Shininess)&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Wie der Name vermuten lässt berechnen wir mit der ersten Formel den an der Oberfläche reflektierten Lichtvektor. Mit der zweiten vergleichen wir dann diesen Vektor mit dem des Beobachters.&lt;br /&gt;
Im Vertexshader berechnen wir die einzelnen Vektoren, die dann wie üblich interpoliert werden:&lt;br /&gt;
&lt;br /&gt;
Vertexshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 normal;&lt;br /&gt;
varying vec3 v;&lt;br /&gt;
varying vec3 lightvec;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
  normal          = normalize(gl_NormalMatrix * gl_Normal);&lt;br /&gt;
  v               = vec3(gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
  lightvec        = normalize(gl_LightSource[0].position.xyz - v);&lt;br /&gt;
  gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Im Fragmentshader bringen wir jetzt die Berechnungen aus dem Per-Vertex-Lighting und die des Specular zusammen:&lt;br /&gt;
&lt;br /&gt;
Fragmentshader:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 normal;&lt;br /&gt;
varying vec3 v;&lt;br /&gt;
varying vec3 lightvec;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec3 Eye             = normalize(-v);&lt;br /&gt;
 &lt;br /&gt;
 vec3 Reflected       = normalize( reflect( -lightvec, normal )); &lt;br /&gt;
 //hat den selben effekt wie&lt;br /&gt;
 //vec3 Reflected       = normalize( 2.0 * dot(normal, lightvec) *  normal - lightvec);&lt;br /&gt;
 &lt;br /&gt;
 vec4 IAmbient        = gl_LightSource[0].ambient;&lt;br /&gt;
 vec4 IDiffuse        = gl_LightSource[0].diffuse * max(dot(normal, lightvec), 0.0);&lt;br /&gt;
 vec4 ISpecular       = gl_LightSource[0].specular * pow(max(dot(Reflected, Eye), 0.0), gl_FrontMaterial.shininess);&lt;br /&gt;
 gl_FragColor         = gl_FrontLightModelProduct.sceneColor + IAmbient + IDiffuse + ISpecular;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Erklärung zu reflect:&lt;br /&gt;
Man sollte nach Möglichkeit immer glSlang eigene Funktionen nutzen, da diese ggf. vom Hersteller der Grafikkarte direkt in Hardware implementiert wird und somit zu einem Performenz zuwachs führen kann. Der Compiler kann jedoch die von Hand geschriebenen Funktionen kaum auf die Hardware mappen, was diesen Performenz zuwachs natürlich wieder aufheben würde.&lt;br /&gt;
&lt;br /&gt;
[[bild:Tutimg_glsl_ext_perpixellicht.jpg|256px]]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
Sodala. Fertig! Ich hoffe, ihr habt etwas gelernt und ich all' eure Fragen beantworten konnte. Wenn nicht, dann werden wir euch im DGL-Forum Rede und Antwort stehen. Auch Kritik ist dort gern gesehen, denn nur so können zukünftige Tutorials weiter an Qualität gewinnen. Ich würde mich auch sehr freuen, wenn ihr im Shaderforum eure Ergebnisse postet, egal wie langweilig sie auch seien mögen  ihr beherrscht jetzt immerhin Shader :-).&lt;br /&gt;
Also, ich packs jetzt, sonst packts mich.&lt;br /&gt;
&lt;br /&gt;
'''Euer''' &amp;lt;br&amp;gt;&lt;br /&gt;
'''La_Boda''' (-pdl-_at_web.de)&lt;br /&gt;
&lt;br /&gt;
== Anhang ==&lt;br /&gt;
[http://www.delphigl.com/do_download.php?f=3250 Source Code (VCL)]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_glsl]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|GLSL2]]&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19736</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19736"/>
				<updated>2006-10-08T15:38:21Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Beispiel B */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. 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 glSlang 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. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs 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;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang 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 glSlang 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 Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&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_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&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 natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang 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|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&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        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] 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   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] 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;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] 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;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler 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;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(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;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] 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;
&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 [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. 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;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @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;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&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|glGetObjectParameterivARB}} 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|glGetInfoLogARB}} 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;
 glCompileShaderARB(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|center]]&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|center]]&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;
&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 [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem 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;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(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;glsl&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;/glsl&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;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;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 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 Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten 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;
|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;
|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;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&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;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&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 aussen 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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen ü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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;
==Trigonometire 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 angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle 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 Arccosinus 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;
&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 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;
&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 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. &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;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &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 I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&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;
&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;
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;glsl&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;/glsl&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;glsl&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;/glsl&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;
&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge 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.&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;
&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;glsl&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;/glsl&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;
Ausserdem 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;glsl&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;/glsl&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;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&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 ([mailto:webmaster@delphigl.de webmaster@delphigl.de])&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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19735</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19735"/>
				<updated>2006-10-08T15:37:32Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Beispielshader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. 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 glSlang 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. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs 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;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang 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 glSlang 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 Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&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_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&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 natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang 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|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&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        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] 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   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] 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;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] 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;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler 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;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(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;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] 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;
&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 [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. 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;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @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;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&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|glGetObjectParameterivARB}} 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|glGetInfoLogARB}} 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;
 glCompileShaderARB(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|center]]&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|center]]&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;
&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 [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem 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;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(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;glsl&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;/glsl&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;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;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 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 Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten 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;
|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;
|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;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&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;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&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 aussen 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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen ü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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;
==Trigonometire 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 angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle 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 Arccosinus 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;
&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 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;
&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 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. &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;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &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 I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&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;
&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;
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;glsl&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;/glsl&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;glsl&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;/glsl&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;
&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;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&amp;lt;/glsl&amp;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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge 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.&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;
&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;glsl&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;/glsl&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;
Ausserdem 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;glsl&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;/glsl&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;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&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 ([mailto:webmaster@delphigl.de webmaster@delphigl.de])&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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19734</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19734"/>
				<updated>2006-10-08T15:36:16Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Beispiel B */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. 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 glSlang 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. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs 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;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang 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 glSlang 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 Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&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_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&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 natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang 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|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&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        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] 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   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] 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;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] 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;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler 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;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(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;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] 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;
&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 [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. 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;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @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;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&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|glGetObjectParameterivARB}} 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|glGetInfoLogARB}} 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;
 glCompileShaderARB(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|center]]&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|center]]&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;
&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 [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem 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;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(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;glsl&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;/glsl&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;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;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 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 Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten 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;
|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;
|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;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&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;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&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 aussen 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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen ü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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;
==Trigonometire 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 angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle 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 Arccosinus 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;
&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 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;
&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 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. &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;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &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 I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&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;
&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;
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;glsl&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;/glsl&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;glsl&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;/glsl&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;
&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;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&amp;lt;/glsl&amp;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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge 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.&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;
&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;
 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;
&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;
Ausserdem 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;
 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;
&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;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&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 ([mailto:webmaster@delphigl.de webmaster@delphigl.de])&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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19733</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19733"/>
				<updated>2006-10-08T15:34:57Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Beispiel A */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. 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 glSlang 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. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs 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;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang 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 glSlang 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 Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&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_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&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 natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang 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|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&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        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] 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   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] 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;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] 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;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler 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;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(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;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] 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;
&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 [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. 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;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @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;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&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|glGetObjectParameterivARB}} 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|glGetInfoLogARB}} 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;
 glCompileShaderARB(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|center]]&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|center]]&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;
&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 [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem 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;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(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;glsl&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;/glsl&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;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;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 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 Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten 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;
|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;
|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;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&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;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&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 aussen 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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen ü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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;
==Trigonometire 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 angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle 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 Arccosinus 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;
&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 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;
&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 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. &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;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &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 I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&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;
&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;
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;glsl&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;/glsl&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;glsl&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;/glsl&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;
&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;
&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;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge 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.&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;
&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;
 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;
&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;
Ausserdem 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;
 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;
&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;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&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 ([mailto:webmaster@delphigl.de webmaster@delphigl.de])&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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19732</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19732"/>
				<updated>2006-10-08T15:33:38Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Eingebaute Uniformvariablen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. 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 glSlang 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. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs 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;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang 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 glSlang 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 Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&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_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&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 natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang 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|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&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        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] 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   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] 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;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] 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;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler 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;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(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;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] 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;
&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 [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. 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;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @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;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&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|glGetObjectParameterivARB}} 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|glGetInfoLogARB}} 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;
 glCompileShaderARB(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|center]]&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|center]]&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;
&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 [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem 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;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(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;glsl&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;/glsl&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;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;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 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 Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten 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;
|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;
|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;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&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;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&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 aussen 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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen ü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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;
==Trigonometire 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 angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle 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 Arccosinus 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;
&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 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;
&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 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. &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;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &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 I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&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;
&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;
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;
&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;
&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;
&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;
&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;
&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;
&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;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge 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.&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;
&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;
 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;
&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;
Ausserdem 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;
 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;
&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;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&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 ([mailto:webmaster@delphigl.de webmaster@delphigl.de])&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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19731</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19731"/>
				<updated>2006-10-08T15:28:24Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Schleifen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. 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 glSlang 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. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs 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;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang 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 glSlang 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 Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&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_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&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 natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang 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|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&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        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] 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   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] 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;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] 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;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler 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;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(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;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] 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;
&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 [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. 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;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @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;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&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|glGetObjectParameterivARB}} 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|glGetInfoLogARB}} 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;
 glCompileShaderARB(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|center]]&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|center]]&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;
&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 [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem 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;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(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;glsl&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;/glsl&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;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;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 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 Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten 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;
|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;
|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;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&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;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&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 aussen 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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen ü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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&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;
&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;
&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&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;
&lt;br /&gt;
*struct gl_MaterialParameters&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;
&lt;br /&gt;
*struct gl_LightSourceParameters&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;
&lt;br /&gt;
*struct gl_LightModelParameters&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;
&lt;br /&gt;
*struct gl_LightModelProducts&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;
&lt;br /&gt;
*struct gl_LightProducts&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;
&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;
 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;
&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;
&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;
==Trigonometire 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 angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle 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 Arccosinus 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;
&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 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;
&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 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. &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;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &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 I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&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;
&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;
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;
&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;
&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;
&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;
&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;
&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;
&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;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge 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.&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;
&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;
 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;
&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;
Ausserdem 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;
 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;
&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;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&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 ([mailto:webmaster@delphigl.de webmaster@delphigl.de])&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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19730</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=19730"/>
				<updated>2006-10-08T15:24:55Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Die Shadersprache */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. 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 glSlang 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. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs 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;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang 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 glSlang 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 Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&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 Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&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_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&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 natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang 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|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&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        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] 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   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] 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;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] 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;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler 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;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(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;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] 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;
&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 [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. 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;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @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;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&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|glGetObjectParameterivARB}} 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|glGetInfoLogARB}} 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;
 glCompileShaderARB(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|center]]&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|center]]&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;
&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 [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem 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;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(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;glsl&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;/glsl&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;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;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 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 Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten 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;
|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;
|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;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&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;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&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 aussen 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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen ü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;glsl&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;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;glsl&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;/glsl&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;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&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;/glsl&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;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&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;
&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;
&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&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;
&lt;br /&gt;
*struct gl_MaterialParameters&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;
&lt;br /&gt;
*struct gl_LightSourceParameters&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;
&lt;br /&gt;
*struct gl_LightModelParameters&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;
&lt;br /&gt;
*struct gl_LightModelProducts&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;
&lt;br /&gt;
*struct gl_LightProducts&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;
&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;
 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;
&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;
&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;
==Trigonometire 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 angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle 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 Arccosinus 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;
&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 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;
&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 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. &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;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &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 I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&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;
&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;
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;
&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;
&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;
&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;
&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;
&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;
&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;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge 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.&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;
&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;
 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;
&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;
Ausserdem 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;
 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;
&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;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&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 ([mailto:webmaster@delphigl.de webmaster@delphigl.de])&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>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19729</id>
		<title>GLSL Licht und Schatten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19729"/>
				<updated>2006-10-08T15:12:42Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Oversampling der Schattenmap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Willkommen zu meinem erstem Tutorial. Schatten können sowohl Traum als auch Albtraum eines jeden OpenGL-Progrmamieres werden. Im Gegensatz zur einfachen Beleuchtung mit Lichtquellen, steigt der Rechenaufwand hier extrem an und ohne Optimierung zwingen die Schatten selbst die modernste Hardware in die Knie.&lt;br /&gt;
Für Schatten gibt es zwei praktikable Algoritmen: Den Stencilschatten und den projezierten Schatten. Hier möchte ich mich auf den projezierten Schatten beschränken, er bietet gegenüber dem Stencilschatten einige Vorteile:&lt;br /&gt;
&lt;br /&gt;
*Die komplette Berechnung kann von der Grakfikkarte übernommen werden&lt;br /&gt;
*Es ist möglich Softshadows zu realisieren&lt;br /&gt;
*Die Shadowmaps können unter Umständen für mehr als ein Frame verwendet werden&lt;br /&gt;
&lt;br /&gt;
Um den Rechenaufwand zu veringern werde ich hier zusätzliche Projektionstechniken zeigen, die über den Vertexshader realisiert werden: Die perspektivische Map und das parabolide Mapping. &lt;br /&gt;
&lt;br /&gt;
Für sehr weit entfernte Lichtquellen und offene Szenen ist der Einsatz von perspektisch angepassten Maps sinvoll. Da das Licht quasi parallel ausgestrahlt wird. Ist ein winkelabhängiger Cube oder dualparabolische Map kaum möglich. Auch eine einfache quadratische Shadowmap zeigt deutliche Schwächen bei der Auflösung im Nahbereich und dem zu hohem Oversampling in der Entfernung.&lt;br /&gt;
&lt;br /&gt;
Das parabolide Mapping ermöglicht nicht nur die Simulation eine Fischaugenoptik, sondern kann auch die Cubemap vollständig ersetzen. Durch einen geringfügig höheren Rechen- und Programieraufwand genügen zwei Renderpasses um eine vollständige Tiefen- oder Reflektionsmap zu erstellen. Was gegenüber der klassischen Cubemap den Prozessor und GPU um den Faktor 3 entlastet.&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Dieses Tutorial basiert auf den grundlegenden Techniken, die erst in den letzten Jahren entwickelt wurden. Jeder der hier mit anfängt, sollte die zwei anderenen GLSL Tutorials gelesen haben und einfache Fragmentshader schreiben können. Auch das Laden und Einbinden von Texturen in die Shader sollte kein Problem mehr darstellen.&lt;br /&gt;
&lt;br /&gt;
===Framebufferobjekte===&lt;br /&gt;
Für das Erstellen von dual paraboliden Tiefentexturen ist noch das Rendern in Framebufferobjekten Vorraussetzung (zu denen es leider noch kein Tutorial gibt). Damit der Einstieg nicht zu schwer wird sollte dieser Code helfen das FBO zu initialsisieren:&lt;br /&gt;
&lt;br /&gt;
Als Erstes müssen die nötigen Extensions initialisiert werden&lt;br /&gt;
Dann sollten die benötigten Modelle als VBO in die Grafikkarte hochgeladen werden.&lt;br /&gt;
Nun muss das Framebufferobjekt (FBO) für die Schattenmaps erzeugt werdern.&lt;br /&gt;
So könnte die Initialsierung des FBOs aussehen. C code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;GLuint shadow_map = 0; // &lt;br /&gt;
GLuint shadow_fbo = 0; // the shadow texture&lt;br /&gt;
GLuint shadow_size = 4096; //muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
glGenTextures (1, &amp;amp;shadow_map); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindTexture (GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
glTexImage2D (GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0,GL_DEPTH_COMPONENT , GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
glGenFramebuffersEXT (1, &amp;amp;shadow_fbo); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D,shadow_map, 0);&lt;br /&gt;
glDrawBuffer (GL_FALSE);&lt;br /&gt;
glReadBuffer (GL_FALSE);&lt;br /&gt;
GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/cpp&amp;gt;&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;var shadow_map,&lt;br /&gt;
    shadow_fbo,&lt;br /&gt;
    shadow_size : GLuint;&lt;br /&gt;
    status      : GLenum; &lt;br /&gt;
begin&lt;br /&gt;
  shadow_map  := 0;  &lt;br /&gt;
  shadow_fbo  := 0;     // the shadow texture&lt;br /&gt;
  shadow_size := 4096; // muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @shadow_map);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @shadow_fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadow_map, 0);&lt;br /&gt;
  glDrawBuffe (GL_FALSE);&lt;br /&gt;
  glReadBuffer(GL_FALSE);&lt;br /&gt;
  status := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt sollten die Shader und weiter Texturen geladen werden.&lt;br /&gt;
&lt;br /&gt;
===Beschleunigtes Rendern===&lt;br /&gt;
&lt;br /&gt;
Ich empfehle auch die zu rendernden Daten als Vertexbufferobjekte zu übergeben, da sonst die Mehrfachverwendung der Daten zu einer extremen Bremse wird. Da es hierzu bereits ein Tutorial gibt werde ich hier nichts mehr darüber schrieben.&lt;br /&gt;
Alternativ sollte alles was zwischen glBegin und glEnd in Displaylisten gespeichter werden. Das Speichern von Texturwechseln usw ist nicht sinvoll, da diese nicht zum Rendern der Shadowmaps benötig werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehrfachen Lichquellen kann es wiederum Sinn machen den ersten Rendervorgang inclusive Shaderwechsel in einer Displayliste zwischenzuspeichen und die zusätzlichen Schadowmaps mit dieser zu rendern.&lt;br /&gt;
&lt;br /&gt;
===Algemeines zu GLSL===&lt;br /&gt;
Ich möchte nocheinmal darauf hinweisen, das sich uniformvariablen nur setzten Lassen, wenn der entsprechnde shader gebunden ist. (Es funktionier nicht wenn der shader nicht gebunden ist. Warum man den shader dabei allerdings angeben muss ist mir nicht so ganz klar)&lt;br /&gt;
In den Beispielen werden nur die Uniformvariablen wärend des Rendervorgangs neu gesetzt die sich ändern.  Die zuweisung der TMU zu einem Sampler gehöhrt in der Regel nicht dazu. &lt;br /&gt;
&lt;br /&gt;
===Grundlegendes zu den Koordinatensystemen in den Shadern===&lt;br /&gt;
&lt;br /&gt;
Im Vertexshader müssen alle komponenten von gl_Position in einem Bereich von -1.0 bis 1.0 gebracht werden. Besonders beim Z-Wert könnte es verwirrend, dass der Bereich  von gl_FragDepth im Fragmentshader von 0.0 bis 1.0 geht. Auch muss beachtet werden, dass Texturkordinaten den bereich von 0.0 bis 1.0 nutzen, wärend die Rendertargets im Bereich on -1.0 bis 1.0 arbeiten.&lt;br /&gt;
In den Shadern werden daher öfters Multimplikationen mit 0.5 und einer anschließenden Addition von 0.5 auftreten.&lt;br /&gt;
&lt;br /&gt;
==Perspektivische Maps==&lt;br /&gt;
&lt;br /&gt;
In dem erstem Teil dieses Artikels geht es um perspektivisch angepasste Schattenmaps. Normale projezierte Schatten haben das Problem, das sie im Nahenbereich besonders stark verpixeln und in der Entfernung durch ein viel zu hohes Oversampling Bandbreite verschwenden.&lt;br /&gt;
&lt;br /&gt;
Für eine globale Lichquelle wird nur ein Vektor gegeben, der die Richtung des Lichtes beschreibt. Die gedachte Lichtquelle ist quasi unendlich weit weg. Da eine Entfernungsberechnung zur Lichquelle unmöglich ist, muss die Schattenberechnung relativ zu einer Referenzebene durchgeführt werden. Diese Ebene kann sowohl Senkrecht zum Lichvektor, als auch parallel zum gedachtem Boden ausgerichtet werden. Die Ausrichtung der Referenzebene beeinflusst die später sichtbare Auflösung der Schatten.&lt;br /&gt;
&lt;br /&gt;
Nach dem ein Vertex auf die Ebene projeziert wurde und der Abstand ein einen berech von 0.0...1.0 gebracht wurde, muss diese unendlich große Ebene noch auf eine endliche Größe projeziert werden, die auf eine Textur passt und die entfernungsabhängige Detailierung beachtet.&lt;br /&gt;
&lt;br /&gt;
Wenn wir unsere Referenzebene einfachhalber den Horizont schneidet (und auch den Bildschirm in obere und untere Hälfte teilt) Könnte ein Algorimus in etwa so aussehen (Dieser lässt sich später in ein Vertexshaderprogramm umsetzten):&lt;br /&gt;
&lt;br /&gt;
Projeziere den Vertex in die Modelview (Diese Schritt wurde auch bei den dualparaboliden Maps durchgeführt)&lt;br /&gt;
Ermittel den Schnittpunt des vom Vertex ausgehendem gedachtem Lichtstrahl und der Referenzebene.&lt;br /&gt;
Benutze den Abstand zwischen Schnittpunkt und Vertex um den Z-Wert zu ermitteln. (Es sind zwei zusätzlich referenzwerte nötig die die funktion Farclip und Nearclip übernehmen)&lt;br /&gt;
Projeziere die Ebene auf eine Ebene die in eine Textur passt pos/=abs(pos)+1.0 passt recht gut.&lt;br /&gt;
Anschließend wird noch die Schadowmap noch gestreckt und der Bereich hinter der Kammera entfernt.&lt;br /&gt;
&lt;br /&gt;
Das wichtigste ist, dass beim auswerten der shadowmaps der gleiche Projektionsalgoritmus verwendet wird wie beim generieren.&lt;br /&gt;
&lt;br /&gt;
Prinzipell sollte sich der Algoritmus schon auf einer Geforce 3 oder Radeon 8500 implementieren lassen. Da da der Code hier in GLSL geschrieben ist, sollte in etwa Shadermodel 2.0 unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeitsmäßig ist dieser Algoritmus den Stencilshadows deutlich überlegen. Auch bei Stencilshadows sind mehrere Renderpasses nötig. Vorallem das extruieren der Siluetten kostet einiges an Bandbreite. Der geschätzte Aufwand ist etwa 20 (Aufwendige Shader im Finalem Renderdurchgang)bis 80% (CPU limitiert Geometrieübergabe) Mehraufwand gegenüber einer Schattenlos gerenderten Scene.&lt;br /&gt;
Auch die Qualität ist nicht schlechter. Bei der Verwendung von weichen Schatten wirken Shadowmaps natürlicher als die extrem scharfen Stencilshadows. &lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
In der Hauptschleife könnte folgender Code verwendet werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, 0 ); //Entfernt alle Texturen aus der ersten TMU&lt;br /&gt;
	glUseProgramObjectARB(shadow); //lädt den Schattenshader&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb); //Bindet das Framebufferobjekt&lt;br /&gt;
	&lt;br /&gt;
	glViewport (0, 0,shadow_sz,shadow_sz); //Anpassen des Viewportes &lt;br /&gt;
	glClear(GL_DEPTH_BUFFER_BIT); //Z-Buffer löschen&lt;br /&gt;
	&lt;br /&gt;
	render(); //Erster Renderdurchgang&lt;br /&gt;
&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); //Normalen Framebuffer binden&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, shadow_tx ); //Tiefenmap an die erste TMU binden&lt;br /&gt;
	glUseProgramObjectARB(final); //finalen shader binden&lt;br /&gt;
	&lt;br /&gt;
	glViewport(0, 0, screen_size_x, screen_size_y);&lt;br /&gt;
	&lt;br /&gt;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Color und Z-Buffer löschen&lt;br /&gt;
	render(); //rendern&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Shader===&lt;br /&gt;
&lt;br /&gt;
Als erstes der Vertexshader zum generieren der Schadowmap. shadow.vert:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){&lt;br /&gt;
&lt;br /&gt;
	vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0)); //Lichtvektor in den Modelsprace rotieren&lt;br /&gt;
	vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex); //Vertex in den Modelspace projezieren&lt;br /&gt;
	vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y; //Schnittpunkt mit der XZ Referenzebene&lt;br /&gt;
	pos = pos / (abs(pos)+1.0); //Projektion der Ebene auf ein Quadrat&lt;br /&gt;
	pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
	gl_Position.xy = pos;&lt;br /&gt;
	gl_Position.z = -mvertex.y ; // Der Bereich von +-1 über der Referenzebene wird erfasst&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Lichtrichtung wird vorläufig noch fest übergeben. Eine Auswertung einer Opengl Lichtquelle oder einer Uniformvariable wäre ebenfalls möglich. Anschließend wird der Vertex in die Modelview projeziert und der Schnittpunkt des vom Vertexausgehendem Lichstrahls mit der Referenszebene berechnet. Als letztes wird noch der Abstand zur Referenzebenein einem Bereich 0..1  umgerechnet und die Texturkoordinaten für eventuelles Alphamasking oder Heightmapping durchgeschleift. Soll Alphamasking verwendet werden, muss ein entsprechender Shader geschrieben werden der bei den freizulassenden pixeln discard(); aufruft. Dies sollte jedoch nur für die betroffenen Poligone stat finden, da die Grafikkarte dann keine Early-Z Optimierungen verwenden kann. Ansonsten ist der Fragmentshader ist sehr einfach: shadow.frag:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die für die Auswertung müssen wir im finalem Renderdurchgang exakt die gleichen Texturkoordinaten für die Shadowmap generieren. Allerdings gibt es eine Besonderheit: Die koordinaten einer Textur reichen von 0;0 bis 1;1, Die Koordinaten eines Rendertargets reichen jedoch von -1;-1 bis 1;1, so das eine zusätzliche korrektor nötig ist.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
        vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0));&lt;br /&gt;
        vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
        vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y;&lt;br /&gt;
        pos = pos / (abs(pos)+1.0);&lt;br /&gt;
        pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
        pos = pos * 0.5 + 0.5; //auf Texturkoordinaten umrechnen&lt;br /&gt;
 &lt;br /&gt;
        spos.xy = pos; //Daten in einer Varying verpacken&lt;br /&gt;
        spos.z = -mvertex.y * 0.5 + 0.5 - 0.005; // far and near clamping and Anti-Z-fighting-offset &lt;br /&gt;
 	&lt;br /&gt;
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //Die echte Transformation&lt;br /&gt;
 &lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten 5 Zeilen der main() sollten exakt das gleiche tun wie der Vertexshader zum gnerieren dem Map.&lt;br /&gt;
&lt;br /&gt;
Nun fehlt noch ein Fragmentshader für den letzten Durchgang:&lt;br /&gt;
&lt;br /&gt;
Es muss noch der Noralvektor berücksichtigt werden!!!&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Shadowmap;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
 &lt;br /&gt;
void main(void){&lt;br /&gt;
        if (texture2D(Shadowmap, spos.xy).r &amp;gt; spos.z ){&lt;br /&gt;
              //Licht&lt;br /&gt;
              gl_FragColor = vec4(1.0,1.0,1.0,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        else{&lt;br /&gt;
              //Schatten&lt;br /&gt;
              gl_FragColor = vec4(0.5,0.5,0.5,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Parabolide Maps==&lt;br /&gt;
&lt;br /&gt;
Einfache parabolide Maps können für alle Punktlichquellen verwendet werden, deren Licht nicht in alle Richtungen abgestrahlt wird. Darunter fallen vorallem Spots und an Wänden oder Decken befestigte Lampen. Im gegensatz zur Paralelem Licht oder einer Punktlichquelle bringt eine solche Lichtquelle häufig eine Helligkeitsmap mit. Für die Helligkeitsmap und die Schattenmap können die gleichen Texturkoordinaten verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Bei kleinen Öffnungswinkeln hat die parabolide Map keinen Vorteil gegenüber einer normalen Projektion. Der Vortiel ist jedoch das der Code sich für Öffnungswinkel von bis zu ~240 Grad eignet. &lt;br /&gt;
&lt;br /&gt;
Um eine solche Lichquelle zu beschreiben weden nicht weniger als drei Vektoren benötigt:&lt;br /&gt;
&lt;br /&gt;
* Position&lt;br /&gt;
* Richtung &lt;br /&gt;
* Tangent&lt;br /&gt;
&lt;br /&gt;
Wärend die Funktion der ersten beiden Vektoren klar ist, wird der Tangent wird dazu benötigt die Schattenmap und Helligkeitsmap auszurichten. Er ist Senkrecht zur Richtung tangential zur Textur ausgerichtet &lt;br /&gt;
Beschreiben lässt sich diese Funktion lässte sich am ehesten durch das Verdrehen einer Taschenlampe. Wenn die Schattenmap gegenüber den schattenwerfenden Objekten verdreht wird, sieht das Bild auf keinen Fall mehr natürlich aus.&lt;br /&gt;
 &lt;br /&gt;
Es ist sowohl möglich die Berechnungen im Vertexshader durchzuführen, als auch eine entsprechnede Matrix in den Uniformvariablen abzulegen. Wenn die Berechnungen per Matrix durchgefühert werden lässt sich das Prinzip der paraboliden Maps zuindest als Reflektionsmap nutzen. Ein weiterer Vorteil an einer vorberechneten Matrix ist, dass diese auch für shadowmap verwendet werdne kann die nicht jedes Frame neu berechnet werden.&lt;br /&gt;
&lt;br /&gt;
==Dual Parabolide Maps==&lt;br /&gt;
Von OpenGL kennen wir zwei Projektionsmöglichkeiten: Orthografische und perspektivische Projektion. Beide Projektionen arbeiten ohne Verzerrung. Jede Gerade bleibt beim Transformieren eine Gerade. Wenn man dagegen das Bild eines Fischeyeobjektives betrachtet, allen einem sofort die zu Kurven verzerrten Geraden auf. Der entscheidene Vorteil an einer Fisheyeaufnahme ist, dass ein Öffnungswinkel von 180 Grad erfasst werden kann. Zwei entgegensetzte Aufnahmen können so problemlos den kompletten Raum um die Kamera erfassen.&lt;br /&gt;
&lt;br /&gt;
Für das Erstellen der Tiefenmap ist es notwendig den Raum um das reflektierende Objekt in eine Textur zu rendern. Meistens wird hier eine Cubemap verwendet. Soll diese dynamisch generiert werden, ist es auffällig, dass die Scene ganze 6 mal gerendert werden muss. Mit der dual paraboliden Map sind nur noch zwei Rendervorgänge nötig, es wird zwar keine Füllrate eingespart, dafür müssen nun nur noch 1/3 der Daten transformiert werden, so das die Vertexshader und die CPU entlastet werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitere Optimierung ist unter Umständen möglich: Wenn bei einer Cubemap auf eine der Flächen verzichte werden kann. Z.B. wird die Reflektion im Lack eines Autos so gut wie nie verdeckte Straße zeigen. Auch ist für eine an einer  Wand befestigten Lampe nur eine halbkugelförmige Shadowmap nötig. Wenn sie einen Abstand zur Wand hat, genügt es auch hier den Blickwinkel von 180 Grad etwas zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Die Projektion der dualparaboliden Map kann man sich am besten Bild eines Fisheyobjektives vorstellen. Mathematisch etwas genauer ist das Reflektionsbild der umgebenden Welt in einem Rotationsparaboliden.&lt;br /&gt;
&lt;br /&gt;
Die Hardwareanforderungen an den Pixelshader sind nicht gerade gering. Der Pixelshader für die 8fachen Lichquellen kommt nach dem Compelieren auf über 170 Instruktions. Eine Shader 2.0 Karte wie z.B. die Radeon 9x00 sind hier hoffnungslos überfordert da sie nur an 3 Stellen im Programm auf die Textureinheiten zugreifen können und der Assembler nicht mehr in der Lage ist die Instruktions passend umzusortieren. Noch fataler wird es  wenn die Texturelookups durch dynamisches Branching übersprungen weder sollen: Die Karte hat keine Chance mehr diese umzusortieren.&lt;br /&gt;
&lt;br /&gt;
Wer dualparbolide Maps auf SM2.0 Karten einsetzten will sollte damit rechnen, dass das Limit bei 2 bis 4 Maps liegen sollte.&lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
So kann in der Hauptschleife das rendern der 16 paraboliden Maps und der anschließende Finale Renderdurchgang durchgeführt werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for (int light;light&amp;lt;8;light++){&lt;br /&gt;
        glViewport (shadow_size/2*(lights/4),shadow_size/4 *(light%4),shadow_size/4,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;light&amp;quot;),light);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),0);&lt;br /&gt;
        render();&lt;br /&gt;
        glViewport (shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light%4),shadow_size/4 ,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),1);&lt;br /&gt;
        render();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Vieport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0,Windowsize_X,Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for light := 0 to 7 do&lt;br /&gt;
begin&lt;br /&gt;
  glViewport(shadow_size/2*(lights/4), shadow_size/4 *(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'light'), light);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'), 0);&lt;br /&gt;
  render();&lt;br /&gt;
  glViewport(shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'),1);&lt;br /&gt;
  render();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Viewport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0, Windowsize_X, Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Die Shader===&lt;br /&gt;
&lt;br /&gt;
====Shader zum Rendern der Schattenmaps====&lt;br /&gt;
parabol.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;  uniform int renderpass;&lt;br /&gt;
  uniform int light;&lt;br /&gt;
  varying vec3 normal;&lt;br /&gt;
  varying vec3 pos;&lt;br /&gt;
&lt;br /&gt;
  void main(void){&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewMatrix * gl_Vertex - gl_LightSource[light].position ;&lt;br /&gt;
&lt;br /&gt;
	float L= length (gl_Position.xyz);&lt;br /&gt;
	gl_Position /= -L;&lt;br /&gt;
	if (renderpass == 1) gl_Position.z *=-1.0;&lt;br /&gt;
	gl_Position.z += 1.0;&lt;br /&gt;
	gl_Position.xy /= gl_Position.z;&lt;br /&gt;
	if (gl_Position.z &amp;gt;= 0.01){&lt;br /&gt;
		gl_Position.z = L / 15.0;//Todo: optimieren&lt;br /&gt;
		gl_Position.w = 1.0;&lt;br /&gt;
		}&lt;br /&gt;
	else{&lt;br /&gt;
		gl_Position.z = -1.0;&lt;br /&gt;
		gl_Position.w = -1.0;&lt;br /&gt;
		}&lt;br /&gt;
        &lt;br /&gt;
        gl_Position.z = 2.0 * gl_Position.z -1.0; //Todo: optimieren&lt;br /&gt;
	pos=gl_Position.xyz;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
parabol.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 pos;&lt;br /&gt;
void main(void){&lt;br /&gt;
	if (length(pos.xy)&amp;gt;1.005)discard; //Diese Zeile kann durchaus entfallen. Kosten/Nutzen unbekannt.&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Uniformaviablen, die gesetzt werden müssen: Eine ist die Nummer der aktuellen Lichtquelle und die zweite der Renderpass, der angibt ob die Vorder- oder Rückseite der parabolischen Map gerendert werden soll. Eine automatische Berechnung der Texturkoordinaten wäre zwar möglich, jedoch ist die Änderung des Viewports deutlich weniger Rechenaufwendig.&lt;br /&gt;
&lt;br /&gt;
Statt einer Multiplikation des gl_Vertex mit der gl_ModelViewProjektionMatrix wird hier nur mit der gl_ModelViewMatrix multipliziert. Dadurch werden nur die Transformationen durchgeführt und die Projektion übersprungen.&lt;br /&gt;
Die Division durch -L entspricht weitgehend einer Normalsierung, spiegelt die Welt jedoch in die richtige Lage. L enthält jetzt die Tiefeninformation, gl_Position einen Vektor, der von der Kammera auf den Vertex zeigt. Mit den zwei folgenden Zeilen wird der Vektor parabolisch auf die Bildschirmkoordinaten projeziert (Intervall von -1.0 bis 1.0). Mit Hilfe der folgenden if-Abfrage werden alle Vertices hinter der Kammera geclipt. Nur sichtbare Vertices bekommen gültige z Werte für den Zbuffer im Intervall von -1.0 bis 1.0. &lt;br /&gt;
&lt;br /&gt;
Der Fragmentshader ist extrem einfach, da wir aufgrund des nicht vorhandem Colorbuffers keinen Farbwert benötigen lassen wir diesen wie bei den perspektivischen Maps einfach undefiniert.&lt;br /&gt;
Zudem verlassen wir den Shader mit discard, wenn der der Pixel außerhalb der aktuellen paraboliden Map liegt. Die Voteil ist, das nur der kreisförmige Bereich der Map verwendet wird, der Nachteil, das durchaus eine Early-Z optimierung nicht mehr möglich ist. Sehr Sinvoll sollte dies sein, wenn die Shadowmaps dynamisch nach benötigter Größe angeordnet werden. Da sich Kreise besser als Quadrate packen lassen.&lt;br /&gt;
&lt;br /&gt;
====Shader für den finalen Renderdurchgang====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
final.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	Normal = gl_NormalMatrix * gl_Normal;&lt;br /&gt;
 	ModelVertex  = vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
final.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
uniform int MaxLights;&lt;br /&gt;
&lt;br /&gt;
//Achtung folgende Zeile ist nicht GLSL konform. &lt;br /&gt;
//Workaround: Array als Uniform übergeben oder durch sehr aufwendige berechnung erstzten&lt;br /&gt;
//Sollte es auch auf ATI Karten funktinieren, frage ich mich warum es nicht erlaubt ist...&lt;br /&gt;
const vec2 texofset[8] = {vec2 (0.125,0.125), vec2 (0.125,0.375), vec2 (0.125,0.625), vec2 (0.125,0.875),&lt;br /&gt;
			  vec2 (0.625,0.125), vec2 (0.625,0.375), vec2 (0.625,0.625), vec2 (0.625,0.875)};&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
	vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
	for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
		vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
		vec3 lightdir = normalize( lightvec );&lt;br /&gt;
		vec2 parabol = texofset[LightNum];&lt;br /&gt;
		if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
			parabol.t += 0.25;&lt;br /&gt;
			}&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
		parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
		vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
		light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
		}&lt;br /&gt;
	vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));	//Textur auslesen; &lt;br /&gt;
	gl_FragColor = light * color ;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Möglicher weise für ATI taugliche Variante:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
 &lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
const int MaxLights=8;&lt;br /&gt;
 &lt;br /&gt;
vec2 texofset[8]; &lt;br /&gt;
void main(void){&lt;br /&gt;
	texofset[0] = vec2 (0.125,0.125);&lt;br /&gt;
	texofset[1] = vec2 (0.125,0.375);&lt;br /&gt;
	texofset[2] = vec2 (0.125,0.625);&lt;br /&gt;
	texofset[3] = vec2 (0.125,0.875);&lt;br /&gt;
	texofset[4] = vec2 (0.625,0.125);&lt;br /&gt;
	texofset[5] = vec2 (0.625,0.375);&lt;br /&gt;
	texofset[6] = vec2 (0.625,0.625);&lt;br /&gt;
	texofset[7] = vec2 (0.625,0.875);&lt;br /&gt;
&lt;br /&gt;
        vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
        vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
        for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
                vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
                vec3 lightdir = normalize( lightvec );&lt;br /&gt;
                vec2 parabol = texofset[LightNum];&lt;br /&gt;
                if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
                        parabol.t += 0.25;&lt;br /&gt;
                        }&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
                parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
                float shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
                light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
                }&lt;br /&gt;
        vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0])); //Textur auslesen; &lt;br /&gt;
        gl_FragColor = light * color ;&lt;br /&gt;
        }&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Shader besitzen 3 Uniformvariablen, die unbedingt mit den richtigen Werten gefüllt werden müssen. Zwei davon sind Texturen, die dritte die Anzahl der aktiven Lichtquellen. Es ist wichtig zu wissen, dass der Shader nicht den OpenGL-Status der Lichquellen berücksichtigt und nur die Daten der Ersten bis MaxLights holt.&lt;br /&gt;
Während bei den Schattenmaps die meiste Arbeit im Vertexshader erledigt werden könnte, ist dieser sehr Fragmentshader lastig. Die Texturkoordinatenberechnung ist sehr ähnlich zu der im shadow.vert. Die größte Änderung ist, dass hier abhängig von der Lichtquellennummer ein Offset aufaddiert wird um die Untertextur auszuwählen. Ein zusätzlicher Offset wird dazuaddiert, wenn auf die zweite parabolide Map einer Lichtquelle zugegriffen wird.&lt;br /&gt;
Um ein dynamisches Branching zu vermeiden, wird mit der Stepfunktion ermittelt ob sich das Fragment im Schatten befindet.&lt;br /&gt;
&lt;br /&gt;
==Optimierungen und Verbesserungen==&lt;br /&gt;
Hier sind noch einige Vorschläge, die helfen können um besser Qualität oder Leistungen im eigenem Programm zu bekommen. Eine uniververselle Lösung lässt sich nur auf kosten von Performance schreiben. Viel besser ist es, wenn man die Shader an die jeweilige Situation anpasst. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schatten durch Alphatest===&lt;br /&gt;
Der bisherige Schattenshader kann nur ganze Polygone einen Schatten werfen lassen. Wenn shadow.vert so ergänzt wird, das die Texturkoordinaten in den Fragmentshader  weitergereicht werden, dann ist es mit folgendem Fragmentshader möglich Shatten in Abhängikeit einer Alphatextur zu rendern:&lt;br /&gt;
&lt;br /&gt;
shadow.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
        if (texture2D(Texture0,vec2(gl_TexCoord[0])).a &amp;lt; 0.5) discard;&lt;br /&gt;
}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Shader wird verlassen wenn das Texel einen Alphawert von kleiner als 50% hat. Damit lassen sich Schatten von Pflanzen wesentlich realistischer darstellen. Dieser Shader sollte natürlich nur dann verwendet werden, wenn eine Alphakanal in der Textur vorhanden ist. Auch Shader mit Paralax- oder Displacementmapping arbeiten kann man so um einen Schatten ergänzen, wenn die Polygone transparente Teile enthalten.&lt;br /&gt;
Es ist auch möglich den shader zu verlassen, wenn eine bestimmte Farbe in der Textur gefunden wird, dann nimmt die Alphamaske keinen Speicherplatz mehr weg.&lt;br /&gt;
&lt;br /&gt;
===Farbiges Glas===&lt;br /&gt;
&lt;br /&gt;
Schatten hat jetzt ja sachon fast jeder. Aber wie wäre es mal mit einfärben von dynamischen Lichtquellen?&lt;br /&gt;
Der Algoritmus ist nicht schwer:&lt;br /&gt;
&lt;br /&gt;
* Alle Undurchichtigen Sceneteile in die Tiefenmaps gerendert. &lt;br /&gt;
* Zusätzlich wird eine Colormap gebunden und das Schreiben in den Zbuffer unterbunden.&lt;br /&gt;
* Die Colormap wird mit Weiß oder einer Helligkeitsmap initialisiert.&lt;br /&gt;
* Rendern aller transparenten Objekten&lt;br /&gt;
* Auf finales Rendern umschalten&lt;br /&gt;
* Alle undurchsichtigen Objekte mit hilfe der Schadowmap und der modifizierten Beleuchtungmap beleuchten.&lt;br /&gt;
* Alle Transparenten Objekte rendern, unter Berücksichtigung, dass die Lichtquelle bereits das gefilterte Licht aussendet. Dieses Blending sollte rückgängig gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Bei diesem Algoritmus bleibt noch das Alphablendingproblem mit der mehrfachen Überdeckung. Beim Modifizieren der Beleuchtungsmap gegebenfalls den Stencilbuffer zur Hilfe nehmen. Hier wäre ein denkbarer Algoritmus:&lt;br /&gt;
&lt;br /&gt;
* Alle transparenten Poligone in den Zbuffer rendern. Dabei für alle Poligone, deren  doppelte Filterung zu Fehlern führen kann mit verschiedenen Stencilwerte schreiben.&lt;br /&gt;
* Zbuffer und Colorbuffer Löschen. &lt;br /&gt;
* Helligkeitsmap in den Colorbuffer kopieren.&lt;br /&gt;
* Alle nicht transparanten Objekte in den Zbuffer Rendern. &lt;br /&gt;
* Alle transparenten Poligone mit den gleichen Stencilwerten wie im erstem Pass rendern. Die Bedingung ist, dass nur Polygone in den Zbuffer geschrieben werden, bei den Stencilwerte nicht mit den Stencilbuffer übereinstimmen. Die vordersten Polygone werden so aussortiert und nur die zweite Schicht landet im Zbuffer.&lt;br /&gt;
* Im letztem Rendervorgang müssen die gefilterten Lichtfarben der Transparenten Polygone in den Colorbuffer geschrieben werden. Die Bedingung ist das die Stencilwerte übereinstimmen müssen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn es wie ein großer Mehraufwand aussieht, ist der Anteil der transparenten Poligone doch eher gering. So das deren dreifacher Overdraw kaum eine Rolle spielt. Im Finalem Renderdurch gang gibt es bei den transparenten Polygonen noch eine Besonderheit: Stimmt die Entfernung aus der Shadowmap mit der Entfernung der Lichquellen (fast) überein, so wird das Poligon mit dem Licht aus der Colormap belauchtet. Ist die Entfernung aus der Shadowmap jedoch größer als die entfernung zu lichquellen, enthällt die Colormap die gefilterte Farbe des Lichtes hinter dem Poligon. Für die beleutung des Poligon muss also das Licht der Lichquelle benutzt werden. Sinvoll ist es die helligkeit für diesen Fall im Alphawert der Colormap zu Speichern.&lt;br /&gt;
&lt;br /&gt;
Ansonsten noch ein paar Vorschläge:&lt;br /&gt;
* Objekte die aus dem gleichem Glas sind und auch einfarbig. Sollten mit dem gleichem Stencilwert verarbeitet werden. So sieht z.B. das gefärbte Licht einer zweifach durchstrahlten leicht gefäbten Glasskuppel natürlicher aus als ein Vollschatten. Auch wenn das Licht korrekter weise zwei mal hätte gefiltert werden müssen. &lt;br /&gt;
* Eventuel macht es sind mehrfarbige Objekte in mehrfache einfarbige Objekte zu zerlegen.&lt;br /&gt;
* Komplexe Mehrfachfilterungen sollten vermieden werden oder so gewählt werden, das sie natürlich ausehen. Gute Filter wären komplementärfarben, da dort ein echter Schatten erzeugt wird. Schlechte Kombinationen wären unter anderem Rot+Gelb, Blau+Gelb, usw...&lt;br /&gt;
* Um von den Farbfehlern abzulenken, farbige Objekte in einer rotverschobenen Farbe flourezieren lassen. (Violet-&amp;gt; Blau -&amp;gt; Grün -&amp;gt; Gleb -&amp;gt; Organge -&amp;gt; Rot) Durch blau gefärbte Fenster, blau gefilterte Licht welches Dinge grün aufleuchten lässt nimmt einem jeder PC Modder ab...&lt;br /&gt;
&lt;br /&gt;
===Schattenmap durch eine Heightmap modifizieren===&lt;br /&gt;
Auch wennich hierzu noch kein Beispiel haben, ist es möglich gl_FragDepth mit hilfe einer Heightmap zu modifizieren. Prinzipiell entspricht dies einem einfachem Offsetmapping. Damit wäre durchaus eine Selbstschattierung von Bumpmaps möglich.&lt;br /&gt;
&lt;br /&gt;
===Zweite parabolische Map vermeiden===&lt;br /&gt;
Lichtquellen, die nur in eine Richtung Licht werfen können, wie z.B. Spotlichter oder Lichter, die in Bodenähe oder Wandnähe befestigt sind, benötigen keinen vollständig erfassten Tiefenraum. Die Parabolische Map kann problemlos herein oder herausskaliert werden, so das Öffnungswinkel von 0 bis ca 240 Grad möglich sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das verkleinern des Öffnungswinkels für zusätzliche Spotlichter ermöglicht auch kleinere Tiefenmaps, die in die 9 Zwischenräume der großen gepackt werden können. Die Zwischenräume können noch Maps mit einem Durchmesser von 40% der großen Maps aufnehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Texturelookups vermeiden===&lt;br /&gt;
Wenn das Skalarprodukt von normalvec und -lightdir negativ ist, dann ist die Oberfläche von der Lichtquelle abgewandt und Berechnungen für die Lichquelle können komplett übersprungen werden. Diverse Multiplikationen und vorallem Texturelookups können so übersprungen werden. Besondere aufwendige Algorithmen wie selbstschattierende Bumpmaps, können so deutlich Beschleunigt werden. &lt;br /&gt;
&lt;br /&gt;
Für die Beleuchtung sollte dann allerdings auch folgende Zeile verwendet werden. (Das Skalarprodukt von vor der if Abfrage aber umbedingt wiederverwerten!) &lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
  light += gl_LightSource[0].diffuse * max(dot(normalvec, -lightdir), 0.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reichweite der Lichtquellen=== &lt;br /&gt;
Leider bietet OpenGL nicht direkt die Möglichkeit die maximale Reichweite einer Lichquelle anzugeben. In den Shadern wird zur Zeit der Wert 15.0 als maximale Entfernung zur Lichtquelle verwendet. Für ein einfaches Programm ist es sicher ausreichend, ansonsten macht es Sinn diesen Wert durch eine Unformvariable zu ersetzten, oder um mehr Flexibiltät zu bekommen durch ein Array aus 8 Uniformfloats.&lt;br /&gt;
&lt;br /&gt;
===Oversampling der Schattenmap===&lt;br /&gt;
Die Qualität lässt sich dadurch mehrere Samples auf der Schattenmap verbessern. Das folgende Codefragment nimmt 3 statt des einem Samples und glättet die Ränder des Schattens. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;glsl&amp;gt;const float pof =1.0 /4096.0 *0.7;&lt;br /&gt;
vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol +vec2(pof,0)).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,-pof/1.2) ).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,pof/1.2)).r );&lt;br /&gt;
light += shadow * 0.33 * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Durch 9x Oversampling lässt sich schon eine sehr gute Qualität ereichen, sorgt aber bei 8 Lichtquellen durch die 72 Texturelookups für einen Zusammenbruch der Framerate.&lt;br /&gt;
Wichtig ist auch, dass man beachtet, dass die dualparaboliden Maps an Ihren Ränden undefiniert sind und so zu Artefakten kommen kann wenn man außerhalb des gültigem Bereichs sampled. Eine Möglichkeit wäre einen Bereich zu erfassen, der etwas größer als 180 Grad ist, um am Rand zusätzliche Texel zu schaffen.&lt;br /&gt;
&lt;br /&gt;
===Ein zusätzlicher Renderpass===&lt;br /&gt;
Nach dem die Tiefenmap gerendert würde, wäre es möglich in einem weiterem Framebufferobjekt eine zusätzliche Map zu rendern, in der mit Hilfe einer Kantenerkennung die Helligkeit der Softshadows vorberechnet wird. Auch hier muss berücksichtigt werden, dass die dualparaboliden Maps einen Übergang haben.&lt;br /&gt;
&lt;br /&gt;
===Dynamische Lichter in statische Lightmaps Rendern===&lt;br /&gt;
Wenn sich Lichtquellen nicht relativ zur Umgebung nicht bewegen, ist es möglich sie in eine Lightmap zu rendern. Unter der Annahme, dass Lightmapkoordinaten vorhanden sind (ohne geht es echt nicht gut), müssen diese nur per Vertexshader an den Pixelshader weitergegeben werden. Im Pixelshader kann dann wie im final.frag die Helligkeit berechnet werden und in der Lightmap abgespeichert werden.&lt;br /&gt;
Es ist immer noch möglich, das dynamische Objekte einen Schatten werfen: Es werden nur noch die beweglichen Objekte in die Tiefenmap gerendert. Im Schatten wird dann einfach das Licht der im Schatten liegenden Lichtquelle subtraiert.&lt;br /&gt;
&lt;br /&gt;
===Statische Anteile in den Schattenmaps===&lt;br /&gt;
Es ist möglich mit einer zusätzlichen Matrix die Tiefenmaps zu den Weltkoordinaten auszurichten. Statische Anteile können dann aus einer zweiten Tiefenmap kopiert werden. Ein wenig problematisch ist das Entfernen der Rotation aus der gl_ModelViewMatrix. Das größte Problem ist, das die Positionen der Lichquellen bereits mit der gl_ModelViewMatrix multipliziert sind. Die einfachste Lösung ist, aus den den Rotationswinkeln eine neue Matrix zu erechnen, mit dessen Hilfe die Schattenvektoren für die Texturkoordinatenberechnung zurückgedreht werden. Diese Matrix sollte dann als Uniformvariable übergeben werden.&lt;br /&gt;
Wenn die Schatten durch einen zusätzlichen Renderdurchgang gefiltert werden. Ist es sinvoll die Maps erst hier zu vereinen. Von beiden Tiefenmaps muss nur immer der kleinere Wert genommen werden.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19728</id>
		<title>GLSL Licht und Schatten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19728"/>
				<updated>2006-10-08T15:11:43Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Texturelookups vermeiden */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Willkommen zu meinem erstem Tutorial. Schatten können sowohl Traum als auch Albtraum eines jeden OpenGL-Progrmamieres werden. Im Gegensatz zur einfachen Beleuchtung mit Lichtquellen, steigt der Rechenaufwand hier extrem an und ohne Optimierung zwingen die Schatten selbst die modernste Hardware in die Knie.&lt;br /&gt;
Für Schatten gibt es zwei praktikable Algoritmen: Den Stencilschatten und den projezierten Schatten. Hier möchte ich mich auf den projezierten Schatten beschränken, er bietet gegenüber dem Stencilschatten einige Vorteile:&lt;br /&gt;
&lt;br /&gt;
*Die komplette Berechnung kann von der Grakfikkarte übernommen werden&lt;br /&gt;
*Es ist möglich Softshadows zu realisieren&lt;br /&gt;
*Die Shadowmaps können unter Umständen für mehr als ein Frame verwendet werden&lt;br /&gt;
&lt;br /&gt;
Um den Rechenaufwand zu veringern werde ich hier zusätzliche Projektionstechniken zeigen, die über den Vertexshader realisiert werden: Die perspektivische Map und das parabolide Mapping. &lt;br /&gt;
&lt;br /&gt;
Für sehr weit entfernte Lichtquellen und offene Szenen ist der Einsatz von perspektisch angepassten Maps sinvoll. Da das Licht quasi parallel ausgestrahlt wird. Ist ein winkelabhängiger Cube oder dualparabolische Map kaum möglich. Auch eine einfache quadratische Shadowmap zeigt deutliche Schwächen bei der Auflösung im Nahbereich und dem zu hohem Oversampling in der Entfernung.&lt;br /&gt;
&lt;br /&gt;
Das parabolide Mapping ermöglicht nicht nur die Simulation eine Fischaugenoptik, sondern kann auch die Cubemap vollständig ersetzen. Durch einen geringfügig höheren Rechen- und Programieraufwand genügen zwei Renderpasses um eine vollständige Tiefen- oder Reflektionsmap zu erstellen. Was gegenüber der klassischen Cubemap den Prozessor und GPU um den Faktor 3 entlastet.&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Dieses Tutorial basiert auf den grundlegenden Techniken, die erst in den letzten Jahren entwickelt wurden. Jeder der hier mit anfängt, sollte die zwei anderenen GLSL Tutorials gelesen haben und einfache Fragmentshader schreiben können. Auch das Laden und Einbinden von Texturen in die Shader sollte kein Problem mehr darstellen.&lt;br /&gt;
&lt;br /&gt;
===Framebufferobjekte===&lt;br /&gt;
Für das Erstellen von dual paraboliden Tiefentexturen ist noch das Rendern in Framebufferobjekten Vorraussetzung (zu denen es leider noch kein Tutorial gibt). Damit der Einstieg nicht zu schwer wird sollte dieser Code helfen das FBO zu initialsisieren:&lt;br /&gt;
&lt;br /&gt;
Als Erstes müssen die nötigen Extensions initialisiert werden&lt;br /&gt;
Dann sollten die benötigten Modelle als VBO in die Grafikkarte hochgeladen werden.&lt;br /&gt;
Nun muss das Framebufferobjekt (FBO) für die Schattenmaps erzeugt werdern.&lt;br /&gt;
So könnte die Initialsierung des FBOs aussehen. C code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;GLuint shadow_map = 0; // &lt;br /&gt;
GLuint shadow_fbo = 0; // the shadow texture&lt;br /&gt;
GLuint shadow_size = 4096; //muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
glGenTextures (1, &amp;amp;shadow_map); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindTexture (GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
glTexImage2D (GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0,GL_DEPTH_COMPONENT , GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
glGenFramebuffersEXT (1, &amp;amp;shadow_fbo); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D,shadow_map, 0);&lt;br /&gt;
glDrawBuffer (GL_FALSE);&lt;br /&gt;
glReadBuffer (GL_FALSE);&lt;br /&gt;
GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/cpp&amp;gt;&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;var shadow_map,&lt;br /&gt;
    shadow_fbo,&lt;br /&gt;
    shadow_size : GLuint;&lt;br /&gt;
    status      : GLenum; &lt;br /&gt;
begin&lt;br /&gt;
  shadow_map  := 0;  &lt;br /&gt;
  shadow_fbo  := 0;     // the shadow texture&lt;br /&gt;
  shadow_size := 4096; // muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @shadow_map);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @shadow_fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadow_map, 0);&lt;br /&gt;
  glDrawBuffe (GL_FALSE);&lt;br /&gt;
  glReadBuffer(GL_FALSE);&lt;br /&gt;
  status := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt sollten die Shader und weiter Texturen geladen werden.&lt;br /&gt;
&lt;br /&gt;
===Beschleunigtes Rendern===&lt;br /&gt;
&lt;br /&gt;
Ich empfehle auch die zu rendernden Daten als Vertexbufferobjekte zu übergeben, da sonst die Mehrfachverwendung der Daten zu einer extremen Bremse wird. Da es hierzu bereits ein Tutorial gibt werde ich hier nichts mehr darüber schrieben.&lt;br /&gt;
Alternativ sollte alles was zwischen glBegin und glEnd in Displaylisten gespeichter werden. Das Speichern von Texturwechseln usw ist nicht sinvoll, da diese nicht zum Rendern der Shadowmaps benötig werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehrfachen Lichquellen kann es wiederum Sinn machen den ersten Rendervorgang inclusive Shaderwechsel in einer Displayliste zwischenzuspeichen und die zusätzlichen Schadowmaps mit dieser zu rendern.&lt;br /&gt;
&lt;br /&gt;
===Algemeines zu GLSL===&lt;br /&gt;
Ich möchte nocheinmal darauf hinweisen, das sich uniformvariablen nur setzten Lassen, wenn der entsprechnde shader gebunden ist. (Es funktionier nicht wenn der shader nicht gebunden ist. Warum man den shader dabei allerdings angeben muss ist mir nicht so ganz klar)&lt;br /&gt;
In den Beispielen werden nur die Uniformvariablen wärend des Rendervorgangs neu gesetzt die sich ändern.  Die zuweisung der TMU zu einem Sampler gehöhrt in der Regel nicht dazu. &lt;br /&gt;
&lt;br /&gt;
===Grundlegendes zu den Koordinatensystemen in den Shadern===&lt;br /&gt;
&lt;br /&gt;
Im Vertexshader müssen alle komponenten von gl_Position in einem Bereich von -1.0 bis 1.0 gebracht werden. Besonders beim Z-Wert könnte es verwirrend, dass der Bereich  von gl_FragDepth im Fragmentshader von 0.0 bis 1.0 geht. Auch muss beachtet werden, dass Texturkordinaten den bereich von 0.0 bis 1.0 nutzen, wärend die Rendertargets im Bereich on -1.0 bis 1.0 arbeiten.&lt;br /&gt;
In den Shadern werden daher öfters Multimplikationen mit 0.5 und einer anschließenden Addition von 0.5 auftreten.&lt;br /&gt;
&lt;br /&gt;
==Perspektivische Maps==&lt;br /&gt;
&lt;br /&gt;
In dem erstem Teil dieses Artikels geht es um perspektivisch angepasste Schattenmaps. Normale projezierte Schatten haben das Problem, das sie im Nahenbereich besonders stark verpixeln und in der Entfernung durch ein viel zu hohes Oversampling Bandbreite verschwenden.&lt;br /&gt;
&lt;br /&gt;
Für eine globale Lichquelle wird nur ein Vektor gegeben, der die Richtung des Lichtes beschreibt. Die gedachte Lichtquelle ist quasi unendlich weit weg. Da eine Entfernungsberechnung zur Lichquelle unmöglich ist, muss die Schattenberechnung relativ zu einer Referenzebene durchgeführt werden. Diese Ebene kann sowohl Senkrecht zum Lichvektor, als auch parallel zum gedachtem Boden ausgerichtet werden. Die Ausrichtung der Referenzebene beeinflusst die später sichtbare Auflösung der Schatten.&lt;br /&gt;
&lt;br /&gt;
Nach dem ein Vertex auf die Ebene projeziert wurde und der Abstand ein einen berech von 0.0...1.0 gebracht wurde, muss diese unendlich große Ebene noch auf eine endliche Größe projeziert werden, die auf eine Textur passt und die entfernungsabhängige Detailierung beachtet.&lt;br /&gt;
&lt;br /&gt;
Wenn wir unsere Referenzebene einfachhalber den Horizont schneidet (und auch den Bildschirm in obere und untere Hälfte teilt) Könnte ein Algorimus in etwa so aussehen (Dieser lässt sich später in ein Vertexshaderprogramm umsetzten):&lt;br /&gt;
&lt;br /&gt;
Projeziere den Vertex in die Modelview (Diese Schritt wurde auch bei den dualparaboliden Maps durchgeführt)&lt;br /&gt;
Ermittel den Schnittpunt des vom Vertex ausgehendem gedachtem Lichtstrahl und der Referenzebene.&lt;br /&gt;
Benutze den Abstand zwischen Schnittpunkt und Vertex um den Z-Wert zu ermitteln. (Es sind zwei zusätzlich referenzwerte nötig die die funktion Farclip und Nearclip übernehmen)&lt;br /&gt;
Projeziere die Ebene auf eine Ebene die in eine Textur passt pos/=abs(pos)+1.0 passt recht gut.&lt;br /&gt;
Anschließend wird noch die Schadowmap noch gestreckt und der Bereich hinter der Kammera entfernt.&lt;br /&gt;
&lt;br /&gt;
Das wichtigste ist, dass beim auswerten der shadowmaps der gleiche Projektionsalgoritmus verwendet wird wie beim generieren.&lt;br /&gt;
&lt;br /&gt;
Prinzipell sollte sich der Algoritmus schon auf einer Geforce 3 oder Radeon 8500 implementieren lassen. Da da der Code hier in GLSL geschrieben ist, sollte in etwa Shadermodel 2.0 unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeitsmäßig ist dieser Algoritmus den Stencilshadows deutlich überlegen. Auch bei Stencilshadows sind mehrere Renderpasses nötig. Vorallem das extruieren der Siluetten kostet einiges an Bandbreite. Der geschätzte Aufwand ist etwa 20 (Aufwendige Shader im Finalem Renderdurchgang)bis 80% (CPU limitiert Geometrieübergabe) Mehraufwand gegenüber einer Schattenlos gerenderten Scene.&lt;br /&gt;
Auch die Qualität ist nicht schlechter. Bei der Verwendung von weichen Schatten wirken Shadowmaps natürlicher als die extrem scharfen Stencilshadows. &lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
In der Hauptschleife könnte folgender Code verwendet werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, 0 ); //Entfernt alle Texturen aus der ersten TMU&lt;br /&gt;
	glUseProgramObjectARB(shadow); //lädt den Schattenshader&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb); //Bindet das Framebufferobjekt&lt;br /&gt;
	&lt;br /&gt;
	glViewport (0, 0,shadow_sz,shadow_sz); //Anpassen des Viewportes &lt;br /&gt;
	glClear(GL_DEPTH_BUFFER_BIT); //Z-Buffer löschen&lt;br /&gt;
	&lt;br /&gt;
	render(); //Erster Renderdurchgang&lt;br /&gt;
&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); //Normalen Framebuffer binden&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, shadow_tx ); //Tiefenmap an die erste TMU binden&lt;br /&gt;
	glUseProgramObjectARB(final); //finalen shader binden&lt;br /&gt;
	&lt;br /&gt;
	glViewport(0, 0, screen_size_x, screen_size_y);&lt;br /&gt;
	&lt;br /&gt;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Color und Z-Buffer löschen&lt;br /&gt;
	render(); //rendern&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Shader===&lt;br /&gt;
&lt;br /&gt;
Als erstes der Vertexshader zum generieren der Schadowmap. shadow.vert:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){&lt;br /&gt;
&lt;br /&gt;
	vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0)); //Lichtvektor in den Modelsprace rotieren&lt;br /&gt;
	vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex); //Vertex in den Modelspace projezieren&lt;br /&gt;
	vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y; //Schnittpunkt mit der XZ Referenzebene&lt;br /&gt;
	pos = pos / (abs(pos)+1.0); //Projektion der Ebene auf ein Quadrat&lt;br /&gt;
	pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
	gl_Position.xy = pos;&lt;br /&gt;
	gl_Position.z = -mvertex.y ; // Der Bereich von +-1 über der Referenzebene wird erfasst&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Lichtrichtung wird vorläufig noch fest übergeben. Eine Auswertung einer Opengl Lichtquelle oder einer Uniformvariable wäre ebenfalls möglich. Anschließend wird der Vertex in die Modelview projeziert und der Schnittpunkt des vom Vertexausgehendem Lichstrahls mit der Referenszebene berechnet. Als letztes wird noch der Abstand zur Referenzebenein einem Bereich 0..1  umgerechnet und die Texturkoordinaten für eventuelles Alphamasking oder Heightmapping durchgeschleift. Soll Alphamasking verwendet werden, muss ein entsprechender Shader geschrieben werden der bei den freizulassenden pixeln discard(); aufruft. Dies sollte jedoch nur für die betroffenen Poligone stat finden, da die Grafikkarte dann keine Early-Z Optimierungen verwenden kann. Ansonsten ist der Fragmentshader ist sehr einfach: shadow.frag:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die für die Auswertung müssen wir im finalem Renderdurchgang exakt die gleichen Texturkoordinaten für die Shadowmap generieren. Allerdings gibt es eine Besonderheit: Die koordinaten einer Textur reichen von 0;0 bis 1;1, Die Koordinaten eines Rendertargets reichen jedoch von -1;-1 bis 1;1, so das eine zusätzliche korrektor nötig ist.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
        vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0));&lt;br /&gt;
        vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
        vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y;&lt;br /&gt;
        pos = pos / (abs(pos)+1.0);&lt;br /&gt;
        pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
        pos = pos * 0.5 + 0.5; //auf Texturkoordinaten umrechnen&lt;br /&gt;
 &lt;br /&gt;
        spos.xy = pos; //Daten in einer Varying verpacken&lt;br /&gt;
        spos.z = -mvertex.y * 0.5 + 0.5 - 0.005; // far and near clamping and Anti-Z-fighting-offset &lt;br /&gt;
 	&lt;br /&gt;
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //Die echte Transformation&lt;br /&gt;
 &lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten 5 Zeilen der main() sollten exakt das gleiche tun wie der Vertexshader zum gnerieren dem Map.&lt;br /&gt;
&lt;br /&gt;
Nun fehlt noch ein Fragmentshader für den letzten Durchgang:&lt;br /&gt;
&lt;br /&gt;
Es muss noch der Noralvektor berücksichtigt werden!!!&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Shadowmap;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
 &lt;br /&gt;
void main(void){&lt;br /&gt;
        if (texture2D(Shadowmap, spos.xy).r &amp;gt; spos.z ){&lt;br /&gt;
              //Licht&lt;br /&gt;
              gl_FragColor = vec4(1.0,1.0,1.0,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        else{&lt;br /&gt;
              //Schatten&lt;br /&gt;
              gl_FragColor = vec4(0.5,0.5,0.5,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Parabolide Maps==&lt;br /&gt;
&lt;br /&gt;
Einfache parabolide Maps können für alle Punktlichquellen verwendet werden, deren Licht nicht in alle Richtungen abgestrahlt wird. Darunter fallen vorallem Spots und an Wänden oder Decken befestigte Lampen. Im gegensatz zur Paralelem Licht oder einer Punktlichquelle bringt eine solche Lichtquelle häufig eine Helligkeitsmap mit. Für die Helligkeitsmap und die Schattenmap können die gleichen Texturkoordinaten verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Bei kleinen Öffnungswinkeln hat die parabolide Map keinen Vorteil gegenüber einer normalen Projektion. Der Vortiel ist jedoch das der Code sich für Öffnungswinkel von bis zu ~240 Grad eignet. &lt;br /&gt;
&lt;br /&gt;
Um eine solche Lichquelle zu beschreiben weden nicht weniger als drei Vektoren benötigt:&lt;br /&gt;
&lt;br /&gt;
* Position&lt;br /&gt;
* Richtung &lt;br /&gt;
* Tangent&lt;br /&gt;
&lt;br /&gt;
Wärend die Funktion der ersten beiden Vektoren klar ist, wird der Tangent wird dazu benötigt die Schattenmap und Helligkeitsmap auszurichten. Er ist Senkrecht zur Richtung tangential zur Textur ausgerichtet &lt;br /&gt;
Beschreiben lässt sich diese Funktion lässte sich am ehesten durch das Verdrehen einer Taschenlampe. Wenn die Schattenmap gegenüber den schattenwerfenden Objekten verdreht wird, sieht das Bild auf keinen Fall mehr natürlich aus.&lt;br /&gt;
 &lt;br /&gt;
Es ist sowohl möglich die Berechnungen im Vertexshader durchzuführen, als auch eine entsprechnede Matrix in den Uniformvariablen abzulegen. Wenn die Berechnungen per Matrix durchgefühert werden lässt sich das Prinzip der paraboliden Maps zuindest als Reflektionsmap nutzen. Ein weiterer Vorteil an einer vorberechneten Matrix ist, dass diese auch für shadowmap verwendet werdne kann die nicht jedes Frame neu berechnet werden.&lt;br /&gt;
&lt;br /&gt;
==Dual Parabolide Maps==&lt;br /&gt;
Von OpenGL kennen wir zwei Projektionsmöglichkeiten: Orthografische und perspektivische Projektion. Beide Projektionen arbeiten ohne Verzerrung. Jede Gerade bleibt beim Transformieren eine Gerade. Wenn man dagegen das Bild eines Fischeyeobjektives betrachtet, allen einem sofort die zu Kurven verzerrten Geraden auf. Der entscheidene Vorteil an einer Fisheyeaufnahme ist, dass ein Öffnungswinkel von 180 Grad erfasst werden kann. Zwei entgegensetzte Aufnahmen können so problemlos den kompletten Raum um die Kamera erfassen.&lt;br /&gt;
&lt;br /&gt;
Für das Erstellen der Tiefenmap ist es notwendig den Raum um das reflektierende Objekt in eine Textur zu rendern. Meistens wird hier eine Cubemap verwendet. Soll diese dynamisch generiert werden, ist es auffällig, dass die Scene ganze 6 mal gerendert werden muss. Mit der dual paraboliden Map sind nur noch zwei Rendervorgänge nötig, es wird zwar keine Füllrate eingespart, dafür müssen nun nur noch 1/3 der Daten transformiert werden, so das die Vertexshader und die CPU entlastet werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitere Optimierung ist unter Umständen möglich: Wenn bei einer Cubemap auf eine der Flächen verzichte werden kann. Z.B. wird die Reflektion im Lack eines Autos so gut wie nie verdeckte Straße zeigen. Auch ist für eine an einer  Wand befestigten Lampe nur eine halbkugelförmige Shadowmap nötig. Wenn sie einen Abstand zur Wand hat, genügt es auch hier den Blickwinkel von 180 Grad etwas zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Die Projektion der dualparaboliden Map kann man sich am besten Bild eines Fisheyobjektives vorstellen. Mathematisch etwas genauer ist das Reflektionsbild der umgebenden Welt in einem Rotationsparaboliden.&lt;br /&gt;
&lt;br /&gt;
Die Hardwareanforderungen an den Pixelshader sind nicht gerade gering. Der Pixelshader für die 8fachen Lichquellen kommt nach dem Compelieren auf über 170 Instruktions. Eine Shader 2.0 Karte wie z.B. die Radeon 9x00 sind hier hoffnungslos überfordert da sie nur an 3 Stellen im Programm auf die Textureinheiten zugreifen können und der Assembler nicht mehr in der Lage ist die Instruktions passend umzusortieren. Noch fataler wird es  wenn die Texturelookups durch dynamisches Branching übersprungen weder sollen: Die Karte hat keine Chance mehr diese umzusortieren.&lt;br /&gt;
&lt;br /&gt;
Wer dualparbolide Maps auf SM2.0 Karten einsetzten will sollte damit rechnen, dass das Limit bei 2 bis 4 Maps liegen sollte.&lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
So kann in der Hauptschleife das rendern der 16 paraboliden Maps und der anschließende Finale Renderdurchgang durchgeführt werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for (int light;light&amp;lt;8;light++){&lt;br /&gt;
        glViewport (shadow_size/2*(lights/4),shadow_size/4 *(light%4),shadow_size/4,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;light&amp;quot;),light);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),0);&lt;br /&gt;
        render();&lt;br /&gt;
        glViewport (shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light%4),shadow_size/4 ,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),1);&lt;br /&gt;
        render();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Vieport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0,Windowsize_X,Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for light := 0 to 7 do&lt;br /&gt;
begin&lt;br /&gt;
  glViewport(shadow_size/2*(lights/4), shadow_size/4 *(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'light'), light);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'), 0);&lt;br /&gt;
  render();&lt;br /&gt;
  glViewport(shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'),1);&lt;br /&gt;
  render();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Viewport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0, Windowsize_X, Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Die Shader===&lt;br /&gt;
&lt;br /&gt;
====Shader zum Rendern der Schattenmaps====&lt;br /&gt;
parabol.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;  uniform int renderpass;&lt;br /&gt;
  uniform int light;&lt;br /&gt;
  varying vec3 normal;&lt;br /&gt;
  varying vec3 pos;&lt;br /&gt;
&lt;br /&gt;
  void main(void){&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewMatrix * gl_Vertex - gl_LightSource[light].position ;&lt;br /&gt;
&lt;br /&gt;
	float L= length (gl_Position.xyz);&lt;br /&gt;
	gl_Position /= -L;&lt;br /&gt;
	if (renderpass == 1) gl_Position.z *=-1.0;&lt;br /&gt;
	gl_Position.z += 1.0;&lt;br /&gt;
	gl_Position.xy /= gl_Position.z;&lt;br /&gt;
	if (gl_Position.z &amp;gt;= 0.01){&lt;br /&gt;
		gl_Position.z = L / 15.0;//Todo: optimieren&lt;br /&gt;
		gl_Position.w = 1.0;&lt;br /&gt;
		}&lt;br /&gt;
	else{&lt;br /&gt;
		gl_Position.z = -1.0;&lt;br /&gt;
		gl_Position.w = -1.0;&lt;br /&gt;
		}&lt;br /&gt;
        &lt;br /&gt;
        gl_Position.z = 2.0 * gl_Position.z -1.0; //Todo: optimieren&lt;br /&gt;
	pos=gl_Position.xyz;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
parabol.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 pos;&lt;br /&gt;
void main(void){&lt;br /&gt;
	if (length(pos.xy)&amp;gt;1.005)discard; //Diese Zeile kann durchaus entfallen. Kosten/Nutzen unbekannt.&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Uniformaviablen, die gesetzt werden müssen: Eine ist die Nummer der aktuellen Lichtquelle und die zweite der Renderpass, der angibt ob die Vorder- oder Rückseite der parabolischen Map gerendert werden soll. Eine automatische Berechnung der Texturkoordinaten wäre zwar möglich, jedoch ist die Änderung des Viewports deutlich weniger Rechenaufwendig.&lt;br /&gt;
&lt;br /&gt;
Statt einer Multiplikation des gl_Vertex mit der gl_ModelViewProjektionMatrix wird hier nur mit der gl_ModelViewMatrix multipliziert. Dadurch werden nur die Transformationen durchgeführt und die Projektion übersprungen.&lt;br /&gt;
Die Division durch -L entspricht weitgehend einer Normalsierung, spiegelt die Welt jedoch in die richtige Lage. L enthält jetzt die Tiefeninformation, gl_Position einen Vektor, der von der Kammera auf den Vertex zeigt. Mit den zwei folgenden Zeilen wird der Vektor parabolisch auf die Bildschirmkoordinaten projeziert (Intervall von -1.0 bis 1.0). Mit Hilfe der folgenden if-Abfrage werden alle Vertices hinter der Kammera geclipt. Nur sichtbare Vertices bekommen gültige z Werte für den Zbuffer im Intervall von -1.0 bis 1.0. &lt;br /&gt;
&lt;br /&gt;
Der Fragmentshader ist extrem einfach, da wir aufgrund des nicht vorhandem Colorbuffers keinen Farbwert benötigen lassen wir diesen wie bei den perspektivischen Maps einfach undefiniert.&lt;br /&gt;
Zudem verlassen wir den Shader mit discard, wenn der der Pixel außerhalb der aktuellen paraboliden Map liegt. Die Voteil ist, das nur der kreisförmige Bereich der Map verwendet wird, der Nachteil, das durchaus eine Early-Z optimierung nicht mehr möglich ist. Sehr Sinvoll sollte dies sein, wenn die Shadowmaps dynamisch nach benötigter Größe angeordnet werden. Da sich Kreise besser als Quadrate packen lassen.&lt;br /&gt;
&lt;br /&gt;
====Shader für den finalen Renderdurchgang====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
final.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	Normal = gl_NormalMatrix * gl_Normal;&lt;br /&gt;
 	ModelVertex  = vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
final.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
uniform int MaxLights;&lt;br /&gt;
&lt;br /&gt;
//Achtung folgende Zeile ist nicht GLSL konform. &lt;br /&gt;
//Workaround: Array als Uniform übergeben oder durch sehr aufwendige berechnung erstzten&lt;br /&gt;
//Sollte es auch auf ATI Karten funktinieren, frage ich mich warum es nicht erlaubt ist...&lt;br /&gt;
const vec2 texofset[8] = {vec2 (0.125,0.125), vec2 (0.125,0.375), vec2 (0.125,0.625), vec2 (0.125,0.875),&lt;br /&gt;
			  vec2 (0.625,0.125), vec2 (0.625,0.375), vec2 (0.625,0.625), vec2 (0.625,0.875)};&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
	vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
	for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
		vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
		vec3 lightdir = normalize( lightvec );&lt;br /&gt;
		vec2 parabol = texofset[LightNum];&lt;br /&gt;
		if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
			parabol.t += 0.25;&lt;br /&gt;
			}&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
		parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
		vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
		light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
		}&lt;br /&gt;
	vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));	//Textur auslesen; &lt;br /&gt;
	gl_FragColor = light * color ;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Möglicher weise für ATI taugliche Variante:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
 &lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
const int MaxLights=8;&lt;br /&gt;
 &lt;br /&gt;
vec2 texofset[8]; &lt;br /&gt;
void main(void){&lt;br /&gt;
	texofset[0] = vec2 (0.125,0.125);&lt;br /&gt;
	texofset[1] = vec2 (0.125,0.375);&lt;br /&gt;
	texofset[2] = vec2 (0.125,0.625);&lt;br /&gt;
	texofset[3] = vec2 (0.125,0.875);&lt;br /&gt;
	texofset[4] = vec2 (0.625,0.125);&lt;br /&gt;
	texofset[5] = vec2 (0.625,0.375);&lt;br /&gt;
	texofset[6] = vec2 (0.625,0.625);&lt;br /&gt;
	texofset[7] = vec2 (0.625,0.875);&lt;br /&gt;
&lt;br /&gt;
        vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
        vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
        for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
                vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
                vec3 lightdir = normalize( lightvec );&lt;br /&gt;
                vec2 parabol = texofset[LightNum];&lt;br /&gt;
                if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
                        parabol.t += 0.25;&lt;br /&gt;
                        }&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
                parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
                float shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
                light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
                }&lt;br /&gt;
        vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0])); //Textur auslesen; &lt;br /&gt;
        gl_FragColor = light * color ;&lt;br /&gt;
        }&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Shader besitzen 3 Uniformvariablen, die unbedingt mit den richtigen Werten gefüllt werden müssen. Zwei davon sind Texturen, die dritte die Anzahl der aktiven Lichtquellen. Es ist wichtig zu wissen, dass der Shader nicht den OpenGL-Status der Lichquellen berücksichtigt und nur die Daten der Ersten bis MaxLights holt.&lt;br /&gt;
Während bei den Schattenmaps die meiste Arbeit im Vertexshader erledigt werden könnte, ist dieser sehr Fragmentshader lastig. Die Texturkoordinatenberechnung ist sehr ähnlich zu der im shadow.vert. Die größte Änderung ist, dass hier abhängig von der Lichtquellennummer ein Offset aufaddiert wird um die Untertextur auszuwählen. Ein zusätzlicher Offset wird dazuaddiert, wenn auf die zweite parabolide Map einer Lichtquelle zugegriffen wird.&lt;br /&gt;
Um ein dynamisches Branching zu vermeiden, wird mit der Stepfunktion ermittelt ob sich das Fragment im Schatten befindet.&lt;br /&gt;
&lt;br /&gt;
==Optimierungen und Verbesserungen==&lt;br /&gt;
Hier sind noch einige Vorschläge, die helfen können um besser Qualität oder Leistungen im eigenem Programm zu bekommen. Eine uniververselle Lösung lässt sich nur auf kosten von Performance schreiben. Viel besser ist es, wenn man die Shader an die jeweilige Situation anpasst. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schatten durch Alphatest===&lt;br /&gt;
Der bisherige Schattenshader kann nur ganze Polygone einen Schatten werfen lassen. Wenn shadow.vert so ergänzt wird, das die Texturkoordinaten in den Fragmentshader  weitergereicht werden, dann ist es mit folgendem Fragmentshader möglich Shatten in Abhängikeit einer Alphatextur zu rendern:&lt;br /&gt;
&lt;br /&gt;
shadow.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
        if (texture2D(Texture0,vec2(gl_TexCoord[0])).a &amp;lt; 0.5) discard;&lt;br /&gt;
}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Shader wird verlassen wenn das Texel einen Alphawert von kleiner als 50% hat. Damit lassen sich Schatten von Pflanzen wesentlich realistischer darstellen. Dieser Shader sollte natürlich nur dann verwendet werden, wenn eine Alphakanal in der Textur vorhanden ist. Auch Shader mit Paralax- oder Displacementmapping arbeiten kann man so um einen Schatten ergänzen, wenn die Polygone transparente Teile enthalten.&lt;br /&gt;
Es ist auch möglich den shader zu verlassen, wenn eine bestimmte Farbe in der Textur gefunden wird, dann nimmt die Alphamaske keinen Speicherplatz mehr weg.&lt;br /&gt;
&lt;br /&gt;
===Farbiges Glas===&lt;br /&gt;
&lt;br /&gt;
Schatten hat jetzt ja sachon fast jeder. Aber wie wäre es mal mit einfärben von dynamischen Lichtquellen?&lt;br /&gt;
Der Algoritmus ist nicht schwer:&lt;br /&gt;
&lt;br /&gt;
* Alle Undurchichtigen Sceneteile in die Tiefenmaps gerendert. &lt;br /&gt;
* Zusätzlich wird eine Colormap gebunden und das Schreiben in den Zbuffer unterbunden.&lt;br /&gt;
* Die Colormap wird mit Weiß oder einer Helligkeitsmap initialisiert.&lt;br /&gt;
* Rendern aller transparenten Objekten&lt;br /&gt;
* Auf finales Rendern umschalten&lt;br /&gt;
* Alle undurchsichtigen Objekte mit hilfe der Schadowmap und der modifizierten Beleuchtungmap beleuchten.&lt;br /&gt;
* Alle Transparenten Objekte rendern, unter Berücksichtigung, dass die Lichtquelle bereits das gefilterte Licht aussendet. Dieses Blending sollte rückgängig gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Bei diesem Algoritmus bleibt noch das Alphablendingproblem mit der mehrfachen Überdeckung. Beim Modifizieren der Beleuchtungsmap gegebenfalls den Stencilbuffer zur Hilfe nehmen. Hier wäre ein denkbarer Algoritmus:&lt;br /&gt;
&lt;br /&gt;
* Alle transparenten Poligone in den Zbuffer rendern. Dabei für alle Poligone, deren  doppelte Filterung zu Fehlern führen kann mit verschiedenen Stencilwerte schreiben.&lt;br /&gt;
* Zbuffer und Colorbuffer Löschen. &lt;br /&gt;
* Helligkeitsmap in den Colorbuffer kopieren.&lt;br /&gt;
* Alle nicht transparanten Objekte in den Zbuffer Rendern. &lt;br /&gt;
* Alle transparenten Poligone mit den gleichen Stencilwerten wie im erstem Pass rendern. Die Bedingung ist, dass nur Polygone in den Zbuffer geschrieben werden, bei den Stencilwerte nicht mit den Stencilbuffer übereinstimmen. Die vordersten Polygone werden so aussortiert und nur die zweite Schicht landet im Zbuffer.&lt;br /&gt;
* Im letztem Rendervorgang müssen die gefilterten Lichtfarben der Transparenten Polygone in den Colorbuffer geschrieben werden. Die Bedingung ist das die Stencilwerte übereinstimmen müssen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn es wie ein großer Mehraufwand aussieht, ist der Anteil der transparenten Poligone doch eher gering. So das deren dreifacher Overdraw kaum eine Rolle spielt. Im Finalem Renderdurch gang gibt es bei den transparenten Polygonen noch eine Besonderheit: Stimmt die Entfernung aus der Shadowmap mit der Entfernung der Lichquellen (fast) überein, so wird das Poligon mit dem Licht aus der Colormap belauchtet. Ist die Entfernung aus der Shadowmap jedoch größer als die entfernung zu lichquellen, enthällt die Colormap die gefilterte Farbe des Lichtes hinter dem Poligon. Für die beleutung des Poligon muss also das Licht der Lichquelle benutzt werden. Sinvoll ist es die helligkeit für diesen Fall im Alphawert der Colormap zu Speichern.&lt;br /&gt;
&lt;br /&gt;
Ansonsten noch ein paar Vorschläge:&lt;br /&gt;
* Objekte die aus dem gleichem Glas sind und auch einfarbig. Sollten mit dem gleichem Stencilwert verarbeitet werden. So sieht z.B. das gefärbte Licht einer zweifach durchstrahlten leicht gefäbten Glasskuppel natürlicher aus als ein Vollschatten. Auch wenn das Licht korrekter weise zwei mal hätte gefiltert werden müssen. &lt;br /&gt;
* Eventuel macht es sind mehrfarbige Objekte in mehrfache einfarbige Objekte zu zerlegen.&lt;br /&gt;
* Komplexe Mehrfachfilterungen sollten vermieden werden oder so gewählt werden, das sie natürlich ausehen. Gute Filter wären komplementärfarben, da dort ein echter Schatten erzeugt wird. Schlechte Kombinationen wären unter anderem Rot+Gelb, Blau+Gelb, usw...&lt;br /&gt;
* Um von den Farbfehlern abzulenken, farbige Objekte in einer rotverschobenen Farbe flourezieren lassen. (Violet-&amp;gt; Blau -&amp;gt; Grün -&amp;gt; Gleb -&amp;gt; Organge -&amp;gt; Rot) Durch blau gefärbte Fenster, blau gefilterte Licht welches Dinge grün aufleuchten lässt nimmt einem jeder PC Modder ab...&lt;br /&gt;
&lt;br /&gt;
===Schattenmap durch eine Heightmap modifizieren===&lt;br /&gt;
Auch wennich hierzu noch kein Beispiel haben, ist es möglich gl_FragDepth mit hilfe einer Heightmap zu modifizieren. Prinzipiell entspricht dies einem einfachem Offsetmapping. Damit wäre durchaus eine Selbstschattierung von Bumpmaps möglich.&lt;br /&gt;
&lt;br /&gt;
===Zweite parabolische Map vermeiden===&lt;br /&gt;
Lichtquellen, die nur in eine Richtung Licht werfen können, wie z.B. Spotlichter oder Lichter, die in Bodenähe oder Wandnähe befestigt sind, benötigen keinen vollständig erfassten Tiefenraum. Die Parabolische Map kann problemlos herein oder herausskaliert werden, so das Öffnungswinkel von 0 bis ca 240 Grad möglich sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das verkleinern des Öffnungswinkels für zusätzliche Spotlichter ermöglicht auch kleinere Tiefenmaps, die in die 9 Zwischenräume der großen gepackt werden können. Die Zwischenräume können noch Maps mit einem Durchmesser von 40% der großen Maps aufnehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Texturelookups vermeiden===&lt;br /&gt;
Wenn das Skalarprodukt von normalvec und -lightdir negativ ist, dann ist die Oberfläche von der Lichtquelle abgewandt und Berechnungen für die Lichquelle können komplett übersprungen werden. Diverse Multiplikationen und vorallem Texturelookups können so übersprungen werden. Besondere aufwendige Algorithmen wie selbstschattierende Bumpmaps, können so deutlich Beschleunigt werden. &lt;br /&gt;
&lt;br /&gt;
Für die Beleuchtung sollte dann allerdings auch folgende Zeile verwendet werden. (Das Skalarprodukt von vor der if Abfrage aber umbedingt wiederverwerten!) &lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
  light += gl_LightSource[0].diffuse * max(dot(normalvec, -lightdir), 0.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reichweite der Lichtquellen=== &lt;br /&gt;
Leider bietet OpenGL nicht direkt die Möglichkeit die maximale Reichweite einer Lichquelle anzugeben. In den Shadern wird zur Zeit der Wert 15.0 als maximale Entfernung zur Lichtquelle verwendet. Für ein einfaches Programm ist es sicher ausreichend, ansonsten macht es Sinn diesen Wert durch eine Unformvariable zu ersetzten, oder um mehr Flexibiltät zu bekommen durch ein Array aus 8 Uniformfloats.&lt;br /&gt;
&lt;br /&gt;
===Oversampling der Schattenmap===&lt;br /&gt;
Die Qualität lässt sich dadurch mehrere Samples auf der Schattenmap verbessern. Das folgende Codefragment nimmt 3 statt des einem Samples und glättet die Ränder des Schattens. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;const float pof =1.0 /4096.0 *0.7;&lt;br /&gt;
vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol +vec2(pof,0)).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,-pof/1.2) ).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,pof/1.2)).r );&lt;br /&gt;
light += shadow * 0.33 * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Durch 9x Oversampling lässt sich schon eine sehr gute Qualität ereichen, sorgt aber bei 8 Lichtquellen durch die 72 Texturelookups für einen Zusammenbruch der Framerate.&lt;br /&gt;
Wichtig ist auch, dass man beachtet, dass die dualparaboliden Maps an Ihren Ränden undefiniert sind und so zu Artefakten kommen kann wenn man außerhalb des gültigem Bereichs sampled. Eine Möglichkeit wäre einen Bereich zu erfassen, der etwas größer als 180 Grad ist, um am Rand zusätzliche Texel zu schaffen.&lt;br /&gt;
&lt;br /&gt;
===Ein zusätzlicher Renderpass===&lt;br /&gt;
Nach dem die Tiefenmap gerendert würde, wäre es möglich in einem weiterem Framebufferobjekt eine zusätzliche Map zu rendern, in der mit Hilfe einer Kantenerkennung die Helligkeit der Softshadows vorberechnet wird. Auch hier muss berücksichtigt werden, dass die dualparaboliden Maps einen Übergang haben.&lt;br /&gt;
&lt;br /&gt;
===Dynamische Lichter in statische Lightmaps Rendern===&lt;br /&gt;
Wenn sich Lichtquellen nicht relativ zur Umgebung nicht bewegen, ist es möglich sie in eine Lightmap zu rendern. Unter der Annahme, dass Lightmapkoordinaten vorhanden sind (ohne geht es echt nicht gut), müssen diese nur per Vertexshader an den Pixelshader weitergegeben werden. Im Pixelshader kann dann wie im final.frag die Helligkeit berechnet werden und in der Lightmap abgespeichert werden.&lt;br /&gt;
Es ist immer noch möglich, das dynamische Objekte einen Schatten werfen: Es werden nur noch die beweglichen Objekte in die Tiefenmap gerendert. Im Schatten wird dann einfach das Licht der im Schatten liegenden Lichtquelle subtraiert.&lt;br /&gt;
&lt;br /&gt;
===Statische Anteile in den Schattenmaps===&lt;br /&gt;
Es ist möglich mit einer zusätzlichen Matrix die Tiefenmaps zu den Weltkoordinaten auszurichten. Statische Anteile können dann aus einer zweiten Tiefenmap kopiert werden. Ein wenig problematisch ist das Entfernen der Rotation aus der gl_ModelViewMatrix. Das größte Problem ist, das die Positionen der Lichquellen bereits mit der gl_ModelViewMatrix multipliziert sind. Die einfachste Lösung ist, aus den den Rotationswinkeln eine neue Matrix zu erechnen, mit dessen Hilfe die Schattenvektoren für die Texturkoordinatenberechnung zurückgedreht werden. Diese Matrix sollte dann als Uniformvariable übergeben werden.&lt;br /&gt;
Wenn die Schatten durch einen zusätzlichen Renderdurchgang gefiltert werden. Ist es sinvoll die Maps erst hier zu vereinen. Von beiden Tiefenmaps muss nur immer der kleinere Wert genommen werden.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19727</id>
		<title>GLSL Licht und Schatten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19727"/>
				<updated>2006-10-08T15:11:24Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Schatten durch Alphatest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Willkommen zu meinem erstem Tutorial. Schatten können sowohl Traum als auch Albtraum eines jeden OpenGL-Progrmamieres werden. Im Gegensatz zur einfachen Beleuchtung mit Lichtquellen, steigt der Rechenaufwand hier extrem an und ohne Optimierung zwingen die Schatten selbst die modernste Hardware in die Knie.&lt;br /&gt;
Für Schatten gibt es zwei praktikable Algoritmen: Den Stencilschatten und den projezierten Schatten. Hier möchte ich mich auf den projezierten Schatten beschränken, er bietet gegenüber dem Stencilschatten einige Vorteile:&lt;br /&gt;
&lt;br /&gt;
*Die komplette Berechnung kann von der Grakfikkarte übernommen werden&lt;br /&gt;
*Es ist möglich Softshadows zu realisieren&lt;br /&gt;
*Die Shadowmaps können unter Umständen für mehr als ein Frame verwendet werden&lt;br /&gt;
&lt;br /&gt;
Um den Rechenaufwand zu veringern werde ich hier zusätzliche Projektionstechniken zeigen, die über den Vertexshader realisiert werden: Die perspektivische Map und das parabolide Mapping. &lt;br /&gt;
&lt;br /&gt;
Für sehr weit entfernte Lichtquellen und offene Szenen ist der Einsatz von perspektisch angepassten Maps sinvoll. Da das Licht quasi parallel ausgestrahlt wird. Ist ein winkelabhängiger Cube oder dualparabolische Map kaum möglich. Auch eine einfache quadratische Shadowmap zeigt deutliche Schwächen bei der Auflösung im Nahbereich und dem zu hohem Oversampling in der Entfernung.&lt;br /&gt;
&lt;br /&gt;
Das parabolide Mapping ermöglicht nicht nur die Simulation eine Fischaugenoptik, sondern kann auch die Cubemap vollständig ersetzen. Durch einen geringfügig höheren Rechen- und Programieraufwand genügen zwei Renderpasses um eine vollständige Tiefen- oder Reflektionsmap zu erstellen. Was gegenüber der klassischen Cubemap den Prozessor und GPU um den Faktor 3 entlastet.&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Dieses Tutorial basiert auf den grundlegenden Techniken, die erst in den letzten Jahren entwickelt wurden. Jeder der hier mit anfängt, sollte die zwei anderenen GLSL Tutorials gelesen haben und einfache Fragmentshader schreiben können. Auch das Laden und Einbinden von Texturen in die Shader sollte kein Problem mehr darstellen.&lt;br /&gt;
&lt;br /&gt;
===Framebufferobjekte===&lt;br /&gt;
Für das Erstellen von dual paraboliden Tiefentexturen ist noch das Rendern in Framebufferobjekten Vorraussetzung (zu denen es leider noch kein Tutorial gibt). Damit der Einstieg nicht zu schwer wird sollte dieser Code helfen das FBO zu initialsisieren:&lt;br /&gt;
&lt;br /&gt;
Als Erstes müssen die nötigen Extensions initialisiert werden&lt;br /&gt;
Dann sollten die benötigten Modelle als VBO in die Grafikkarte hochgeladen werden.&lt;br /&gt;
Nun muss das Framebufferobjekt (FBO) für die Schattenmaps erzeugt werdern.&lt;br /&gt;
So könnte die Initialsierung des FBOs aussehen. C code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;GLuint shadow_map = 0; // &lt;br /&gt;
GLuint shadow_fbo = 0; // the shadow texture&lt;br /&gt;
GLuint shadow_size = 4096; //muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
glGenTextures (1, &amp;amp;shadow_map); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindTexture (GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
glTexImage2D (GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0,GL_DEPTH_COMPONENT , GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
glGenFramebuffersEXT (1, &amp;amp;shadow_fbo); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D,shadow_map, 0);&lt;br /&gt;
glDrawBuffer (GL_FALSE);&lt;br /&gt;
glReadBuffer (GL_FALSE);&lt;br /&gt;
GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/cpp&amp;gt;&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;var shadow_map,&lt;br /&gt;
    shadow_fbo,&lt;br /&gt;
    shadow_size : GLuint;&lt;br /&gt;
    status      : GLenum; &lt;br /&gt;
begin&lt;br /&gt;
  shadow_map  := 0;  &lt;br /&gt;
  shadow_fbo  := 0;     // the shadow texture&lt;br /&gt;
  shadow_size := 4096; // muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @shadow_map);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @shadow_fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadow_map, 0);&lt;br /&gt;
  glDrawBuffe (GL_FALSE);&lt;br /&gt;
  glReadBuffer(GL_FALSE);&lt;br /&gt;
  status := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt sollten die Shader und weiter Texturen geladen werden.&lt;br /&gt;
&lt;br /&gt;
===Beschleunigtes Rendern===&lt;br /&gt;
&lt;br /&gt;
Ich empfehle auch die zu rendernden Daten als Vertexbufferobjekte zu übergeben, da sonst die Mehrfachverwendung der Daten zu einer extremen Bremse wird. Da es hierzu bereits ein Tutorial gibt werde ich hier nichts mehr darüber schrieben.&lt;br /&gt;
Alternativ sollte alles was zwischen glBegin und glEnd in Displaylisten gespeichter werden. Das Speichern von Texturwechseln usw ist nicht sinvoll, da diese nicht zum Rendern der Shadowmaps benötig werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehrfachen Lichquellen kann es wiederum Sinn machen den ersten Rendervorgang inclusive Shaderwechsel in einer Displayliste zwischenzuspeichen und die zusätzlichen Schadowmaps mit dieser zu rendern.&lt;br /&gt;
&lt;br /&gt;
===Algemeines zu GLSL===&lt;br /&gt;
Ich möchte nocheinmal darauf hinweisen, das sich uniformvariablen nur setzten Lassen, wenn der entsprechnde shader gebunden ist. (Es funktionier nicht wenn der shader nicht gebunden ist. Warum man den shader dabei allerdings angeben muss ist mir nicht so ganz klar)&lt;br /&gt;
In den Beispielen werden nur die Uniformvariablen wärend des Rendervorgangs neu gesetzt die sich ändern.  Die zuweisung der TMU zu einem Sampler gehöhrt in der Regel nicht dazu. &lt;br /&gt;
&lt;br /&gt;
===Grundlegendes zu den Koordinatensystemen in den Shadern===&lt;br /&gt;
&lt;br /&gt;
Im Vertexshader müssen alle komponenten von gl_Position in einem Bereich von -1.0 bis 1.0 gebracht werden. Besonders beim Z-Wert könnte es verwirrend, dass der Bereich  von gl_FragDepth im Fragmentshader von 0.0 bis 1.0 geht. Auch muss beachtet werden, dass Texturkordinaten den bereich von 0.0 bis 1.0 nutzen, wärend die Rendertargets im Bereich on -1.0 bis 1.0 arbeiten.&lt;br /&gt;
In den Shadern werden daher öfters Multimplikationen mit 0.5 und einer anschließenden Addition von 0.5 auftreten.&lt;br /&gt;
&lt;br /&gt;
==Perspektivische Maps==&lt;br /&gt;
&lt;br /&gt;
In dem erstem Teil dieses Artikels geht es um perspektivisch angepasste Schattenmaps. Normale projezierte Schatten haben das Problem, das sie im Nahenbereich besonders stark verpixeln und in der Entfernung durch ein viel zu hohes Oversampling Bandbreite verschwenden.&lt;br /&gt;
&lt;br /&gt;
Für eine globale Lichquelle wird nur ein Vektor gegeben, der die Richtung des Lichtes beschreibt. Die gedachte Lichtquelle ist quasi unendlich weit weg. Da eine Entfernungsberechnung zur Lichquelle unmöglich ist, muss die Schattenberechnung relativ zu einer Referenzebene durchgeführt werden. Diese Ebene kann sowohl Senkrecht zum Lichvektor, als auch parallel zum gedachtem Boden ausgerichtet werden. Die Ausrichtung der Referenzebene beeinflusst die später sichtbare Auflösung der Schatten.&lt;br /&gt;
&lt;br /&gt;
Nach dem ein Vertex auf die Ebene projeziert wurde und der Abstand ein einen berech von 0.0...1.0 gebracht wurde, muss diese unendlich große Ebene noch auf eine endliche Größe projeziert werden, die auf eine Textur passt und die entfernungsabhängige Detailierung beachtet.&lt;br /&gt;
&lt;br /&gt;
Wenn wir unsere Referenzebene einfachhalber den Horizont schneidet (und auch den Bildschirm in obere und untere Hälfte teilt) Könnte ein Algorimus in etwa so aussehen (Dieser lässt sich später in ein Vertexshaderprogramm umsetzten):&lt;br /&gt;
&lt;br /&gt;
Projeziere den Vertex in die Modelview (Diese Schritt wurde auch bei den dualparaboliden Maps durchgeführt)&lt;br /&gt;
Ermittel den Schnittpunt des vom Vertex ausgehendem gedachtem Lichtstrahl und der Referenzebene.&lt;br /&gt;
Benutze den Abstand zwischen Schnittpunkt und Vertex um den Z-Wert zu ermitteln. (Es sind zwei zusätzlich referenzwerte nötig die die funktion Farclip und Nearclip übernehmen)&lt;br /&gt;
Projeziere die Ebene auf eine Ebene die in eine Textur passt pos/=abs(pos)+1.0 passt recht gut.&lt;br /&gt;
Anschließend wird noch die Schadowmap noch gestreckt und der Bereich hinter der Kammera entfernt.&lt;br /&gt;
&lt;br /&gt;
Das wichtigste ist, dass beim auswerten der shadowmaps der gleiche Projektionsalgoritmus verwendet wird wie beim generieren.&lt;br /&gt;
&lt;br /&gt;
Prinzipell sollte sich der Algoritmus schon auf einer Geforce 3 oder Radeon 8500 implementieren lassen. Da da der Code hier in GLSL geschrieben ist, sollte in etwa Shadermodel 2.0 unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeitsmäßig ist dieser Algoritmus den Stencilshadows deutlich überlegen. Auch bei Stencilshadows sind mehrere Renderpasses nötig. Vorallem das extruieren der Siluetten kostet einiges an Bandbreite. Der geschätzte Aufwand ist etwa 20 (Aufwendige Shader im Finalem Renderdurchgang)bis 80% (CPU limitiert Geometrieübergabe) Mehraufwand gegenüber einer Schattenlos gerenderten Scene.&lt;br /&gt;
Auch die Qualität ist nicht schlechter. Bei der Verwendung von weichen Schatten wirken Shadowmaps natürlicher als die extrem scharfen Stencilshadows. &lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
In der Hauptschleife könnte folgender Code verwendet werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, 0 ); //Entfernt alle Texturen aus der ersten TMU&lt;br /&gt;
	glUseProgramObjectARB(shadow); //lädt den Schattenshader&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb); //Bindet das Framebufferobjekt&lt;br /&gt;
	&lt;br /&gt;
	glViewport (0, 0,shadow_sz,shadow_sz); //Anpassen des Viewportes &lt;br /&gt;
	glClear(GL_DEPTH_BUFFER_BIT); //Z-Buffer löschen&lt;br /&gt;
	&lt;br /&gt;
	render(); //Erster Renderdurchgang&lt;br /&gt;
&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); //Normalen Framebuffer binden&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, shadow_tx ); //Tiefenmap an die erste TMU binden&lt;br /&gt;
	glUseProgramObjectARB(final); //finalen shader binden&lt;br /&gt;
	&lt;br /&gt;
	glViewport(0, 0, screen_size_x, screen_size_y);&lt;br /&gt;
	&lt;br /&gt;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Color und Z-Buffer löschen&lt;br /&gt;
	render(); //rendern&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Shader===&lt;br /&gt;
&lt;br /&gt;
Als erstes der Vertexshader zum generieren der Schadowmap. shadow.vert:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){&lt;br /&gt;
&lt;br /&gt;
	vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0)); //Lichtvektor in den Modelsprace rotieren&lt;br /&gt;
	vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex); //Vertex in den Modelspace projezieren&lt;br /&gt;
	vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y; //Schnittpunkt mit der XZ Referenzebene&lt;br /&gt;
	pos = pos / (abs(pos)+1.0); //Projektion der Ebene auf ein Quadrat&lt;br /&gt;
	pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
	gl_Position.xy = pos;&lt;br /&gt;
	gl_Position.z = -mvertex.y ; // Der Bereich von +-1 über der Referenzebene wird erfasst&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Lichtrichtung wird vorläufig noch fest übergeben. Eine Auswertung einer Opengl Lichtquelle oder einer Uniformvariable wäre ebenfalls möglich. Anschließend wird der Vertex in die Modelview projeziert und der Schnittpunkt des vom Vertexausgehendem Lichstrahls mit der Referenszebene berechnet. Als letztes wird noch der Abstand zur Referenzebenein einem Bereich 0..1  umgerechnet und die Texturkoordinaten für eventuelles Alphamasking oder Heightmapping durchgeschleift. Soll Alphamasking verwendet werden, muss ein entsprechender Shader geschrieben werden der bei den freizulassenden pixeln discard(); aufruft. Dies sollte jedoch nur für die betroffenen Poligone stat finden, da die Grafikkarte dann keine Early-Z Optimierungen verwenden kann. Ansonsten ist der Fragmentshader ist sehr einfach: shadow.frag:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die für die Auswertung müssen wir im finalem Renderdurchgang exakt die gleichen Texturkoordinaten für die Shadowmap generieren. Allerdings gibt es eine Besonderheit: Die koordinaten einer Textur reichen von 0;0 bis 1;1, Die Koordinaten eines Rendertargets reichen jedoch von -1;-1 bis 1;1, so das eine zusätzliche korrektor nötig ist.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
        vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0));&lt;br /&gt;
        vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
        vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y;&lt;br /&gt;
        pos = pos / (abs(pos)+1.0);&lt;br /&gt;
        pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
        pos = pos * 0.5 + 0.5; //auf Texturkoordinaten umrechnen&lt;br /&gt;
 &lt;br /&gt;
        spos.xy = pos; //Daten in einer Varying verpacken&lt;br /&gt;
        spos.z = -mvertex.y * 0.5 + 0.5 - 0.005; // far and near clamping and Anti-Z-fighting-offset &lt;br /&gt;
 	&lt;br /&gt;
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //Die echte Transformation&lt;br /&gt;
 &lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten 5 Zeilen der main() sollten exakt das gleiche tun wie der Vertexshader zum gnerieren dem Map.&lt;br /&gt;
&lt;br /&gt;
Nun fehlt noch ein Fragmentshader für den letzten Durchgang:&lt;br /&gt;
&lt;br /&gt;
Es muss noch der Noralvektor berücksichtigt werden!!!&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Shadowmap;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
 &lt;br /&gt;
void main(void){&lt;br /&gt;
        if (texture2D(Shadowmap, spos.xy).r &amp;gt; spos.z ){&lt;br /&gt;
              //Licht&lt;br /&gt;
              gl_FragColor = vec4(1.0,1.0,1.0,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        else{&lt;br /&gt;
              //Schatten&lt;br /&gt;
              gl_FragColor = vec4(0.5,0.5,0.5,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Parabolide Maps==&lt;br /&gt;
&lt;br /&gt;
Einfache parabolide Maps können für alle Punktlichquellen verwendet werden, deren Licht nicht in alle Richtungen abgestrahlt wird. Darunter fallen vorallem Spots und an Wänden oder Decken befestigte Lampen. Im gegensatz zur Paralelem Licht oder einer Punktlichquelle bringt eine solche Lichtquelle häufig eine Helligkeitsmap mit. Für die Helligkeitsmap und die Schattenmap können die gleichen Texturkoordinaten verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Bei kleinen Öffnungswinkeln hat die parabolide Map keinen Vorteil gegenüber einer normalen Projektion. Der Vortiel ist jedoch das der Code sich für Öffnungswinkel von bis zu ~240 Grad eignet. &lt;br /&gt;
&lt;br /&gt;
Um eine solche Lichquelle zu beschreiben weden nicht weniger als drei Vektoren benötigt:&lt;br /&gt;
&lt;br /&gt;
* Position&lt;br /&gt;
* Richtung &lt;br /&gt;
* Tangent&lt;br /&gt;
&lt;br /&gt;
Wärend die Funktion der ersten beiden Vektoren klar ist, wird der Tangent wird dazu benötigt die Schattenmap und Helligkeitsmap auszurichten. Er ist Senkrecht zur Richtung tangential zur Textur ausgerichtet &lt;br /&gt;
Beschreiben lässt sich diese Funktion lässte sich am ehesten durch das Verdrehen einer Taschenlampe. Wenn die Schattenmap gegenüber den schattenwerfenden Objekten verdreht wird, sieht das Bild auf keinen Fall mehr natürlich aus.&lt;br /&gt;
 &lt;br /&gt;
Es ist sowohl möglich die Berechnungen im Vertexshader durchzuführen, als auch eine entsprechnede Matrix in den Uniformvariablen abzulegen. Wenn die Berechnungen per Matrix durchgefühert werden lässt sich das Prinzip der paraboliden Maps zuindest als Reflektionsmap nutzen. Ein weiterer Vorteil an einer vorberechneten Matrix ist, dass diese auch für shadowmap verwendet werdne kann die nicht jedes Frame neu berechnet werden.&lt;br /&gt;
&lt;br /&gt;
==Dual Parabolide Maps==&lt;br /&gt;
Von OpenGL kennen wir zwei Projektionsmöglichkeiten: Orthografische und perspektivische Projektion. Beide Projektionen arbeiten ohne Verzerrung. Jede Gerade bleibt beim Transformieren eine Gerade. Wenn man dagegen das Bild eines Fischeyeobjektives betrachtet, allen einem sofort die zu Kurven verzerrten Geraden auf. Der entscheidene Vorteil an einer Fisheyeaufnahme ist, dass ein Öffnungswinkel von 180 Grad erfasst werden kann. Zwei entgegensetzte Aufnahmen können so problemlos den kompletten Raum um die Kamera erfassen.&lt;br /&gt;
&lt;br /&gt;
Für das Erstellen der Tiefenmap ist es notwendig den Raum um das reflektierende Objekt in eine Textur zu rendern. Meistens wird hier eine Cubemap verwendet. Soll diese dynamisch generiert werden, ist es auffällig, dass die Scene ganze 6 mal gerendert werden muss. Mit der dual paraboliden Map sind nur noch zwei Rendervorgänge nötig, es wird zwar keine Füllrate eingespart, dafür müssen nun nur noch 1/3 der Daten transformiert werden, so das die Vertexshader und die CPU entlastet werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitere Optimierung ist unter Umständen möglich: Wenn bei einer Cubemap auf eine der Flächen verzichte werden kann. Z.B. wird die Reflektion im Lack eines Autos so gut wie nie verdeckte Straße zeigen. Auch ist für eine an einer  Wand befestigten Lampe nur eine halbkugelförmige Shadowmap nötig. Wenn sie einen Abstand zur Wand hat, genügt es auch hier den Blickwinkel von 180 Grad etwas zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Die Projektion der dualparaboliden Map kann man sich am besten Bild eines Fisheyobjektives vorstellen. Mathematisch etwas genauer ist das Reflektionsbild der umgebenden Welt in einem Rotationsparaboliden.&lt;br /&gt;
&lt;br /&gt;
Die Hardwareanforderungen an den Pixelshader sind nicht gerade gering. Der Pixelshader für die 8fachen Lichquellen kommt nach dem Compelieren auf über 170 Instruktions. Eine Shader 2.0 Karte wie z.B. die Radeon 9x00 sind hier hoffnungslos überfordert da sie nur an 3 Stellen im Programm auf die Textureinheiten zugreifen können und der Assembler nicht mehr in der Lage ist die Instruktions passend umzusortieren. Noch fataler wird es  wenn die Texturelookups durch dynamisches Branching übersprungen weder sollen: Die Karte hat keine Chance mehr diese umzusortieren.&lt;br /&gt;
&lt;br /&gt;
Wer dualparbolide Maps auf SM2.0 Karten einsetzten will sollte damit rechnen, dass das Limit bei 2 bis 4 Maps liegen sollte.&lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
So kann in der Hauptschleife das rendern der 16 paraboliden Maps und der anschließende Finale Renderdurchgang durchgeführt werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for (int light;light&amp;lt;8;light++){&lt;br /&gt;
        glViewport (shadow_size/2*(lights/4),shadow_size/4 *(light%4),shadow_size/4,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;light&amp;quot;),light);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),0);&lt;br /&gt;
        render();&lt;br /&gt;
        glViewport (shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light%4),shadow_size/4 ,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),1);&lt;br /&gt;
        render();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Vieport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0,Windowsize_X,Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for light := 0 to 7 do&lt;br /&gt;
begin&lt;br /&gt;
  glViewport(shadow_size/2*(lights/4), shadow_size/4 *(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'light'), light);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'), 0);&lt;br /&gt;
  render();&lt;br /&gt;
  glViewport(shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'),1);&lt;br /&gt;
  render();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Viewport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0, Windowsize_X, Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Die Shader===&lt;br /&gt;
&lt;br /&gt;
====Shader zum Rendern der Schattenmaps====&lt;br /&gt;
parabol.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;  uniform int renderpass;&lt;br /&gt;
  uniform int light;&lt;br /&gt;
  varying vec3 normal;&lt;br /&gt;
  varying vec3 pos;&lt;br /&gt;
&lt;br /&gt;
  void main(void){&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewMatrix * gl_Vertex - gl_LightSource[light].position ;&lt;br /&gt;
&lt;br /&gt;
	float L= length (gl_Position.xyz);&lt;br /&gt;
	gl_Position /= -L;&lt;br /&gt;
	if (renderpass == 1) gl_Position.z *=-1.0;&lt;br /&gt;
	gl_Position.z += 1.0;&lt;br /&gt;
	gl_Position.xy /= gl_Position.z;&lt;br /&gt;
	if (gl_Position.z &amp;gt;= 0.01){&lt;br /&gt;
		gl_Position.z = L / 15.0;//Todo: optimieren&lt;br /&gt;
		gl_Position.w = 1.0;&lt;br /&gt;
		}&lt;br /&gt;
	else{&lt;br /&gt;
		gl_Position.z = -1.0;&lt;br /&gt;
		gl_Position.w = -1.0;&lt;br /&gt;
		}&lt;br /&gt;
        &lt;br /&gt;
        gl_Position.z = 2.0 * gl_Position.z -1.0; //Todo: optimieren&lt;br /&gt;
	pos=gl_Position.xyz;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
parabol.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 pos;&lt;br /&gt;
void main(void){&lt;br /&gt;
	if (length(pos.xy)&amp;gt;1.005)discard; //Diese Zeile kann durchaus entfallen. Kosten/Nutzen unbekannt.&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Uniformaviablen, die gesetzt werden müssen: Eine ist die Nummer der aktuellen Lichtquelle und die zweite der Renderpass, der angibt ob die Vorder- oder Rückseite der parabolischen Map gerendert werden soll. Eine automatische Berechnung der Texturkoordinaten wäre zwar möglich, jedoch ist die Änderung des Viewports deutlich weniger Rechenaufwendig.&lt;br /&gt;
&lt;br /&gt;
Statt einer Multiplikation des gl_Vertex mit der gl_ModelViewProjektionMatrix wird hier nur mit der gl_ModelViewMatrix multipliziert. Dadurch werden nur die Transformationen durchgeführt und die Projektion übersprungen.&lt;br /&gt;
Die Division durch -L entspricht weitgehend einer Normalsierung, spiegelt die Welt jedoch in die richtige Lage. L enthält jetzt die Tiefeninformation, gl_Position einen Vektor, der von der Kammera auf den Vertex zeigt. Mit den zwei folgenden Zeilen wird der Vektor parabolisch auf die Bildschirmkoordinaten projeziert (Intervall von -1.0 bis 1.0). Mit Hilfe der folgenden if-Abfrage werden alle Vertices hinter der Kammera geclipt. Nur sichtbare Vertices bekommen gültige z Werte für den Zbuffer im Intervall von -1.0 bis 1.0. &lt;br /&gt;
&lt;br /&gt;
Der Fragmentshader ist extrem einfach, da wir aufgrund des nicht vorhandem Colorbuffers keinen Farbwert benötigen lassen wir diesen wie bei den perspektivischen Maps einfach undefiniert.&lt;br /&gt;
Zudem verlassen wir den Shader mit discard, wenn der der Pixel außerhalb der aktuellen paraboliden Map liegt. Die Voteil ist, das nur der kreisförmige Bereich der Map verwendet wird, der Nachteil, das durchaus eine Early-Z optimierung nicht mehr möglich ist. Sehr Sinvoll sollte dies sein, wenn die Shadowmaps dynamisch nach benötigter Größe angeordnet werden. Da sich Kreise besser als Quadrate packen lassen.&lt;br /&gt;
&lt;br /&gt;
====Shader für den finalen Renderdurchgang====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
final.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	Normal = gl_NormalMatrix * gl_Normal;&lt;br /&gt;
 	ModelVertex  = vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
final.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
uniform int MaxLights;&lt;br /&gt;
&lt;br /&gt;
//Achtung folgende Zeile ist nicht GLSL konform. &lt;br /&gt;
//Workaround: Array als Uniform übergeben oder durch sehr aufwendige berechnung erstzten&lt;br /&gt;
//Sollte es auch auf ATI Karten funktinieren, frage ich mich warum es nicht erlaubt ist...&lt;br /&gt;
const vec2 texofset[8] = {vec2 (0.125,0.125), vec2 (0.125,0.375), vec2 (0.125,0.625), vec2 (0.125,0.875),&lt;br /&gt;
			  vec2 (0.625,0.125), vec2 (0.625,0.375), vec2 (0.625,0.625), vec2 (0.625,0.875)};&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
	vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
	for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
		vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
		vec3 lightdir = normalize( lightvec );&lt;br /&gt;
		vec2 parabol = texofset[LightNum];&lt;br /&gt;
		if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
			parabol.t += 0.25;&lt;br /&gt;
			}&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
		parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
		vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
		light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
		}&lt;br /&gt;
	vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));	//Textur auslesen; &lt;br /&gt;
	gl_FragColor = light * color ;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Möglicher weise für ATI taugliche Variante:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
 &lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
const int MaxLights=8;&lt;br /&gt;
 &lt;br /&gt;
vec2 texofset[8]; &lt;br /&gt;
void main(void){&lt;br /&gt;
	texofset[0] = vec2 (0.125,0.125);&lt;br /&gt;
	texofset[1] = vec2 (0.125,0.375);&lt;br /&gt;
	texofset[2] = vec2 (0.125,0.625);&lt;br /&gt;
	texofset[3] = vec2 (0.125,0.875);&lt;br /&gt;
	texofset[4] = vec2 (0.625,0.125);&lt;br /&gt;
	texofset[5] = vec2 (0.625,0.375);&lt;br /&gt;
	texofset[6] = vec2 (0.625,0.625);&lt;br /&gt;
	texofset[7] = vec2 (0.625,0.875);&lt;br /&gt;
&lt;br /&gt;
        vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
        vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
        for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
                vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
                vec3 lightdir = normalize( lightvec );&lt;br /&gt;
                vec2 parabol = texofset[LightNum];&lt;br /&gt;
                if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
                        parabol.t += 0.25;&lt;br /&gt;
                        }&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
                parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
                float shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
                light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
                }&lt;br /&gt;
        vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0])); //Textur auslesen; &lt;br /&gt;
        gl_FragColor = light * color ;&lt;br /&gt;
        }&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Shader besitzen 3 Uniformvariablen, die unbedingt mit den richtigen Werten gefüllt werden müssen. Zwei davon sind Texturen, die dritte die Anzahl der aktiven Lichtquellen. Es ist wichtig zu wissen, dass der Shader nicht den OpenGL-Status der Lichquellen berücksichtigt und nur die Daten der Ersten bis MaxLights holt.&lt;br /&gt;
Während bei den Schattenmaps die meiste Arbeit im Vertexshader erledigt werden könnte, ist dieser sehr Fragmentshader lastig. Die Texturkoordinatenberechnung ist sehr ähnlich zu der im shadow.vert. Die größte Änderung ist, dass hier abhängig von der Lichtquellennummer ein Offset aufaddiert wird um die Untertextur auszuwählen. Ein zusätzlicher Offset wird dazuaddiert, wenn auf die zweite parabolide Map einer Lichtquelle zugegriffen wird.&lt;br /&gt;
Um ein dynamisches Branching zu vermeiden, wird mit der Stepfunktion ermittelt ob sich das Fragment im Schatten befindet.&lt;br /&gt;
&lt;br /&gt;
==Optimierungen und Verbesserungen==&lt;br /&gt;
Hier sind noch einige Vorschläge, die helfen können um besser Qualität oder Leistungen im eigenem Programm zu bekommen. Eine uniververselle Lösung lässt sich nur auf kosten von Performance schreiben. Viel besser ist es, wenn man die Shader an die jeweilige Situation anpasst. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schatten durch Alphatest===&lt;br /&gt;
Der bisherige Schattenshader kann nur ganze Polygone einen Schatten werfen lassen. Wenn shadow.vert so ergänzt wird, das die Texturkoordinaten in den Fragmentshader  weitergereicht werden, dann ist es mit folgendem Fragmentshader möglich Shatten in Abhängikeit einer Alphatextur zu rendern:&lt;br /&gt;
&lt;br /&gt;
shadow.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
        if (texture2D(Texture0,vec2(gl_TexCoord[0])).a &amp;lt; 0.5) discard;&lt;br /&gt;
}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Shader wird verlassen wenn das Texel einen Alphawert von kleiner als 50% hat. Damit lassen sich Schatten von Pflanzen wesentlich realistischer darstellen. Dieser Shader sollte natürlich nur dann verwendet werden, wenn eine Alphakanal in der Textur vorhanden ist. Auch Shader mit Paralax- oder Displacementmapping arbeiten kann man so um einen Schatten ergänzen, wenn die Polygone transparente Teile enthalten.&lt;br /&gt;
Es ist auch möglich den shader zu verlassen, wenn eine bestimmte Farbe in der Textur gefunden wird, dann nimmt die Alphamaske keinen Speicherplatz mehr weg.&lt;br /&gt;
&lt;br /&gt;
===Farbiges Glas===&lt;br /&gt;
&lt;br /&gt;
Schatten hat jetzt ja sachon fast jeder. Aber wie wäre es mal mit einfärben von dynamischen Lichtquellen?&lt;br /&gt;
Der Algoritmus ist nicht schwer:&lt;br /&gt;
&lt;br /&gt;
* Alle Undurchichtigen Sceneteile in die Tiefenmaps gerendert. &lt;br /&gt;
* Zusätzlich wird eine Colormap gebunden und das Schreiben in den Zbuffer unterbunden.&lt;br /&gt;
* Die Colormap wird mit Weiß oder einer Helligkeitsmap initialisiert.&lt;br /&gt;
* Rendern aller transparenten Objekten&lt;br /&gt;
* Auf finales Rendern umschalten&lt;br /&gt;
* Alle undurchsichtigen Objekte mit hilfe der Schadowmap und der modifizierten Beleuchtungmap beleuchten.&lt;br /&gt;
* Alle Transparenten Objekte rendern, unter Berücksichtigung, dass die Lichtquelle bereits das gefilterte Licht aussendet. Dieses Blending sollte rückgängig gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Bei diesem Algoritmus bleibt noch das Alphablendingproblem mit der mehrfachen Überdeckung. Beim Modifizieren der Beleuchtungsmap gegebenfalls den Stencilbuffer zur Hilfe nehmen. Hier wäre ein denkbarer Algoritmus:&lt;br /&gt;
&lt;br /&gt;
* Alle transparenten Poligone in den Zbuffer rendern. Dabei für alle Poligone, deren  doppelte Filterung zu Fehlern führen kann mit verschiedenen Stencilwerte schreiben.&lt;br /&gt;
* Zbuffer und Colorbuffer Löschen. &lt;br /&gt;
* Helligkeitsmap in den Colorbuffer kopieren.&lt;br /&gt;
* Alle nicht transparanten Objekte in den Zbuffer Rendern. &lt;br /&gt;
* Alle transparenten Poligone mit den gleichen Stencilwerten wie im erstem Pass rendern. Die Bedingung ist, dass nur Polygone in den Zbuffer geschrieben werden, bei den Stencilwerte nicht mit den Stencilbuffer übereinstimmen. Die vordersten Polygone werden so aussortiert und nur die zweite Schicht landet im Zbuffer.&lt;br /&gt;
* Im letztem Rendervorgang müssen die gefilterten Lichtfarben der Transparenten Polygone in den Colorbuffer geschrieben werden. Die Bedingung ist das die Stencilwerte übereinstimmen müssen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn es wie ein großer Mehraufwand aussieht, ist der Anteil der transparenten Poligone doch eher gering. So das deren dreifacher Overdraw kaum eine Rolle spielt. Im Finalem Renderdurch gang gibt es bei den transparenten Polygonen noch eine Besonderheit: Stimmt die Entfernung aus der Shadowmap mit der Entfernung der Lichquellen (fast) überein, so wird das Poligon mit dem Licht aus der Colormap belauchtet. Ist die Entfernung aus der Shadowmap jedoch größer als die entfernung zu lichquellen, enthällt die Colormap die gefilterte Farbe des Lichtes hinter dem Poligon. Für die beleutung des Poligon muss also das Licht der Lichquelle benutzt werden. Sinvoll ist es die helligkeit für diesen Fall im Alphawert der Colormap zu Speichern.&lt;br /&gt;
&lt;br /&gt;
Ansonsten noch ein paar Vorschläge:&lt;br /&gt;
* Objekte die aus dem gleichem Glas sind und auch einfarbig. Sollten mit dem gleichem Stencilwert verarbeitet werden. So sieht z.B. das gefärbte Licht einer zweifach durchstrahlten leicht gefäbten Glasskuppel natürlicher aus als ein Vollschatten. Auch wenn das Licht korrekter weise zwei mal hätte gefiltert werden müssen. &lt;br /&gt;
* Eventuel macht es sind mehrfarbige Objekte in mehrfache einfarbige Objekte zu zerlegen.&lt;br /&gt;
* Komplexe Mehrfachfilterungen sollten vermieden werden oder so gewählt werden, das sie natürlich ausehen. Gute Filter wären komplementärfarben, da dort ein echter Schatten erzeugt wird. Schlechte Kombinationen wären unter anderem Rot+Gelb, Blau+Gelb, usw...&lt;br /&gt;
* Um von den Farbfehlern abzulenken, farbige Objekte in einer rotverschobenen Farbe flourezieren lassen. (Violet-&amp;gt; Blau -&amp;gt; Grün -&amp;gt; Gleb -&amp;gt; Organge -&amp;gt; Rot) Durch blau gefärbte Fenster, blau gefilterte Licht welches Dinge grün aufleuchten lässt nimmt einem jeder PC Modder ab...&lt;br /&gt;
&lt;br /&gt;
===Schattenmap durch eine Heightmap modifizieren===&lt;br /&gt;
Auch wennich hierzu noch kein Beispiel haben, ist es möglich gl_FragDepth mit hilfe einer Heightmap zu modifizieren. Prinzipiell entspricht dies einem einfachem Offsetmapping. Damit wäre durchaus eine Selbstschattierung von Bumpmaps möglich.&lt;br /&gt;
&lt;br /&gt;
===Zweite parabolische Map vermeiden===&lt;br /&gt;
Lichtquellen, die nur in eine Richtung Licht werfen können, wie z.B. Spotlichter oder Lichter, die in Bodenähe oder Wandnähe befestigt sind, benötigen keinen vollständig erfassten Tiefenraum. Die Parabolische Map kann problemlos herein oder herausskaliert werden, so das Öffnungswinkel von 0 bis ca 240 Grad möglich sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das verkleinern des Öffnungswinkels für zusätzliche Spotlichter ermöglicht auch kleinere Tiefenmaps, die in die 9 Zwischenräume der großen gepackt werden können. Die Zwischenräume können noch Maps mit einem Durchmesser von 40% der großen Maps aufnehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Texturelookups vermeiden===&lt;br /&gt;
Wenn das Skalarprodukt von normalvec und -lightdir negativ ist, dann ist die Oberfläche von der Lichtquelle abgewandt und Berechnungen für die Lichquelle können komplett übersprungen werden. Diverse Multiplikationen und vorallem Texturelookups können so übersprungen werden. Besondere aufwendige Algorithmen wie selbstschattierende Bumpmaps, können so deutlich Beschleunigt werden. &lt;br /&gt;
&lt;br /&gt;
Für die Beleuchtung sollte dann allerdings auch folgende Zeile verwendet werden. (Das Skalarprodukt von vor der if Abfrage aber umbedingt wiederverwerten!) &lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
  light += gl_LightSource[0].diffuse * max(dot(normalvec, -lightdir), 0.0);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reichweite der Lichtquellen=== &lt;br /&gt;
Leider bietet OpenGL nicht direkt die Möglichkeit die maximale Reichweite einer Lichquelle anzugeben. In den Shadern wird zur Zeit der Wert 15.0 als maximale Entfernung zur Lichtquelle verwendet. Für ein einfaches Programm ist es sicher ausreichend, ansonsten macht es Sinn diesen Wert durch eine Unformvariable zu ersetzten, oder um mehr Flexibiltät zu bekommen durch ein Array aus 8 Uniformfloats.&lt;br /&gt;
&lt;br /&gt;
===Oversampling der Schattenmap===&lt;br /&gt;
Die Qualität lässt sich dadurch mehrere Samples auf der Schattenmap verbessern. Das folgende Codefragment nimmt 3 statt des einem Samples und glättet die Ränder des Schattens. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;const float pof =1.0 /4096.0 *0.7;&lt;br /&gt;
vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol +vec2(pof,0)).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,-pof/1.2) ).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,pof/1.2)).r );&lt;br /&gt;
light += shadow * 0.33 * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Durch 9x Oversampling lässt sich schon eine sehr gute Qualität ereichen, sorgt aber bei 8 Lichtquellen durch die 72 Texturelookups für einen Zusammenbruch der Framerate.&lt;br /&gt;
Wichtig ist auch, dass man beachtet, dass die dualparaboliden Maps an Ihren Ränden undefiniert sind und so zu Artefakten kommen kann wenn man außerhalb des gültigem Bereichs sampled. Eine Möglichkeit wäre einen Bereich zu erfassen, der etwas größer als 180 Grad ist, um am Rand zusätzliche Texel zu schaffen.&lt;br /&gt;
&lt;br /&gt;
===Ein zusätzlicher Renderpass===&lt;br /&gt;
Nach dem die Tiefenmap gerendert würde, wäre es möglich in einem weiterem Framebufferobjekt eine zusätzliche Map zu rendern, in der mit Hilfe einer Kantenerkennung die Helligkeit der Softshadows vorberechnet wird. Auch hier muss berücksichtigt werden, dass die dualparaboliden Maps einen Übergang haben.&lt;br /&gt;
&lt;br /&gt;
===Dynamische Lichter in statische Lightmaps Rendern===&lt;br /&gt;
Wenn sich Lichtquellen nicht relativ zur Umgebung nicht bewegen, ist es möglich sie in eine Lightmap zu rendern. Unter der Annahme, dass Lightmapkoordinaten vorhanden sind (ohne geht es echt nicht gut), müssen diese nur per Vertexshader an den Pixelshader weitergegeben werden. Im Pixelshader kann dann wie im final.frag die Helligkeit berechnet werden und in der Lightmap abgespeichert werden.&lt;br /&gt;
Es ist immer noch möglich, das dynamische Objekte einen Schatten werfen: Es werden nur noch die beweglichen Objekte in die Tiefenmap gerendert. Im Schatten wird dann einfach das Licht der im Schatten liegenden Lichtquelle subtraiert.&lt;br /&gt;
&lt;br /&gt;
===Statische Anteile in den Schattenmaps===&lt;br /&gt;
Es ist möglich mit einer zusätzlichen Matrix die Tiefenmaps zu den Weltkoordinaten auszurichten. Statische Anteile können dann aus einer zweiten Tiefenmap kopiert werden. Ein wenig problematisch ist das Entfernen der Rotation aus der gl_ModelViewMatrix. Das größte Problem ist, das die Positionen der Lichquellen bereits mit der gl_ModelViewMatrix multipliziert sind. Die einfachste Lösung ist, aus den den Rotationswinkeln eine neue Matrix zu erechnen, mit dessen Hilfe die Schattenvektoren für die Texturkoordinatenberechnung zurückgedreht werden. Diese Matrix sollte dann als Uniformvariable übergeben werden.&lt;br /&gt;
Wenn die Schatten durch einen zusätzlichen Renderdurchgang gefiltert werden. Ist es sinvoll die Maps erst hier zu vereinen. Von beiden Tiefenmaps muss nur immer der kleinere Wert genommen werden.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19726</id>
		<title>GLSL Licht und Schatten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19726"/>
				<updated>2006-10-08T15:10:28Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Shader für den finalen Renderdurchgang */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Willkommen zu meinem erstem Tutorial. Schatten können sowohl Traum als auch Albtraum eines jeden OpenGL-Progrmamieres werden. Im Gegensatz zur einfachen Beleuchtung mit Lichtquellen, steigt der Rechenaufwand hier extrem an und ohne Optimierung zwingen die Schatten selbst die modernste Hardware in die Knie.&lt;br /&gt;
Für Schatten gibt es zwei praktikable Algoritmen: Den Stencilschatten und den projezierten Schatten. Hier möchte ich mich auf den projezierten Schatten beschränken, er bietet gegenüber dem Stencilschatten einige Vorteile:&lt;br /&gt;
&lt;br /&gt;
*Die komplette Berechnung kann von der Grakfikkarte übernommen werden&lt;br /&gt;
*Es ist möglich Softshadows zu realisieren&lt;br /&gt;
*Die Shadowmaps können unter Umständen für mehr als ein Frame verwendet werden&lt;br /&gt;
&lt;br /&gt;
Um den Rechenaufwand zu veringern werde ich hier zusätzliche Projektionstechniken zeigen, die über den Vertexshader realisiert werden: Die perspektivische Map und das parabolide Mapping. &lt;br /&gt;
&lt;br /&gt;
Für sehr weit entfernte Lichtquellen und offene Szenen ist der Einsatz von perspektisch angepassten Maps sinvoll. Da das Licht quasi parallel ausgestrahlt wird. Ist ein winkelabhängiger Cube oder dualparabolische Map kaum möglich. Auch eine einfache quadratische Shadowmap zeigt deutliche Schwächen bei der Auflösung im Nahbereich und dem zu hohem Oversampling in der Entfernung.&lt;br /&gt;
&lt;br /&gt;
Das parabolide Mapping ermöglicht nicht nur die Simulation eine Fischaugenoptik, sondern kann auch die Cubemap vollständig ersetzen. Durch einen geringfügig höheren Rechen- und Programieraufwand genügen zwei Renderpasses um eine vollständige Tiefen- oder Reflektionsmap zu erstellen. Was gegenüber der klassischen Cubemap den Prozessor und GPU um den Faktor 3 entlastet.&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Dieses Tutorial basiert auf den grundlegenden Techniken, die erst in den letzten Jahren entwickelt wurden. Jeder der hier mit anfängt, sollte die zwei anderenen GLSL Tutorials gelesen haben und einfache Fragmentshader schreiben können. Auch das Laden und Einbinden von Texturen in die Shader sollte kein Problem mehr darstellen.&lt;br /&gt;
&lt;br /&gt;
===Framebufferobjekte===&lt;br /&gt;
Für das Erstellen von dual paraboliden Tiefentexturen ist noch das Rendern in Framebufferobjekten Vorraussetzung (zu denen es leider noch kein Tutorial gibt). Damit der Einstieg nicht zu schwer wird sollte dieser Code helfen das FBO zu initialsisieren:&lt;br /&gt;
&lt;br /&gt;
Als Erstes müssen die nötigen Extensions initialisiert werden&lt;br /&gt;
Dann sollten die benötigten Modelle als VBO in die Grafikkarte hochgeladen werden.&lt;br /&gt;
Nun muss das Framebufferobjekt (FBO) für die Schattenmaps erzeugt werdern.&lt;br /&gt;
So könnte die Initialsierung des FBOs aussehen. C code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;GLuint shadow_map = 0; // &lt;br /&gt;
GLuint shadow_fbo = 0; // the shadow texture&lt;br /&gt;
GLuint shadow_size = 4096; //muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
glGenTextures (1, &amp;amp;shadow_map); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindTexture (GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
glTexImage2D (GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0,GL_DEPTH_COMPONENT , GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
glGenFramebuffersEXT (1, &amp;amp;shadow_fbo); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D,shadow_map, 0);&lt;br /&gt;
glDrawBuffer (GL_FALSE);&lt;br /&gt;
glReadBuffer (GL_FALSE);&lt;br /&gt;
GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/cpp&amp;gt;&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;var shadow_map,&lt;br /&gt;
    shadow_fbo,&lt;br /&gt;
    shadow_size : GLuint;&lt;br /&gt;
    status      : GLenum; &lt;br /&gt;
begin&lt;br /&gt;
  shadow_map  := 0;  &lt;br /&gt;
  shadow_fbo  := 0;     // the shadow texture&lt;br /&gt;
  shadow_size := 4096; // muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @shadow_map);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @shadow_fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadow_map, 0);&lt;br /&gt;
  glDrawBuffe (GL_FALSE);&lt;br /&gt;
  glReadBuffer(GL_FALSE);&lt;br /&gt;
  status := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt sollten die Shader und weiter Texturen geladen werden.&lt;br /&gt;
&lt;br /&gt;
===Beschleunigtes Rendern===&lt;br /&gt;
&lt;br /&gt;
Ich empfehle auch die zu rendernden Daten als Vertexbufferobjekte zu übergeben, da sonst die Mehrfachverwendung der Daten zu einer extremen Bremse wird. Da es hierzu bereits ein Tutorial gibt werde ich hier nichts mehr darüber schrieben.&lt;br /&gt;
Alternativ sollte alles was zwischen glBegin und glEnd in Displaylisten gespeichter werden. Das Speichern von Texturwechseln usw ist nicht sinvoll, da diese nicht zum Rendern der Shadowmaps benötig werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehrfachen Lichquellen kann es wiederum Sinn machen den ersten Rendervorgang inclusive Shaderwechsel in einer Displayliste zwischenzuspeichen und die zusätzlichen Schadowmaps mit dieser zu rendern.&lt;br /&gt;
&lt;br /&gt;
===Algemeines zu GLSL===&lt;br /&gt;
Ich möchte nocheinmal darauf hinweisen, das sich uniformvariablen nur setzten Lassen, wenn der entsprechnde shader gebunden ist. (Es funktionier nicht wenn der shader nicht gebunden ist. Warum man den shader dabei allerdings angeben muss ist mir nicht so ganz klar)&lt;br /&gt;
In den Beispielen werden nur die Uniformvariablen wärend des Rendervorgangs neu gesetzt die sich ändern.  Die zuweisung der TMU zu einem Sampler gehöhrt in der Regel nicht dazu. &lt;br /&gt;
&lt;br /&gt;
===Grundlegendes zu den Koordinatensystemen in den Shadern===&lt;br /&gt;
&lt;br /&gt;
Im Vertexshader müssen alle komponenten von gl_Position in einem Bereich von -1.0 bis 1.0 gebracht werden. Besonders beim Z-Wert könnte es verwirrend, dass der Bereich  von gl_FragDepth im Fragmentshader von 0.0 bis 1.0 geht. Auch muss beachtet werden, dass Texturkordinaten den bereich von 0.0 bis 1.0 nutzen, wärend die Rendertargets im Bereich on -1.0 bis 1.0 arbeiten.&lt;br /&gt;
In den Shadern werden daher öfters Multimplikationen mit 0.5 und einer anschließenden Addition von 0.5 auftreten.&lt;br /&gt;
&lt;br /&gt;
==Perspektivische Maps==&lt;br /&gt;
&lt;br /&gt;
In dem erstem Teil dieses Artikels geht es um perspektivisch angepasste Schattenmaps. Normale projezierte Schatten haben das Problem, das sie im Nahenbereich besonders stark verpixeln und in der Entfernung durch ein viel zu hohes Oversampling Bandbreite verschwenden.&lt;br /&gt;
&lt;br /&gt;
Für eine globale Lichquelle wird nur ein Vektor gegeben, der die Richtung des Lichtes beschreibt. Die gedachte Lichtquelle ist quasi unendlich weit weg. Da eine Entfernungsberechnung zur Lichquelle unmöglich ist, muss die Schattenberechnung relativ zu einer Referenzebene durchgeführt werden. Diese Ebene kann sowohl Senkrecht zum Lichvektor, als auch parallel zum gedachtem Boden ausgerichtet werden. Die Ausrichtung der Referenzebene beeinflusst die später sichtbare Auflösung der Schatten.&lt;br /&gt;
&lt;br /&gt;
Nach dem ein Vertex auf die Ebene projeziert wurde und der Abstand ein einen berech von 0.0...1.0 gebracht wurde, muss diese unendlich große Ebene noch auf eine endliche Größe projeziert werden, die auf eine Textur passt und die entfernungsabhängige Detailierung beachtet.&lt;br /&gt;
&lt;br /&gt;
Wenn wir unsere Referenzebene einfachhalber den Horizont schneidet (und auch den Bildschirm in obere und untere Hälfte teilt) Könnte ein Algorimus in etwa so aussehen (Dieser lässt sich später in ein Vertexshaderprogramm umsetzten):&lt;br /&gt;
&lt;br /&gt;
Projeziere den Vertex in die Modelview (Diese Schritt wurde auch bei den dualparaboliden Maps durchgeführt)&lt;br /&gt;
Ermittel den Schnittpunt des vom Vertex ausgehendem gedachtem Lichtstrahl und der Referenzebene.&lt;br /&gt;
Benutze den Abstand zwischen Schnittpunkt und Vertex um den Z-Wert zu ermitteln. (Es sind zwei zusätzlich referenzwerte nötig die die funktion Farclip und Nearclip übernehmen)&lt;br /&gt;
Projeziere die Ebene auf eine Ebene die in eine Textur passt pos/=abs(pos)+1.0 passt recht gut.&lt;br /&gt;
Anschließend wird noch die Schadowmap noch gestreckt und der Bereich hinter der Kammera entfernt.&lt;br /&gt;
&lt;br /&gt;
Das wichtigste ist, dass beim auswerten der shadowmaps der gleiche Projektionsalgoritmus verwendet wird wie beim generieren.&lt;br /&gt;
&lt;br /&gt;
Prinzipell sollte sich der Algoritmus schon auf einer Geforce 3 oder Radeon 8500 implementieren lassen. Da da der Code hier in GLSL geschrieben ist, sollte in etwa Shadermodel 2.0 unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeitsmäßig ist dieser Algoritmus den Stencilshadows deutlich überlegen. Auch bei Stencilshadows sind mehrere Renderpasses nötig. Vorallem das extruieren der Siluetten kostet einiges an Bandbreite. Der geschätzte Aufwand ist etwa 20 (Aufwendige Shader im Finalem Renderdurchgang)bis 80% (CPU limitiert Geometrieübergabe) Mehraufwand gegenüber einer Schattenlos gerenderten Scene.&lt;br /&gt;
Auch die Qualität ist nicht schlechter. Bei der Verwendung von weichen Schatten wirken Shadowmaps natürlicher als die extrem scharfen Stencilshadows. &lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
In der Hauptschleife könnte folgender Code verwendet werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, 0 ); //Entfernt alle Texturen aus der ersten TMU&lt;br /&gt;
	glUseProgramObjectARB(shadow); //lädt den Schattenshader&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb); //Bindet das Framebufferobjekt&lt;br /&gt;
	&lt;br /&gt;
	glViewport (0, 0,shadow_sz,shadow_sz); //Anpassen des Viewportes &lt;br /&gt;
	glClear(GL_DEPTH_BUFFER_BIT); //Z-Buffer löschen&lt;br /&gt;
	&lt;br /&gt;
	render(); //Erster Renderdurchgang&lt;br /&gt;
&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); //Normalen Framebuffer binden&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, shadow_tx ); //Tiefenmap an die erste TMU binden&lt;br /&gt;
	glUseProgramObjectARB(final); //finalen shader binden&lt;br /&gt;
	&lt;br /&gt;
	glViewport(0, 0, screen_size_x, screen_size_y);&lt;br /&gt;
	&lt;br /&gt;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Color und Z-Buffer löschen&lt;br /&gt;
	render(); //rendern&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Shader===&lt;br /&gt;
&lt;br /&gt;
Als erstes der Vertexshader zum generieren der Schadowmap. shadow.vert:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){&lt;br /&gt;
&lt;br /&gt;
	vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0)); //Lichtvektor in den Modelsprace rotieren&lt;br /&gt;
	vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex); //Vertex in den Modelspace projezieren&lt;br /&gt;
	vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y; //Schnittpunkt mit der XZ Referenzebene&lt;br /&gt;
	pos = pos / (abs(pos)+1.0); //Projektion der Ebene auf ein Quadrat&lt;br /&gt;
	pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
	gl_Position.xy = pos;&lt;br /&gt;
	gl_Position.z = -mvertex.y ; // Der Bereich von +-1 über der Referenzebene wird erfasst&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Lichtrichtung wird vorläufig noch fest übergeben. Eine Auswertung einer Opengl Lichtquelle oder einer Uniformvariable wäre ebenfalls möglich. Anschließend wird der Vertex in die Modelview projeziert und der Schnittpunkt des vom Vertexausgehendem Lichstrahls mit der Referenszebene berechnet. Als letztes wird noch der Abstand zur Referenzebenein einem Bereich 0..1  umgerechnet und die Texturkoordinaten für eventuelles Alphamasking oder Heightmapping durchgeschleift. Soll Alphamasking verwendet werden, muss ein entsprechender Shader geschrieben werden der bei den freizulassenden pixeln discard(); aufruft. Dies sollte jedoch nur für die betroffenen Poligone stat finden, da die Grafikkarte dann keine Early-Z Optimierungen verwenden kann. Ansonsten ist der Fragmentshader ist sehr einfach: shadow.frag:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die für die Auswertung müssen wir im finalem Renderdurchgang exakt die gleichen Texturkoordinaten für die Shadowmap generieren. Allerdings gibt es eine Besonderheit: Die koordinaten einer Textur reichen von 0;0 bis 1;1, Die Koordinaten eines Rendertargets reichen jedoch von -1;-1 bis 1;1, so das eine zusätzliche korrektor nötig ist.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
        vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0));&lt;br /&gt;
        vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
        vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y;&lt;br /&gt;
        pos = pos / (abs(pos)+1.0);&lt;br /&gt;
        pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
        pos = pos * 0.5 + 0.5; //auf Texturkoordinaten umrechnen&lt;br /&gt;
 &lt;br /&gt;
        spos.xy = pos; //Daten in einer Varying verpacken&lt;br /&gt;
        spos.z = -mvertex.y * 0.5 + 0.5 - 0.005; // far and near clamping and Anti-Z-fighting-offset &lt;br /&gt;
 	&lt;br /&gt;
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //Die echte Transformation&lt;br /&gt;
 &lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten 5 Zeilen der main() sollten exakt das gleiche tun wie der Vertexshader zum gnerieren dem Map.&lt;br /&gt;
&lt;br /&gt;
Nun fehlt noch ein Fragmentshader für den letzten Durchgang:&lt;br /&gt;
&lt;br /&gt;
Es muss noch der Noralvektor berücksichtigt werden!!!&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Shadowmap;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
 &lt;br /&gt;
void main(void){&lt;br /&gt;
        if (texture2D(Shadowmap, spos.xy).r &amp;gt; spos.z ){&lt;br /&gt;
              //Licht&lt;br /&gt;
              gl_FragColor = vec4(1.0,1.0,1.0,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        else{&lt;br /&gt;
              //Schatten&lt;br /&gt;
              gl_FragColor = vec4(0.5,0.5,0.5,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Parabolide Maps==&lt;br /&gt;
&lt;br /&gt;
Einfache parabolide Maps können für alle Punktlichquellen verwendet werden, deren Licht nicht in alle Richtungen abgestrahlt wird. Darunter fallen vorallem Spots und an Wänden oder Decken befestigte Lampen. Im gegensatz zur Paralelem Licht oder einer Punktlichquelle bringt eine solche Lichtquelle häufig eine Helligkeitsmap mit. Für die Helligkeitsmap und die Schattenmap können die gleichen Texturkoordinaten verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Bei kleinen Öffnungswinkeln hat die parabolide Map keinen Vorteil gegenüber einer normalen Projektion. Der Vortiel ist jedoch das der Code sich für Öffnungswinkel von bis zu ~240 Grad eignet. &lt;br /&gt;
&lt;br /&gt;
Um eine solche Lichquelle zu beschreiben weden nicht weniger als drei Vektoren benötigt:&lt;br /&gt;
&lt;br /&gt;
* Position&lt;br /&gt;
* Richtung &lt;br /&gt;
* Tangent&lt;br /&gt;
&lt;br /&gt;
Wärend die Funktion der ersten beiden Vektoren klar ist, wird der Tangent wird dazu benötigt die Schattenmap und Helligkeitsmap auszurichten. Er ist Senkrecht zur Richtung tangential zur Textur ausgerichtet &lt;br /&gt;
Beschreiben lässt sich diese Funktion lässte sich am ehesten durch das Verdrehen einer Taschenlampe. Wenn die Schattenmap gegenüber den schattenwerfenden Objekten verdreht wird, sieht das Bild auf keinen Fall mehr natürlich aus.&lt;br /&gt;
 &lt;br /&gt;
Es ist sowohl möglich die Berechnungen im Vertexshader durchzuführen, als auch eine entsprechnede Matrix in den Uniformvariablen abzulegen. Wenn die Berechnungen per Matrix durchgefühert werden lässt sich das Prinzip der paraboliden Maps zuindest als Reflektionsmap nutzen. Ein weiterer Vorteil an einer vorberechneten Matrix ist, dass diese auch für shadowmap verwendet werdne kann die nicht jedes Frame neu berechnet werden.&lt;br /&gt;
&lt;br /&gt;
==Dual Parabolide Maps==&lt;br /&gt;
Von OpenGL kennen wir zwei Projektionsmöglichkeiten: Orthografische und perspektivische Projektion. Beide Projektionen arbeiten ohne Verzerrung. Jede Gerade bleibt beim Transformieren eine Gerade. Wenn man dagegen das Bild eines Fischeyeobjektives betrachtet, allen einem sofort die zu Kurven verzerrten Geraden auf. Der entscheidene Vorteil an einer Fisheyeaufnahme ist, dass ein Öffnungswinkel von 180 Grad erfasst werden kann. Zwei entgegensetzte Aufnahmen können so problemlos den kompletten Raum um die Kamera erfassen.&lt;br /&gt;
&lt;br /&gt;
Für das Erstellen der Tiefenmap ist es notwendig den Raum um das reflektierende Objekt in eine Textur zu rendern. Meistens wird hier eine Cubemap verwendet. Soll diese dynamisch generiert werden, ist es auffällig, dass die Scene ganze 6 mal gerendert werden muss. Mit der dual paraboliden Map sind nur noch zwei Rendervorgänge nötig, es wird zwar keine Füllrate eingespart, dafür müssen nun nur noch 1/3 der Daten transformiert werden, so das die Vertexshader und die CPU entlastet werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitere Optimierung ist unter Umständen möglich: Wenn bei einer Cubemap auf eine der Flächen verzichte werden kann. Z.B. wird die Reflektion im Lack eines Autos so gut wie nie verdeckte Straße zeigen. Auch ist für eine an einer  Wand befestigten Lampe nur eine halbkugelförmige Shadowmap nötig. Wenn sie einen Abstand zur Wand hat, genügt es auch hier den Blickwinkel von 180 Grad etwas zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Die Projektion der dualparaboliden Map kann man sich am besten Bild eines Fisheyobjektives vorstellen. Mathematisch etwas genauer ist das Reflektionsbild der umgebenden Welt in einem Rotationsparaboliden.&lt;br /&gt;
&lt;br /&gt;
Die Hardwareanforderungen an den Pixelshader sind nicht gerade gering. Der Pixelshader für die 8fachen Lichquellen kommt nach dem Compelieren auf über 170 Instruktions. Eine Shader 2.0 Karte wie z.B. die Radeon 9x00 sind hier hoffnungslos überfordert da sie nur an 3 Stellen im Programm auf die Textureinheiten zugreifen können und der Assembler nicht mehr in der Lage ist die Instruktions passend umzusortieren. Noch fataler wird es  wenn die Texturelookups durch dynamisches Branching übersprungen weder sollen: Die Karte hat keine Chance mehr diese umzusortieren.&lt;br /&gt;
&lt;br /&gt;
Wer dualparbolide Maps auf SM2.0 Karten einsetzten will sollte damit rechnen, dass das Limit bei 2 bis 4 Maps liegen sollte.&lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
So kann in der Hauptschleife das rendern der 16 paraboliden Maps und der anschließende Finale Renderdurchgang durchgeführt werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for (int light;light&amp;lt;8;light++){&lt;br /&gt;
        glViewport (shadow_size/2*(lights/4),shadow_size/4 *(light%4),shadow_size/4,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;light&amp;quot;),light);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),0);&lt;br /&gt;
        render();&lt;br /&gt;
        glViewport (shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light%4),shadow_size/4 ,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),1);&lt;br /&gt;
        render();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Vieport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0,Windowsize_X,Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for light := 0 to 7 do&lt;br /&gt;
begin&lt;br /&gt;
  glViewport(shadow_size/2*(lights/4), shadow_size/4 *(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'light'), light);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'), 0);&lt;br /&gt;
  render();&lt;br /&gt;
  glViewport(shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'),1);&lt;br /&gt;
  render();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Viewport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0, Windowsize_X, Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Die Shader===&lt;br /&gt;
&lt;br /&gt;
====Shader zum Rendern der Schattenmaps====&lt;br /&gt;
parabol.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;  uniform int renderpass;&lt;br /&gt;
  uniform int light;&lt;br /&gt;
  varying vec3 normal;&lt;br /&gt;
  varying vec3 pos;&lt;br /&gt;
&lt;br /&gt;
  void main(void){&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewMatrix * gl_Vertex - gl_LightSource[light].position ;&lt;br /&gt;
&lt;br /&gt;
	float L= length (gl_Position.xyz);&lt;br /&gt;
	gl_Position /= -L;&lt;br /&gt;
	if (renderpass == 1) gl_Position.z *=-1.0;&lt;br /&gt;
	gl_Position.z += 1.0;&lt;br /&gt;
	gl_Position.xy /= gl_Position.z;&lt;br /&gt;
	if (gl_Position.z &amp;gt;= 0.01){&lt;br /&gt;
		gl_Position.z = L / 15.0;//Todo: optimieren&lt;br /&gt;
		gl_Position.w = 1.0;&lt;br /&gt;
		}&lt;br /&gt;
	else{&lt;br /&gt;
		gl_Position.z = -1.0;&lt;br /&gt;
		gl_Position.w = -1.0;&lt;br /&gt;
		}&lt;br /&gt;
        &lt;br /&gt;
        gl_Position.z = 2.0 * gl_Position.z -1.0; //Todo: optimieren&lt;br /&gt;
	pos=gl_Position.xyz;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
parabol.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 pos;&lt;br /&gt;
void main(void){&lt;br /&gt;
	if (length(pos.xy)&amp;gt;1.005)discard; //Diese Zeile kann durchaus entfallen. Kosten/Nutzen unbekannt.&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Uniformaviablen, die gesetzt werden müssen: Eine ist die Nummer der aktuellen Lichtquelle und die zweite der Renderpass, der angibt ob die Vorder- oder Rückseite der parabolischen Map gerendert werden soll. Eine automatische Berechnung der Texturkoordinaten wäre zwar möglich, jedoch ist die Änderung des Viewports deutlich weniger Rechenaufwendig.&lt;br /&gt;
&lt;br /&gt;
Statt einer Multiplikation des gl_Vertex mit der gl_ModelViewProjektionMatrix wird hier nur mit der gl_ModelViewMatrix multipliziert. Dadurch werden nur die Transformationen durchgeführt und die Projektion übersprungen.&lt;br /&gt;
Die Division durch -L entspricht weitgehend einer Normalsierung, spiegelt die Welt jedoch in die richtige Lage. L enthält jetzt die Tiefeninformation, gl_Position einen Vektor, der von der Kammera auf den Vertex zeigt. Mit den zwei folgenden Zeilen wird der Vektor parabolisch auf die Bildschirmkoordinaten projeziert (Intervall von -1.0 bis 1.0). Mit Hilfe der folgenden if-Abfrage werden alle Vertices hinter der Kammera geclipt. Nur sichtbare Vertices bekommen gültige z Werte für den Zbuffer im Intervall von -1.0 bis 1.0. &lt;br /&gt;
&lt;br /&gt;
Der Fragmentshader ist extrem einfach, da wir aufgrund des nicht vorhandem Colorbuffers keinen Farbwert benötigen lassen wir diesen wie bei den perspektivischen Maps einfach undefiniert.&lt;br /&gt;
Zudem verlassen wir den Shader mit discard, wenn der der Pixel außerhalb der aktuellen paraboliden Map liegt. Die Voteil ist, das nur der kreisförmige Bereich der Map verwendet wird, der Nachteil, das durchaus eine Early-Z optimierung nicht mehr möglich ist. Sehr Sinvoll sollte dies sein, wenn die Shadowmaps dynamisch nach benötigter Größe angeordnet werden. Da sich Kreise besser als Quadrate packen lassen.&lt;br /&gt;
&lt;br /&gt;
====Shader für den finalen Renderdurchgang====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
final.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	Normal = gl_NormalMatrix * gl_Normal;&lt;br /&gt;
 	ModelVertex  = vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
final.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
uniform int MaxLights;&lt;br /&gt;
&lt;br /&gt;
//Achtung folgende Zeile ist nicht GLSL konform. &lt;br /&gt;
//Workaround: Array als Uniform übergeben oder durch sehr aufwendige berechnung erstzten&lt;br /&gt;
//Sollte es auch auf ATI Karten funktinieren, frage ich mich warum es nicht erlaubt ist...&lt;br /&gt;
const vec2 texofset[8] = {vec2 (0.125,0.125), vec2 (0.125,0.375), vec2 (0.125,0.625), vec2 (0.125,0.875),&lt;br /&gt;
			  vec2 (0.625,0.125), vec2 (0.625,0.375), vec2 (0.625,0.625), vec2 (0.625,0.875)};&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
	vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
	for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
		vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
		vec3 lightdir = normalize( lightvec );&lt;br /&gt;
		vec2 parabol = texofset[LightNum];&lt;br /&gt;
		if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
			parabol.t += 0.25;&lt;br /&gt;
			}&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
		parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
		vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
		light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
		}&lt;br /&gt;
	vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));	//Textur auslesen; &lt;br /&gt;
	gl_FragColor = light * color ;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Möglicher weise für ATI taugliche Variante:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
 &lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
const int MaxLights=8;&lt;br /&gt;
 &lt;br /&gt;
vec2 texofset[8]; &lt;br /&gt;
void main(void){&lt;br /&gt;
	texofset[0] = vec2 (0.125,0.125);&lt;br /&gt;
	texofset[1] = vec2 (0.125,0.375);&lt;br /&gt;
	texofset[2] = vec2 (0.125,0.625);&lt;br /&gt;
	texofset[3] = vec2 (0.125,0.875);&lt;br /&gt;
	texofset[4] = vec2 (0.625,0.125);&lt;br /&gt;
	texofset[5] = vec2 (0.625,0.375);&lt;br /&gt;
	texofset[6] = vec2 (0.625,0.625);&lt;br /&gt;
	texofset[7] = vec2 (0.625,0.875);&lt;br /&gt;
&lt;br /&gt;
        vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
        vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
        for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
                vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
                vec3 lightdir = normalize( lightvec );&lt;br /&gt;
                vec2 parabol = texofset[LightNum];&lt;br /&gt;
                if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
                        parabol.t += 0.25;&lt;br /&gt;
                        }&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
                parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
                float shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
                light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
                }&lt;br /&gt;
        vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0])); //Textur auslesen; &lt;br /&gt;
        gl_FragColor = light * color ;&lt;br /&gt;
        }&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Shader besitzen 3 Uniformvariablen, die unbedingt mit den richtigen Werten gefüllt werden müssen. Zwei davon sind Texturen, die dritte die Anzahl der aktiven Lichtquellen. Es ist wichtig zu wissen, dass der Shader nicht den OpenGL-Status der Lichquellen berücksichtigt und nur die Daten der Ersten bis MaxLights holt.&lt;br /&gt;
Während bei den Schattenmaps die meiste Arbeit im Vertexshader erledigt werden könnte, ist dieser sehr Fragmentshader lastig. Die Texturkoordinatenberechnung ist sehr ähnlich zu der im shadow.vert. Die größte Änderung ist, dass hier abhängig von der Lichtquellennummer ein Offset aufaddiert wird um die Untertextur auszuwählen. Ein zusätzlicher Offset wird dazuaddiert, wenn auf die zweite parabolide Map einer Lichtquelle zugegriffen wird.&lt;br /&gt;
Um ein dynamisches Branching zu vermeiden, wird mit der Stepfunktion ermittelt ob sich das Fragment im Schatten befindet.&lt;br /&gt;
&lt;br /&gt;
==Optimierungen und Verbesserungen==&lt;br /&gt;
Hier sind noch einige Vorschläge, die helfen können um besser Qualität oder Leistungen im eigenem Programm zu bekommen. Eine uniververselle Lösung lässt sich nur auf kosten von Performance schreiben. Viel besser ist es, wenn man die Shader an die jeweilige Situation anpasst. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schatten durch Alphatest===&lt;br /&gt;
Der bisherige Schattenshader kann nur ganze Polygone einen Schatten werfen lassen. Wenn shadow.vert so ergänzt wird, das die Texturkoordinaten in den Fragmentshader  weitergereicht werden, dann ist es mit folgendem Fragmentshader möglich Shatten in Abhängikeit einer Alphatextur zu rendern:&lt;br /&gt;
&lt;br /&gt;
shadow.frag&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
        if (texture2D(Texture0,vec2(gl_TexCoord[0])).a &amp;lt; 0.5) discard;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Der Shader wird verlassen wenn das Texel einen Alphawert von kleiner als 50% hat. Damit lassen sich Schatten von Pflanzen wesentlich realistischer darstellen. Dieser Shader sollte natürlich nur dann verwendet werden, wenn eine Alphakanal in der Textur vorhanden ist. Auch Shader mit Paralax- oder Displacementmapping arbeiten kann man so um einen Schatten ergänzen, wenn die Polygone transparente Teile enthalten.&lt;br /&gt;
Es ist auch möglich den shader zu verlassen, wenn eine bestimmte Farbe in der Textur gefunden wird, dann nimmt die Alphamaske keinen Speicherplatz mehr weg.&lt;br /&gt;
&lt;br /&gt;
===Farbiges Glas===&lt;br /&gt;
&lt;br /&gt;
Schatten hat jetzt ja sachon fast jeder. Aber wie wäre es mal mit einfärben von dynamischen Lichtquellen?&lt;br /&gt;
Der Algoritmus ist nicht schwer:&lt;br /&gt;
&lt;br /&gt;
* Alle Undurchichtigen Sceneteile in die Tiefenmaps gerendert. &lt;br /&gt;
* Zusätzlich wird eine Colormap gebunden und das Schreiben in den Zbuffer unterbunden.&lt;br /&gt;
* Die Colormap wird mit Weiß oder einer Helligkeitsmap initialisiert.&lt;br /&gt;
* Rendern aller transparenten Objekten&lt;br /&gt;
* Auf finales Rendern umschalten&lt;br /&gt;
* Alle undurchsichtigen Objekte mit hilfe der Schadowmap und der modifizierten Beleuchtungmap beleuchten.&lt;br /&gt;
* Alle Transparenten Objekte rendern, unter Berücksichtigung, dass die Lichtquelle bereits das gefilterte Licht aussendet. Dieses Blending sollte rückgängig gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Bei diesem Algoritmus bleibt noch das Alphablendingproblem mit der mehrfachen Überdeckung. Beim Modifizieren der Beleuchtungsmap gegebenfalls den Stencilbuffer zur Hilfe nehmen. Hier wäre ein denkbarer Algoritmus:&lt;br /&gt;
&lt;br /&gt;
* Alle transparenten Poligone in den Zbuffer rendern. Dabei für alle Poligone, deren  doppelte Filterung zu Fehlern führen kann mit verschiedenen Stencilwerte schreiben.&lt;br /&gt;
* Zbuffer und Colorbuffer Löschen. &lt;br /&gt;
* Helligkeitsmap in den Colorbuffer kopieren.&lt;br /&gt;
* Alle nicht transparanten Objekte in den Zbuffer Rendern. &lt;br /&gt;
* Alle transparenten Poligone mit den gleichen Stencilwerten wie im erstem Pass rendern. Die Bedingung ist, dass nur Polygone in den Zbuffer geschrieben werden, bei den Stencilwerte nicht mit den Stencilbuffer übereinstimmen. Die vordersten Polygone werden so aussortiert und nur die zweite Schicht landet im Zbuffer.&lt;br /&gt;
* Im letztem Rendervorgang müssen die gefilterten Lichtfarben der Transparenten Polygone in den Colorbuffer geschrieben werden. Die Bedingung ist das die Stencilwerte übereinstimmen müssen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn es wie ein großer Mehraufwand aussieht, ist der Anteil der transparenten Poligone doch eher gering. So das deren dreifacher Overdraw kaum eine Rolle spielt. Im Finalem Renderdurch gang gibt es bei den transparenten Polygonen noch eine Besonderheit: Stimmt die Entfernung aus der Shadowmap mit der Entfernung der Lichquellen (fast) überein, so wird das Poligon mit dem Licht aus der Colormap belauchtet. Ist die Entfernung aus der Shadowmap jedoch größer als die entfernung zu lichquellen, enthällt die Colormap die gefilterte Farbe des Lichtes hinter dem Poligon. Für die beleutung des Poligon muss also das Licht der Lichquelle benutzt werden. Sinvoll ist es die helligkeit für diesen Fall im Alphawert der Colormap zu Speichern.&lt;br /&gt;
&lt;br /&gt;
Ansonsten noch ein paar Vorschläge:&lt;br /&gt;
* Objekte die aus dem gleichem Glas sind und auch einfarbig. Sollten mit dem gleichem Stencilwert verarbeitet werden. So sieht z.B. das gefärbte Licht einer zweifach durchstrahlten leicht gefäbten Glasskuppel natürlicher aus als ein Vollschatten. Auch wenn das Licht korrekter weise zwei mal hätte gefiltert werden müssen. &lt;br /&gt;
* Eventuel macht es sind mehrfarbige Objekte in mehrfache einfarbige Objekte zu zerlegen.&lt;br /&gt;
* Komplexe Mehrfachfilterungen sollten vermieden werden oder so gewählt werden, das sie natürlich ausehen. Gute Filter wären komplementärfarben, da dort ein echter Schatten erzeugt wird. Schlechte Kombinationen wären unter anderem Rot+Gelb, Blau+Gelb, usw...&lt;br /&gt;
* Um von den Farbfehlern abzulenken, farbige Objekte in einer rotverschobenen Farbe flourezieren lassen. (Violet-&amp;gt; Blau -&amp;gt; Grün -&amp;gt; Gleb -&amp;gt; Organge -&amp;gt; Rot) Durch blau gefärbte Fenster, blau gefilterte Licht welches Dinge grün aufleuchten lässt nimmt einem jeder PC Modder ab...&lt;br /&gt;
&lt;br /&gt;
===Schattenmap durch eine Heightmap modifizieren===&lt;br /&gt;
Auch wennich hierzu noch kein Beispiel haben, ist es möglich gl_FragDepth mit hilfe einer Heightmap zu modifizieren. Prinzipiell entspricht dies einem einfachem Offsetmapping. Damit wäre durchaus eine Selbstschattierung von Bumpmaps möglich.&lt;br /&gt;
&lt;br /&gt;
===Zweite parabolische Map vermeiden===&lt;br /&gt;
Lichtquellen, die nur in eine Richtung Licht werfen können, wie z.B. Spotlichter oder Lichter, die in Bodenähe oder Wandnähe befestigt sind, benötigen keinen vollständig erfassten Tiefenraum. Die Parabolische Map kann problemlos herein oder herausskaliert werden, so das Öffnungswinkel von 0 bis ca 240 Grad möglich sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das verkleinern des Öffnungswinkels für zusätzliche Spotlichter ermöglicht auch kleinere Tiefenmaps, die in die 9 Zwischenräume der großen gepackt werden können. Die Zwischenräume können noch Maps mit einem Durchmesser von 40% der großen Maps aufnehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Texturelookups vermeiden===&lt;br /&gt;
Wenn das Skalarprodukt von normalvec und -lightdir negativ ist, dann ist die Oberfläche von der Lichtquelle abgewandt und Berechnungen für die Lichquelle können komplett übersprungen werden. Diverse Multiplikationen und vorallem Texturelookups können so übersprungen werden. Besondere aufwendige Algorithmen wie selbstschattierende Bumpmaps, können so deutlich Beschleunigt werden. &lt;br /&gt;
&lt;br /&gt;
Für die Beleuchtung sollte dann allerdings auch folgende Zeile verwendet werden. (Das Skalarprodukt von vor der if Abfrage aber umbedingt wiederverwerten!) &lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
  light += gl_LightSource[0].diffuse * max(dot(normalvec, -lightdir), 0.0);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reichweite der Lichtquellen=== &lt;br /&gt;
Leider bietet OpenGL nicht direkt die Möglichkeit die maximale Reichweite einer Lichquelle anzugeben. In den Shadern wird zur Zeit der Wert 15.0 als maximale Entfernung zur Lichtquelle verwendet. Für ein einfaches Programm ist es sicher ausreichend, ansonsten macht es Sinn diesen Wert durch eine Unformvariable zu ersetzten, oder um mehr Flexibiltät zu bekommen durch ein Array aus 8 Uniformfloats.&lt;br /&gt;
&lt;br /&gt;
===Oversampling der Schattenmap===&lt;br /&gt;
Die Qualität lässt sich dadurch mehrere Samples auf der Schattenmap verbessern. Das folgende Codefragment nimmt 3 statt des einem Samples und glättet die Ränder des Schattens. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;const float pof =1.0 /4096.0 *0.7;&lt;br /&gt;
vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol +vec2(pof,0)).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,-pof/1.2) ).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,pof/1.2)).r );&lt;br /&gt;
light += shadow * 0.33 * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Durch 9x Oversampling lässt sich schon eine sehr gute Qualität ereichen, sorgt aber bei 8 Lichtquellen durch die 72 Texturelookups für einen Zusammenbruch der Framerate.&lt;br /&gt;
Wichtig ist auch, dass man beachtet, dass die dualparaboliden Maps an Ihren Ränden undefiniert sind und so zu Artefakten kommen kann wenn man außerhalb des gültigem Bereichs sampled. Eine Möglichkeit wäre einen Bereich zu erfassen, der etwas größer als 180 Grad ist, um am Rand zusätzliche Texel zu schaffen.&lt;br /&gt;
&lt;br /&gt;
===Ein zusätzlicher Renderpass===&lt;br /&gt;
Nach dem die Tiefenmap gerendert würde, wäre es möglich in einem weiterem Framebufferobjekt eine zusätzliche Map zu rendern, in der mit Hilfe einer Kantenerkennung die Helligkeit der Softshadows vorberechnet wird. Auch hier muss berücksichtigt werden, dass die dualparaboliden Maps einen Übergang haben.&lt;br /&gt;
&lt;br /&gt;
===Dynamische Lichter in statische Lightmaps Rendern===&lt;br /&gt;
Wenn sich Lichtquellen nicht relativ zur Umgebung nicht bewegen, ist es möglich sie in eine Lightmap zu rendern. Unter der Annahme, dass Lightmapkoordinaten vorhanden sind (ohne geht es echt nicht gut), müssen diese nur per Vertexshader an den Pixelshader weitergegeben werden. Im Pixelshader kann dann wie im final.frag die Helligkeit berechnet werden und in der Lightmap abgespeichert werden.&lt;br /&gt;
Es ist immer noch möglich, das dynamische Objekte einen Schatten werfen: Es werden nur noch die beweglichen Objekte in die Tiefenmap gerendert. Im Schatten wird dann einfach das Licht der im Schatten liegenden Lichtquelle subtraiert.&lt;br /&gt;
&lt;br /&gt;
===Statische Anteile in den Schattenmaps===&lt;br /&gt;
Es ist möglich mit einer zusätzlichen Matrix die Tiefenmaps zu den Weltkoordinaten auszurichten. Statische Anteile können dann aus einer zweiten Tiefenmap kopiert werden. Ein wenig problematisch ist das Entfernen der Rotation aus der gl_ModelViewMatrix. Das größte Problem ist, das die Positionen der Lichquellen bereits mit der gl_ModelViewMatrix multipliziert sind. Die einfachste Lösung ist, aus den den Rotationswinkeln eine neue Matrix zu erechnen, mit dessen Hilfe die Schattenvektoren für die Texturkoordinatenberechnung zurückgedreht werden. Diese Matrix sollte dann als Uniformvariable übergeben werden.&lt;br /&gt;
Wenn die Schatten durch einen zusätzlichen Renderdurchgang gefiltert werden. Ist es sinvoll die Maps erst hier zu vereinen. Von beiden Tiefenmaps muss nur immer der kleinere Wert genommen werden.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19725</id>
		<title>GLSL Licht und Schatten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19725"/>
				<updated>2006-10-08T15:09:35Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Shader zum Rendern der Schattenmaps */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Willkommen zu meinem erstem Tutorial. Schatten können sowohl Traum als auch Albtraum eines jeden OpenGL-Progrmamieres werden. Im Gegensatz zur einfachen Beleuchtung mit Lichtquellen, steigt der Rechenaufwand hier extrem an und ohne Optimierung zwingen die Schatten selbst die modernste Hardware in die Knie.&lt;br /&gt;
Für Schatten gibt es zwei praktikable Algoritmen: Den Stencilschatten und den projezierten Schatten. Hier möchte ich mich auf den projezierten Schatten beschränken, er bietet gegenüber dem Stencilschatten einige Vorteile:&lt;br /&gt;
&lt;br /&gt;
*Die komplette Berechnung kann von der Grakfikkarte übernommen werden&lt;br /&gt;
*Es ist möglich Softshadows zu realisieren&lt;br /&gt;
*Die Shadowmaps können unter Umständen für mehr als ein Frame verwendet werden&lt;br /&gt;
&lt;br /&gt;
Um den Rechenaufwand zu veringern werde ich hier zusätzliche Projektionstechniken zeigen, die über den Vertexshader realisiert werden: Die perspektivische Map und das parabolide Mapping. &lt;br /&gt;
&lt;br /&gt;
Für sehr weit entfernte Lichtquellen und offene Szenen ist der Einsatz von perspektisch angepassten Maps sinvoll. Da das Licht quasi parallel ausgestrahlt wird. Ist ein winkelabhängiger Cube oder dualparabolische Map kaum möglich. Auch eine einfache quadratische Shadowmap zeigt deutliche Schwächen bei der Auflösung im Nahbereich und dem zu hohem Oversampling in der Entfernung.&lt;br /&gt;
&lt;br /&gt;
Das parabolide Mapping ermöglicht nicht nur die Simulation eine Fischaugenoptik, sondern kann auch die Cubemap vollständig ersetzen. Durch einen geringfügig höheren Rechen- und Programieraufwand genügen zwei Renderpasses um eine vollständige Tiefen- oder Reflektionsmap zu erstellen. Was gegenüber der klassischen Cubemap den Prozessor und GPU um den Faktor 3 entlastet.&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Dieses Tutorial basiert auf den grundlegenden Techniken, die erst in den letzten Jahren entwickelt wurden. Jeder der hier mit anfängt, sollte die zwei anderenen GLSL Tutorials gelesen haben und einfache Fragmentshader schreiben können. Auch das Laden und Einbinden von Texturen in die Shader sollte kein Problem mehr darstellen.&lt;br /&gt;
&lt;br /&gt;
===Framebufferobjekte===&lt;br /&gt;
Für das Erstellen von dual paraboliden Tiefentexturen ist noch das Rendern in Framebufferobjekten Vorraussetzung (zu denen es leider noch kein Tutorial gibt). Damit der Einstieg nicht zu schwer wird sollte dieser Code helfen das FBO zu initialsisieren:&lt;br /&gt;
&lt;br /&gt;
Als Erstes müssen die nötigen Extensions initialisiert werden&lt;br /&gt;
Dann sollten die benötigten Modelle als VBO in die Grafikkarte hochgeladen werden.&lt;br /&gt;
Nun muss das Framebufferobjekt (FBO) für die Schattenmaps erzeugt werdern.&lt;br /&gt;
So könnte die Initialsierung des FBOs aussehen. C code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;GLuint shadow_map = 0; // &lt;br /&gt;
GLuint shadow_fbo = 0; // the shadow texture&lt;br /&gt;
GLuint shadow_size = 4096; //muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
glGenTextures (1, &amp;amp;shadow_map); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindTexture (GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
glTexImage2D (GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0,GL_DEPTH_COMPONENT , GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
glGenFramebuffersEXT (1, &amp;amp;shadow_fbo); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D,shadow_map, 0);&lt;br /&gt;
glDrawBuffer (GL_FALSE);&lt;br /&gt;
glReadBuffer (GL_FALSE);&lt;br /&gt;
GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/cpp&amp;gt;&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;var shadow_map,&lt;br /&gt;
    shadow_fbo,&lt;br /&gt;
    shadow_size : GLuint;&lt;br /&gt;
    status      : GLenum; &lt;br /&gt;
begin&lt;br /&gt;
  shadow_map  := 0;  &lt;br /&gt;
  shadow_fbo  := 0;     // the shadow texture&lt;br /&gt;
  shadow_size := 4096; // muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @shadow_map);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @shadow_fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadow_map, 0);&lt;br /&gt;
  glDrawBuffe (GL_FALSE);&lt;br /&gt;
  glReadBuffer(GL_FALSE);&lt;br /&gt;
  status := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt sollten die Shader und weiter Texturen geladen werden.&lt;br /&gt;
&lt;br /&gt;
===Beschleunigtes Rendern===&lt;br /&gt;
&lt;br /&gt;
Ich empfehle auch die zu rendernden Daten als Vertexbufferobjekte zu übergeben, da sonst die Mehrfachverwendung der Daten zu einer extremen Bremse wird. Da es hierzu bereits ein Tutorial gibt werde ich hier nichts mehr darüber schrieben.&lt;br /&gt;
Alternativ sollte alles was zwischen glBegin und glEnd in Displaylisten gespeichter werden. Das Speichern von Texturwechseln usw ist nicht sinvoll, da diese nicht zum Rendern der Shadowmaps benötig werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehrfachen Lichquellen kann es wiederum Sinn machen den ersten Rendervorgang inclusive Shaderwechsel in einer Displayliste zwischenzuspeichen und die zusätzlichen Schadowmaps mit dieser zu rendern.&lt;br /&gt;
&lt;br /&gt;
===Algemeines zu GLSL===&lt;br /&gt;
Ich möchte nocheinmal darauf hinweisen, das sich uniformvariablen nur setzten Lassen, wenn der entsprechnde shader gebunden ist. (Es funktionier nicht wenn der shader nicht gebunden ist. Warum man den shader dabei allerdings angeben muss ist mir nicht so ganz klar)&lt;br /&gt;
In den Beispielen werden nur die Uniformvariablen wärend des Rendervorgangs neu gesetzt die sich ändern.  Die zuweisung der TMU zu einem Sampler gehöhrt in der Regel nicht dazu. &lt;br /&gt;
&lt;br /&gt;
===Grundlegendes zu den Koordinatensystemen in den Shadern===&lt;br /&gt;
&lt;br /&gt;
Im Vertexshader müssen alle komponenten von gl_Position in einem Bereich von -1.0 bis 1.0 gebracht werden. Besonders beim Z-Wert könnte es verwirrend, dass der Bereich  von gl_FragDepth im Fragmentshader von 0.0 bis 1.0 geht. Auch muss beachtet werden, dass Texturkordinaten den bereich von 0.0 bis 1.0 nutzen, wärend die Rendertargets im Bereich on -1.0 bis 1.0 arbeiten.&lt;br /&gt;
In den Shadern werden daher öfters Multimplikationen mit 0.5 und einer anschließenden Addition von 0.5 auftreten.&lt;br /&gt;
&lt;br /&gt;
==Perspektivische Maps==&lt;br /&gt;
&lt;br /&gt;
In dem erstem Teil dieses Artikels geht es um perspektivisch angepasste Schattenmaps. Normale projezierte Schatten haben das Problem, das sie im Nahenbereich besonders stark verpixeln und in der Entfernung durch ein viel zu hohes Oversampling Bandbreite verschwenden.&lt;br /&gt;
&lt;br /&gt;
Für eine globale Lichquelle wird nur ein Vektor gegeben, der die Richtung des Lichtes beschreibt. Die gedachte Lichtquelle ist quasi unendlich weit weg. Da eine Entfernungsberechnung zur Lichquelle unmöglich ist, muss die Schattenberechnung relativ zu einer Referenzebene durchgeführt werden. Diese Ebene kann sowohl Senkrecht zum Lichvektor, als auch parallel zum gedachtem Boden ausgerichtet werden. Die Ausrichtung der Referenzebene beeinflusst die später sichtbare Auflösung der Schatten.&lt;br /&gt;
&lt;br /&gt;
Nach dem ein Vertex auf die Ebene projeziert wurde und der Abstand ein einen berech von 0.0...1.0 gebracht wurde, muss diese unendlich große Ebene noch auf eine endliche Größe projeziert werden, die auf eine Textur passt und die entfernungsabhängige Detailierung beachtet.&lt;br /&gt;
&lt;br /&gt;
Wenn wir unsere Referenzebene einfachhalber den Horizont schneidet (und auch den Bildschirm in obere und untere Hälfte teilt) Könnte ein Algorimus in etwa so aussehen (Dieser lässt sich später in ein Vertexshaderprogramm umsetzten):&lt;br /&gt;
&lt;br /&gt;
Projeziere den Vertex in die Modelview (Diese Schritt wurde auch bei den dualparaboliden Maps durchgeführt)&lt;br /&gt;
Ermittel den Schnittpunt des vom Vertex ausgehendem gedachtem Lichtstrahl und der Referenzebene.&lt;br /&gt;
Benutze den Abstand zwischen Schnittpunkt und Vertex um den Z-Wert zu ermitteln. (Es sind zwei zusätzlich referenzwerte nötig die die funktion Farclip und Nearclip übernehmen)&lt;br /&gt;
Projeziere die Ebene auf eine Ebene die in eine Textur passt pos/=abs(pos)+1.0 passt recht gut.&lt;br /&gt;
Anschließend wird noch die Schadowmap noch gestreckt und der Bereich hinter der Kammera entfernt.&lt;br /&gt;
&lt;br /&gt;
Das wichtigste ist, dass beim auswerten der shadowmaps der gleiche Projektionsalgoritmus verwendet wird wie beim generieren.&lt;br /&gt;
&lt;br /&gt;
Prinzipell sollte sich der Algoritmus schon auf einer Geforce 3 oder Radeon 8500 implementieren lassen. Da da der Code hier in GLSL geschrieben ist, sollte in etwa Shadermodel 2.0 unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeitsmäßig ist dieser Algoritmus den Stencilshadows deutlich überlegen. Auch bei Stencilshadows sind mehrere Renderpasses nötig. Vorallem das extruieren der Siluetten kostet einiges an Bandbreite. Der geschätzte Aufwand ist etwa 20 (Aufwendige Shader im Finalem Renderdurchgang)bis 80% (CPU limitiert Geometrieübergabe) Mehraufwand gegenüber einer Schattenlos gerenderten Scene.&lt;br /&gt;
Auch die Qualität ist nicht schlechter. Bei der Verwendung von weichen Schatten wirken Shadowmaps natürlicher als die extrem scharfen Stencilshadows. &lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
In der Hauptschleife könnte folgender Code verwendet werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, 0 ); //Entfernt alle Texturen aus der ersten TMU&lt;br /&gt;
	glUseProgramObjectARB(shadow); //lädt den Schattenshader&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb); //Bindet das Framebufferobjekt&lt;br /&gt;
	&lt;br /&gt;
	glViewport (0, 0,shadow_sz,shadow_sz); //Anpassen des Viewportes &lt;br /&gt;
	glClear(GL_DEPTH_BUFFER_BIT); //Z-Buffer löschen&lt;br /&gt;
	&lt;br /&gt;
	render(); //Erster Renderdurchgang&lt;br /&gt;
&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); //Normalen Framebuffer binden&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, shadow_tx ); //Tiefenmap an die erste TMU binden&lt;br /&gt;
	glUseProgramObjectARB(final); //finalen shader binden&lt;br /&gt;
	&lt;br /&gt;
	glViewport(0, 0, screen_size_x, screen_size_y);&lt;br /&gt;
	&lt;br /&gt;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Color und Z-Buffer löschen&lt;br /&gt;
	render(); //rendern&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Shader===&lt;br /&gt;
&lt;br /&gt;
Als erstes der Vertexshader zum generieren der Schadowmap. shadow.vert:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){&lt;br /&gt;
&lt;br /&gt;
	vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0)); //Lichtvektor in den Modelsprace rotieren&lt;br /&gt;
	vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex); //Vertex in den Modelspace projezieren&lt;br /&gt;
	vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y; //Schnittpunkt mit der XZ Referenzebene&lt;br /&gt;
	pos = pos / (abs(pos)+1.0); //Projektion der Ebene auf ein Quadrat&lt;br /&gt;
	pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
	gl_Position.xy = pos;&lt;br /&gt;
	gl_Position.z = -mvertex.y ; // Der Bereich von +-1 über der Referenzebene wird erfasst&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Lichtrichtung wird vorläufig noch fest übergeben. Eine Auswertung einer Opengl Lichtquelle oder einer Uniformvariable wäre ebenfalls möglich. Anschließend wird der Vertex in die Modelview projeziert und der Schnittpunkt des vom Vertexausgehendem Lichstrahls mit der Referenszebene berechnet. Als letztes wird noch der Abstand zur Referenzebenein einem Bereich 0..1  umgerechnet und die Texturkoordinaten für eventuelles Alphamasking oder Heightmapping durchgeschleift. Soll Alphamasking verwendet werden, muss ein entsprechender Shader geschrieben werden der bei den freizulassenden pixeln discard(); aufruft. Dies sollte jedoch nur für die betroffenen Poligone stat finden, da die Grafikkarte dann keine Early-Z Optimierungen verwenden kann. Ansonsten ist der Fragmentshader ist sehr einfach: shadow.frag:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die für die Auswertung müssen wir im finalem Renderdurchgang exakt die gleichen Texturkoordinaten für die Shadowmap generieren. Allerdings gibt es eine Besonderheit: Die koordinaten einer Textur reichen von 0;0 bis 1;1, Die Koordinaten eines Rendertargets reichen jedoch von -1;-1 bis 1;1, so das eine zusätzliche korrektor nötig ist.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
        vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0));&lt;br /&gt;
        vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
        vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y;&lt;br /&gt;
        pos = pos / (abs(pos)+1.0);&lt;br /&gt;
        pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
        pos = pos * 0.5 + 0.5; //auf Texturkoordinaten umrechnen&lt;br /&gt;
 &lt;br /&gt;
        spos.xy = pos; //Daten in einer Varying verpacken&lt;br /&gt;
        spos.z = -mvertex.y * 0.5 + 0.5 - 0.005; // far and near clamping and Anti-Z-fighting-offset &lt;br /&gt;
 	&lt;br /&gt;
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //Die echte Transformation&lt;br /&gt;
 &lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten 5 Zeilen der main() sollten exakt das gleiche tun wie der Vertexshader zum gnerieren dem Map.&lt;br /&gt;
&lt;br /&gt;
Nun fehlt noch ein Fragmentshader für den letzten Durchgang:&lt;br /&gt;
&lt;br /&gt;
Es muss noch der Noralvektor berücksichtigt werden!!!&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Shadowmap;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
 &lt;br /&gt;
void main(void){&lt;br /&gt;
        if (texture2D(Shadowmap, spos.xy).r &amp;gt; spos.z ){&lt;br /&gt;
              //Licht&lt;br /&gt;
              gl_FragColor = vec4(1.0,1.0,1.0,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        else{&lt;br /&gt;
              //Schatten&lt;br /&gt;
              gl_FragColor = vec4(0.5,0.5,0.5,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Parabolide Maps==&lt;br /&gt;
&lt;br /&gt;
Einfache parabolide Maps können für alle Punktlichquellen verwendet werden, deren Licht nicht in alle Richtungen abgestrahlt wird. Darunter fallen vorallem Spots und an Wänden oder Decken befestigte Lampen. Im gegensatz zur Paralelem Licht oder einer Punktlichquelle bringt eine solche Lichtquelle häufig eine Helligkeitsmap mit. Für die Helligkeitsmap und die Schattenmap können die gleichen Texturkoordinaten verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Bei kleinen Öffnungswinkeln hat die parabolide Map keinen Vorteil gegenüber einer normalen Projektion. Der Vortiel ist jedoch das der Code sich für Öffnungswinkel von bis zu ~240 Grad eignet. &lt;br /&gt;
&lt;br /&gt;
Um eine solche Lichquelle zu beschreiben weden nicht weniger als drei Vektoren benötigt:&lt;br /&gt;
&lt;br /&gt;
* Position&lt;br /&gt;
* Richtung &lt;br /&gt;
* Tangent&lt;br /&gt;
&lt;br /&gt;
Wärend die Funktion der ersten beiden Vektoren klar ist, wird der Tangent wird dazu benötigt die Schattenmap und Helligkeitsmap auszurichten. Er ist Senkrecht zur Richtung tangential zur Textur ausgerichtet &lt;br /&gt;
Beschreiben lässt sich diese Funktion lässte sich am ehesten durch das Verdrehen einer Taschenlampe. Wenn die Schattenmap gegenüber den schattenwerfenden Objekten verdreht wird, sieht das Bild auf keinen Fall mehr natürlich aus.&lt;br /&gt;
 &lt;br /&gt;
Es ist sowohl möglich die Berechnungen im Vertexshader durchzuführen, als auch eine entsprechnede Matrix in den Uniformvariablen abzulegen. Wenn die Berechnungen per Matrix durchgefühert werden lässt sich das Prinzip der paraboliden Maps zuindest als Reflektionsmap nutzen. Ein weiterer Vorteil an einer vorberechneten Matrix ist, dass diese auch für shadowmap verwendet werdne kann die nicht jedes Frame neu berechnet werden.&lt;br /&gt;
&lt;br /&gt;
==Dual Parabolide Maps==&lt;br /&gt;
Von OpenGL kennen wir zwei Projektionsmöglichkeiten: Orthografische und perspektivische Projektion. Beide Projektionen arbeiten ohne Verzerrung. Jede Gerade bleibt beim Transformieren eine Gerade. Wenn man dagegen das Bild eines Fischeyeobjektives betrachtet, allen einem sofort die zu Kurven verzerrten Geraden auf. Der entscheidene Vorteil an einer Fisheyeaufnahme ist, dass ein Öffnungswinkel von 180 Grad erfasst werden kann. Zwei entgegensetzte Aufnahmen können so problemlos den kompletten Raum um die Kamera erfassen.&lt;br /&gt;
&lt;br /&gt;
Für das Erstellen der Tiefenmap ist es notwendig den Raum um das reflektierende Objekt in eine Textur zu rendern. Meistens wird hier eine Cubemap verwendet. Soll diese dynamisch generiert werden, ist es auffällig, dass die Scene ganze 6 mal gerendert werden muss. Mit der dual paraboliden Map sind nur noch zwei Rendervorgänge nötig, es wird zwar keine Füllrate eingespart, dafür müssen nun nur noch 1/3 der Daten transformiert werden, so das die Vertexshader und die CPU entlastet werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitere Optimierung ist unter Umständen möglich: Wenn bei einer Cubemap auf eine der Flächen verzichte werden kann. Z.B. wird die Reflektion im Lack eines Autos so gut wie nie verdeckte Straße zeigen. Auch ist für eine an einer  Wand befestigten Lampe nur eine halbkugelförmige Shadowmap nötig. Wenn sie einen Abstand zur Wand hat, genügt es auch hier den Blickwinkel von 180 Grad etwas zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Die Projektion der dualparaboliden Map kann man sich am besten Bild eines Fisheyobjektives vorstellen. Mathematisch etwas genauer ist das Reflektionsbild der umgebenden Welt in einem Rotationsparaboliden.&lt;br /&gt;
&lt;br /&gt;
Die Hardwareanforderungen an den Pixelshader sind nicht gerade gering. Der Pixelshader für die 8fachen Lichquellen kommt nach dem Compelieren auf über 170 Instruktions. Eine Shader 2.0 Karte wie z.B. die Radeon 9x00 sind hier hoffnungslos überfordert da sie nur an 3 Stellen im Programm auf die Textureinheiten zugreifen können und der Assembler nicht mehr in der Lage ist die Instruktions passend umzusortieren. Noch fataler wird es  wenn die Texturelookups durch dynamisches Branching übersprungen weder sollen: Die Karte hat keine Chance mehr diese umzusortieren.&lt;br /&gt;
&lt;br /&gt;
Wer dualparbolide Maps auf SM2.0 Karten einsetzten will sollte damit rechnen, dass das Limit bei 2 bis 4 Maps liegen sollte.&lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
So kann in der Hauptschleife das rendern der 16 paraboliden Maps und der anschließende Finale Renderdurchgang durchgeführt werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for (int light;light&amp;lt;8;light++){&lt;br /&gt;
        glViewport (shadow_size/2*(lights/4),shadow_size/4 *(light%4),shadow_size/4,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;light&amp;quot;),light);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),0);&lt;br /&gt;
        render();&lt;br /&gt;
        glViewport (shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light%4),shadow_size/4 ,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),1);&lt;br /&gt;
        render();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Vieport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0,Windowsize_X,Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for light := 0 to 7 do&lt;br /&gt;
begin&lt;br /&gt;
  glViewport(shadow_size/2*(lights/4), shadow_size/4 *(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'light'), light);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'), 0);&lt;br /&gt;
  render();&lt;br /&gt;
  glViewport(shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'),1);&lt;br /&gt;
  render();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Viewport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0, Windowsize_X, Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Die Shader===&lt;br /&gt;
&lt;br /&gt;
====Shader zum Rendern der Schattenmaps====&lt;br /&gt;
parabol.vert&lt;br /&gt;
&amp;lt;glsl&amp;gt;  uniform int renderpass;&lt;br /&gt;
  uniform int light;&lt;br /&gt;
  varying vec3 normal;&lt;br /&gt;
  varying vec3 pos;&lt;br /&gt;
&lt;br /&gt;
  void main(void){&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewMatrix * gl_Vertex - gl_LightSource[light].position ;&lt;br /&gt;
&lt;br /&gt;
	float L= length (gl_Position.xyz);&lt;br /&gt;
	gl_Position /= -L;&lt;br /&gt;
	if (renderpass == 1) gl_Position.z *=-1.0;&lt;br /&gt;
	gl_Position.z += 1.0;&lt;br /&gt;
	gl_Position.xy /= gl_Position.z;&lt;br /&gt;
	if (gl_Position.z &amp;gt;= 0.01){&lt;br /&gt;
		gl_Position.z = L / 15.0;//Todo: optimieren&lt;br /&gt;
		gl_Position.w = 1.0;&lt;br /&gt;
		}&lt;br /&gt;
	else{&lt;br /&gt;
		gl_Position.z = -1.0;&lt;br /&gt;
		gl_Position.w = -1.0;&lt;br /&gt;
		}&lt;br /&gt;
        &lt;br /&gt;
        gl_Position.z = 2.0 * gl_Position.z -1.0; //Todo: optimieren&lt;br /&gt;
	pos=gl_Position.xyz;&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
parabol.frag&lt;br /&gt;
&amp;lt;glsl&amp;gt;varying vec3 pos;&lt;br /&gt;
void main(void){&lt;br /&gt;
	if (length(pos.xy)&amp;gt;1.005)discard; //Diese Zeile kann durchaus entfallen. Kosten/Nutzen unbekannt.&lt;br /&gt;
	}&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Uniformaviablen, die gesetzt werden müssen: Eine ist die Nummer der aktuellen Lichtquelle und die zweite der Renderpass, der angibt ob die Vorder- oder Rückseite der parabolischen Map gerendert werden soll. Eine automatische Berechnung der Texturkoordinaten wäre zwar möglich, jedoch ist die Änderung des Viewports deutlich weniger Rechenaufwendig.&lt;br /&gt;
&lt;br /&gt;
Statt einer Multiplikation des gl_Vertex mit der gl_ModelViewProjektionMatrix wird hier nur mit der gl_ModelViewMatrix multipliziert. Dadurch werden nur die Transformationen durchgeführt und die Projektion übersprungen.&lt;br /&gt;
Die Division durch -L entspricht weitgehend einer Normalsierung, spiegelt die Welt jedoch in die richtige Lage. L enthält jetzt die Tiefeninformation, gl_Position einen Vektor, der von der Kammera auf den Vertex zeigt. Mit den zwei folgenden Zeilen wird der Vektor parabolisch auf die Bildschirmkoordinaten projeziert (Intervall von -1.0 bis 1.0). Mit Hilfe der folgenden if-Abfrage werden alle Vertices hinter der Kammera geclipt. Nur sichtbare Vertices bekommen gültige z Werte für den Zbuffer im Intervall von -1.0 bis 1.0. &lt;br /&gt;
&lt;br /&gt;
Der Fragmentshader ist extrem einfach, da wir aufgrund des nicht vorhandem Colorbuffers keinen Farbwert benötigen lassen wir diesen wie bei den perspektivischen Maps einfach undefiniert.&lt;br /&gt;
Zudem verlassen wir den Shader mit discard, wenn der der Pixel außerhalb der aktuellen paraboliden Map liegt. Die Voteil ist, das nur der kreisförmige Bereich der Map verwendet wird, der Nachteil, das durchaus eine Early-Z optimierung nicht mehr möglich ist. Sehr Sinvoll sollte dies sein, wenn die Shadowmaps dynamisch nach benötigter Größe angeordnet werden. Da sich Kreise besser als Quadrate packen lassen.&lt;br /&gt;
&lt;br /&gt;
====Shader für den finalen Renderdurchgang====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
final.vert&lt;br /&gt;
&amp;lt;cpp&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	Normal = gl_NormalMatrix * gl_Normal;&lt;br /&gt;
 	ModelVertex  = vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
final.frag&lt;br /&gt;
&amp;lt;cpp&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
uniform int MaxLights;&lt;br /&gt;
&lt;br /&gt;
//Achtung folgende Zeile ist nicht GLSL konform. &lt;br /&gt;
//Workaround: Array als Uniform übergeben oder durch sehr aufwendige berechnung erstzten&lt;br /&gt;
//Sollte es auch auf ATI Karten funktinieren, frage ich mich warum es nicht erlaubt ist...&lt;br /&gt;
const vec2 texofset[8] = {vec2 (0.125,0.125), vec2 (0.125,0.375), vec2 (0.125,0.625), vec2 (0.125,0.875),&lt;br /&gt;
			  vec2 (0.625,0.125), vec2 (0.625,0.375), vec2 (0.625,0.625), vec2 (0.625,0.875)};&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
	vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
	for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
		vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
		vec3 lightdir = normalize( lightvec );&lt;br /&gt;
		vec2 parabol = texofset[LightNum];&lt;br /&gt;
		if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
			parabol.t += 0.25;&lt;br /&gt;
			}&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
		parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
		vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
		light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
		}&lt;br /&gt;
	vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));	//Textur auslesen; &lt;br /&gt;
	gl_FragColor = light * color ;&lt;br /&gt;
	}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Möglicher weise für ATI taugliche Variante:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
 &lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
const int MaxLights=8;&lt;br /&gt;
 &lt;br /&gt;
vec2 texofset[8]; &lt;br /&gt;
void main(void){&lt;br /&gt;
	texofset[0] = vec2 (0.125,0.125);&lt;br /&gt;
	texofset[1] = vec2 (0.125,0.375);&lt;br /&gt;
	texofset[2] = vec2 (0.125,0.625);&lt;br /&gt;
	texofset[3] = vec2 (0.125,0.875);&lt;br /&gt;
	texofset[4] = vec2 (0.625,0.125);&lt;br /&gt;
	texofset[5] = vec2 (0.625,0.375);&lt;br /&gt;
	texofset[6] = vec2 (0.625,0.625);&lt;br /&gt;
	texofset[7] = vec2 (0.625,0.875);&lt;br /&gt;
&lt;br /&gt;
        vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
        vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
        for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
                vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
                vec3 lightdir = normalize( lightvec );&lt;br /&gt;
                vec2 parabol = texofset[LightNum];&lt;br /&gt;
                if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
                        parabol.t += 0.25;&lt;br /&gt;
                        }&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
                parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
                float shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
                light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
                }&lt;br /&gt;
        vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0])); //Textur auslesen; &lt;br /&gt;
        gl_FragColor = light * color ;&lt;br /&gt;
        }&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Shader besitzen 3 Uniformvariablen, die unbedingt mit den richtigen Werten gefüllt werden müssen. Zwei davon sind Texturen, die dritte die Anzahl der aktiven Lichtquellen. Es ist wichtig zu wissen, dass der Shader nicht den OpenGL-Status der Lichquellen berücksichtigt und nur die Daten der Ersten bis MaxLights holt.&lt;br /&gt;
Während bei den Schattenmaps die meiste Arbeit im Vertexshader erledigt werden könnte, ist dieser sehr Fragmentshader lastig. Die Texturkoordinatenberechnung ist sehr ähnlich zu der im shadow.vert. Die größte Änderung ist, dass hier abhängig von der Lichtquellennummer ein Offset aufaddiert wird um die Untertextur auszuwählen. Ein zusätzlicher Offset wird dazuaddiert, wenn auf die zweite parabolide Map einer Lichtquelle zugegriffen wird.&lt;br /&gt;
Um ein dynamisches Branching zu vermeiden, wird mit der Stepfunktion ermittelt ob sich das Fragment im Schatten befindet.&lt;br /&gt;
&lt;br /&gt;
==Optimierungen und Verbesserungen==&lt;br /&gt;
Hier sind noch einige Vorschläge, die helfen können um besser Qualität oder Leistungen im eigenem Programm zu bekommen. Eine uniververselle Lösung lässt sich nur auf kosten von Performance schreiben. Viel besser ist es, wenn man die Shader an die jeweilige Situation anpasst. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schatten durch Alphatest===&lt;br /&gt;
Der bisherige Schattenshader kann nur ganze Polygone einen Schatten werfen lassen. Wenn shadow.vert so ergänzt wird, das die Texturkoordinaten in den Fragmentshader  weitergereicht werden, dann ist es mit folgendem Fragmentshader möglich Shatten in Abhängikeit einer Alphatextur zu rendern:&lt;br /&gt;
&lt;br /&gt;
shadow.frag&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
        if (texture2D(Texture0,vec2(gl_TexCoord[0])).a &amp;lt; 0.5) discard;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Der Shader wird verlassen wenn das Texel einen Alphawert von kleiner als 50% hat. Damit lassen sich Schatten von Pflanzen wesentlich realistischer darstellen. Dieser Shader sollte natürlich nur dann verwendet werden, wenn eine Alphakanal in der Textur vorhanden ist. Auch Shader mit Paralax- oder Displacementmapping arbeiten kann man so um einen Schatten ergänzen, wenn die Polygone transparente Teile enthalten.&lt;br /&gt;
Es ist auch möglich den shader zu verlassen, wenn eine bestimmte Farbe in der Textur gefunden wird, dann nimmt die Alphamaske keinen Speicherplatz mehr weg.&lt;br /&gt;
&lt;br /&gt;
===Farbiges Glas===&lt;br /&gt;
&lt;br /&gt;
Schatten hat jetzt ja sachon fast jeder. Aber wie wäre es mal mit einfärben von dynamischen Lichtquellen?&lt;br /&gt;
Der Algoritmus ist nicht schwer:&lt;br /&gt;
&lt;br /&gt;
* Alle Undurchichtigen Sceneteile in die Tiefenmaps gerendert. &lt;br /&gt;
* Zusätzlich wird eine Colormap gebunden und das Schreiben in den Zbuffer unterbunden.&lt;br /&gt;
* Die Colormap wird mit Weiß oder einer Helligkeitsmap initialisiert.&lt;br /&gt;
* Rendern aller transparenten Objekten&lt;br /&gt;
* Auf finales Rendern umschalten&lt;br /&gt;
* Alle undurchsichtigen Objekte mit hilfe der Schadowmap und der modifizierten Beleuchtungmap beleuchten.&lt;br /&gt;
* Alle Transparenten Objekte rendern, unter Berücksichtigung, dass die Lichtquelle bereits das gefilterte Licht aussendet. Dieses Blending sollte rückgängig gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Bei diesem Algoritmus bleibt noch das Alphablendingproblem mit der mehrfachen Überdeckung. Beim Modifizieren der Beleuchtungsmap gegebenfalls den Stencilbuffer zur Hilfe nehmen. Hier wäre ein denkbarer Algoritmus:&lt;br /&gt;
&lt;br /&gt;
* Alle transparenten Poligone in den Zbuffer rendern. Dabei für alle Poligone, deren  doppelte Filterung zu Fehlern führen kann mit verschiedenen Stencilwerte schreiben.&lt;br /&gt;
* Zbuffer und Colorbuffer Löschen. &lt;br /&gt;
* Helligkeitsmap in den Colorbuffer kopieren.&lt;br /&gt;
* Alle nicht transparanten Objekte in den Zbuffer Rendern. &lt;br /&gt;
* Alle transparenten Poligone mit den gleichen Stencilwerten wie im erstem Pass rendern. Die Bedingung ist, dass nur Polygone in den Zbuffer geschrieben werden, bei den Stencilwerte nicht mit den Stencilbuffer übereinstimmen. Die vordersten Polygone werden so aussortiert und nur die zweite Schicht landet im Zbuffer.&lt;br /&gt;
* Im letztem Rendervorgang müssen die gefilterten Lichtfarben der Transparenten Polygone in den Colorbuffer geschrieben werden. Die Bedingung ist das die Stencilwerte übereinstimmen müssen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn es wie ein großer Mehraufwand aussieht, ist der Anteil der transparenten Poligone doch eher gering. So das deren dreifacher Overdraw kaum eine Rolle spielt. Im Finalem Renderdurch gang gibt es bei den transparenten Polygonen noch eine Besonderheit: Stimmt die Entfernung aus der Shadowmap mit der Entfernung der Lichquellen (fast) überein, so wird das Poligon mit dem Licht aus der Colormap belauchtet. Ist die Entfernung aus der Shadowmap jedoch größer als die entfernung zu lichquellen, enthällt die Colormap die gefilterte Farbe des Lichtes hinter dem Poligon. Für die beleutung des Poligon muss also das Licht der Lichquelle benutzt werden. Sinvoll ist es die helligkeit für diesen Fall im Alphawert der Colormap zu Speichern.&lt;br /&gt;
&lt;br /&gt;
Ansonsten noch ein paar Vorschläge:&lt;br /&gt;
* Objekte die aus dem gleichem Glas sind und auch einfarbig. Sollten mit dem gleichem Stencilwert verarbeitet werden. So sieht z.B. das gefärbte Licht einer zweifach durchstrahlten leicht gefäbten Glasskuppel natürlicher aus als ein Vollschatten. Auch wenn das Licht korrekter weise zwei mal hätte gefiltert werden müssen. &lt;br /&gt;
* Eventuel macht es sind mehrfarbige Objekte in mehrfache einfarbige Objekte zu zerlegen.&lt;br /&gt;
* Komplexe Mehrfachfilterungen sollten vermieden werden oder so gewählt werden, das sie natürlich ausehen. Gute Filter wären komplementärfarben, da dort ein echter Schatten erzeugt wird. Schlechte Kombinationen wären unter anderem Rot+Gelb, Blau+Gelb, usw...&lt;br /&gt;
* Um von den Farbfehlern abzulenken, farbige Objekte in einer rotverschobenen Farbe flourezieren lassen. (Violet-&amp;gt; Blau -&amp;gt; Grün -&amp;gt; Gleb -&amp;gt; Organge -&amp;gt; Rot) Durch blau gefärbte Fenster, blau gefilterte Licht welches Dinge grün aufleuchten lässt nimmt einem jeder PC Modder ab...&lt;br /&gt;
&lt;br /&gt;
===Schattenmap durch eine Heightmap modifizieren===&lt;br /&gt;
Auch wennich hierzu noch kein Beispiel haben, ist es möglich gl_FragDepth mit hilfe einer Heightmap zu modifizieren. Prinzipiell entspricht dies einem einfachem Offsetmapping. Damit wäre durchaus eine Selbstschattierung von Bumpmaps möglich.&lt;br /&gt;
&lt;br /&gt;
===Zweite parabolische Map vermeiden===&lt;br /&gt;
Lichtquellen, die nur in eine Richtung Licht werfen können, wie z.B. Spotlichter oder Lichter, die in Bodenähe oder Wandnähe befestigt sind, benötigen keinen vollständig erfassten Tiefenraum. Die Parabolische Map kann problemlos herein oder herausskaliert werden, so das Öffnungswinkel von 0 bis ca 240 Grad möglich sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das verkleinern des Öffnungswinkels für zusätzliche Spotlichter ermöglicht auch kleinere Tiefenmaps, die in die 9 Zwischenräume der großen gepackt werden können. Die Zwischenräume können noch Maps mit einem Durchmesser von 40% der großen Maps aufnehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Texturelookups vermeiden===&lt;br /&gt;
Wenn das Skalarprodukt von normalvec und -lightdir negativ ist, dann ist die Oberfläche von der Lichtquelle abgewandt und Berechnungen für die Lichquelle können komplett übersprungen werden. Diverse Multiplikationen und vorallem Texturelookups können so übersprungen werden. Besondere aufwendige Algorithmen wie selbstschattierende Bumpmaps, können so deutlich Beschleunigt werden. &lt;br /&gt;
&lt;br /&gt;
Für die Beleuchtung sollte dann allerdings auch folgende Zeile verwendet werden. (Das Skalarprodukt von vor der if Abfrage aber umbedingt wiederverwerten!) &lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
  light += gl_LightSource[0].diffuse * max(dot(normalvec, -lightdir), 0.0);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reichweite der Lichtquellen=== &lt;br /&gt;
Leider bietet OpenGL nicht direkt die Möglichkeit die maximale Reichweite einer Lichquelle anzugeben. In den Shadern wird zur Zeit der Wert 15.0 als maximale Entfernung zur Lichtquelle verwendet. Für ein einfaches Programm ist es sicher ausreichend, ansonsten macht es Sinn diesen Wert durch eine Unformvariable zu ersetzten, oder um mehr Flexibiltät zu bekommen durch ein Array aus 8 Uniformfloats.&lt;br /&gt;
&lt;br /&gt;
===Oversampling der Schattenmap===&lt;br /&gt;
Die Qualität lässt sich dadurch mehrere Samples auf der Schattenmap verbessern. Das folgende Codefragment nimmt 3 statt des einem Samples und glättet die Ränder des Schattens. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;const float pof =1.0 /4096.0 *0.7;&lt;br /&gt;
vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol +vec2(pof,0)).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,-pof/1.2) ).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,pof/1.2)).r );&lt;br /&gt;
light += shadow * 0.33 * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Durch 9x Oversampling lässt sich schon eine sehr gute Qualität ereichen, sorgt aber bei 8 Lichtquellen durch die 72 Texturelookups für einen Zusammenbruch der Framerate.&lt;br /&gt;
Wichtig ist auch, dass man beachtet, dass die dualparaboliden Maps an Ihren Ränden undefiniert sind und so zu Artefakten kommen kann wenn man außerhalb des gültigem Bereichs sampled. Eine Möglichkeit wäre einen Bereich zu erfassen, der etwas größer als 180 Grad ist, um am Rand zusätzliche Texel zu schaffen.&lt;br /&gt;
&lt;br /&gt;
===Ein zusätzlicher Renderpass===&lt;br /&gt;
Nach dem die Tiefenmap gerendert würde, wäre es möglich in einem weiterem Framebufferobjekt eine zusätzliche Map zu rendern, in der mit Hilfe einer Kantenerkennung die Helligkeit der Softshadows vorberechnet wird. Auch hier muss berücksichtigt werden, dass die dualparaboliden Maps einen Übergang haben.&lt;br /&gt;
&lt;br /&gt;
===Dynamische Lichter in statische Lightmaps Rendern===&lt;br /&gt;
Wenn sich Lichtquellen nicht relativ zur Umgebung nicht bewegen, ist es möglich sie in eine Lightmap zu rendern. Unter der Annahme, dass Lightmapkoordinaten vorhanden sind (ohne geht es echt nicht gut), müssen diese nur per Vertexshader an den Pixelshader weitergegeben werden. Im Pixelshader kann dann wie im final.frag die Helligkeit berechnet werden und in der Lightmap abgespeichert werden.&lt;br /&gt;
Es ist immer noch möglich, das dynamische Objekte einen Schatten werfen: Es werden nur noch die beweglichen Objekte in die Tiefenmap gerendert. Im Schatten wird dann einfach das Licht der im Schatten liegenden Lichtquelle subtraiert.&lt;br /&gt;
&lt;br /&gt;
===Statische Anteile in den Schattenmaps===&lt;br /&gt;
Es ist möglich mit einer zusätzlichen Matrix die Tiefenmaps zu den Weltkoordinaten auszurichten. Statische Anteile können dann aus einer zweiten Tiefenmap kopiert werden. Ein wenig problematisch ist das Entfernen der Rotation aus der gl_ModelViewMatrix. Das größte Problem ist, das die Positionen der Lichquellen bereits mit der gl_ModelViewMatrix multipliziert sind. Die einfachste Lösung ist, aus den den Rotationswinkeln eine neue Matrix zu erechnen, mit dessen Hilfe die Schattenvektoren für die Texturkoordinatenberechnung zurückgedreht werden. Diese Matrix sollte dann als Uniformvariable übergeben werden.&lt;br /&gt;
Wenn die Schatten durch einen zusätzlichen Renderdurchgang gefiltert werden. Ist es sinvoll die Maps erst hier zu vereinen. Von beiden Tiefenmaps muss nur immer der kleinere Wert genommen werden.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19724</id>
		<title>GLSL Licht und Schatten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GLSL_Licht_und_Schatten&amp;diff=19724"/>
				<updated>2006-10-08T15:08:39Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Shader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Willkommen zu meinem erstem Tutorial. Schatten können sowohl Traum als auch Albtraum eines jeden OpenGL-Progrmamieres werden. Im Gegensatz zur einfachen Beleuchtung mit Lichtquellen, steigt der Rechenaufwand hier extrem an und ohne Optimierung zwingen die Schatten selbst die modernste Hardware in die Knie.&lt;br /&gt;
Für Schatten gibt es zwei praktikable Algoritmen: Den Stencilschatten und den projezierten Schatten. Hier möchte ich mich auf den projezierten Schatten beschränken, er bietet gegenüber dem Stencilschatten einige Vorteile:&lt;br /&gt;
&lt;br /&gt;
*Die komplette Berechnung kann von der Grakfikkarte übernommen werden&lt;br /&gt;
*Es ist möglich Softshadows zu realisieren&lt;br /&gt;
*Die Shadowmaps können unter Umständen für mehr als ein Frame verwendet werden&lt;br /&gt;
&lt;br /&gt;
Um den Rechenaufwand zu veringern werde ich hier zusätzliche Projektionstechniken zeigen, die über den Vertexshader realisiert werden: Die perspektivische Map und das parabolide Mapping. &lt;br /&gt;
&lt;br /&gt;
Für sehr weit entfernte Lichtquellen und offene Szenen ist der Einsatz von perspektisch angepassten Maps sinvoll. Da das Licht quasi parallel ausgestrahlt wird. Ist ein winkelabhängiger Cube oder dualparabolische Map kaum möglich. Auch eine einfache quadratische Shadowmap zeigt deutliche Schwächen bei der Auflösung im Nahbereich und dem zu hohem Oversampling in der Entfernung.&lt;br /&gt;
&lt;br /&gt;
Das parabolide Mapping ermöglicht nicht nur die Simulation eine Fischaugenoptik, sondern kann auch die Cubemap vollständig ersetzen. Durch einen geringfügig höheren Rechen- und Programieraufwand genügen zwei Renderpasses um eine vollständige Tiefen- oder Reflektionsmap zu erstellen. Was gegenüber der klassischen Cubemap den Prozessor und GPU um den Faktor 3 entlastet.&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Dieses Tutorial basiert auf den grundlegenden Techniken, die erst in den letzten Jahren entwickelt wurden. Jeder der hier mit anfängt, sollte die zwei anderenen GLSL Tutorials gelesen haben und einfache Fragmentshader schreiben können. Auch das Laden und Einbinden von Texturen in die Shader sollte kein Problem mehr darstellen.&lt;br /&gt;
&lt;br /&gt;
===Framebufferobjekte===&lt;br /&gt;
Für das Erstellen von dual paraboliden Tiefentexturen ist noch das Rendern in Framebufferobjekten Vorraussetzung (zu denen es leider noch kein Tutorial gibt). Damit der Einstieg nicht zu schwer wird sollte dieser Code helfen das FBO zu initialsisieren:&lt;br /&gt;
&lt;br /&gt;
Als Erstes müssen die nötigen Extensions initialisiert werden&lt;br /&gt;
Dann sollten die benötigten Modelle als VBO in die Grafikkarte hochgeladen werden.&lt;br /&gt;
Nun muss das Framebufferobjekt (FBO) für die Schattenmaps erzeugt werdern.&lt;br /&gt;
So könnte die Initialsierung des FBOs aussehen. C code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;GLuint shadow_map = 0; // &lt;br /&gt;
GLuint shadow_fbo = 0; // the shadow texture&lt;br /&gt;
GLuint shadow_size = 4096; //muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
glGenTextures (1, &amp;amp;shadow_map); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindTexture (GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
glTexImage2D (GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0,GL_DEPTH_COMPONENT , GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
glGenFramebuffersEXT (1, &amp;amp;shadow_fbo); //In Pascal das &amp;amp; durch ein @ ersetzten&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D,shadow_map, 0);&lt;br /&gt;
glDrawBuffer (GL_FALSE);&lt;br /&gt;
glReadBuffer (GL_FALSE);&lt;br /&gt;
GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/cpp&amp;gt;&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;var shadow_map,&lt;br /&gt;
    shadow_fbo,&lt;br /&gt;
    shadow_size : GLuint;&lt;br /&gt;
    status      : GLenum; &lt;br /&gt;
begin&lt;br /&gt;
  shadow_map  := 0;  &lt;br /&gt;
  shadow_fbo  := 0;     // the shadow texture&lt;br /&gt;
  shadow_size := 4096; // muss kleiner sein als die maximale Texturgröße sein&lt;br /&gt;
&lt;br /&gt;
  glGenTextures(1, @shadow_map);&lt;br /&gt;
  glBindTexture(GL_TEXTURE_2D, shadow_map);&lt;br /&gt;
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, shadow_size, shadow_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);&lt;br /&gt;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;
&lt;br /&gt;
  glGenFramebuffersEXT(1, @shadow_fbo);&lt;br /&gt;
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo);&lt;br /&gt;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadow_map, 0);&lt;br /&gt;
  glDrawBuffe (GL_FALSE);&lt;br /&gt;
  glReadBuffer(GL_FALSE);&lt;br /&gt;
  status := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); //noch ein wenig Code anfügen um den Status zu überprüfen.&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt sollten die Shader und weiter Texturen geladen werden.&lt;br /&gt;
&lt;br /&gt;
===Beschleunigtes Rendern===&lt;br /&gt;
&lt;br /&gt;
Ich empfehle auch die zu rendernden Daten als Vertexbufferobjekte zu übergeben, da sonst die Mehrfachverwendung der Daten zu einer extremen Bremse wird. Da es hierzu bereits ein Tutorial gibt werde ich hier nichts mehr darüber schrieben.&lt;br /&gt;
Alternativ sollte alles was zwischen glBegin und glEnd in Displaylisten gespeichter werden. Das Speichern von Texturwechseln usw ist nicht sinvoll, da diese nicht zum Rendern der Shadowmaps benötig werden.&lt;br /&gt;
&lt;br /&gt;
Bei mehrfachen Lichquellen kann es wiederum Sinn machen den ersten Rendervorgang inclusive Shaderwechsel in einer Displayliste zwischenzuspeichen und die zusätzlichen Schadowmaps mit dieser zu rendern.&lt;br /&gt;
&lt;br /&gt;
===Algemeines zu GLSL===&lt;br /&gt;
Ich möchte nocheinmal darauf hinweisen, das sich uniformvariablen nur setzten Lassen, wenn der entsprechnde shader gebunden ist. (Es funktionier nicht wenn der shader nicht gebunden ist. Warum man den shader dabei allerdings angeben muss ist mir nicht so ganz klar)&lt;br /&gt;
In den Beispielen werden nur die Uniformvariablen wärend des Rendervorgangs neu gesetzt die sich ändern.  Die zuweisung der TMU zu einem Sampler gehöhrt in der Regel nicht dazu. &lt;br /&gt;
&lt;br /&gt;
===Grundlegendes zu den Koordinatensystemen in den Shadern===&lt;br /&gt;
&lt;br /&gt;
Im Vertexshader müssen alle komponenten von gl_Position in einem Bereich von -1.0 bis 1.0 gebracht werden. Besonders beim Z-Wert könnte es verwirrend, dass der Bereich  von gl_FragDepth im Fragmentshader von 0.0 bis 1.0 geht. Auch muss beachtet werden, dass Texturkordinaten den bereich von 0.0 bis 1.0 nutzen, wärend die Rendertargets im Bereich on -1.0 bis 1.0 arbeiten.&lt;br /&gt;
In den Shadern werden daher öfters Multimplikationen mit 0.5 und einer anschließenden Addition von 0.5 auftreten.&lt;br /&gt;
&lt;br /&gt;
==Perspektivische Maps==&lt;br /&gt;
&lt;br /&gt;
In dem erstem Teil dieses Artikels geht es um perspektivisch angepasste Schattenmaps. Normale projezierte Schatten haben das Problem, das sie im Nahenbereich besonders stark verpixeln und in der Entfernung durch ein viel zu hohes Oversampling Bandbreite verschwenden.&lt;br /&gt;
&lt;br /&gt;
Für eine globale Lichquelle wird nur ein Vektor gegeben, der die Richtung des Lichtes beschreibt. Die gedachte Lichtquelle ist quasi unendlich weit weg. Da eine Entfernungsberechnung zur Lichquelle unmöglich ist, muss die Schattenberechnung relativ zu einer Referenzebene durchgeführt werden. Diese Ebene kann sowohl Senkrecht zum Lichvektor, als auch parallel zum gedachtem Boden ausgerichtet werden. Die Ausrichtung der Referenzebene beeinflusst die später sichtbare Auflösung der Schatten.&lt;br /&gt;
&lt;br /&gt;
Nach dem ein Vertex auf die Ebene projeziert wurde und der Abstand ein einen berech von 0.0...1.0 gebracht wurde, muss diese unendlich große Ebene noch auf eine endliche Größe projeziert werden, die auf eine Textur passt und die entfernungsabhängige Detailierung beachtet.&lt;br /&gt;
&lt;br /&gt;
Wenn wir unsere Referenzebene einfachhalber den Horizont schneidet (und auch den Bildschirm in obere und untere Hälfte teilt) Könnte ein Algorimus in etwa so aussehen (Dieser lässt sich später in ein Vertexshaderprogramm umsetzten):&lt;br /&gt;
&lt;br /&gt;
Projeziere den Vertex in die Modelview (Diese Schritt wurde auch bei den dualparaboliden Maps durchgeführt)&lt;br /&gt;
Ermittel den Schnittpunt des vom Vertex ausgehendem gedachtem Lichtstrahl und der Referenzebene.&lt;br /&gt;
Benutze den Abstand zwischen Schnittpunkt und Vertex um den Z-Wert zu ermitteln. (Es sind zwei zusätzlich referenzwerte nötig die die funktion Farclip und Nearclip übernehmen)&lt;br /&gt;
Projeziere die Ebene auf eine Ebene die in eine Textur passt pos/=abs(pos)+1.0 passt recht gut.&lt;br /&gt;
Anschließend wird noch die Schadowmap noch gestreckt und der Bereich hinter der Kammera entfernt.&lt;br /&gt;
&lt;br /&gt;
Das wichtigste ist, dass beim auswerten der shadowmaps der gleiche Projektionsalgoritmus verwendet wird wie beim generieren.&lt;br /&gt;
&lt;br /&gt;
Prinzipell sollte sich der Algoritmus schon auf einer Geforce 3 oder Radeon 8500 implementieren lassen. Da da der Code hier in GLSL geschrieben ist, sollte in etwa Shadermodel 2.0 unterstützt werden.&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeitsmäßig ist dieser Algoritmus den Stencilshadows deutlich überlegen. Auch bei Stencilshadows sind mehrere Renderpasses nötig. Vorallem das extruieren der Siluetten kostet einiges an Bandbreite. Der geschätzte Aufwand ist etwa 20 (Aufwendige Shader im Finalem Renderdurchgang)bis 80% (CPU limitiert Geometrieübergabe) Mehraufwand gegenüber einer Schattenlos gerenderten Scene.&lt;br /&gt;
Auch die Qualität ist nicht schlechter. Bei der Verwendung von weichen Schatten wirken Shadowmaps natürlicher als die extrem scharfen Stencilshadows. &lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
In der Hauptschleife könnte folgender Code verwendet werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, 0 ); //Entfernt alle Texturen aus der ersten TMU&lt;br /&gt;
	glUseProgramObjectARB(shadow); //lädt den Schattenshader&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb); //Bindet das Framebufferobjekt&lt;br /&gt;
	&lt;br /&gt;
	glViewport (0, 0,shadow_sz,shadow_sz); //Anpassen des Viewportes &lt;br /&gt;
	glClear(GL_DEPTH_BUFFER_BIT); //Z-Buffer löschen&lt;br /&gt;
	&lt;br /&gt;
	render(); //Erster Renderdurchgang&lt;br /&gt;
&lt;br /&gt;
	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); //Normalen Framebuffer binden&lt;br /&gt;
	glBindTexture(GL_TEXTURE_2D, shadow_tx ); //Tiefenmap an die erste TMU binden&lt;br /&gt;
	glUseProgramObjectARB(final); //finalen shader binden&lt;br /&gt;
	&lt;br /&gt;
	glViewport(0, 0, screen_size_x, screen_size_y);&lt;br /&gt;
	&lt;br /&gt;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Color und Z-Buffer löschen&lt;br /&gt;
	render(); //rendern&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Shader===&lt;br /&gt;
&lt;br /&gt;
Als erstes der Vertexshader zum generieren der Schadowmap. shadow.vert:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){&lt;br /&gt;
&lt;br /&gt;
	vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0)); //Lichtvektor in den Modelsprace rotieren&lt;br /&gt;
	vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex); //Vertex in den Modelspace projezieren&lt;br /&gt;
	vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y; //Schnittpunkt mit der XZ Referenzebene&lt;br /&gt;
	pos = pos / (abs(pos)+1.0); //Projektion der Ebene auf ein Quadrat&lt;br /&gt;
	pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
	gl_Position.xy = pos;&lt;br /&gt;
	gl_Position.z = -mvertex.y ; // Der Bereich von +-1 über der Referenzebene wird erfasst&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Lichtrichtung wird vorläufig noch fest übergeben. Eine Auswertung einer Opengl Lichtquelle oder einer Uniformvariable wäre ebenfalls möglich. Anschließend wird der Vertex in die Modelview projeziert und der Schnittpunkt des vom Vertexausgehendem Lichstrahls mit der Referenszebene berechnet. Als letztes wird noch der Abstand zur Referenzebenein einem Bereich 0..1  umgerechnet und die Texturkoordinaten für eventuelles Alphamasking oder Heightmapping durchgeschleift. Soll Alphamasking verwendet werden, muss ein entsprechender Shader geschrieben werden der bei den freizulassenden pixeln discard(); aufruft. Dies sollte jedoch nur für die betroffenen Poligone stat finden, da die Grafikkarte dann keine Early-Z Optimierungen verwenden kann. Ansonsten ist der Fragmentshader ist sehr einfach: shadow.frag:&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void){}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die für die Auswertung müssen wir im finalem Renderdurchgang exakt die gleichen Texturkoordinaten für die Shadowmap generieren. Allerdings gibt es eine Besonderheit: Die koordinaten einer Textur reichen von 0;0 bis 1;1, Die Koordinaten eines Rendertargets reichen jedoch von -1;-1 bis 1;1, so das eine zusätzliche korrektor nötig ist.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
        vec3 lightdir = gl_NormalMatrix * normalize(vec3(0.1,-1.0,0.0));&lt;br /&gt;
        vec3 mvertex =  vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
        vec2 pos = mvertex.xz + lightdir.xz * -mvertex.y/lightdir.y;&lt;br /&gt;
        pos = pos / (abs(pos)+1.0);&lt;br /&gt;
        pos = pos * vec2(1.0,1.8) + vec2(0.0,0.8); //Abschneiden des Bereiches hinter der Kammera&lt;br /&gt;
        pos = pos * 0.5 + 0.5; //auf Texturkoordinaten umrechnen&lt;br /&gt;
 &lt;br /&gt;
        spos.xy = pos; //Daten in einer Varying verpacken&lt;br /&gt;
        spos.z = -mvertex.y * 0.5 + 0.5 - 0.005; // far and near clamping and Anti-Z-fighting-offset &lt;br /&gt;
 	&lt;br /&gt;
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //Die echte Transformation&lt;br /&gt;
 &lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten 5 Zeilen der main() sollten exakt das gleiche tun wie der Vertexshader zum gnerieren dem Map.&lt;br /&gt;
&lt;br /&gt;
Nun fehlt noch ein Fragmentshader für den letzten Durchgang:&lt;br /&gt;
&lt;br /&gt;
Es muss noch der Noralvektor berücksichtigt werden!!!&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Shadowmap;&lt;br /&gt;
varying vec3 spos;&lt;br /&gt;
 &lt;br /&gt;
void main(void){&lt;br /&gt;
        if (texture2D(Shadowmap, spos.xy).r &amp;gt; spos.z ){&lt;br /&gt;
              //Licht&lt;br /&gt;
              gl_FragColor = vec4(1.0,1.0,1.0,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        else{&lt;br /&gt;
              //Schatten&lt;br /&gt;
              gl_FragColor = vec4(0.5,0.5,0.5,1.0);&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Parabolide Maps==&lt;br /&gt;
&lt;br /&gt;
Einfache parabolide Maps können für alle Punktlichquellen verwendet werden, deren Licht nicht in alle Richtungen abgestrahlt wird. Darunter fallen vorallem Spots und an Wänden oder Decken befestigte Lampen. Im gegensatz zur Paralelem Licht oder einer Punktlichquelle bringt eine solche Lichtquelle häufig eine Helligkeitsmap mit. Für die Helligkeitsmap und die Schattenmap können die gleichen Texturkoordinaten verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Bei kleinen Öffnungswinkeln hat die parabolide Map keinen Vorteil gegenüber einer normalen Projektion. Der Vortiel ist jedoch das der Code sich für Öffnungswinkel von bis zu ~240 Grad eignet. &lt;br /&gt;
&lt;br /&gt;
Um eine solche Lichquelle zu beschreiben weden nicht weniger als drei Vektoren benötigt:&lt;br /&gt;
&lt;br /&gt;
* Position&lt;br /&gt;
* Richtung &lt;br /&gt;
* Tangent&lt;br /&gt;
&lt;br /&gt;
Wärend die Funktion der ersten beiden Vektoren klar ist, wird der Tangent wird dazu benötigt die Schattenmap und Helligkeitsmap auszurichten. Er ist Senkrecht zur Richtung tangential zur Textur ausgerichtet &lt;br /&gt;
Beschreiben lässt sich diese Funktion lässte sich am ehesten durch das Verdrehen einer Taschenlampe. Wenn die Schattenmap gegenüber den schattenwerfenden Objekten verdreht wird, sieht das Bild auf keinen Fall mehr natürlich aus.&lt;br /&gt;
 &lt;br /&gt;
Es ist sowohl möglich die Berechnungen im Vertexshader durchzuführen, als auch eine entsprechnede Matrix in den Uniformvariablen abzulegen. Wenn die Berechnungen per Matrix durchgefühert werden lässt sich das Prinzip der paraboliden Maps zuindest als Reflektionsmap nutzen. Ein weiterer Vorteil an einer vorberechneten Matrix ist, dass diese auch für shadowmap verwendet werdne kann die nicht jedes Frame neu berechnet werden.&lt;br /&gt;
&lt;br /&gt;
==Dual Parabolide Maps==&lt;br /&gt;
Von OpenGL kennen wir zwei Projektionsmöglichkeiten: Orthografische und perspektivische Projektion. Beide Projektionen arbeiten ohne Verzerrung. Jede Gerade bleibt beim Transformieren eine Gerade. Wenn man dagegen das Bild eines Fischeyeobjektives betrachtet, allen einem sofort die zu Kurven verzerrten Geraden auf. Der entscheidene Vorteil an einer Fisheyeaufnahme ist, dass ein Öffnungswinkel von 180 Grad erfasst werden kann. Zwei entgegensetzte Aufnahmen können so problemlos den kompletten Raum um die Kamera erfassen.&lt;br /&gt;
&lt;br /&gt;
Für das Erstellen der Tiefenmap ist es notwendig den Raum um das reflektierende Objekt in eine Textur zu rendern. Meistens wird hier eine Cubemap verwendet. Soll diese dynamisch generiert werden, ist es auffällig, dass die Scene ganze 6 mal gerendert werden muss. Mit der dual paraboliden Map sind nur noch zwei Rendervorgänge nötig, es wird zwar keine Füllrate eingespart, dafür müssen nun nur noch 1/3 der Daten transformiert werden, so das die Vertexshader und die CPU entlastet werden.&lt;br /&gt;
&lt;br /&gt;
Eine weitere Optimierung ist unter Umständen möglich: Wenn bei einer Cubemap auf eine der Flächen verzichte werden kann. Z.B. wird die Reflektion im Lack eines Autos so gut wie nie verdeckte Straße zeigen. Auch ist für eine an einer  Wand befestigten Lampe nur eine halbkugelförmige Shadowmap nötig. Wenn sie einen Abstand zur Wand hat, genügt es auch hier den Blickwinkel von 180 Grad etwas zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Die Projektion der dualparaboliden Map kann man sich am besten Bild eines Fisheyobjektives vorstellen. Mathematisch etwas genauer ist das Reflektionsbild der umgebenden Welt in einem Rotationsparaboliden.&lt;br /&gt;
&lt;br /&gt;
Die Hardwareanforderungen an den Pixelshader sind nicht gerade gering. Der Pixelshader für die 8fachen Lichquellen kommt nach dem Compelieren auf über 170 Instruktions. Eine Shader 2.0 Karte wie z.B. die Radeon 9x00 sind hier hoffnungslos überfordert da sie nur an 3 Stellen im Programm auf die Textureinheiten zugreifen können und der Assembler nicht mehr in der Lage ist die Instruktions passend umzusortieren. Noch fataler wird es  wenn die Texturelookups durch dynamisches Branching übersprungen weder sollen: Die Karte hat keine Chance mehr diese umzusortieren.&lt;br /&gt;
&lt;br /&gt;
Wer dualparbolide Maps auf SM2.0 Karten einsetzten will sollte damit rechnen, dass das Limit bei 2 bis 4 Maps liegen sollte.&lt;br /&gt;
&lt;br /&gt;
===Hauptprogramm===&lt;br /&gt;
&lt;br /&gt;
So kann in der Hauptschleife das rendern der 16 paraboliden Maps und der anschließende Finale Renderdurchgang durchgeführt werden:&lt;br /&gt;
&amp;lt;cpp&amp;gt;//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for (int light;light&amp;lt;8;light++){&lt;br /&gt;
        glViewport (shadow_size/2*(lights/4),shadow_size/4 *(light%4),shadow_size/4,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;light&amp;quot;),light);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),0);&lt;br /&gt;
        render();&lt;br /&gt;
        glViewport (shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light%4),shadow_size/4 ,shadow_size/4);&lt;br /&gt;
        glUniform1iARB(glGetUniformLocationARB(parabol, &amp;quot;renderpass&amp;quot;),1);&lt;br /&gt;
        render();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Vieport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0,Windowsize_X,Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ungetesteter Pascalcode:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
//Shader für Dualparabolische Mpas aktivieren&lt;br /&gt;
glUseProgramObjectARB(parabol);&lt;br /&gt;
&lt;br /&gt;
//Framebufferobjekt aktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fb);&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
//Die 8 Lichtquellen Rendern&lt;br /&gt;
for light := 0 to 7 do&lt;br /&gt;
begin&lt;br /&gt;
  glViewport(shadow_size/2*(lights/4), shadow_size/4 *(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'light'), light);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'), 0);&lt;br /&gt;
  render();&lt;br /&gt;
  glViewport(shadow_size/4+shadow_size/2*(lights/4), shadow_size/4*(light mod 4), shadow_size/4, shadow_size/4);&lt;br /&gt;
  glUniform1iARB(glGetUniformLocationARB(parabol, 'renderpass'),1);&lt;br /&gt;
  render();&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
// Framebufferobjekt deaktivieren&lt;br /&gt;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);&lt;br /&gt;
&lt;br /&gt;
//Richtigen Shader aktivieren&lt;br /&gt;
glUseProgramObjectARB(final);&lt;br /&gt;
//Viewport an Fenstergröße anpassen&lt;br /&gt;
glViewport(0, 0, Windowsize_X, Windowsize_Y);&lt;br /&gt;
&lt;br /&gt;
//Frame rendern&lt;br /&gt;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
render();&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Die Shader===&lt;br /&gt;
&lt;br /&gt;
====Shader zum Rendern der Schattenmaps====&lt;br /&gt;
parabol.vert&lt;br /&gt;
&amp;lt;cpp&amp;gt;  uniform int renderpass;&lt;br /&gt;
  uniform int light;&lt;br /&gt;
  varying vec3 normal;&lt;br /&gt;
  varying vec3 pos;&lt;br /&gt;
&lt;br /&gt;
  void main(void){&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewMatrix * gl_Vertex - gl_LightSource[light].position ;&lt;br /&gt;
&lt;br /&gt;
	float L= length (gl_Position.xyz);&lt;br /&gt;
	gl_Position /= -L;&lt;br /&gt;
	if (renderpass == 1) gl_Position.z *=-1.0;&lt;br /&gt;
	gl_Position.z += 1.0;&lt;br /&gt;
	gl_Position.xy /= gl_Position.z;&lt;br /&gt;
	if (gl_Position.z &amp;gt;= 0.01){&lt;br /&gt;
		gl_Position.z = L / 15.0;//Todo: optimieren&lt;br /&gt;
		gl_Position.w = 1.0;&lt;br /&gt;
		}&lt;br /&gt;
	else{&lt;br /&gt;
		gl_Position.z = -1.0;&lt;br /&gt;
		gl_Position.w = -1.0;&lt;br /&gt;
		}&lt;br /&gt;
        &lt;br /&gt;
        gl_Position.z = 2.0 * gl_Position.z -1.0; //Todo: optimieren&lt;br /&gt;
	pos=gl_Position.xyz;&lt;br /&gt;
	}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
parabol.frag&lt;br /&gt;
&amp;lt;cpp&amp;gt;varying vec3 pos;&lt;br /&gt;
void main(void){&lt;br /&gt;
	if (length(pos.xy)&amp;gt;1.005)discard; //Diese Zeile kann durchaus entfallen. Kosten/Nutzen unbekannt.&lt;br /&gt;
	}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Uniformaviablen, die gesetzt werden müssen: Eine ist die Nummer der aktuellen Lichtquelle und die zweite der Renderpass, der angibt ob die Vorder- oder Rückseite der parabolischen Map gerendert werden soll. Eine automatische Berechnung der Texturkoordinaten wäre zwar möglich, jedoch ist die Änderung des Viewports deutlich weniger Rechenaufwendig.&lt;br /&gt;
&lt;br /&gt;
Statt einer Multiplikation des gl_Vertex mit der gl_ModelViewProjektionMatrix wird hier nur mit der gl_ModelViewMatrix multipliziert. Dadurch werden nur die Transformationen durchgeführt und die Projektion übersprungen.&lt;br /&gt;
Die Division durch -L entspricht weitgehend einer Normalsierung, spiegelt die Welt jedoch in die richtige Lage. L enthält jetzt die Tiefeninformation, gl_Position einen Vektor, der von der Kammera auf den Vertex zeigt. Mit den zwei folgenden Zeilen wird der Vektor parabolisch auf die Bildschirmkoordinaten projeziert (Intervall von -1.0 bis 1.0). Mit Hilfe der folgenden if-Abfrage werden alle Vertices hinter der Kammera geclipt. Nur sichtbare Vertices bekommen gültige z Werte für den Zbuffer im Intervall von -1.0 bis 1.0. &lt;br /&gt;
&lt;br /&gt;
Der Fragmentshader ist extrem einfach, da wir aufgrund des nicht vorhandem Colorbuffers keinen Farbwert benötigen lassen wir diesen wie bei den perspektivischen Maps einfach undefiniert.&lt;br /&gt;
Zudem verlassen wir den Shader mit discard, wenn der der Pixel außerhalb der aktuellen paraboliden Map liegt. Die Voteil ist, das nur der kreisförmige Bereich der Map verwendet wird, der Nachteil, das durchaus eine Early-Z optimierung nicht mehr möglich ist. Sehr Sinvoll sollte dies sein, wenn die Shadowmaps dynamisch nach benötigter Größe angeordnet werden. Da sich Kreise besser als Quadrate packen lassen.&lt;br /&gt;
&lt;br /&gt;
====Shader für den finalen Renderdurchgang====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
final.vert&lt;br /&gt;
&amp;lt;cpp&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	Normal = gl_NormalMatrix * gl_Normal;&lt;br /&gt;
 	ModelVertex  = vec3 (gl_ModelViewMatrix * gl_Vertex);&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
	gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
 	}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
final.frag&lt;br /&gt;
&amp;lt;cpp&amp;gt;varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
&lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
uniform int MaxLights;&lt;br /&gt;
&lt;br /&gt;
//Achtung folgende Zeile ist nicht GLSL konform. &lt;br /&gt;
//Workaround: Array als Uniform übergeben oder durch sehr aufwendige berechnung erstzten&lt;br /&gt;
//Sollte es auch auf ATI Karten funktinieren, frage ich mich warum es nicht erlaubt ist...&lt;br /&gt;
const vec2 texofset[8] = {vec2 (0.125,0.125), vec2 (0.125,0.375), vec2 (0.125,0.625), vec2 (0.125,0.875),&lt;br /&gt;
			  vec2 (0.625,0.125), vec2 (0.625,0.375), vec2 (0.625,0.625), vec2 (0.625,0.875)};&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
	vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
	for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
		vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
		vec3 lightdir = normalize( lightvec );&lt;br /&gt;
		vec2 parabol = texofset[LightNum];&lt;br /&gt;
		if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
			parabol.t += 0.25;&lt;br /&gt;
			}&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
		parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
		vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
		light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
		}&lt;br /&gt;
	vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));	//Textur auslesen; &lt;br /&gt;
	gl_FragColor = light * color ;&lt;br /&gt;
	}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Möglicher weise für ATI taugliche Variante:&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
varying vec3 Normal;&lt;br /&gt;
varying vec3 ModelVertex;&lt;br /&gt;
 &lt;br /&gt;
uniform sampler2D Texture0; // Eine normale Textur &lt;br /&gt;
uniform sampler2D Shadowmap;  //Damit ist auch die 4. TMU belegt..&lt;br /&gt;
const int MaxLights=8;&lt;br /&gt;
 &lt;br /&gt;
vec2 texofset[8]; &lt;br /&gt;
void main(void){&lt;br /&gt;
	texofset[0] = vec2 (0.125,0.125);&lt;br /&gt;
	texofset[1] = vec2 (0.125,0.375);&lt;br /&gt;
	texofset[2] = vec2 (0.125,0.625);&lt;br /&gt;
	texofset[3] = vec2 (0.125,0.875);&lt;br /&gt;
	texofset[4] = vec2 (0.625,0.125);&lt;br /&gt;
	texofset[5] = vec2 (0.625,0.375);&lt;br /&gt;
	texofset[6] = vec2 (0.625,0.625);&lt;br /&gt;
	texofset[7] = vec2 (0.625,0.875);&lt;br /&gt;
&lt;br /&gt;
        vec4 light=vec4 (0.2, 0.2, 0.2, 0.0); //Emmitiertes Licht&lt;br /&gt;
        vec3 normalvec =normalize(Normal.xyz);&lt;br /&gt;
        for (int LightNum = 0;LightNum &amp;lt; MaxLights; LightNum++){&lt;br /&gt;
                vec3 lightvec = ModelVertex - gl_LightSource[LightNum].position.xyz;&lt;br /&gt;
                vec3 lightdir = normalize( lightvec );&lt;br /&gt;
                vec2 parabol = texofset[LightNum];&lt;br /&gt;
                if (lightdir.z &amp;gt; 0.0){&lt;br /&gt;
                        parabol.t += 0.25;&lt;br /&gt;
                        }&lt;br /&gt;
                // parabolische Projektion für subtextur&lt;br /&gt;
                parabol -=  lightdir.xy * 0.125/ (abs (lightdir.z) + 1.0); &lt;br /&gt;
                float shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol).r );&lt;br /&gt;
                light += shadow * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&lt;br /&gt;
                }&lt;br /&gt;
        vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0])); //Textur auslesen; &lt;br /&gt;
        gl_FragColor = light * color ;&lt;br /&gt;
        }&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Shader besitzen 3 Uniformvariablen, die unbedingt mit den richtigen Werten gefüllt werden müssen. Zwei davon sind Texturen, die dritte die Anzahl der aktiven Lichtquellen. Es ist wichtig zu wissen, dass der Shader nicht den OpenGL-Status der Lichquellen berücksichtigt und nur die Daten der Ersten bis MaxLights holt.&lt;br /&gt;
Während bei den Schattenmaps die meiste Arbeit im Vertexshader erledigt werden könnte, ist dieser sehr Fragmentshader lastig. Die Texturkoordinatenberechnung ist sehr ähnlich zu der im shadow.vert. Die größte Änderung ist, dass hier abhängig von der Lichtquellennummer ein Offset aufaddiert wird um die Untertextur auszuwählen. Ein zusätzlicher Offset wird dazuaddiert, wenn auf die zweite parabolide Map einer Lichtquelle zugegriffen wird.&lt;br /&gt;
Um ein dynamisches Branching zu vermeiden, wird mit der Stepfunktion ermittelt ob sich das Fragment im Schatten befindet.&lt;br /&gt;
&lt;br /&gt;
==Optimierungen und Verbesserungen==&lt;br /&gt;
Hier sind noch einige Vorschläge, die helfen können um besser Qualität oder Leistungen im eigenem Programm zu bekommen. Eine uniververselle Lösung lässt sich nur auf kosten von Performance schreiben. Viel besser ist es, wenn man die Shader an die jeweilige Situation anpasst. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schatten durch Alphatest===&lt;br /&gt;
Der bisherige Schattenshader kann nur ganze Polygone einen Schatten werfen lassen. Wenn shadow.vert so ergänzt wird, das die Texturkoordinaten in den Fragmentshader  weitergereicht werden, dann ist es mit folgendem Fragmentshader möglich Shatten in Abhängikeit einer Alphatextur zu rendern:&lt;br /&gt;
&lt;br /&gt;
shadow.frag&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
        if (texture2D(Texture0,vec2(gl_TexCoord[0])).a &amp;lt; 0.5) discard;&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Der Shader wird verlassen wenn das Texel einen Alphawert von kleiner als 50% hat. Damit lassen sich Schatten von Pflanzen wesentlich realistischer darstellen. Dieser Shader sollte natürlich nur dann verwendet werden, wenn eine Alphakanal in der Textur vorhanden ist. Auch Shader mit Paralax- oder Displacementmapping arbeiten kann man so um einen Schatten ergänzen, wenn die Polygone transparente Teile enthalten.&lt;br /&gt;
Es ist auch möglich den shader zu verlassen, wenn eine bestimmte Farbe in der Textur gefunden wird, dann nimmt die Alphamaske keinen Speicherplatz mehr weg.&lt;br /&gt;
&lt;br /&gt;
===Farbiges Glas===&lt;br /&gt;
&lt;br /&gt;
Schatten hat jetzt ja sachon fast jeder. Aber wie wäre es mal mit einfärben von dynamischen Lichtquellen?&lt;br /&gt;
Der Algoritmus ist nicht schwer:&lt;br /&gt;
&lt;br /&gt;
* Alle Undurchichtigen Sceneteile in die Tiefenmaps gerendert. &lt;br /&gt;
* Zusätzlich wird eine Colormap gebunden und das Schreiben in den Zbuffer unterbunden.&lt;br /&gt;
* Die Colormap wird mit Weiß oder einer Helligkeitsmap initialisiert.&lt;br /&gt;
* Rendern aller transparenten Objekten&lt;br /&gt;
* Auf finales Rendern umschalten&lt;br /&gt;
* Alle undurchsichtigen Objekte mit hilfe der Schadowmap und der modifizierten Beleuchtungmap beleuchten.&lt;br /&gt;
* Alle Transparenten Objekte rendern, unter Berücksichtigung, dass die Lichtquelle bereits das gefilterte Licht aussendet. Dieses Blending sollte rückgängig gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Bei diesem Algoritmus bleibt noch das Alphablendingproblem mit der mehrfachen Überdeckung. Beim Modifizieren der Beleuchtungsmap gegebenfalls den Stencilbuffer zur Hilfe nehmen. Hier wäre ein denkbarer Algoritmus:&lt;br /&gt;
&lt;br /&gt;
* Alle transparenten Poligone in den Zbuffer rendern. Dabei für alle Poligone, deren  doppelte Filterung zu Fehlern führen kann mit verschiedenen Stencilwerte schreiben.&lt;br /&gt;
* Zbuffer und Colorbuffer Löschen. &lt;br /&gt;
* Helligkeitsmap in den Colorbuffer kopieren.&lt;br /&gt;
* Alle nicht transparanten Objekte in den Zbuffer Rendern. &lt;br /&gt;
* Alle transparenten Poligone mit den gleichen Stencilwerten wie im erstem Pass rendern. Die Bedingung ist, dass nur Polygone in den Zbuffer geschrieben werden, bei den Stencilwerte nicht mit den Stencilbuffer übereinstimmen. Die vordersten Polygone werden so aussortiert und nur die zweite Schicht landet im Zbuffer.&lt;br /&gt;
* Im letztem Rendervorgang müssen die gefilterten Lichtfarben der Transparenten Polygone in den Colorbuffer geschrieben werden. Die Bedingung ist das die Stencilwerte übereinstimmen müssen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn es wie ein großer Mehraufwand aussieht, ist der Anteil der transparenten Poligone doch eher gering. So das deren dreifacher Overdraw kaum eine Rolle spielt. Im Finalem Renderdurch gang gibt es bei den transparenten Polygonen noch eine Besonderheit: Stimmt die Entfernung aus der Shadowmap mit der Entfernung der Lichquellen (fast) überein, so wird das Poligon mit dem Licht aus der Colormap belauchtet. Ist die Entfernung aus der Shadowmap jedoch größer als die entfernung zu lichquellen, enthällt die Colormap die gefilterte Farbe des Lichtes hinter dem Poligon. Für die beleutung des Poligon muss also das Licht der Lichquelle benutzt werden. Sinvoll ist es die helligkeit für diesen Fall im Alphawert der Colormap zu Speichern.&lt;br /&gt;
&lt;br /&gt;
Ansonsten noch ein paar Vorschläge:&lt;br /&gt;
* Objekte die aus dem gleichem Glas sind und auch einfarbig. Sollten mit dem gleichem Stencilwert verarbeitet werden. So sieht z.B. das gefärbte Licht einer zweifach durchstrahlten leicht gefäbten Glasskuppel natürlicher aus als ein Vollschatten. Auch wenn das Licht korrekter weise zwei mal hätte gefiltert werden müssen. &lt;br /&gt;
* Eventuel macht es sind mehrfarbige Objekte in mehrfache einfarbige Objekte zu zerlegen.&lt;br /&gt;
* Komplexe Mehrfachfilterungen sollten vermieden werden oder so gewählt werden, das sie natürlich ausehen. Gute Filter wären komplementärfarben, da dort ein echter Schatten erzeugt wird. Schlechte Kombinationen wären unter anderem Rot+Gelb, Blau+Gelb, usw...&lt;br /&gt;
* Um von den Farbfehlern abzulenken, farbige Objekte in einer rotverschobenen Farbe flourezieren lassen. (Violet-&amp;gt; Blau -&amp;gt; Grün -&amp;gt; Gleb -&amp;gt; Organge -&amp;gt; Rot) Durch blau gefärbte Fenster, blau gefilterte Licht welches Dinge grün aufleuchten lässt nimmt einem jeder PC Modder ab...&lt;br /&gt;
&lt;br /&gt;
===Schattenmap durch eine Heightmap modifizieren===&lt;br /&gt;
Auch wennich hierzu noch kein Beispiel haben, ist es möglich gl_FragDepth mit hilfe einer Heightmap zu modifizieren. Prinzipiell entspricht dies einem einfachem Offsetmapping. Damit wäre durchaus eine Selbstschattierung von Bumpmaps möglich.&lt;br /&gt;
&lt;br /&gt;
===Zweite parabolische Map vermeiden===&lt;br /&gt;
Lichtquellen, die nur in eine Richtung Licht werfen können, wie z.B. Spotlichter oder Lichter, die in Bodenähe oder Wandnähe befestigt sind, benötigen keinen vollständig erfassten Tiefenraum. Die Parabolische Map kann problemlos herein oder herausskaliert werden, so das Öffnungswinkel von 0 bis ca 240 Grad möglich sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das verkleinern des Öffnungswinkels für zusätzliche Spotlichter ermöglicht auch kleinere Tiefenmaps, die in die 9 Zwischenräume der großen gepackt werden können. Die Zwischenräume können noch Maps mit einem Durchmesser von 40% der großen Maps aufnehmen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Texturelookups vermeiden===&lt;br /&gt;
Wenn das Skalarprodukt von normalvec und -lightdir negativ ist, dann ist die Oberfläche von der Lichtquelle abgewandt und Berechnungen für die Lichquelle können komplett übersprungen werden. Diverse Multiplikationen und vorallem Texturelookups können so übersprungen werden. Besondere aufwendige Algorithmen wie selbstschattierende Bumpmaps, können so deutlich Beschleunigt werden. &lt;br /&gt;
&lt;br /&gt;
Für die Beleuchtung sollte dann allerdings auch folgende Zeile verwendet werden. (Das Skalarprodukt von vor der if Abfrage aber umbedingt wiederverwerten!) &lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
  light += gl_LightSource[0].diffuse * max(dot(normalvec, -lightdir), 0.0);&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reichweite der Lichtquellen=== &lt;br /&gt;
Leider bietet OpenGL nicht direkt die Möglichkeit die maximale Reichweite einer Lichquelle anzugeben. In den Shadern wird zur Zeit der Wert 15.0 als maximale Entfernung zur Lichtquelle verwendet. Für ein einfaches Programm ist es sicher ausreichend, ansonsten macht es Sinn diesen Wert durch eine Unformvariable zu ersetzten, oder um mehr Flexibiltät zu bekommen durch ein Array aus 8 Uniformfloats.&lt;br /&gt;
&lt;br /&gt;
===Oversampling der Schattenmap===&lt;br /&gt;
Die Qualität lässt sich dadurch mehrere Samples auf der Schattenmap verbessern. Das folgende Codefragment nimmt 3 statt des einem Samples und glättet die Ränder des Schattens. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;const float pof =1.0 /4096.0 *0.7;&lt;br /&gt;
vec4 shadow = step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol +vec2(pof,0)).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,-pof/1.2) ).r );&lt;br /&gt;
shadow += step (length(lightvec)/15.0 -0.05, texture2D(Shadowmap, parabol+vec2(-pof/2.0,pof/1.2)).r );&lt;br /&gt;
light += shadow * 0.33 * gl_LightSource[LightNum].diffuse * abs(dot(normalvec, lightdir));&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Durch 9x Oversampling lässt sich schon eine sehr gute Qualität ereichen, sorgt aber bei 8 Lichtquellen durch die 72 Texturelookups für einen Zusammenbruch der Framerate.&lt;br /&gt;
Wichtig ist auch, dass man beachtet, dass die dualparaboliden Maps an Ihren Ränden undefiniert sind und so zu Artefakten kommen kann wenn man außerhalb des gültigem Bereichs sampled. Eine Möglichkeit wäre einen Bereich zu erfassen, der etwas größer als 180 Grad ist, um am Rand zusätzliche Texel zu schaffen.&lt;br /&gt;
&lt;br /&gt;
===Ein zusätzlicher Renderpass===&lt;br /&gt;
Nach dem die Tiefenmap gerendert würde, wäre es möglich in einem weiterem Framebufferobjekt eine zusätzliche Map zu rendern, in der mit Hilfe einer Kantenerkennung die Helligkeit der Softshadows vorberechnet wird. Auch hier muss berücksichtigt werden, dass die dualparaboliden Maps einen Übergang haben.&lt;br /&gt;
&lt;br /&gt;
===Dynamische Lichter in statische Lightmaps Rendern===&lt;br /&gt;
Wenn sich Lichtquellen nicht relativ zur Umgebung nicht bewegen, ist es möglich sie in eine Lightmap zu rendern. Unter der Annahme, dass Lightmapkoordinaten vorhanden sind (ohne geht es echt nicht gut), müssen diese nur per Vertexshader an den Pixelshader weitergegeben werden. Im Pixelshader kann dann wie im final.frag die Helligkeit berechnet werden und in der Lightmap abgespeichert werden.&lt;br /&gt;
Es ist immer noch möglich, das dynamische Objekte einen Schatten werfen: Es werden nur noch die beweglichen Objekte in die Tiefenmap gerendert. Im Schatten wird dann einfach das Licht der im Schatten liegenden Lichtquelle subtraiert.&lt;br /&gt;
&lt;br /&gt;
===Statische Anteile in den Schattenmaps===&lt;br /&gt;
Es ist möglich mit einer zusätzlichen Matrix die Tiefenmaps zu den Weltkoordinaten auszurichten. Statische Anteile können dann aus einer zweiten Tiefenmap kopiert werden. Ein wenig problematisch ist das Entfernen der Rotation aus der gl_ModelViewMatrix. Das größte Problem ist, das die Positionen der Lichquellen bereits mit der gl_ModelViewMatrix multipliziert sind. Die einfachste Lösung ist, aus den den Rotationswinkeln eine neue Matrix zu erechnen, mit dessen Hilfe die Schattenvektoren für die Texturkoordinatenberechnung zurückgedreht werden. Diese Matrix sollte dann als Uniformvariable übergeben werden.&lt;br /&gt;
Wenn die Schatten durch einen zusätzlichen Renderdurchgang gefiltert werden. Ist es sinvoll die Maps erst hier zu vereinen. Von beiden Tiefenmaps muss nur immer der kleinere Wert genommen werden.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19723</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=19723"/>
				<updated>2006-10-08T15:06:35Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19698</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=19698"/>
				<updated>2006-09-27T20:30:39Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; // ivec4 doesn't work. So I use vec4. Why does ivec4 not work?&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
varying vec4 color;&lt;br /&gt;
void main(void){&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[index[i] * 2];&lt;br /&gt;
		temp2 += weight[i] * bones[index[i] * 2 + 1];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat3 mat;&lt;br /&gt;
	mat[0] = temp1.xyz;&lt;br /&gt;
	mat[1] = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2] = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * vec4(mat * gl_Vertex.xyz + temp2.xyz,1.0);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	color = weight.xywz;  //for testing&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19693</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=19693"/>
				<updated>2006-09-27T11:30:12Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
#version 120&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; &lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                       0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                       0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                       0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[int(index[i]*2.0)];&lt;br /&gt;
		temp2 += weight[i] * bones[int(index[i]*2.0+1.0)];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat[0].xyz = temp1.xyz;&lt;br /&gt;
	mat[1].xyz = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	mat[3].xyz = temp2.xyz;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
&lt;br /&gt;
	//TBN Matrix Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19692</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=19692"/>
				<updated>2006-09-27T01:11:04Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
#version 120&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; &lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                       0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                       0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                       0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[int(index[i]*2.0)];&lt;br /&gt;
		temp2 += weight[i] * bones[int(index[i]*2.0+1.0)];&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat[0].xyz = temp1.xyz;&lt;br /&gt;
	mat[1].xyz = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	mat[3].xyz = temp2.xyz;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19691</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=19691"/>
				<updated>2006-09-27T01:01:42Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 48 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
#version 120&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index; &lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	vec4 temp1 = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	vec4 temp2 = 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;
		temp1 += weight[i] * bones[int(index[i]*2.0)];&lt;br /&gt;
		temp2 += weight[i] * bones[int(index[i]*2.0+1.0)];&lt;br /&gt;
		&lt;br /&gt;
		}&lt;br /&gt;
	//Matrix decompression&lt;br /&gt;
	mat[0].xyz = temp1.xyz;&lt;br /&gt;
	mat[1].xyz = vec3(-temp1.y, temp1.w, temp2.w);&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz);&lt;br /&gt;
	mat[3].xyz = temp2.xyz;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
&lt;br /&gt;
	//Untested TBN Code &lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal);&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent));&lt;br /&gt;
	B = cross (T,N);&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Da code für die TBN Matrix kann bei bedarf teilweise gelöscht werden. Nur mit Normal werden etwa 38 Instruktions benötig und komplet ohne werden nur noch 32 instruktions benötigt.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19690</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=19690"/>
				<updated>2006-09-27T00:53:35Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Kompression der Matrizen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden. Wichtig ist, das beachtet wird, das Opengl transponierte Matrizen verwendet.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||rot11&lt;br /&gt;
 |-&lt;br /&gt;
 |trans0 ||trans1 ||trans2 ||rot21&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 96 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
mat4 bone_matrix(int i){&lt;br /&gt;
	mat4 mat; //neue Matrix&lt;br /&gt;
	mat[0] = bones[i*2]; //erste komponete kopieren&lt;br /&gt;
	mat[1] = bones[i*2+1]; //zweite&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
	mat[3] = vec4 (0.0, 0.0, 0.0, 1.0); //dummy für 4x4 Matrix&lt;br /&gt;
	return mat;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
main(void){&lt;br /&gt;
	vec4 pos = 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;
		pos += weight[i] * bone_matrix(index[i]) * gl_Vertex;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein wenig Resourcensparender formuliert (ca 32 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = mat * gl_Vertex;&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boneanimationshader mit code zum Transformieren einer TBN Matrix (40 Instructions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute ivec4 index;&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal); //Normal&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent)); //Tangent&lt;br /&gt;
	B = cross (N,T); //Bitangent&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Besonders beachtet werden sollten die Klammern bei der Berechnung, da MatrixMatrixmultiplikationen erheblich mehr Instruktions erzeugen.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19689</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=19689"/>
				<updated>2006-09-25T11:57:54Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Woher kommen die Animationsdaten? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||trans2&lt;br /&gt;
 |-&lt;br /&gt;
 |0 ||0 ||0 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans2 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 96 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
mat4 bone_matrix(int i){&lt;br /&gt;
	mat4 mat; //neue Matrix&lt;br /&gt;
	mat[0] = bones[i*2]; //erste komponete kopieren&lt;br /&gt;
	mat[1] = bones[i*2+1]; //zweite&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
	mat[3] = vec4 (0.0, 0.0, 0.0, 1.0); //dummy für 4x4 Matrix&lt;br /&gt;
	return mat;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
main(void){&lt;br /&gt;
	vec4 pos = 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;
		pos += weight[i] * bone_matrix(index[i]) * gl_Vertex;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein wenig Resourcensparender formuliert (ca 32 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = mat * gl_Vertex;&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boneanimationshader mit code zum Transformieren einer TBN Matrix (40 Instructions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute ivec4 index;&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal); //Normal&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent)); //Tangent&lt;br /&gt;
	B = cross (N,T); //Bitangent&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Besonders beachtet werden sollten die Klammern bei der Berechnung, da MatrixMatrixmultiplikationen erheblich mehr Instruktions erzeugen.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19688</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=19688"/>
				<updated>2006-09-24T11:21:45Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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.&lt;br /&gt;
&lt;br /&gt;
===Limits===&lt;br /&gt;
&lt;br /&gt;
Aktuelle Grafikkarten erlauben 256 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||trans2&lt;br /&gt;
 |-&lt;br /&gt;
 |0 ||0 ||0 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans2 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 96 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
mat4 bone_matrix(int i){&lt;br /&gt;
	mat4 mat; //neue Matrix&lt;br /&gt;
	mat[0] = bones[i*2]; //erste komponete kopieren&lt;br /&gt;
	mat[1] = bones[i*2+1]; //zweite&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
	mat[3] = vec4 (0.0, 0.0, 0.0, 1.0); //dummy für 4x4 Matrix&lt;br /&gt;
	return mat;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
main(void){&lt;br /&gt;
	vec4 pos = 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;
		pos += weight[i] * bone_matrix(index[i]) * gl_Vertex;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein wenig Resourcensparender formuliert (ca 32 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = mat * gl_Vertex;&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boneanimationshader mit code zum Transformieren einer TBN Matrix (40 Instructions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute ivec4 index;&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal); //Normal&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent)); //Tangent&lt;br /&gt;
	B = cross (N,T); //Bitangent&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Besonders beachtet werden sollten die Klammern bei der Berechnung, da MatrixMatrixmultiplikationen erheblich mehr Instruktions erzeugen.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19681</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=19681"/>
				<updated>2006-09-22T12:03:14Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Kompression der Matrizen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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.&lt;br /&gt;
&lt;br /&gt;
===Limits===&lt;br /&gt;
&lt;br /&gt;
Aktuelle Grafikkarten erlauben 256 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es wäre möglich die Cosinuswerte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. &lt;br /&gt;
&lt;br /&gt;
Sinvoller ist es einen Vektor aus dem Rotationsteil mit Hilfe eines Kreutzproduktes neu zu berechnen. Da bei reinen Rotations/Skalierungsmatrizen Die SUmmer von rot01 und rot10 Null ergibt, kann einer von beiden den den dritten Wert des Translationsteil aufnehmen. &lt;br /&gt;
&lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der Aufwand für die Rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenleistung eingespart werden.&lt;br /&gt;
&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||trans2&lt;br /&gt;
 |-&lt;br /&gt;
 |0 ||0 ||0 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans2 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 96 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
mat4 bone_matrix(int i){&lt;br /&gt;
	mat4 mat; //neue Matrix&lt;br /&gt;
	mat[0] = bones[i*2]; //erste komponete kopieren&lt;br /&gt;
	mat[1] = bones[i*2+1]; //zweite&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
	mat[3] = vec4 (0.0, 0.0, 0.0, 1.0); //dummy für 4x4 Matrix&lt;br /&gt;
	return mat;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
main(void){&lt;br /&gt;
	vec4 pos = 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;
		pos += weight[i] * bone_matrix(index[i]) * gl_Vertex;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein wenig Resourcensparender formuliert (ca 32 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = mat * gl_Vertex;&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boneanimationshader mit code zum Transformieren einer TBN Matrix (40 Instructions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute ivec4 index;&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal); //Normal&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent)); //Tangent&lt;br /&gt;
	B = cross (T,N); //Bitangent&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Besonders beachtet werden sollten die Klammern bei der Berechnung, da MatrixMatrixmultiplikationen erheblich mehr Instruktions erzeugen.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19680</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=19680"/>
				<updated>2006-09-21T22:30:19Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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.&lt;br /&gt;
&lt;br /&gt;
===Limits===&lt;br /&gt;
&lt;br /&gt;
Aktuelle Grafikkarten erlauben 256 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es ist möglich die Cosinus werte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. Wenn jedoch nur ein Cosinuswert weggelassen wird, kann das Vorzeichen aus den Vorzeichen der beiden anderen Cosinuswerte rekonstruiert werden, weil das Produkt aller Cosinuswerte einer Rotationsmatrix immer Positiv ist.&lt;br /&gt;
Der Gewinn ist, das nur noch 2 float4 Vektoren gemittelt werden müssen, jedoch kommt für die Rekonstruktion des driiten Cosinuswertes eine Wurzel und 3-4 Multiplikationen dazu.&lt;br /&gt;
&lt;br /&gt;
Noch einfacher lassen sich 3 Komponenten des Rotationsteil der Matrix rekonstruieren, wenn sie durch das Kreutzprodukt neu Berechnen lassen. Da immernoch ein Wert redundant in der Matrix gespeichert ist, kann er den Z Wert des Translationsteil aufnehmen. &lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der aufwand für die rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenbleistung eingespart werden.&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||trans2&lt;br /&gt;
 |-&lt;br /&gt;
 |0 ||0 ||0 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans2 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 96 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
mat4 bone_matrix(int i){&lt;br /&gt;
	mat4 mat; //neue Matrix&lt;br /&gt;
	mat[0] = bones[i*2]; //erste komponete kopieren&lt;br /&gt;
	mat[1] = bones[i*2+1]; //zweite&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
	mat[3] = vec4 (0.0, 0.0, 0.0, 1.0); //dummy für 4x4 Matrix&lt;br /&gt;
	return mat;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
main(void){&lt;br /&gt;
	vec4 pos = 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;
		pos += weight[i] * bone_matrix(index[i]) * gl_Vertex;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein wenig Resourcensparender formuliert (ca 32 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute ivec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = mat * gl_Vertex;&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boneanimationshader mit code zum Transformieren einer TBN Matrix (40 Instructions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute ivec4 index;&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal); //Normal&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent)); //Tangent&lt;br /&gt;
	B = cross (T,N); //Bitangent&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Besonders beachtet werden sollten die Klammern bei der Berechnung, da MatrixMatrixmultiplikationen erheblich mehr Instruktions erzeugen.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Boneanimation_per_Vertexshader&amp;diff=19679</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=19679"/>
				<updated>2006-09-21T22:25:49Z</updated>
		
		<summary type="html">&lt;p&gt;Oc2k1: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel richted sich an alle, die schon weit Fortgeschritten sind. Ein sicherer Umgang mit Shadern und Vertexbufferobjekten ist hier Vorrausetzung. Bei der Boneanimation per Vertexshader geht es darum, möglichst viel Arbeit auf die Grafikkarte auszulagern.&lt;br /&gt;
Wer schon immer mal einen hochdetailierten Dinosaurier oder Octobus sein Unwesen treiben lassen will 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 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 die durch ein festes Gelenk verbunden sind sollten umbedingt vermiedern 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.&lt;br /&gt;
&lt;br /&gt;
===Limits===&lt;br /&gt;
&lt;br /&gt;
Aktuelle Grafikkarten erlauben 256 Uniformvariablend des Typs Float4. Für einen Bone werden 3 Float4 benötigt. Damit lassen sich etwa 80 Bones gleichzeitig verwenden. Wird dies schon beim Entwurf des Modells beachtet, stellt diese Wert kaum ein Limit dar. Bei einem symetrischem Modell lässt sich dieser Wert fast verdoppeln. Wenn die nicht ausreicht macht es Sinn Objekte mit vielen Bones wie Hände oder Gesichter getrennt zu Rendern.&lt;br /&gt;
Vorausgesetzt werden sollte eine Grafikkarte, die wenigstends das Shadermodel 2.0 unterstützt. Besser ist jedoch eine Grafikkarte, die Shadermodel3.0 unterstützt, damit der Code durch dynamisches Branching teilweise übersprungen werden kann.&lt;br /&gt;
&lt;br /&gt;
==Technik==&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 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. Sollten die Atributevariablen knapp werden ist es sinvoll die Gewichtung mit 0.999 zu Multiplizieren und die Indexnummer dazuzuaddieren. Solang dies nicht nötig ist koste es jedoch nur unötig Performance beim trennen.&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 lohnt sich der Aufwand die Gelenkposition zu speichern und den Abstand nach der Interpolation zu korrigieren.&lt;br /&gt;
&lt;br /&gt;
===Gewichten der Bones===&lt;br /&gt;
&lt;br /&gt;
Gerade im Vertexshader muss man genau überlegen, wo man Multiplikationen oder höhere Operationen einsparen kann prinzipell gibt es zwei Möglichkeiten. Die erste ist, dass die Matrizen anhand Ihrer Gewichtungen zu einer durchschnittlichen Matrix zusammenzurechnet werden. Pro Matrix werden 12 Multiplikationen und 12 Additionen benötigt, von denen je 3 aus Symetriegründen Wegrationalisiert werden können.&lt;br /&gt;
Bei der zweiten Variante werden erst die Vektoren mit den Matrizen multipliziert und anschließend gewichtet. Jedoch werden dann pro Matrix * Vektor Multiplikation 12 Multiplikationen gebraucht. Da aber neben dem Vertex auch noch der Normal und gegebenfals Tangentvektoren Multipliziert werden müssen, ist der Aufwand der ersten Variante deutlich geringer.&lt;br /&gt;
&lt;br /&gt;
===Quaternionen im Vertexshader===&lt;br /&gt;
&lt;br /&gt;
Der Sinn von Quaternionen im Vertexshader ist sehr fraglich. Sie wären möglich, jedoch langsamer, lediglicht die Multiplikation von Quaternionen mit einem zweitem Quartenion ist deulich schneller als eine Matrix * Matrixmultiplikation. Gerade diese Operationen werden sollten jedoch vor dem Vertexshader durchgeführt werden, da sie die Form des ganzen Skelletes beeinflussen und sich über das Frame nicht ändern. Da mit bleibt nur noch ein einziger Vorteil: Es werden nur noch 2 Flot4 Vektoren zum Speichern eines Bones benötigt. Der Preis sind allerdings 27 Multiplikationen und 18 Additionen für die Umwandlung.&lt;br /&gt;
&lt;br /&gt;
===Kompression der Matrizen===&lt;br /&gt;
&lt;br /&gt;
Eine vollständige Transformationsmatrix benötigt 16 Komponenten. 4 können direkt entfallen, da uns die W Komponente der Vektoren nicht interresiert. Der Rotationsteil der Matrix ist jedoch immernoch sehr redundant. Die 3 Sinuskomponenten sind mit umgekehrtem Vorzeichen doppelt verhanden. Es bleiben noch 9 Komponenten über, die sich dummerweise nicht auf zwei float4 Vektoren aufteilen lassen. Es ist möglich die Cosinus werte mit Hilfe des Pytagoras neu zu berechnen, allerdings geht hierbei das Vorzeichen verloren, so dass keine Rotationen von mehr als 90 Grad mehr möglich wären. Wenn jedoch nur ein Cosinuswert weggelassen wird, kann das Vorzeichen aus den Vorzeichen der beiden anderen Cosinuswerte rekonstruiert werden, weil das Produkt aller Cosinuswerte einer Rotationsmatrix immer Positiv ist.&lt;br /&gt;
Der Gewinn ist, das nur noch 2 float4 Vektoren gemittelt werden müssen, jedoch kommt für die Rekonstruktion des driiten Cosinuswertes eine Wurzel und 3-4 Multiplikationen dazu.&lt;br /&gt;
&lt;br /&gt;
Noch einfacher lassen sich 3 Komponenten des Rotationsteil der Matrix rekonstruieren, wenn sie durch das Kreutzprodukt neu Berechnen lassen. Da immernoch ein Wert redundant in der Matrix gespeichert ist, kann er den Z Wert des Translationsteil aufnehmen. &lt;br /&gt;
Da nun nur noch 8 Werte gemittel werden müssen und der aufwand für die rekonstruktion sehr einfach ist, kann hier sowohl Platz in den Uniforvariablen als auch Rechenbleistung eingespart werden.&lt;br /&gt;
{| align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |Normale Transformationsmatrix:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |rot01 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |-&lt;br /&gt;
 |rot02 ||rot12 ||rot22 ||trans2&lt;br /&gt;
 |-&lt;br /&gt;
 |0 ||0 ||0 ||1&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
 | Gepackte Transformationsmatrix:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |rot00 ||rot10 ||rot20 ||trans0&lt;br /&gt;
 |-&lt;br /&gt;
 |trans2 ||rot11 ||rot21 ||trans1&lt;br /&gt;
 |}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
Einfacher Vertexshader für Bones (ca 96 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute vec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
mat4 bone_matrix(int i){&lt;br /&gt;
	mat4 mat; //neue Matrix&lt;br /&gt;
	mat[0] = bones[i*2]; //erste komponete kopieren&lt;br /&gt;
	mat[1] = bones[i*2+1]; //zweite&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
	mat[3] = vec4 (0.0, 0.0, 0.0, 1.0); //dummy für 4x4 Matrix&lt;br /&gt;
	return mat;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
main(void){&lt;br /&gt;
	vec4 pos = 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;
		pos += weight[i] * bone_matrix(index[i]) * gl_Vertex;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein wenig Resourcensparender formuliert (ca 32 Instruktions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight; //Die gewichtung aller Bones Summe = 1&lt;br /&gt;
attribute vec4 index; //enthält die Bonummer mit 2 Multipliziert&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = mat * gl_Vertex;&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Boneanimationshader mit code zum Transformieren einer TBN Matrix (40 Instructions):&lt;br /&gt;
&amp;lt;cpp&amp;gt;&lt;br /&gt;
attribute vec4 weight;&lt;br /&gt;
attribute vec4 index;&lt;br /&gt;
attribute vec3 tangent;&lt;br /&gt;
&lt;br /&gt;
uniform vec4 bones[2*32];&lt;br /&gt;
&lt;br /&gt;
varying vec3 T,B,N;&lt;br /&gt;
&lt;br /&gt;
void main(void){&lt;br /&gt;
	mat4 mat= mat4(0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                 0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
	for (int i = 0; i&amp;lt;4; i++){&lt;br /&gt;
		mat[0] += weight[i] * bones[index[i]];&lt;br /&gt;
		mat[1] += weight[i] * bones[index[i]+1];&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	mat[2][3] = mat[1][0]; //Translations teil der 3 Spalte aus der 2. hohlen&lt;br /&gt;
	mat[1][0] = -mat[0][1]; // Translationswert durch gespiegelten Kosinuswert ersetzten&lt;br /&gt;
	mat[2].xyz = cross (mat[0].xyz,mat[1].xyz); //Wenn es nicht stimmt komponenten tauschen&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * (mat * gl_Vertex);&lt;br /&gt;
	N = gl_NormalMatrix * (mat3(mat) * gl_Normal); //Normal&lt;br /&gt;
	T = gl_NormalMatrix * (mat3(mat) * vec3(tangent)); //Tangent&lt;br /&gt;
	B = cross (T,N); //Bitangent&lt;br /&gt;
&lt;br /&gt;
        gl_TexCoord[0] = gl_MultiTexCoord0;&lt;br /&gt;
        gl_TexCoord[1] = gl_MultiTexCoord1;&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Besonders beachtet werden sollten die Klammern bei der Berechnung, da MatrixMatrixmultiplikationen erheblich mehr Instruktions erzeugen.&lt;/div&gt;</summary>
		<author><name>Oc2k1</name></author>	</entry>

	</feed>