Zum Inhalt springen

„High Level Shading Language“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
K Vertex/Pixel Shader Methode: Kleiner Grammatik-Fix
K Alternativen: Literatur ergänzt
 
(5 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
'''High Level Shading Language''' (HLSL) bezeichnet die für [[DirectX]] entwickelte [[Programmiersprache]], die für die Programmierung von [[Shader]]-Bausteinen eingesetzt wird. Gelegentlich wird auch die Gruppe der [[Höhere Programmiersprache|höheren Programmiersprachen]] für Shader mit HLSL bezeichnet.
'''High Level Shading Language''' (HLSL) ist eine für [[DirectX]] entwickelte [[Programmiersprache]], die für die Programmierung von [[Shader]]-Bausteinen eingesetzt wird. Gelegentlich wird auch die gesamte Gruppe der [[Höhere Programmiersprache|höheren Programmiersprachen]] für Shader als HLSL bezeichnet.


== Aufgabe ==
== Aufgabe ==
Unter „[[Shading]]“ versteht die Computergrafik die Veränderung einzelner Vertices bzw. Fragmente innerhalb der [[Grafikpipeline]]. Dabei wird möglichst hardwarenah gearbeitet, was lange die Verwendung von [[Assembler (Informatik)|Assembler]] nötig machte. Die Programmierung mit Assembler ist jedoch recht unpraktisch, fehleranfällig und vom Hardwarehersteller abhängig. Diesen Umstand sollen ''High Level Shading Languages'' beheben. Sie stellen hochsprachliche Strukturen zur Verfügung, die die Programmierung vereinfachen und damit dem Programmierer ermöglichen, sich auf sein Ziel zu konzentrieren. Ein [[Compiler]] übersetzt den Code der Hochsprache in Maschinensprache für den Grafikprozessor. Die DirectX-spezifische Hochsprache HLSL wird zur Laufzeit der Applikation von der DirectX-Bibliothek mit Hilfe des Grafiktreibers in die für die aktuelle Grafikhardware geeignete Assemblersprache übersetzt. Unterschiedliche Shader für Nvidia- oder ATI/AMD-Grafikkarten sind damit nicht mehr notwendig.
Unter [[Shading]] wird in der Computergrafik die Veränderung einzelner Vertices bzw. Fragmente innerhalb der [[Grafikpipeline]] bezeichnet.
Dabei wird bevorzugt direkt auf der Hardware gearbeitet, was lange die Verwendung von [[Assembler (Informatik)|Assembler]] nötig machte. Die Programmierung mit Assembler ist jedoch recht unpraktisch, fehleranfällig und vom Hardwarehersteller abhängig. Diesen Umstand sollen ''High Level Shading Languages'' beheben. Sie stellen hochsprachliche Strukturen zur Verfügung, die die Programmierung vereinfachen und damit dem Programmierer ermöglichen, sich auf sein Ziel zu konzentrieren. Ein [[Compiler]] übersetzt den Code der Hochsprache in Maschinensprache für den Grafikprozessor. Die DirectX-spezifische Hochsprache HLSL wird zur Laufzeit der Applikation von der DirectX-Bibliothek mit Hilfe des Grafiktreibers in die für die aktuelle Grafikhardware geeignete Assemblersprache übersetzt. Unterschiedliche Shader für Nvidia- oder ATI/AMD-Grafikkarten sind damit nicht mehr notwendig.


== Sprach-Elemente ==
== Sprach-Elemente ==
HLSL bietet keine OOP-Ansätze wie andere Sprachen. Es ist stark an C orientiert, stellt aber für die Shader-Programmierung optimierte Datentypen und Operationen zur Verfügung.

HLSL bietet keine OOP Ansätze wie andere Sprachen, ist stark an C orientiert, aber mit auf die Shader-Programmierung optimierten eingebauten Datentypen und Operationen.


=== Globale Shader-Parameter ===
=== Globale Shader-Parameter ===
Parameter, die an einen Shader übergeben werden, stehen in HLSL global im kompletten Code zur Verfügung. Sie werden außerhalb von Methoden oder Structs geschrieben, meist zu Beginn des Codes.

Parameter, die an einen Shader übergeben werden, stehen in HLSL global im kompletten Code zur Verfügung und werden außerhalb von Methoden oder Structs geschrieben, meist zu Beginn des Codes.


<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
float4x4 world; // Definiert eine 4x4 - Fließkomma-Matrix, hier die Welt-Matrix
float4x4 world; // Definiert eine 4x4-Fließkomma-Matrix, hier die Welt-Matrix
float4x4 worldViewProj; // Die Welt-View-Projektionsmatrix, gerechnet als World*View*Proj.
float4x4 worldViewProj; // Die Welt-View-Projektionsmatrix, gerechnet als World*View*Proj.
float3 lightDir; // Ein 3-Element Vektor.
float3 lightDir; // Ein 3-Element Vektor.
float4 LightColor = {0.5,0.5,0.5,1}; // Lichtfarbe (Vektor mit vordefiniertem Wert)
float4 LightColor = {0.5, 0.5, 0.5, 1}; // Lichtfarbe (Vektor mit vordefiniertem Wert)
float4 Ambient = {0.5,0.5,0.5,1}; // Lichtfarbe des Umgebungslichtes
float4 Ambient = {0.5, 0.5, 0.5, 1}; // Lichtfarbe des Umgebungslichtes
float4 LightDir={0,0,-1, 0}; // Richtung des Sonnenlichtes (hier: Senkrecht von oben)
float4 LightDir = {0, 0, -1, 0}; // Richtung des Sonnenlichtes (hier: Senkrecht von oben)


texture2D Tex0; // Eine Textur
texture2D Tex0; // Eine Textur


SamplerState DefaultSampler // Der "Sampler" definiert die Parameter für das Texture-Mapping
SamplerState DefaultSampler // Der "Sampler" definiert die Parameter für das Texture-Mapping
{
{
filter=MIN_MAG_MIP_LINEAR; // Interpolationsfilter für Texturstreckung
filter = MIN_MAG_MIP_LINEAR; // Interpolationsfilter für Texturstreckung
AddressU = Clamp; // Texturkoordinaten ausserhalb [0..1] beschneiden
AddressU = Clamp; // Texturkoordinaten ausserhalb [0..1] beschneiden
AddressV = Clamp;
AddressV = Clamp;
};
};
</syntaxhighlight>
</syntaxhighlight>
Für die Bedeutung der obigen Matrizen siehe den Artikel [[Grafikpipeline]].
Für die Bedeutung der obigen Matrizen siehe den Artikel [[Grafikpipeline]].

=== Eingabe und Ausgabe des Vertex-Shaders ===
=== Eingabe und Ausgabe des Vertex-Shaders ===
Statt jeden Parameter einzeln in die Parameterliste einer Shader-Methode zu schreiben, sind in der Praxis einheitliche Structs üblich. Dies spart Schreibarbeit und schafft mehr Übersichtlichkeit. Im Prinzip können beliebige Werte und Vektoren mit der Eingabestruktur übergeben werden, eine Position ist aber fast immer dabei.


<syntaxhighlight lang="hlsl">
Man kann natürlich jeden Parameter einzeln in die Parameterliste einer Shader-Methode schreiben, in der Praxis sind jedoch einheitliche Structs üblich, um Schreibarbeit zu sparen und für mehr Übersichtlichkeit zu sorgen. Im Prinzip können beliebige Werte und Vektoren mit der Eingabestruktur übergeben werden, eine Position ist aber fast immer dabei.
// Eingabe für den Vertex-Shader.

<syntaxhighlight lang="c">
// Eingabe für den Vertex-Shader.
struct MyShaderIn
struct MyShaderIn
{
{
float4 Position : POSITION; // Dem Compiler wird bekannt gegeben, was die Variable "bedeutet". Hier: Das ist eine Position
float4 Position : POSITION; // Dem Compiler wird bekannt gegeben, was die Variable "bedeutet". Hier: Das ist eine Position
float4 Normal: NORMAL0; // Die Vertex-Normale, wird für die Beleuchtung verwendet
float4 Normal : NORMAL0; // Die Vertex-Normale, wird für die Beleuchtung verwendet
float2 TexCoords: TEXCOORD0; // Texturkoordinaten
float2 TexCoords : TEXCOORD0; // Texturkoordinaten
}
}


Zeile 47: Zeile 44:
{
{
float4 Position : POSITION;
float4 Position : POSITION;
float4 TexCoords TEXCOORD0;
float4 TexCoords : TEXCOORD0;
float4 Normal : TEXCOORD1;
float4 Normal : TEXCOORD1;
}
}
</syntaxhighlight>
</syntaxhighlight>
Der "In-Struct" gibt die Datenstruktur an, wie sie vom Drahtgittermodell in den Shader gereicht wird, also an den VertexShader. Dieser verarbeitet die Daten und gibt einen "Out-Struct" als Rückgabetyp zurück. Dieser wird dann an den PixelShader weitergereicht, der am Ende nur noch einen float4 oder ähnliches zurückgibt, mit der endgültigen Pixelfarbe.
Der „In-Struct“ gibt die Datenstruktur an, wie sie vom Drahtgittermodell an den Shader gereicht wird, also an den VertexShader. Dieser verarbeitet die Daten und gibt einen „Out-Struct“ als Rückgabetyp zurück. Dieser wird dann an den PixelShader weitergereicht, der am Ende nur noch einen float4 oder ähnliches zurückgibt, mit der endgültigen Pixelfarbe.


=== Vertex/Pixel Shader Methode ===
=== Vertex/Pixel Shader Methode ===


Für [[Vertex-Shader]] und [[Pixel-Shader]] muss eine Methode vorhanden sein. Diese nimmt eine Datenstruktur auf und verarbeitet sie entsprechend. Der Vertex-Shader wird einmal für jeden Vertex aufgerufen, der Pixel-Shader einmal pro zu renderndem Texturpixel.
Für [[Vertex-Shader]] und [[Pixel-Shader]] muss eine Methode vorhanden sein. Diese nimmt eine Datenstruktur auf und verarbeitet sie entsprechend. Der Vertex-Shader wird einmal für jeden Vertex aufgerufen, der Pixel-Shader einmal pro zu renderndem Texturpixel.
<syntaxhighlight lang="c">
<syntaxhighlight lang="hlsl">
MyShaderOut MyVertexShader(MyShaderIn In)
MyShaderOut MyVertexShader(MyShaderIn In)
{
{
Zeile 74: Zeile 72:
return dot(-lightDir, normal);
return dot(-lightDir, normal);
}
}



// Der Pixel-Shader gibt als Rückgabewert lediglich eine Farbe (ggf. mit Alpha) zurück
// Der Pixel-Shader gibt als Rückgabewert lediglich eine Farbe (ggf. mit Alpha) zurück
Zeile 81: Zeile 78:
// Beleuchtungsstärke der Fläche (Das Skalarprodukt aus negativem Lichtvektor und
// Beleuchtungsstärke der Fläche (Das Skalarprodukt aus negativem Lichtvektor und
// Normalvektor der Fläche ist > 0 wenn die Fläche der Lichtquelle zugewandt ist)
// Normalvektor der Fläche ist > 0 wenn die Fläche der Lichtquelle zugewandt ist)
float sunLight=dot((float3)-LightDir, In.Normal);
float sunLight = dot((float3)-LightDir, In.Normal);
float4 sunLightColor=float4(sunLight,sunLight,sunLight,1); // Den Alphakanal setzen
float4 sunLightColor = float4(sunLight, sunLight, sunLight, 1); // Den Alphakanal setzen
sunLightColor *= LightColor; // Die Lichtfarbe anbringen
sunLightColor *= LightColor; // Die Lichtfarbe anbringen
sunLightColor = saturate(sunLightColor); // Die Farbwerte auf [0..1] beschneiden
sunLightColor = saturate(sunLightColor); // Die Farbwerte auf [0..1] beschneiden
Zeile 89: Zeile 86:
float4 baseColor = Tex0.Sample(DefaultSampler, In.TexCoords);
float4 baseColor = Tex0.Sample(DefaultSampler, In.TexCoords);
float4 brightnessColor = baseColor*(sunLightColor + Ambient); // Helligkeit und Kontrast einrechnen
float4 brightnessColor = baseColor*(sunLightColor + Ambient); // Helligkeit und Kontrast einrechnen
brightnessColor=(brightnessColor + OffsetBrightness) * (1.0 + OffsetContrast);
brightnessColor = (brightnessColor + OffsetBrightness) * (1.0 + OffsetContrast);
return brightnessColor;
return brightnessColor;
}
}
</syntaxhighlight>
</syntaxhighlight>


