• 5Minuten
blank

Einsatz im GameMaker Studio 2

In GMS gibt es zwei Shader. Den „Vertex-Shader“ und den „Fragment-Shader“.

Vertex-Shader

Der Vertex-Shader ist ein Programm, das auf jeder Eingabe-Vertex des zu rendernden Modells ausgeführt wird. Seine Hauptaufgabe besteht darin, die 3D-Position jedes Vertex in 2D-Bildschirmkoordinaten zu transformieren und andere Daten wie Farben oder Texturen für die Verwendung im Fragment-Shader zu interpolieren.

Shader Code
Wenn man in GMS einen neuen Shader erstellt, wird der Basiscode für Vertex- und Fragment-Shader automatisch erstellt

In der Computergrafik ist ein Vertex (Mehrzahl: Vertices oder Vertexes) ein Eckpunkt in einem geometrischen Modell, das aus einer Sammlung von Punkten, Linien und Flächen besteht. Jeder Vertex hat eine Position im Raum und kann auch zusätzliche Informationen wie Farbe, Texturkoordinaten oder Normalenvektoren enthalten.

Fragment-Shader

Der Fragment-Shader ist ein Programm, das auf jedem Pixel der gerenderten Oberfläche ausgeführt wird. Seine Hauptaufgabe besteht darin, die Farben und andere visuelle Effekte für jeden Pixel auf der Oberfläche zu berechnen, basierend auf den Daten, die vom Vertex-Shader interpoliert wurden. Dieser wird in 2D-Spielen am häufigsten verwendet.

Die Berechnungen im Fragment-Shader werden für jeden Pixel auf der gerenderten Oberfläche ausgeführt. Die Ergebnisse der Berechnungen werden dann verwendet, um den Pixel im Framebuffer zu setzen, der dann auf dem Bildschirm angezeigt wird.

Insgesamt arbeiten Vertex- und Fragment-Shader eng zusammen, um die Geometrie und Farben der gerenderten Objekte in einer 3D-Szene zu erzeugen. Vertex-Shader führen Berechnungen für jedes Vertex aus, während der Fragment-Shader für jeden Pixel ausgeführt wird.

Float-Nummern

In der Programmierung gibt es verschiedene Datentypen, die zur Speicherung von Zahlenwerten verwendet werden können. Einer der häufigsten Datentypen ist der sogenannte „float“, der zur Speicherung von Fließkommazahlen verwendet wird. Float-Zahlen haben normalerweise eine bestimmte Anzahl an Nachkommastellen, die je nach Anwendung variieren können.

In GLSL wird die Verwendung von Float-Zahlen zur Darstellung von Farben und anderen Grafikdaten häufig verwendet. Um sicherzustellen, dass eine Zahl als Float-Nummer und nicht als Ganzzahl interpretiert wird, muss man das Suffix „.0“ oder „.0f“ hinzufügen. Zum Beispiel würde die Zahl 1 als Integer geschrieben, während 1.0 oder 1.0f als Float geschrieben würden.

Im konkreten Beispiel werden die Float-Werte 1.0, 0.0 und 0.0 als Rotanteil, Grünanteil und Blauanteil einer Farbe verwendet, während der Float-Wert 1.0 als Alpha-Kanal verwendet wird, um die Deckkraft des Objekts zu bestimmen.

Wichtig: Schreibt man versehentlich „1“ statt „1.0“, gibt es bei der Kompilierung eine Fehlermeldung, weil float erwartet wird, aber integer kommt.

Der kleine Tunneleffekt wurde ebenfalls als Shader (in GameMaker Studio 2.3) programmiert

Ablauf

Im ersten Tutorial werden wir lediglich einen Sprite manipulieren. Dafür gehen wir wie folgt vor:

  1. Neues Projekt erstellen
  2. Sprite laden
  3. Objekt erstellen
  4. Sprite im Objekt setzen
  5. Shader erstellen
  6. Fragment-Shader programmieren
  7. Shader im Draw-Event des Objekts einbinden

Shader erstellen

