The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe

Bahasa Indonesia - Tiếng Việt - 日本語 - 中文版 - 한국어 - Español - Portugues - Français - Italiano - Deutsch - Русский - Polski - English


Muster

Weil Shader-Programme Bildpunkt für Bildpunkt ausgeführt werden, spielt es keine große Rolle, wie oft man ein bestimmtes Muster innerhalb der Zeichenfläche wiederholt – die Anzahl der Berechnungen bleibt gleich. Aus diesem Grund eignen sich Fragment-Shader ganz hervorragend für die Erzeugung sich wiederholender Kachelmuster.

Nina Warmerdam – Das IMPRINT Projekt (2013)

In diesem Kapitel werden wir anwenden, was wir bislang gelernt haben, und es über den gesamten Raum unserer Zeichenfläche wiederholen. Wie schon in den vorhergehenden Kapiteln wird unsere Strategie darin bestehen, die Koordinaten zu vervielfältigen. Dadurch werden sich Formen, die wir innerhalb des Koordinatenraumes zwischen 0.0 und 1.0 zeichnen, vervielfältigen lassen, so dass ein kontinuierliches Muster entlang eines Rasters entsteht.

"Das Gitternetz eröffnet einen Rahmen, innerhalb dessen sich die menschliche Intuition und Schöpfungskraft entfalten kann. Inmitten des Chaos der Natur stellen Muster einen Kontrastpunkt dar, indem sie eine vorhersehbare, sich wiederholende Ordnung realisieren. Schon seit frühen Mustern auf Keramikflächen in antiken Bädern haben die Menschen Gitternetze genutzt, um ihr Leben durch repetitive Dekorationen zu verschönen.“ 10 PRINT, Mit Press, (2013)

Lasst uns zunächst noch einmal die fract()-Funktion ins Gedächtnis rufen. Sie liefert den Nachkommateil einer Zahl zurück, wodurch fract() effektiv den Modulo (Rest) einer Division durch 1 ergibt (mod(x,1.0)). Unsere normalisierte Variable für das Koordinatensystem (st) bewegt sich ohnehin zwischen 0.0 und 1.0. Deshalb macht es wenig Sinn, Berechnungen wie die folgende anzustellen:

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution;
    vec3 color = vec3(0.0);
    st = fract(st);
    color = vec3(st,0.0);
    gl_FragColor = vec4(color,1.0);
}

Wenn wir aber das Koordinatensystem hochskalieren – sagen wir einmal um den Faktor drei – erhalten wir drei interpolierende Sequenzen: die Erste mit Fließkommawerten von 0 bis 1, die Zweite mit Werten von 1 bis 2 und die Dritte mit Werten zwischen 2 und 3.

Jetzt ist es an der Zeit, in jedem dieser Drei mal Drei „Unterräume“ zu zeichnen, indem Du die Kommentarzeichen in Programmzeile 27 entfernst. (Weil wir die x- und y-Ordinate gleichermaßen skalieren, bleibt das Seitenverhältnis erhalten.)

Probiere einige der folgenden Übungen aus, um Dein Verständnis zu vertiefen:

Anwendung von Matrizen innerhalb von Mustern

Weil jeder „Unterraum“ und jede Gitterzelle eine verkleinerte Fassung des normalisierten Koordinatensystems darstellt, mit dem wir bereits gearbeitet haben, können wir auch Matrizenoperationen darauf anwenden. So lässt sich der Koordinatenraum innerhalb einer Gitterzelle verschieben, rotieren und auch skalieren.

Vektormuster eines schottischen Tartans von Kavalenkava

Versetzte Muster

Sagen wir einmal, wir wollen ein Mauerwerk zeichnen. Beim Blick auf eine solche Wand fällt sofort auf, dass die Steine in jeder Reihe jeweils um eine halbe Steinlänge versetzt sind. Stellt sich natürlich die Frage, wie wir so etwas per Programmcode umsetzen können?

Im ersten Schritt müssen wir zunächst einmal wissen, ob die Zeile, an der unser Thread gerade arbeitet, gerade oder ungerade ist. Denn darüber können wir den Versatz der Muster entlang der x-Achse bestimmen. Dafür können wir mod() mit 2.0 verwenden und schauen, ob das Ergebnis weniger als 1.0 beträgt oder nicht. Wirf einen Blick auf die folgende Formel und entferne nacheinander die Kommentarzeichen in den letzten beiden Zeilen.

