Merge pull request #116 from MITI67/master
Four german translated files updated, characeter set was wrong (not UTF-8)pull/119/head^2
commit
5b64cf8ac4
@ -0,0 +1,50 @@
|
||||
# Einleitung
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="cmyk-halftone.frag" data-textures="vangogh.jpg" width="700px" height="320px"></canvas>
|
||||
|
||||
Die oben abgebildeten Grafiken wurden auf ganz unterschiedliche Weise erstellt. Die linke Abbildung stammt aus den Händen des Malers Van Gogh, der die Farben in stundenlanger Arbeit Schicht für Schicht mit einem Pinsel aufgetragen hat. Die rechte Abbildung wurde dagegen innerhalb von Sekundenbruchteilen mit Hilfe von vier Punktmatrizen erzeugt: eine für Cyan, eine für Magenta, eine für Gelb und eine für Schwarz. Der entscheidende Unterschied: Das zweite Bild wurde nicht seriell erstellt, d.h. Strich für Strich, sondern parallel, alle Punkte zur gleichen Zeit.
|
||||
|
||||
Dieses Buch handelt von einer Computertechnik mit Namen *Fragment Shader*, die die digitale Erzeugung von Bildern revolutioniert und zu neuen Höhen geführt hat. Man kann ihre Erfindung ein wenig vergleichen mit dem Schritt von der manuellen Vervielfältigung einzelner Grafiken und Dokumente hin zur massenhaften Replikation durch Gutenbergs Druckerpresse.
|
||||
|
||||
![Gutenbergs Druckerpresse](gutenpress.jpg)
|
||||
|
||||
Fragment-Shader ermöglichen die vollständige Kontrolle über alle Bildpunkte, die als Grafik auf dem Bildschirm erscheinen. Und das mit ungeheurer Geschwindigkeit. Deshalb wird diese Technik mittlerweile in vielen Bereichen der Computergrafik angewandt, von Videofiltern auf Smartphones bis hin zu den neuesten fotorealistisch wirkenden 3D-Videospielen.
|
||||
|
||||
![Grafik aus dem Spiel „Journey“ von That Game Company](journey.jpg)
|
||||
|
||||
Die folgenden Kapitel wollen Dir zeigen, wie unglaublich schnell und leistungsfähig diese Technik ist, und wie Du sie im Rahmen von privaten und beruflichen Projekten einsetzen kannst.
|
||||
|
||||
## Für wen ist dieses Buch geeignet?
|
||||
|
||||
Dieses Buch wendet sich an kreative Programmierer, Spieleentwickler und Ingenieure, die bereits über eine gewisse Programmiererfahrung, sowie grundlegende Kenntnisse aus den Bereichen der Linearen Algebra und der Trigonometrie verfügen. (Falls Du erst noch Programmieren lernen möchtest, empfehle ich Dir, mit [Processing](https://processing.org/) zu beginnen und anschließend mit diesem Buch fortzufahren.)
|
||||
|
||||
Die folgenden Kapitel werden Dir zeigen, wie Du Shader in Deinen Projekten einsetzen kannst, um die Qualität und die Geschwindigkeit bei der Erzeugung von Grafiken zu verbessern. GLSL-Shader (GLSL steht für „OpenGL Shading Language“) lassen sich auf einer Vielzahl von Hardwareplattformen und Betriebssystemen kompilieren und ausführen. Dadurch kannst Du das erlernte Wissen in jeder Umgebung einsetzen, die OpenGL, OpenGL ES oder WebGL unterstützt.
|
||||
|
||||
In anderen Worten, Du kannst Dein Know-how u.a. beim Malen mit [Processing](https://processing.org/), bei Anwendungen für [openFrameworks](http://openframeworks.cc/), interaktiven Installationen mit [Cinder](http://libcinder.org/), Webseiten mit [Three.js](http://threejs.org/) oder bei Spielen für iOS/Android nutzen.
|
||||
|
||||
## Welchen Aspekten widmet sich dieses Buch?
|
||||
|
||||
Dieses Buch konzentriert sich auf den Einsatz von GLSL-Pixel-Shadern. Zunächst erklären wir, was Shader sind, dann wenden wir uns der algorithmischen Erzeugung von Formen, Mustern, Texturen und Animationen zu. Du lernst die Grundlagen der Programmiersprache für OpenGL-Shader kennen und erfährst, wie man sie für konkrete Zwecke nutzt. Dazu zählt die Bildbearbeitung (Bildmanipulationen, Matrizenoperationen, Farbfilter und weitere Effekte), sowie Simulationen (Conways Game of Life, Reaktion und Diffusion von Chemikalien nach Gray-Scott, Erzeugung von Wasserwellen, die Nachbildung des Malens mit Wasserfarben, Erzeugung von Voronoi-Zellen und mehr). Zum Ende des Buches hin lernst Du fortschrittliche Techniken kennen, bei denen etwa mit Hilfe des sogenannten "Ray Marchings" beeindruckende 2D-Grafiken aus 3D-Daten generiert werden.
|
||||
|
||||
*In jedem Kapitel gibt es interaktive Beispiele, mit denen Du vieles ausprobieren kannst.* Sobald du etwas am Programmcode änderst, erscheinen die daraus resultierenden Veränderungen an der erzeugten Grafik sofort auf dem Bildschirm. Die vorgestellten Konzepte sind teilweise abstrakt und auf den ersten Blick vielleicht ein wenig verwirrend. Aber mit Hilfe der interaktiven Beispiele kannst Du den Lernstoff leicht nachvollziehen. Je mehr Du ausprobierst, desto einfacher wird Dir das Lernen fallen.
|
||||
|
||||
Was dieses Buch nicht behandelt:
|
||||
|
||||
* Dies *ist kein * Buch über openGL oder webGL. OpenGL/webGL ist ein umfassenderes Thema als GLSL- oder Fragment-Shader. Wenn Du mehr über openGL/webGL lernen möchtest, empfehle ich Dir die folgenden Materialien: [OpenGL Einführung (Englisch)](https://open.gl/introduction), [Die achte Ausgabe des "OpenGL Programming Guide" (Englisch)](http://www.amazon.com/OpenGL-Programming-Guide-Official-Learning/dp/0321773039/ref=sr_1_1?s=books&ie=UTF8&qid=1424007417&sr=1-1&keywords=open+gl+programming+guide) (auch bekannt als das "Red Book")) oder ["WebGL: Up and Running" (Englisch)](http://www.amazon.com/WebGL-Up-Running-Tony-Parisi/dp/144932357X/ref=sr_1_4?s=books&ie=UTF8&qid=1425147254&sr=1-4&keywords=webgl)
|
||||
|
||||
* Das vorliegende Werk *ist außerdem kein* Mathematik-Buch. Obwohl wir bei vielen Techniken und Algorithmen auf Algebra und Trigonometrie zurückgreifen, werden die mathematischen Grundlagen nicht an jeder Stelle vollständig in allen Details erklärt. Bei Fragen dazu empfehle ich Dir eines der folgenden Bücher: [Dritte Ausgabe von "Mathematics for 3D Game Programming and Computer Graphics" (Englisch)](http://www.amazon.com/Mathematics-Programming-Computer-Graphics-Third/dp/1435458869/ref=sr_1_1?ie=UTF8&qid=1424007839&sr=8-1&keywords=mathematics+for+games) oder [Zweite Ausgabe von "Essential Mathematics for Games and Interactive Applications" (Englisch)](http://www.amazon.com/Essential-Mathematics-Games-Interactive-Applications/dp/0123742978/ref=sr_1_1?ie=UTF8&qid=1424007889&sr=8-1&keywords=essentials+mathematics+for+developers).
|
||||
|
||||
## Was benötigst Du, um loszulegen?
|
||||
|
||||
Nicht viel! Wenn Du auf Deinem Rechner, Smartphone oder Tablet einen modernen Webbrowser hast, der WebGL unterstützt (etwa Chrome, Firefox oder Safari), und eine Internetverbindung besteht, dann drücke einfach auf die Schaltfläche für das nächste Kapitel am Ende dieser Seite, um zu beginnen.
|
||||
|
||||
Alternativ kannst Du auch:
|
||||
|
||||
- [Eine Offline-Fassung dieses Buches erstellen](https://thebookofshaders.com/appendix/)
|
||||
|
||||
- [Die Beispielprogramme aus diesem Buch direkt auf einem RaspberryPi ausführen (ohne Internet-Browser)](https://thebookofshaders.com/appendix/)
|
||||
|
||||
- [Eine PDF-Datei mit diesem Buch erzeugen, um es auszudrucken](https://thebookofshaders.com/appendix/)
|
||||
|
||||
- Die [Online-Ablage dieses Buches](https://github.com/patriciogonzalezvivo/thebookofshaders) bei GitHub nutzen, um Fehler zu melden und Programmcode mit anderen Lesern zu teilen.
|
||||
|
@ -0,0 +1,48 @@
|
||||
# Einstieg
|
||||
## Was ist ein Fragment-Shader?
|
||||
|
||||
Im vorangegangenen Kapitel haben wir Fragment-Shader als eine Art Gutenbergsche Druckerpresse für Grafiken beschrieben. Nun, wie kommen wir darauf? Und vor allem: Was genau soll das sein, ein „Shader“?
|
||||
|
||||
![Von Brief-für-Brief zu Seite-für-Seite. Rechts: William Blades (1891), links Rolt-Wheeler (1920).](print.png)
|
||||
|
||||
Falls Du schon Erfahrung mit der Erstellung von Computergrafiken gesammelt hast, kennst Du bestimmt die folgende Vorgehensweise: Man malt per Programmbefehl Kreise, Rechtecke, Dreiecke und Linien, damit auf dem Bildschirm nach und nach die gewünschte Grafik entsteht. Dieser Prozess erinnert stark an das Verfassen eines Dokuments per Hand, indem man einzelne Zeichen-Operationen Schritt für Schritt abarbeitet.
|
||||
|
||||
Auch Shader verkörpern eine Abfolge von Operationen, doch hier werden diese Operationen gleichzeitig für jeden Bildpunkt (Pixel) auf der Zeichenfläche ausgeführt. Das hat zur Folge, dass der Programmcode des Shaders in Abhängigkeit von der Lage des jeweils bearbeiteten Bildpunktes unterschiedlich agieren muss. Der Shader arbeitet dabei als eine Funktion, die die Koordinaten des jeweiligen Bildpunktes erhält und als Ergebnis die Farbe für diesen Bildpunkt zurückliefert. Ist der Shader einmal kompiliert, läuft dieser Prozess unglaublich schnell und für sehr viele Bildpunkte gleichzeitig ab.
|
||||
|
||||
![Verschiebbare Lettern mit Chinesischen Symbolen](typepress.jpg)
|
||||
|
||||
## Warum arbeiten Shader schnell?
|
||||
|
||||
Diese Frage beantwortet sich, wenn wir uns das Prinzip der *parallelen Verarbeitung* anschauen.
|
||||
|
||||
Stelle Dir den Prozessor in Deinem Computer als eine große Pipeline vor und jede zu bearbeitende Aufgabe als etwas, das durch die Pipeline fließt - wie an einem Fließband innerhalb einer Fabrik. Einige Aufgaben sind größer als andere, weshalb ihre Abarbeitung mehr Zeit und mehr Energie in Anspruch nimmt. Wir sagen dann, diese Aufgaben benötigen mehr „Prozessorleistung“. Der Aufbau des Computers zwingt die verschiedenen Aufgaben dazu, eine nach der anderen durch die Pipeline zu strömen. Die nächste Aufgabe ist an der Reihe, sobald die vorangehende Aufgabe erfolgreich abgearbeitet wurde. Moderne Prozessoren verfügen in der Regel über mehrere Kerne (typischerweise zwei, vier oder acht), von denen jeder wie eine Pipeline arbeitet, so dass mehrere Ströme von Aufgaben (engl. „Threads“) gleichzeitig abgearbeitet werden können.
|
||||
|
||||
![CPU](00.jpeg)
|
||||
|
||||
Videospiele und leistungsstarke Grafikanwendungen benötigen in der Regel wesentlich mehr Prozessorleistung als andere Computerprogramme. Weil sie grafikorientiert arbeiten, müssen diese Programme eine enorme Anzahl an Pixel-Operationen ausführen. Jeder einzelne Bildpunkt muss individuell berechnet werden, und bei 3D-Anwendungen kommen noch perspektivische Verzerrungen sowie das Spiel von Licht und Schatten hinzu.
|
||||
|
||||
Kommen wir noch einmal auf das Bild einer Pipeline zurück. Jeder einzelne Bildpunkt verkörpert eine Rechenaufgabe, die durch die Pipeline abgearbeitet werden muss. Einzeln genommen macht das nicht viel Arbeit - der enorme Aufwand entsteht erst durch die schiere Masse an Pixeln auf dem Bildschirm. Schon bei einer Auflösung von 800 x 600 Bildpunkten müssen pro Bild 480.000 Pixels berechnet werden. Für eine flüssige Darstellung mit 30 Bildern pro Sekunde ergeben sich also bereits 14.400.000 Berechnungen pro Sekunde. Das ist eine Dimension, bei der auch moderne Prozessoren an ihre Grenzen stoßen. Und bei einem hochauflösenden Retina-Display mit 2880 x 1800 Bildpunkten und einer Wiederholrate von 60 Bildern pro Sekunde kommen sogar 311.040.000 Berechnungen pro Sekunde zusammen. Fragt sich also, wie ein Computersystem dies bewältigen kann?
|
||||
|
||||
![](03.jpeg)
|
||||
|
||||
Hier kommt die gleichzeitige - parallele - Berechnung möglichst vieler Bildpunkte ins Spiel. An die Stelle weniger großer und immens leistungsfähiger Pipelines (sprich: Mikroprozessoren) treten viele kleine, einfachere Prozessoren, die parallel arbeiten. Sie bilden den Kern einer sogenannten „Graphic Processing Unit“, kurz GPU.
|
||||
|
||||
![GPU](04.jpeg)
|
||||
|
||||
Stelle Dir eine solche GPU wie ein Feld aus lauter Pipelines vor - eine neben der anderen. Jeder Bildpunkt entspricht einem Tischtennisball, der durch eine solche Pipeline hindurchmuss. 14.400.000 Bälle pro Sekunde sind wahrscheinlich zu viel für jede einzelne noch so dicke Pipeline. Hat man aber ein Feld aus 800 x 600 kleinen Pipelines, muss jede nur 30 Bälle pro Sekunde verarbeiten, damit man eine flüssige Darstellung auf dem Bildschirm erhält. Und das ist durchaus machbar. Gleiches gilt für höhere Auflösungen und größere Bildwiederholraten: Je mehr Pipelines parallel arbeiten, desto mehr Bildpunkte können sie pro Zeiteinheit bewältigen.
|
||||
|
||||
Die enorme Leistung einer solchen GPU rührt aber auch aus einer anderen Quelle: Viele für die Grafikberechnung unverzichtbare mathematische Operationen lassen sich direkt in der Hardware, in jeder einzelnen Pipeline, parallel ausführen. Es wird also keine zusätzliche Software benötigt, um diese Berechnungen in mehreren Schritten aus einfachen Grundoperationen zusammenzusetzen. Das gilt beispielsweise für die wichtigen Trigonometrischen Funktionen und für Matrizenoperationen. Das bringt die Darstellung zusätzlich auf Trab.
|
||||
|
||||
## Was ist GLSL?
|
||||
|
||||
GLSL ist die Abkürzung für „OpenGL Shading Language“, einem weit verbreiteten Standard für Shader-Programme, mit dem sich die folgenden Kapitel beschäftigen. Es gibt auch andere Arten von Shadern, je nach Grafikhardware und Betriebssystem. Wir orientieren uns hier an der wichtigen OpenGL-Spezifikation, die von der [Khronos Gruppe](https://www.khronos.org/opengl/) erarbeitet wurde. Wenn man die Geschichte von OpenGL kennt, kann man einige der teilweise etwas merkwürdigen Konstrukte und Konventionen besser verstehen. Allen Interessierten empfehle ich deshalb einen Blick auf [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html).
|
||||
|
||||
## Warum sind Shader so anspruchsvoll?
|
||||
|
||||
Mein reicher Onkel Willi aus Amerika sagte früher immer zu mir: „Denk dran, Junge, unglaublich viel Power bedeutet immer auch unglaublich viel Verantwortung“. Dies gilt in gewisser Weise auch für das Feld des „Parallel Computings“. Die enorme Leistungsfähigkeit moderner GPUs erzeugt ihre eigenen Regeln und Abhängigkeiten. Und die wollen beachtet werden, damit wir nicht über das Ziel hinausschießen.
|
||||
|
||||
Damit jede Pipeline innerhalb der GPU parallel an ihrer Aufgabe arbeiten kann, muss sie unabhängig von den anderen Pipelines sein. Sie ist quasi blind dafür, was die anderen gerade tun. Dies bringt u.a. die Einschränkung mit sich, dass alle Daten nur in eine Richtung fließen können. Es ist praktisch unmöglich, auf die Ergebnisse einer anderen Pipeline einzugehen, deren Ergebnis abzurufen und damit eine dritte Pipeline zu füttern.
|
||||
|
||||
Außerdem hält die GPU ihre zahlreichen Mikroprozessoren (Pipelines) ständig beschäftigt. Sobald eine Pipeline mit der Berechnung der Farbe für einen Bildpunkt fertig ist, wird sie auch schon mit dem nächsten Bildpunkt „gefüttert“. Aus Sicht des Shader-Programms gibt es quasi kein Vorher und Nachher, sondern immer nur den aktuell zu berechnenden Bildpunkt. Das Shader-Programm in jeder Pipeline ist also nicht nur blind für alle anderen, sondern auch ohne Erinnerung für das Gewesene. Das ist ein Teil der Herausforderung, die die Entwicklung von Shadern bei Programmieranfängern nicht unbedingt beliebt macht.
|
||||
|
||||
Aber keine Angst! In den folgenden Kapiteln werden wir uns Schritt für Schritt von einfachen Shadern hin zu komplexen Shadern voran arbeiten. Sofern Du diesen Text mit einem modernen Browser liest, wirst Du ganz einfach mit den zahlreichen interaktiven Beispielprogrammen experimentieren können. Also, lass uns gleich anfangen, indem Du auf die „Next“-Schaltfläche unten auf der Seite klickst.
|
@ -0,0 +1,53 @@
|
||||
## Hallo Welt
|
||||
|
||||
Beim Erlernen einer neuen Programmiersprache beginnt man häufig mit dem berühmten „Hello world!“-Beispiel. Dabei handelt es sich um einen simplen Einzeiler, der die Meldung „Hello world!“ auf den Bildschirm bringt - als Gruß an die Welt und als Ausdruck der Vorfreude auf die kommenden Möglichkeiten.
|
||||
|
||||
In der Welt der Shader-Programmierung ist die Textausgabe eine zu komplizierte Angelegenheit, um gleich damit zu beginnen. Stattdessen wollen wir eine leuchtende Farbe als Willkommensgruß auf den Bildschirm zaubern.
|
||||
|
||||
<div class="codeAndCanvas" data="hello_world.frag"></div>
|
||||
|
||||
Falls Du dieses Buch in einem Internet-Browser liest, ist der obige Programmcode interaktiv. Du kannst in das Listing hineinklicken und jeden Teil des Programmcodes ändern. Deine Änderungen werden sofort innerhalb der Zeichenfläche sichtbar, weil der Shader-Code automatisch kompiliert und ausgeführt wird. Versuche es doch einfach einmal, indem Du die Zahlenwerte in der *Programmzeile 6* änderst.
|
||||
|
||||
Obwohl diese wenigen, einfachen Programmzeilen noch nicht nach viel aussehen, können wir daraus bereits einige Erkenntnisse gewinnen:
|
||||
|
||||
1. Shader-Programme verfügen über genau eine ```main```-Funktion, die an ihrem Ende einen Farbcode zurückliefert. Das erinnert stark an die Programmiersprache C, nur dass es dort nicht immer um Farbcodes geht.
|
||||
|
||||
2. Der berechnete Farbwert wird für die Rückgabe in die reservierte globale Variable ```gl_FragColor``` eingetragen.
|
||||
|
||||
3. Die stark von C beeinflusste Programmiersprache für Shader verfügt über eingebaute *Variablen* (so wie ```gl_FragColor```), *Funktionen* und *Datentypen*. Im obigen Beispiel sehen wir bereits den Datentyp ```vec4```, der einen vierdimensionalen Vektor aus Fließkommazahlen repräsentiert. Im weiteren Verlauf des Buches werden wir noch die Typen ```vec3``` und ```vec2``` kennen lernen, ebenso die wichtigen Typen ```float```, ```int``` und ```bool```.
|
||||
|
||||
4. Wenn wir uns den ```vec4``` Datentyp im obigen Beispiel genau anschauen, können wir bereits erahnen, dass die vier Zahlenwerte für die Farbkanäle Rot, Grün, Blau und Alpha (ein Maß für die Deckkraft) stehen. Außerdem erkennen wir, dass diese Werte offensichtlich normalisiert sind, sich also zwischen ```0.0``` und ```1.0``` bewegen. Später werden wir noch sehen, dass es uns diese Normalisierung vereinfacht, die Inhalte von Variablen auf Farbwerte *abzubilden*.
|
||||
|
||||
5. Eine weiteres aus C bekanntes Element sind die Präprozessor-Makros, die auch in unserem obigen Beispiel auftauchen. Mit ihrer Hilfe lassen sich Konstanten definieren (```#define```) und konditionale Festlegungen treffen (mit ```#ifdef``` und ```#endif```). Alle diese Makrobefehle beginnen mit einer Raute (```#```). Ihre Auswertung erfolgt als erster Schritt noch vor der eigentlichen Kompilierung des Shaders. Das Ergebnis dieser Auswertung bestimmt jeweils, welche Zeilen und Ausdrücke tatsächlich in den Programmcode einfließen, der anschließend kompiliert wird. In unserem obigen Beispiel wird die *Programmzeile 2* beispielsweise nur dann übernommen, wenn das Symbol ```GL_ES``` definiert ist. Dies ist in der Regel nur in Umgebungen auf mobilen Geräten der Fall, d.h. wenn das obige Programm beispielsweise auf einem Smartphone kompiliert wird, ist die Zeile 2 darin vorhanden und wirkt sich entsprechend aus. Beim Kompilieren auf einem Laptop oder PC taucht die Zeile 2 aber gar nicht auf, weil dort auch das Symbol ```GL_ES``` nicht definiert ist.
|
||||
|
||||
6. Fließkomma-Datentypen sind ganz entscheidend für die Berechnungen innerhalb von Shadern. Deshalb spielt die *Genauigkeit* dieser Operationen eine wichtige Rolle. Eine geringere Genauigkeit bedeutet weniger Aufwand und geht deshalb mit einer schnelleren Berechnung einher. Der Preis dafür sind allerdings Einbußen bei der Qualität der Berechnungen. Wenn man will, kann man die Genauigkeit jeder einzelnen Fließkommavariablen genau festlegen. Meist unterscheidet man jedoch grundsätzlich, je nach den Möglichkeiten der Plattform, auf der ein Shader zur Ausführung kommen soll. So setzen wir hier in der zweiten Programmzeile die Genauigkeit auf Medium (```precision mediump float;```), wenn der Shader auf einem Mobilgerät kompiliert wird. Darüber hinaus gibt es noch die Genauigkeitsstufen „niedrig“ (```precision lowp float;```) und „hoch“ (```precision highp float;```). Letzteres ist auf vielen Plattformen die Vorgabe, sofern wir nichts Anderes festlegen.
|
||||
|
||||
7. Die letzte und für die Praxis vielleicht wichtigste Erkenntnis aus dem obigen Programmcode ist, dass wir Fließkommawerte immer mit einem Punkt („.“) versehen sollten, auch wenn der Nachkommateil leer bleibt (Null ist). Denn sonst macht der Compiler möglicherweise Integer-Werte (Ganzzahlen) daraus, und das kann während der Ausführung des Shaders zu hässlichen Programmfehlern führen. Die Zeichenfläche bleibt dann einfach weiß, weil es nicht weitergeht. Wenn du guten und auf vielen Shader-Plattformen ausführbaren Code entwickeln möchtest, gewöhne Dir die Kennzeichnung als Fließkommazahl durch den Punkt am besten gleich an. Denn der folgende Programmcode wird beispielsweise auf einigen Shader-Plattformen funktionieren, auf anderen hingegen nicht:
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
gl_FragColor = vec4(1,0,0,1); // FEHLERQUELLE!
|
||||
}
|
||||
```
|
||||
|
||||
So, wo wir nun die wichtigen Elemente unseres kleinen „Hello world!“-Programms beschrieben haben, ist es an der Zeit, mit Veränderungen am Programmcode zu experimentieren. Du wirst feststellen, dass sich das Programm bei Syntaxfehlern oder unbekannten Befehlen weigert, zu kompilieren, und die Zeichenfläche deshalb weiß bleibt. Es gibt einige interessante Dinge, die Du direkt einmal ausprobieren kannst, beispielsweise:
|
||||
|
||||
* Versuche, die Fließkommazahlen durch Ganzzahlen zu ersetzen. Dann wirst Du unmittelbar feststellen, ob Deine aktuelle Umgebung/Grafikkarte damit umgehen kann.
|
||||
|
||||
* Versuche, die *Programmzeile 6* auszukommentieren, und schau was passiert, wenn der Code dadurch keinen Farbwert zurückliefert.
|
||||
|
||||
* Versuche, eine zusätzliche Funktion in den Programmcode einzufügen, die eine von Dir gewählte Farbe zurückliefert und rufe diese Funktion innerhalb von ```main()``` auf. Dazu ein Tipp: Hier folgt der Programmcode für eine Funktion, die Rot zurückliefert:
|
||||
|
||||
```glsl
|
||||
vec4 red(){
|
||||
return vec4(1.0,0.0,0.0,1.0);
|
||||
}
|
||||
```
|
||||
|
||||
* Es gibt verschiedene Wege, um einen Wert vom Typ ```vec4``` zu konstruieren. Versuche, weitere Wege zu entdecken. So geht es zum Beispiel auch:
|
||||
|
||||
```glsl
|
||||
vec4 color = vec4(vec3(1.0,0.0,1.0),1.0);
|
||||
```
|
||||
|
||||
Obwohl dieses „Hello world!“-Programm noch nicht so wahnsinnig aufregend daherkommt, ist es doch das simpelste Beispiel aus der Welt der Shader. Wir beeinflussen damit die Farbe aller Bildpunkte innerhalb unserer Zeichenfläche. In den nun folgenden Kapiteln werden wir die Farbe der einzelnen Bildpunkte aufgrund von zwei unterschiedlichen Arten von Eingabewerten steuern: Ihrer Position (d.h die Lage eines zu bearbeitenden Pixels innerhalb der Zeichenfläche) und der Zeit (d.h. der Zeitspanne, die seit dem Laden einer Seite vergangen ist).
|
@ -0,0 +1,61 @@
|
||||
## Uniforms
|
||||
|
||||
Wir haben bereits gesehen, wie die GPU eine große Anzahl von parallelen Aufgaben (engl. *Threads*) verwaltet. Jeder Thread übernimmt die Berechnung des Farbwerts für einen Pixel, also für einen kleinen Teil der gesamten Grafik. Obwohl er dabei blind für die anderen Threads ist, muss es einen Weg geben, wie die CPU bestimmte Daten an alle Threads übermitteln kann. Aufgrund der Architektur einer Grafikkarte müssen diese Daten für alle ausgeführten Threads einheitlich (engl. *uniform*) und nur lesbar (engl. *read-only*) sein. Jeder Thread erhält also die gleichen Daten, die er nicht verändern kann.
|
||||
|
||||
Man bezeichnet diese Daten deshalb als ```uniform```. Es gibt sie in den wichtigsten Datentypen, die GLSL unterstützt: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` und ```samplerCube```. Uniforms werden gemeinsam mit ihrem jeweiligen Datentyp am Anfang eines Shader-Programms definiert, sofern man darauf Bezug nehmen möchte. Dies geschieht in der Regel gleich nachdem man die gewünschte Genauigkeit für alle Fließkommaoperationen in dem Programm festgelegt hat.
|
||||
|
||||
```glsl
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution; // Groesse der Malfläche (canvas) in Pixeln (Breite, Hoehe)
|
||||
uniform vec2 u_mouse; // Mausposition über der Malfleache in Pixeln (X, Y)
|
||||
uniform float u_time; // Zeit in Sekunden seit dem Start des Bildaufbaus
|
||||
```
|
||||
|
||||
Man kann sich Uniforms als eine Brücke zwischen der CPU und der GPU vorstellen. Ihre Bezeichnung hängt von der jeweiligen Implementation der GLSL-Umgebung ab. Im Rahmen dieses Buches verwenden wir die folgenden Namen: ```u_time``` , ```u_resolution``` und ```u_mouse```. Wir folgen damit der Konvention, die Variablennamen jeweils mit dem Präfix ```u_``` beginnen zu lassen, damit sie im Programmcode deutlich als Uniforms erkennbar sind. In anderen Umgebungen für die Entwicklung von Shadern tragen sie andere Namen, wie beispielsweise bei [ShaderToy.com](https://www.shadertoy.com/). Dort heißt es:
|
||||
|
||||
```glsl
|
||||
uniform vec3 iResolution; // Groesse der Malflaeche
|
||||
uniform vec4 iMouse; // Mausposition
|
||||
uniform float iGlobalTime; // Zeit seit dem Start
|
||||
```
|
||||
|
||||
Aber nun genug geredet. Lass uns die Uniforms in Aktion betrachten. Der folgende Programmcode nutzt ```u_time``` - die Anzahl der Sekunden, seitdem der Shader gestartet wurde - in Verbindung mit einer Sinus-Funktion, um die Intensität der Rotfärbung der Malfläche pulsieren zu lassen.
|
||||
|
||||
<div class="codeAndCanvas" data="time.frag"></div>
|
||||
|
||||
Wie Du siehst, hält GLSL noch einige Überraschungen bereit. Die GPU unterstützt in der Hardware realisierte Winkel-, Trigonometrie- und Exponential-Funktionen. Hier einige dieser Funktionen im Überblick: [```sin()```](../glossary/?search=sin), [```cos()```](../glossary/?search=cos), [```tan()```](../glossary/?search=tan), [```asin()```](../glossary/?search=asin), [```acos()```](../glossary/?search=acos), [```atan()```](../glossary/?search=atan), [```pow()```](../glossary/?search=pow), [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log), [```sqrt()```](../glossary/?search=sqrt), [```abs()```](../glossary/?search=abs), [```sign()```](../glossary/?search=sign), [```floor()```](../glossary/?search=floor), [```ceil()```](../glossary/?search=ceil), [```fract()```](../glossary/?search=fract), [```mod()```](../glossary/?search=mod), [```min()```](../glossary/?search=min), [```max()```](../glossary/?search=max) sowie [```clamp()```](../glossary/?search=clamp).
|
||||
|
||||
Nun ist es an der Zeit, mit dem obigen Shader zu experimentieren.
|
||||
|
||||
* Versuche, die Frequenz zu verlangsamen, mit der sich die Rotfärbung ändert, bis dieser Prozess kaum noch wahrnehmbar ist.
|
||||
|
||||
* Beschleunige die Frequenz, bis man fast nur noch eine Farbe sieht.
|
||||
|
||||
* Experimentiere mit periodischen Änderungen auch in den anderen Farbkanälen (Grün und Blau), so dass sich interessante Farbspiele und Muster ergeben.
|
||||
|
||||
## gl_FragCoord
|
||||
|
||||
So, wie GLSL das Resultat eines Shader-Durchlaufs standardmäßig in der Variable ```vec4 gl_FragColor``` erwartet, liefert es uns auch standardmäßig einen Eingabewert: Die Koordinate des jeweils zu bearbeitenden Bildpunkts in der Variable ```vec4 gl_FragCoord```. Im Englischen spricht man in diesem Zusammenhang auch von einem *screen fragment*. Diese Variable kann man nicht als ```uniform``` bezeichnen, weil ihr Inhalt bzw. Wert mit jedem Shader-Durchlauf variiert. Man spricht deshalb auch von einem *varying*.
|
||||
|
||||
<div class="codeAndCanvas" data="space.frag"></div>
|
||||
|
||||
Im obigen Programmcode *normalisieren* wir zunächst die Koordinate des zu bearbeitenden Fragments, indem wir sie durch die Auflösung der Zeichenfläche teilen. Auf diese Weise bilden wir die *X-* und *Y-Ordinate* jeweils auf den Wertebereich zwischen ```0.0``` und ```1.0``` ab. Das erleichtert es uns, diese Ordinaten auf Farbwerte für den Rot- und den Grün-Kanal zu übertragen. Schließlich müssen sich diese auch immer jeweils zwischen ```0.0``` und ```1.0``` bewegen.
|
||||
|
||||
In der Welt der Shader-Programmierung haben wir nicht so viele Möglichkeiten zum Debugging, abgesehen davon, dass wir dem gerade berechneten Bildpunkt intensive Farbtöne zuweisen können. Das entstehende Bild lässt dann Rückschlüsse auf die Abläufe innerhalb des Shaders zu. Du wirst im Laufe dieses Buches entdecken, dass die Shader-Programmierung manchmal dem Versuch gleicht, ein Modellschiff in eine Flasche zu pressen. Denn das ist gleichermaßen schwierig, aber auch schön anzusehen und in jedem Fall lohnend.
|
||||
|
||||
![](08.png)
|
||||
|
||||
Jetzt ist es an der Zeit für eine kleine Herausforderung in Bezug auf das Verständnis des obigen Programmcodes.
|
||||
|
||||
* Kannst du ausmachen, wo sich die Koordinate ```(0.0,0.0)``` innerhalb unserer Zeichenfläche befindet?
|
||||
|
||||
* Und wo liegen wohl die Koordinaten ```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` und ```(1.0,1.0)```? Die Farben der jeweiligen Bildpunkte verraten es Dir!
|
||||
|
||||
* Gelingt es Dir, die aktuelle Mausposition aus dem Uniform ```u_mouse``` einzubeziehen? Denke daran, dass sich die Angaben in dieser Uniform auf Pixel beziehen und zunächst nicht normalisiert sind. Kannst Du den Programmcode so gestalten, dass die erzeugten Farben auf die Mausbewegung reagieren?
|
||||
|
||||
* Fällt Dir ein Weg ein, wie man die Farbgestaltung auf interessante Weise durch die Einbeziehung von ```u_time``` und ```u_mouse``` dynamisieren kann?
|
||||
|
||||
Nach all diesen Übungen fragst Du Dich vielleicht, wo Du Deine neuen Shader-Kenntnisse sonst noch ausprobieren kannst. Im folgenden Kapitel zeigen wir, wie man Shader in *three.js*, *Processing* und *openFrameworks* zum Laufen bringt.
|
@ -0,0 +1,190 @@
|
||||
## Ausführung Deiner Shader
|
||||
|
||||
Beim Schreiben dieses Buches und im Rahmen meiner künstlerischen Tätigkeit habe ich eine Sammlung von Tools entwickelt, mit deren Hilfe man Shader programmieren, anzeigen, teilen und kuratieren kann. Dieses Tools laufen auf Linux Desktops, Rechnern mit MacOS, dem [RaspberryPi](https://www.raspberrypi.org/) und auf Internet-Browsern. Sie sorgen dafür, dass Du Deine Shader dort nutzen kannst, ohne etwas an deren Programmcode verändern zu müssen.
|
||||
|
||||
**Anzeige**: Alle Live-Beispiele in diesem Buch werden mit [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) angezeigt. Dieses Tool macht es unglaublich einfach, Shader ohne weitere Umstände im Internet-Browser auszuführen.
|
||||
|
||||
```html
|
||||
<canvas class="glslCanvas" data-fragment-url="yourShader.frag" data-textures="yourInputImage.png" width="500" height="500"></canvas>
|
||||
```
|
||||
|
||||
Wie Du oben siehst, benötigt man lediglich ein ```canvas``` HTML-Element mit der Klassenzuweisung ```class="glslCanvas"``` und eine URL als Verweis auf Deine Shader-Datei im Attribut ```data-fragment-url```. Mehr darüber kannst Du [hier](https://github.com/patriciogonzalezvivo/glslCanvas) erfahren.
|
||||
|
||||
Vielleicht geht es Dir wie mir, und Du möchtest Deine Shader direkt aus der Kommandozeile starten. In diesem Fall solltest Du Dir einmal den [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) anschauen. Diese Anwendung ermöglicht es Dir, Shader aus ```bash```-Skripten oder aus der Unix-Pipeline heraus zu starten, ganz ähnlich wie dies mit [ImageMagick](http://www.imagemagick.org/script/index.php) möglich ist. Außerdem bietet der [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) eine großartige Möglichkeit, Shader auf Deinem [RaspberryPi](https://www.raspberrypi.org/) zu kompilieren. Das ist auch der Grund, warum das Projekt [openFrame.io](http://openframe.io/) dieses Tool für die Präsentation von Computerkunst nutzt. Mehr über diese Anwendung kannst Du [hier](https://github.com/patriciogonzalezvivo/glslViewer) erfahren.
|
||||
|
||||
```bash
|
||||
glslViewer deinShader.frag deineEingabeGrafik.png -w 500 -h 500 -s 1 -o deineAusgabeGrafik.png
|
||||
```
|
||||
|
||||
**Entwickeln**: Um die Entwicklung von Shadern im Internet-Browser zu ermöglichen, habe ich einen Online-Editor mit dem Namen [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor) entwickelt. Dieser Editor kommt bei den Live-Beispielen in diesem Buch zum Einsatz. Er bringt eine Reihe praktischer Widgets mit, die Dich beim Experimentieren mit dem Shader-Code unterstützen. Du kannst diesen Editor auch als eigenständige Web-Anwendung über die URL [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/) ausführen lassen. Mehr über diesen Editor erfährst Du [hier](https://github.com/patriciogonzalezvivo/glslEditor).
|
||||
|
||||
![](glslEditor-01.gif)
|
||||
|
||||
Wenn Du lieber offline statt online mit [SublimeText](https://www.sublimetext.com/) arbeitest, kannst Du dieses [Paket für den glslViewer](https://packagecontrol.io/packages/glslViewer) installieren. Mehr darüber erfährst Du [hier](https://github.com/patriciogonzalezvivo/sublime-glslViewer)
|
||||
|
||||
![](glslViewer.gif)
|
||||
|
||||
**Teilen**: Direkt aus dem Online-Editor ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) heraus kannst Du Deine Shader mit anderen teilen. Sowohl die eingebettete als auch die eigenständige Variante des Editors verfügen über eine Export-Schaltfläche. Sie liefert Dir eine einzigartige URL als Referenz auf Deinen Shader. Diese URL kannst Du dann an andere weitergeben. Außerdem bietet der Editor die Möglichkeit, Deine Shader zur Veröffentlichung direkt an das Projekt [openFrame.io](http://openframe.io/) zu senden.
|
||||
|
||||
![](glslEditor-00.gif)
|
||||
|
||||
**Kuratieren**: Deinen Shader-Code mit anderen zu teilen ist nur der Anfang. Du kannst Deine Shader auch als Werke der Computerkunst veröffentlichen. Jenseits der Weitergabe an das Projekt [openFrame.io](http://openframe.io/), habe ich ein Tool entwickelt, mit dem man Shader-Programme in eine Galerie innerhalb einer Webseite integrieren kann. Der Name dieses Tools lautet passenderweise [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Mehr darüber erfährst Du [hier](https://github.com/patriciogonzalezvivo/glslGallery).
|
||||
|
||||
![](glslGallery.gif)
|
||||
|
||||
## Ausführen von Shadern in Deiner bevorzugten Umgebung
|
||||
|
||||
Falls Du bereits Erfahrung mit der Programmierung in einer Umgebung wie [Processing](https://processing.org/), [Three.js](http://threejs.org/) oder [OpenFrameworks](http://openframeworks.cc/) gesammelt hast, möchtest Du Deine Shader vielleicht in dieser Umgebung ausführen lassen. Die folgenden Codebeispiele zeigen Dir, wie man Shader unter Verwendung der gleichen Uniforms, die wir in diesem Buch verwenden, in diesen Umgebungen ausführen kann. (In der [GitHub-Ablage dieses Kapitels](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) findest Du den gesamten Sourcecode für die Einbindung von Shadern unter den drei genannten Umgebungen.)
|
||||
|
||||
### Ausführung unter **Three.js**
|
||||
|
||||
Der brillante und äußerst bescheidene Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) hat zusammen mit [Gleichgesinnten](https://github.com/mrdoob/three.js/graphs/contributors) eines der wahrscheinlich populärsten Frameworks für WebGL mit dem Namen [Three.js](http://threejs.org/) entwickelt. Du findest dort viele Beispiele, Tutorials und Bücher, die Dir zeigen, wie Du diese JavaScript-Bibliothek zur Erstellung cooler 3D-Grafiken nutzen kannst.
|
||||
|
||||
Hier folgt ein Beispiel für den HTML- und JS-Code, den Du für Deine ersten Experimente mit Shadern unter *three.js* benötigst. Bitte beachte das Script unter dem HTML-Tag ```id="fragmentShader"```. Dort kannst Du Deine Shader aus dem vorliegenden Buch einfügen.
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script src="js/three.min.js"></script>
|
||||
<script id="vertexShader" type="x-shader/x-vertex">
|
||||
void main() {
|
||||
gl_Position = vec4( position, 1.0 );
|
||||
}
|
||||
</script>
|
||||
<script id="fragmentShader" type="x-shader/x-fragment">
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;
|
||||
gl_FragColor=vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var container;
|
||||
var camera, scene, renderer;
|
||||
var uniforms;
|
||||
|
||||
init();
|
||||
animate();
|
||||
|
||||
function init() {
|
||||
container = document.getElementById( 'container' );
|
||||
|
||||
camera = new THREE.Camera();
|
||||
camera.position.z = 1;
|
||||
|
||||
scene = new THREE.Scene();
|
||||
|
||||
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
|
||||
|
||||
uniforms = {
|
||||
u_time: { type: "f", value: 1.0 },
|
||||
u_resolution: { type: "v2", value: new THREE.Vector2() },
|
||||
u_mouse: { type: "v2", value: new THREE.Vector2() }
|
||||
};
|
||||
|
||||
var material = new THREE.ShaderMaterial( {
|
||||
uniforms: uniforms,
|
||||
vertexShader: document.getElementById( 'vertexShader' ).textContent,
|
||||
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
|
||||
} );
|
||||
|
||||
var mesh = new THREE.Mesh( geometry, material );
|
||||
scene.add( mesh );
|
||||
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
|
||||
container.appendChild( renderer.domElement );
|
||||
|
||||
onWindowResize();
|
||||
window.addEventListener( 'resize', onWindowResize, false );
|
||||
|
||||
document.onmousemove = function(e){
|
||||
uniforms.u_mouse.value.x = e.pageX
|
||||
uniforms.u_mouse.value.y = e.pageY
|
||||
}
|
||||
}
|
||||
|
||||
function onWindowResize( event ) {
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
uniforms.u_resolution.value.x = renderer.domElement.width;
|
||||
uniforms.u_resolution.value.y = renderer.domElement.height;
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
uniforms.u_time.value += 0.05;
|
||||
renderer.render( scene, camera );
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
### In **Processing**
|
||||
|
||||
Ursprünglich im Jahre 2001 von [Ben Fry](http://benfry.com/) und [Casey Reas](http://reas.com/) entwickelt, verkörpert [Processing](https://processing.org/) eine unglaublich einfache und gleichzeitig leistungsfähige Umgebung für Deinen Einstieg in das Thema "Programmierung". (Auch ich habe so angefangen.) [Andres Colubri](https://codeanticode.wordpress.com/) hat wichtige Erweiterungen für die Einbeziehung von openGL und Videofunktionen in Processing entwickelt. Sie machen es ganz einfach, in dieser Umgebung mit GLSL-Shadern zu arbeiten. Processing sucht dazu einfach nach einem Shader mit dem Namen ```shader.frag``` in dem Unterverzeichnis ```data``` Deines Zeichenblocks („sketch“). Stelle einfach sicher, dass Du die Beispiele aus dem vorliegenden Buch unter diesem Dateinamen in dem genannten Verzeichnis ablegst.
|
||||
|
||||
```cpp
|
||||
PShader shader;
|
||||
|
||||
void setup() {
|
||||
size(640, 360, P2D);
|
||||
noStroke();
|
||||
|
||||
shader = loadShader("shader.frag");
|
||||
}
|
||||
|
||||
void draw() {
|
||||
shader.set("u_resolution", float(width), float(height));
|
||||
shader.set("u_mouse", float(mouseX), float(mouseY));
|
||||
shader.set("u_time", millis() / 1000.0);
|
||||
shader(shader);
|
||||
rect(0,0,width,height);
|
||||
}
|
||||
```
|
||||
|
||||
Damit Dein Shader auch unter Versionen von Processing kleiner 2.1 läuft, musst Du lediglich die folgende Programmzeile an den Anfang Deines Shaders stellen: ```#define PROCESSING_COLOR_SHADER```. Das sieht dann so aus:
|
||||
|
||||
```glsl
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define PROCESSING_COLOR_SHADER
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec3 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.st/u_resolution;
|
||||
gl_FragColor = vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
||||
```
|
||||
|
||||
Mehr Informationen über den Einsatz von Shadern in Processing findest Du auch in diesem [Tutorial](https://processing.org/tutorials/pshader/).
|
||||
|
||||
### In **openFrameworks**
|
||||
|
||||
Jeder hat einen Platz, an dem er oder sie sich besonders wohl fühlt. Bei mir ist das die [openFrameworks Gemeinschaft](http://openframeworks.cc/). Diese C++-Umgebung ermöglicht die bequeme Einbindung von OpenGL und weiteren Open Source C++-Bibliotheken. In vielerlei Hinsicht ähnelt sie der Arbeit mit Processing, nur dass man es hier mit C++ und C++-Compilern zu tun hat. Genau wie Processing sucht *openFrameworks* nach Deinen Shader-Dateien im ```DATA```-Unterverzeichnis. Deshalb vergiss nicht, Deine ```.frag```-Dateien dorthin zu kopieren und den Dateinamen entsprechend anzupassen, wenn Du diese Dateien ausführen willst.
|
||||
|
||||
```cpp
|
||||
void ofApp::draw(){
|
||||
ofShader shader;
|
||||
shader.load("","shader.frag");
|
||||
|
||||
shader.begin();
|
||||
shader.setUniform1f("u_time", ofGetElapsedTimef());
|
||||
shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight());
|
||||
ofRect(0,0,ofGetWidth(), ofGetHeight());
|
||||
shader.end();
|
||||
}
|
||||
```
|
||||
|
||||
Weitere Informationen über die Verwendung von Shadern in *openFrameworks* findest Du in diesem [exzellenten Tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html), das von [Joshua Noble](http://thefactoryfactory.com/) verfasst wurde.
|
@ -0,0 +1,152 @@
|
||||
# Algorithmisches Zeichnen
|
||||
## Modellierungsfunktionen
|
||||
|
||||
Dieses Kapitel könnte auch die Überschrift „Mr. Miyagi's Zaun- Lektion“ tragen, in Anspielung auf den Film „Karate Kid“ aus dem Jahre 1984. Bislang haben wir die normalisierte Position von *x* und *y* auf den *roten* und *grünen* Farbkanal des jeweiligen Punktes abgebildet. Wir haben dazu eine Funktion gebaut, die im Wesentlichen einen zweidimensionalen Vektor (*X* und *Y*) entgegennimmt und einen vierdimensionalen Vektor (*Rot*, *Grün*, *Blau* und *Alpha*) zurückliefert. Aber bevor wir damit fortfahren, Daten zwischen verschiedenen Dimensionen zu transformieren, müssen wir mit einfacheren Aufgaben beginnen. Und zwar mit viel einfacheren Aufgaben. Ich meine damit das Verständnis eindimensionaler Funktionen. Desto mehr Zeit und Energie Du darauf verwendest, desto stärker wird dein Shader-Karate sein.
|
||||
|
||||
![Ausschnitt aus dem Film "Karate Kid" (1984)](mr_miyagi.jpg)
|
||||
|
||||
Die folgende Codestruktur ist unser Zaun, an dem wir in Anlehnung an die Geschichte von „Karate Kid“ üben werden. Wir visualisieren damit den normalisierten Wert der *X-Ordinate* (```st.x```) auf zweierlei Weise: einmal in Form der Helligkeit (beachte den weichen, schrittweisen Übergang von Schwarz zu Weiß) und außerdem indem wir die Werte in Form einer grünen (Funktions-) Linie darstellen (der jeweilige *X-Wert* wird dabei eins-zu-eins auf den *Y-Wert* abgebildet). Halte Dich dabei bitte nicht zu lange mit der *plot()*-Funktion auf, denn darauf werden wir gleich noch im Detail eingehen.
|
||||
|
||||
<div class="codeAndCanvas" data="linear.frag"></div>
|
||||
|
||||
**Ein kurzer Hinweis**: Der Konstruktor des ```vec3```-Datentyps „versteht“, wenn Du allen drei Farbkanälen durch die Angabe eines einzigen Parameters diesen einen gleichen Wert zuweisen willst. In diesem Fall erhält man immer einen Grauton zwischen Schwarz ```(0.0, 0.0, 0.0)``` und Weiß ```(1.0, 1.0, 1.0)```.
|
||||
|
||||
Ebenso versteht der Konstruktor des ```vec4```-Datentyps, wenn Du einen vierdimensionalen Vektor aus einem dreidimensionalen Vektor erzeugen willst. Der dreidimensionale Vektor verkörpert in diesem Fall den *RGB-Farbwert*, der zusätzliche Parameter den Wert für den *Alpha-Kanal*, also die Deckkraft. Dies geschieht hier in den *Programmzeilen 20 und 26*.
|
||||
|
||||
Dieser Programmcode ist Dein Zaun, an dem Du das Streichen bzw. Malen üben kannst. Es ist wichtig, dass Du Dir den Code genau anschaust und ihn verstehst. Denn die darin enthaltenen Konzepte, wie etwa die Normalisierung von *x* und *y* auf Werte zwischen *0.0* und *1.0*, werden uns weiterhin begleiten.
|
||||
|
||||
Die hier genutzte Eins-zu-Eins-Abbildung zwischen *x* und *y* (in diesem Fall als Helligkeit genutzt) wird als *lineare Interpolation* bezeichnet. Davon abweichend können wir auch unterschiedliche mathematische Funktionen nutzen, um der Linie eine andere Form zu geben. So können wir zum Beispiel *x hoch 5* einsetzen, um eine geschwungene, steil ansteigende Kurve zu erzeugen.
|
||||
|
||||
<div class="codeAndCanvas" data="expo.frag"></div>
|
||||
|
||||
Interessant, nicht wahr? Versuche einfach einmal, in der *Zeile 22* andere Exponenten wie beispielsweise ```20.0```, ```2.0```, ```1.0```, ```0.0```, ```0.2``` und ```0.02``` einzusetzen. Das Verständnis zwischen dem Exponenten und den daraus resultierenden Werten wird Dir sicher weiterhelfen. Schließlich ist es der geschickte Einsatz dieser und anderer mathematischer Funktionen, die Dir bei der Shader-Programmierung unglaubliche Möglichkeiten eröffnen.
|
||||
|
||||
[```pow()```](../glossary/?search=pow) ist eine eingebaute mathematische Funktion von GLSL. Daneben gibt es noch viele weitere. Die meisten davon können sehr schnell in der Hardware der Grafikkarte ausgeführt werden. Ihr geschickter Einsatz beschleunigt deshalb die Ausführung Deiner Shader.
|
||||
|
||||
Ersetze die Funktion *pow* in der *Zeile 22* durch eine andere Funktion und beobachte das Resultat. Probiere zum Beispiel die folgenden Funktionen aus: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log) und [```sqrt()```](../glossary/?search=sqrt). Einige dieser Funktionen erzeugen interessantere Ergebnisse, wenn man sie in Verbindung mit einem Vielfachen oder einem Bruchteil der Kreiszahl *pi* nutzt. In der *Programmzeile 8* findest Du deshalb ein Makro, dass das Symbol ```PI``` innerhalb des Programmcodes durch den zugehörigen Wert ```3.14159265359``` ersetzt.
|
||||
|
||||
### Step und Smoothstep
|
||||
|
||||
GLSL bringt auch einige einzigartige Interpolationsfunktionen mit, die durch die Hardware beschleunigt werden.
|
||||
|
||||
Die Interpolationsfunktion [```step()```](../glossary/?search=step) nimmt zwei Argumente entgegen: Das erste verkörpert den Schwellenwert, während das zweite Argument den Wert darstellt, der mit diesem Schwellenwert verglichen werden soll. Liegt dieser Wert unterhalb des Schwellenwerts, liefert die Funktion ```0.0``` zurück, bei jedem Wert größer oder gleich dem Schwellenwert hingegen ```1.0```.
|
||||
|
||||
Ändere im folgenden Programmcode doch einfach einmal den Schwellenwert in *Zeile 20* und beobachte, was dann passiert.
|
||||
|
||||
<div class="codeAndCanvas" data="step.frag"></div>
|
||||
|
||||
Die zweite eingebaute Interpolationsfunktion trägt den Namen [```smoothstep()```](../glossary/?search=smoothstep). Sie interpoliert einen Wert, sofern sich dieser innerhalb eines angegebenen Wertbereichs befindet. Die ersten zwei Argumente stellen dabei die untere und die obere Schwelle dieses Wertebereichs dar, während das dritte Argument den zu interpolierenden Wert verkörpert.
|
||||
|
||||
Die Funktion liefert ```0.0``` zurück, wenn der zu interpolierende Wert unterhalb des genannten Schwellenwerts liegt, also kleiner als das erste Argument ist. Analog dazu liefert sie ```1.0``` zurück, wenn der zu interpolierende Wert größer als der obere Schwellenwert
|
||||
ist. Befindet sich der zu interpolierende Wert jedoch innerhalb der gegebenen Spanne, wird ein Wert zwischen ```0.0``` und ```1.0``` zurückgeliefert, je nachdem wie nahe sich der Wert am oberen oder unteren Ende der Spanne befindet. Genau in der Mitte lautet das Ergebnis ```0.5```.
|
||||
|
||||
Wie das folgende Programm zeigt, ist das Ergebnis jedoch nicht vollständig linear, sondern am oberen und unteren Ende des Wertebereichs etwas „abgerundet“. Dadurch wird in den Randbereichen bewusst ein etwas weicherer Übergang erzielt, falls sich weitere interpolierte Werte anschließen.
|
||||
|
||||
<div class="codeAndCanvas" data="smoothstep.frag"></div>
|
||||
|
||||
Im obigen Beispiel nutzen wir die ```smoothstep()```-Funktion innerhalb der ```plot()```-Funktion, um die grüne Linie zu erzeugen, die die Ergebnisse aus der Y-Berechnung in *Zeile 20* darstellt. Siehst Du, wie diese grüne Linie nach oben und unten jeweils ein wenig ausfedert und sanft in den Hintergrund übergeht? Das erreichen wir, indem wir in *Zeile 12 und 13* zwei Aufrufe von [```smoothstep()```](../glossary/?search=smoothstep) miteinander verbinden. Schau Dir die folgende Berechnung an und setze sie in die *Zeile 20* ein.
|
||||
|
||||
```glsl
|
||||
float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);
|
||||
```
|
||||
|
||||
Die Formel entspricht dem Vorgehen innerhalb der ```plot()```-Funktion. Sie symbolisiert, wie ```plot()``` genau in der Mitte (auf dem gegebenen Y-Wert) ein volles Grün erzeugt (Rückgabewert ```1.0```), während bei Werten darunter und darüber ein weicher Übergang zur Hintergrundfarbe erfolgt (Rückgabewerte von ```1.0``` langsam absteigend zu ```0.0```).
|
||||
|
||||
|
||||
### Sinus und Cosinus
|
||||
|
||||
Wenn man mathematische Funktionen nutzen möchte, um Grafiken zu animieren, in eine geschwungene Form zu bringen oder sanft ein- und auszublenden, gibt es nichts Besseres, als sich mit Sinus und Cosinus anzufreunden.
|
||||
|
||||
Diese beiden trigonometrischen Funktionen sind so praktisch wie ein Schweizer Offiziersmesser, wenn es darum geht, Kreise zu konstruieren. Es ist wichtig zu verstehen, wie sich die beiden Funktionen einzeln verhalten und wie man sie gemeinsam nutzen kann. Kurz gesagt, bei einem gegebenen Winkel (in Form eines Bogenmaßes) liefern sie die korrekte *x*- ([*Cosinus*](../glossary/?search=cos)) und *y*- ([*Sinus*](../glossary/?search=sin)) Ordinate für die Position des zugehörigen Punktes auf einem Einheitskreis mit dem Radius ```1```. Weil sich die zurückgelieferten Funktionsergebnisse dabei immer dynamisch zwischen ```-1.0``` und ```1.0``` oszillieren, sind diese Funktionen ein ungeheuer praktisches Werkzeug für vielerlei Aufgaben.
|
||||
|
||||
![](sincos.gif)
|
||||
|
||||
Es ist nicht ganz leicht, alle Zusammenhänge zwischen trigonometrischen Funktionen auf der einen Seite und Kreisen auf der anderen Seite zu beschreiben. Die obige Animation zeigt jedoch sehr schön die oben zitierte Rolle von *Sinus* und *Cosinus* bei der Erzeugung eines Einheitskreises.
|
||||
|
||||
<div class="simpleFunction" data="y = sin(x);"></div>
|
||||
|
||||
Schau Dir die Sinuswelle genau an und beobachte, wie der daraus abgeleitete Wert für die Y-Ordinate auf dem Einheitskreis sanft zwischen ```+1``` und ```-1``` oszilliert. Und mit der Cosinuswelle erzeugen wir die zugehörige X-Ordinate.
|
||||
|
||||
Wie wir in dem zeitbasierten Beispiel im vorangegangenen Kapitel gesehen haben, lässt sich dieses rhythmische Verhalten von [```sin()```](../glossary/?search=sin) gut nutzen, um bestimmte Werte und Eigenschaften zu animieren. Wenn Du diesen Text in einem Internet-Browser liest, wirst du feststellen, dass Du die obige Formel *y=sin(x);* editieren kannst, um zu sehen, wie sich die Funktionskurve dadurch ändert. (Hinweis: Bitte nicht das Semikolon am Ende der Zeile vergessen, sonst gibt es einen Syntaxfehler.)
|
||||
|
||||
Probiere die folgenden Übungen aus und beobachte, was daraufhin geschieht:
|
||||
|
||||
* Addiere die Zeit (```u_time```) zu *x* hinzu, bevor Du aus der Summe den ```sin``` berechnest. Verinnerliche die daraus entstehende **Bewegung** entlang der *x-Achse*.
|
||||
|
||||
* Multipliziere *x* mit ```PI```, bevor Du den ```sin``` berechnest. Beobachte, wie sich die Phasenlänge auf jeweils 2 Einheiten entlang der X-Achse verkürzt und sich die Schwingung dann wiederholt. Dadurch verdoppelt sich also die Frequenz.
|
||||
|
||||
* Multipliziere die Zeit (```u_time```) mit *x*, bevor Du daraus den ```sin``` berechnest. Du wirst sehen, wie die einzelnen Wellen so weit zusammengedrückt werden, dass das Ergebnis wie ein unidentifizierbares Rauschen wirkt.
|
||||
|
||||
* Addiere den Wert ```1.0``` zum Ergebnis von [```sin(x)```](../glossary/?search=sin) hinzu und beobachte, wie sich die Welle dadurch nach oben verschiebt und jeweils zwischen den Werten von ```0.0``` und ```2.0``` oszilliert.
|
||||
|
||||
* Multipliziere [```sin(x)```](../glossary/?search=sin) mit ```2.0```. Du wirst feststellen, dass sich die Amplitude der Schwingung (die Minimal- und Maximalwerte) verdoppelt.
|
||||
|
||||
* Lass den absoluten Wert ([```abs()```](../glossary/?search=abs)) von ```sin(x)``` berechnen. Der entstehende Graph erinnert an die Spur eines hüpfenden Balls, nicht wahr?
|
||||
|
||||
* Lass nur den Nachkommateil ([```fract()```](../glossary/?search=fract)) des Resultats von [```sin(x)```](../glossary/?search=sin) berechnen.
|
||||
|
||||
* Addiere jeweils den höheren Integer-Wert ([```ceil()```](../glossary/?search=ceil)) von [```sin(x)```](../glossary/?search=sin) und den kleineren Integer-Wert ([```floor()```](../glossary/?search=floor)) von [```sin(x)```](../glossary/?search=sin), um eine digitale Welle zwischen ```1``` und ```-1``` zu erhalten.
|
||||
|
||||
### Einige besonders nützliche Funktionen
|
||||
|
||||
Am Ende der letzten Übung haben wir einige neue Funktionen eingeführt. Jetzt ist es an der Zeit, mit diesen Funktionen zu experimentieren, indem Du Schritt für Schritt die Kommentarzeichen aus den folgenden Programmzeilen entfernst. Lerne diese Funktionen kennen und beobachte, wie sie funktionieren. Du wirst Dich vielleicht fragen, warum? Eine Google-Suche nach „generativer Kunst“ bzw. „generative art“ wird Dir diese Frage schnell beantworten. Denke daran, dass diese Funktionen wie der Zaun aus „Karate Kid“ sind. Noch bewegen wir uns nur in einer Dimension, aufwärts und abwärts. Aber bald schon geht es damit in zwei, drei und vier Dimensionen!
|
||||
|
||||
![Anthony Mattox (2009)](anthony-mattox-ribbon.jpg)
|
||||
|
||||
<div class="simpleFunction" data="y = mod(x,0.5); // liefert den Modulo von x mit 0.5
|
||||
//y = fract(x); // liefert den Nachkommateil einer Zahl
|
||||
//y = ceil(x); // die kleinste Ganzzahl, groesser oder gleich x
|
||||
//y = floor(x); // die naechste Ganzzahl, kleiner oder gleich x
|
||||
//y = sign(x); // das Vorzeichen von x
|
||||
//y = abs(x); // der absolute Wert von x
|
||||
//y = clamp(x,0.0,1.0); // x auf den Bereich zwischen 0.0 und 1.0 abbilden
|
||||
//y = min(0.0,x); // die kleinere Zahl von x und 0.0 zurueckliefern
|
||||
//y = max(0.0,x); // die groessere Zahl von x und 0.0 zurueckliefern"></div>
|
||||
|
||||
### Fortgeschrittene formgebende Funktionen
|
||||
|
||||
[Golan Levin](http://www.flong.com/) hat eine großartige Dokumentation über komplexe formgebende Funktionen verfasst, die für unsere Zwecke extrem hilfreich ist. Indem Du einen Teil dieser Funktionen nach GLSL portierst, schaffst Du Dir eine wertvolle Sammlung an Codeschnipseln.
|
||||
|
||||
* [Polynomische formgebende Funktionen: www.flong.com/texts/code/shapers_poly](http://www.flong.com/texts/code/shapers_poly/)
|
||||
|
||||
* [Exponentielle formgebende Funktionen: www.flong.com/texts/code/shapers_exp](http://www.flong.com/texts/code/shapers_exp/)
|
||||
|
||||
* [Kreisförmige & elliptische formgebende Funktionen: www.flong.com/texts/code/shapers_circ](http://www.flong.com/texts/code/shapers_circ/)
|
||||
|
||||
* [Bezier und andere parametrische formgebende Funktionen: www.flong.com/texts/code/shapers_bez](http://www.flong.com/texts/code/shapers_bez/)
|
||||
|
||||
<div class="glslGallery" data="160414041542,160414041933,160414041756" data-properties="clickRun:editor,hoverPreview:false"></div>
|
||||
|
||||
Genau wie Küchenchefs Gewürze und exotische Zutaten sammeln, entwickeln Digitalkünstler und kreative Entwicker häufig eine Liebe für bestimmte formgebenden Funktionen.
|
||||
|
||||
[Inigo Quiles](http://www.iquilezles.org/) stellt eine großartige Auswahl an [nützlichen Funktionen](http://www.iquilezles.org/www/articles/functions/functions.htm) vor. Wenn Du [diesen Artikel](http://www.iquilezles.org/www/articles/functions/functions.htm) gelesen hast, dann werfe einen Blick auf die folgenden Übertragungen dieser Funktionen nach GLSL. Beobachte aufmerksam die kleinen, aber erforderlichen Anpassungen wie etwa den Punkt (".") bei Fließkommazahlen und die Umsetzung der Funktionsnamen von C auf GLSL; so heißt es in GLSL beispielsweise ```pow()``` statt ```powf()``` wie in C:
|
||||
|
||||
<div class="glslGallery" data="05/impulse,05/cubicpulse,05/expo,05/expstep,05/parabola,05/pcurve" data-properties="clickRun:editor,hoverPreview:false"></div>
|
||||
|
||||
Um Deine Motivation zu erhalten, hier ein elegantes Beispiel (entwickelt von [Danguafer](https://www.shadertoy.com/user/Danguafer)) für die Meisterschaft im Karate der formgebenden Funktionen.
|
||||
|
||||
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/XsXXDn?gui=true&t=10&paused=true" allowfullscreen></iframe>
|
||||
|
||||
Im nächsten Kapitel werden wir neue Schrittfolgen für unser „Karate“ lernen. Zunächst beim Mischen von Farben, dann beim Malen von Formen.
|
||||
|
||||
####Übung
|
||||
|
||||
Wirf einen Blick auf die folgende Tabelle mit Gleichungen, die von [Kynd](http://www.kynd.info/log/) erstellt wurde. Schau Dir an, wie er Funktionen und ihre Eigenschaften kombiniert, um Werte zwischen ```0.0``` und ```1.0``` zu erhalten. Jetzt ist ein guter Moment, um mit diesen Funktionen ein wenig zu experimentieren. Denn je mehr Du in dieses Denken hineinwächst, desto besser wird Dein Karate sein.
|
||||
|
||||
![Kynd - www.flickr.com/photos/kynd/9546075099/ (2013)](kynd.png)
|
||||
|
||||
####Für Deine Werkzeugsammlung
|
||||
|
||||
Hier kommen einige Tools, die es Dir erleichtern werden, diese Art von Funktionen grafisch zu visualisieren.
|
||||
|
||||
* Grapher: Wenn Du einen Computer mit MacOS hast, gib bei der Suche mit Spotlight ```grapher``` ein, und Du wirst dieses superpraktische Tool finden.
|
||||
|
||||
![OS X Grapher (2004)](grapher.png)
|
||||
|
||||
* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): Einmal mehr ein Werkzeug von [Inigo Quilez](http://www.iquilezles.org), mit dem man GLSL-Funktionen in WebGL darstellen kann.
|
||||
|
||||
![Inigo Quilez - GraphToy (2010)](graphtoy.png)
|
||||
|
||||
* [Shadershop](http://tobyschachman.com/Shadershop/): Dieses großartige Werkzeug von [Toby Schachman](http://tobyschachman.com/) zeigt Dir auf intuitive und grafisch faszinierende Weise, wie Du komplexe Funktionen entwickeln kannst.
|
||||
|
||||
![Toby Schachman - Shadershop (2014)](shadershop.png)
|
@ -0,0 +1,147 @@
|
||||
![Paul Klee - Color Chart (1931)](klee.jpg)
|
||||
|
||||
## Farben
|
||||
|
||||
Wir hatten bislang noch wenig Gelegenheit, um über die Vektortypen von GLSL zu sprechen. Bevor es mit anderen Inhalten weitergeht, ist es wichtig, mehr über diese Variablentypen zu erfahren. Das Thema „Farben“ bietet sich dafür an.
|
||||
|
||||
Falls Du mit den Konzepten der objektorientierten Programmierung vertraut bist, ist Dir vielleicht schon aufgefallen, dass wir die verschiedenen Elemente innerhalb eines Vektors wie eine gewöhnliche ```struct``` in C ansprechen.
|
||||
|
||||
```glsl
|
||||
vec3 red = vec3(1.0,0.0,0.0);
|
||||
red.x = 1.0;
|
||||
red.y = 0.0;
|
||||
red.z = 0.0;
|
||||
```
|
||||
|
||||
Die Festlegung von Farben über die Komponenten *x*, *y* und *z* wirkt zunächst etwas merkwürdig, nicht wahr? Aus diesem Grund gibt es weitere Möglichkeiten, um auf diese Elemente zuzugreifen. Die Inhalte von ```.x```, ```.y``` und ```.z``` können auch als ```.r```, ```.g``` und ```.b```, sowie als ```.s```, ```.t``` und ```.p``` angesprochen werden (```.s```, ```.t``` und ```.p``` werden typischerweise für die Raumkoordinaten von Texturen genutzt, wie wir in späteren Kapiteln noch sehen werden). Darüber hinaus lassen sich die Elemente eines Vektors auch über ihre Index-Position als ```[0]```, ```[1]``` und ```[2]``` ansprechen.
|
||||
|
||||
Die folgenden Programmzeilen zeigen die unterschiedlichen Ansätze, um jeweils auf die gleichen Vektorinhalte zuzugreifen:
|
||||
|
||||
```glsl
|
||||
vec4 vector;
|
||||
vector[0] = vector.r = vector.x = vector.s;
|
||||
vector[1] = vector.g = vector.y = vector.t;
|
||||
vector[2] = vector.b = vector.z = vector.p;
|
||||
vector[3] = vector.a = vector.w = vector.q;
|
||||
```
|
||||
|
||||
Tatsächlich handelt es sich bei den unterschiedlichen Namen nur um verschiedene Bezeichner für jeweils ein und dieselbe Sache. Die Namen sollen Dir helfen, verständlichen Code zu schreiben, je nachdem, wofür ein Vektor gerade zum Einsatz kommt (Farben, Koordinaten, Raumpunkte etc.)
|
||||
|
||||
Ein weiteres praktisches Merkmal der Vektortypen in GLSL ist die Möglichkeit, ihre Eigenschaften in beliebiger Weise zu kombinieren. Das macht es besonders einfach, Werte zu tauschen und in andere Datentypen zu konvertieren. Diese Fähigkeit wird im Englischen als *swizzle* bezeichnet, was so viel wie „umrühren“ oder „mischen“ bedeutet.
|
||||
|
||||
```glsl
|
||||
vec3 yellow, magenta, green;
|
||||
|
||||
// Zusammenruehren von Gelb
|
||||
yellow.rg = vec2(1.0); // Zuweisung von 1. an den Rot- und den Gruen-Kanal von yellow
|
||||
yellow[2] = 0.0; // Zuweisung von 0. an den Blau-Kanal von yellow
|
||||
|
||||
// Zusammenruehren von Magenta
|
||||
magenta = yellow.rbg; // Zuweisung von yellow an magenta bei gleichzeitigem Tausch der Kanaele fuer Blau und Gruen
|
||||
|
||||
// Zusammenruehren von Gruen
|
||||
green.rgb = yellow.bgb; // Zuweisung des Blau-Kanals von yellow an den Rot- und Blau-Kanal von green
|
||||
```
|
||||
|
||||
#### Für Deine Werkzeugkiste
|
||||
|
||||
Vielleicht bist Du es nicht gewohnt, Farben über Zahlenwerte zu definieren. Und mal ganz ehrlich, das ist ja auch nicht sonderlich intuitiv. Glücklicherweise gibt es eine Menge intelligenter Programme und Webseiten, mit denen man Farben am Bildschirm auswählen kann und dann die zugehörigen Werte für Rot, Grün und Blau erhält. Am besten, man bekommt sie gleich als Definition für einen ```vec3``` oder ```vec4``` im GLSL-Format geliefert. Hier sind zum Beispiel die Vorlagen, die ich auf [Spectrum](http://www.eigenlogik.com/spectrum/mac) nutze, um einen passenden Ausdruck für GLSL zu erhalten:
|
||||
|
||||
```
|
||||
vec3({{rn}},{{gn}},{{bn}})
|
||||
vec4({{rn}},{{gn}},{{bn}},1.0)
|
||||
```
|
||||
|
||||
### Mischen von Farben
|
||||
|
||||
Jetzt, wo Du weißt, wie man Farben definiert, wird es Zeit, dies mit unserem bisher gesammelten Wissen zu verknüpfen. In GLSL gibt es eine äußerst praktische Funktion mit dem Namen [```mix()```](../glossary/?search=mix), über die man zwei Werte in Form von Prozentangaben mischen kann. Vielleicht kannst Du Dir bereits denken, wie diese Prozentangaben auszusehen haben? Genau, als Werte zwischen ```0.0``` und ```1.0```! Das passt doch perfekt, nachdem Du schon so viel Zahlen-Karate am Zaun geübt hast. Es ist an der Zeit, Dein Wissen umzusetzen.
|
||||
|
||||
![](mix-f.jpg)
|
||||
|
||||
Lenke Dein Augenmerk im folgenden Programm besonders auf die *Zeile 18*. Schau Dir genau an, wie hier die absoluten Werte aus einer *Sinusfunktion* genutzt werden, um zeitabhängig und mit unterschiedlichen Verhältnissen die Farben aus den Variablen ```colorA``` und ```colorB``` zu mischen.
|
||||
|
||||
<div class="codeAndCanvas" data="mix.frag"></div>
|
||||
|
||||
Jetzt zeige Deine Fähigkeiten, indem Du:
|
||||
|
||||
* Einen ausdrucksstarken Übergang zwischen den Farben konstruierst. Denke an ein bestimmtes Gefühl, eine impulsive menschliche Regung. Welche Farbe vermag dieses Gefühl wohl am besten auszudrücken? Und wie soll sich diese Farbe entwickeln, um anschließend wieder zu verschwinden? Animiere den Übergang mit Hilfe formgebender Funktionen. Robert Penner hat eine Reihe populärer Übergangsfunktionen für Computeranimationen entwickelt, die als [easing functions](http://easings.net/) bekannt sind. Du kannst für Deine Nachforschungen und als Inspiration auf [dieses Beispiel](../edit.php#06/easing.frag) zurückgreifen. Aber die besten Ergebnisse erzielst Du natürlich, wenn Du Deine ganz eigenen Übergänge kreierst.
|
||||
|
||||
### Das Spiel mit Farbverläufen
|
||||
|
||||
Die [```mix()```](../glossary/?search=mix)-Funktion hat noch mehr zu bieten. Anstelle eines einzelnen Werts vom Typ ```float```, können wir auch einen Datentyp übergeben, der zu den ersten beiden Argumenten passt. In unserem Fall ist das ein ```vec3```. Dadurch gewinnen wir die Kontrolle über das Mischen in allen drei Farbkanälen *Rot*, *Grün* und *Blau* (```r```, ```g``` und ```b```).
|
||||
|
||||
![](mix-vec.jpg)
|
||||
|
||||
Werfe nun einen Blick auf das folgende Beispiel. Wie schon bei den Beispielen im letzten Kapitel verbinden wir den Übergang auch hier mit dem normalisierten Wert der *X-Ordinate* und visualisieren ihn als eine Linie. Im ersten Schritt folgen die Übergänge in allen drei Farbkanälen derselben Linie.
|
||||
|
||||
Lösche jetzt die Kommentarzeichen aus der *Programmzeile 25*, damit diese ebenfalls ausgeführt wird, und schau, was daraufhin geschieht. Dann entferne auch die Kommentarzeichen vor den *Zeilen 26 und 27*. Achte darauf, dass diese drei Zeilen jeweils das Mischverhältnis für die *Rot-*, *Grün*, und *Blau-Kanäle* zwischen den Farben aus den Variablen ```colorA``` und ```colorB``` festlegen.
|
||||
|
||||
<div class="codeAndCanvas" data="gradient.frag"></div>
|
||||
|
||||
Vielleicht erkennst Du die drei formgebenden Funktionen in den *Zeilen 25 bis 27* wieder. Experimentiere mit ihnen. Es ist an der Zeit, dass Du die erlernten Fähigkeiten aus dem letzten Kapitel nutzt, um interessante Farbverläufe zu produzieren. Probiere die folgenden Übungen aus:
|
||||
|
||||
![William Turner - The Fighting Temeraire (1838)](turner.jpg)
|
||||
|
||||
* Erzeuge einen Farbverlauf, der an den Sonnenuntergang bei William Turner erinnert.
|
||||
|
||||
* Animiere einen Übergang zwischen Sonnenaufgang und Sonnenuntergang mit Hilfe von ```u_time```.
|
||||
|
||||
* Kannst Du mit Hilfe des bislang Erlernten einen Regenbogen entstehen lassen?
|
||||
|
||||
* Nutze die ```step()```-Funktion, um eine farbenfrohe Flagge zu erzeugen.
|
||||
|
||||
### HSB
|
||||
|
||||
Beim Thema „Farben“ kommen wir nicht an dem Konzept der „Farbräume“ vorbei. Wie Du vielleicht weißt, gibt es unterschiedliche Möglichkeiten, Farben zu beschreiben, jenseits ihrer Auftrennung in *Rot-*, *Grün-* und *Blau-Anteile* (sprich: Kanäle).
|
||||
|
||||
[HSB](https://de.wikipedia.org/wiki/HSV-Farbraum) steht für *Hue* (dt. Farbwert), *Saturation* (dt. Farbsättigung) und *Brightness* (dt. absolute Helligkeit). Dieses Farbsystem ist intuitiver und in vielen Fällen auch praktischer, wenn es um die Festlegung von Farben geht. Nimm Dir einen Moment Zeit, um die Konvertierungsfunktionen ```rgb2hsv()``` und ```hsv2rgb()``` im folgenden Programmcode zu studieren.
|
||||
|
||||
Indem wir die Position auf der *X-Achse* auf den Farbwert und die Position auf der *Y-Achse* auf die Helligkeit abbilden, erhalten wir ein hübsches Spektralbild. Diese räumliche Verteilung der Farben kann sehr praktisch sei, wenn es um die Auswahl einer Farbe für einen bestimmten Zweck geht.
|
||||
|
||||
<div class="codeAndCanvas" data="hsb.frag"></div>
|
||||
|
||||
### HSB in Polarkoordinaten
|
||||
|
||||
Das *HSB-Farbmodell* wurde ursprünglich entwickelt, um in Polarkoordinaten (bestehend aus einem *Winkel* und einem *Radius*) ausgedrückt zu werden und nicht für kartesische Koordinaten (bestehend aus einer *X-* und einer *Y-Ordinate*). Um unsere ```HSB```-Funktion mit Polarkoordinaten arbeiten zu lassen, müssen wir den Winkel und die Entfernung des jeweiligen Bildpunktes von der Mitte der Zeichenfläche berechnen. Dafür nutzen wir die [```length()```](../glossary/?search=length)-Funktion, sowie die Funktion [```atan(y,x)```](../glossary/?search=atan) (das ist die GLSL-Variante der in vielen Programmiersprachen verfügbaren Funktion ```atan2(y,x)``` zur Berechnung des Arkustangens).
|
||||
|
||||
Bei der Nutzung von Vektor- und Trigonometrie-Funktionen werden Variablen der Datentypen ```vec2```, ```vec3``` und ```vec4``` wie Vektoren behandelt, auch wenn sie tatsächlich Farben verkörpern. Wir beginnen hier also, Farben und Vektoren gleichermaßen zu bearbeiten - eine Flexibilität, die sich noch als äußerst praktisch und weitreichend erweisen wird.
|
||||
|
||||
**Hinweis:** Nur, falls Du Dich fragst: Abgesehen von [```length```](../glossary/?search=length) gibt es noch viele weitere geometrische Funktionen. Dazu gehören beisielsweise: [```distance()```](../glossary/?search=distance), [```dot()```](../glossary/?search=dot), [```cross```](../glossary/?search=cross), [```normalize()```](../glossary/?search=normalize), [```faceforward()```](../glossary/?search=fraceforward), [```reflect()```](../glossary/?search=reflect) und [```refract()```](../glossary/?search=refract).
|
||||
|
||||
Außerdem bietet GLSL vergleichende Funktionen für Vektoren wie [```lessThan()```](../glossary/?search=lessThan), [```lessThanEqual()```](../glossary/?search=lessThanEqual), [```greaterThan()```](../glossary/?search=greaterThan), [```greaterThanEqual()```](../glossary/?search=greaterThanEqual), [```equal()```](../glossary/?search=equal) und [```notEqual()```](../glossary/?search=notEqual).
|
||||
|
||||
Nachdem wir den Winkel und die Entfernung (Länge) berechnet haben, müssen wir diese Werte normalisieren, indem wir sie auf den Wertebereich zwischen ```0.0``` und ```1.0``` abbilden. In der *Programmzeile 27* liefert der Aufruf von [```atan(y,x)```](../glossary/?search=atan) den Winkel als Bogenmaß zwischen *-PI* und *PI* (```-3.14``` bis ```3.14```) zurück. Deshalb müssen wir dieses Ergebnis durch ```TWO_PI``` (Zweimal *PI*, als Konstante oben im Programm definiert) teilen. Wir erhalten dadurch Werte zwischen ```-0.5``` und ```0.5```, die wir durch einfache Addition von ```0.5``` auf den benötigten Wertebereich zwischen ```0.0``` und ```1.0``` abbilden. Allerdings werden wir hier als Ergebnis immer maximal ```0.5``` erhalten, weil wir ja die Entfernung von der Mitte der Zeichenfläche berechnen. Deshalb müssen wir dieses Ergebnis noch mit ```2``` multiplizieren, damit wir maximal auf den Wert von ```1.0``` kommen.
|
||||
|
||||
Wie Du siehst, dreht sich also auch hier das ganze Spiel darum, Werte zwischen ```0.0``` und ```1.0``` zu erzielen, mit denen wir so gerne arbeiten.
|
||||
|
||||
<div class="codeAndCanvas" data="hsb-colorwheel.frag"></div>
|
||||
|
||||
Probiere die folgenden Übungen aus:
|
||||
|
||||
* Verändere das obige Programmbeispiel so, dass sich das Farbrad dreht, wie der Mauszeiger bei einer länger währenden Operation.
|
||||
|
||||
* Nutze eine formgebende Funktion in Verbindung mit der Konvertierungsfunktion von *HSB* nach *RGB*, um einen bestimmten Farbwert in den Vordergrund zu rücken und die anderen Farben „klein“ zu halten.
|
||||
|
||||
![William Home Lizars - Das Rot-, Gelb- und Blau-Spektrum in Relation zum Spektrum des Sonnenlichts (1834)](spectrums.jpg)
|
||||
|
||||
* Wenn Du Dir das Farbrad auf Farbauswahlfeldern (wie auf der folgenden Grafik) genau anschaust, erkennst Du, dass diese einen *RYB-Farbraum* repräsentieren. Die gegenüberliegende Farbe von Rot sollte z.B. Grün sein, doch in unserem obigen Beispielprogramm erscheint dort Zyan. Gelingt es Dir, einen Weg zu finden, damit unser Beispielprogramm das gleiche Farbbild liefert, wie auf der Abbildung unten? (Ein Tipp: Das ist der perfekte Moment, um eine passende formgebende Funktion zum Einsatz zu bringen.)
|
||||
|
||||
![](colorwheel.png)
|
||||
|
||||
* Lies [Josep's Alvers Buch: „Interaction of Color“](http://www.goodreads.com/book/show/111113.Interaction_of_Color) und klicke die folgenden Shader an, um aus deren Programmcode zu lernen.
|
||||
|
||||
<div class="glslGallery" data="160505191155,160505193939,160505200330,160509131554,160509131509,160509131420,160509131240" data-properties="clickRun:editor,openFrameIcon:false,showAuthor:false"></div>
|
||||
|
||||
#### Ein Hinweis zu Funktionen und ihren Argumenten
|
||||
|
||||
Bevor wir zum nächsten Kapitel springen, lass und kurz anhalten und einen Schritt zurückgehen. Schau Dir noch einmal die Funktionen aus den letzten Beispielprogrammen an. Vielleicht fällt Dir das Schüsselwort ```in``` im Kopf einer Funktion vor dem jeweiligen Argument auf. Es handelt sich dabei um einen sogenannten [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier), der in diesem Fall festlegt, dass der jeweilige Parameter von der Funktion nur ausgelesen und nicht überschrieben werden kann. In kommenden Programmbeispielen werden wir sehen, dass Parameter auch als ```out``` oder ```inout``` gekennzeichnet werden können. ```inout``` entspricht dabei der Übergabe eines Arguments „by reference“, so dass Änderungen an diesem Parameter auch an den Aufrufer und in die von ihm eingesetzte Variable zurückfließen.
|
||||
|
||||
```glsl
|
||||
int newFunction(in vec4 aVec4, // nur auslesbar
|
||||
out vec3 aVec3, // nicht initalisiert, nur beschreibbar
|
||||
inout int aInt); // lesen und schreiben, Aenderungen fliessen zum Aufrufer zurueck
|
||||
```
|
||||
|
||||
Du hast vielleicht nicht damit gerechnet, aber jetzt haben wir bereits alle Elemente beisammen, um aufregende Grafiken zu erstellen. Im nächsten Kapitel werden wir lernen, wie man all unsere kleinen Tricks nutzen kann, um den Raum richtig in Wallung zu bringen. Ja, du hast richtig gehört. Genau darum geht's.
|
||||
|
||||
|
@ -0,0 +1,101 @@
|
||||
## 2D-Matrizen
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="matrix.frag" width="700px" height="200px"></canvas>
|
||||
|
||||
### Verschieben
|
||||
|
||||
Im letzten Kapitel haben wir gesehen, wie man unterschiedliche Formen zeichnet. Der Trick, um diese Formen auf der Zeichenfläche beliebig zu positionieren, besteht nun darin, das Koordinatensystem „unterhalb“ dieser Formen zu verschieben. Wir erreichen dies, indem wir einfach einen Vektor zur ```st```-Variable addieren, die die Lage des jeweiligen Objekts beim Zeichnen bestimmt. Dadurch verschiebt sich das gesamte Koordinatensystem.
|
||||
|
||||
![](translate.jpg)
|
||||
|
||||
Es ist vermutlich einfacher, das Verfahren in der Praxis nachzuvollziehen, als es in der Theorie zu beschreiben. Schau einfach selbst:
|
||||
|
||||
* Entferne die Kommentarzeichen in der *Programmzeile 35*, und Du wirst sehen, wie sich das Zeichenobjekt gemeinsam mit dem darunterliegenden Koordinatenraum bewegt.
|
||||
|
||||
<div class="codeAndCanvas" data="cross-translate.frag"></div>
|
||||
|
||||
Jetzt versuche Dich an der folgenden Aufgabe:
|
||||
|
||||
* Nutze ```u_time``` in Verbindung mit einer formgebenden Funktion, um das kleine Kreuz auf interessante Weise über die Zeichenfläche zu bewegen. Das Vorbild dafür kann durchaus aus der realen Welt stammen, beispielsweise eine Wellenbewegung, das Schwingen eines Pendels, ein springender Ball, ein beschleunigendes Auto oder ein stoppendes Fahrrad.
|
||||
|
||||
### Rotationen
|
||||
|
||||
Um Objekte rotieren zu lassen, müssen wir ebenfalls nur das zugrundeliegende Koordinatensystem transformieren. Wir verwenden dafür eine [Rotationsmatrix](http://de.wikipedia.org/wiki/Matrix_(Mathematik)). Eine Matrix ist eine geordnete Anordnung von Zahlen in Form von Zeilen und Spalten. Vektoren werden mit Matrizen nach einem festen vorgegebenen Verfahren multipliziert, um den Vektor auf eine bestimmte Art und Weise zu verändern.
|
||||
|
||||
[![Aus dem Wikipedia-Eintrag zur Matrizenmultiplikation](matrixes.png)](http://de.wikipedia.org/wiki/Matrizenmultiplikation)
|
||||
|
||||
GLSL verfügt über eingebaute Unterstützung für zwei-, drei- und vierdimensionale Matrizen: [```mat2```](../glossary/?search=mat2) (2x2), [```mat3```](../glossary/?search=mat3) (3x3) und [```mat4```](../glossary/?search=mat4) (4x4). Außerdem unterstützt GLSL die Matrizenmultiplikation (```*```) mit einem Vektor sowie die Multiplikation zweier Matrizen mit der speziellen Funktion ([```matrixCompMult()```](../glossary/?search=matrixCompMult)).
|
||||
|
||||
Darauf basierend, wie Matrizen funktionieren, kann man Matrizen mit einem bestimmten „Verhalten“ konstruieren. Beispielsweise können wir eine Matrix zum Verschieben eines Vektors nutzen:
|
||||
|
||||
![](3dtransmat.png)
|
||||
|
||||
Noch interessanter wird es, wenn wir eine Matrix zur Drehung des Koordinatensystems verwenden:
|
||||
|
||||
![](rotmat.png)
|
||||
|
||||
Schau Dir den folgenden Programmcode an, der die benötigte Matrix für eine Rotation des Koordinatensystems um einen vorgegebenen Winkel produziert. Diese Funktion folgt der obigen Formel für zweidimensionale Vektoren, um die Koordinaten um einen ```vec2(0.0)```-Punkt rotieren zu lassen.
|
||||
|
||||
```glsl
|
||||
mat2 rotate2d(float _angle){
|
||||
return mat2(cos(_angle),-sin(_angle),
|
||||
sin(_angle),cos(_angle));
|
||||
}
|
||||
```
|
||||
|
||||
In Bezug auf die Art und Weise, wie wir Formen bislang gezeichnet haben, ist das noch nicht ganz das, was wir benötigen. Unser Kreuz wird in der Mitte der Zeichenfläche dargestellt, was dem Punkt ```vec2(0.5)``` entspricht. Vor der Rotation müssen wir die Form deshalb von der Mitte des Koordinatensystem zum ```vec2(0.0)``` verschieben, anschließend die Drehung ausführen und das Objekt dann wieder an seinen ursprünglichen Platz bringen.
|
||||
|
||||
![](rotate.jpg)
|
||||
|
||||
In Programmcode „gegossen“, sieht das dann wie folgt aus:
|
||||
|
||||
<div class="codeAndCanvas" data="cross-rotate.frag"></div>
|
||||
|
||||
Probiere die folgenden Übungen aus:
|
||||
|
||||
* Entferne die Kommentarzeichnen aus der *Programmzeile 45* und beobachte, was dann passiert.
|
||||
|
||||
* Kommentiere das Verschieben vor und nach der Rotation in den *Zeilen 37 und 39* aus und beobachte die Konsequenzen.
|
||||
|
||||
* Nutze Rotationen, um die Animation zu verbessern, die Du beim Beispiel zum Verschieben erstellt hast.
|
||||
|
||||
### Skalieren
|
||||
|
||||
Wir haben gesehen, wie man die Verschiebung und Rotation von Objekten realisiert, indem man mit Matrizen auf den Koordinatenraum einwirkt. Falls Du bereits mit 3D-Modellierungssoftware oder den Matrizenfunktionen in Procesing gearbeitet hast, weißt Du wahrscheinlich, dass man Matrizen auch für die Skalierung von Objekten verwenden kann.
|
||||
|
||||
![](scale.png)
|
||||
|
||||
Indem wir uns an der obigen Formel orientieren, können wir eine 2D-Saklierungsmatrix für das gewünschte Vergrößern oder Verkleinern erstellen:
|
||||
|
||||
```glsl
|
||||
mat2 scale(vec2 _scale){
|
||||
return mat2(_scale.x,0.0,
|
||||
0.0,_scale.y);
|
||||
}
|
||||
```
|
||||
|
||||
<div class="codeAndCanvas" data="cross-scale.frag"></div>
|
||||
|
||||
Probiere die folgenden Übungen aus, um noch besser zu verstehen, wie das Ganze funktioniert.
|
||||
|
||||
* Entferne die Kommentare in der *Programmzeile 42*, um zu sehen, wie der Koordinatenraum skaliert wird.
|
||||
|
||||
* Schau Dir an, was geschieht, wenn Du die Verschiebung vor und nach der Skalierung in den *Programmzeilen 37 und 39* entfernst.
|
||||
|
||||
* Probiere eine Rotationsmatrix in Verbindung mit einer Skalierungsmatrix aus. Sei Dir bewusst, dass die Reihenfolge der Matrixoperationen dabei eine entscheidende Rolle spielt.
|
||||
|
||||
* Jetzt, wo Du weißt, wie man unterschiedliche Formen malt, verschiebt, rotiert und skaliert, ist es an der Zeit, eine etwas komplexere Komposition zu erstellen. Designe und entwickle die Simulation einer [futuristischen Benutzeroberfläche bzw. eines Head-up-Displays](https://www.pinterest.com/patriciogonzv/huds/). Nutze das folgende Beispiel aus den Shadertoys von [Ndel](https://www.shadertoy.com/user/ndel) als Inspirationsquelle und als Referenz.
|
||||
|
||||
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/4s2SRt?gui=true&t=10&paused=true" allowfullscreen></iframe>
|
||||
|
||||
### Ein anderes Einsatzgebiet für Matrizen: YUV-Farben
|
||||
|
||||
[*YUV*](https://de.wikipedia.org/wiki/YUV-Farbmodell) ist ein Farbmodell, das für die analoge Kodierung von Fotos und Videos verwendet wird. Das Modell berücksichtigt die Grenzen der menschlichen Farbwahrnehmung und nutzt dies für die Beschränkung der Bandbreite bei der Kodierung der Farbigkeit (Chrominanz).
|
||||
|
||||
Der folgende Programmcode zeigt eine interessante Einsatzmöglichkeit für den Einsatz von Matrizenfunktionen zur Konvertierung von Farben zwischen zwei Farbräumen bzw. Farbsystemen.
|
||||
|
||||
<div class="codeAndCanvas" data="yuv.frag"></div>
|
||||
|
||||
Wie Du siehst, behandeln wir Farben hier als Vektoren, indem wir sie mit Matrizen multiplizieren. Auf diese Weise können wir die Farben über ihre Farbwerte hin und her bewegen.
|
||||
|
||||
In diesem Kapitel haben wir gelernt, wie man Matrixtransformationen für das Verschieben, Rotieren und Skalieren von Vektoren nutzt. Für die Erstellung von Kompositionen aus mehreren grafischen Formen und Objekten sind diese Transformationen essenziell. Im nächsten Kapitel werden wir all das Erlernte anwenden, um bezaubernde prozedurale Muster zu erstellen. Du wirst sehen, dass die Wiederholung und Variation von Programmcode höchst interessante Resultate liefern kann.
|
@ -1,105 +1,108 @@
|
||||
<canvas id="custom" class="canvas" data-fragment-url="src/moon/moon.frag" data-textures="src/moon/moon.jpg" width="350px" height="350px"></canvas>
|
||||
|
||||
# The Book of Shaders
|
||||
*by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) and [Jen Lowe](http://jenlowe.net/)*
|
||||
|
||||
This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.
|
||||
|
||||
<div class="header">
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=B5FSVSHGEATCG" style="float: right;"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" alt=""></a>
|
||||
</div>
|
||||
|
||||
## Contents
|
||||
|
||||
* [About this book](00/)
|
||||
|
||||
* Getting started
|
||||
* [What is a shader?](01/)
|
||||
* [“Hello world!”](02/)
|
||||
* [Uniforms](03/)
|
||||
* [Running your shader](04/)
|
||||
|
||||
* Algorithmic drawing
|
||||
* [Shaping functions](05/)
|
||||
* [Colors](06/)
|
||||
* [Shapes](07/)
|
||||
* [Matrices](08/)
|
||||
* [Patterns](09/)
|
||||
|
||||
* Generative designs
|
||||
* [Random](10/)
|
||||
* [Noise](11/)
|
||||
* [Cellular noise](12/)
|
||||
* [Fractional brownian motion](13/)
|
||||
* Fractals
|
||||
|
||||
* Image processing:
|
||||
* Textures
|
||||
* Image operations
|
||||
* Kernel convolutions
|
||||
* Filters
|
||||
* Others effects
|
||||
|
||||
* Simulation
|
||||
* Pingpong
|
||||
* Conway
|
||||
* Ripples
|
||||
* Water color
|
||||
* Reaction diffusion
|
||||
|
||||
* 3D graphics
|
||||
* Lights
|
||||
* Normal-maps
|
||||
* Bump-maps
|
||||
* Ray marching
|
||||
* Environmental-maps (spherical and cube)
|
||||
* Reflect and refract
|
||||
|
||||
* [Appendix:](appendix/) Other ways to use this book
|
||||
* [How can I navigate this book offline?](appendix/00/)
|
||||
* [How to run the examples on a Raspberry Pi?](appendix/01/)
|
||||
* [How to print this book?](appendix/02/)
|
||||
* [How can I collaborate?](appendix/03/)
|
||||
* [An introduction for those coming from JS](appendix/04/) by [Nicolas Barradeau](http://www.barradeau.com/)
|
||||
|
||||
* [Examples Gallery](examples/)
|
||||
|
||||
* [Glossary](glossary/)
|
||||
|
||||
## About the Authors
|
||||
|
||||
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) is a New York based artist and developer. He explores interstitial spaces between organic and synthetic, analog and digital, individual and collective. In his work he uses code as an expressive language with the intention of developing a better together.
|
||||
|
||||
Patricio studied and practiced psychotherapy and expressive art therapy. He holds an MFA in Design & Technology from Parsons The New School, where he now teaches. Currently he works as a Graphic Engineer at Mapzen making openSource mapping tools.
|
||||
|
||||
<div class="header"> <a href="http://patriciogonzalezvivo.com/" target="_blank">WebSite</a> - <a href="https://twitter.com/patriciogv" target="_blank">Twitter</a> - <a href="https://github.com/patriciogonzalezvivo" target="_blank">GitHub</a> - <a href="https://vimeo.com/patriciogv" target="_blank">Vimeo</a> - <a href="https://www.flickr.com/photos/106950246@N06/" target="_blank"> Flickr</a></div>
|
||||
|
||||
[Jen Lowe](http://jenlowe.net/) is an independent data scientist and data communicator at Datatelling where she brings together people + numbers + words. She teaches in SVA's Design for Social Innovation program, cofounded the School for Poetic Computation, taught Math for Artists at NYU ITP, researched at the Spatial Information Design Lab at Columbia University, and contributed ideas at the White House Office of Science and Technology Policy. She's spoken at SXSW and Eyeo. Her work has been covered by The New York Times and Fast Company. Her research, writing, and speaking explore the promises and implications of data and technology in society. She has a B.S. in Applied Math and a Master's in Information Science. Often oppositional, she's always on the side of love.
|
||||
|
||||
<div class="header"> <a href="http://jenlowe.net/" target="_blank">WebSite</a> - <a href="https://twitter.com/datatelling" target="_blank">Twitter</a> - <a href="https://github.com/datatelling" target="_blank">GitHub</a></div>
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Thanks [Scott Murray](http://alignedleft.com/) for the inspiration and advice.
|
||||
|
||||
Thanks [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) for contributing with support, good ideas and code.
|
||||
|
||||
Thanks [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) and [Sawako](https://twitter.com/sawakohome) for the [Japanese translation (日本語訳)](?lan=jp)
|
||||
|
||||
Thanks [Tong Li](https://www.facebook.com/tong.lee.9484) and [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) for the [Chinese translation (中文版)](?lan=ch)
|
||||
|
||||
Thanks [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) for the Korean [translation (한국어)](?lan=kr)
|
||||
|
||||
Thanks [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) for the Spanish [translation (español)](?lan=es)
|
||||
|
||||
Thanks [Nicolas Barradeau](https://twitter.com/nicoptere) and [Karim Naaji](http://karim.naaji.fr/) for the French [translation (français)](?lan=fr)
|
||||
|
||||
Thanks [Andrea Rovescalli](https://www.earove.info) for the Italian [translation (italiano)](?lan=it)
|
||||
|
||||
Thanks to everyone who has believed in this project and [contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) or donations.
|
||||
|
||||
## Get new chapters
|
||||
|
||||
Sign up for the news letter or [follow it on Twitter](https://twitter.com/bookofshaders)
|
||||
|
||||
<form style="border:1px solid #ccc;padding:3px;text-align:center;" action="https://tinyletter.com/thebookofshaders" method="post" target="popupwindow" onsubmit="window.open('https://tinyletter.com/thebookofshaders', 'popupwindow', 'scrollbars=yes,width=800,height=600');return true"><a href="https://tinyletter.com/thebookofshaders"><p><label for="tlemail">Enter your email address</label></p></a><p><input type="text" style="width:140px" name="email" id="tlemail" /></p><input type="hidden" value="1" name="embed"/><input type="submit" value="Subscribe" /><p><a href="https://tinyletter.com" target="_blank"></a></p></form>
|
||||
<canvas id="custom" class="canvas" data-fragment-url="src/moon/moon.frag" data-textures="src/moon/moon.jpg" width="350px" height="350px"></canvas>
|
||||
|
||||
# The Book of Shaders
|
||||
*by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) and [Jen Lowe](http://jenlowe.net/)*
|
||||
|
||||
This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.
|
||||
|
||||
<div class="header">
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=B5FSVSHGEATCG" style="float: right;"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" alt=""></a>
|
||||
</div>
|
||||
|
||||
## Contents
|
||||
|
||||
* [About this book](00/)
|
||||
|
||||
* Getting started
|
||||
* [What is a shader?](01/)
|
||||
* [“Hello world!”](02/)
|
||||
* [Uniforms](03/)
|
||||
* [Running your shader](04/)
|
||||
|
||||
* Algorithmic drawing
|
||||
* [Shaping functions](05/)
|
||||
* [Colors](06/)
|
||||
* [Shapes](07/)
|
||||
* [Matrices](08/)
|
||||
* [Patterns](09/)
|
||||
|
||||
* Generative designs
|
||||
* [Random](10/)
|
||||
* [Noise](11/)
|
||||
* Cellular noise
|
||||
* Fractional brownian motion
|
||||
* Fractals
|
||||
|
||||
* Image processing:
|
||||
* Textures
|
||||
* Image operations
|
||||
* Kernel convolutions
|
||||
* Filters
|
||||
* Others effects
|
||||
|
||||
* Simulation
|
||||
* Pingpong
|
||||
* Conway
|
||||
* Ripples
|
||||
* Water color
|
||||
* Reaction diffusion
|
||||
|
||||
* 3D graphics
|
||||
* Lights
|
||||
* Normal-maps
|
||||
* Bump-maps
|
||||
* Ray marching
|
||||
* Environmental-maps (spherical and cube)
|
||||
* Reflect and refract
|
||||
|
||||
* [Appendix:](appendix/) Other ways to use this book
|
||||
* [How can I navigate this book offline?](appendix/00/)
|
||||
* [How to run the examples on a RaspberryPi?](appendix/01/)
|
||||
* [How to print this book?](appendix/02/)
|
||||
* [How can I collaborate?](appendix/03/)
|
||||
* [An introduction for those coming from JS](appendix/04/) by [Nicolas Barradeau](http://www.barradeau.com/)
|
||||
|
||||
* [Examples Gallery](examples/)
|
||||
|
||||
* [Glossary](glossary/)
|
||||
|
||||
## About the Authors
|
||||
|
||||
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) is a New York based artist and developer. He explores interstitial spaces between organic and synthetic, analog and digital, individual and collective. In his work he uses code as an expressive language with the intention of developing a better together.
|
||||
|
||||
Patricio studied and practiced psychotherapy and expressive art therapy. He holds an MFA in Design & Technology from Parsons The New School, where he now teaches. Currently he works as a Graphic Engineer at Mapzen making openSource mapping tools.
|
||||
|
||||
<div class="header"> <a href="http://patriciogonzalezvivo.com/" target="_blank">WebSite</a> - <a href="https://twitter.com/patriciogv" target="_blank">Twitter</a> - <a href="https://github.com/patriciogonzalezvivo" target="_blank">GitHub</a> - <a href="https://vimeo.com/patriciogv" target="_blank">Vimeo</a> - <a href="https://www.flickr.com/photos/106950246@N06/" target="_blank"> Flickr</a></div>
|
||||
|
||||
[Jen Lowe](http://jenlowe.net/) is an independent data scientist and data communicator at Datatelling where she brings together people + numbers + words. She teaches in SVA's Design for Social Innovation program, cofounded the School for Poetic Computation, taught Math for Artists at NYU ITP, researched at the Spatial Information Design Lab at Columbia University, and contributed ideas at the White House Office of Science and Technology Policy. She's spoken at SXSW and Eyeo. Her work has been covered by The New York Times and Fast Company. Her research, writing, and speaking explore the promises and implications of data and technology in society. She has a B.S. in Applied Math and a Master's in Information Science. Often oppositional, she's always on the side of love.
|
||||
|
||||
<div class="header"> <a href="http://jenlowe.net/" target="_blank">WebSite</a> - <a href="https://twitter.com/datatelling" target="_blank">Twitter</a> - <a href="https://github.com/datatelling" target="_blank">GitHub</a></div>
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Thanks [Scott Murray](http://alignedleft.com/) for the inspiration and advice.
|
||||
|
||||
Thanks [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) for contributing with support, good ideas and code.
|
||||
|
||||
Thanks [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) and [Sawako](https://twitter.com/sawakohome) for the [Japanese translation (日本語訳)](?lan=jp)
|
||||
|
||||
Thanks [Tong Li](https://www.facebook.com/tong.lee.9484) and [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) for the [Chinese translation (中文版)](?lan=ch)
|
||||
|
||||
Thanks [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) for the Korean [translation (한국어)](?lan=kr)
|
||||
|
||||
Thanks [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) for the Spanish [translation (español)](?lan=es)
|
||||
|
||||
Thanks [Nicolas Barradeau](https://twitter.com/nicoptere) and [Karim Naaji](http://karim.naaji.fr/) for the French [translation (français)](?lan=fr)
|
||||
|
||||
Thanks [Andrea Rovescalli](https://www.earove.info) for the Italian [translation (italiano)](?lan=it)
|
||||
|
||||
Thanks [Michael Tischer](http://www.mitinet.de) for the German [translation (deutsch)](?lan=de)
|
||||
|
||||
Thanks to everyone who has believed in this project and [contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) or donations.
|
||||
|
||||
## Get new chapters
|
||||
|
||||
Sign up for the news letter or [follow it on Twitter](https://twitter.com/bookofshaders)
|
||||
|
||||
<form style="border:1px solid #ccc;padding:3px;text-align:center;" action="https://tinyletter.com/thebookofshaders" method="post" target="popupwindow" onsubmit="window.open('https://tinyletter.com/thebookofshaders', 'popupwindow', 'scrollbars=yes,width=800,height=600');return true"><a href="https://tinyletter.com/thebookofshaders"><p><label for="tlemail">Enter your email address</label></p></a><p><input type="text" style="width:140px" name="email" id="tlemail" /></p><input type="hidden" value="1" name="embed"/><input type="submit" value="Subscribe" /><p><a href="https://tinyletter.com" target="_blank"></a></p></form>
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
## Wie kann ich dieses Buch offline lesen?
|
||||
|
||||
Nehmen wir einmal an, Du gehst auf eine längere Reise und möchtest Dich unterwegs in die Shader-Programmierung einarbeiten. In diesem Fall könntest Du eine Kopie dieses Buches auf Deinen Rechner laden und diese über einen lokalen Server anzeigen lassen.
|
||||
|
||||
Alles, was Du dafür benötigst, ist Python 2.6 und ein Client-Programm für GIT. Auf Computern mit MacOS und auf dem RaspberryPi ist Python standardmäßig bereits vorinstalliert. Dort musst Du lediglich den GIT-Client zusätzlich installieren.
|
||||
|
||||
Unter **MacOSX** benötigst Du dafür [homebrew](http://brew.sh/). Sobald das Paket installiert ist, kannst Du in einem Terminal-Fenster folgendes eingeben:
|
||||
|
||||
```bash
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install git
|
||||
```
|
||||
|
||||
Auf einem **RaspberryPi** gibst Du folgendes ein:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
sudo apt-get install git-core
|
||||
```
|
||||
|
||||
Hast Du alles beisammen, musst Du lediglich folgende Befehle aufrufen, um das *Book of Shaders* per GIT auf Deinen Rechner zu laden und den Server zur Anzeige des Inhalts zu starten:
|
||||
|
||||
```bash
|
||||
cd ~
|
||||
git clone --recursive https://github.com/patriciogonzalezvivo/thebookofshaders.git
|
||||
cd thebookofshaders
|
||||
git submodule foreach git pull
|
||||
php -S localhost:8000
|
||||
```
|
||||
|
||||
Nutze dann den vorinstallierten Internet-Browser auf Deinem Rechner zur Anzeige des Buches durch Eingabe folgender URL [```http://localhost:8000/```](http://localhost:8000/)
|
@ -0,0 +1,25 @@
|
||||
## Wie kann ich die Beispielprogramme auf einem RaspberryPi ausführen?
|
||||
|
||||
Vor wenigen Jahren konnte man noch nicht davon ausgehen, dass jedermann über einen Computer mit einer GPU verfügt. Heutzutage gilt das nicht mehr. Doch im Bereich von Schulen, Universitäten und anderen Weiterbildungseichrichtungen ist dies immer noch eine hohe Anforderung.
|
||||
|
||||
Durch das [Raspberry Projekt](http://www.raspberrypi.org/) hat mittlerweile eine neue Generation kleiner und billiger Computer (das Stück ab ca. 40 Euro) ihren Weg in viele Klassenzimmer gefunden. Vor allem verfügt der [RaspberryPi](http://www.raspberrypi.org/) über einen ansehnlichen Grafikchip mit GPU, der direkt aus der Kommandozeile angesprochen werden kann.
|
||||
|
||||
Ich habe ein flexibles Werkzeug für die Programmierung von GLSL-Shadern entwickelt, den [**glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer). Damit können alle Beispiele aus diesem Buch ausgeführt werden. Sobald man Veränderungen am aktuellen Shader-Programmcode abspeichert, kompiliert das Programm den Shader erneut und bringt ihn zur Ausführung. Auf dem Bildschirm erscheint daraufhin die aktualisierte Anzeige des Shaders.
|
||||
|
||||
Indem Du eine lokale Kopie dieses Buches und seiner Beispielprogramme auf Deinem Rechner anlegst (mehr dazu im vorhergehenden Kapitel) und den [```glslViewer```] (https://github.com/patriciogonzalezvivo/glslViewer) installierst, kannst Du die Beispielprogramme mit dem ```glslviewer``` ausführen. Wenn Du beim Start dieses Programms den Kommandozeilenschalter ```-l``` angibst, erscheint die erzeugte Grafik in einer Ecke des Bildschirms, während Du gleichzeitig den Shader-Programmcode mit einem beliebigen Text-Editor (etwa ```nano```, ```pico```, ```vi```, ```vim``` oder ```emacs```) bearbeitest. Das funktioniert auch, wenn Du mit dem Terminal des RaspberryPi über ssh/sftp verbunden bist.
|
||||
|
||||
Um die angesprochenen Tools auf einem RaspberryPi zu installieren, rufe nach dem Start des Betriebssystems und dem Einloggen folgende Befehle über die Kommandozeile auf:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
sudo apt-get install git-core
|
||||
cd ~
|
||||
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
|
||||
cd glslViewer
|
||||
make
|
||||
make install
|
||||
cd ~
|
||||
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
|
||||
cd thebookofshaders
|
||||
```
|
@ -0,0 +1,69 @@
|
||||
## Wie kann ich dieses Buch ausdrucken?
|
||||
|
||||
Nehmen wir einmal an, Du willst gar nicht mit den Beispielprogrammen in diesem Buch interagieren, sondern den Text wie ein gutes altes Buch im Urlaub oder auf dem täglichen Weg zur Arbeit lesen. In diesem Fall kannst Du Dir den Text einfach ausdrucken.
|
||||
|
||||
|
||||
#### Installation des glslViewer
|
||||
|
||||
Um den Text auszudrucken, müssen die verschiedenen Bestandteile des Buches zunächst aufbereitet werden. Dafür benötigst Du den [```glslViewer```](https://github.com/patriciogonzalezvivo/glslViewer), ein Werkzeug für die Kommandozeile, mit dem Du aus den verschiedenen Beispielprogrammen die daraus resultierenden Bilder generieren kannst.
|
||||
|
||||
Unter **MacOSX** benötigst Du zunächst [homebrew](http://brew.sh/). Nach dessen Installation kannst Du in einem Terminalfenster folgendes eingeben:
|
||||
|
||||
```bash
|
||||
brew update
|
||||
brew upgrade
|
||||
brew tap homebrew/versions
|
||||
brew install glfw3
|
||||
cd ~
|
||||
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
|
||||
cd glslViewer
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
Auf einem **RaspberryPi** gibst Du folgende Befehle ein:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
sudo apt-get install git-core
|
||||
cd ~
|
||||
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
|
||||
cd glslViewer
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
#### Installation von Latex und Pandoc
|
||||
|
||||
Für den Ausdruck müssen die einzelnen Kapitel zunächst aus dem vorliegenden Textformat (*Markdown*) zunächst nach Latex und anschließend nach PDF konvertiert werden.
|
||||
|
||||
Unter **MacOSX**:
|
||||
|
||||
Lade und installiere zunächst [basictex inkl. der MacTeX-Erweiterungen](http://www.tug.org/mactex/morepackages.html) und installiere anschließend [Pandoc](http://johnmacfarlane.net/pandoc/), indem Du folgende Kommandos eingibst:
|
||||
|
||||
```bash
|
||||
brew install pandoc
|
||||
```
|
||||
|
||||
Auf einem **RaspberryPi** gibst Du bitte folgende Kommandos ein:
|
||||
|
||||
```bash
|
||||
sudo apt-get install texlive-xetex pandoc
|
||||
```
|
||||
|
||||
#### Das Buch nach PDF umwandeln und ausdrucken
|
||||
|
||||
Jetzt, wo Du alle Werkzeuge beisammenhast, ist es an der Zeit, eine Kopie des Buches aus der [Ablage im Internet](https://github.com/patriciogonzalezvivo/thebookofshaders) herunterzuladen und daraus eine PDF-Datei zu erstellen.
|
||||
|
||||
Öffne dafür erneut ein Terminalfenster und gib die folgenden Befehle ein:
|
||||
|
||||
```bash
|
||||
cd ~
|
||||
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
|
||||
cd thebookofshaders
|
||||
make
|
||||
```
|
||||
|
||||
Wenn alles funktioniert hat, findest Du anschließend die Datei ```book.pdf``` vor, die Du auf Deinem bevorzugten Gerät lesen oder ausdrucken kannst.
|
||||
|
@ -0,0 +1,65 @@
|
||||
## Wie kann ich zu diesem Buch beitragen?
|
||||
|
||||
Schön, dass Du Interesse hast, an diesem Buch mitzuwirken. Zahlreiche Möglichkeiten bieten sich dafür an. Du kannst ...
|
||||
|
||||
- Inhalte übersetzen
|
||||
- Das [```Glossar```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary) verbessern
|
||||
- Fehler bereinigen
|
||||
- Deine eigenen GLSL-Shader über den [Online Editor](http://editor.thebookofshaders.com/) mit anderen teilen
|
||||
|
||||
### Inhalte übersetzen
|
||||
|
||||
Der Quelltext dieses Buches wurde in [Markdown](https://daringfireball.net/projects/markdown/syntax) verfasst. Dadurch ist es sehr einfach, den Text zu bearbeiten und zu erweitern.
|
||||
|
||||
1. Besuche zunächst die Internet-Ablage dieses Buches bei [Github unter ```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Verschaffe Dir einen Überblick über die verschiedenen Verzeichnisse und die darin enthaltenen Dateien. Du wirst feststellen, dass die eigentlichen Textinhalte des Buches jeweils in der Datei ```README.md``` und in anderen Dateien enthalten sind, die Großbuchstaben im Namen tragen. Beispiele dafür sind etwa ```TITLE.md```, ```SUMMARY.md``` usw. Die Übersetzungen dieser Texte stecken in Dateien, die am Ende des Namens ein Kürzel für die jeweilige Sprache tragen, also z.B. ```README-jp.md```, ```README-es.md``` usw.
|
||||
|
||||
2. Lege einen Fork der Ablage an und klone den Fork auf Deinen Computer.
|
||||
|
||||
3. Lege jeweils eine Kopie der Datei an, die Du übersetzen möchtest, und vergiss dabei nicht, das Sprachkürzel im Dateinamen zu ergänzen.
|
||||
|
||||
4. Übersetze den Inhalt des Dokuments Zeile für Zeile (siehe dazu auch die **Übersetzungshinweise** unten).
|
||||
|
||||
5. Überprüfe den Inhalt hinsichtlich der Rechtschreibung und der korrekten Anzeige im Browser (siehe unten unter **Testen**).
|
||||
|
||||
6. Lade die veränderten Dateien in Deinen Fork hoch und setze einen [Pull Request](https://help.github.com/articles/using-pull-requests/) ab.
|
||||
|
||||
#### Übersetzungshinweise
|
||||
|
||||
Lösche und verändere nichts an der Einbindung der Beispielprogramme innerhalb des Quelltextes. Dieses sehen wie folgt aus:
|
||||
|
||||
```html
|
||||
<div class="codeAndCanvas" data="grid-making.frag"></div>
|
||||
```
|
||||
|
||||
oder
|
||||
|
||||
```html
|
||||
<div class="simpleFunction" data="y = mod(x,2.0);"></div>
|
||||
```
|
||||
|
||||
#### Testen
|
||||
|
||||
Starte auf Deinem lokalen Rechner einen PHP-Server innerhalb des Verzeichnisses, in das Du das Buch geklont hast:
|
||||
|
||||
```bash
|
||||
php -S localhost:8000
|
||||
```
|
||||
|
||||
Rufe dann in Deinem Internet-Browser die URL ```localhost:8000``` auf. Klicke Dich bis zu dem Kapitel durch, an dem Du gerade arbeitest. Füge der angezeigten URL in der Adresszeile des Browsers den Zusatz ```?lan=``` hinzu, gefolgt von dem Sprachenkürzel, das Du bei der Benennung der jeweiligen Datei verwendet hast.
|
||||
|
||||
Um ein Beispiel zu nennen: Wenn Du gerade das Kapitel ```03``` ins Französische übersetzt und dabei mit der Datei ```03/README-fr.md``` arbeitest, kannst Du diese Datei anzeigen, indem Du folgende URL eingibst: ```http://localhost:8000/03/?lan=fr```
|
||||
|
||||
### Verbesserungen am Glossar
|
||||
|
||||
Das Glossar befindet sich noch in Arbeit. Wir freuen uns über Vorschläge, wie man das Glossar zu einem wertvollen Bestandteil des Buches ausbauen kann. Schick uns einfach eine Nachricht an [@bookofshaders](https://twitter.com/bookofshaders).
|
||||
|
||||
### Fehler bereinigen
|
||||
|
||||
Irren ist menschlich! Wenn Dir ein Fehler auffällt, bereinige die Stelle und setze einfach einen entsprechenden Pull Request auf Github ab, oder eröffnete dort eine Diskussion zu dem Thema. Vielen Dank!
|
||||
|
||||
### Teile Deine Shader mit Anderen
|
||||
|
||||
Du wirst im Quelltext des Buches bei den Beispielen viele Verweise auf den [Online-Editor](http://editor.thebookofshaders.com/) sehen.
|
||||
Sobald Du einen Shader entwickelt hast, auf den Du stolz bist, klicke auf die „Export“-Schaltfläche (bzw. das ```⇪```-Symbol) und kopiere anschließend die im Editor angezeigte „URL to code...“. Sende diese URL an [@bookofshaders](https://twitter.com/bookofshaders) oder an [@kyndinfo](https://twitter.com/kyndinfo). Wir freuen uns auf tolle Shader und werden diese gerne unserer [Galerie mit Beispielen](https://thebookofshaders.com/examples/) hinzufügen.
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
# Appendix
|
||||
|
||||
1. [Wie kann ich dieses Buch offline lesen?](00/?lan=de)
|
||||
|
||||
2. [Wie kann ich die Beispielprogramme auf einem RaspberryPi ausführen?](01/?lan=de)
|
||||
|
||||
3. [Wie kann ich dieses Buch ausdrucken?](02/?lan=de)
|
||||
|
||||
4. [Wie kann ich zu diesem Buch beitragen?](03/?lan=de)
|
||||
|
||||
5. [An introduction for those coming from JS](04/) by [Nicolas Barradeau](http://www.barradeau.com/)
|
||||
|
||||
6. [An introduction for vectors](05/) by ...
|
||||
|
||||
7. [An introduction to interpolation](06) by ...
|
@ -0,0 +1,2 @@
|
||||
## Ausgewählte Beispiel Shader
|
||||
|
@ -0,0 +1,9 @@
|
||||
# Galerie mit ausgewählten Shader Beispielen
|
||||
|
||||
<p class="gallery_author">Kuratiert von <a href="https://www.kynd.info">kynd</a>(<a href="https://twitter.com/kyndinfo">@kyndinfo</a>) und Patricio Gonzalez Vivo(<a href="https://twitter.com/patriciogv">@patriciogv</a>)</p>
|
||||
|
||||
Dies ist eine Sammlung von Shader Beispielen aus den verschiedenen Kapiteln dieses Buches. Sie wird ergänzt durch weitere Shader, die von Lesern über den [Online-Editor](http://editor.thebookofshaders.com/) zur Verfügung gestellt wurden.
|
||||
|
||||
Du bist herzlich eingeladen, die verschiedenen Shader auszuprobieren, zu erweitern und zu verändern. Und natürlich kannst Du auch ganz neue Shader enwickeln.
|
||||
|
||||
Wenn Du Deine Arbeiten anderen Lesern zur Verfügung stellen möchtest, klicke auf die „Export“-Schaltfläche im Editor und kopiere anschließend den Inhalt des Feldes „URL to code...“. Sende diese URL an [@bookofshaders](https://twitter.com/bookofshaders) oder an [@kyndinfo](https://twitter.com/kyndinfo). Wir freuen uns auf Deine Ergebnisse.
|
Loading…
Reference in New Issue