Da die ersten vier Punkte klar sein sollten, springen wir gleich zu Punkt 5. In der Leiste ganz rechts (Assets) können wir einen Shader anlegen. Im Beispiel nenne ich ihn sh_color_sprite. Wenn wir es doppelklicken, sehen wir, dass Fragment- und Vertex-Shader bereits Code enthalten. Im Beispiel werden wir zunächst die Farbe des Sprites manipulieren, also brauchen wir lediglich den Fragment-Shader. Der Vertrex-Shader bleibt, wie er ist.

Farbe ändern

GMS gibt uns beim Fragment-Shader folgenden Code:

Das ist unser Grundgerüst. Wir fügen lediglich zwei Zeilen hinzu und verändern die letzte Zeile:

Die erste Änderung ist uniform vec4 sprite_color;. Mit uniform deklarieren wir eine Variable, auf die wir „von Außen“, also dem Objekt mit dem Sprite, zugreifen können. Hier haben wir eine Variable namens sprite_color definiert, die eine 4-Komponenten-Vektor ist, der die RGBA-Werte (Rot, Grün, Blau, Alpha, also Transparenz) der Farbe des Sprites enthält.

Die zweite Veränderung ist die Zeile vec4 inverted_color = sprite_color;. Hier wird der Farbwert übergeben. Damit dieser auch berechnet wird, haben wir die letzte Zeile lediglich ergänzt.

gl_FragColor ist eine Ausgabevariable in einem Fragment-Shader-Programm, die verwendet wird, um die Farbe des aktuellen Fragments (Pixel) zu setzen.

In OpenGL-basierten Grafiksystemen, einschließlich GameMaker Studio 2, wird die gl_FragColor Variable automatisch vom Grafiktreiber erstellt und initialisiert. Der Fragment-Shader-Code muss lediglich eine Farbe zuweisen, um das entsprechende Fragment zu färben.

Draw-Event im Objekt

Hier brauchen wir nur wenige Zeilen:

Mit shader_set() aktivieren wir den Shader, der auf das aktuelle Objekt angewendet werden soll. sh_color_sprite enthält die ID des zuvor erstellten Shaders. Durch das Aktivieren des Shaders wird der Grafikprozessor des Computers angewiesen, diesen Shader für alle folgenden Grafikoperationen zu verwenden, bis ein anderer Shader aktiviert wird.

Die zweite Zeile ruft die Funktion shader_get_uniform() auf, um die Uniform-Variable sprite_color aus dem Shader zu holen. In diesem Fall wird die Uniform-Variable aus dem Shader mit der ID sh_color_sprite abgerufen und der Variablen sh_color zugewiesen.

Die dritte Zeile ruft die Funktion shader_set_uniform_f() auf, um den Wert der Uniform-Variable sh_color auf vec4(1.0, 0.0, 0.0, 1.0) zu setzen. Diese Funktion setzt den Wert der Uniform-Variable, die mit der ID in der ersten Argumentposition übereinstimmt, auf einen Vektor mit 4 float-Werten, die in den nachfolgenden Argumenten angegeben werden. In diesem Fall wird die Uniform-Variable sh_color, die in Schritt 2 definiert wurde, auf einen Vektor gesetzt, der Rot als Primärfarbe und eine vollständige Deckkraft (1.0) hat.

Würde man es grün färben wollen, sähe die Zeile so aus:

Die nächste Zeile ruft die Funktion draw_self() auf, um das aktuelle Objekt zu zeichnen. Der Grafikprozessor des Computers verwendet den aktiven Shader, um das Objekt zu rendern, und verwendet die Uniform-Variable sprite_color, um die Farbe des Objekts zu bestimmen.

Links das Original, rechts ist es rot eingefärbt
Links das Original, rechts ist es rot eingefärbt

Die letzte Zeile ruft die Funktion shader_reset() auf, um den aktuell aktiven Shader aufzuheben und den Standard-Shader des Systems wiederherzustellen. Dies stellt sicher, dass nach Beendigung des Renderns des Objekts der aktive Shader nicht versehentlich auf andere Objekte oder Grafikoperationen angewendet wird.

Autor

Abonnieren
Benachrichtige mich bei
guest

0 Comments
Inline Feedbacks
Alle Kommentare anzeigen