Wie Du siehst, können wir den ternären Operator nutzen, um zu prüfen, ob das Ergebnis von mod() mit 2.0 unter dem Wert von 1.0 liegt. Oder wir können die step()-Funktion nutzen, um das gleiche Ergebnis zu erzielen. Und step() ist in der konkreten Ausführung sogar noch etwas schneller. Doch wie kommt das? Obwohl es schwer vorhersehbar ist, wie eine bestimmte Grafikkarte Shader-Code kompiliert und optimiert, können wir davon ausgehen, dass eingebaute Funktionen schneller ausgeführt werden, also solche, die erst in mehrere Einzelschritte aufgelöst werden müssen. Wann immer Du eine eingebaute Funktion für Deine Zwecke nutzen kannst, tue dies deshalb auch!

Nun haben wir also unsere „Ungerade-Funktion“ beisammen, sodass wir den ungeraden Reihen unseres Mauerwerks einen Versatz geben können. In der Programmzeile 14 des folgenden Listings befindet sich der entsprechende Programmcode. Beachte, dass das Ergebnis unserer Berechnung für gerade Reihen 0.0 lautet und die Multiplikation mit dem Versatz von 0.5 dann eben auch 0.0 ergibt. Bei ungeraden Reihen multiplizieren wir den Versatz von 0.5 hingegen mit 1.0, so dass daraus eine entsprechende Verschiebung der x-Achse des Koordinatensystems folgt.

Entferne jetzt die Kommentarzeichen in der Programmzeile 32, wodurch das Seitenverhältnis unseres Koordinatensystems gestreckt wird und wir die Anmutung eines modernen Mauerwerks erhalten. Wenn Du die Kommentarzeichen in Programmzeile 40 entfernst, erkennst Du die Anordnung und Wiederholung des Koordinatensystems anhand der Farben Rot und Grün.

Truchet-Kacheln

Wir haben nun gelernt, wie man feststellt, ob sich die zu zeichnende Gitterzelle in einer geraden oder ungeraden Zeile bzw. Spalte befindet, Auf Basis dieser Information können wir ein einzelnes Designelement in Abhängigkeit seiner Position wiederverwenden. Wirf einen Blick auf die sogenannten Truchet-Kacheln, bei denen eine einzelne Form in vier unterschiedlichen Anordnungen dargestellt wird:

Indem wir die Anordnung des Musters von Kachel zu Kachel variieren, können wir eine unendliche Menge von Designs erzeugen.

Schaue Die die Funktion rotateTilePattern() genau an. Sie unterteilt den Raum jeweils in vier Zellen und dreht jede davon in eine unterschiedliche Richtung.

Erschaffe Deine eigenen Regeln

Prozedurale, sich wiederholende Muster zu kreieren, ist eine interessante Übung für den Geist. Es geht darum, den minimalen Satz an Elementen zu finden, die sich wiederholen müssen, um ein größeres komplexes Ganzes zu erschaffen. Diese Vorgehensweise ist sehr alt. Die Menschheit benutzt Muster und Gitternetze schon seit tausenden von Jahren, um Wände und Böden, Textilien und andere Objekte zu verzieren. Angefangen von mäandernden Mustern im alten Griechenland bis hin zu chinesischen Gitterfenstern, ist es immer wieder das Spiel aus Wiederholung bei gleichzeitiger Variation, die unsere Fantasie anregt. Nimm Dir ein wenig Zeit, um diese Art von Dekorationen und Mustern zu studieren. Von geometrischen Mustern aus Arabien bis hin zu prachtvollen Stoffmustern aus dem afrikanischem Kulturkreis eröffnet sich Dir ein ganzes Universum an Mustern, von denen Du lernen kannst.

Franz Sales Meyer – Handbuch der Ornamentik (1920)

Mit diesem Kapitel enden die Abschnitte zum algorithmischen Zeichnen. In den folgenden Kapiteln werden wir sehen, wie man ein wenig mehr Zufall in unsere Shader bringt, um die Natur nachzuempfinden.