Shader:
Nachdem
du dich nun in den verschiedenen Themen mit vorgegebenen Shadern rumschlagen
musstest, will ich dir hier erklären, wie man einen Shader schreibt
und worauf man zu achten hat.
Shader
sind Textdateien, deren Inhalt den Texturen Eigenschaften verleihen können,
z.B: metallischen Glanz, Wassereigenschaften, Spielgeeigenschaften oder
auch Metal-Sound von sich zu geben, wenn man über sie läuft.
Da Shader
Textdateien sind, kann man sie mit jedem beliebigen Textbeartbeitungsprogramm
schreiben, z.B. auch NotePad oder WordPad. Um einen Shader zu schreiben,
gibt es einige Zeichen, ohne die ein Shader nicht auskommt:
- die geschwungenen
Klammern:{ } Sie markieren den Anfang und das Ende des Shaders, sowie
Anfang und Ende einer Schicht (auch Stage genannt)
- die zwei Slahes:
// Sie dienen nur dazu, einen Kommentar in den Textdateien zuzulassen.
Alles, was hinter diesen beiden Zeichen bis zum Ende der Zeile steht,
wird von der Engine nichtmehr zum Shader gerechnet.
- Du solltest beachten,
dass du im Shader auf Grossschreibung und Umlaute verzichtest.
Wie du schon weisst,
müssen Shader in die Shaderlist.txt eingetragen werden, damit sie
funktionieren. Dazu öffnest du jetzt die Datei Shaderlist.txt und
schreibst dort in eine neue Zeile "erstershader":
Nun öffnest du
dein Textprogramm und schreibst hinein:
// mein erster
Shader
textures/shader1/textur
{
{
map textures/shader1/textur.tga
}
}
|
Dies ist der warscheinlich
einfachste Shader überhaupt - denn er verändert die Textur selbst
garnicht. Doch für unsere Zwecke reicht er völlig aus. Kommen
wir nun zur Erklärung des Shaders:
//
mein erster Shader |
Ist
lediglich ein Kommentar, er dient nur zur Erklärung oder dazu,
bestimmte Teile des Shaders zu testzwecken abzuschalten. |
textures/shader1/textur |
Name des Shaders
- damit legst du fest, wo du später die Textur finden kannst. |
{ |
Beginn des Shaders |
{
|
Hier beginnt
die erste Schicht |
map textures/shader1/textur.tga
|
Mit dieser Anweisung
(map <Pfad zur Textur> ) gibt man der Engine die Anweisung,
die Oberfläche der Textur mit der angegebenen Textur zu belegen. |
}
|
Hier endet die
erste Schicht |
} |
Hier endet der
Shader |
Nun speicherst du
diese Datei im Ordner "Main/scripts" unter dem Namen "erstershader.shader"
ab.
Erstellst
du nun einen Ordner namens "shader1" im Textures-Ordner und
kopierst dort eine beliebige Textur namens "textur" hinein,
läuft der Shader.
Nun wagen
wir uns an einen neuen Shader, der diesmal etwas anspruchsvoller wird.
Wir wollen einen Shader haben, der aus 2 Texturen besteht. Diese beiden
Texturen findest du hier.
Nun gucken wir sie uns gleichmal an:
Diese
beiden Texturen sollen dargestellt werden. Du kannst natürlich auch
beide Texturen durch andere ersetzen. Bei uns soll folgender Effekt entstehen:
Logo1.tga UND Logo2.tga sollen gleichzeitig dargestellt werden. Dazu benutzen
wir einfach den folgenden Shader:
textures/meinshader/logo2
{
{
map textures/meinshader/logo1.tga
}
{
map textures/meinshader/logo2.tga
blendfunc add
}
{
map $lightmap
blendfunc filter
}
} |
Nun erkläre
ich dir erstmal, was es mit den neuen Befehlen auf sich hat:
textures/meinshader/logo2 |
Name
des Shaders - damit legst du fest, wo du später die Textur finden
kannst. |
{ |
Beginn des Shaders |
|
|
{
|
Beginn der ersten
Stage |
map textures/meinshader/logo1.tga
|
Der Pfad zur
Textur, die in der ersten Stage dargestellt wird. |
}
|
Ende der ersten
Stage |
|
|
{
|
Beginn der zweiten
Stage |
map textures/meinshader/logo2.tga
|
Der Pfad zur
zweiten Textur, die in der zweiten Stage dargestellt wird.
|
blendfunc
add
|
Dieser Parameter
gibt an, dass die beiden Texturen additiv (also übereinander)
dargestellt werden. |
}
|
Ende der zweiten
Stage |
|
|
{
|
Anfang der dritten
Stage |
map $lightmap
|
Gibt an, dass
die normale Textur (logo1.tga) als Lightmap verwendet wird. |
blendfunc
filter
|
Gibt an, wie
die Lightmap überblendet wird. |
}
|
Ende der dritten
Stage |
|
|
} |
Ende des Shaders |
So, jetzt sind wir
ja schon ziemlich weit - einen Shader mit 3 Stages ist schon ziemlich
schwer zu verstehen. Nun toppen wir das ganze, in dem wir das Logo nun
noch blinkend dargestellt haben wollen. Dazu kommt lediglich zwei Zeilen
im Shader dazu - zum Schluss sieht der Shader so aus:
textures/meinshader/logo1
{
qer_editorimage textures/meinshader/logo2.tga
{
map textures/meinshader/logo1.tga
}
{
map textures/meinshader/logo2.tga
rgbGen wave square 0.5 0.5 0 1.1
blendfunc add
}
{
map $lightmap
blendfunc filter
}
} |
Nun erkläre ich
dir auch gleich, was die beiden neuen Zeilen bedeuten:
textures/meinshader/logo1 |
Name
des Shaders - damit legst du fest, wo du später die Textur finden
kannst. |
{ |
Anfang des Shaders |
qer_editorimage
textures/meinshader/logo2.tga |
Gibt an, welches
Bild der Shader im Radiant hat (vergibst du diesen nicht, so erscheint
"Shader Image Missing") |
|
|
{
|
Anfang der ersten
Stage |
map textures/meinshader/logo1.tga
|
Der Pfad zur
Textur, die in der ersten Stage dargestellt wird. |
}
|
Ende der ersten
Stage |
|
|
{
|
Beginn der zweiten
Stage |
map textures/meinshader/logo2.tga
|
Der Pfad zur
zweiten Textur, die in der zweiten Stage dargestellt wird. |
rgbGen wave
square 0.5 0.5 0 1.1
|
generiert die
Vertexfarbe. Darauf gehe ich gleich näher ein. Der Syntax "wave"
generiert den "Blinkabstand" der Textur. |
blendfunc
add
|
Dieser Parameter
gibt an, dass die beiden Texturen additiv (also übereinander)
dargestellt werden. |
}
|
Ende der zweiten
Stage |
|
|
{
|
Anfang der dritten
Stage |
map $lightmap
|
Gibt an, dass
die normale Textur (logo1.tga) als Lightmap verwendet wird. |
blendfunc
filter
|
Gibt an, wie
die Lightmap überblendet wird. |
}
|
Ende der dritten
Stage |
|
|
} |
Ende des Shaders |
Nun gehe ich etwas
näher auf folgenden Teil im Shader ein:
rgbGen wave square
0.5 0.5 0 1.1
rgbGen generiert ja
die Vertex-Farbe. Diese wird mit der Farbe der Textur multipliziert um
dann die entgültige Farbe zu erhalten. Normal ist die Vertexfarbe
weiss, d.h. die Farbe ändert sich nicht ( [Texturfarbe] * 1 1 1).
Mit dem Syntax "wave" wird die Engine dazu veranlasst, diese
Farbe zu wechseln, d.h. man erzeugt blinkende Effekte. Die komplette Reihenfolge
des Befehls lautet so:
rgbGen
wave <func> <base> <amp> <phase> <freq>
<func>
gibt an, in welcher Weisse sich die Vertexfarbe ändern soll - es
gibt 5 Parameter für diese Änderung:
- sin (gleichmässige
Ab- und Aufwärtsbewegung, entspricht genau der Sinuswelle)
- triangle (Dreiecksbewegung,
d.h.Gradliniger Auf- und Abbau der Werte)
- square (Wechsel
zwischen zwei Werten, also z.B. an und aus.
- sawtooth (geradliniger
Aufbau, radikaler Abfall der Kurve)
- invertedsawthooth
(radikaler Aufbau, geradliniger Abbau, Umgekehrte Sawtooth-Funktion)
<base>
gibt den Basiswert an, auf den sich später der <amp>-Wert bezieht
bezieht.
<amp>
gibt den maximalen Ausschlag der Kurve in Bezug auf den Basis-Wert (<base>)
an.
<phase>
Hier mit kann man eine zeitliche Verzerrung der Kurve erziehlen, damit
z.B.nicht alle Shader in der gleichen Abfolge blinken. Meistens wird <phase>
allerdings auf den Wert 0 gesetzt.
<freq>
steht sinnigerweisse für "Frequenz", also wie oft eine
Kurve innerhalb einer Sekunde wiederholt wird. Der Wert 2 veranlasst den
Shader dazu, die Kurve innerhalb einer Sekunde 2mal zu wiederholen. Der
Wert 0.5 veranlasst den Shader dazu, die Kurve nur alle 2 Sekunden zu
wiederholen.
Bei unserem
Shader wechselt also die Vertexfarbe immer zwischen den Werten 1 1 1 und
0 0 0, d.h. das Logo wird angezeigt, wenn der Wert auf 1 1 1 steht. Wechselt
der Wert auf 0 0 0, verschwindet das Logo.
.
Alpha-Texturen:
Wie du
bei dem Logo gesehen hast, wird nur der "haradirki"-Schriftzug
gargestellt, der Rest wird von der Engine abgeschnitten, d.h. er wird
nicht dargestellt. Nun zeige ich dir, wie man eine solche Alphashader
selbst hinbekommt. Zuerst erstellst du ganz normal deine Textur.
Hier
kannst du die Textur "logo2.tga" und deren Alpha-Channel sehen.
Zwar kann man hier nicht genau den Unterschied zur richtigen Textur erkennen
- doch sind die drei Innenräume von den Buchstaben "a"
und "d" komplett weiss - was daraufhin deutet, dass dieser Innenraum
auch von der Engine dargestellt werden soll.
Nun kommen
wir aber zum Shader:
textures/meinshader/logo2
{
{
map textures/meinshader/logo2.tga
alphaFunc GT0
}
}
|
Nun folgt auch gleich
die Erklärung zum Shader:
textures/meinshader/logo2 |
Name
des Shaders - damit legst du fest, wo du später die Textur finden
kannst. |
{ |
Anfang des Shaders |
|
|
{
|
Anfang der ersten
Stage |
map textures/meinshader/logo2.tga
|
Der Pfad zur
Textur, die in der ersten Stage dargestellt wird. |
alphaFunc
GT0
|
Durch diesen
Parameter zeichnet die Engine nur die Bereiche der Textur, die im
Alphakanal einen höheren Wert als 0 0 0 haben (die nicht schwarz
sind) |
}
|
Ende der ersten
Stage |
|
|
} |
Ende des Shaders |
Nun erkläre ich
dir diese Zeile noch etwas genauer:
alphaFunc
<syn>
Folgende Syntaxe sind
hier möglich:
- GT0 "GREATER
THAN 0" (diesen Syntax haben wir in unserem Beispiel verwendet)
- LT128 "LESS
THAN 128"
- GE128 "GREATER
THAN OR EQUAL TO 128"
ACHTUNG: Hierbei sind
nur die Farbwerte von 0 - 255 zulässig, nicht die gesamte 16- oder
gar die 32-Bit-Palette
Unser Alpha-Kanal besteht nur
aus Pixeln, die auf 0 0 0 stehen (die schwarz sind) und aus Pixeln, die
auf 1 1 1 stehen (die weiss sind), d.h. das weisse wird dargestellt, das
schwarze nicht.
Shader
sind, wie du siehst, eine recht schwierige Angelegenheit. Jedoch lassen
sich damit wirklich tolle Effekte erzielen, die jede Map enorm aufwerten.
Du solltest dich hier mit dem Thema etwas genauer beschäftigen und
erstmal vorhandene Shader modifizieren. Später kannst du dann versuchen,
einen eigenen Shader zu schreiben.
Jedoch
darfst du nie vergessen, deinen Shader in die Shaderlist.txt einzutragen
- da sonst der Shader nicht geladen wird. Das kannst du leicht erkennen,
da dann die Textur nicht weiss umrandet ist.
|