=== Geometrie Shader ===
=== Geometrie-Shader ===
Die Implementierung eines [[Geometry-Shader]]s ist optional und ermöglicht es, ein Primitiv auf 0 bis n neue Primitive abzubilden. Die Art der Ausgabe-Primitive sowie die Maximalanzahl der produzierten Vertices muss allerdings zur [[Übersetzungszeit]] bekanntgegeben werden. Die Implementierung erfolgt hier prozedural und verwendet eigens dafür eingeführte Datenstrukturen (PointStream<T>, LineStream<T> und TriangleStream<T>).


Weiter besteht die Möglichkeit, auch auf die benachbarten Dreiecke und Linien zuzugreifen. Dies kann mit Hilfe der Input-Modifier ''trianglead'' und ''lineadj'' erreicht werden. Typische Anwendungen für Geometry-Shader sind die Generierung von Point-Sprites und das Rendern in CubeMap-Texturen. Hier ein einfacher Geometry-Shader, der jedes Dreieck, auf das er angewandt wird, zu seinen Schwerpunkt hin verkleinert:
Die Implementierung eines [[Geometry-Shader]] ist optional und ermöglicht es ein Primitiv auf 0 bis n neue Primitive abzubilden.
Die Art der Ausgabe-Primitive sowie die Maximalanzahl der produzierten Vertices muss allerdings zur [[Übersetzungszeit]] bekanntgegeben werden.
Die Implementierung erfolgt hier prozedural und verwendet eigens dafür eingeführte Datenstrukturen (PointStream<T>, LineStream<T> und TriangleStream<T>).
Weiters besteht die Möglichkeit auch auf die benachbarten Dreiecke bzw. Linien zuzugreifen. Dies kann mit Hilfe der Input-Modifier (triangleadj und lineadj) erreicht werden.
Typische Anwendungen für Geometry-Shader sind die Generierung von Point-Sprites und das Rendern in CubeMap-Texturen.
Hier ein einfacher Geometry-Shader, der jedes Dreieck auf das er angewandt wird zu seinen Schwerpunkt hin verkleinert:


