Fri, 28 Mar 2025
Seite 3: Im ersten Teil dieser Tutorialserie über das Programmieren von Postprocessing Shadern in HLSL haben wir uns mit den Grundlagen solcher Effekte beschäftigt. Nun sollen Sie die Möglichkeiten kennen lernen, zahlreiche interessante Effekte für Ihre Spiele zu erstellen, unter anderem Schwarz/Weiß-Filter, Sepia und einfaches Bloom.
Das Tutorial richtet sich an Anfänger und geht von den Grundlagen des vorangegangenen Teils aus.
Das gesamte Tutorial zusammen mit Codebeispielen steht hier zum Download bereit.
Er will doch nur spielen |
Negativbild |
Monochrome/Graustufen |
Schwarzweiß |
Sepia |
Bloom |
Sepia-Bloom
Machen wir einen kleinen Exkurs! Ein in Computerspielen sehr häufig verwendeter Effekt ist Bloom. Bloom macht im Endeffekt nichts anderes,
als helle Pixel noch heller erscheinen zu lassen. Es entsteht ein schöner Kontrast im Bild. Sie sind bereits in der Lage einen einfachen Bloomshader zu programmieren.
Durch einfaches Quadrieren der Farbkomponenten eines Pixels kann man die hellen Pixel besonders von den dunklen abheben.
Denn je kleiner eine Zahl unter 1 ist, desto kleiner ist ihr Quadrat. Also reicht es aus jede Farbkomponente zu quadrieren um eine Steigerung des Kontrastes zu bewirken. Da sich die
hellen Farben weniger oder kaum beeinflussen lassen, dunklere aber hingegen deutlich schwächer werden.
HLSL bietet einem hierfür einen extra Befehl, ähnlich dem in lite-c:
pow(Basis,Exponent);
Also:
[...]
float4 Color;
Color=tex2D(mySampler,Tex.xy);//Pixelfarbe auslesen
Color.rgb=pow(Color.rgb,2.0f);//Kontrast erhöhen
[...]
Das Ergebnis sieht zu dunkel aus? Dann hellen Sie es doch mit einem Faktor auf.
[...]
Color.rgb=pow(Color.rgb,2)*2.0f;//Kontrast erhöhen und aufhellen
[...]
Die Ähnlichkeit zum Sepiashader im Testlevel ist übrigens zufällig und kommt nur durch die Farbe der verwendeten Lichtquelle zustande.
Der Nachteil dieser Methode ist, dass der Bloom typische 'Schein' der leuchtenden Flächen fehlt und bei sehr dunklen Flächen die
Details verloren gehen.
Ein selektiver Bloomshader würde also schönere und natürlichere Ergebnisse liefern.
Um diesen Bloomeffekt noch besser zu machen, müsste man die hellen Bereiche finden und zusätzlich durch einen Blurfilter z.B. Box Blur oder Gaussian
Blur laufen lassen. Anschließend müsste man das Ergebnis zur Ausgabe hinzumischen. Dann hätte man auch schöne Leuchteffekte und Übergänge zu weniger gut beleuchteten Teilen des Bildes.
Dies ist jedoch Thema eines der nächsten Shadertutorials.
Aber nichtsdestotrotz können wir auch diesen Effekt einfach simulieren. Dazu speichern wir vor der pow-Operation die tatsächliche Pixelfarbe
temporär ab und mischen sie danach vor der Ausgabe hinzu. Je größer der Exponent desto schärfer werden die Leuchtpunkte. Denn die besonders dunklen
Pixel werden so zu schwach um die Ausgangsfarbe zu beeinflussen. Die hellen hingegen bleiben hell genug um die Ausgabepixel deutlich heller zu machen. Somit schaffen wir uns eine Art Maske, die die dunklen Stellen wegretuschiert. Wer mit Programmen wie Photoshop oder GIMP arbeitet, kennt sich aus.
Um die gelesene Pixelfarbe zu speichern erstellen wir einen lokalen Fließkommavektor namens tempColor. Da wir uns nicht um den Alphawert des Pixels
kümmern müssen, weil wir ihn nicht ändern, kann der Vektor hier nur drei Komponenten haben, also vom Typ float3 statt float4 sein.
Diesem können wir einfach die Werte von Color zuweisen. Durch automatisches Typecasting werden r,g und b von tempColor die entsprechenden Werte
von Color zugewiesen. Color.a wird praktischerweise außer Acht gelassen... wie gesagt, HLSL ist syntaktisch sehr viel komfortabler als C.
[...]
float4 Color;//Ausgabefarbe rgba(temporär)
float3 tempColor;//weiterer temporärer Vektor
Color=tex2D(mySampler,Tex.xy);//Pixelfarbe auslesen
tempColor=Color;//und zwischenspeichern
Color.rgb=pow(Color.rgb,2.0f);//Kontrast erhöhen, Maske
Color.rgb*=tempColor;//Maske anwenden und die Originalfarbe wieder dazu mischen
Color.rgb+=tempColor;
return Color;
[...]
Das Anwenden der Maske geschiet durch Multiplikation mit dem zwischengespeicherten Originalbild.
Danach stellt Color die Leuchtfleckenfarbe dar. Durch Addition der Originalfarbe erhalten wir ein
stellenweise aufgehelltes Bild mit allen urspünglichen Details.
Leider funktioniert das automatische Typecasting nicht in umgekehrte Richtung, also konnten wir einem
größeren Vektor(Color) nicht direkt tempColor (float3) zuweisen. Logisch, schließlich ist diese Zuweisung nicht eindeutig. Denn r,g,b und a
sind lediglich Kurzschreibweisen für die Stelle im Array (Vektor), [0],[1],[2] und [3]. Und man kann nicht sagen, was mit der 4. Stelle
([3]) bei der Zuweisung passieren soll. Dennoch wird sie angesprochen.
Deshalb war es nötig zu spezifizieren, welche Komponenten von Color für die Zuweisung verwendet werden sollen.
'Color.rgb' hat Color auf float3 Größe gebracht. So konnte die automatische Zuweisung vonstatten gehen.
Und um diesem Shader den letzten Schliff zu geben und die Übergänge von hellen zu dunklen Bereichen sanfter zu machen, können wir noch das Ergebnis der pow-Operation in ein Graustufenbild umwandeln. Unsere Maske war bisher ja auch farbig statt graustufig, wie sie sein sollte:
[...]
float4 Color;//Ausgabefarbe rgba(temporär)
float3 tempColor;//weiterer temporärer Vektor
Color=tex2D(mySampler,Tex.xy);//Pixelfarbe auslesen
tempColor=Color;//und zwischenspeichern
Color.rgb=pow(Color.rgb,2.0f);//Kontrast erhöhen, Maske
Color.rgb=(Color.r+Color.b+Color.g)/3.0f;//Maske monochrom machen
Color.rgb*=tempColor;//Maske anwenden und die Originalfarbe wieder dazu mischen
Color.rgb+=tempColor;
return Color;
[...]
Die Stärke der Leuchtflecken kann übrigens durch Erhöhung des Kontrasts und Helligkeit der Maske erreicht werden. Hierzu bei Wunsch einfach einen Faktor nachstellen.
Zum Abschluss dieses Tutorials sollten wir noch das Kombinieren verschiedener Operationen in einem Pass durchgehen. Denn je nach Shadermodell hat man eine unterschiedliche Beschränkung an der Zahl der Operationen z.B. tex2D. Wir werden jetzt den Sepia Shader mit dem stark vereinfachten Bloomshader kombinieren.
/*Außerhalb der Pixelshader-Funktion! Am Anfang der fx Datei*/
const float strength=0.15f;
[...]
//an der bekannten Stelle im Pixelshader
float4 Color;
Color=tex2D(mySampler,Tex.xy);
Color.rgb=pow(Color.rgb,2.0f)*2.0f;//unsere Bloom Operation
Color.rgb=(Color.r+Color.g+Color.b)/3.0f;//danach Sepia Operationen
Color.r+=strength;//färbe in Sepia Töne
Color.b-=strength;
return Color;
[...]
Unsere Bloom-Shader Specialversion kann selbstverständlich auch auf dem selben Weg mit Sepia kombiniert werden. Die Monochrome-Operation muss da aber nicht doppelt vorkommen. Denn die Ergebnisse unterscheien sich nur geringfügig, jeder zusätzliche Befehl kostet aber Rechenleistung pro Pixel. Und ein Shader muss immer optimiert sein, damit der auch auf älterer Hardware läuft.
/*Außerhalb der Pixelshader-Funktion! Am Anfang der fx Datei*/
const float strength=0.15f;
[...]
//Pixelshader
float4 PP_Shader (float2 Tex: TEXCOORD0):COLOR0
{
float4 Color;//Ausgabefarbe rgba(temporär)
float3 tempColor;//weiterer temporärer Vektor
Color=tex2D(mySampler,Tex.xy);//Pixelfarbe auslesen
Color.rgb=(Color.r+Color.b+Color.g)/3.0f;//monochrom machen
tempColor=Color;//und zwischenspeichern
Color.rgb=pow(Color.rgb,2.0f);//Kontrast erhöhen, Maske
Color.rgb*=tempColor;//Maske anwenden und die Originalfarbe wieder dazu mischen
Color.rgb+=tempColor;
Color.r+=strength;//färbe in Sepia Töne
Color.b-=strength;
return Color;//schließlich Resultat zurückliefern
}
[...]
News
28.05.2012 |
Neuestes Video Quick terrain/ Schnelles Terrain Tutorial (no sound) from Grygoriy Kulesko on Vimeo. |
Zufallsbild
|
Vote Derzeitig finden keine Votings statt. |
Partner
Werden Sie Link-Partner von kstudios.de und an
dieser Stelle erscheint ein Link zu Ihrer Website!
Kontakt