Sprite verzerren
Im zweiten Beispiel werden wir das Sprite verzerren. Im Prinzip ist das nicht viel anders, als würde man die Farbe ändern. Der Code für den Fragment-Shader sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | varying vec2 v_vTexcoord; varying vec4 v_vColour; uniform vec2 distortion_amount; void main() { vec2 distortion_offset = vec2( sin(v_vTexcoord.y * 10.0) * distortion_amount.x, cos(v_vTexcoord.x * 10.0) * distortion_amount.y ); vec2 distorted_texcoord = v_vTexcoord + distortion_offset; gl_FragColor = v_vColour * texture2D(gm_BaseTexture, distorted_texcoord); } |
Die Verzerrung erfolgt, indem wir jeden Pixel des Sprites in seiner Position verändern. Das Beispiel verwendet eine Uniform-Variable, die distortion_amount
heißt und einen vec2-Vektor darstellt. Die x-Komponente des Vektors beeinflusst die Verzerrung auf der horizontalen Achse, während die y-Komponente die Verzerrung auf der vertikalen Achse beeinflusst.
Im Fragment-Shader-Bereich wird ein Offset-Vektor distortion_offset
berechnet, der abhängig von der aktuellen Texturkoordinate (in v_vTexcoord
) und den Verzerrungsparametern ist. In diesem Beispiel wird der Offset basierend auf der Sinus- und Kosinus-Funktion der Texturkoordinaten berechnet. Man kann jedoch die Formel ändern, um verschiedene Arten von Verzerrungen zu erzeugen.
Der berechnete Offset wird dann auf die Texturkoordinate addiert, um die verzerrte Texturkoordinate distorted_texcoord
zu erhalten. Schließlich wird die Farbe des verzerrten Pixels aus der Textur gelesen und mit der Vertex-Farbe (in v_vColour
) multipliziert, um die endgültige Ausgabe-Farbe (gl_FragColor
) zu generieren.
Draw-Event
Hier ist der Code nahezu identisch zur Färbung:
1 2 3 4 5 | shader_set(sh_distortion_sprite); sh_distortion = shader_get_uniform(sh_distortion_sprite, „distortion_amount"); shader_set_uniform_f(sh_distortion, 0.02, 0.04); draw_self(); shader_reset(); |
Wir setzen nur andere Namen ein (der Shader heißt bei mir sh_distortion_sprite
) und übergeben lediglich zwei Variablen statt der vier bei den Farben. Da ich im Beispiel ein kleines Sprite verwende, reichen geringe Werte, wie 0.02 und 0.04, um eine deutliche Änderung zu sehen.
Dynamische Werte
Die Verzerrung, aber auch die Verfärbung, lassen sich natürlich auch variabel gestalten. So kann man bspw. die Farbe von Bedingungen im Spiel abhängig machen, etwa den Abstand zu bestimmten Objekten.
Bei der Verzerrung wäre eine Animation sehr schön. So könnte man zwei Variablen mit disX
und disY
anlegen und diese bis zu einem bestimmten Wert hochzählen lassen.
Beispiel:
Create-Event
1 2 | disX = 0.0; disY = 0.0; |
Draw-Event
1 2 3 4 5 6 7 | if (disX < 0.8) { disX += 0.01; disY += 0.02; } shader_set_uniform_f(sh_distortion, disX, disY); |
Einfach die entsprechenden Zeilen einfügen bzw. die letzte Zeile austauschen, schon erhalten wir eine hübsche Bewegung.
Fazit und Ausblick
Was wir bisher gemacht haben, war nur die oberste Schneeflocke auf dem Shader-Eisberg. Das Thema ist so umfangreich, dass sich damit zahllose Bücher befassen.
Dieser Auftakt hilft, den Einstieg in das Thema zu finden und offenbart dabei zahlreiche Möglichkeiten. Wir können nun Farben und Pixel einzelner Sprites manipulieren, womit man sehr viele Dinge anfangen kann. Eines der Vorteile ist, dass wir nicht für jede Kleinigkeit neue Sprites brauchen. Wir färben und verformen es über den Shader und können so zum Beispiel auch Objekte explodieren lassen.
Im nächsten Teil gehen wir einen Schritt weiter und manipulieren alles, was auf dem Bildschirm zu sehen ist. Solche Post-Processing-Effekte können in Spielen sehr oft eingesetzt werden.
Verwendete Sprites
Weiterführende Links
Shader-Programmierung 2: Post-Processing
Shader-Programmierung 3: Effekte
Shader-Effekt: Warping
Textscroller: Wellen und einzelne Farben
Raster bar Effekt
Sonnenblumen und der goldene Schnitt