<syntaxhighlight lang="c">
<syntaxhighlight lang="hlsl">
[maxvertexcount(3)]
[maxvertexcount(3)]
void GS(triangle MyShaderOut[3] input, inout TriangleStream<MyShaderOut> OutputStream)
void GS(triangle MyShaderOut[3] input, inout TriangleStream<MyShaderOut> OutputStream)
Zeile 124: Zeile 117:
}
}
</syntaxhighlight>
</syntaxhighlight>

=== Techniken ===
=== Techniken ===
Zuletzt müssen die definierten Methoden in Form von Techniken und Durchläufen zugeordnet werden, damit sie vom Compiler entsprechend umgesetzt werden. Die Syntax der Shader hat sich mit DirectX 10 geringfügig geändert, daher wird die Zielversion auch bei der Technik nochmal explizit angegeben.


<syntaxhighlight lang="hlsl">
Zuletzt müssen die definierten Methoden in Form von Techniken und Durchläufen zugeordnet werden, damit sie vom Compiler entsprechend umgesetzt werden. Die Syntax der Shader hat sich mit DirectX 10 geringfügig geändert, daher wird die Zielversion auch bei der Technik nochmal explizit angegeben.
<syntaxhighlight lang="c">
technique10 MyTechnique // Für DirectX 10+
technique10 MyTechnique // Für DirectX 10+
{
{
Zeile 143: Zeile 137:
* [[OpenGL Shading Language]]
* [[OpenGL Shading Language]]
* [[OpenGL ES Shading Language]]
* [[OpenGL ES Shading Language]]

== Literatur ==

* Doron Feinstein: ''HLSL Development Cookbook''. Birmingham: Packt Publishing 2013. ISBN 978-184969420-9


[[Kategorie:Geometrische Modellierung]]
[[Kategorie:Geometrische Modellierung]]

Aktuelle Version vom 28. Juni 2023, 09:55 Uhr

High Level Shading Language (HLSL) ist eine für DirectX entwickelte Programmiersprache, die für die Programmierung von Shader-Bausteinen eingesetzt wird. Gelegentlich wird auch die gesamte Gruppe der höheren Programmiersprachen für Shader als HLSL bezeichnet.

Unter „Shading“ versteht die Computergrafik die Veränderung einzelner Vertices bzw. Fragmente innerhalb der Grafikpipeline. Dabei wird möglichst hardwarenah gearbeitet, was lange die Verwendung von Assembler nötig machte. Die Programmierung mit Assembler ist jedoch recht unpraktisch, fehleranfällig und vom Hardwarehersteller abhängig. Diesen Umstand sollen High Level Shading Languages beheben. Sie stellen hochsprachliche Strukturen zur Verfügung, die die Programmierung vereinfachen und damit dem Programmierer ermöglichen, sich auf sein Ziel zu konzentrieren. Ein Compiler übersetzt den Code der Hochsprache in Maschinensprache für den Grafikprozessor. Die DirectX-spezifische Hochsprache HLSL wird zur Laufzeit der Applikation von der DirectX-Bibliothek mit Hilfe des Grafiktreibers in die für die aktuelle Grafikhardware geeignete Assemblersprache übersetzt. Unterschiedliche Shader für Nvidia- oder ATI/AMD-Grafikkarten sind damit nicht mehr notwendig.

Sprach-Elemente

[Bearbeiten | Quelltext bearbeiten]

HLSL bietet keine OOP-Ansätze wie andere Sprachen. Es ist stark an C orientiert, stellt aber für die Shader-Programmierung optimierte Datentypen und Operationen zur Verfügung.

Globale Shader-Parameter

[Bearbeiten | Quelltext bearbeiten]

Parameter, die an einen Shader übergeben werden, stehen in HLSL global im kompletten Code zur Verfügung. Sie werden außerhalb von Methoden oder Structs geschrieben, meist zu Beginn des Codes.

 float4x4 world; // Definiert eine 4x4-Fließkomma-Matrix, hier die Welt-Matrix 
 float4x4 worldViewProj; // Die Welt-View-Projektionsmatrix, gerechnet als World*View*Proj.
 float3 lightDir; // Ein 3-Element Vektor. 
 float4 LightColor = {0.5, 0.5, 0.5, 1}; // Lichtfarbe (Vektor mit vordefiniertem Wert)
 float4 Ambient = {0.5, 0.5, 0.5, 1}; // Lichtfarbe des Umgebungslichtes
 float4 LightDir = {0, 0, -1, 0}; // Richtung des Sonnenlichtes (hier: Senkrecht von oben)

 texture2D Tex0; // Eine Textur

 SamplerState DefaultSampler // Der "Sampler" definiert die Parameter für das Texture-Mapping
 {
     filter = MIN_MAG_MIP_LINEAR; // Interpolationsfilter für Texturstreckung 
     AddressU = Clamp; // Texturkoordinaten ausserhalb [0..1] beschneiden
     AddressV = Clamp;
 };

Für die Bedeutung der obigen Matrizen siehe den Artikel Grafikpipeline.

Eingabe und Ausgabe des Vertex-Shaders

[Bearbeiten | Quelltext bearbeiten]

Statt jeden Parameter einzeln in die Parameterliste einer Shader-Methode zu schreiben, sind in der Praxis einheitliche Structs üblich. Dies spart Schreibarbeit und schafft mehr Übersichtlichkeit. Im Prinzip können beliebige Werte und Vektoren mit der Eingabestruktur übergeben werden, eine Position ist aber fast immer dabei.

 // Eingabe für den Vertex-Shader. 
 struct MyShaderIn
 {
     float4 Position : POSITION; // Dem Compiler wird bekannt gegeben, was die Variable "bedeutet". Hier: Das ist eine Position
     float4 Normal : NORMAL0; // Die Vertex-Normale, wird für die Beleuchtung verwendet
     float2 TexCoords : TEXCOORD0; // Texturkoordinaten
 }

 struct MyShaderOut
 {
     float4 Position : POSITION;
     float4 TexCoords : TEXCOORD0;
     float4 Normal : TEXCOORD1;
 }

Der „In-Struct“ gibt die Datenstruktur an, wie sie vom Drahtgittermodell an den Shader gereicht wird, also an den VertexShader. Dieser verarbeitet die Daten und gibt einen „Out-Struct“ als Rückgabetyp zurück. Dieser wird dann an den PixelShader weitergereicht, der am Ende nur noch einen float4 oder ähnliches zurückgibt, mit der endgültigen Pixelfarbe.

Vertex/Pixel Shader Methode

[Bearbeiten | Quelltext bearbeiten]

Für Vertex-Shader und Pixel-Shader muss eine Methode vorhanden sein. Diese nimmt eine Datenstruktur auf und verarbeitet sie entsprechend. Der Vertex-Shader wird einmal für jeden Vertex aufgerufen, der Pixel-Shader einmal pro zu renderndem Texturpixel.

 MyShaderOut MyVertexShader(MyShaderIn In)
 {
     MyShaderOut Output = (MyShaderOut)0;
     // Die nächste Zeile ist die Projektionsmultiplikation. Sie multipliziert die Position des aktuellen Punktes mit
     // der aus Welt-, Kamera- und Projektionsmatrix kombinierten 4x4-Matrix, um die Bildschirmkoordinaten zu erhalten
     Output.Position = mul(In.Position, WorldViewProj); 
     Output.TexCoords = In.TexCoords; // Texturkoordinaten werden in diesem einfachen Beispiel einfach durchgereicht
     Output.Normal = normalize(mul(In.Normal, (float3x3)World)); // Die Normale wird rotiert
     return Output;
 }

 // Eine Hilfsfunktion
 float DotProduct(float3 lightPos, float3 pos3D, float3 normal)
 {
     float3 lightDir = normalize(pos3D - lightPos);
     return dot(-lightDir, normal);    
 }

  // Der Pixel-Shader gibt als Rückgabewert lediglich eine Farbe (ggf. mit Alpha) zurück
 float4 MyPixelShader(MyShaderIn In): COLOR0
 {
     // Beleuchtungsstärke der Fläche (Das Skalarprodukt aus negativem Lichtvektor und 
     // Normalvektor der Fläche ist > 0 wenn die Fläche der Lichtquelle zugewandt ist)
     float sunLight = dot((float3)-LightDir, In.Normal); 
     float4 sunLightColor = float4(sunLight, sunLight, sunLight, 1); // Den Alphakanal setzen
     sunLightColor *= LightColor; // Die Lichtfarbe anbringen
     sunLightColor = saturate(sunLightColor); // Die Farbwerte auf [0..1] beschneiden
     // Die Texturfarbe an der zu zeichnenden Stelle abholen. Um die Interpolation der Texturkoordinaten 
     // brauchen wir uns nicht zu kümmern, das übernehmen Hardware und Compiler. 
     float4 baseColor = Tex0.Sample(DefaultSampler, In.TexCoords);
     float4 brightnessColor = baseColor*(sunLightColor + Ambient); // Helligkeit und Kontrast einrechnen
     brightnessColor = (brightnessColor + OffsetBrightness) * (1.0 + OffsetContrast);
     return brightnessColor;
 }

Geometrie-Shader

[Bearbeiten | Quelltext bearbeiten]

Die Implementierung eines Geometry-Shaders ist optional und ermöglicht es, ein Primitiv auf 0 bis n neue Primitive abzubilden. Die Art der Ausgabe-Primitive sowie die Maximalanzahl der produzierten Vertices muss allerdings zur Übersetzungszeit bekanntgegeben werden. Die Implementierung erfolgt hier prozedural und verwendet eigens dafür eingeführte Datenstrukturen (PointStream<T>, LineStream<T> und TriangleStream<T>).

Weiter besteht die Möglichkeit, auch auf die benachbarten Dreiecke und Linien zuzugreifen. Dies kann mit Hilfe der Input-Modifier trianglead und lineadj erreicht werden. Typische Anwendungen für Geometry-Shader sind die Generierung von Point-Sprites und das Rendern in CubeMap-Texturen. Hier ein einfacher Geometry-Shader, der jedes Dreieck, auf das er angewandt wird, zu seinen Schwerpunkt hin verkleinert:

 [maxvertexcount(3)]
 void GS(triangle MyShaderOut[3] input, inout TriangleStream<MyShaderOut> OutputStream)
 {
     MyShaderOut point;
     float4 centroid = (input[0].Position + input[1].Position + input[2].Position) / 3.0;
     point = input[0];
     point.Position = lerp(centroid, input[0].Position, 0.9);
     OutputStream.Append(point);

     point = input[1];
     point.Position = lerp(centroid, input[1].Position, 0.9);
     OutputStream.Append(point);

     point = input[2];
     point.Position = lerp(centroid, input[2].Position, 0.9);
     OutputStream.Append(point);

     OutputStream.RestartStrip();
 }

Zuletzt müssen die definierten Methoden in Form von Techniken und Durchläufen zugeordnet werden, damit sie vom Compiler entsprechend umgesetzt werden. Die Syntax der Shader hat sich mit DirectX 10 geringfügig geändert, daher wird die Zielversion auch bei der Technik nochmal explizit angegeben.

 technique10 MyTechnique // Für DirectX 10+
 {
     pass Pass0
     {
         VertexShader = compile vs_4_0 MyVertexShader();
         PixelShader = compile ps_4_0 MyPixelShader();
     }
 }