diff --git a/00/README-ch.md b/00/README-ch.md index 693c88d..31c75f5 100644 --- a/00/README-ch.md +++ b/00/README-ch.md @@ -48,4 +48,4 @@ Fragment shaders(片段着色器)可以让你控制像素在屏幕上的快 * [做一个PDF版的书用于打印](https://thebookofshaders.com/appendix/) -* 用[github仓库](https://github.com/patriciogonzalezvivo/thebookofshaders)来帮助解决问题和分享代码 \ No newline at end of file +* 用[github仓库](https://github.com/patriciogonzalezvivo/thebookofshaders)来帮助解决问题和分享代码 diff --git a/00/README-de.md b/00/README-de.md index 9160d8e..624c98d 100644 --- a/00/README-de.md +++ b/00/README-de.md @@ -1,50 +1,49 @@ -# Einleitung - - - -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. - -Alternativ kannst Du auch: - -- [Eine Offline-Fassung dieses Buches erstellen](https://thebookofshaders.com/appendix/?lan=de) - -- [Die Beispielprogramme aus diesem Buch direkt auf einem RaspberryPi ausführen (ohne Internet-Browser)](https://thebookofshaders.com/appendix/?lan=de) - -- [Eine PDF-Datei mit diesem Buch erzeugen, um es auszudrucken](https://thebookofshaders.com/appendix/?lan=de) - -- Die [Online-Ablage dieses Buches](https://github.com/patriciogonzalezvivo/thebookofshaders) bei GitHub nutzen, um Fehler zu melden und Programmcode mit anderen Lesern zu teilen. - +# Einleitung + + + +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. + +Alternativ kannst Du auch: + +- [Eine Offline-Fassung dieses Buches erstellen](https://thebookofshaders.com/appendix/?lan=de) + +- [Die Beispielprogramme aus diesem Buch direkt auf einem RaspberryPi ausführen (ohne Internet-Browser)](https://thebookofshaders.com/appendix/?lan=de) + +- [Eine PDF-Datei mit diesem Buch erzeugen, um es auszudrucken](https://thebookofshaders.com/appendix/?lan=de) + +- Die [Online-Ablage dieses Buches](https://github.com/patriciogonzalezvivo/thebookofshaders) bei GitHub nutzen, um Fehler zu melden und Programmcode mit anderen Lesern zu teilen. diff --git a/00/README-fr.md b/00/README-fr.md index 7c12278..89e18af 100644 --- a/00/README-fr.md +++ b/00/README-fr.md @@ -1,4 +1,4 @@ -# Introduction +# Introduction @@ -42,7 +42,7 @@ ce que ce livre n'est pas: * ce *n'est pas* livre sur l'openGL ou le webGL. OpenGL/webGL dépasse de loin le GLSL ou les shaders. si vous voulez en savoir plus, les liens suivants vous aideront [OpenGL Introduction](https://open.gl/introduction), [the 8th edition of the OpenGL Programming Guide](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) (alias "the red book") ou [WebGL: Up and Running](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) * ce *n'est pas* un livre de maths. Même si le livre contient un certain nombre de notions et d'algorithmes nécessitant des connaissances en algèbre et en trigonométrie, nous ne rentrerons pas dans le détail. Pour toute question relative aux maths, vous pouvez choisir un de ces livres et le garder près de vous : [3rd Edition of Mathematics for 3D Game Programming and computer Graphics](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) ou [2nd Edition of Essential Mathematics for Games and Interactive Applications](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). - + ## bien démarrer @@ -57,4 +57,3 @@ Cela étant et selon ce que vous voulez faire de ce livre, vous pouvez : - [créer un PDF du livre pour l'imprimer](https://thebookofshaders.com/appendix/) - vous servir du [repo online](https://github.com/patriciogonzalezvivo/thebookofshaders) pour contribuer ou nous aider à débugger. - diff --git a/00/README-it.md b/00/README-it.md index 9ddab8d..a4199e5 100644 --- a/00/README-it.md +++ b/00/README-it.md @@ -47,4 +47,3 @@ In alternativa, in base a ciò di cui avete bisogno, è possibile: - [Fare un PDF del libro da stampare](https://thebookofshaders.com/appendix/) - Utilizzare la [repository on-line](https://github.com/patriciogonzalezvivo/thebookofshaders) per aiutare a risolvere i problemi e per condividere il codice. - diff --git a/00/README-kr.md b/00/README-kr.md index 2ffbe7d..ffa44dd 100644 --- a/00/README-kr.md +++ b/00/README-kr.md @@ -1,48 +1,47 @@ -# Introduction - - - -위에 두 이미지는 다른 방법을 통해 만들어졌다. 첫번째것은 반 고흐가 직접 레이어 위에 레이어를 쌓는 방식으로 만들어졌다. 제법 시간이 걸렸을것이다. 두번째것은 몇초 안되는 시간안에 픽셀들의 행렬연산 4개를 통해 만들어 졌다: 한개는 cyan색, 다른 한개는 magenta색, 또 다른 한개는 yellow, 그리고 마지막것은 black. 중요한점은 두번째 이미지는 그림을 부분마다 따로 그려나가게 아니라 그림의 다른 모든 부분이 한번에 그려졌다는 것이다. - -이 책은, *fragment shaders*, 라는 디지털 그림 제작과정을 다음 레벨로 이끌어낼 혁신적인 컴퓨팅 기술에 대한 것이다. 바로 그래픽 인더스트리의 구텐베르크 인쇄술인것이다. - -![Gutenberg's press](gutenpress.jpg) - -Fragment shader는 매우 빠른 속도로 스크린에 렌더되는 픽셀들을 완전히 컨트롤 할수 있는 능력을 준다. 핸드폰의 비디오 필터나, AAA 3D 비디오 같은 미디어에서 쓰이는 이유도 이것때문이다. - -![Journey by That Game Company](journey.jpg) - -앞으로 맞이할 챕터들은 독자가 이 강력하고 바른 기술을 스스로 습득하고, 자신의 작업에 적용할수 있는 길을 보여줄것이다. - -## 누구를 위한 책인가? - -이 책은 삼각함수와 선형대수학에 대한 기본이해가 있고 작업에 있어 그래픽 요소를 극대화 시키려는 creative coder, 게임 개발자, 그래픽 엔지니어들을 위한 책이다. (만약 본인이 코딩입문자라면 이 링크를 보고, [Processing](https://processing.org/) 코딩이 익숙해졌을때쯤 다시 돌아와 이책을 보길 권한다.) - -이책은 독자들에게 쉐이더를 프로젝트에 어떻게 쓰는지와, 이를 통한 퍼포먼스 향상과 퀄리티를 높이는 방법들을 보여줄것이다. GLSL (OpenGL Shading Language) 쉐이더들은 OpenGL, OpenGL ES 혹은 WebGL을 가진 환경에서 컴파일되고 실행될것이다. 한마디로, 이것에 대한 기술을 [Processing](https://processing.org/) 스켓치파일들, [openFrameworks](http://openframeworks.cc/) 어플들, [Cinder](http://libcinder.org/) 설치미술들, [Three.js](http://threejs.org/) 웹사이트들 또는 iOS/Android 게임들에 적용할수 있다는 것이다. - -## 어떤 내용들을 다루나? - -이책은 GLSL pixel shader를 메인으로 다룬다. 먼저, 쉐이더가 무엇인지 알아보고, 절차적(procedural) 모양, 패턴, 텍스쳐, 애니메이션등에 응용해볼것이다. 쉐이딩 랭기지의 기본에 대해 다지게 되고, 여러 분야에 적용해볼수 있도록 유도하는데 예를들면: 이미지 처리(이미지 여산, 메트릭스 회선, blurs, color filters, 룩업테이블과 기타 효과들)와 시뮬레이션 (Conway's game of life, Gray-Scott's reaction-diffusion, water ripples, 물감 효과, Voronoi cells등등)이 그 좋은 예이다. 책의 막바지에는 Ray Marching과 같은 고급기술도 소개를 한다. - -*각 챕터는 인터엑티브한 예제들로 구성되어 있다.* 예제들의 코드를 변경하면, 바로 그에 대한 결과를 볼수 있다. 컨셉자체가 추상적이거나 난해할수도 있기에, 이런 인터엑티브 예제가 이해하는데 큰 도움이 될거라고 믿는다. 컨셉에 대한 예제를 많이 가지고 놀아볼수록 그에 대한 이해역시 빨리 될거라고 생각한다. - -이책이 다루지 않는 부분: - -* 이책은 openGL이나 webGL서적이 아니다. openGL/webGL은 GLSL이나 fragment shader보다 훨씬 더 큰 주제이다. 그런것들에 대해 좀더 싶히 공부하고 싶다면: [OpenGL Introduction](https://open.gl/introduction), [the 8th edition of the OpenGL Programming Guide](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) (빨간책이라고도 알려진) 이나 [WebGL: Up and Running](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) 등을 추천한다. - -* 이책은 수학색이 아니라. 물론 여러 종류의 알고리즘과 대수학과, 삼각함수에 기댄 수학수식이 많이 이용되지만, 그런것들에 대해 자세히 설명하지는 않을 것이다. 수학에 대한 질문은 : [3rd Edition of Mathematics for 3D Game Programming and computer Graphics](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) 를 보거나, [2nd Edition of Essential Mathematics for Games and Interactive Applications](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) 등을 참고하기 바란다. - -## 시작하기 위해 무엇을 해야하나? - -필요한것은 따로 없다! 근대 브라우져를 이용하고 있다면, WebGL이 서포트 될것이고 (구글 크롬이나 파이어폭스, 사파리), 인터넷만 있으면 된다! (지금 보고 있지만) 페이지 최하단에 있는 "Next"버튼을 눌러 다음챕터로 가면 시작이다. - -아니면 , 다음과 같은 방법으로도 이 책을 접할수 있다: - -- [이책의 오프라인 버젼](https://thebookofshaders.com/appendix/) - -- [Raspberry Pi에서 브라우져 없이 예제들 돌리기](https://thebookofshaders.com/appendix/) - -- [이책의 PDF버젼 만들기](https://thebookofshaders.com/appendix/) - -- 또는 [온라인 리포](https://github.com/patriciogonzalezvivo/thebookofshaders) 이슈들을 답하거나, 올려주세요. - +# Introduction + + + +위에 두 이미지는 다른 방법을 통해 만들어졌다. 첫번째것은 반 고흐가 직접 레이어 위에 레이어를 쌓는 방식으로 만들어졌다. 제법 시간이 걸렸을것이다. 두번째것은 몇초 안되는 시간안에 픽셀들의 행렬연산 4개를 통해 만들어 졌다: 한개는 cyan색, 다른 한개는 magenta색, 또 다른 한개는 yellow, 그리고 마지막것은 black. 중요한점은 두번째 이미지는 그림을 부분마다 따로 그려나가게 아니라 그림의 다른 모든 부분이 한번에 그려졌다는 것이다. + +이 책은, *fragment shaders*, 라는 디지털 그림 제작과정을 다음 레벨로 이끌어낼 혁신적인 컴퓨팅 기술에 대한 것이다. 바로 그래픽 인더스트리의 구텐베르크 인쇄술인것이다. + +![Gutenberg's press](gutenpress.jpg) + +Fragment shader는 매우 빠른 속도로 스크린에 렌더되는 픽셀들을 완전히 컨트롤 할수 있는 능력을 준다. 핸드폰의 비디오 필터나, AAA 3D 비디오 같은 미디어에서 쓰이는 이유도 이것때문이다. + +![Journey by That Game Company](journey.jpg) + +앞으로 맞이할 챕터들은 독자가 이 강력하고 바른 기술을 스스로 습득하고, 자신의 작업에 적용할수 있는 길을 보여줄것이다. + +## 누구를 위한 책인가? + +이 책은 삼각함수와 선형대수학에 대한 기본이해가 있고 작업에 있어 그래픽 요소를 극대화 시키려는 creative coder, 게임 개발자, 그래픽 엔지니어들을 위한 책이다. (만약 본인이 코딩입문자라면 이 링크를 보고, [Processing](https://processing.org/) 코딩이 익숙해졌을때쯤 다시 돌아와 이책을 보길 권한다.) + +이책은 독자들에게 쉐이더를 프로젝트에 어떻게 쓰는지와, 이를 통한 퍼포먼스 향상과 퀄리티를 높이는 방법들을 보여줄것이다. GLSL (OpenGL Shading Language) 쉐이더들은 OpenGL, OpenGL ES 혹은 WebGL을 가진 환경에서 컴파일되고 실행될것이다. 한마디로, 이것에 대한 기술을 [Processing](https://processing.org/) 스켓치파일들, [openFrameworks](http://openframeworks.cc/) 어플들, [Cinder](http://libcinder.org/) 설치미술들, [Three.js](http://threejs.org/) 웹사이트들 또는 iOS/Android 게임들에 적용할수 있다는 것이다. + +## 어떤 내용들을 다루나? + +이책은 GLSL pixel shader를 메인으로 다룬다. 먼저, 쉐이더가 무엇인지 알아보고, 절차적(procedural) 모양, 패턴, 텍스쳐, 애니메이션등에 응용해볼것이다. 쉐이딩 랭기지의 기본에 대해 다지게 되고, 여러 분야에 적용해볼수 있도록 유도하는데 예를들면: 이미지 처리(이미지 여산, 메트릭스 회선, blurs, color filters, 룩업테이블과 기타 효과들)와 시뮬레이션 (Conway's game of life, Gray-Scott's reaction-diffusion, water ripples, 물감 효과, Voronoi cells등등)이 그 좋은 예이다. 책의 막바지에는 Ray Marching과 같은 고급기술도 소개를 한다. + +*각 챕터는 인터엑티브한 예제들로 구성되어 있다.* 예제들의 코드를 변경하면, 바로 그에 대한 결과를 볼수 있다. 컨셉자체가 추상적이거나 난해할수도 있기에, 이런 인터엑티브 예제가 이해하는데 큰 도움이 될거라고 믿는다. 컨셉에 대한 예제를 많이 가지고 놀아볼수록 그에 대한 이해역시 빨리 될거라고 생각한다. + +이책이 다루지 않는 부분: + +* 이책은 openGL이나 webGL서적이 아니다. openGL/webGL은 GLSL이나 fragment shader보다 훨씬 더 큰 주제이다. 그런것들에 대해 좀더 싶히 공부하고 싶다면: [OpenGL Introduction](https://open.gl/introduction), [the 8th edition of the OpenGL Programming Guide](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) (빨간책이라고도 알려진) 이나 [WebGL: Up and Running](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) 등을 추천한다. + +* 이책은 수학색이 아니라. 물론 여러 종류의 알고리즘과 대수학과, 삼각함수에 기댄 수학수식이 많이 이용되지만, 그런것들에 대해 자세히 설명하지는 않을 것이다. 수학에 대한 질문은 : [3rd Edition of Mathematics for 3D Game Programming and computer Graphics](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) 를 보거나, [2nd Edition of Essential Mathematics for Games and Interactive Applications](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) 등을 참고하기 바란다. + +## 시작하기 위해 무엇을 해야하나? + +필요한것은 따로 없다! 근대 브라우져를 이용하고 있다면, WebGL이 서포트 될것이고 (구글 크롬이나 파이어폭스, 사파리), 인터넷만 있으면 된다! (지금 보고 있지만) 페이지 최하단에 있는 "Next"버튼을 눌러 다음챕터로 가면 시작이다. + +아니면 , 다음과 같은 방법으로도 이 책을 접할수 있다: + +- [이책의 오프라인 버젼](https://thebookofshaders.com/appendix/) + +- [Raspberry Pi에서 브라우져 없이 예제들 돌리기](https://thebookofshaders.com/appendix/) + +- [이책의 PDF버젼 만들기](https://thebookofshaders.com/appendix/) + +- 또는 [온라인 리포](https://github.com/patriciogonzalezvivo/thebookofshaders) 이슈들을 답하거나, 올려주세요. diff --git a/00/README.md b/00/README.md index 2115a68..1ddc000 100644 --- a/00/README.md +++ b/00/README.md @@ -2,7 +2,7 @@ -The images above were made in different ways. The first one was made by Van Gogh's hand applying layer over layer of paint. It took him hours. The second was produced in seconds by the combination of four matrices of pixels: one for cyan, one for magenta, one for yellow and one for black. The key difference is that the second image is produced in a non-serial way (that means not step-by-step, but all at the same time). +The images above were made in different ways. The first one was made by Van Gogh's hand applying layer over layer of paint. It took him hours. The second was produced in seconds by the combination of four matrices of pixels: one for cyan, one for magenta, one for yellow and one for black. The key difference is that the second image is produced in a non-serial way (that means not step-by-step, but all at the same time). This book is about the revolutionary computational technique, *fragment shaders*, that is taking digitally generated images to the next level. You can think of it as the equivalent of Gutenberg's press for graphics. @@ -45,4 +45,3 @@ Alternatively, based on what you have or what you need from this book you can: - [Make a PDF of the book to print](https://thebookofshaders.com/appendix/) - Use the [on-line repository](https://github.com/patriciogonzalezvivo/thebookofshaders) to help resolve issues and share code. - diff --git a/00/cmyk-halftone.frag b/00/cmyk-halftone.frag index 40d8452..ad83b96 100644 --- a/00/cmyk-halftone.frag +++ b/00/cmyk-halftone.frag @@ -14,7 +14,7 @@ precision mediump float; #define SST 0.888 #define SSQ 0.288 -uniform sampler2D u_tex0; +uniform sampler2D u_tex0; uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; @@ -72,7 +72,7 @@ void main() { mat2 mm = rotm(R+D2R(75.0)); mat2 my = rotm(R); mat2 mk = rotm(R+D2R(45.0)); - + float k = halftone(fc,mk).a; vec4 c = cmyki2rgb(ss(vec4( halftone(fc,mc).r, @@ -86,6 +86,6 @@ void main() { st = vec2(st.x,st.y*0.5)*2.0; gl_FragColor = texture2D(u_tex0,st); } - - -} \ No newline at end of file + + +} diff --git a/00/halftone.frag b/00/halftone.frag index 251598e..6f46466 100644 --- a/00/halftone.frag +++ b/00/halftone.frag @@ -2,7 +2,7 @@ precision mediump float; #endif -uniform sampler2D u_tex0; +uniform sampler2D u_tex0; uniform vec2 u_resolution; uniform vec2 u_mouse; @@ -30,7 +30,7 @@ void main () { if (st.x > 0.5) { // Halftone dot matrix shader // @author Tomek Augustyn 2010 - + // Ported from my old PixelBender experiment // https://github.com/og2t/HiSlope/blob/master/src/hislope/pbk/fx/halftone/Halftone.pbk float ratio = u_resolution.y / u_resolution.x; @@ -39,25 +39,25 @@ void main () { vec2 srcCoord = vec2(st.x-0.5, st.y*0.5)*2.0; vec2 rotationCenter = vec2(0.5); vec2 shift = dstCoord - rotationCenter; - + float dotSize = 5.0; float angle = 45.0; - + float rasterPattern = added(shift, sind(angle), cosd(angle), rotationCenter, PI / dotSize * 680.0); vec4 srcPixel = texture2D(u_tex0, srcCoord); - + float avg = 0.2125 * srcPixel.r + 0.7154 * srcPixel.g + 0.0721 * srcPixel.b; float gray = (rasterPattern * threshold + avg - threshold) / (1.0 - threshold); - // uncomment to see how the raster pattern looks + // uncomment to see how the raster pattern looks // gray = rasterPattern; - + gl_FragColor = vec4(gray, gray, gray, 1.0); } else { st = vec2(st.x,st.y*0.5)*2.0; gl_FragColor = texture2D(u_tex0, st); } - - + + } diff --git a/00/index.php b/00/index.php index a6df888..0f2dc41 100644 --- a/00/index.php +++ b/00/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/01/README-ch.md b/01/README-ch.md index d04e8ab..26e2e9e 100644 --- a/01/README-ch.md +++ b/01/README-ch.md @@ -29,7 +29,7 @@ Shaders 也是一系列的指令,但是这些指令会对屏幕上的每个像 ![GPU](04.jpeg) -设想一堆小型微处理器排成一个平面的画面,假设每个像素的数据是乒乓球。14400000个乒乓球可以在一秒内阻塞几乎任何管道。但是一面800x600的管道墙,每秒接收30波480000个像素的信息就可以流畅完成。这在更高的分辨率下也是成立的 —— 并行的处理器越多,可以处理的数据流就越大。 +设想一堆小型微处理器排成一个平面的画面,假设每个像素的数据是乒乓球。14400000个乒乓球可以在一秒内阻塞几乎任何管道。但是一面800x600的管道墙,每秒接收30波480000个像素的信息就可以流畅完成。这在更高的分辨率下也是成立的 —— 并行的处理器越多,可以处理的数据流就越大。 另一个 GPU 的魔法是特殊数学函数可通过硬件加速。非常复杂的数学操作可以直接被微芯片解决,而无须通过软件。这就表示可以有更快的三角和矩阵运算 —— 和电流一样快。 @@ -45,4 +45,4 @@ GLSL 代表 openGL Shading Language,openGL 着色语言,这是你在接下 并且 GPU 会让所有并行的微处理器(管道们)一直处在忙碌状态;只要它们一有空闲就会接到新的信息。一个线程不可能知道它前一刻在做什么。它可能是在画操作系统界面上的一个按钮,然后渲染了游戏中的一部分天空,然后显示了一封 email 中的一些文字。每个线程不仅是“盲视”的,而且还是“无记忆”的。同时,它要求编写一个通用的规则,依据像素的不同位置依次输出不同的结果。这种抽象性,和盲视、无记忆的限制使得 shaders 在程序员新手中不是很受欢迎。 -但是不要担心!在接下来的章节中,我们会一步一步地,由浅入深地学习着色语言。如果你是在用一个靠谱的浏览器阅读这个教程,你会喜欢边读边玩书中的示例的。好了,不要再浪费时间了,赶快去玩起来吧! 点击 **Next >>** 开启 shader 之旅! \ No newline at end of file +但是不要担心!在接下来的章节中,我们会一步一步地,由浅入深地学习着色语言。如果你是在用一个靠谱的浏览器阅读这个教程,你会喜欢边读边玩书中的示例的。好了,不要再浪费时间了,赶快去玩起来吧! 点击 **Next >>** 开启 shader 之旅! diff --git a/01/README-de.md b/01/README-de.md index 1dd2920..ecdc774 100644 --- a/01/README-de.md +++ b/01/README-de.md @@ -1,48 +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. +# 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. diff --git a/01/README-it.md b/01/README-it.md index a1d9c14..be7838b 100644 --- a/01/README-it.md +++ b/01/README-it.md @@ -45,4 +45,4 @@ Affinché ogni tubo, o thread, venga eseguito in parallelo, è necessario che si Anche la GPU mantiene costantemente occupati i micro-processore paralleli (i tubi); non appena sono liberi ricevono nuove informazioni da elaborare. E' quindi impossibile per un thread sapere che cosa stava facendo nel momento precedente. Potrebbe disegnare un bottone dell'UI del sistema operativo, subito dopo rendere una porzione di cielo in un videogioco e poi visualizzare il testo di una e-mail. Ogni thread non è solo **cieco ** ma anche **senza memoria**. Oltre all'astrazione necessaria per programmare una funzione generica che cambia il risultato pixel per pixel, a seconda della sua posizione, i vincoli ciechi e senza memoria non rendono gli shaders molto popolari tra i programmatori debuttanti. -Non preoccuparti! Nei capitoli seguenti, impareremo passo-passo a partire dai semplici shaders fino a quelli avanzati. Se stai leggendo questo libro con un navigatore moderno, potrai giocare con gli esempi interattivi. Quindi non aspettare altro tempo e clicca su *Next >>* per iniziare il divertimento! \ No newline at end of file +Non preoccuparti! Nei capitoli seguenti, impareremo passo-passo a partire dai semplici shaders fino a quelli avanzati. Se stai leggendo questo libro con un navigatore moderno, potrai giocare con gli esempi interattivi. Quindi non aspettare altro tempo e clicca su *Next >>* per iniziare il divertimento! diff --git a/01/README-kr.md b/01/README-kr.md index 7107391..d609d3c 100644 --- a/01/README-kr.md +++ b/01/README-kr.md @@ -33,16 +33,16 @@ CPU가 하나의 큰 공장같은 파이프라고 가정하자. 파이프로 들 GPU의 또다른 슈퍼파워중 하나는, 하드웨어지원으로 가속된 수학 함수 연산이다. 즉, 소프트웨어상에서가 아닌, 마이크로칩상에서 바로 연산이 진행된다는 이야기다. 이말은 더 많은 삼각함수연산, 매트릭스연산이 가능하다는 말이다 - 전기가 얼마나 빠르게 흐르냐에 따라. -## GLSL은 무엇인가? +## GLSL은 무엇인가? -GLSL은 openGL Shading Language의 줄임말로, 앞으로의 챕터들에서 쓰게될 쉐이더 프로그램 랭기지이다. 하드웨어나 운영체제에 따라 이 언어는 달라지기도 한다. 이 책에서는 크로노스그룹에서 규정된 openGL 규격을 따른다. [Khronos Group](https://www.khronos.org/opengl/). OpenGL의 역사를 이해하는것 또한 앞으로 보게될 전문용어들에 크게 도움이 될것이며, 아래 링크를 추천한다: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) +GLSL은 openGL Shading Language의 줄임말로, 앞으로의 챕터들에서 쓰게될 쉐이더 프로그램 랭기지이다. 하드웨어나 운영체제에 따라 이 언어는 달라지기도 한다. 이 책에서는 크로노스그룹에서 규정된 openGL 규격을 따른다. [Khronos Group](https://www.khronos.org/opengl/). OpenGL의 역사를 이해하는것 또한 앞으로 보게될 전문용어들에 크게 도움이 될것이며, 아래 링크를 추천한다: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## 왜 쉐이더를 사람들이 어렵다고 할까? -2차 세계대전에서 쌀공급으로 유명한 미국의 벤삼촌이 이르길, "큰 힘에는 큰 책임이 따른다"고 했다. 병렬연산또한 이 법칙을 따른다; GPU의 강력한 컴퓨테이션 능력은 이것을 쓰기위해 따라야할 제약과 제한이 있다. +2차 세계대전에서 쌀공급으로 유명한 미국의 벤삼촌이 이르길, "큰 힘에는 큰 책임이 따른다"고 했다. 병렬연산또한 이 법칙을 따른다; GPU의 강력한 컴퓨테이션 능력은 이것을 쓰기위해 따라야할 제약과 제한이 있다. 파이프상에서 병렬처리를 하기위해서는, 각 쓰레드마다, 서로에 대해 철저히 개별적이여야 한다. 쓰레드는 다른 쓰레드에 대해 "실명" 되어 있다고 미국에서는 표현하는데, 서로의 데이터에 대해 엑세스가 없다는 말이다. 그래서 각각의 프로세스들은 서로 데이터를 주고 받고 처리하는것이 불가능하다. 쓰레드끼리 소통하게 하는것은 데이터를 더럽힐수 있다. 또한, GPU는 모든 병렬 마이크로 프로세서들 (파이프들) 을 항시 바쁘게 하고 있다; 이 파이프들은 해당작업이 끝나는 대로 다른 작업을 받아 수행하도록 설계되어 있다. 또한, 각 쓰레드는 이미 수행한 작업에 대한 어떠한 정보도 가질수 없다. 보통 이런 작업들은 운영체제의 UI요소를 그리고 있는것이거나, 게임의 배경화면을 그리거나, 브라우져의 이메일 텍스트를 그리는 것들이다. 각 쓰레드는 서로에게 **실명**되있다고 표현할뿐아니라, **기억이없음** 이라고도 표현하는데, 이것은 이미 수행한 작업에 대한 어떠한 정보도 가지고 있지 않다는 말이다. 바로 이런 점들이 일반적인 프로그래밍 요소와 크게 다른부분이라고 할수 있어서 프로그래밍을 막 접한 이들에게는 어려운 컨셉일수도 있는것이다. -하지만 걱정하지 마시라! 앞으로의 챕터들에서 우리는 간단한 것부터 복잡한 쉐이딩 연산들에 대해 하나씩 짚고 넘어갈 것이다. 만약 당신이 이 책을 근대 브라우져에서 읽오 있다면, 인터엑티브한 예제들로 인해 공부에 도움을 받을것이다. 더이상 지겨운 서론은 짚어 치우고, *Next >>*를 누르고 코드로 넘어가보자! \ No newline at end of file +하지만 걱정하지 마시라! 앞으로의 챕터들에서 우리는 간단한 것부터 복잡한 쉐이딩 연산들에 대해 하나씩 짚고 넘어갈 것이다. 만약 당신이 이 책을 근대 브라우져에서 읽오 있다면, 인터엑티브한 예제들로 인해 공부에 도움을 받을것이다. 더이상 지겨운 서론은 짚어 치우고, *Next >>*를 누르고 코드로 넘어가보자! diff --git a/01/README.md b/01/README.md index aa4e71a..a3f0073 100644 --- a/01/README.md +++ b/01/README.md @@ -1,7 +1,7 @@ # Getting started ## What is a fragment shader? -In the previous chapter we described shaders as the equivalent of the Gutenberg press for graphics. Why? And more importantly: what's a shader? +In the previous chapter we described shaders as the equivalent of the Gutenberg press for graphics. Why? And more importantly: what's a shader? ![From Letter-by-Letter, Right: William Blades (1891). To Page-by-page, Left: Rolt-Wheeler (1920).](print.png) @@ -33,13 +33,13 @@ Picture the tiny microprocessors as a table of pipes, and the data of each pixel Another “super power” of the GPU is special math functions accelerated via hardware, so complicated math operations are resolved directly by the microchips instead of by software. That means extra fast trigonometrical and matrix operations - as fast as electricity can go. -## What is GLSL? +## What is GLSL? -GLSL stands for openGL Shading Language, which is the specific standard of shader programs you'll see in the following chapters. There are other types of shaders depending on hardware and Operating Systems. Here we will work with the openGL specs regulated by [Khronos Group](https://www.khronos.org/opengl/). Understanding the history of OpenGL can be helpful for understanding most of its weird conventions, for that I recommend taking a look at: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) +GLSL stands for openGL Shading Language, which is the specific standard of shader programs you'll see in the following chapters. There are other types of shaders depending on hardware and Operating Systems. Here we will work with the openGL specs regulated by [Khronos Group](https://www.khronos.org/opengl/). Understanding the history of OpenGL can be helpful for understanding most of its weird conventions, for that I recommend taking a look at: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## Why are Shaders famously painful? -As Uncle Ben said “with great power comes great responsibility,” and parallel computation follows this rule; the powerful architectural design of the GPU comes with its own constraints and restrictions. +As Uncle Ben said “with great power comes great responsibility,” and parallel computation follows this rule; the powerful architectural design of the GPU comes with its own constraints and restrictions. In order to run in parallel every pipe, or thread, has to be independent from every other thread. We say the threads are *blind* to what the rest of the threads are doing. This restriction implies that all data must flow in the same direction. So it’s impossible to check the result of another thread, modify the input data, or pass the outcome of a thread into another thread. Allowing thread-to-thread communications puts the integrity of the data at risk. diff --git a/01/index.php b/01/index.php index 1022e00..b7b9033 100644 --- a/01/index.php +++ b/01/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/01/notes.md b/01/notes.md index 8b8353e..dd4fb91 100644 --- a/01/notes.md +++ b/01/notes.md @@ -5,4 +5,4 @@ ### Nicolas B * clearly answer the "what is a fragment shader?" question in some sort of recap paragraph. -* beef up explanations around the compilation step (a brief overview will do). \ No newline at end of file +* beef up explanations around the compilation step (a brief overview will do). diff --git a/02/README-ch.md b/02/README-ch.md index 0db60c4..fe869ab 100644 --- a/02/README-ch.md +++ b/02/README-ch.md @@ -5,7 +5,7 @@ 然而在 GPU 的世界里,第一步就渲染一行文字太难了,所以我们改为选择一个鲜艳的欢迎色,来吧躁起来!
- + 如果你是在线阅读这本书的话,上面的代码都是可以交互的。你可以点击或者改动代码中任何一部分,尽情探索。多亏 GPU 的架构,shader 会**飞速**地编译和更新,这使得你的改动都会立刻出现在你眼前。试试改动第6行的值,看会发生什么。 尽管这几行简单的代码看起来不像有很多内容,我们还是可以据此推测出一些知识点: diff --git a/02/README-de.md b/02/README-de.md index 89d6ff2..9132e24 100644 --- a/02/README-de.md +++ b/02/README-de.md @@ -1,53 +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. - -
- -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); // potenzielle 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 des zu bearbeitenden Pixels innerhalb der Zeichenfläche) und der Zeit (d.h. der Zeitspanne, die seit dem Laden einer Seite vergangen ist). +## 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. + +
+ +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); // potenzielle 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 des zu bearbeitenden Pixels innerhalb der Zeichenfläche) und der Zeit (d.h. der Zeitspanne, die seit dem Laden einer Seite vergangen ist). diff --git a/02/README-it.md b/02/README-it.md index ab6340d..2cb09f5 100644 --- a/02/README-it.md +++ b/02/README-it.md @@ -5,7 +5,7 @@ Di solito l'esempio "Ciao Mondo!" è il primo passo per imparare un nuovo lingua Nel mondo GPU rendere un testo è un esercizio troppo complicato per un primo passo, perciò sceglieremo un colore brillante di benvenuto per mostrare il nostro entusiasmo!
- + Se stai leggendo questo libro in un navigatore, noterai che il precedente blocco di codice è interattivo. Ciò significa che è possibile fare click e modificare qualsiasi parte del codice per capire come funziona. Le modifiche verranno aggiornate immediatamente grazie all'architettura GPU che compila e sostituisce gli shaders *al volo*. Prova per esempio a cambiare i valori della linea 6. Anche se queste semplici righe di codice non sembrano essere molto importanti, possiamo trarre molte informazioni: diff --git a/02/README-kr.md b/02/README-kr.md index af6584d..ba64e40 100644 --- a/02/README-kr.md +++ b/02/README-kr.md @@ -1,53 +1,53 @@ -## Hello World - -보통 "Hello world!" 예제들은 모든 컴퓨터 언어의 시작챕터의 제목이다. 라인하나를 출력하는 명령어로 보통 시작되며, 이 언어가 어떤 것들을 할수 있는지에 대한 첫번째 발걸음을 시작한다. - -GPU-세상에서는 이런 문자열을 출력하는것은 첫번째 발걸음으로 다소 복잡한 경향이 있다. 하여, 우리는 밝은 색하나를 출력하는 것으로 대신해 발걸음을 떼어본다! - -
- -이첵을 브라우져에서 읽고 있다면, 위에 구간이 상호작용이 가능하다는것을 알수 있다. 클릭하거나, 코드를 수정하여 결과를 바로 볼수 있다는 것이다. 이런 변화 인풋은 바로 GPU파이프라인으로 주입되어 컴파일되고, *실시간으로* 결과를 바꿔준다. 6번째 줄의 코드를 수정하여 이를 체험해보시라. - -매우 간단한 코드지만, 상당히 중요한 내용을 우리는 엿볼수 있는데: - -1. 쉐이더 언어는 color값을 리턴하는 ```main``` 함수이고, 이는 C와 형태가 유사하다. - -2. 마지막으로 리턴되는 픽셀 색 값은, ```gl_FragColor```라는 전역변수에 대입된다. - -3. 이 C-유형의 언어는, 미리 선언된, *변수*들 (```gl_FragColor```같은), *함수* 와 *타입*를 가진다. 이 예제의 경우, 실수로 이루어진 4차원 벡터 타입인, ```vec4```. 더 나아가면서, ```vec3``` 나 ```vec2```, ```float```, ```int```, 또한 ```bool```같은 것들이 보이게 될것이다. - -4. '''vec4''' 타입을 자세히 살펴보면, 각 인수는 RED, GREEN, BLUE and ALPHA 채널이다. 이 값들은 *노멀라이즈된* 값이 ```0.0``` 에서 ```1.0``` 으로 맵핑된것이다. 나중에 나아가면서 노멀라이징을 어떻게 하는지, *map* 을 어떻게 하는지 살펴보게 될것이다. - -5. 예제에서 볼수 있는 또 다른 중요한 *C 요소*는 전처리기 마크로들에 대한 사용이다. 마크로들은 컴파일되기 전에 일어나는 스텝이다. ```#define```을 이용해, 전역변수를 선언하거나, 기본적인 논리구현이 가능하다 (```#ifdef```나 ```#endif```를 통해). 모든 마크로는 해쉬태그 마크 (```#```) 로 시작한다. 이런 Pre-compilation은 컴파일이 실제로 일어나기 바로 전에 각 해쉬태그의 해당값을 이 코드로 카피한다. 위에 예제 'hello world!'를 보면, 우리는 ```GL_ES```를 선언하였는데, 이는 모바일 기기나, 브라우져에서 컴파일될때 전처리되는 부분들인 것이다. - -6. 실수 타입들은 쉐이더에서 신경써야할 부분중 하나인데, *precision(실수정확도)*의 정도가 퍼포먼스에 영향을 미치기 때문이다. 낮은 정도의 precision을 가질수록 빠른 렌더 속도를 가지지만, 렌더 퀄리티가 그만큼 떨어진다는 것을 의미한다. 첫번째 라인을 보면, (```precision mediump float;```) 라는 내용이 보이는데, 실수정확도를 중간정도로 맞춘것이다. 높게는 (```precision lowp float;```) 낮게는 (```precision lowp float;```)이다. - -7. 마지막으로, 그리고 제일 중요할지도 모르지만, GLSL에서는 데이터 타입의 casting이 확보되지 않는다. 무슨말인가하면, 제조업체들은 그래픽카드의 연산을 가속화 하기위해 각각 다른 시도들을 하였는데, 결국은 이것은 최소사양을 저격하고 있다. 자동 casting같은 경우는 여기에 포함되지 않고 있다. 우리의 "hello world!" 예제의 ```vec4``` 또한, ```floats```라는 데이터타입을 예상하게 되는것이다. 앞으로 쉐이더 프로그램을 하면서 실수의 경우에는 항상 점 (```.```) 을 포함하여 이 변수가, 값이 실수임을 명시하자. 예를들어 아래와 같은 코드는 작동이 안될것이다: - -```glsl -void main() { - gl_FragColor = vec4(1,0,0,1); // ERROR -} -``` - -자, 이제 우리의 첫 예제인 "hello world!"프로그램에 대한 설명을 마친다. 예제의 코드를 수정하면서 이 단원에서 배운 내용을 곱씹어보는 시간을 갖길 바란다. 만약 코드에 에러가 있다면 컴파일 에러가 나면서 화면이 하얗게 될것이다. 아래와 같은 재밌는 시도들도 해볼수 있을것이다.: - -* 실수값들을 정수값들로 바꿔보고, 본인의 그래픽 카드가 이값을 인식하고 아웃풋하는 결과를 보라. - -* 6번째 라인을 코멘트아웃하고, 함수의 픽셀값에 아무런 값도 넣어보지 말라. - -* ```main()```안에, 새로운 함수를 만들고 새로운 값을 리턴하게 해보라, 힌트로는 아래는 빨간색을 리턴하는 함수다 : - -```glsl -vec4 red(){ - return vec4(1.0,0.0,0.0,1.0); -} -``` - -* ```vec4```값을 만드는 방법을 여러가지가 있다. 아래역시 그중하나이다: - -```glsl -vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); -``` - -이 예제 자체가 그리 흥미롭지는 않지만 매우 중요한 기본 예제중 하나이다 - 캔바스의 모든 색을 같은색으로 바꿔보는 작업. 다음에 오는 챕터에서는 픽셀 색들을 2개의 인풋을 사용하여 바꿔보는 예제를 해볼것이다. (스크린위에 픽셀들의 위치를 이용한) 그리고 시간을 이용해 이들을 바꾸는 작업도 해볼것이다. (페이지가 로드완료된 후로 몇초가 지났는지를 이용한) \ No newline at end of file +## Hello World + +보통 "Hello world!" 예제들은 모든 컴퓨터 언어의 시작챕터의 제목이다. 라인하나를 출력하는 명령어로 보통 시작되며, 이 언어가 어떤 것들을 할수 있는지에 대한 첫번째 발걸음을 시작한다. + +GPU-세상에서는 이런 문자열을 출력하는것은 첫번째 발걸음으로 다소 복잡한 경향이 있다. 하여, 우리는 밝은 색하나를 출력하는 것으로 대신해 발걸음을 떼어본다! + +
+ +이첵을 브라우져에서 읽고 있다면, 위에 구간이 상호작용이 가능하다는것을 알수 있다. 클릭하거나, 코드를 수정하여 결과를 바로 볼수 있다는 것이다. 이런 변화 인풋은 바로 GPU파이프라인으로 주입되어 컴파일되고, *실시간으로* 결과를 바꿔준다. 6번째 줄의 코드를 수정하여 이를 체험해보시라. + +매우 간단한 코드지만, 상당히 중요한 내용을 우리는 엿볼수 있는데: + +1. 쉐이더 언어는 color값을 리턴하는 ```main``` 함수이고, 이는 C와 형태가 유사하다. + +2. 마지막으로 리턴되는 픽셀 색 값은, ```gl_FragColor```라는 전역변수에 대입된다. + +3. 이 C-유형의 언어는, 미리 선언된, *변수*들 (```gl_FragColor```같은), *함수* 와 *타입*를 가진다. 이 예제의 경우, 실수로 이루어진 4차원 벡터 타입인, ```vec4```. 더 나아가면서, ```vec3``` 나 ```vec2```, ```float```, ```int```, 또한 ```bool```같은 것들이 보이게 될것이다. + +4. '''vec4''' 타입을 자세히 살펴보면, 각 인수는 RED, GREEN, BLUE and ALPHA 채널이다. 이 값들은 *노멀라이즈된* 값이 ```0.0``` 에서 ```1.0``` 으로 맵핑된것이다. 나중에 나아가면서 노멀라이징을 어떻게 하는지, *map* 을 어떻게 하는지 살펴보게 될것이다. + +5. 예제에서 볼수 있는 또 다른 중요한 *C 요소*는 전처리기 마크로들에 대한 사용이다. 마크로들은 컴파일되기 전에 일어나는 스텝이다. ```#define```을 이용해, 전역변수를 선언하거나, 기본적인 논리구현이 가능하다 (```#ifdef```나 ```#endif```를 통해). 모든 마크로는 해쉬태그 마크 (```#```) 로 시작한다. 이런 Pre-compilation은 컴파일이 실제로 일어나기 바로 전에 각 해쉬태그의 해당값을 이 코드로 카피한다. 위에 예제 'hello world!'를 보면, 우리는 ```GL_ES```를 선언하였는데, 이는 모바일 기기나, 브라우져에서 컴파일될때 전처리되는 부분들인 것이다. + +6. 실수 타입들은 쉐이더에서 신경써야할 부분중 하나인데, *precision(실수정확도)*의 정도가 퍼포먼스에 영향을 미치기 때문이다. 낮은 정도의 precision을 가질수록 빠른 렌더 속도를 가지지만, 렌더 퀄리티가 그만큼 떨어진다는 것을 의미한다. 첫번째 라인을 보면, (```precision mediump float;```) 라는 내용이 보이는데, 실수정확도를 중간정도로 맞춘것이다. 높게는 (```precision lowp float;```) 낮게는 (```precision lowp float;```)이다. + +7. 마지막으로, 그리고 제일 중요할지도 모르지만, GLSL에서는 데이터 타입의 casting이 확보되지 않는다. 무슨말인가하면, 제조업체들은 그래픽카드의 연산을 가속화 하기위해 각각 다른 시도들을 하였는데, 결국은 이것은 최소사양을 저격하고 있다. 자동 casting같은 경우는 여기에 포함되지 않고 있다. 우리의 "hello world!" 예제의 ```vec4``` 또한, ```floats```라는 데이터타입을 예상하게 되는것이다. 앞으로 쉐이더 프로그램을 하면서 실수의 경우에는 항상 점 (```.```) 을 포함하여 이 변수가, 값이 실수임을 명시하자. 예를들어 아래와 같은 코드는 작동이 안될것이다: + +```glsl +void main() { + gl_FragColor = vec4(1,0,0,1); // ERROR +} +``` + +자, 이제 우리의 첫 예제인 "hello world!"프로그램에 대한 설명을 마친다. 예제의 코드를 수정하면서 이 단원에서 배운 내용을 곱씹어보는 시간을 갖길 바란다. 만약 코드에 에러가 있다면 컴파일 에러가 나면서 화면이 하얗게 될것이다. 아래와 같은 재밌는 시도들도 해볼수 있을것이다.: + +* 실수값들을 정수값들로 바꿔보고, 본인의 그래픽 카드가 이값을 인식하고 아웃풋하는 결과를 보라. + +* 6번째 라인을 코멘트아웃하고, 함수의 픽셀값에 아무런 값도 넣어보지 말라. + +* ```main()```안에, 새로운 함수를 만들고 새로운 값을 리턴하게 해보라, 힌트로는 아래는 빨간색을 리턴하는 함수다 : + +```glsl +vec4 red(){ + return vec4(1.0,0.0,0.0,1.0); +} +``` + +* ```vec4```값을 만드는 방법을 여러가지가 있다. 아래역시 그중하나이다: + +```glsl +vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); +``` + +이 예제 자체가 그리 흥미롭지는 않지만 매우 중요한 기본 예제중 하나이다 - 캔바스의 모든 색을 같은색으로 바꿔보는 작업. 다음에 오는 챕터에서는 픽셀 색들을 2개의 인풋을 사용하여 바꿔보는 예제를 해볼것이다. (스크린위에 픽셀들의 위치를 이용한) 그리고 시간을 이용해 이들을 바꾸는 작업도 해볼것이다. (페이지가 로드완료된 후로 몇초가 지났는지를 이용한) diff --git a/02/README.md b/02/README.md index 2aa745e..3c1e05b 100644 --- a/02/README.md +++ b/02/README.md @@ -1,11 +1,11 @@ ## Hello World -Usually the "Hello world!" example is the first step to learning a new language. It's a simple one-line program that outputs an enthusiastic welcoming message and declares opportunities ahead. +Usually the "Hello world!" example is the first step to learning a new language. It's a simple one-line program that outputs an enthusiastic welcoming message and declares opportunities ahead. In GPU-land rendering text is an overcomplicated task for a first step, instead we'll choose a bright welcoming color to shout our enthusiasm!
- + If you are reading this book in a browser the previous block of code is interactive. That means you can click and change any part of the code you want to explore. Changes will be updated immediately thanks to the GPU architecture that compiles and replaces shaders *on the fly*. Give it a try by changing the values on line 6. Although these simple lines of code don't look like a lot, we can infer substantial knowledge from them: @@ -16,7 +16,7 @@ Although these simple lines of code don't look like a lot, we can infer substant 3. This C-flavored language has built in *variables* (like ```gl_FragColor```), *functions* and *types*. In this case we've just been introduced to ```vec4``` that stands for a four dimensional vector of floating point precision. Later we will see more types like ```vec3``` and ```vec2``` together with the popular: ```float```, ```int``` and ```bool```. -4. If we look closely to the ```vec4``` type we can infer that the four arguments respond to the RED, GREEN, BLUE and ALPHA channels. Also we can see that these values are *normalized*, which means they go from ```0.0``` to ```1.0```. Later, we will learn how normalizing values makes it easier to *map* values between variables. +4. If we look closely to the ```vec4``` type we can infer that the four arguments respond to the RED, GREEN, BLUE and ALPHA channels. Also we can see that these values are *normalized*, which means they go from ```0.0``` to ```1.0```. Later, we will learn how normalizing values makes it easier to *map* values between variables. 5. Another important *C feature* we can see in this example is the presence of preprocessor macros. Macros are part of a pre-compilation step. With them it is possible to ```#define``` global variables and do some basic conditional operation ( with ```#ifdef``` and ```#endif```). All the macro comands begin with a hashtag (```#```). Pre-compilation happens right before compiling and copies all the calls to ```#defines``` and check ```#ifdef``` (is defined) and ```#ifndef``` (is not defined) conditionals. In our "hello world!" example above, we only insert the line 2 if ```GL_ES``` is defined, which mostly happens when the code is compiled on mobile devices and browsers. @@ -50,4 +50,4 @@ vec4 red(){ vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` -Although this example isn't very exciting, it is the most basic example - we are changing all the pixels inside the canvas to the same exact color. In the following chapter we will see how to change the pixel colors by using two types of input: space (the place of the pixel on the screen) and time (the number of seconds since the page was loaded). +Although this example isn't very exciting, it is the most basic example - we are changing all the pixels inside the canvas to the same exact color. In the following chapter we will see how to change the pixel colors by using two types of input: space (the place of the pixel on the screen) and time (the number of seconds since the page was loaded). diff --git a/02/SUMMARY.md b/02/SUMMARY.md index 4fd29f1..5b81322 100644 --- a/02/SUMMARY.md +++ b/02/SUMMARY.md @@ -1 +1 @@ -Usually the "Hello world!" example is the first step to learning a new language. In GPU-land rendering text is an overcomplicated task for a first step, instead we'll choose a bright welcoming color to shout our enthusiasm! \ No newline at end of file +Usually the "Hello world!" example is the first step to learning a new language. In GPU-land rendering text is an overcomplicated task for a first step, instead we'll choose a bright welcoming color to shout our enthusiasm! diff --git a/02/hello_world.frag b/02/hello_world.frag index 4748df1..a402fdd 100644 --- a/02/hello_world.frag +++ b/02/hello_world.frag @@ -5,7 +5,3 @@ precision mediump float; void main() { gl_FragColor = vec4(1.0,0.0,1.0,1.0); } - - - - diff --git a/02/notes.md b/02/notes.md index 797bba7..e5b54a1 100644 --- a/02/notes.md +++ b/02/notes.md @@ -11,4 +11,4 @@ (float) 1 == 1.0 ``` -* I figured out that vec4() is a vector with 4 values, but perhaps you could make that explicit somewhere. \ No newline at end of file +* I figured out that vec4() is a vector with 4 values, but perhaps you could make that explicit somewhere. diff --git a/03/README-ch.md b/03/README-ch.md index 0d0f311..10d8f6e 100644 --- a/03/README-ch.md +++ b/03/README-ch.md @@ -11,7 +11,7 @@ precision mediump float; uniform vec2 u_resolution; // 画布尺寸(宽,高) uniform vec2 u_mouse; // 鼠标位置(在屏幕上哪个像素) -uniform float u_time; // 时间(加载后的秒数) +uniform float u_time; // 时间(加载后的秒数) ``` 你可以把 uniforms 想象成连通 GPU 和 CPU 的许多小的桥梁。虽然这些 uniforms 的名字千奇百怪,但是在这一系列的例子中我一直有用到:```u_time``` (时间), ```u_resolution``` (画布尺寸)和 ```u_mouse``` (鼠标位置)。按业界传统应在 uniform 值的名字前加 ```u_``` ,这样一看即知是 uniform。尽管如此你也还会见到各种各样的名字。比如[ShaderToy.com](https://www.shadertoy.com/)就用了如下的名字: @@ -58,4 +58,4 @@ GLSL 还有更多惊喜。GPU 的硬件加速支持我们使用角度,三角 * 你可以用 ```u_time``` 和 ```u_mouse``` 来改变颜色的图案吗?不妨琢磨一些有趣的途径。 -经过这些小练习后,你可能会好奇还能用强大的 shader 做什么。接下来的章节你会知道如何把你的 shader 和 three.js,Processing,和 openFrameworks 结合起来。 \ No newline at end of file +经过这些小练习后,你可能会好奇还能用强大的 shader 做什么。接下来的章节你会知道如何把你的 shader 和 three.js,Processing,和 openFrameworks 结合起来。 diff --git a/03/README-de.md b/03/README-de.md index 07223ae..a35d07c 100644 --- a/03/README-de.md +++ b/03/README-de.md @@ -1,61 +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. - -
- -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 in der Übersicht: [```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*, weil es sich nur um einen kleinen Teil der Zeichenfläche handelt, eben ein „Fragment“. Diese Variable kann man nicht als ```uniform``` bezeichnen, weil ihr Inhalt bzw. ihr Wert mit jedem Shader-Durchlauf variiert. Man spricht deshalb auch von einem *varying*. - -
- -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 Farbwerte in GLSL 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 diesem 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. +## 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. + +
+ +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 in der Übersicht: [```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*, weil es sich nur um einen kleinen Teil der Zeichenfläche handelt, eben ein „Fragment“. Diese Variable kann man nicht als ```uniform``` bezeichnen, weil ihr Inhalt bzw. ihr Wert mit jedem Shader-Durchlauf variiert. Man spricht deshalb auch von einem *varying*. + +
+ +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 Farbwerte in GLSL 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 diesem 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. diff --git a/03/README-it.md b/03/README-it.md index dabd918..d3894f6 100644 --- a/03/README-it.md +++ b/03/README-it.md @@ -1,61 +1,61 @@ -## Uniforms - -Finora abbiamo visto come la GPU gestisce un gran numero di thread paralleli, ciascuno responsabile nell'assegnazione d'un colore ad una frazione dell'immagine totale. Sebbene ogni thread parallelo è cieco nei confronti degli altri, dobbiamo essere in grado d'inviare alcuni input dalla CPU a tutti i thread. A causa dell'architettura della scheda grafica tali input saranno uguali (*uniform*) per tutti i thread e necessariamente impostati come di *sola lettura*. In altre parole, ogni thread riceve gli stessi dati che possono essere letti ma non possono essere cambiati. - -Questi input sono chiamati ```uniform``` e sono disponibili nella maggior parte di tipi supportati: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` e ```samplerCube```. Gli Uniforms sono definiti con i rispettivi tipi, all'inizio del codice, dopo aver definito la precisione della virgola mobile. - -```glsl -#ifdef GL_ES -precision mediump float; -#endif - -uniform vec2 u_resolution; // dimensione del Canvas (larghezza, altezza) -uniform vec2 u_mouse; // posizione del mouse (x,y) in pixels -uniform float u_time; // tempo in secondi da quando lo shader è iniziato -``` - -È possibile immaginare gli uniforms come piccoli ponti tra la CPU e la GPU. I nomi variano da applicazione ad applicazione, ma in questa serie di esempi userò: ```u_time``` (tempo in secondi da quando lo shader è iniziato), ```u_resolution``` (la dimensione della finestra in cui lo shader è in corso d'elaborazione) e ```u_mouse``` (la posizione in pixel del mouse all'interno della finestra). Seguirò la convenzione di mettere ```u_``` prima del nome degli uniforms per essere espliciti sulla natura di questa variabile, ma incontrerete varie nomenclature per gli uniforms. Per esempio [ShaderToy.com](https://www.shadertoy.com/) utilizza gli stessi uniforms, ma con i seguenti nomi: - -```glsl -uniform vec3 iResolution; // dimensione del Canvas (in pixels) -uniform vec4 iMouse; // posizione del mouse in pixels. xy: corrente, zw: click -uniform float iGlobalTime; // tempo (in secondi) da quando lo shader è iniziato -``` - -Ma ora basta chiacchiere, vediamo gli uniforms in azione. Nel seguente codice utilizziamo ```u_time``` - il numero di secondi da quando lo shader è iniziato - insieme ad una funzione seno per animare con una transizione la quantità di rosso sullo schermo. - -
- -Come potete vedere GLSL ha molte sorprese. La GPU ha funzioni trigonometriche ed esponenziali, che sono accelerate dall'hardware. Alcune di queste funzioni sono: [```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) and [```clamp()```](../glossary/?search=clamp). - -Ora è il momento di giocare con il codice qui sopra. - -* Rallentate la frequenza fino a quando il cambiamento di colore diventa quasi impercettibile. - -* Aumentate la frequenza fino a vedere un solo colore, senza sfarfallio. - -* Date tre frequenze differenti ai tre canali (RGB) per ottenere motivi e comportamenti interessanti. - -## gl_FragCoord - -Allo stesso modo GLSL ci dà un output di default, ```vec4 gl_FragColor```, ma anche un input di default, ```vec4 gl_FragCoord```, che contiene le coordinate sullo schermo del *pixel* o del *screen fragment* del thread attivo. Con ```vec4 gl_FragCoord```, sappiamo dove un thread sta lavorando all'interno dello schermo. In questo caso la variabile non è un ```uniform``` perché sarà diversa da thread a thread. Le variabili che cambiano in ogni thread, come ```gl_FragCoord```, sono chiamate *varying*. - -
- -Nel codice qui sopra *normalizziamo* le coordinate del fragment dividendole per la risoluzione totale dello schermo. In questo modo i valori andranno tra ```0.0``` e ```1.0```, una tecnica che rende facile mappare i valori X e Y per i canali ROSSO e VERDE. - -Nel mondo degli shaders non abbiamo troppe risorse per il debug a parte l'assegnazione di colori intensi alle variabili e cercare di trovargli un senso. Scoprirete che a volte programmando in GLSL è come mettere una nave all'interno di una bottiglia: un processo difficile, bello e gratificante. - -![](08.png) - -Ora è il momento di mettere in pratica gli insegnamenti che abbiamo imparato. - -* Sapreste dire dove è la coordinata ```(0.0,0.0)``` sul nostro schermo? - -* E dove sono ```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` e ```(1.0,1.0)```? - -* Riuscite ad immaginare come usare ```u_mouse``` sapendo che i valori sono espressi in pixel e NON in valori normalizzati? Sapresti usare ```u_mouse``` per muovere i colori? - -* Sapreste trovare un modo interessante per cambiare questo pattern grafico utilizzando ```u_time``` e le coordinate ```u_mouse```? - -Dopo aver fatto questi esercizi, ci si potrebbe chiedere dove si potrebbero provare i nuovi super poteri che gli shader ci hanno dato. Nel prossimo capitolo vedremo come creare i vostri shader in Three.js, Processing e openFrameworks. \ No newline at end of file +## Uniforms + +Finora abbiamo visto come la GPU gestisce un gran numero di thread paralleli, ciascuno responsabile nell'assegnazione d'un colore ad una frazione dell'immagine totale. Sebbene ogni thread parallelo è cieco nei confronti degli altri, dobbiamo essere in grado d'inviare alcuni input dalla CPU a tutti i thread. A causa dell'architettura della scheda grafica tali input saranno uguali (*uniform*) per tutti i thread e necessariamente impostati come di *sola lettura*. In altre parole, ogni thread riceve gli stessi dati che possono essere letti ma non possono essere cambiati. + +Questi input sono chiamati ```uniform``` e sono disponibili nella maggior parte di tipi supportati: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` e ```samplerCube```. Gli Uniforms sono definiti con i rispettivi tipi, all'inizio del codice, dopo aver definito la precisione della virgola mobile. + +```glsl +#ifdef GL_ES +precision mediump float; +#endif + +uniform vec2 u_resolution; // dimensione del Canvas (larghezza, altezza) +uniform vec2 u_mouse; // posizione del mouse (x,y) in pixels +uniform float u_time; // tempo in secondi da quando lo shader è iniziato +``` + +È possibile immaginare gli uniforms come piccoli ponti tra la CPU e la GPU. I nomi variano da applicazione ad applicazione, ma in questa serie di esempi userò: ```u_time``` (tempo in secondi da quando lo shader è iniziato), ```u_resolution``` (la dimensione della finestra in cui lo shader è in corso d'elaborazione) e ```u_mouse``` (la posizione in pixel del mouse all'interno della finestra). Seguirò la convenzione di mettere ```u_``` prima del nome degli uniforms per essere espliciti sulla natura di questa variabile, ma incontrerete varie nomenclature per gli uniforms. Per esempio [ShaderToy.com](https://www.shadertoy.com/) utilizza gli stessi uniforms, ma con i seguenti nomi: + +```glsl +uniform vec3 iResolution; // dimensione del Canvas (in pixels) +uniform vec4 iMouse; // posizione del mouse in pixels. xy: corrente, zw: click +uniform float iGlobalTime; // tempo (in secondi) da quando lo shader è iniziato +``` + +Ma ora basta chiacchiere, vediamo gli uniforms in azione. Nel seguente codice utilizziamo ```u_time``` - il numero di secondi da quando lo shader è iniziato - insieme ad una funzione seno per animare con una transizione la quantità di rosso sullo schermo. + +
+ +Come potete vedere GLSL ha molte sorprese. La GPU ha funzioni trigonometriche ed esponenziali, che sono accelerate dall'hardware. Alcune di queste funzioni sono: [```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) and [```clamp()```](../glossary/?search=clamp). + +Ora è il momento di giocare con il codice qui sopra. + +* Rallentate la frequenza fino a quando il cambiamento di colore diventa quasi impercettibile. + +* Aumentate la frequenza fino a vedere un solo colore, senza sfarfallio. + +* Date tre frequenze differenti ai tre canali (RGB) per ottenere motivi e comportamenti interessanti. + +## gl_FragCoord + +Allo stesso modo GLSL ci dà un output di default, ```vec4 gl_FragColor```, ma anche un input di default, ```vec4 gl_FragCoord```, che contiene le coordinate sullo schermo del *pixel* o del *screen fragment* del thread attivo. Con ```vec4 gl_FragCoord```, sappiamo dove un thread sta lavorando all'interno dello schermo. In questo caso la variabile non è un ```uniform``` perché sarà diversa da thread a thread. Le variabili che cambiano in ogni thread, come ```gl_FragCoord```, sono chiamate *varying*. + +
+ +Nel codice qui sopra *normalizziamo* le coordinate del fragment dividendole per la risoluzione totale dello schermo. In questo modo i valori andranno tra ```0.0``` e ```1.0```, una tecnica che rende facile mappare i valori X e Y per i canali ROSSO e VERDE. + +Nel mondo degli shaders non abbiamo troppe risorse per il debug a parte l'assegnazione di colori intensi alle variabili e cercare di trovargli un senso. Scoprirete che a volte programmando in GLSL è come mettere una nave all'interno di una bottiglia: un processo difficile, bello e gratificante. + +![](08.png) + +Ora è il momento di mettere in pratica gli insegnamenti che abbiamo imparato. + +* Sapreste dire dove è la coordinata ```(0.0,0.0)``` sul nostro schermo? + +* E dove sono ```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` e ```(1.0,1.0)```? + +* Riuscite ad immaginare come usare ```u_mouse``` sapendo che i valori sono espressi in pixel e NON in valori normalizzati? Sapresti usare ```u_mouse``` per muovere i colori? + +* Sapreste trovare un modo interessante per cambiare questo pattern grafico utilizzando ```u_time``` e le coordinate ```u_mouse```? + +Dopo aver fatto questi esercizi, ci si potrebbe chiedere dove si potrebbero provare i nuovi super poteri che gli shader ci hanno dato. Nel prossimo capitolo vedremo come creare i vostri shader in Three.js, Processing e openFrameworks. diff --git a/03/README-kr.md b/03/README-kr.md index e2960a4..6df87c6 100644 --- a/03/README-kr.md +++ b/03/README-kr.md @@ -1,6 +1,6 @@ ## Uniforms -우리는 여태것 GPU가 병렬처리에 왜 유리한지, 또 GPU의 각 Thread가 한 이미지의 각 부분을 어떻게 다루는지 또한 살펴보았다. 병렬처리 Thread들이 서로에 대해 데이터를 공유할수 없더라도, CPU에서 인풋을 받을수 있다. 그리고 이 인풋들은 모든 Thread들에 있어서 일정(*uniform*)하고 *read only*이다. 즉, 읽을순 있어도 변경할수 없다는 뜻이다. +우리는 여태것 GPU가 병렬처리에 왜 유리한지, 또 GPU의 각 Thread가 한 이미지의 각 부분을 어떻게 다루는지 또한 살펴보았다. 병렬처리 Thread들이 서로에 대해 데이터를 공유할수 없더라도, CPU에서 인풋을 받을수 있다. 그리고 이 인풋들은 모든 Thread들에 있어서 일정(*uniform*)하고 *read only*이다. 즉, 읽을순 있어도 변경할수 없다는 뜻이다. 이런 인풋들을 ```uniform```이라고 하고, ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D```, ```samplerCube``` 등의 데이터 타입을 지원한다. 유니폼 값들은 보통 floating pont precision설정이 끝난후 선언된다. @@ -11,7 +11,7 @@ precision mediump float; uniform vec2 u_resolution; // Canvas size (width,height) uniform vec2 u_mouse; // mouse position in screen pixels -uniform float u_time; // Time in seconds since load +uniform float u_time; // Time in seconds since load ``` 유니폼은 CPU와 GPU사이에 다리라고 봐도 좋을것이다. 유니폼 값들의 이름은 구현마다 다 다르지만 여기서는: ```u_time``` (쉐이더 연산이 시작된후부터의 초), ```u_resolution``` (쉐이더가 그려지고 있는 빌보드의 사이즈) and ```u_mouse``` (그려지는 빌보드내에서 마우스의 현재 픽셀 위치값) 등으로 나타내겠다. ```u_``` 를 변수앞에 붙혀서, 유니폼이라고 명시한다는 점도 유의하기 바란다. 더 많은 예제는 [ShaderToy.com](https://www.shadertoy.com/) 에서 찾아볼수 있지만, 변수이름이 약간 다르니 살펴보기 바란다: @@ -39,7 +39,7 @@ GLSL의 재미를 약간 맛볼수 있었다. GPU는 전에도 설명했듯이, ## gl_FragCoord -비슷한 원리로, GLSL은 내장 아웃풋 값들을 가진다. ```vec4 gl_FragColor```, 또한 내장 인풋 값도 있다, *screen fragment*상에서 *pixel*의 위치를 가지고 있는 ```vec4 gl_FragCoord```. ```vec4 gl_FragCoord```로 각 쓰레드가 빌보드의 어느 부분을 작업하고 있는지 알수 있다. 그래서 이값은 ```uniform```값과는 조금다르다. 각 쓰레드마다 값이 다른 *varying*타입이기 때문이다. +비슷한 원리로, GLSL은 내장 아웃풋 값들을 가진다. ```vec4 gl_FragColor```, 또한 내장 인풋 값도 있다, *screen fragment*상에서 *pixel*의 위치를 가지고 있는 ```vec4 gl_FragCoord```. ```vec4 gl_FragCoord```로 각 쓰레드가 빌보드의 어느 부분을 작업하고 있는지 알수 있다. 그래서 이값은 ```uniform```값과는 조금다르다. 각 쓰레드마다 값이 다른 *varying*타입이기 때문이다. In the same way GLSL gives us a default output, ```vec4 gl_FragColor```, it also gives us a default input, ```vec4 gl_FragCoord```, which holds the screen coordinates of the *pixel* or *screen fragment* that the active thread is working on. With ```vec4 gl_FragCoord```, we know where a thread is working inside the billboard. In this case we don't call it ```uniform``` because it will be different from thread to thread, instead ```gl_FragCoord``` is called a *varying*.
@@ -60,4 +60,4 @@ In the same way GLSL gives us a default output, ```vec4 gl_FragColor```, it also * ```u_time```과, ```u_mouse```를 이용해, 색의 패턴을 재밌게 바꾸는 시도도 해보자. -몇번 해보다 보면, 이런 쉐이딩 기술을 어디에 적용할지 의문이 갈것이다. 다음챕터에서, 쉐이딩 기술을 이용하는 라이브러리들에 대해 알아볼것이다. three.js, Processing, openFrameworks와 같은 툴을 이용하여. \ No newline at end of file +몇번 해보다 보면, 이런 쉐이딩 기술을 어디에 적용할지 의문이 갈것이다. 다음챕터에서, 쉐이딩 기술을 이용하는 라이브러리들에 대해 알아볼것이다. three.js, Processing, openFrameworks와 같은 툴을 이용하여. diff --git a/03/README.md b/03/README.md index 301879c..cd22a28 100644 --- a/03/README.md +++ b/03/README.md @@ -1,6 +1,6 @@ ## Uniforms -So far we have seen how the GPU manages large numbers of parallel threads, each one responsible for assigning the color to a fraction of the total image. Although each parallel thread is blind to the others, we need to be able to send some inputs from the CPU to all the threads. Because of the architecture of the graphics card those inputs are going to be equal (*uniform*) to all the threads and necessarily set as *read only*. In other words, each thread receives the same data which it can read but cannot change. +So far we have seen how the GPU manages large numbers of parallel threads, each one responsible for assigning the color to a fraction of the total image. Although each parallel thread is blind to the others, we need to be able to send some inputs from the CPU to all the threads. Because of the architecture of the graphics card those inputs are going to be equal (*uniform*) to all the threads and necessarily set as *read only*. In other words, each thread receives the same data which it can read but cannot change. These inputs are called ```uniform``` and come in most of the supported types: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` and ```samplerCube```. Uniforms are defined with the corresponding type at the top of the shader right after assigning the default floating point precision. @@ -11,7 +11,7 @@ precision mediump float; uniform vec2 u_resolution; // Canvas size (width,height) uniform vec2 u_mouse; // mouse position in screen pixels -uniform float u_time; // Time in seconds since load +uniform float u_time; // Time in seconds since load ``` You can picture the uniforms like little bridges between the CPU and the GPU. The names will vary from implementation to implementation but in this series of examples I’m always passing: ```u_time``` (time in seconds since the shader started), ```u_resolution``` (billboard size where the shader is being drawn) and ```u_mouse``` (mouse position inside the billboard in pixels). I’m following the convention of putting ```u_``` before the uniform name to be explicit about the nature of this variable but you will find all kinds of names for uniforms. For example [ShaderToy.com](https://www.shadertoy.com/) uses the same uniforms but with the following names: @@ -42,7 +42,7 @@ In the same way GLSL gives us a default output, ```vec4 gl_FragColor```, it also
-In the above code we *normalize* the coordinate of the fragment by dividing it by the total resolution of the billboard. By doing this the values will go between ```0.0``` and ```1.0```, which makes it easy to map the X and Y values to the RED and GREEN channel. +In the above code we *normalize* the coordinate of the fragment by dividing it by the total resolution of the billboard. By doing this the values will go between ```0.0``` and ```1.0```, which makes it easy to map the X and Y values to the RED and GREEN channel. In shader-land we don’t have too many resources for debugging besides assigning strong colors to variables and trying to make sense of them. You will discover that sometimes coding in GLSL is very similar to putting ships inside bottles. Is equally hard, beautiful and gratifying. @@ -54,7 +54,7 @@ Now it is time to try and challenge our understanding of this code. * What about ```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` and ```(1.0,1.0)```? -* Can you figure out how to use ```u_mouse``` knowing that the values are in pixels and NOT normalized values? Can you use it to move colors around? +* Can you figure out how to use ```u_mouse``` knowing that the values are in pixels and NOT normalized values? Can you use it to move colors around? * Can you imagine an interesting way of changing this color pattern using ```u_time``` and ```u_mouse``` coordinates? diff --git a/03/index.php b/03/index.php index 7b41dc5..79fb6fc 100644 --- a/03/index.php +++ b/03/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/03/notes.md b/03/notes.md index 88a6d4e..e29cd9a 100644 --- a/03/notes.md +++ b/03/notes.md @@ -41,11 +41,11 @@ void main() { // gl_FragCoord.xy = vec2(0.0,0.0); // / / // vec2(500.0,500.0); - + vec2 st = gl_FragCoord.xy/u_resolution; - + // ST -> vec2(0.0,0.0) to vec2(1.0,1.0) - + // RED GREEN BLUE ALPHA gl_FragColor = vec4(st.x, st.y, 0.0, 1.0); } @@ -64,4 +64,3 @@ which holds the screen coordinates of the *pixel* or *screen fragment* that the * I've stressed the fact that gl_FragCoord is implicitly declared so that people don't panic when they don't find it in the new code sample :) also those are reserved names, so I stressed the fact that you can't use them as var names in your custom code. - diff --git a/03/time.frag b/03/time.frag index a6a5fe4..60c2625 100644 --- a/03/time.frag +++ b/03/time.frag @@ -7,5 +7,3 @@ uniform float u_time; void main() { gl_FragColor = vec4(abs(sin(u_time)),0.0,0.0,1.0); } - - diff --git a/04/README-ch.md b/04/README-ch.md index cc8ccde..30fa14f 100644 --- a/04/README-ch.md +++ b/04/README-ch.md @@ -42,7 +42,7 @@ function init() { container = document.getElementById( 'container' ); - + camera = new THREE.Camera(); camera.position.z = 1; @@ -66,7 +66,7 @@ renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio( window.devicePixelRatio ); - + container.appendChild( renderer.domElement ); onWindowResize(); @@ -102,7 +102,7 @@ PShader shader; void setup() { size(640, 360, P2D); noStroke(); - + shader = loadShader("shader.frag"); } @@ -139,12 +139,12 @@ void main() { ### **openFrameworks** 每个人都有自己的舒适区,我的则是[openFrameworks community](http://openframeworks.cc/)。这个 C++ 框架打包了 OpenGL 和其他开源 C++ 库。在很多方面它和 Processing 非常像,但是明显和 C++ 编译器打交道一定比较麻烦。和 Processing 很像地,openFrameworks 会在你的 data 文件夹里寻找 shader 文件,所以不要忘记把你的后缀 ```.frag``` 的文件拷进去,加载的时候记得改名。 - + ```cpp void ofApp::draw(){ ofShader shader; shader.load("","shader.frag"); - + shader.begin(); shader.setUniform1f("u_time", ofGetElapsedTimef()); shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight()); diff --git a/04/README-de.md b/04/README-de.md index c5ed935..3c0335c 100644 --- a/04/README-de.md +++ b/04/README-de.md @@ -1,190 +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 [Raspberry Pi](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 - -``` - -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 [Raspberry Pi](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**: Du kannst Deine Shader direkt aus dem Online-Editor ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) heraus 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 einbetten 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 - -
- - - - - -``` - -### 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. +## 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 [Raspberry Pi](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 + +``` + +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 [Raspberry Pi](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**: Du kannst Deine Shader direkt aus dem Online-Editor ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) heraus 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 einbetten 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 + +
+ + + + + +``` + +### 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. diff --git a/04/README-fr.md b/04/README-fr.md index 52afb56..4ccb347 100644 --- a/04/README-fr.md +++ b/04/README-fr.md @@ -91,7 +91,7 @@ Notez bien la balise de script appelée ```id="fragmentShader"```, c'est là qu' function init() { container = document.getElementById( 'container' ); - + camera = new THREE.Camera(); camera.position.z = 1; @@ -116,12 +116,12 @@ Notez bien la balise de script appelée ```id="fragmentShader"```, c'est là qu' 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 @@ -162,7 +162,7 @@ PShader shader; void setup() { size(640, 360, P2D); noStroke(); - + shader = loadShader("shader.frag"); } @@ -203,12 +203,12 @@ Chacun a sa zone de confort, pour moi, ça reste [la communité openFrameworks]( Ce framework C++ intègre OpenGL et d'autres librairies C++ open source. C'est très proche de Processing à ceci près que c'est un langage compilé et qu'il vaut donc mieux être habitué aux compilateurs C++. Comme Processing, openFrameworks va chercher le fichier du shader dans la dossier data, donc n'oubliez pas de créer un fichier ```.frag```, d'y coller le contenu du shader et de spécifier le nom de ce fichier dans votre programme OF. - + ```cpp void ofApp::draw(){ ofShader shader; shader.load("","shader.frag"); - + shader.begin(); shader.setUniform1f("u_time", ofGetElapsedTimef()); shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight()); diff --git a/04/README-it.md b/04/README-it.md index 6c79a1e..928a80d 100644 --- a/04/README-it.md +++ b/04/README-it.md @@ -70,7 +70,7 @@ Di seguito è riportato un esempio di codice HTML e JS per iniziare con gli shad function init() { container = document.getElementById( 'container' ); - + camera = new THREE.Camera(); camera.position.z = 1; @@ -95,12 +95,12 @@ Di seguito è riportato un esempio di codice HTML e JS per iniziare con gli shad 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 @@ -136,7 +136,7 @@ PShader shader; void setup() { size(640, 360, P2D); noStroke(); - + shader = loadShader("shader.frag"); } @@ -173,12 +173,12 @@ Per ulteriori informazioni sugli shader in Processing controllate questo [tutori ### In **openFrameworks** Ognuno ha un luogo in cui sentirsi a proprio agio e, nel mio caso, è ancora la [comunità di openFrameworks](http://openframeworks.cc/). Questo framework C++ integra OpenGL e altre librerie C++ open source. Per molti aspetti è molto simile a Processing, ma con le ovvie complicazioni dovute ai compilatori C++. Allo stesso modo di Processing, openFrameworks cercherà i tuoi file shader nella cartella dati, quindi non dimenticate di copiare i file ```.frag``` che si desiderano utilizzare e modificate il nome quando li si carica. - + ```cpp void ofApp::draw(){ ofShader shader; shader.load("","shader.frag"); - + shader.begin(); shader.setUniform1f("u_time", ofGetElapsedTimef()); shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight()); @@ -187,4 +187,4 @@ void ofApp::draw(){ } ``` -Per ulteriori informazioni sugli shader in openFrameworks consultate questo [ottimo tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) fatto da [Joshua Noble](http://thefactoryfactory.com/). \ No newline at end of file +Per ulteriori informazioni sugli shader in openFrameworks consultate questo [ottimo tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) fatto da [Joshua Noble](http://thefactoryfactory.com/). diff --git a/04/README-kr.md b/04/README-kr.md index 18fb064..5e2c453 100644 --- a/04/README-kr.md +++ b/04/README-kr.md @@ -7,7 +7,7 @@ **Note 2**: 만약 WebGL에서 쉐이더를 구동하고, 다른 프레임워크를 따로 쓰고 싶지 않다면, [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas)를 이용해서 할수 있다. 이 웹 툴은 이 책에 최적화 되어 있고, 실제로 저자가 프로젝트마다 사용하는 툴이기도 하다. ### **Three.js** 에서 - + Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) 가 다른 참여자[참여자](https://github.com/mrdoob/three.js/graphs/contributors)들과 개발한 WebGL을 이용한 프레임 워크인 [Three.js](http://threejs.org/). 많은 예제와, 튜토리얼, 책들이 존재하고, 이를 이용해 여러 3D graphics데모를 만들어 볼수 있다. 아래는 HTML과 JS를 이용해 three.js를 구동하는 예제이다. ```id="fragmentShader"```부분을 보면, 쉐이더가 어디에서 적용되는지 볼수 있다. @@ -40,7 +40,7 @@ Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) 가 다른 참여자 function init() { container = document.getElementById( 'container' ); - + camera = new THREE.Camera(); camera.position.z = 1; @@ -64,7 +64,7 @@ Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) 가 다른 참여자 renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio( window.devicePixelRatio ); - + container.appendChild( renderer.domElement ); onWindowResize(); @@ -100,7 +100,7 @@ PShader shader; void setup() { size(640, 360, P2D); noStroke(); - + shader = loadShader("shader.frag"); } @@ -141,7 +141,7 @@ void main() { void ofApp::draw(){ ofShader shader; shader.load("","shader.frag"); - + shader.begin(); shader.setUniform1f("u_time", ofGetElapsedTimef()); shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight()); diff --git a/04/README.md b/04/README.md index 5205748..a0ccde5 100644 --- a/04/README.md +++ b/04/README.md @@ -2,7 +2,7 @@ As part of the construction of this book and my art practice I made an ecosystem of tools to create, display, share and curate shaders. This tools works consistently across Linux Desktops, MacOS, [Raspberry Pi](https://www.raspberrypi.org/) and browsers without the need of changing your code. -**Display**: all live examples in this book are displayed using [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) which makes the process of running standalone shader incredible easy. +**Display**: all live examples in this book are displayed using [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) which makes the process of running standalone shader incredible easy. ```html @@ -37,8 +37,8 @@ If you prefer to work offline using [SublimeText](https://www.sublimetext.com/) In case you already have experience programming in a framework like: [Processing](https://processing.org/), [Three.js](http://threejs.org/) or [OpenFrameworks](http://openframeworks.cc/), you're probably excited to try shaders on this platforms you feel comfortable with. The following are examples of how to set shaders in some popular frameworks with the same uniforms that we are going to use throughout this book. (In the [GitHub repository for this chapter](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), you'll find the full source code for these three frameworks.) ### In **Three.js** - -The brilliant and very humble Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) has been developing along with other [contributors](https://github.com/mrdoob/three.js/graphs/contributors) probably one of the most famous frameworks for WebGL, called [Three.js](http://threejs.org/). You will find a lot of examples, tutorials and books that teach you how to use this JavaScript library to make cool 3D graphics. + +The brilliant and very humble Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) has been developing along with other [contributors](https://github.com/mrdoob/three.js/graphs/contributors) probably one of the most famous frameworks for WebGL, called [Three.js](http://threejs.org/). You will find a lot of examples, tutorials and books that teach you how to use this JavaScript library to make cool 3D graphics. Below is an example of the HTML and JS you need to get started with shaders in three.js. Pay attention to the ```id="fragmentShader"``` script, here is where you can copy the shaders you find in this book. @@ -70,7 +70,7 @@ Below is an example of the HTML and JS you need to get started with shaders in t function init() { container = document.getElementById( 'container' ); - + camera = new THREE.Camera(); camera.position.z = 1; @@ -95,12 +95,12 @@ Below is an example of the HTML and JS you need to get started with shaders in t 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 @@ -136,7 +136,7 @@ PShader shader; void setup() { size(640, 360, P2D); noStroke(); - + shader = loadShader("shader.frag"); } @@ -173,12 +173,12 @@ For more information about shaders in Processing check out this [tutorial](https ### In **openFrameworks** Everybody has a place where they feel comfortable, in my case, that’s still the [openFrameworks community](http://openframeworks.cc/). This C++ framework wraps around OpenGL and other open source C++ libraries. In many ways it's very similar to Processing, but with the obvious complications of dealing with C++ compilers. In the same way as Processing, openFrameworks will search for your shader files in the data folder, so don’t forget to copy the ```.frag``` files you want to use and change the name when you load them. - + ```cpp void ofApp::draw(){ ofShader shader; shader.load("","shader.frag"); - + shader.begin(); shader.setUniform1f("u_time", ofGetElapsedTimef()); shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight()); diff --git a/04/index.php b/04/index.php index 4eb3d3e..9c27b1b 100644 --- a/04/index.php +++ b/04/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/04/openFrameworks/bin/data/shader.frag b/04/openFrameworks/bin/data/shader.frag index f2abc59..f90dad8 100644 --- a/04/openFrameworks/bin/data/shader.frag +++ b/04/openFrameworks/bin/data/shader.frag @@ -12,4 +12,4 @@ uniform float u_time; void main() { vec2 st = gl_FragCoord.st/u_resolution; gl_FragColor = vec4(st.x,st.y,0.0,1.0); -} \ No newline at end of file +} diff --git a/04/openFrameworks/src/ofApp.cpp b/04/openFrameworks/src/ofApp.cpp index 79244e6..47755ab 100644 --- a/04/openFrameworks/src/ofApp.cpp +++ b/04/openFrameworks/src/ofApp.cpp @@ -4,7 +4,7 @@ //-------------------------------------------------------------- void ofApp::setup(){ - + // Load and compile the shader // shader.load("","shader.frag"); @@ -12,30 +12,30 @@ void ofApp::setup(){ //-------------------------------------------------------------- void ofApp::update(){ - + } //-------------------------------------------------------------- void ofApp::draw(){ - + // Replace the pipeline with our shader shader.begin(); - + // Send uniforms shader.setUniform1f("u_time", ofGetElapsedTimef()); shader.setUniform2f("u_mouse", mouseX, mouseY); shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight()); - + // make a billboard ofRect(0,0,ofGetWidth(), ofGetHeight()); - + // Default shader pipeline shader.end(); } //-------------------------------------------------------------- void ofApp::keyPressed(int key){ - + // Reload everytime you press a key // shader.load("","shader.frag"); @@ -77,6 +77,6 @@ void ofApp::gotMessage(ofMessage msg){ } //-------------------------------------------------------------- -void ofApp::dragEvent(ofDragInfo dragInfo){ +void ofApp::dragEvent(ofDragInfo dragInfo){ } diff --git a/04/openFrameworks/src/ofApp.h b/04/openFrameworks/src/ofApp.h index 906784a..e7c50f0 100644 --- a/04/openFrameworks/src/ofApp.h +++ b/04/openFrameworks/src/ofApp.h @@ -19,6 +19,6 @@ public: void windowResized(int w, int h); void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); - + ofShader shader; }; diff --git a/04/processing/data/shader.frag b/04/processing/data/shader.frag index 9fa9bcb..0c2e773 100644 --- a/04/processing/data/shader.frag +++ b/04/processing/data/shader.frag @@ -14,4 +14,4 @@ uniform float u_time; void main() { vec2 st = gl_FragCoord.st/u_resolution; gl_FragColor = vec4(st.x,st.y,0.0,1.0); -} \ No newline at end of file +} diff --git a/04/processing/processing.pde b/04/processing/processing.pde index d7b836a..eedb762 100644 --- a/04/processing/processing.pde +++ b/04/processing/processing.pde @@ -5,7 +5,7 @@ PShader shader; void setup() { size(640, 360, P2D); noStroke(); - + // Load and compile shader shader = loadShader("shader.frag"); } @@ -15,10 +15,10 @@ 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); - + // Replace the default pipeline programs with our shader shader(shader); - + // Draw a billboard rect(0,0,width,height); } diff --git a/04/three_js/index.html b/04/three_js/index.html index 0ebccc2..03ee6b6 100644 --- a/04/three_js/index.html +++ b/04/three_js/index.html @@ -38,7 +38,7 @@ function init() { container = document.getElementById( 'container' ); - + camera = new THREE.Camera(); camera.position.z = 1; @@ -63,7 +63,7 @@ renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio( window.devicePixelRatio ); - + container.appendChild( renderer.domElement ); onWindowResize(); @@ -88,4 +88,4 @@ renderer.render( scene, camera ); } - \ No newline at end of file + diff --git a/05/README-ch.md b/05/README-ch.md index d1466eb..237b840 100644 --- a/05/README-ch.md +++ b/05/README-ch.md @@ -22,7 +22,7 @@ [```pow()```](../glossary/?search=pow) (求x的y次幂)是 GLSL 的一个原生函数,GLSL 有很多原生函数。大多数原生函数都是硬件加速的,也就是说如果你正确使用这些函数,你的代码就会跑得更快。 换掉第 19 行的幂函数,试试看[```exp()```](../glossary/?search=exp)(以自然常数e为底的指数函数),[```log()```](../glossary/?search=log)(对数函数) 和 [```sqrt()```](../glossary/?search=sqrt)(平方根函数)。当你用 Pi 来玩的时候有些方程会变得更有趣。在第 5 行我定义了一个宏,使得每当程序调用 ```PI``` 的时候就用 ```3.14159265359``` 来替换它。 - + ### Step 和 Smoothstep GLSL 还有一些独特的原生插值函数可以被硬件加速。 diff --git a/05/README-de.md b/05/README-de.md index 1df45f2..68c3467 100644 --- a/05/README-de.md +++ b/05/README-de.md @@ -1,152 +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. - -
- -**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. - -
- -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. - -
- -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. - -
- -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 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. - -
- -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) - -
- -### 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/) - -
- -Genau wie Küchenchefs Gewürze und exotische Zutaten sammeln, entwickeln Digitalkünstler und kreative Entwickler 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: - -
- -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. - - - -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) +# 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. + +
+ +**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. + +
+ +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. + +
+ +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. + +
+ +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 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. + +
+ +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) + +
+ +### 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/) + +
+ +Genau wie Küchenchefs Gewürze und exotische Zutaten sammeln, entwickeln Digitalkünstler und kreative Entwickler 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: + +
+ +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. + + + +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) diff --git a/05/README-it.md b/05/README-it.md index 6c718b6..0974d9e 100644 --- a/05/README-it.md +++ b/05/README-it.md @@ -9,7 +9,7 @@ La seguente struttura di codice sarà la nostra recinzione. In questa visualizzi
-**Nota veloce**: il costruttore di tipo ```vec3``` "capisce" che vuoi assegnare i tre canali di colori allo stesso valore, mentre ```vec4``` capisce che vuoi costruire un vettore a quattro dimensioni con tre unidimensionali più un quarto valore (in questo caso il valore che controlla l’alfa o l’opacità). Guarda, ad esempio, le righe 20 e 26 qui sopra. +**Nota veloce**: il costruttore di tipo ```vec3``` "capisce" che vuoi assegnare i tre canali di colori allo stesso valore, mentre ```vec4``` capisce che vuoi costruire un vettore a quattro dimensioni con tre unidimensionali più un quarto valore (in questo caso il valore che controlla l’alfa o l’opacità). Guarda, ad esempio, le righe 20 e 26 qui sopra. Questo codice è il tuo recinto; è importante osservarlo e capirlo. Tornerai spesso in questo spazio tra *0.0* e *1.0*. Imparerai l’arte di combinare e modellare questa linea. @@ -22,7 +22,7 @@ Interessante, vero? Alla riga 22 prova esponenti diversi, per esempio: 20.0, 2.0 [```pow()```](../glossary/?search=pow) è una funzione nativa il GLSL e ce ne sono molte altre. La maggior parte di queste sono accelerate al livello dell’hardware; ciò significa che se esse sono usate in modo appropriato e con discrezione, renderanno il tuo codice molto più veloce. Sostituisci la funzione alla riga 22. Provane altre, come: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log) e [```sqrt()```](../glossary/?search=sqrt). Alcune di queste funzioni sono più interessanti quando le si utilizza con PI. Puoi vedere alla riga 8, che ho definito un macro che sostituisce qualsiasi chiamata a ```PI``` con valore ```3.14159265359```. - + ### Step e Smoothstep GLSL ha anche alcune funzioni interpolanti native uniche che sono accelerate dall’hardware. @@ -84,7 +84,7 @@ AAl termine dell’ultimo esercizio abbiamo presentato alcune nuove funzioni. È
-또 하나의 잘 알려진 함수중 하나는 [```smoothstep()```](../glossary/?search=smoothstep)이다. 두값의 레인지를 주고, 그 사이의 값으로 보간시켜주는 방법이다. 처음 두개의 인자는 레인지의 시작점과 끝점이고, 세번째 인자는 두 점사이에서 보간되고 리턴되는 값이다. +또 하나의 잘 알려진 함수중 하나는 [```smoothstep()```](../glossary/?search=smoothstep)이다. 두값의 레인지를 주고, 그 사이의 값으로 보간시켜주는 방법이다. 처음 두개의 인자는 레인지의 시작점과 끝점이고, 세번째 인자는 두 점사이에서 보간되고 리턴되는 값이다.
@@ -94,7 +94,7 @@ GLSL에는 하드웨어 가속화된 내장 보간법 함수들이 존재한다. ### 고급 쉐이핑 함수들 -[Golan Levin](http://www.flong.com/) 는 제법 복잡하지만 굉장히 유용한 쉐이핑 함수들을 잘 정리해 두었다. 이들을 GLSL로 포팅하는것또한 굉장히 유용한 공부방법일 것이다. 자신만의 쉐이핑 펑션 라이브러리를 개설해보자. +[Golan Levin](http://www.flong.com/) 는 제법 복잡하지만 굉장히 유용한 쉐이핑 함수들을 잘 정리해 두었다. 이들을 GLSL로 포팅하는것또한 굉장히 유용한 공부방법일 것이다. 자신만의 쉐이핑 펑션 라이브러리를 개설해보자. * [Polynomial Shaping Functions: www.flong.com/texts/code/shapers_poly](http://www.flong.com/texts/code/shapers_poly/) @@ -106,7 +106,7 @@ GLSL에는 하드웨어 가속화된 내장 보간법 함수들이 존재한다. 요리사가 자신만의 요리재료와 소스 노하우를 모으듯, digital artist들이나, creative coder들 역시 그들만의 쉐이핑 펑션을 만드는 버릇을 가져야 할것이다. -[Iñigo Quiles](http://www .iquilezles.org/)가 가지고 있는 [useful functions](http://www.iquilezles.org/www/articles/functions/functions.htm)정리는 매우 유용하다. [이 글](http://www.iquilezles.org/www/articles/functions/functions.htm)을 읽고, GLSL로 번역해보는 작업도 해볼수 있다. 조심해야 될 점들은, "."(점)을 실수 뒤에 꼭 넣어야 한다는 점이다. 함수의 이름이 ```powf()``` 에서 ```pow()```등으로 바뀌어 구현되는 점등이다. +[Iñigo Quiles](http://www .iquilezles.org/)가 가지고 있는 [useful functions](http://www.iquilezles.org/www/articles/functions/functions.htm)정리는 매우 유용하다. [이 글](http://www.iquilezles.org/www/articles/functions/functions.htm)을 읽고, GLSL로 번역해보는 작업도 해볼수 있다. 조심해야 될 점들은, "."(점)을 실수 뒤에 꼭 넣어야 한다는 점이다. 함수의 이름이 ```powf()``` 에서 ```pow()```등으로 바뀌어 구현되는 점등이다. * [Impulse](../edit.php#05/impulse.frag) * [Cubic Pulse](../edit.php#05/cubicpulse.frag) diff --git a/05/README.md b/05/README.md index edad9b8..0315e4f 100644 --- a/05/README.md +++ b/05/README.md @@ -1,7 +1,7 @@ # Algorithmic drawing ## Shaping functions -This chapter could be named "Mr. Miyagi's fence lesson." Previously, we mapped the normalized position of *x* and *y* to the *red* and *green* channels. Essentially we made a function that takes a two dimensional vector (x and y) and returns a four dimensional vector (r, g, b and a). But before we go further transforming data between dimensions we need to start simpler... much simpler. That means understanding how to make one dimensional functions. The more energy and time you spend learning and mastering this, the stronger your shader karate will be. +This chapter could be named "Mr. Miyagi's fence lesson." Previously, we mapped the normalized position of *x* and *y* to the *red* and *green* channels. Essentially we made a function that takes a two dimensional vector (x and y) and returns a four dimensional vector (r, g, b and a). But before we go further transforming data between dimensions we need to start simpler... much simpler. That means understanding how to make one dimensional functions. The more energy and time you spend learning and mastering this, the stronger your shader karate will be. ![The Karate Kid (1984)](mr_miyagi.jpg) @@ -19,17 +19,17 @@ This one-to-one relationship between *x* and *y* (or the brightness) is know as Interesting, right? On line 22 try different exponents: 20.0, 2.0, 1.0, 0.0, 0.2 and 0.02 for example. Understanding this relationship between the value and the exponent will be very helpful. Using these types of mathematical functions here and there will give you expressive control over your code, a sort of data acupuncture that let you control the flow of values. -[```pow()```](../glossary/?search=pow) is a native function in GLSL and there are many others. Most of them are accelerated at the level of the hardware, which means if they are used in the right way and with discretion they will make your code faster. +[```pow()```](../glossary/?search=pow) is a native function in GLSL and there are many others. Most of them are accelerated at the level of the hardware, which means if they are used in the right way and with discretion they will make your code faster. Replace the power function on line 22. Try other ones like: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log) and [```sqrt()```](../glossary/?search=sqrt). Some of these functions are more interesting when you play with them using PI. You can see on line 8 that I have defined a macro that will replace any call to ```PI``` with the value ```3.14159265359```. - + ### Step and Smoothstep -GLSL also has some unique native interpolation functions that are hardware accelerated. +GLSL also has some unique native interpolation functions that are hardware accelerated. -The [```step()```](../glossary/?search=step) interpolation receives two parameters. The first one is the limit or threshold, while the second one is the value we want to check or pass. Any value under the limit will return ```0.0``` while everything above the limit will return ```1.0```. +The [```step()```](../glossary/?search=step) interpolation receives two parameters. The first one is the limit or threshold, while the second one is the value we want to check or pass. Any value under the limit will return ```0.0``` while everything above the limit will return ```1.0```. -Try changing this threshold value on line 20 of the following code. +Try changing this threshold value on line 20 of the following code.
@@ -65,7 +65,7 @@ Try the following exercises and notice what happens: * Multiply time (```u_time```) by *x* before computing the ```sin```. See how the **frequency** between phases becomes more and more compressed. Note that u_time may have already become very large, making the graph hard to read. -* Add 1.0 to [```sin(x)```](../glossary/?search=sin). See how all the wave is **displaced** up and now all values are between 0.0 and 2.0. +* Add 1.0 to [```sin(x)```](../glossary/?search=sin). See how all the wave is **displaced** up and now all values are between 0.0 and 2.0. * Multiply [```sin(x)```](../glossary/?search=sin) by 2.0. See how the **amplitude** doubles in size. @@ -93,7 +93,7 @@ At the end of the last exercise we introduced some new functions. Now it’s tim ### Advance shaping functions -[Golan Levin](http://www.flong.com/) has great documentation of more complex shaping functions that are extraordinarily helpful. Porting them to GLSL is a really smart move, to start builidng your own resource of snippets of code. +[Golan Levin](http://www.flong.com/) has great documentation of more complex shaping functions that are extraordinarily helpful. Porting them to GLSL is a really smart move, to start builidng your own resource of snippets of code. * [Polynomial Shaping Functions: www.flong.com/texts/code/shapers_poly](http://www.flong.com/texts/code/shapers_poly/) @@ -105,7 +105,7 @@ At the end of the last exercise we introduced some new functions. Now it’s tim
-Like chefs that collect spices and exotic ingredients, digital artists and creative coders have a particular love of working on their own shaping functions. +Like chefs that collect spices and exotic ingredients, digital artists and creative coders have a particular love of working on their own shaping functions. [Iñigo Quiles](http://www.iquilezles.org/) has a great collection of [useful functions](http://www.iquilezles.org/www/articles/functions/functions.htm). After reading [this article](http://www.iquilezles.org/www/articles/functions/functions.htm) take a look at the following translation of these functions to GLSL. Pay attention to the small changes required, like putting the "." (dot) on floating point numbers and using the GLSL name for *C functions*; for example instead of ```powf()``` use ```pow()```: diff --git a/05/cubicpulse.frag b/05/cubicpulse.frag index 0494557..7e695c2 100644 --- a/05/cubicpulse.frag +++ b/05/cubicpulse.frag @@ -9,7 +9,7 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -// Function from Iñigo Quiles +// Function from Iñigo Quiles // www.iquilezles.org/www/articles/functions/functions.htm float cubicPulse( float c, float w, float x ){ x = abs(x - c); @@ -19,7 +19,7 @@ float cubicPulse( float c, float w, float x ){ } float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -29,9 +29,9 @@ void main() { float y = cubicPulse(0.5,0.2,st.x); vec3 color = vec3(y); - + float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/easing.frag b/05/easing.frag index 7f5bfb3..22a4904 100644 --- a/05/easing.frag +++ b/05/easing.frag @@ -179,7 +179,7 @@ float backInOut(float t) { } float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -230,4 +230,4 @@ void main() { float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/expo.frag b/05/expo.frag index eda4018..3268dab 100644 --- a/05/expo.frag +++ b/05/expo.frag @@ -12,7 +12,7 @@ uniform vec2 u_mouse; uniform float u_time; float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -25,6 +25,6 @@ void main() { float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/expstep.frag b/05/expstep.frag index a27afc8..2754f85 100644 --- a/05/expstep.frag +++ b/05/expstep.frag @@ -9,14 +9,14 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -// Function from Iñigo Quiles +// Function from Iñigo Quiles // www.iquilezles.org/www/articles/functions/functions.htm float expStep( float x, float k, float n ){ return exp( -k*pow(x,n) ); } float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -26,9 +26,9 @@ void main() { float y = expStep(st.x,10.,1.0); vec3 color = vec3(y); - + float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/featured_examples.php b/05/featured_examples.php index 02bce30..4b81131 100644 --- a/05/featured_examples.php +++ b/05/featured_examples.php @@ -1 +1 @@ -
\ No newline at end of file +
diff --git a/05/impulse.frag b/05/impulse.frag index 8572f3b..27fd711 100644 --- a/05/impulse.frag +++ b/05/impulse.frag @@ -9,7 +9,7 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -// Function from Iñigo Quiles +// Function from Iñigo Quiles // www.iquilezles.org/www/articles/functions/functions.htm float impulse( float k, float x ){ float h = k*x; @@ -17,7 +17,7 @@ float impulse( float k, float x ){ } float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -27,9 +27,9 @@ void main() { float y = impulse(12.,st.x); vec3 color = vec3(y); - + float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/index.php b/05/index.php index baf8a5f..293e33e 100644 --- a/05/index.php +++ b/05/index.php @@ -1,4 +1,4 @@ -text(file_get_contents($README.'.md')); - + echo '
@@ -29,5 +29,5 @@ '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/05/linear.frag b/05/linear.frag index e594a92..aa80120 100644 --- a/05/linear.frag +++ b/05/linear.frag @@ -8,7 +8,7 @@ uniform float u_time; // Plot a line on Y using a value between 0.0-1.0 float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -18,10 +18,10 @@ void main() { float y = st.x; vec3 color = vec3(y); - + // Plot a line float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/notes.md b/05/notes.md index 6bdae9f..37bc405 100644 --- a/05/notes.md +++ b/05/notes.md @@ -7,4 +7,4 @@ * Actually, this is the point where you lose me. I want it to be more gradual. It feels like there are 100 new concepts on this one page. ### Nicolas -* took the freedom to explain more indepth what interpolation is and why it rocks :) \ No newline at end of file +* took the freedom to explain more indepth what interpolation is and why it rocks :) diff --git a/05/parabola.frag b/05/parabola.frag index 01c0a40..4064eeb 100644 --- a/05/parabola.frag +++ b/05/parabola.frag @@ -8,14 +8,14 @@ precision mediump float; uniform vec2 u_resolution; uniform float u_time; -// Function from Iñigo Quiles +// Function from Iñigo Quiles // www.iquilezles.org/www/articles/functions/functions.htm float parabola( float x, float k ){ return pow( 4.0*x*(1.0-x), k ); } float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -25,9 +25,9 @@ void main() { float y = parabola(st.x,1.0); vec3 color = vec3(y); - + float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/pcurve.frag b/05/pcurve.frag index 3cc8acf..57de285 100644 --- a/05/pcurve.frag +++ b/05/pcurve.frag @@ -9,7 +9,7 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -// Function from Iñigo Quiles +// Function from Iñigo Quiles // www.iquilezles.org/www/articles/functions/functions.htm float pcurve( float x, float a, float b ){ float k = pow(a+b,a+b) / (pow(a,a)*pow(b,b)); @@ -17,7 +17,7 @@ float pcurve( float x, float a, float b ){ } float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -27,9 +27,9 @@ void main() { float y = pcurve(st.x,3.0,1.0); vec3 color = vec3(y); - + float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/smoothstep.frag b/05/smoothstep.frag index 7111a30..0ae3f8c 100644 --- a/05/smoothstep.frag +++ b/05/smoothstep.frag @@ -9,7 +9,7 @@ uniform vec2 u_mouse; uniform float u_time; float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -20,9 +20,9 @@ void main() { float y = smoothstep(0.1,0.9,st.x); vec3 color = vec3(y); - + float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/05/step.frag b/05/step.frag index 927a213..d45152e 100644 --- a/05/step.frag +++ b/05/step.frag @@ -8,7 +8,7 @@ uniform vec2 u_resolution; uniform float u_time; float plot(vec2 st, float pct){ - return smoothstep( pct-0.02, pct, st.y) - + return smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y); } @@ -23,6 +23,6 @@ void main() { float pct = plot(st,y); color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/06/README-ch.md b/06/README-ch.md index 23955d0..a286c2a 100644 --- a/06/README-ch.md +++ b/06/README-ch.md @@ -11,7 +11,7 @@ vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; -red.z = 0.0; +red.z = 0.0; ``` 以x,y,z定义颜色是不是有些奇怪?正因如此,我们有其他方法访问这些变量——以不同的名字。```.x```, ```.y```, ```.z```也可以被写作```.r```, ```.g```, ```.b``` 和 ```.s```, ```.t```, ```.p```。(```.s```, ```.t```, ```.p```通常被用做后面章节提到的贴图空间坐标)你也可以通过使用索引位置```[0]```, ```[1]``` 和 ```[2]```来访问向量. @@ -34,7 +34,7 @@ GLSL中向量类型的另一大特点是可以用你需要的任意顺序简单 ```glsl vec3 yellow, magenta, green; -// Making Yellow +// Making Yellow yellow.rg = vec2(1.0); // Assigning 1. to red and green channels yellow[2] = 0.0; // Assigning 0. to blue channel @@ -42,7 +42,7 @@ yellow[2] = 0.0; // Assigning 0. to blue channel magenta = yellow.rbg; // Assign the channels with green and blue swapped // Making Green -green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels +green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels ``` #### 个人工具箱 @@ -97,9 +97,9 @@ green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue * 用 ```step()``` 函数在做一个五彩的旗子。 ### HSB - + 我们不能脱离色彩空间来谈论颜色。正如你所知,除了rgb值,有其他不同的方法去描述定义颜色。 - + [HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) 代表色相,饱和度和亮度(或称为值)。这更符合直觉也更有利于组织颜色。稍微花些时间阅读下面的 ```rgb2hsv()``` 和 ```hsv2rgb()``` 函数。 将x坐标(位置)映射到Hue值并将y坐标映射到明度,我们就得到了五彩的可见光光谱。这样的色彩空间分布实现起来非常方便,比起RGB,用HSB来拾取颜色更直观。 @@ -137,12 +137,10 @@ HSB原本是在极坐标下产生的(以半径和角度定义)而并非在 在进入下一章之前让我们停下脚步回顾下。复习下之前例子的函数。你会注意到变量类型之前有个限定符 ```in```,在这个 [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) (限定符)例子中它特指这个变量是只读的。在之后的例子中我们会看到可以定义一个 ```out``` 或者 ```inout```变量。最后这个 ```inout```,再概念上类似于参照输入一个变量,这意味着我们有可能修改一个传入的变量。 ```glsl -int newFunction(in vec4 aVec4, // read-only +int newFunction(in vec4 aVec4, // read-only out vec3 aVec3, // write-only inout int aInt); // read-write -``` +``` 或许你还不相信我们可以用所有这些元素来画一些炫酷的东西。下一章我们会学习如何结合所有这些技巧通过融合 (*blending*) 空间来创造几何形状。没错。。。融合(*blending*) 空间。 - - diff --git a/06/README-de.md b/06/README-de.md index 6f12ac3..a4dcee6 100644 --- a/06/README-de.md +++ b/06/README-de.md @@ -1,147 +1,145 @@ -![Paul Klee – Farbkarte (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 auf den ersten Blick 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. - -
- -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) - -Wirf 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. Dann schau, was daraufhin geschieht. Entferne anschließend 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. - -
- -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. - -
- -### HSB in Polarkoordinaten - -Das *HSB-Farbmodell* wurde ursprünglich entwickelt, um Farben in Polarkoordinaten (bestehend aus einem *Winkel* und einem *Radius*) auszudrücken und nicht als 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=faceforward), [```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. - -
- -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 in der folgenden Abbildung) 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. - -
- -#### Ein Hinweis zu Funktionen und ihren Argumenten - -Bevor wir zum nächsten Kapitel springen, lass und kurz innehalten 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 alle unsere kleinen Tricks nutzen kann, um den Raum richtig in Wallung zu bringen. Ja, du hast richtig gehört. Genau darum geht's. - - +![Paul Klee – Farbkarte (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 auf den ersten Blick 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. + +
+ +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) + +Wirf 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. Dann schau, was daraufhin geschieht. Entferne anschließend 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. + +
+ +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. + +
+ +### HSB in Polarkoordinaten + +Das *HSB-Farbmodell* wurde ursprünglich entwickelt, um Farben in Polarkoordinaten (bestehend aus einem *Winkel* und einem *Radius*) auszudrücken und nicht als 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=faceforward), [```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. + +
+ +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 in der folgenden Abbildung) 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. + +
+ +#### Ein Hinweis zu Funktionen und ihren Argumenten + +Bevor wir zum nächsten Kapitel springen, lass und kurz innehalten 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 alle unsere kleinen Tricks nutzen kann, um den Raum richtig in Wallung zu bringen. Ja, du hast richtig gehört. Genau darum geht's. diff --git a/06/README-fr.md b/06/README-fr.md index faee52d..afaf27f 100644 --- a/06/README-fr.md +++ b/06/README-fr.md @@ -14,7 +14,7 @@ Si vous connaissez la Programmation Orientée Objet, vous aurez remarqué que no vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; -red.z = 0.0; +red.z = 0.0; ``` Dans l'exemple ci dessus, *x*, *y* et *z* permettent d'**accéder** aux 3 valeurs contenues dans l'objet ```red``` de type ```vec3```, ce sont les **accesseurs** aux propriétés de ```red```. @@ -259,10 +259,7 @@ Cette dernière, ```inout```, est équivalente à passer un argument *par réfé int newFunction(in vec4 aVec4, // lecture seule out vec3 aVec3, // écriture seule inout int aInt); // lecture / écriture -``` +``` Vous ne le savez pas encore et vous pourriez ne pas le croire mais nous avons à présent tout ce qu'il nous faut pour dessiner à peu près n'importe quoi. Au prochain chapitre, nous verrons comment combiner ces techniques pour *mélanger* l'espace. Oui... *mélanger* l'espace. - - - diff --git a/06/README-it.md b/06/README-it.md index 9a9897e..353e295 100644 --- a/06/README-it.md +++ b/06/README-it.md @@ -10,7 +10,7 @@ Se siete pratici con i paradigmi di programmazione orientata agli oggetti, proba vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; -red.z = 0.0; +red.z = 0.0; ``` Definire il colore usando una notazione *x*, *y* e *z* può essere fuorviante e creare confusione, vero? Per questo esistono altri modi di accedere alle stesse informazioni, con nomi diversi. I valori di ```.x```, ```.y``` e ```.z``` possono anche essere chiamati ```.r```, ```.g``` e ```.b```, e ```.s```, ```.t``` e ```.p```. (```.s```, ```.t``` e ```.p``` solitamente sono usati per le coordinate spaziali di una texture, che vedremo nel prossimo capitolo). Puoi anche accedere ai valori in un vettore usando gli indici di posizione ```[0]```, ```[1]``` e ```[2]```. @@ -44,7 +44,7 @@ magenta = yellow.rbg; // Invertite il canale del verde con quello del blu green.rgb = yellow.bgb; // Assegnare il canale blu del giallo (0) ai canali rosso e blu ``` -#### Per la vostra cassetta degli attrezzi +#### Per la vostra cassetta degli attrezzi Potreste non essere abituati a selezionare i colori attraverso numeri - di sicuro questo processo potrebbe risultare controintuitivo. Per vostra fortuna esistono tanti programmi che semplificano questo lavoro. Trovatene uno che vada incontro ai vostri bisogni e usatelo per ottenere colori in formato ```vec3``` 0 ```vec4``` format. Per esempio, qui trovate i templates che io uso su [Spectrum](http://www.eigenlogik.com/spectrum/mac): @@ -75,7 +75,7 @@ La funzione [```mix()```](../glossary/?search=mix) ha molto da offrire. Invece d Guardate l'esempio seguente. Così come negli esempi nel capitolo precedente, stiamo collegando la transizione alla *x* normalizzata e la visualizziamo con una linea. In questo momento tutti e tre i canali seguono la medesima linea. -Ora, togliete il commento alla riga 25 e guardate cosa succede. Poi provate a togliere il commento alle righe 26 e 27. Ricordate che le linee visualizzano la quantità di ```colorA``` e ```colorB``` da mescolare per ogni canale. +Ora, togliete il commento alla riga 25 e guardate cosa succede. Poi provate a togliere il commento alle righe 26 e 27. Ricordate che le linee visualizzano la quantità di ```colorA``` e ```colorB``` da mescolare per ogni canale.
@@ -103,7 +103,7 @@ Mappando la posizione sull'asse x con la tonalità e la posizione sull'asse y co ### HSB nelle coordinate polari -Originariamente HSB è stato creato per essere rappresentato in coordinate polari (basate su angoli e raggio) e non in coordinate cartesiane (basate su x e y). Per unire la nostra funzione HSB alle coordinate polari, dobbiamo ottenere l'angolo e la distanza dal centro del canvas per ogni coordinata pixel. Per far questo usiamo la funzione [```length()```](../glossary/?search=length) e [```atan(y,x)```](../glossary/?search=atan) (che è la versione GLSL della più comune ```atan2(y,x)```). +Originariamente HSB è stato creato per essere rappresentato in coordinate polari (basate su angoli e raggio) e non in coordinate cartesiane (basate su x e y). Per unire la nostra funzione HSB alle coordinate polari, dobbiamo ottenere l'angolo e la distanza dal centro del canvas per ogni coordinata pixel. Per far questo usiamo la funzione [```length()```](../glossary/?search=length) e [```atan(y,x)```](../glossary/?search=atan) (che è la versione GLSL della più comune ```atan2(y,x)```). Quando si usano vettori e funzioni trigonometriche, ```vec2```, ```vec3``` e ```vec4``` sono considerati come vettori anche quando rappresentano i colori. Inizieremo a considerare in modo simile i colori e i vettori, e in realtà troverete che questa flessibilità concettuale è molto potente. @@ -141,4 +141,4 @@ int newFunction(in vec4 aVec4, // solo lettura inout int aInt); // lettura e scrittura ``` -Potreste non crederci ma ora abbiamo tutti gli elementi per creare dei fantastici disegni. Nel prossimo capitolo impareremo come si possono combinare tutte queste tecniche per creare forme geometriche *fondendo* lo spazio. Sì, avete capito bene, *fondendo* lo spazio. \ No newline at end of file +Potreste non crederci ma ora abbiamo tutti gli elementi per creare dei fantastici disegni. Nel prossimo capitolo impareremo come si possono combinare tutte queste tecniche per creare forme geometriche *fondendo* lo spazio. Sì, avete capito bene, *fondendo* lo spazio. diff --git a/06/README.md b/06/README.md index d4edd50..1e0b442 100644 --- a/06/README.md +++ b/06/README.md @@ -2,7 +2,7 @@ ## Colors -We haven't much of a chance to talk about GLSL vector types. Before going further it's important to learn more about these variables and the subject of colors is a great way to find out more about them. +We haven't much of a chance to talk about GLSL vector types. Before going further it's important to learn more about these variables and the subject of colors is a great way to find out more about them. If you are familiar with object oriented programming paradigms you've probably noticed that we have been accessing the data inside the vectors like any regular C-like ```struct```. @@ -10,7 +10,7 @@ If you are familiar with object oriented programming paradigms you've probably n vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; -red.z = 0.0; +red.z = 0.0; ``` Defining color using an *x*, *y* and *z* notation can be confusing and misleading, right? That's why there are other ways to access this same information, but with different names. The values of ```.x```, ```.y``` and ```.z``` can also be called ```.r```, ```.g``` and ```.b```, and ```.s```, ```.t``` and ```.p```. (```.s```, ```.t``` and ```.p``` are usually used for spatial coordinates of a texture, which we'll see in a later chapter.) You can also access the data in a vector by using the index position, ```[0]```, ```[1]``` and ```[2]```. @@ -25,14 +25,14 @@ vector[2] = vector.b = vector.z = vector.p; vector[3] = vector.a = vector.w = vector.q; ``` -These different ways of pointing to the variables inside a vector are just nomenclatures designed to help you write clear code. This flexibility embedded in shading language is a door for you to start thinking interchangably about color and space coordinates. +These different ways of pointing to the variables inside a vector are just nomenclatures designed to help you write clear code. This flexibility embedded in shading language is a door for you to start thinking interchangably about color and space coordinates. Another great feature of vector types in GLSL is that the properties can be combined in any order you want, which makes it easy to cast and mix values. This ability is called *swizzle*. ```glsl vec3 yellow, magenta, green; -// Making Yellow +// Making Yellow yellow.rg = vec2(1.0); // Assigning 1. to red and green channels yellow[2] = 0.0; // Assigning 0. to blue channel @@ -40,7 +40,7 @@ yellow[2] = 0.0; // Assigning 0. to blue channel magenta = yellow.rbg; // Assign the channels with green and blue swapped // Making Green -green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels +green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels ``` #### For your toolbox @@ -58,7 +58,7 @@ Now that you know how colors are defined, it's time to integrate this with our p ![](mix-f.jpg) -Check the following code at line 18 and see how we are using the absolute values of a sin wave over time to mix ```colorA``` and ```colorB```. +Check the following code at line 18 and see how we are using the absolute values of a sin wave over time to mix ```colorA``` and ```colorB```.
@@ -66,13 +66,13 @@ Show off your skills by: * Make an expressive transition between colors. Think of a particular emotion. What color seems most representative of it? How does it appear? How does it fade away? Think of another emotion and the matching color for it. Change the beginning and ending color of the above code to match those emotions. Then animate the transition using shaping functions. Robert Penner developed a series of popular shaping functions for computer animation known as [easing functions](http://easings.net/), you can use [this example](../edit.php#06/easing.frag) as research and inspiration but the best result will come from making your own transitions. -### Playing with gradients +### Playing with gradients The [```mix()```](../glossary/?search=mix) function has more to offer. Instead of a single ```float```, we can pass a variable type that matches the two first arguments, in our case a ```vec3```. By doing that we gain control over the mixing percentages of each individual color channel, ```r```, ```g``` and ```b```. ![](mix-vec.jpg) -Take a look at the following example. Like the examples in the previous chapter, we are hooking the transition to the normalized *x* coordinate and visualizing it with a line. Right now all the channels go along the same line. +Take a look at the following example. Like the examples in the previous chapter, we are hooking the transition to the normalized *x* coordinate and visualizing it with a line. Right now all the channels go along the same line. Now, uncomment line number 25 and watch what happens. Then try uncommenting lines 26 and 27. Remember that the lines visualize the amount of ```colorA``` and ```colorB``` to mix per channel. @@ -92,9 +92,9 @@ You probably recognize the three shaping functions we are using on lines 25 to 2 ### HSB -We can't talk about color without speaking about color space. As you probably know there are different ways to organize color besides by red, green and blue channels. +We can't talk about color without speaking about color space. As you probably know there are different ways to organize color besides by red, green and blue channels. -[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) stands for Hue, Saturation and Brightness (or Value) and is a more intuitive and useful organization of colors. Take a moment to read the ```rgb2hsv()``` and ```hsv2rgb()``` functions in the following code. +[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) stands for Hue, Saturation and Brightness (or Value) and is a more intuitive and useful organization of colors. Take a moment to read the ```rgb2hsv()``` and ```hsv2rgb()``` functions in the following code. By mapping the position on the x axis to the Hue and the position on the y axis to the Brightness, we obtain a nice spectrum of visible colors. This spatial distribution of color can be very handy; it's more intuitive to pick a color with HSB than with RGB. @@ -104,7 +104,7 @@ By mapping the position on the x axis to the Hue and the position on the y axis HSB was originally designed to be represented in polar coordinates (based on the angle and radius) instead of cartesian coordinates (based on x and y). To map our HSB function to polar coordinates we need to obtain the angle and distance from the center of the billboard to the pixel coordinate. For that we will use the [```length()```](../glossary/?search=length) function and [```atan(y,x)```](../glossary/?search=atan) (which is the GLSL version of the commonly used ```atan2(y,x)```). -When using vector and trigonometric functions, ```vec2```, ```vec3``` and ```vec4``` are treated as vectors even when they represent colors. We will start treating colors and vectors similarly, in fact you will come to find this conceptual flexibility very empowering. +When using vector and trigonometric functions, ```vec2```, ```vec3``` and ```vec4``` are treated as vectors even when they represent colors. We will start treating colors and vectors similarly, in fact you will come to find this conceptual flexibility very empowering. **Note:** If you were wondering, there are more geometric functions besides [```length```](../glossary/?search=length) like: [```distance()```](../glossary/?search=distance), [```dot()```](../glossary/?search=dot), [```cross```](../glossary/?search=cross), [```normalize()```](../glossary/?search=normalize), [```faceforward()```](../glossary/?search=faceforward), [```reflect()```](../glossary/?search=reflect) and [```refract()```](../glossary/?search=refract). Also GLSL has special vector relational functions such as: [```lessThan()```](../glossary/?search=lessThan), [```lessThanEqual()```](../glossary/?search=lessThanEqual), [```greaterThan()```](../glossary/?search=greaterThan), [```greaterThanEqual()```](../glossary/?search=greaterThanEqual), [```equal()```](../glossary/?search=equal) and [```notEqual()```](../glossary/?search=notEqual). @@ -135,11 +135,9 @@ Try the following exercises: Before jumping to the next chapter let’s stop and rewind. Go back and take look at the functions in previous examples. You will notice ```in``` before the type of the arguments. This is a [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) and in this case it specifies that the variable is read only. In future examples we will see that it is also possible to define arguments as ```out``` or ```inout```. This last one, ```inout```, is conceptually similar to passing an argument by reference which will give us the possibility to modify a passed variable. ```glsl -int newFunction(in vec4 aVec4, // read-only +int newFunction(in vec4 aVec4, // read-only out vec3 aVec3, // write-only inout int aInt); // read-write ``` You may not believe it but now we have all the elements to make cool drawings. In the next chapter we will learn how to combine all our tricks to make geometric forms by *blending* the space. Yep... *blending* the space. - - diff --git a/06/easing.frag b/06/easing.frag index 79beecf..54ca0f5 100644 --- a/06/easing.frag +++ b/06/easing.frag @@ -186,4 +186,4 @@ void main() { float pct = cubicInOut( abs(fract(t)*2.0-1.) ); gl_FragColor = vec4(vec3(mix(colorA, colorB, pct)),1.0); -} \ No newline at end of file +} diff --git a/06/gradient.frag b/06/gradient.frag index 2837b67..9a09e36 100644 --- a/06/gradient.frag +++ b/06/gradient.frag @@ -12,7 +12,7 @@ vec3 colorA = vec3(0.149,0.141,0.912); vec3 colorB = vec3(1.000,0.833,0.224); float plot (vec2 st, float pct){ - return smoothstep( pct-0.01, pct, st.y) - + return smoothstep( pct-0.01, pct, st.y) - smoothstep( pct, pct+0.01, st.y); } @@ -21,7 +21,7 @@ void main() { vec3 color = vec3(0.0); vec3 pct = vec3(st.x); - + // pct.r = smoothstep(0.0,1.0, st.x); // pct.g = sin(st.x*PI); // pct.b = pow(st.x,0.5); @@ -34,4 +34,4 @@ void main() { color = mix(color,vec3(0.0,0.0,1.0),plot(st,pct.b)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/06/hsb-colorwheel.frag b/06/hsb-colorwheel.frag index 83301c8..fbbb6b0 100644 --- a/06/hsb-colorwheel.frag +++ b/06/hsb-colorwheel.frag @@ -7,12 +7,12 @@ precision mediump float; uniform vec2 u_resolution; uniform float u_time; -// Function from Iñigo Quiles +// Function from Iñigo Quiles // https://www.shadertoy.com/view/MsS3Wc vec3 hsb2rgb( in vec3 c ){ vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), - 6.0)-3.0)-1.0, - 0.0, + 6.0)-3.0)-1.0, + 0.0, 1.0 ); rgb = rgb*rgb*(3.0-2.0*rgb); return c.z * mix( vec3(1.0), rgb, c.y); @@ -26,10 +26,10 @@ void main(){ vec2 toCenter = vec2(0.5)-st; float angle = atan(toCenter.y,toCenter.x); float radius = length(toCenter)*2.0; - + // Map the angle (-PI to PI) to the Hue (from 0 to 1) // and the Saturation to the radius color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/06/hsb.frag b/06/hsb.frag index 4e00a19..1b2d73d 100644 --- a/06/hsb.frag +++ b/06/hsb.frag @@ -7,25 +7,25 @@ uniform float u_time; vec3 rgb2hsb( in vec3 c ){ vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), - vec4(c.gb, K.xy), + vec4 p = mix(vec4(c.bg, K.wz), + vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), - vec4(c.r, p.yzx), + vec4 q = mix(vec4(p.xyw, c.r), + vec4(c.r, p.yzx), step(p.x, c.r)); float d = q.x - min(q.w, q.y); float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), - d / (q.x + e), + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), + d / (q.x + e), q.x); } -// Function from Iñigo Quiles +// Function from Iñigo Quiles // https://www.shadertoy.com/view/MsS3Wc vec3 hsb2rgb( in vec3 c ){ vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), - 6.0)-3.0)-1.0, - 0.0, + 6.0)-3.0)-1.0, + 0.0, 1.0 ); rgb = rgb*rgb*(3.0-2.0*rgb); return c.z * mix(vec3(1.0), rgb, c.y); @@ -40,4 +40,4 @@ void main(){ color = hsb2rgb(vec3(st.x,1.0,st.y)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/06/index.php b/06/index.php index d2bca38..703b3b8 100644 --- a/06/index.php +++ b/06/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/06/mix.frag b/06/mix.frag index 1cb18f2..8c43457 100644 --- a/06/mix.frag +++ b/06/mix.frag @@ -13,9 +13,9 @@ void main() { float pct = abs(sin(u_time)); - // Mix uses pct (a value from 0-1) to + // Mix uses pct (a value from 0-1) to // mix the two colors - color = mix(colorA, colorB, pct); + color = mix(colorA, colorB, pct); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/06/notes.md b/06/notes.md index f49c64a..88331a7 100644 --- a/06/notes.md +++ b/06/notes.md @@ -94,7 +94,7 @@ or you can instead, use a single ```vec4``` which ```.xy``` **accessor** will re [/NICO] -These different ways of pointing to the variables inside a vector are just nomenclatures designed to help you write clear code. This flexibility embedded in shading language is a door for you to start thinking interchangably about color and space coordinates. +These different ways of pointing to the variables inside a vector are just nomenclatures designed to help you write clear code. This flexibility embedded in shading language is a door for you to start thinking interchangably about color and space coordinates. [NICO] @@ -104,4 +104,4 @@ Another great feature of vector types in GLSL is that the properties can be comb to: Concatenation or *swizzle* gets really interesting when we need to cast and mix values. The following example show you how to *swizzle* properties between vectors. -[/NICO] \ No newline at end of file +[/NICO] diff --git a/07/NOTES.md b/07/NOTES.md index a09bb46..41f4c56 100644 --- a/07/NOTES.md +++ b/07/NOTES.md @@ -8,4 +8,4 @@ * L 113 the longest distance between a pixel and the center in a normalised space is: SQRT( 2 ) * 0.5 = ~0.7071..., not 0.5 (also present ion chapter 6) * L 123 'a bigger or smaller circular surface' a circular surface is called a 'disc' :) * L 175 a word about Quadrants and its relation to the bi-unit square maybe? or just explaining why we use a bi-unit square instead of the regular 0-1 normalized space... -* L 217 'how use' missing 'to' \ No newline at end of file +* L 217 'how use' missing 'to' diff --git a/07/README-ch.md b/07/README-ch.md index 566f1fa..cac8d2e 100644 --- a/07/README-ch.md +++ b/07/README-ch.md @@ -1,5 +1,5 @@ ## 形状 - + ![Alice Hubbard, Providence, United States, ca. 1892. Photo: Zindman/Freemont.](froebel.jpg) @@ -20,7 +20,7 @@ ```glsl if ( (X GREATER THAN 1) AND (Y GREATER THAN 1) ) paint white - else + else paint black ``` @@ -32,13 +32,13 @@ uniform vec2 u_resolution; void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + // Each result will return 1.0 (white) or 0.0 (black). float left = step(0.1,st.x); // Similar to ( X greater than 0.1 ) float bottom = step(0.1,st.y); // Similar to ( Y greater than 0.1 ) // The multiplication of left*bottom will be similar to the logical AND. - color = vec3( left * bottom ); + color = vec3( left * bottom ); gl_FragColor = vec4(color,1.0); } @@ -51,7 +51,7 @@ step()函数会让没每一个小于0.1的像素变成黑色(vec3(0.0) 在前一例代码中我们重复每个像素的结构(左边和底边)。我们可以把原来的一个值换成两个值直接给step()来精减代码。就像这样: ```glsl - vec2 borders = step(vec2(0.1),st); + vec2 borders = step(vec2(0.1),st); float pct = borders.x * borders.y; ``` @@ -131,7 +131,7 @@ There are several ways to calculate that distance. The easiest one uses the [``` 其实我们是通过“空间距离”来重新解释什么是图形。这种技巧被称之为“距离场”,从字体轮廓到3D图形被广泛应用。 来小试下牛刀: - + * 用[```step()```](../glossary/?search=step)函数把所有大于0.5的像素点变成白色,并把小于的变成黑色(0.0)。 * 反转前景色和背景色。 @@ -229,10 +229,10 @@ pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6))); * 用这个例子,改造一个输入位置,指定图形(形状)的顶点数来返回一个距离场(的值)。 -* 结合使用 [```min()```](../glossary/?search=min) 和 [```max()```](../glossary/?search=max) 函数混合距离场。 +* 结合使用 [```min()```](../glossary/?search=min) 和 [```max()```](../glossary/?search=max) 函数混合距离场。 * 用距离场画个自己感兴趣的logo。 恭喜!你完成了最艰难的部分!休息下让这些概念沉淀一下吧 —— 用Processing 来画简单的形状很容易,但却不到火候。在 shader 的世界里,画形状是很纠结,而且适应这种新的编程范式会有些累人。 -既然现在你知道了如何画形状,我十分肯定你脑袋里已经充满了新的点子。在接下来的章节里你会学习到怎么移动,旋转以及缩放图形。这将使你的创作如虎添翼! \ No newline at end of file +既然现在你知道了如何画形状,我十分肯定你脑袋里已经充满了新的点子。在接下来的章节里你会学习到怎么移动,旋转以及缩放图形。这将使你的创作如虎添翼! diff --git a/07/README-de.md b/07/README-de.md index 92b674c..dc145bc 100644 --- a/07/README-de.md +++ b/07/README-de.md @@ -1,234 +1,233 @@ -![Alice Hubbard, Providence, USA, ca. 1892. Foto: Zindman/Freemont.](froebel.jpg) - -## Formen - -Endlich! Auf diesen Moment haben wir in den vorangegangenen Kapiteln hingearbeitet! Du hast die wichtigsten Grundlagen von GLSL, seine Datentypen und Funktionen kennengelernt. Und du hast mit formgebenden Funktionen gearbeitet. Jetzt ist es an der Zeit, all dieses Wissen zusammenzuführen. Bist Du bereit? In diesem Kapitel wirst Du lernen, wie man grundlegende geometrische Formen auf parallele, prozedurale Weise erstellt. - -### Rechtecke - -Stell dir vor, Du hast ein Millimeterpapier vor Dir, wie man es zuweilen im Mathematikunterricht nutzt. Und Deine Aufgabe ist es, darauf ein ausgefülltes Quadrat zu zeichnen. Die Größe des Papieres beträgt *10 x 10* und das Quadrat soll *8 x 8* sein. Wie gehst Du vor? - -![](grid_paper.jpg) - -Vielleicht würdest Du einfach die gesamte Fläche ausfüllen und dabei nur die erste und die letzte Zeile auslassen, ebenso wie die erste und die letzte Spalte. So käme das gewünschte Quadrat sehr einfach zustande. - -Wie hängt das nun mit Shadern zusammen? Jedes kleine Quadrat auf unserem Millimeterpapier können wir uns als ein Pixel, d.h. einen parallel ausgeführten *Thread*, vorstellen. Und jedes dieser Quadrate (*jeder Thread*) kennt seine Koordinate, wie bei einem Schachbrett. In den vorangegangenen Kapiteln haben wir die *x-* und die *y-Ordinate* jeweils auf den *roten* und *grünen* Farbkanal des Punktes abgebildet. Wir haben gelernt, wie wir den schmalen zweidimensionalen Bereich zwischen ```0.0``` und ```1.0``` bearbeiten. Wie können wir dieses Wissen nun anwenden, um in der Mitte unserer Zeichenfläche ein zentriertes weißes Quadrat zu malen? - -Lass uns mit etwas Pseudocode beginnen, der mit ```if```-Befehlen auf die Lage des zu bearbeitenden Pixels innerhalb der Zeichenfläche eingeht. Das Vorgehen ähnelt dabei in bemerkenswerte Weise dem oben skizzierten beim Malen auf Millimeterpapier. - -```glsl - if ( (X GROESSER ALS 1) UND (Y GROESSER ALS 1) ) - male weiss - else - male schwarz -``` - -Jetzt, wo wir eine Idee haben, wie die Lösung aussehen könnte, lass uns den ```if```-Befehl durch einen Aufruf der [```step()```](../glossary/?search=step)-Funktion ersetzen, und anstelle der Maße *10 x 10* normalisierte Werte zwischen ```0.0``` und ```1.0``` bearbeiten: - -```glsl -uniform vec2 u_resolution; - -void main(){ - vec2 st = gl_FragCoord.xy/u_resolution.xy; - vec3 color = vec3(0.0); - - // diese Berechnungen liefern jeweils 1.0 (weiss) oder 0.0 (schwarz). - float left = step(0.1,st.x); // entspricht X groesser als 0.1 - float bottom = step(0.1,st.y); // entspricht Y groesser als 0.1 - - // die Multiplikation von left*bottom entspricht der logischen Verknüpfung durch UND - color = vec3( left * bottom ); - - gl_FragColor = vec4(color,1.0); -} -``` - -Die [```step()```](../glossary/?search=step)-Funktion setzt jedes Pixel unterhalb von ```0.1``` auf Schwarz (```vec3(0.0)```) und alle anderen auf Weiß (```vec3(1.0)```). Die Multiplikation von ```left``` und ```bottom``` arbeitet wie eine logische *UND-Verknüpfung*, weil nur dann nicht ```0.0```, sondern ```1.0``` herauskommt, wenn beide Variablen auf ```1.0``` stehen. So entstehen zwei schwarze Linien, eine am linken und eine am unteren Rand der Zeichenfläche. Der Rest wird weiß. - -![](rect-01.jpg) - -Im obigen Programmcode wiederholen wir die gleiche Vorgehensweise für beide Ränder (links und unten). Wir können das noch etwas kompakter formulieren, indem wir in einem Aufruf zwei Testwerte in Form eines zweidimensionalen Vektors an [```step()```](../glossary/?search=step) übergeben. Das sieht dann so aus: - -```glsl - vec2 borders = step(vec2(0.1),st); - float pct = borders.x * borders.y; -``` - -Bis jetzt haben wir nur zwei Kanten unseres Rechtecks bearbeitet. Jetzt kommen auch die beiden anderen Kanten – die rechte und die obere – an die Reihe. Schau Dir den folgenden Programmcode an: - -
- -Entferne die Kommentarzeichen aus den *Zeilen 21-22* und beobachte, wie wir die Koordinaten auf den linken und unteren Rand abbilden (```1-st```), damit wir sie wieder mit der [```step()```](../glossary/?search=step) Funktion und dem Wert von ```0.1``` vergleichen können. Aus der oberen rechten Ecke (```vec2(1.0,1.0)```) wird so für unsere Berechnungen quasi die untere linke Ecke ```vec2(0.0,0.0)```. Das ist so, als würden wir die Zeichenfläche einfach um 180 Grad drehen und den Test dann wie zuvor wiederholen. - -![](rect-02.jpg) - -Beachte außerdem, dass in den *Zeilen 18 und 22* die Ergebnisse von ```step()``` in Bezug auf alle vier Seiten miteinander multipliziert werden. Dies entspricht wiederum eine logischen *UND*-Verknüpfung, denn wir erhalten nur dann *Weiß* (```1.0```), wenn keines der Ergebnisse *Schwarz* (```0.0```) ist. Wir könnten auch schreiben: - -```glsl - vec2 bl = step(vec2(0.1),st); // linke und untere Kante - vec2 tr = step(vec2(0.1),1.0-st); // rechte und obere Kante - color = vec3(bl.x * bl.y * tr.x * tr.y); //UND-Verknuepfung -``` - -Interessant, nicht wahr? Wir nutzen für diese Technik also [```step()```](../glossary/?search=step) zum Vergleichen, eine Subtraktion für die Drehung der Koordinaten und die Multiplikation als logische *UND*-Verknüpfung. - -Bevor wir weitermachen, probiere bitte die folgenden Übungen aus: - -* Ändere die Größe und die Proportionen des Rechtecks. - -* Experimentiere mit dem Ersetzen von [```step()```](../glossary/?search=step) durch [```smoothstep()```](../glossary/?search=smoothstep). Versuche, dadurch von harten Kanten zu weichen Kanten mit eleganten Übergängen zu gelangen. - -* Baue den Code so um, dass er [```floor()```](../glossary/?search=floor) verwendet. - -* Nimm die Implementierung, die Dir am besten gefällt, und baue daraus eine Funktion, die Du in Zukunft zum Zeichnen von Rechtecken und Quadraten verwenden kannst. Gestalte diese Funktion möglichst effizient. - -* Entwickle eine andere Funktion, die kein ausgefülltes Rechteck zeichnet, sondern nur die Umrisse, d.h. die vier Kanten. - -* Überlege Dir, wie Du die Rechtecke verschieben und mehrere davon auf der Zeichenfläche platzieren kannst. Falls Dir das gelingt, unterstreiche Deine Fähigkeiten, indem Du eine Komposition in der Art von [Piet Mondrian](http://de.wikipedia.org/wiki/Piet_Mondrian) erstellst. - -![Piet Mondrian - Tableau (1921)](mondrian.jpg) - -### Kreise - -Es ist nicht schwer, Quadrate auf Millimeterpapier zu zeichnen und Rechtecke mit Hilfe kartesischer Koordinaten zu konstruieren. Kreise verlangen jedoch einen anderen Ansatz, zumal wie hier einen Pixel-orientierten Algorithmus benötigen. Eine Lösung besteht darin, die Koordinaten zu transformieren, damit wir beim Zeichnen die [```step()```](../glossary/?search=step)-Funktion nutzen können. - -Doch wie soll das funktionieren? Lasse uns noch einmal zum Mathematikunterricht und dem Millimeterpapier zurückkehren. In der Schule haben die meisten von uns vermutlich gelernt, wie man mit dem Zirkel einen Kreis malt: Über das Drehrad stellt man zunächst den gewünschten Radius ein, platziert den Zirkel im Mittelpunkt des zu zeichnenden Kreises und schwingt das Zeichengerät anschließend mit einer eleganten Drehung über das Papier. - -![](compass.jpg) - -Will man diese Vorgehensweise auf ein Shader-Programm übertragen, bei dem jedes kleine Feld auf dem Millimeterpapier einem Pixel entspricht, muss man jedes Pixel (bzw. Thread) *fragen*, ob es zum Kreis gehört. Das machen wir, indem wir die Entfernung des Pixels zum Mittelpunkt des gewünschten Kreises berechnen. - -![](circle.jpg) - -Tatsächlich gibt es in GLSL mehrere Wege, diese Entfernung zu bestimmen. Die einfachste Möglichkeit greift auf die [```distance()```](../glossary/?search=distance)-Funktion zurück, die intern den Abstand (die Länge) [```length()```](../glossary/?search=length) zwischen zwei Punkten berechnet. In unserem Fall werden diese beiden Punkte durch die aktuelle Pixel-Koordinate sowie die Mitte der Zeichenfläche verkörpert, die hier den Kreismittelpunkt bilden soll. Die ```length()```-Funktion ist nichts anderes als eine Umsetzung der [Hypothenuse-Formel](http://de.wikipedia.org/wiki/Rechtwinkliges_Dreieck), die intern die Quadratwurzel ([```sqrt()```](../glossary/?search=sqrt)) berechnet. - -![](hypotenuse.png) - -Man kann wahlweise die [```distance()```](../glossary/?search=distance)-Funktion, die [```length()```](../glossary/?search=length)-Funktion oder die [```sqrt()```](../glossary/?search=sqrt)-Funktion nutzen, um die Entfernung zur Mitte der Zeichenfläche zu berechnen. Der folgende Programmcode enthält alle drei Möglichkeiten und liefert erwartungsgemäß jeweils das gleiche Ergebnis zurück. - -* Kommentiere die einzelnen Zeilen aus bzw. ein, um Dir die verschiedenen Wege anzuschauen. - -
- -In dem obigen Beispiel bilden wir die Entfernung zum Mittelpunkt der Zeichenfläche auf die Helligkeit der Pixel ab. Je näher sich ein Pixel beim Mittelpunkt befindet, desto geringer (dunkler) ist sein Farbwert. Beachte bitte, dass die Pixel auch zum Rand hin nicht allzu hell werden, weil die Entfernung vom Mittelpunkt ( ```vec2(0.5, 0.5)``` ) zu den Rändern maximal ```0.5``` beträgt. Denke ein wenig über die Abbildung nach und überlege Dir: - -* Was kannst Du daraus ableiten? - -* Wie kannst Du all dies nutzen, um einen Kreis zu malen? - -* Verändere des obige Beispiel, damit der Farbverlauf ausschließlich innerhalb der Grenzen des Kreises stattfindet. - -### Distanzfelder - -Man kann sich das obige Beispiel auch als eine Art Höhenprofil vorstellen, bei dem dunklere Stellen für größere Höhen stehen. Der Farbverlauf repräsentiert dann so etwas wie einen Kegel. Stell Dir vor, Du stehst auf der Spitze des Kegels. Die horizontale Entfernung zum Kegelrand beträgt in alle Richtungen jeweils ```0.5```. Indem Du den Kegel an einer gewählten Stelle abschneidest, erhältst Du je nachdem eine größere oder eine kleinere Kreisfläche. - -![](distance-field.jpg) - -Im Prinzip nutzen wir also eine Neuinterpretation des Raumes (ausgehend vom Abstand zur Mitte), um eine bestimmte Form zu kreieren. Diese Technik ist als „Distanzfeld“ bekannt und wird bei der Erstellung von 3D-Grafiken auf vielfältige Weise genutzt. - -Versuche Dich doch einmal an folgenden Übungen: - -* Nutze die [```step()```](../glossary/?search=step)-Funktion, um alle Punkte größer als ```0.5``` weiß zu malen und alles darunter schwarz. - -* Invertiere die Farben von Vordergrund und Hintergrund. - -* Setze [```smoothstep()```](../glossary/?search=smoothstep) ein und experimentiere mit verschiedenen Grenzwerten, um angenehm sanfte Übergänge am Rand Deines Kreises zu erzeugen. - -* Sobald Dir die Implementierung gefällt, baue daraus eine Funktion, die Du in zukünftigen Projekten einsetzen kannst. - -* Fülle den Kreis mit einer Farbe. - -* Kannst Du den Kreis animieren, so dass sein Umfang rhythmisch ansteigt und abschwillt, so wie bei einem schlagenden Herz? (Du kannst Dich dabei von der Animation aus dem letzten Kapitel anleiten lassen.) - -* Wie sieht es mit der Bewegung des Kreises aus? Gelingt es Dir, den Kreis zu verschieben und mehrere Kreise innerhalb der Zeichenfläche erscheinen zu lassen? - -* Was passiert, wenn Du mehrere Distanzfelder durch unterschiedliche Funktionen und Operationen kombinierst? - -```glsl -pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6)); -pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6)); -pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6))); -pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6))); -pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6))); -``` - -* Entwickle drei Kompositionen auf Basis dieser Technik. Wenn Du sie animieren kannst, umso besser! - -####Für Deine Werkzeugsammlung - -Im Hinblick auf die erforderliche Rechenleistung kann die [```sqrt()```](../glossary/?search=sqrt)-Funktion – und alle Funktionen, die darauf basieren – sehr kostspielig sein. Deshalb hier nun ein anderer Weg, wie man kreisförmige Distanzfelder mit Hilfe der [```dot()```](../glossary/?search=dot)-Funktion über das Skalarprodukt erzeugen kann. - -
- -### Nützliche Eigenschaften von Distanzfeldern - -![Zen garden](zen-garden.jpg) - -Distanzfelder lassen sich nutzen, um beinahe jede Art von Form zu zeichnen. Je komplexer die gewünschte Form, desto komplexer fällt in der Regel auch die dafür benötigte Distanzformel aus. Doch sobald Du die benötigte Distanzformel beisammenhast, wird es sehr einfach, gewünschte Effekte darauf anzuwenden, beispielweise weiche Kanten oder mehrfache Umrisse. Aus diesem Grund sind Distanzfelder u.a. bei der Schriftenerzeugung sehr populär, nachzulesen etwa bei [Mapbox GL Labels](https://www.mapbox.com/blog/text-signed-distance-fields/), bei [Matt DesLauriers](https://twitter.com/mattdesl) und bei [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu). - -Schau Dir den folgenden Programmcode an. - -
- -Wir beginnen, indem wir den Wertebereich unserer *x*- und *y*-Ordinate auf die Spanne zwischen ```-1``` und ```1``` skalieren und damit gleichzeitig die Basis des Koordinatensystems *(0/0)* in die Mitte der Zeichenfläche verschieben. In der *Zeile 24* visualisieren wir die Werte unseres Distanzfeldes, indem wir sie mit zehn multiplizieren und die [```fract()```](../glossary/?search=fract)-Funktion auf das Ergebnis anwenden. *fract()* liefert immer nur den Nachkommateil des Ergebnisses, also eine Zahl zwischen ```0.0``` und ```0.99999...```, so dass bei den wiederholten Aufrufe für die verschiedenen Pixel ein Farbverlauf von Schwarz nach Weiß entsteht. Durch die Multiplikation mit zehn wiederholt sich dieser Verlauf genau zehn Mal. So entsteht ein repetitives Kreismuster, wie bei einem Zen-Garten. - -Lass uns einen Blick auf die Formel zur Berechnung des Distanzfeldes in der *Programmzeile 19* werfen. Dort berechnen wir den Abstand zur Position ```(.3,.3)```. Damit dies in allen vier Quadranten gleichermaßen geschieht, wird der zu bearbeitende Punkt jeweils auf den ersten Quadranten abgebildet. Dafür sorgt hier die [```abs()```](../glossary/?search=abs)-Funktion. - -Wenn Du die Kommentarzeichen in *Programmzeile 20* entfernst, kannst Du beobachten, wie wir die Entfernung bei allen Punkten um ```0.3``` reduzieren. Anschließend setzen wir den Abstand mit Hilfe der [```min()```](../glossary/?search=min)-Funktion für alle Punkte, deren Abstand dann noch größer als ```0.0``` ist (also vorher größer als ```0.3``` war), auf ```0.0```. Das erzeugt ein neues interessantes Muster. - -Sobald Du anschließend die Kommentarzeichen aus der *Programmzeile 21* entfernst, geschieht etwas ähnliches, nur quasi umgekehrt und mit Hilfe der Funktion [```max()```](../glossary/?search=max). Wieder wird der Abstand um ```0.3``` verringert, anschließend aber für alle Punkte auf ```0.0``` gesetzt, deren Abstand nun kleiner als ```0.0``` ist (vorher also zwischen ```0.0``` und ```0.3``` lag). Wir erhalten auf diese Weise mehrere geschachtelte Quadrate mit abgerundeten Ecken. - -Entferne nun nach und nach die Kommentarzeichen aus den *Programmzeilen 27 bis 29*, um deren Auswirkung auf das Zeichnen mit dem Distanzfeld zu verstehen. - -### Polarformen - -![Robert Mangold – Ohne Titel (2008)](mangold.jpg) - -Im Kapitel über die Verwendung von Farben haben wir kartesische Koordinaten auf Polarkoordinaten abgebildet. Wir berechneten dazu den *Radius* und den *Winkel* jeder Koordinate mit Hilfe der folgenden Formel: - -```glsl - vec2 pos = vec2(0.5)-st; - float r = length(pos)*2.0; - float a = atan(pos.y,pos.x); -``` - -Einige dieser Formeln haben wir auch am Anfang dieses Kapitels genutzt, als es darum ging, Kreise zu zeichnen. Wir berechneten die Entfernung zum Kreismittelpunkt mit Hilfe der [```length()```](../glossary/?search=length)-Funktion. Jetzt, wo wir Distanzfelder kennengelernt haben, öffnet sich uns ein weiterer Weg zum Zeichnen komplexer Formen mithilfe von Polarkoordinaten. - -Diese Technik unterliegt gewissen Beschränkungen, ist dafür aber sehr simpel und leistungsfähig. Sie beruht darauf, den Radius eines Kreises in Abhängigkeit des jeweiligen Winkels zu verändern, um unterschiedliche Formen zu erschaffen. Wie genau läuft diese Modulierung ab? Nun, Du hast es vielleicht schon erraten: Mit formgebenden Funktionen. - -Unten findest Du verschiedene Funktionen jeweils zwei Mal: einmal als Verlaufskurve in einem kartesischen Koordinatensystem und dann als Shader-Programmcode in einem polaren Koordinatensystem. Dort stehen die verschiedenen formgebenden Funktionen in den *Programmzeilen 21 bis 25*. Entferne nun Schritt für Schritt die Kommentarzeilen und vergleiche den jeweiligen Funktionsgraphen im kartesischen Koordinatensystem mit seinem Äquivalent beim Zeichnen innerhalb eines Polarkoordinatensystem mit GLSL. - -
- -
- -Versuche doch einmal: - -* Diese Formen zu animieren. - -* Verschiedene formgebende Funktionen zu kombinieren, um Löcher in die Formen zu „stanzen“ und dadurch Blumen, Schneeflocken oder Zahnräder entstehen zu lassen. - -* Nutze die ```plot()```-Funktion aus dem Kapitel über formgebende Funktionen, um nur die Kontur der jeweiligen Form zeichnen zu lassen. - -### Und nun alles zusammen - -Wir haben gelernt, den Radius einer Kreisform mit Hilfe der [```atan()```](../glossary/?search=atan)-Funktion in Abhängigkeit des Winkels für das Zeichnen unterschiedlicher Formen zu nutzen. Nun können wir ```atan()``` auch mit Distanzfeldern einsetzen, um ganz unterschiedliche Effekte zu erzielen. - -Unser Trick nutzt die gegebene Anzahl der Seiten eines Polygons, um das benötigte Distanzfeld mit Hilfe von Polarkoordinaten zu erzeugen. Schau Dir dazu auch den [folgenden Programmcode](http://thndl.com/square-shaped-shaders.html) von [Andrew Baldwin](https://twitter.com/baldand) an. - -
- -* Nutze das obige Programmbeispiel, um eine Funktion zu programmieren, die als Eingabe die Anzahl und Position der Ecken einer gewünschten Form erhält und als Ergebnis den Wert für das Distanzfeld liefert. - -* Mische verschiedene Distanzfelder miteinander, indem Du die Funktionen [```min()```](../glossary/?search=min) und [```max()```](../glossary/?search=max) nutzt. - -* Wähle ein geometrisches Logo, das Du mit Hilfe von Distanzfeldern replizierst. - -Herzlichen Glückwunsch! Du hast Dich durch schwieriges Fahrwasser gekämpft. Nimm eine kleine Pause, damit sich das Erlernte setzen kann. Das Zeichnen komplexer Formen im Land der Shader ist wahrlich nicht ganz trivial, das kann durchaus ein wenig erschöpfen. - -Da Du nun weißt, wie man unterschiedliche Formen zeichnet, kommen Dir bestimmt viele interessante Ideen in den Sinn. In den folgenden Kapiteln lernen wir, wie man Formen verschieben, skalieren und rotieren kann. Das wird Dir ermöglichen, komplexe Kompositionen zu erstellen. - +![Alice Hubbard, Providence, USA, ca. 1892. Foto: Zindman/Freemont.](froebel.jpg) + +## Formen + +Endlich! Auf diesen Moment haben wir in den vorangegangenen Kapiteln hingearbeitet! Du hast die wichtigsten Grundlagen von GLSL, seine Datentypen und Funktionen kennengelernt. Und du hast mit formgebenden Funktionen gearbeitet. Jetzt ist es an der Zeit, all dieses Wissen zusammenzuführen. Bist Du bereit? In diesem Kapitel wirst Du lernen, wie man grundlegende geometrische Formen auf parallele, prozedurale Weise erstellt. + +### Rechtecke + +Stell dir vor, Du hast ein Millimeterpapier vor Dir, wie man es zuweilen im Mathematikunterricht nutzt. Und Deine Aufgabe ist es, darauf ein ausgefülltes Quadrat zu zeichnen. Die Größe des Papieres beträgt *10 x 10* und das Quadrat soll *8 x 8* sein. Wie gehst Du vor? + +![](grid_paper.jpg) + +Vielleicht würdest Du einfach die gesamte Fläche ausfüllen und dabei nur die erste und die letzte Zeile auslassen, ebenso wie die erste und die letzte Spalte. So käme das gewünschte Quadrat sehr einfach zustande. + +Wie hängt das nun mit Shadern zusammen? Jedes kleine Quadrat auf unserem Millimeterpapier können wir uns als ein Pixel, d.h. einen parallel ausgeführten *Thread*, vorstellen. Und jedes dieser Quadrate (*jeder Thread*) kennt seine Koordinate, wie bei einem Schachbrett. In den vorangegangenen Kapiteln haben wir die *x-* und die *y-Ordinate* jeweils auf den *roten* und *grünen* Farbkanal des Punktes abgebildet. Wir haben gelernt, wie wir den schmalen zweidimensionalen Bereich zwischen ```0.0``` und ```1.0``` bearbeiten. Wie können wir dieses Wissen nun anwenden, um in der Mitte unserer Zeichenfläche ein zentriertes weißes Quadrat zu malen? + +Lass uns mit etwas Pseudocode beginnen, der mit ```if```-Befehlen auf die Lage des zu bearbeitenden Pixels innerhalb der Zeichenfläche eingeht. Das Vorgehen ähnelt dabei in bemerkenswerte Weise dem oben skizzierten beim Malen auf Millimeterpapier. + +```glsl + if ( (X GROESSER ALS 1) UND (Y GROESSER ALS 1) ) + male weiss + else + male schwarz +``` + +Jetzt, wo wir eine Idee haben, wie die Lösung aussehen könnte, lass uns den ```if```-Befehl durch einen Aufruf der [```step()```](../glossary/?search=step)-Funktion ersetzen, und anstelle der Maße *10 x 10* normalisierte Werte zwischen ```0.0``` und ```1.0``` bearbeiten: + +```glsl +uniform vec2 u_resolution; + +void main(){ + vec2 st = gl_FragCoord.xy/u_resolution.xy; + vec3 color = vec3(0.0); + + // diese Berechnungen liefern jeweils 1.0 (weiss) oder 0.0 (schwarz). + float left = step(0.1,st.x); // entspricht X groesser als 0.1 + float bottom = step(0.1,st.y); // entspricht Y groesser als 0.1 + + // die Multiplikation von left*bottom entspricht der logischen Verknüpfung durch UND + color = vec3( left * bottom ); + + gl_FragColor = vec4(color,1.0); +} +``` + +Die [```step()```](../glossary/?search=step)-Funktion setzt jedes Pixel unterhalb von ```0.1``` auf Schwarz (```vec3(0.0)```) und alle anderen auf Weiß (```vec3(1.0)```). Die Multiplikation von ```left``` und ```bottom``` arbeitet wie eine logische *UND-Verknüpfung*, weil nur dann nicht ```0.0```, sondern ```1.0``` herauskommt, wenn beide Variablen auf ```1.0``` stehen. So entstehen zwei schwarze Linien, eine am linken und eine am unteren Rand der Zeichenfläche. Der Rest wird weiß. + +![](rect-01.jpg) + +Im obigen Programmcode wiederholen wir die gleiche Vorgehensweise für beide Ränder (links und unten). Wir können das noch etwas kompakter formulieren, indem wir in einem Aufruf zwei Testwerte in Form eines zweidimensionalen Vektors an [```step()```](../glossary/?search=step) übergeben. Das sieht dann so aus: + +```glsl + vec2 borders = step(vec2(0.1),st); + float pct = borders.x * borders.y; +``` + +Bis jetzt haben wir nur zwei Kanten unseres Rechtecks bearbeitet. Jetzt kommen auch die beiden anderen Kanten – die rechte und die obere – an die Reihe. Schau Dir den folgenden Programmcode an: + +
+ +Entferne die Kommentarzeichen aus den *Zeilen 21-22* und beobachte, wie wir die Koordinaten auf den linken und unteren Rand abbilden (```1-st```), damit wir sie wieder mit der [```step()```](../glossary/?search=step) Funktion und dem Wert von ```0.1``` vergleichen können. Aus der oberen rechten Ecke (```vec2(1.0,1.0)```) wird so für unsere Berechnungen quasi die untere linke Ecke ```vec2(0.0,0.0)```. Das ist so, als würden wir die Zeichenfläche einfach um 180 Grad drehen und den Test dann wie zuvor wiederholen. + +![](rect-02.jpg) + +Beachte außerdem, dass in den *Zeilen 18 und 22* die Ergebnisse von ```step()``` in Bezug auf alle vier Seiten miteinander multipliziert werden. Dies entspricht wiederum eine logischen *UND*-Verknüpfung, denn wir erhalten nur dann *Weiß* (```1.0```), wenn keines der Ergebnisse *Schwarz* (```0.0```) ist. Wir könnten auch schreiben: + +```glsl + vec2 bl = step(vec2(0.1),st); // linke und untere Kante + vec2 tr = step(vec2(0.1),1.0-st); // rechte und obere Kante + color = vec3(bl.x * bl.y * tr.x * tr.y); //UND-Verknuepfung +``` + +Interessant, nicht wahr? Wir nutzen für diese Technik also [```step()```](../glossary/?search=step) zum Vergleichen, eine Subtraktion für die Drehung der Koordinaten und die Multiplikation als logische *UND*-Verknüpfung. + +Bevor wir weitermachen, probiere bitte die folgenden Übungen aus: + +* Ändere die Größe und die Proportionen des Rechtecks. + +* Experimentiere mit dem Ersetzen von [```step()```](../glossary/?search=step) durch [```smoothstep()```](../glossary/?search=smoothstep). Versuche, dadurch von harten Kanten zu weichen Kanten mit eleganten Übergängen zu gelangen. + +* Baue den Code so um, dass er [```floor()```](../glossary/?search=floor) verwendet. + +* Nimm die Implementierung, die Dir am besten gefällt, und baue daraus eine Funktion, die Du in Zukunft zum Zeichnen von Rechtecken und Quadraten verwenden kannst. Gestalte diese Funktion möglichst effizient. + +* Entwickle eine andere Funktion, die kein ausgefülltes Rechteck zeichnet, sondern nur die Umrisse, d.h. die vier Kanten. + +* Überlege Dir, wie Du die Rechtecke verschieben und mehrere davon auf der Zeichenfläche platzieren kannst. Falls Dir das gelingt, unterstreiche Deine Fähigkeiten, indem Du eine Komposition in der Art von [Piet Mondrian](http://de.wikipedia.org/wiki/Piet_Mondrian) erstellst. + +![Piet Mondrian - Tableau (1921)](mondrian.jpg) + +### Kreise + +Es ist nicht schwer, Quadrate auf Millimeterpapier zu zeichnen und Rechtecke mit Hilfe kartesischer Koordinaten zu konstruieren. Kreise verlangen jedoch einen anderen Ansatz, zumal wie hier einen Pixel-orientierten Algorithmus benötigen. Eine Lösung besteht darin, die Koordinaten zu transformieren, damit wir beim Zeichnen die [```step()```](../glossary/?search=step)-Funktion nutzen können. + +Doch wie soll das funktionieren? Lasse uns noch einmal zum Mathematikunterricht und dem Millimeterpapier zurückkehren. In der Schule haben die meisten von uns vermutlich gelernt, wie man mit dem Zirkel einen Kreis malt: Über das Drehrad stellt man zunächst den gewünschten Radius ein, platziert den Zirkel im Mittelpunkt des zu zeichnenden Kreises und schwingt das Zeichengerät anschließend mit einer eleganten Drehung über das Papier. + +![](compass.jpg) + +Will man diese Vorgehensweise auf ein Shader-Programm übertragen, bei dem jedes kleine Feld auf dem Millimeterpapier einem Pixel entspricht, muss man jedes Pixel (bzw. Thread) *fragen*, ob es zum Kreis gehört. Das machen wir, indem wir die Entfernung des Pixels zum Mittelpunkt des gewünschten Kreises berechnen. + +![](circle.jpg) + +Tatsächlich gibt es in GLSL mehrere Wege, diese Entfernung zu bestimmen. Die einfachste Möglichkeit greift auf die [```distance()```](../glossary/?search=distance)-Funktion zurück, die intern den Abstand (die Länge) [```length()```](../glossary/?search=length) zwischen zwei Punkten berechnet. In unserem Fall werden diese beiden Punkte durch die aktuelle Pixel-Koordinate sowie die Mitte der Zeichenfläche verkörpert, die hier den Kreismittelpunkt bilden soll. Die ```length()```-Funktion ist nichts anderes als eine Umsetzung der [Hypothenuse-Formel](http://de.wikipedia.org/wiki/Rechtwinkliges_Dreieck), die intern die Quadratwurzel ([```sqrt()```](../glossary/?search=sqrt)) berechnet. + +![](hypotenuse.png) + +Man kann wahlweise die [```distance()```](../glossary/?search=distance)-Funktion, die [```length()```](../glossary/?search=length)-Funktion oder die [```sqrt()```](../glossary/?search=sqrt)-Funktion nutzen, um die Entfernung zur Mitte der Zeichenfläche zu berechnen. Der folgende Programmcode enthält alle drei Möglichkeiten und liefert erwartungsgemäß jeweils das gleiche Ergebnis zurück. + +* Kommentiere die einzelnen Zeilen aus bzw. ein, um Dir die verschiedenen Wege anzuschauen. + +
+ +In dem obigen Beispiel bilden wir die Entfernung zum Mittelpunkt der Zeichenfläche auf die Helligkeit der Pixel ab. Je näher sich ein Pixel beim Mittelpunkt befindet, desto geringer (dunkler) ist sein Farbwert. Beachte bitte, dass die Pixel auch zum Rand hin nicht allzu hell werden, weil die Entfernung vom Mittelpunkt ( ```vec2(0.5, 0.5)``` ) zu den Rändern maximal ```0.5``` beträgt. Denke ein wenig über die Abbildung nach und überlege Dir: + +* Was kannst Du daraus ableiten? + +* Wie kannst Du all dies nutzen, um einen Kreis zu malen? + +* Verändere des obige Beispiel, damit der Farbverlauf ausschließlich innerhalb der Grenzen des Kreises stattfindet. + +### Distanzfelder + +Man kann sich das obige Beispiel auch als eine Art Höhenprofil vorstellen, bei dem dunklere Stellen für größere Höhen stehen. Der Farbverlauf repräsentiert dann so etwas wie einen Kegel. Stell Dir vor, Du stehst auf der Spitze des Kegels. Die horizontale Entfernung zum Kegelrand beträgt in alle Richtungen jeweils ```0.5```. Indem Du den Kegel an einer gewählten Stelle abschneidest, erhältst Du je nachdem eine größere oder eine kleinere Kreisfläche. + +![](distance-field.jpg) + +Im Prinzip nutzen wir also eine Neuinterpretation des Raumes (ausgehend vom Abstand zur Mitte), um eine bestimmte Form zu kreieren. Diese Technik ist als „Distanzfeld“ bekannt und wird bei der Erstellung von 3D-Grafiken auf vielfältige Weise genutzt. + +Versuche Dich doch einmal an folgenden Übungen: + +* Nutze die [```step()```](../glossary/?search=step)-Funktion, um alle Punkte größer als ```0.5``` weiß zu malen und alles darunter schwarz. + +* Invertiere die Farben von Vordergrund und Hintergrund. + +* Setze [```smoothstep()```](../glossary/?search=smoothstep) ein und experimentiere mit verschiedenen Grenzwerten, um angenehm sanfte Übergänge am Rand Deines Kreises zu erzeugen. + +* Sobald Dir die Implementierung gefällt, baue daraus eine Funktion, die Du in zukünftigen Projekten einsetzen kannst. + +* Fülle den Kreis mit einer Farbe. + +* Kannst Du den Kreis animieren, so dass sein Umfang rhythmisch ansteigt und abschwillt, so wie bei einem schlagenden Herz? (Du kannst Dich dabei von der Animation aus dem letzten Kapitel anleiten lassen.) + +* Wie sieht es mit der Bewegung des Kreises aus? Gelingt es Dir, den Kreis zu verschieben und mehrere Kreise innerhalb der Zeichenfläche erscheinen zu lassen? + +* Was passiert, wenn Du mehrere Distanzfelder durch unterschiedliche Funktionen und Operationen kombinierst? + +```glsl +pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6)); +pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6)); +pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +``` + +* Entwickle drei Kompositionen auf Basis dieser Technik. Wenn Du sie animieren kannst, umso besser! + +####Für Deine Werkzeugsammlung + +Im Hinblick auf die erforderliche Rechenleistung kann die [```sqrt()```](../glossary/?search=sqrt)-Funktion – und alle Funktionen, die darauf basieren – sehr kostspielig sein. Deshalb hier nun ein anderer Weg, wie man kreisförmige Distanzfelder mit Hilfe der [```dot()```](../glossary/?search=dot)-Funktion über das Skalarprodukt erzeugen kann. + +
+ +### Nützliche Eigenschaften von Distanzfeldern + +![Zen garden](zen-garden.jpg) + +Distanzfelder lassen sich nutzen, um beinahe jede Art von Form zu zeichnen. Je komplexer die gewünschte Form, desto komplexer fällt in der Regel auch die dafür benötigte Distanzformel aus. Doch sobald Du die benötigte Distanzformel beisammenhast, wird es sehr einfach, gewünschte Effekte darauf anzuwenden, beispielweise weiche Kanten oder mehrfache Umrisse. Aus diesem Grund sind Distanzfelder u.a. bei der Schriftenerzeugung sehr populär, nachzulesen etwa bei [Mapbox GL Labels](https://www.mapbox.com/blog/text-signed-distance-fields/), bei [Matt DesLauriers](https://twitter.com/mattdesl) und bei [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu). + +Schau Dir den folgenden Programmcode an. + +
+ +Wir beginnen, indem wir den Wertebereich unserer *x*- und *y*-Ordinate auf die Spanne zwischen ```-1``` und ```1``` skalieren und damit gleichzeitig die Basis des Koordinatensystems *(0/0)* in die Mitte der Zeichenfläche verschieben. In der *Zeile 24* visualisieren wir die Werte unseres Distanzfeldes, indem wir sie mit zehn multiplizieren und die [```fract()```](../glossary/?search=fract)-Funktion auf das Ergebnis anwenden. *fract()* liefert immer nur den Nachkommateil des Ergebnisses, also eine Zahl zwischen ```0.0``` und ```0.99999...```, so dass bei den wiederholten Aufrufe für die verschiedenen Pixel ein Farbverlauf von Schwarz nach Weiß entsteht. Durch die Multiplikation mit zehn wiederholt sich dieser Verlauf genau zehn Mal. So entsteht ein repetitives Kreismuster, wie bei einem Zen-Garten. + +Lass uns einen Blick auf die Formel zur Berechnung des Distanzfeldes in der *Programmzeile 19* werfen. Dort berechnen wir den Abstand zur Position ```(.3,.3)```. Damit dies in allen vier Quadranten gleichermaßen geschieht, wird der zu bearbeitende Punkt jeweils auf den ersten Quadranten abgebildet. Dafür sorgt hier die [```abs()```](../glossary/?search=abs)-Funktion. + +Wenn Du die Kommentarzeichen in *Programmzeile 20* entfernst, kannst Du beobachten, wie wir die Entfernung bei allen Punkten um ```0.3``` reduzieren. Anschließend setzen wir den Abstand mit Hilfe der [```min()```](../glossary/?search=min)-Funktion für alle Punkte, deren Abstand dann noch größer als ```0.0``` ist (also vorher größer als ```0.3``` war), auf ```0.0```. Das erzeugt ein neues interessantes Muster. + +Sobald Du anschließend die Kommentarzeichen aus der *Programmzeile 21* entfernst, geschieht etwas ähnliches, nur quasi umgekehrt und mit Hilfe der Funktion [```max()```](../glossary/?search=max). Wieder wird der Abstand um ```0.3``` verringert, anschließend aber für alle Punkte auf ```0.0``` gesetzt, deren Abstand nun kleiner als ```0.0``` ist (vorher also zwischen ```0.0``` und ```0.3``` lag). Wir erhalten auf diese Weise mehrere geschachtelte Quadrate mit abgerundeten Ecken. + +Entferne nun nach und nach die Kommentarzeichen aus den *Programmzeilen 27 bis 29*, um deren Auswirkung auf das Zeichnen mit dem Distanzfeld zu verstehen. + +### Polarformen + +![Robert Mangold – Ohne Titel (2008)](mangold.jpg) + +Im Kapitel über die Verwendung von Farben haben wir kartesische Koordinaten auf Polarkoordinaten abgebildet. Wir berechneten dazu den *Radius* und den *Winkel* jeder Koordinate mit Hilfe der folgenden Formel: + +```glsl + vec2 pos = vec2(0.5)-st; + float r = length(pos)*2.0; + float a = atan(pos.y,pos.x); +``` + +Einige dieser Formeln haben wir auch am Anfang dieses Kapitels genutzt, als es darum ging, Kreise zu zeichnen. Wir berechneten die Entfernung zum Kreismittelpunkt mit Hilfe der [```length()```](../glossary/?search=length)-Funktion. Jetzt, wo wir Distanzfelder kennengelernt haben, öffnet sich uns ein weiterer Weg zum Zeichnen komplexer Formen mithilfe von Polarkoordinaten. + +Diese Technik unterliegt gewissen Beschränkungen, ist dafür aber sehr simpel und leistungsfähig. Sie beruht darauf, den Radius eines Kreises in Abhängigkeit des jeweiligen Winkels zu verändern, um unterschiedliche Formen zu erschaffen. Wie genau läuft diese Modulierung ab? Nun, Du hast es vielleicht schon erraten: Mit formgebenden Funktionen. + +Unten findest Du verschiedene Funktionen jeweils zwei Mal: einmal als Verlaufskurve in einem kartesischen Koordinatensystem und dann als Shader-Programmcode in einem polaren Koordinatensystem. Dort stehen die verschiedenen formgebenden Funktionen in den *Programmzeilen 21 bis 25*. Entferne nun Schritt für Schritt die Kommentarzeilen und vergleiche den jeweiligen Funktionsgraphen im kartesischen Koordinatensystem mit seinem Äquivalent beim Zeichnen innerhalb eines Polarkoordinatensystem mit GLSL. + +
+ +
+ +Versuche doch einmal: + +* Diese Formen zu animieren. + +* Verschiedene formgebende Funktionen zu kombinieren, um Löcher in die Formen zu „stanzen“ und dadurch Blumen, Schneeflocken oder Zahnräder entstehen zu lassen. + +* Nutze die ```plot()```-Funktion aus dem Kapitel über formgebende Funktionen, um nur die Kontur der jeweiligen Form zeichnen zu lassen. + +### Und nun alles zusammen + +Wir haben gelernt, den Radius einer Kreisform mit Hilfe der [```atan()```](../glossary/?search=atan)-Funktion in Abhängigkeit des Winkels für das Zeichnen unterschiedlicher Formen zu nutzen. Nun können wir ```atan()``` auch mit Distanzfeldern einsetzen, um ganz unterschiedliche Effekte zu erzielen. + +Unser Trick nutzt die gegebene Anzahl der Seiten eines Polygons, um das benötigte Distanzfeld mit Hilfe von Polarkoordinaten zu erzeugen. Schau Dir dazu auch den [folgenden Programmcode](http://thndl.com/square-shaped-shaders.html) von [Andrew Baldwin](https://twitter.com/baldand) an. + +
+ +* Nutze das obige Programmbeispiel, um eine Funktion zu programmieren, die als Eingabe die Anzahl und Position der Ecken einer gewünschten Form erhält und als Ergebnis den Wert für das Distanzfeld liefert. + +* Mische verschiedene Distanzfelder miteinander, indem Du die Funktionen [```min()```](../glossary/?search=min) und [```max()```](../glossary/?search=max) nutzt. + +* Wähle ein geometrisches Logo, das Du mit Hilfe von Distanzfeldern replizierst. + +Herzlichen Glückwunsch! Du hast Dich durch schwieriges Fahrwasser gekämpft. Nimm eine kleine Pause, damit sich das Erlernte setzen kann. Das Zeichnen komplexer Formen im Land der Shader ist wahrlich nicht ganz trivial, das kann durchaus ein wenig erschöpfen. + +Da Du nun weißt, wie man unterschiedliche Formen zeichnet, kommen Dir bestimmt viele interessante Ideen in den Sinn. In den folgenden Kapiteln lernen wir, wie man Formen verschieben, skalieren und rotieren kann. Das wird Dir ermöglichen, komplexe Kompositionen zu erstellen. diff --git a/07/README-it.md b/07/README-it.md index 9a778c3..74ecd2d 100644 --- a/07/README-it.md +++ b/07/README-it.md @@ -1,230 +1,230 @@ -![Alice Hubbard, Providence, United States, ca. 1892. Photo: Zindman/Freemont.](froebel.jpg) - -## Figure - -Finalmente! Abbiamo costruito e allenato le nostre abilità per questo momento! Avete imparato la maggior parte delle basi, dei tipi e delle funzioni in GLSL. Vi siete esercitati continuamente sulle equazioni di forma. Ora è arrivato il momento di collegare tutti gli elementi. Siete all’altezza di questa sfida! In questo capitolo imparerete a disegnare forme semplici con una procedura in parallelo. - -### Rettangolo - -Immaginate di avere una carta millimetrata, come quelle che si usano per le lezioni di matematica, e che il nostro compito sia quello di disegnare un quadrato. Le dimensioni del foglio sono 10x10 e il quadrato dovrebbe essere 8x8. Cosa fareste? - -![](grid_paper.jpg) - -Colorereste tutto tranne la prima e l’ultima riga e la prima e l’ultima colonna, giusto? - -Come si collega ciò agli shaders? Ogni piccolo quadrato della vostra carta millimetrata è un thread (un pixel). Ogni piccolo quadretto conosce la propria posizione, come per le coordinate di una scacchiera. Nei capitoli precedenti abbiamo associato *x* e *y* ai canali di colore *rosso* e *verde*, e abbiamo imparato come usare il limitato spazio bidimensionale tra 0.0 e 1.0. Come possiamo utilizzare tutto questo per disegnare un quadrato centrato nel mezzo del nostro canvas? - -Iniziamo facendo uno pseudocodice che usi la dichiarazione ```if``` sul campo dello spazio. I principi per fare ciò sono straordinariamente simili a come immaginiamo lo scenario della carta millimetrata. - -```glsl - if ( (X più grande di 1) AND (Y più grande di 1) ) - colora di bianco - else - colora di nero -``` - -Ora che abbiamo un’idea più chiara di come funziona, sostituiamo la dichiarazione ```if``` con [```step()```](../glossary/?search=step), e invece di usare 10x10, usiamo i valori normalizzati tra 0.0 e 1.0. - -```glsl -uniform vec2 u_resolution; - -void main(){ - vec2 st = gl_FragCoord.xy/u_resolution.xy; - vec3 color = vec3(0.0); - - // per ogni valore restituirà 1.0 (bianco) o 0.0 (nero). - float left = step(0.1,st.x); // Simile a ( X più grande di 0.1 ) - float bottom = step(0.1,st.y); // Simile a ( Y più grande di 0.1 ) - - // La moltiplicazione di left*bottom sarà simile alla porta logica AND. - color = vec3( left * bottom ); - - gl_FragColor = vec4(color,1.0); -} -``` - -La funzione [```step()```](../glossary/?search=step) trasformerà ogni pixel al di sotto di 0.1 in nero (```vec3(0.0)```) e il resto in bianco (```vec3(1.0)```). La moltiplicazione tra left e bottom funziona come l’operazione logica AND, dove entrambi devono essere tra 1.0 per tornare a 1.0. Questo traccia due linee nere, una alla base e l’altra sul lato sinistro del canvas. - -![](rect-01.jpg) - -Nel codice precedente abbiamo ripetuto la struttura per ciascun asse (sinistra e base). Possiamo risparmiare alcune linee di codice passando due valori, invece di uno, direttamente a [```step()```](../glossary/?search=step) Ecco com’è: - -```glsl - vec2 borders = step(vec2(0.1),st); - float pct = borders.x * borders.y; -``` - -Fino ad ora abbiamo disegnato solamente due bordi (base-sinistra) del nostro rettangolo. Facciamo gli altri due (alto-destra). Osserva il seguente codice: - -
- -Togliete il commento alle righe 21-22 e osservate come invertiamo le coordinate ```st``` e ripetiamo la stessa funzione [```step()```](../glossary/?search=step). In questo modo il ```vec2(0.0,0.0)``` sarà nell’angolo in alto a destra. Questo è l’equivalente digitale del capovolgimento della pagina e della ripetizione della procedura precedente. - -![](rect-02.jpg) - -Osservate che alla *riga 18 e alla riga 22* ogni lato è stato moltiplicato insieme. Questo equivale a scrivere: - -```glsl - vec2 bl = step(vec2(0.1),st); // sotto-sinistra - vec2 tr = step(vec2(0.1),1.0-st); // sopra-destra - color = vec3(bl.x * bl.y * tr.x * tr.y); -``` - -Interessante, vero? Questa tecnica si basa tutta sull’uso di [```step()```](../glossary/?search=step), della moltiplicazione per le operazioni logiche e il capovolgimento delle coordinate. - -Prima di proseguire, provate i seguenti esercizi: - -* Cambiate le misure e le proporzioni del rettangolo. - -* Provate con lo stesso codice ma usando [```smoothstep()```](../glossary/?search=smoothstep) al posto di [```step()```](../glossary/?search=step). Notate che cambiando valori, potete passare da margini indistinti a lati eleganti e lisci. - -* Fate un’altra implementazione che usi [```floor()```](../glossary/?search=floor). - -* Scegliete l’implementazione che preferite e create una sua funzione che potrete riusare in futuro. Rendete la vostra funzione flessibile ed efficiente. - -* Create un’altra funzione che semplicemente tracci il contorno di un rettangolo. - -* Come pensate di poter importare e spostare diversi rettangoli sullo stesso canvas? Se immaginate come, dimostrate le vostre capacità costruendo una composizione di rettangoli e colori che ricordi il dipinto di [Piet Mondrian](https://it.wikipedia.org/wiki/Piet_Mondrian). - -![Piet Mondrian - Tableau (1921)](mondrian.jpg) - -### Circonferenze - -Disegnare quadrati e rettangoli su carta millimetrata con coordinate cartesiane è semplice, ma le circonferenze richiedono un approccio diverso, specialmente per il fatto che abbiamo bisogno di un algoritmo “per-pixel”. Una soluzione è riassegnare le coordinate spaziali, in modo tale da poter usare la funzione [```step()```](../glossary/?search=step) per disegnare una circonferenza. - -Come? Iniziamo tornando indietro alla lezione di matematica e al foglio a quadretti, sul quale abbiamo aperto il compasso con il raggio della circonferenza, abbiamo premuto l’ago del compasso al centro della circonferenza e tracciato il perimetro della circonferenza con una semplice rotazione. - -![](compass.jpg) - -Tradurre ciò in un shader, dove ogni quadrato sul foglio a quadretti è un pixel, implica *chiedere* ad ogni pixel (o thread) se si trova all’interno dell’area della circonferenza. Lo facciamo calcolando la distanza tra il pixel e il centro della circonferenza. - -![](circle.jpg) - -Esistono diversi modi per calcolare questa distanza. Il più semplice utilizza la funzione [```distance()```](../glossary/?search=distance), che al suo interno calcola la funzione [```length()```](../glossary/?search=length) della differenza tra due punti ( nel nostro caso le coordinate del pixel e il centro del canvas). La funzione ```length()``` non è altro che una scorciatoia dell’[equazione dell’ipotenusa](https://it.wikipedia.org/wiki/Ipotenusa), che usa al suo interno la radice quadrata (([```sqrt()```](../glossary/?search=sqrt))). - -![](hypotenuse.png) - -Potete usare [```distance()```](../glossary/?search=distance), [```length()```](../glossary/?search=length) o [```sqrt()```](../glossary/?search=sqrt) per calcolare la distanza dal centro del canvas. Il codice seguente contiene queste tre funzioni e il fatto non sorprendente è che ciascuna restituisce esattamente lo stesso risultato. - -* Commentate e togliete il commento alle righe per provare i diversi modi di ottenere il medesimo risultato. - -
- -Nell’esempio precedente abbiamo mappato la distanza dal centro del canvas con la luminosità del colore del pixel. Più un pixel è vicino al centro, minore ( più scuro) è il suo valore. Notate che i valori non diventano troppo alti perché la massima distanza dal centro ( ```vec2(0.5, 0.5)``` ) va a malapena oltre 0.5. Osservate attentamente questa mappa e pensate: - -* Cosa potete dedurre da essa? - -* Come possiamo usarla per tracciare una circonferenza? - -* Modificate il codice qui sopra per far sì che l’intero gradiente circolare sia contenuto nel canvas. - -### Campo di distanza - -Possiamo anche immaginare l’esempio soprastante come una carta delle altitudini, dove più scuro implica più alto. Il gradiente ci mostra qualcosa di simile al modello creato da un cono. Immaginate di trovarvi sulla cima di un cono. La distanza orizzontale dal bordo del cono è 0.5. Questa sarà costante in ogni direzione. Scegliendo dove “tagliare” il cono, otterrete una superficie circolare più grande o più piccola. - -![](distance-field.jpg) - -In sostanza, per creare delle forme, stiamo utilizzando una reinterpretazione dello spazio basata sulla distanza dal centro. Questa tecnica è conosciuta come “campo di distanza” (distance field) ed è usata in modi diversi, dai profili dei caratteri (font) alla grafica 3D. - -Esercitatevi con i seguenti esercizi: - -* Usate [```step()```](../glossary/?search=step) per trasformare in bianco tutto ciò che è al di sopra di 0.5 e al di sotto di 0.0. - -* Invertite i colori dello sfondo e del primo piano. - -* Usate [```smoothstep()```](../glossary/?search=smoothstep), provate con valori diversi per ottenere dei margini lisci sulla vostra circonferenza. - -* Una volta che siete soddisfatti con un’implementazione, createne una funzione, che potrete riutilizzare in futuro. - -* Aggiungete il colore alla circonferenza. - -* Riuscite a creare animazioni sulla circonferenza per farla crescere e rimpicciolire, simulando il battito del cuore? (Potete trarre ispirazione dalle animazioni nel capitolo precedente). - -* Che ne dite di spostare questa circonferenza? Riuscite a spostarla e a mettere altre circonferenze su uno stesso canvas? - -* Cosa succede se combinate i campi di distanza con diverse operazioni e funzioni? - -```glsl -pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6)); -pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6)); -pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6))); -pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6))); -pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6))); -``` -* Create tre composizioni usando questa tecnica. Se poi riuscite ad animarle, ancora meglio! - -#### Per la vostra cassetta degli attrezzi - -In termini di potenza computazionale, la funzione [```sqrt()```](../glossary/?search=sqrt), e le altre funzioni che dipendono da essa, possono essere dispendiose. Ecco un altro modo per creare un campo di distanza circolare, basato sulla funzione [```dot()```](../glossary/?search=dot). - -
- -### Proprietà utili dei campi di distanza - -![Zen garden](zen-garden.jpg) - -I campi di distanza possono essere usati per disegnare quasi qualsiasi cosa. Ovviamente, più una forma è complessa, più sarà complicata la sua equazione, ma una volta che avete la formula per creare un campo di distanza di una certa forma è molto facile combinare e/o applicare degli effetti ad essa, come lati lisci e profili multipli. Per questo motivo, i campi di distanza hanno molto successo nella rappresentazione dei caratteri (font), come [Mapbox GL Labels](https://www.mapbox.com/blog/text-signed-distance-fields/), [Matt DesLauriers](https://twitter.com/mattdesl) [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu) e come è descritto nel [Capitolo 7 del libro "iPhone 3D Programming", O’Reilly](http://chimera.labs.oreilly.com/books/1234000001814/ch07.html#ch07_id36000921) - -Osservate il codice seguente. - -
- -Iniziamo spostando il sistema di coordinate al centro e riducendolo a metà per riassegnare i valori di posizione tra -1 e 1. Alla *riga 24* stiamo vedendo i valori del campo di distanza usando una funzione [```fract()```](../glossary/?search=fract), semplificando la visualizzazione dei motivi che essi creano. Il motivo del campo di distanza si continua a ripetere come i cerchi in un giardino zen. - -Osserviamo la formula del campo di distanza alla *riga 19*. Lì stiamo calcolando la distanza dalla posizione su ```(.3,.3)``` o ```vec3(.3)``` in tutti e quattro i quadranti ( questo è ciò che fa [```abs()```](../glossary/?search=abs) qui) . - -Se togliete il commento alla *riga 20*, noterete che stiamo collegando le distanze a questi quattro punti usando il [```min()```](../glossary/?search=min) a zero. Il risultato produce un nuovo motivo interessante. - -Ora provate a togliere il commento alla *riga 21*; stiamo facendo la stessa cosa ma usando la funzione [```max()```](../glossary/?search=max). Il risultato è un rettangolo con gli angoli arrotondati. Notate come gli anelli del campo di distanza diventano più lisci mano a mano che si allontanano dal centro. - -Terminate togliendo il commento una ad una alle *righe da 27 a 29*, per capire i diversi usi dei motivi di un campo di distanza. - -### Forme polari - -![Robert Mangold - Untitled (2008)](mangold.jpg) - -Nel capitolo sul colore, abbiamo assegnato alle coordinate cartesiane le coordinate polari, calcolando il *raggio* e gli *angoli* di ciascun pixel con la seguente formula: - -```glsl - vec2 pos = vec2(0.5)-st; - float r = length(pos)*2.0; - float a = atan(pos.y,pos.x); -``` - -Usiamo parte di questa formula all’inizio del capitolo per tracciare una circonferenza. Abbiamo calcolato la distanza dal centro usando [```length()```](../glossary/?search=length). Ora che conosciamo i campi di distanza, possiamo imparare un altro modo per disegnare le forme usando le coordinate polari. - -Questa tecnica è un po’ restrittiva ma molto semplice. Consiste nel cambiare il raggio di una circonferenza in funzione dell’angolo per realizzare forme diverse. Come funziona la modulazione? Esatto, usando le funzioni di forma! - -Qui sotto troverete le medesime funzioni sul diagramma cartesiano e in un esempio shader nelle coordinate polari ( tra le *righe 21 e 25*). Togliete il commento alle funzioni una alla volta, facendo attenzione alla relazione tra un sistema di coordinate e l’altro. - -
- -
- -Provate a: - -* Animare queste forme. -* Combinare diverse funzioni di forma per fare dei *buchi* nella forma e creare fiori, fiocchi di neve e degli ingranaggi. -* Usare la funzione ```plot()``` che abbiamo usato nel capitolo sulle *funzioni di forma*, per disegnare solamente la sagoma. - -### Unire i poteri - -Ora che abbiamo imparato come modulare il raggio di una circonferenza in relazione all’angolo, usando la funzione [```atan()```](../glossary/?search=atan) per disegnare diverse forme, possiamo imparare come usare ```atan()``` con i campi di distanza e applicare tutti i trucchi e gli effetti possibili con i campi di distanza. - -Il nostro trucco userà il numero di lati di un poligono per costruire il campo di distanza, usando le coordinate polari. Controllate [il seguente codice](http://thndl.com/square-shaped-shaders.html) di [Andrew Baldwin](https://twitter.com/baldand). - -
- -* Usando quest’esempio, create una funzione che inserisca la posizione e il numero degli angoli di una forma desiderata e restituisca il valore di un campo di distanza. - -* Mescolate i campi di distanza usando [```min()```](../glossary/?search=min) e [```max()```](../glossary/?search=max). - -* Scegliete un logo geometrico da riprodurre usando i campi di distanza. - -Congratulazioni! Avete affrontato la parte più complicata! Fate una pausa per poter assimilare questi concetti: disegnare delle semplici forme con Processing è facile, ma qui no. Nella “terra degli Shader”, disegnare le forme è contorto e può essere faticoso adattarsi al nuovo paradigma di codificazione. - -Ora che sapete come disegnare le forme, sono sicuro che vi verranno in mente nuove idee. Nel capitolo successivo imparerete a spostare, ruotare e ridimensionare le forme. Questo vi permetterà di fare delle composizioni! \ No newline at end of file +![Alice Hubbard, Providence, United States, ca. 1892. Photo: Zindman/Freemont.](froebel.jpg) + +## Figure + +Finalmente! Abbiamo costruito e allenato le nostre abilità per questo momento! Avete imparato la maggior parte delle basi, dei tipi e delle funzioni in GLSL. Vi siete esercitati continuamente sulle equazioni di forma. Ora è arrivato il momento di collegare tutti gli elementi. Siete all’altezza di questa sfida! In questo capitolo imparerete a disegnare forme semplici con una procedura in parallelo. + +### Rettangolo + +Immaginate di avere una carta millimetrata, come quelle che si usano per le lezioni di matematica, e che il nostro compito sia quello di disegnare un quadrato. Le dimensioni del foglio sono 10x10 e il quadrato dovrebbe essere 8x8. Cosa fareste? + +![](grid_paper.jpg) + +Colorereste tutto tranne la prima e l’ultima riga e la prima e l’ultima colonna, giusto? + +Come si collega ciò agli shaders? Ogni piccolo quadrato della vostra carta millimetrata è un thread (un pixel). Ogni piccolo quadretto conosce la propria posizione, come per le coordinate di una scacchiera. Nei capitoli precedenti abbiamo associato *x* e *y* ai canali di colore *rosso* e *verde*, e abbiamo imparato come usare il limitato spazio bidimensionale tra 0.0 e 1.0. Come possiamo utilizzare tutto questo per disegnare un quadrato centrato nel mezzo del nostro canvas? + +Iniziamo facendo uno pseudocodice che usi la dichiarazione ```if``` sul campo dello spazio. I principi per fare ciò sono straordinariamente simili a come immaginiamo lo scenario della carta millimetrata. + +```glsl + if ( (X più grande di 1) AND (Y più grande di 1) ) + colora di bianco + else + colora di nero +``` + +Ora che abbiamo un’idea più chiara di come funziona, sostituiamo la dichiarazione ```if``` con [```step()```](../glossary/?search=step), e invece di usare 10x10, usiamo i valori normalizzati tra 0.0 e 1.0. + +```glsl +uniform vec2 u_resolution; + +void main(){ + vec2 st = gl_FragCoord.xy/u_resolution.xy; + vec3 color = vec3(0.0); + + // per ogni valore restituirà 1.0 (bianco) o 0.0 (nero). + float left = step(0.1,st.x); // Simile a ( X più grande di 0.1 ) + float bottom = step(0.1,st.y); // Simile a ( Y più grande di 0.1 ) + + // La moltiplicazione di left*bottom sarà simile alla porta logica AND. + color = vec3( left * bottom ); + + gl_FragColor = vec4(color,1.0); +} +``` + +La funzione [```step()```](../glossary/?search=step) trasformerà ogni pixel al di sotto di 0.1 in nero (```vec3(0.0)```) e il resto in bianco (```vec3(1.0)```). La moltiplicazione tra left e bottom funziona come l’operazione logica AND, dove entrambi devono essere tra 1.0 per tornare a 1.0. Questo traccia due linee nere, una alla base e l’altra sul lato sinistro del canvas. + +![](rect-01.jpg) + +Nel codice precedente abbiamo ripetuto la struttura per ciascun asse (sinistra e base). Possiamo risparmiare alcune linee di codice passando due valori, invece di uno, direttamente a [```step()```](../glossary/?search=step) Ecco com’è: + +```glsl + vec2 borders = step(vec2(0.1),st); + float pct = borders.x * borders.y; +``` + +Fino ad ora abbiamo disegnato solamente due bordi (base-sinistra) del nostro rettangolo. Facciamo gli altri due (alto-destra). Osserva il seguente codice: + +
+ +Togliete il commento alle righe 21-22 e osservate come invertiamo le coordinate ```st``` e ripetiamo la stessa funzione [```step()```](../glossary/?search=step). In questo modo il ```vec2(0.0,0.0)``` sarà nell’angolo in alto a destra. Questo è l’equivalente digitale del capovolgimento della pagina e della ripetizione della procedura precedente. + +![](rect-02.jpg) + +Osservate che alla *riga 18 e alla riga 22* ogni lato è stato moltiplicato insieme. Questo equivale a scrivere: + +```glsl + vec2 bl = step(vec2(0.1),st); // sotto-sinistra + vec2 tr = step(vec2(0.1),1.0-st); // sopra-destra + color = vec3(bl.x * bl.y * tr.x * tr.y); +``` + +Interessante, vero? Questa tecnica si basa tutta sull’uso di [```step()```](../glossary/?search=step), della moltiplicazione per le operazioni logiche e il capovolgimento delle coordinate. + +Prima di proseguire, provate i seguenti esercizi: + +* Cambiate le misure e le proporzioni del rettangolo. + +* Provate con lo stesso codice ma usando [```smoothstep()```](../glossary/?search=smoothstep) al posto di [```step()```](../glossary/?search=step). Notate che cambiando valori, potete passare da margini indistinti a lati eleganti e lisci. + +* Fate un’altra implementazione che usi [```floor()```](../glossary/?search=floor). + +* Scegliete l’implementazione che preferite e create una sua funzione che potrete riusare in futuro. Rendete la vostra funzione flessibile ed efficiente. + +* Create un’altra funzione che semplicemente tracci il contorno di un rettangolo. + +* Come pensate di poter importare e spostare diversi rettangoli sullo stesso canvas? Se immaginate come, dimostrate le vostre capacità costruendo una composizione di rettangoli e colori che ricordi il dipinto di [Piet Mondrian](https://it.wikipedia.org/wiki/Piet_Mondrian). + +![Piet Mondrian - Tableau (1921)](mondrian.jpg) + +### Circonferenze + +Disegnare quadrati e rettangoli su carta millimetrata con coordinate cartesiane è semplice, ma le circonferenze richiedono un approccio diverso, specialmente per il fatto che abbiamo bisogno di un algoritmo “per-pixel”. Una soluzione è riassegnare le coordinate spaziali, in modo tale da poter usare la funzione [```step()```](../glossary/?search=step) per disegnare una circonferenza. + +Come? Iniziamo tornando indietro alla lezione di matematica e al foglio a quadretti, sul quale abbiamo aperto il compasso con il raggio della circonferenza, abbiamo premuto l’ago del compasso al centro della circonferenza e tracciato il perimetro della circonferenza con una semplice rotazione. + +![](compass.jpg) + +Tradurre ciò in un shader, dove ogni quadrato sul foglio a quadretti è un pixel, implica *chiedere* ad ogni pixel (o thread) se si trova all’interno dell’area della circonferenza. Lo facciamo calcolando la distanza tra il pixel e il centro della circonferenza. + +![](circle.jpg) + +Esistono diversi modi per calcolare questa distanza. Il più semplice utilizza la funzione [```distance()```](../glossary/?search=distance), che al suo interno calcola la funzione [```length()```](../glossary/?search=length) della differenza tra due punti ( nel nostro caso le coordinate del pixel e il centro del canvas). La funzione ```length()``` non è altro che una scorciatoia dell’[equazione dell’ipotenusa](https://it.wikipedia.org/wiki/Ipotenusa), che usa al suo interno la radice quadrata (([```sqrt()```](../glossary/?search=sqrt))). + +![](hypotenuse.png) + +Potete usare [```distance()```](../glossary/?search=distance), [```length()```](../glossary/?search=length) o [```sqrt()```](../glossary/?search=sqrt) per calcolare la distanza dal centro del canvas. Il codice seguente contiene queste tre funzioni e il fatto non sorprendente è che ciascuna restituisce esattamente lo stesso risultato. + +* Commentate e togliete il commento alle righe per provare i diversi modi di ottenere il medesimo risultato. + +
+ +Nell’esempio precedente abbiamo mappato la distanza dal centro del canvas con la luminosità del colore del pixel. Più un pixel è vicino al centro, minore ( più scuro) è il suo valore. Notate che i valori non diventano troppo alti perché la massima distanza dal centro ( ```vec2(0.5, 0.5)``` ) va a malapena oltre 0.5. Osservate attentamente questa mappa e pensate: + +* Cosa potete dedurre da essa? + +* Come possiamo usarla per tracciare una circonferenza? + +* Modificate il codice qui sopra per far sì che l’intero gradiente circolare sia contenuto nel canvas. + +### Campo di distanza + +Possiamo anche immaginare l’esempio soprastante come una carta delle altitudini, dove più scuro implica più alto. Il gradiente ci mostra qualcosa di simile al modello creato da un cono. Immaginate di trovarvi sulla cima di un cono. La distanza orizzontale dal bordo del cono è 0.5. Questa sarà costante in ogni direzione. Scegliendo dove “tagliare” il cono, otterrete una superficie circolare più grande o più piccola. + +![](distance-field.jpg) + +In sostanza, per creare delle forme, stiamo utilizzando una reinterpretazione dello spazio basata sulla distanza dal centro. Questa tecnica è conosciuta come “campo di distanza” (distance field) ed è usata in modi diversi, dai profili dei caratteri (font) alla grafica 3D. + +Esercitatevi con i seguenti esercizi: + +* Usate [```step()```](../glossary/?search=step) per trasformare in bianco tutto ciò che è al di sopra di 0.5 e al di sotto di 0.0. + +* Invertite i colori dello sfondo e del primo piano. + +* Usate [```smoothstep()```](../glossary/?search=smoothstep), provate con valori diversi per ottenere dei margini lisci sulla vostra circonferenza. + +* Una volta che siete soddisfatti con un’implementazione, createne una funzione, che potrete riutilizzare in futuro. + +* Aggiungete il colore alla circonferenza. + +* Riuscite a creare animazioni sulla circonferenza per farla crescere e rimpicciolire, simulando il battito del cuore? (Potete trarre ispirazione dalle animazioni nel capitolo precedente). + +* Che ne dite di spostare questa circonferenza? Riuscite a spostarla e a mettere altre circonferenze su uno stesso canvas? + +* Cosa succede se combinate i campi di distanza con diverse operazioni e funzioni? + +```glsl +pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6)); +pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6)); +pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +``` +* Create tre composizioni usando questa tecnica. Se poi riuscite ad animarle, ancora meglio! + +#### Per la vostra cassetta degli attrezzi + +In termini di potenza computazionale, la funzione [```sqrt()```](../glossary/?search=sqrt), e le altre funzioni che dipendono da essa, possono essere dispendiose. Ecco un altro modo per creare un campo di distanza circolare, basato sulla funzione [```dot()```](../glossary/?search=dot). + +
+ +### Proprietà utili dei campi di distanza + +![Zen garden](zen-garden.jpg) + +I campi di distanza possono essere usati per disegnare quasi qualsiasi cosa. Ovviamente, più una forma è complessa, più sarà complicata la sua equazione, ma una volta che avete la formula per creare un campo di distanza di una certa forma è molto facile combinare e/o applicare degli effetti ad essa, come lati lisci e profili multipli. Per questo motivo, i campi di distanza hanno molto successo nella rappresentazione dei caratteri (font), come [Mapbox GL Labels](https://www.mapbox.com/blog/text-signed-distance-fields/), [Matt DesLauriers](https://twitter.com/mattdesl) [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu) e come è descritto nel [Capitolo 7 del libro "iPhone 3D Programming", O’Reilly](http://chimera.labs.oreilly.com/books/1234000001814/ch07.html#ch07_id36000921) + +Osservate il codice seguente. + +
+ +Iniziamo spostando il sistema di coordinate al centro e riducendolo a metà per riassegnare i valori di posizione tra -1 e 1. Alla *riga 24* stiamo vedendo i valori del campo di distanza usando una funzione [```fract()```](../glossary/?search=fract), semplificando la visualizzazione dei motivi che essi creano. Il motivo del campo di distanza si continua a ripetere come i cerchi in un giardino zen. + +Osserviamo la formula del campo di distanza alla *riga 19*. Lì stiamo calcolando la distanza dalla posizione su ```(.3,.3)``` o ```vec3(.3)``` in tutti e quattro i quadranti ( questo è ciò che fa [```abs()```](../glossary/?search=abs) qui) . + +Se togliete il commento alla *riga 20*, noterete che stiamo collegando le distanze a questi quattro punti usando il [```min()```](../glossary/?search=min) a zero. Il risultato produce un nuovo motivo interessante. + +Ora provate a togliere il commento alla *riga 21*; stiamo facendo la stessa cosa ma usando la funzione [```max()```](../glossary/?search=max). Il risultato è un rettangolo con gli angoli arrotondati. Notate come gli anelli del campo di distanza diventano più lisci mano a mano che si allontanano dal centro. + +Terminate togliendo il commento una ad una alle *righe da 27 a 29*, per capire i diversi usi dei motivi di un campo di distanza. + +### Forme polari + +![Robert Mangold - Untitled (2008)](mangold.jpg) + +Nel capitolo sul colore, abbiamo assegnato alle coordinate cartesiane le coordinate polari, calcolando il *raggio* e gli *angoli* di ciascun pixel con la seguente formula: + +```glsl + vec2 pos = vec2(0.5)-st; + float r = length(pos)*2.0; + float a = atan(pos.y,pos.x); +``` + +Usiamo parte di questa formula all’inizio del capitolo per tracciare una circonferenza. Abbiamo calcolato la distanza dal centro usando [```length()```](../glossary/?search=length). Ora che conosciamo i campi di distanza, possiamo imparare un altro modo per disegnare le forme usando le coordinate polari. + +Questa tecnica è un po’ restrittiva ma molto semplice. Consiste nel cambiare il raggio di una circonferenza in funzione dell’angolo per realizzare forme diverse. Come funziona la modulazione? Esatto, usando le funzioni di forma! + +Qui sotto troverete le medesime funzioni sul diagramma cartesiano e in un esempio shader nelle coordinate polari ( tra le *righe 21 e 25*). Togliete il commento alle funzioni una alla volta, facendo attenzione alla relazione tra un sistema di coordinate e l’altro. + +
+ +
+ +Provate a: + +* Animare queste forme. +* Combinare diverse funzioni di forma per fare dei *buchi* nella forma e creare fiori, fiocchi di neve e degli ingranaggi. +* Usare la funzione ```plot()``` che abbiamo usato nel capitolo sulle *funzioni di forma*, per disegnare solamente la sagoma. + +### Unire i poteri + +Ora che abbiamo imparato come modulare il raggio di una circonferenza in relazione all’angolo, usando la funzione [```atan()```](../glossary/?search=atan) per disegnare diverse forme, possiamo imparare come usare ```atan()``` con i campi di distanza e applicare tutti i trucchi e gli effetti possibili con i campi di distanza. + +Il nostro trucco userà il numero di lati di un poligono per costruire il campo di distanza, usando le coordinate polari. Controllate [il seguente codice](http://thndl.com/square-shaped-shaders.html) di [Andrew Baldwin](https://twitter.com/baldand). + +
+ +* Usando quest’esempio, create una funzione che inserisca la posizione e il numero degli angoli di una forma desiderata e restituisca il valore di un campo di distanza. + +* Mescolate i campi di distanza usando [```min()```](../glossary/?search=min) e [```max()```](../glossary/?search=max). + +* Scegliete un logo geometrico da riprodurre usando i campi di distanza. + +Congratulazioni! Avete affrontato la parte più complicata! Fate una pausa per poter assimilare questi concetti: disegnare delle semplici forme con Processing è facile, ma qui no. Nella “terra degli Shader”, disegnare le forme è contorto e può essere faticoso adattarsi al nuovo paradigma di codificazione. + +Ora che sapete come disegnare le forme, sono sicuro che vi verranno in mente nuove idee. Nel capitolo successivo imparerete a spostare, ruotare e ridimensionare le forme. Questo vi permetterà di fare delle composizioni! diff --git a/07/README.md b/07/README.md index 48d8fca..ecf2824 100644 --- a/07/README.md +++ b/07/README.md @@ -2,7 +2,7 @@ ## Shapes -Finally! We have been building skills for this moment! You have learned most of the GLSL foundations, types and functions. You have practiced your shaping equations over and over. Now is the time to put it all together. You are up for this challenge! In this chapter you'll learn how to draw simple shapes in a parallel procedural way. +Finally! We have been building skills for this moment! You have learned most of the GLSL foundations, types and functions. You have practiced your shaping equations over and over. Now is the time to put it all together. You are up for this challenge! In this chapter you'll learn how to draw simple shapes in a parallel procedural way. ### Rectangle @@ -10,7 +10,7 @@ Imagine we have grid paper like we used in math classes and our homework is to d ![](grid_paper.jpg) -You'd paint everything except the first and last rows and the first and last column, right? +You'd paint everything except the first and last rows and the first and last column, right? How does this relate to shaders? Each little square of our grid paper is a thread (a pixel). Each little square knows its position, like the coordinates of a chess board. In previous chapters we mapped *x* and *y* to the *red* and *green* color channels, and we learned how to use the narrow two dimensional territory between 0.0 and 1.0. How can we use this to draw a centered square in the middle of our billboard? @@ -19,7 +19,7 @@ Let's start by sketching pseudocode that uses ```if``` statements over the spati ```glsl if ( (X GREATER THAN 1) AND (Y GREATER THAN 1) ) paint white - else + else paint black ``` @@ -31,13 +31,13 @@ uniform vec2 u_resolution; void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + // Each result will return 1.0 (white) or 0.0 (black). float left = step(0.1,st.x); // Similar to ( X greater than 0.1 ) float bottom = step(0.1,st.y); // Similar to ( Y greater than 0.1 ) // The multiplication of left*bottom will be similar to the logical AND. - color = vec3( left * bottom ); + color = vec3( left * bottom ); gl_FragColor = vec4(color,1.0); } @@ -50,7 +50,7 @@ The [```step()```](../glossary/?search=step) function will turn every pixel belo In the previous code we repeat the structure for each axis (left and bottom). We can save some lines of code by passing two values directly to [```step()```](../glossary/?search=step) instead of one. That looks like this: ```glsl - vec2 borders = step(vec2(0.1),st); + vec2 borders = step(vec2(0.1),st); float pct = borders.x * borders.y; ``` @@ -58,7 +58,7 @@ So far, we’ve only drawn two borders (bottom-left) of our rectangle. Let's do
-Uncomment *lines 21-22* and see how we invert the ```st``` coordinates and repeat the same [```step()```](../glossary/?search=step) function. That way the ```vec2(0.0,0.0)``` will be in the top right corner. This is the digital equivalent of flipping the page and repeating the previous procedure. +Uncomment *lines 21-22* and see how we invert the ```st``` coordinates and repeat the same [```step()```](../glossary/?search=step) function. That way the ```vec2(0.0,0.0)``` will be in the top right corner. This is the digital equivalent of flipping the page and repeating the previous procedure. ![](rect-02.jpg) @@ -90,13 +90,13 @@ Before going forward, try the following exercises: ### Circles -It's easy to draw squares on grid paper and rectangles on cartesian coordinates, but circles require another approach, especially since we need a "per-pixel" algorithm. One solution is to *re-map* the spatial coordinates so that we can use a [```step()```](../glossary/?search=step) function to draw a circle. +It's easy to draw squares on grid paper and rectangles on cartesian coordinates, but circles require another approach, especially since we need a "per-pixel" algorithm. One solution is to *re-map* the spatial coordinates so that we can use a [```step()```](../glossary/?search=step) function to draw a circle. How? Let's start by going back to math class and the grid paper, where we opened a compass to the radius of a circle, pressed one of the compass points at the center of the circle and then traced the edge of the circle with a simple spin. ![](compass.jpg) -Translating this to a shader where each square on the grid paper is a pixel implies *asking* each pixel (or thread) if it is inside the area of the circle. We do this by computing the distance from the pixel to the center of the circle. +Translating this to a shader where each square on the grid paper is a pixel implies *asking* each pixel (or thread) if it is inside the area of the circle. We do this by computing the distance from the pixel to the center of the circle. ![](circle.jpg) @@ -112,7 +112,7 @@ You can use [```distance()```](../glossary/?search=distance), [```length()```](. In the previous example we map the distance to the center of the billboard to the color brightness of the pixel. The closer a pixel is to the center, the lower (darker) value it has. Notice that the values don't get too high because from the center ( ```vec2(0.5, 0.5)``` ) the maximum distance barely goes over 0.5. Contemplate this map and think: -* What you can infer from it? +* What you can infer from it? * How we can use this to draw a circle? @@ -127,14 +127,14 @@ We can also think of the above example as an altitude map, where darker implies Basically we are using a re-interpretation of the space (based on the distance to the center) to make shapes. This technique is known as a “distance field” and is used in different ways from font outlines to 3D graphics. Try the following exercises: - + * Use [```step()```](../glossary/?search=step) to turn everything above 0.5 to white and everything below to 0.0. * Inverse the colors of the background and foreground. * Using [```smoothstep()```](../glossary/?search=smoothstep), experiment with different values to get nice smooth borders on your circle. -* Once you are happy with an implementation, make a function of it that you can reuse in the future. +* Once you are happy with an implementation, make a function of it that you can reuse in the future. * Add color to the circle. @@ -172,7 +172,7 @@ Take a look at the following code. We start by moving the coordinate system to the center and shrinking it in half in order to remap the position values between -1 and 1. Also on *line 24* we are visualizing the distance field values using a [```fract()```](../glossary/?search=fract) function making it easy to see the pattern they create. The distance field pattern repeats over and over like rings in a Zen garden. -Let’s take a look at the distance field formula on *line 19*. There we are calculating the distance to the position on ```(.3,.3)``` or ```vec3(.3)``` in all four quadrants (that’s what [```abs()```](../glossary/?search=abs) is doing there). +Let’s take a look at the distance field formula on *line 19*. There we are calculating the distance to the position on ```(.3,.3)``` or ```vec3(.3)``` in all four quadrants (that’s what [```abs()```](../glossary/?search=abs) is doing there). If you uncomment *line 20*, you will note that we are combining the distances to these four points using the [```min()```](../glossary/?search=min) to zero. The result produces an interesting new pattern. @@ -192,7 +192,7 @@ In the chapter about color we map the cartesian coordinates to polar coordinates float a = atan(pos.y,pos.x); ``` -We use part of this formula at the beginning of the chapter to draw a circle. We calculated the distance to the center using [```length()```](../glossary/?search=length). Now that we know about distance fields we can learn another way of drawing shapes using polar coordinates. +We use part of this formula at the beginning of the chapter to draw a circle. We calculated the distance to the center using [```length()```](../glossary/?search=length). Now that we know about distance fields we can learn another way of drawing shapes using polar coordinates. This technique is a little restrictive but very simple. It consists of changing the radius of a circle depending on the angle to achieve different shapes. How does the modulation work? Yes, using shaping functions! @@ -216,7 +216,7 @@ Try to: Now that we've learned how to modulate the radius of a circle according to the angle using the [```atan()```](../glossary/?search=atan) to draw different shapes, we can learn how use ```atan()``` with distance fields and apply all the tricks and effects possible with distance fields. -The trick will use the number of edges of a polygon to construct the distance field using polar coordinates. Check out [the following code](http://thndl.com/square-shaped-shaders.html) from [Andrew Baldwin](https://twitter.com/baldand). +The trick will use the number of edges of a polygon to construct the distance field using polar coordinates. Check out [the following code](http://thndl.com/square-shaped-shaders.html) from [Andrew Baldwin](https://twitter.com/baldand).
diff --git a/07/arrow.frag b/07/arrow.frag index 581d4d4..04f1401 100644 --- a/07/arrow.frag +++ b/07/arrow.frag @@ -39,8 +39,8 @@ void main(){ st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(0.0); float d = 0.0; - + d = min(shape(st,3),shape(st+vec2(0.,0.19),4)); gl_FragColor = vec4(vec3(1.0-aastep(.2,d)),1.0); -} \ No newline at end of file +} diff --git a/07/batman.frag b/07/batman.frag index b686166..a2314b1 100644 --- a/07/batman.frag +++ b/07/batman.frag @@ -10,7 +10,7 @@ uniform vec2 u_mouse; uniform float u_time; float plot (float y, float pct){ - return smoothstep( pct-0.01, pct, y) - + return smoothstep( pct-0.01, pct, y) - smoothstep( pct, pct+0.01, y); } @@ -35,4 +35,4 @@ void main(){ gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/07/circle-making.frag b/07/circle-making.frag index c7888bd..921ab06 100644 --- a/07/circle-making.frag +++ b/07/circle-making.frag @@ -16,17 +16,17 @@ void main(){ // a. The DISTANCE from the pixel to the center pct = distance(st,vec2(0.5)); - // b. The LENGTH of the vector - // from the pixel to the center + // b. The LENGTH of the vector + // from the pixel to the center // vec2 toCenter = vec2(0.5)-st; // pct = length(toCenter); - // c. The SQUARE ROOT of the vector - // from the pixel to the center + // c. The SQUARE ROOT of the vector + // from the pixel to the center // vec2 tC = vec2(0.5)-st; // pct = sqrt(tC.x*tC.x+tC.y*tC.y); vec3 color = vec3(pct); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/07/circle.frag b/07/circle.frag index d9b7b7e..63f5629 100644 --- a/07/circle.frag +++ b/07/circle.frag @@ -18,8 +18,8 @@ float circle(in vec2 _st, in float _radius){ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; - + vec3 color = vec3(circle(st,0.9)); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/07/cross.frag b/07/cross.frag index a42d89a..080cf09 100644 --- a/07/cross.frag +++ b/07/cross.frag @@ -21,7 +21,7 @@ float box(in vec2 st, in vec2 size){ } float cross(in vec2 st, float size){ - return box(st, vec2(size,size/4.)) + + return box(st, vec2(size,size/4.)) + box(st, vec2(size/4.,size)); } @@ -29,4 +29,4 @@ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; gl_FragColor = vec4( vec3( cross(st,0.4) ) ,1.0); -} \ No newline at end of file +} diff --git a/07/index.php b/07/index.php index 491c360..15582de 100644 --- a/07/index.php +++ b/07/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/07/line.frag b/07/line.frag index f9534c1..cf176ac 100644 --- a/07/line.frag +++ b/07/line.frag @@ -6,10 +6,10 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -float line( vec2 _st, - vec2 _p1, vec2 _p2, +float line( vec2 _st, + vec2 _p1, vec2 _p2, float _width, float _spread){ - + _width = 1.0 / _width; vec2 p2p1 = _p1 - _p2; vec2 p1p2 = -(p2p1); @@ -22,8 +22,8 @@ float line( vec2 _st, float pr2 = dot(p1p2, p1p); if(pr1 > 0.0 && pr2 > 0.0) { - return pow(1.0 / abs(proj * _width), _spread); - } else { + return pow(1.0 / abs(proj * _width), _spread); + } else { return 0.0; } } @@ -37,4 +37,4 @@ void main(){ 0.005, 3.0) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/07/polar.frag b/07/polar.frag index 83e6efa..b6d9edf 100644 --- a/07/polar.frag +++ b/07/polar.frag @@ -27,4 +27,4 @@ void main(){ color = vec3( 1.-smoothstep(f,f+0.02,r) ); gl_FragColor = vec4(color, 1.0); -} \ No newline at end of file +} diff --git a/07/rect-df.frag b/07/rect-df.frag index 6cdf598..e5d3744 100644 --- a/07/rect-df.frag +++ b/07/rect-df.frag @@ -27,4 +27,4 @@ void main(){ // gl_FragColor = vec4(vec3( step(.3,d) ),1.0); // gl_FragColor = vec4(vec3( step(.3,d) * step(d,.4)),1.0); // gl_FragColor = vec4(vec3( smoothstep(.3,.4,d)* smoothstep(.6,.5,d)) ,1.0); -} \ No newline at end of file +} diff --git a/07/rect-making.frag b/07/rect-making.frag index 0464458..0e3eedc 100644 --- a/07/rect-making.frag +++ b/07/rect-making.frag @@ -12,16 +12,16 @@ uniform float u_time; void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + // bottom-left - vec2 bl = step(vec2(0.1),st); + vec2 bl = step(vec2(0.1),st); float pct = bl.x * bl.y; - // top-right + // top-right // vec2 tr = step(vec2(0.1),1.0-st); // pct *= tr.x * tr.y; - + color = vec3(pct); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/07/rect.frag b/07/rect.frag index 85f2fe0..f05a935 100644 --- a/07/rect.frag +++ b/07/rect.frag @@ -21,4 +21,4 @@ void main(){ vec3 color = vec3( rect(st, vec2(0.9) ) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/07/shapes.frag b/07/shapes.frag index 700ac9d..6d7f5d8 100644 --- a/07/shapes.frag +++ b/07/shapes.frag @@ -27,7 +27,7 @@ void main(){ // Angle and radius from the current pixel float a = atan(st.x,st.y)+PI; float r = TWO_PI/float(N); - + // Shaping function that modulate the distance d = cos(floor(.5+a/r)*r-a)*length(st); @@ -35,4 +35,4 @@ void main(){ // color = vec3(d); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/07/tmp/tritri.frag b/07/tmp/tritri.frag index da6d551..af466a1 100644 --- a/07/tmp/tritri.frag +++ b/07/tmp/tritri.frag @@ -63,4 +63,4 @@ void main(){ color += shapeBorder(st+offset+vec2(0.,0.05), 3, .05, .03); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/07/tmp/warp-shape.frag b/07/tmp/warp-shape.frag index 7f02d91..95b438b 100644 --- a/07/tmp/warp-shape.frag +++ b/07/tmp/warp-shape.frag @@ -36,4 +36,4 @@ void main(){ d = step(.4,d); gl_FragColor = vec4(vec3(1.0-d),1.0); -} \ No newline at end of file +} diff --git a/07/triangle-making.frag b/07/triangle-making.frag index b1ccac2..18dcf44 100644 --- a/07/triangle-making.frag +++ b/07/triangle-making.frag @@ -10,7 +10,7 @@ uniform vec2 u_mouse; uniform float u_time; // Based on https://www.shadertoy.com/view/4sSSzG -float triangleDF(vec2 st, +float triangleDF(vec2 st, vec2 p0, vec2 p1, vec2 p2){ vec3 e0, e1, e2; @@ -34,9 +34,9 @@ void main(){ vec3 color = vec3(0.0); // Distance Field in 3 channels - float df = triangleDF(st, - vec2(0.40,0.45), - vec2(0.60,0.45), + float df = triangleDF(st, + vec2(0.40,0.45), + vec2(0.60,0.45), vec2(0.5,0.60)); color = vec3(df); @@ -47,4 +47,4 @@ void main(){ smoothstep(size+0.001,size+1e-7,df); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/07/triangle.frag b/07/triangle.frag index f62ab43..60212a6 100644 --- a/07/triangle.frag +++ b/07/triangle.frag @@ -10,8 +10,8 @@ uniform vec2 u_mouse; uniform float u_time; // Based on https://www.shadertoy.com/view/4sSSzG -float triangle (vec2 st, - vec2 p0, vec2 p1, vec2 p2, +float triangle (vec2 st, + vec2 p0, vec2 p1, vec2 p2, float smoothness){ vec3 e0, e1, e2; @@ -27,19 +27,19 @@ float triangle (vec2 st, float b = max(0.0, dot(e1.xy, st) - e1.z); float c = max(0.0, dot(e2.xy, st) - e2.z); - return smoothstep(smoothness * 2.0, - 1e-7, + return smoothstep(smoothness * 2.0, + 1e-7, length(vec3(a, b, c))); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; - vec3 color = vec3( triangle(st, - vec2(0.0,0.15), - vec2(1.0,0.15), - vec2(0.5,0.88), + vec3 color = vec3( triangle(st, + vec2(0.0,0.15), + vec2(1.0,0.15), + vec2(0.5,0.88), 0.001) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/08/README-ch.md b/08/README-ch.md index 0d0f59e..ef6c96c 100644 --- a/08/README-ch.md +++ b/08/README-ch.md @@ -75,7 +75,7 @@ mat2 scale(vec2 _scale){ } ``` -
+
试试下面的练习,尝试深入理解矩阵的工作机制: diff --git a/08/README-de.md b/08/README-de.md index b72188e..dd1b300 100644 --- a/08/README-de.md +++ b/08/README-de.md @@ -1,101 +1,101 @@ -## 2D-Matrizen - - - -### 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 zu der ```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 studieren. Schau einfach selbst: - -* Entferne die Kommentarzeichen in der *Programmzeile 35*, und Du wirst sehen, wie sich das Zeichenobjekt gemeinsam mit dem darunterliegenden Koordinatenraum bewegt. - -
- -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 auf der Mitte der Zeichenfläche generiert, ausgehend vom Punkt ```vec2(0.5)```. 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: - -
- -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 die 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); -} -``` - -
- -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. - - - -### 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 (der benötigten Bits) 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. - -
- -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. +## 2D-Matrizen + + + +### 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 zu der ```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 studieren. Schau einfach selbst: + +* Entferne die Kommentarzeichen in der *Programmzeile 35*, und Du wirst sehen, wie sich das Zeichenobjekt gemeinsam mit dem darunterliegenden Koordinatenraum bewegt. + +
+ +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 auf der Mitte der Zeichenfläche generiert, ausgehend vom Punkt ```vec2(0.5)```. 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: + +
+ +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 die 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); +} +``` + +
+ +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. + + + +### 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 (der benötigten Bits) 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. + +
+ +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. diff --git a/08/README-it.md b/08/README-it.md index 128c300..0af6cf9 100644 --- a/08/README-it.md +++ b/08/README-it.md @@ -1,101 +1,101 @@ -## Matrici 2D - - - -### Traslare - -Nel capitolo precedente abbiamo imparato a fare alcune figure - il trucco per spostare quelle figure è stato di spostare il sistema di coordinate stesso. Siamo in grado d'ottenere questa trasformazione aggiungendo un vettore alla variabile ```st``` che contiene la posizione di ogni frammento. Ciò causa uno spostamento complessivo del sistema di coordinate. - -![](translate.jpg) - -Di sicuro è più facile da vedere che da spiegare: - -* Rimuovete il commento alla linea 35 del codice sottostante e osservate come il sistema di coordinate si muove. - -
- -Ora provate il seguente esercizio: - -* Utilizzate ```u_time``` insieme alle funzioni di forma per spostare la piccola croce in un modo interessante. Pensate a un tipo di movimento e tentate di applicarlo alla croce. Prendete degli esempi dal "mondo reale", potrebbero esservi utili - per esempio l'andirivieni delle onde, un movimento a pendolo, una palla che rimbalza, una macchina che accelera, una bicicletta che si ferma. - -### Rotazioni - -Anche per ruotare degli oggetti abbiamo bisogno di spostare l'intero sistema spaziale. Per questo utilizzeremo una [matrice](https://it.wikipedia.org/wiki/Matrice). Una matrice è un insieme di numeri organizzato in colonne e righe. Quando si moltiplica un vettore per una matrice, la matrice esegue una serie di operazioni e trasforma il vettore in funzione dei valori che questa contiene. - -[![Wikipedia entry for Matrix (mathematics) ](matrixes.png)](https://it.wikipedia.org/wiki/Matrice) - -GLSL ha un supporto nativo per le matrici a due, tre e quattro dimensioni: [```mat2```](../glossary/?search=mat2) (2x2), [```mat3```](../glossary/?search=mat3) (3x3) e [```mat4```](../glossary/?search=mat4) (4x4). GLSL supporta anche la moltiplicazione di matrici (```*```) e una funzione specifica chiamata ([```matrixCompMult()```](../glossary/?search=matrixCompMult)). - -Le matrici possono essere usate per produrre dei comportamenti specifici. Per esempio per traslare un vettore: - -![](3dtransmat.png) - -Ancora più interessante è la possibilità di utilizzare una matrice per ruotare il sistema di coordinate: - -![](rotmat.png) - -Il seguente codice mostra come costruire una matrice di rotazione 2D. Questa funzione segue la [formula](http://en.wikipedia.org/wiki/Rotation_matrix) per vettori a due dimensioni e fa ruotare le coordinate intorno al punto ```vec2(0.0)```. - -```glsl -mat2 rotate2d(float _angle){ - return mat2(cos(_angle),-sin(_angle), - sin(_angle),cos(_angle)); -} -``` - -Questa maniera d'effettuare una rotazione (intorno all'origine) non funziona con l'approccio che abbiamo utilizzato finora per disegnare le figure. La nostra croce viene disegnata al centro della tela, che corrisponde alla posizione ```vec2(0.5)```. Quindi, prima di ruotare lo spazio, abbiamo bisogno di spostare la figura dal `centro` alla coordinata ```vec2(0.0)```, poi di ruotare lo spazio, e infine di spostarla di nuovo nella posizione originale. - -![](rotate.jpg) - -Date un'occhiata al codice: - -
- -Provate i seguenti esercizi: - -* Rimuovete il commento alla linea 45 del codice qui sopra e prestate attenzione a ciò che accade. - -* Commentate le traslazioni, prima e dopo la rotazione, alle linee 37 e 39, e osservate le conseguenze. - -* Utilizzate delle rotazioni per migliorare l'animazione che avete simulato nell'esercizio sulla traslazione. - -### Scalare - -Abbiamo visto come le matrici sono usate per traslare e ruotare gli oggetti nello spazio. (O più precisamente come trasformare il sistema di coordinate per ruotare e spostare gli oggetti.) Se avete utilizzato un software di modellazione 3D o le funzioni push e pop delle matrici in Processing, si sa che le matrici possono essere utilizzati anche per scalare la dimensione di un oggetto. - -![](scale.png) - -Usando la formula precedente, siamo in grado di scrivere una matrice a due dimensioni per scalare una figura: - -```glsl -mat2 scale(vec2 _scale){ - return mat2(_scale.x,0.0, - 0.0,_scale.y); -} -``` - -
- -Provate i seguenti esercizi per capirne il funzionamento. - -* Rimuovete il commento alla linea 42 del codice per vedere come funziona la messa in scala attraverso l'uso di colori. - -* Osservate cosa succede quando si commentano le traslazioni, prima e dopo il ridimensionamento alle linee 37 e 39. - -* Provate a combinare una matrice di rotazione insieme con una matrice di scala. Attenzione, l'ordine delle operazioni è importante: per prima cosa moltiplicate le matrici fra di loro e poi moltiplicate la matrice finale per i vettori. - -* Ora che sapete come disegnare, spostare, ruotare, scalare molteplici forme, è il momento di fare una bella composizione. Progettate e realizzate una [falsa UI o HUD (heads up display)](https://www.pinterest.com/patriciogonzv/huds/). Utilizzate il seguente esempio su ShaderToy di [Ndel](https://www.shadertoy.com/user/ndel) per avere un riferimento. - - - -### Altri usi delle matrici: il colore YUV - -Lo [YUV](https://it.wikipedia.org/wiki/YUV) è uno spazio colore utilizzato per la codifica analogica di foto e video che tenga conto della gamma di percezione umana per ridurre la larghezza di banda dei componenti della crominanza. - -Nel seguente codice utilizzeremo delle operazioni di matrice in GLSL per trasformare i colori da uno spazio colore all'altro. - -
- -Come si può vedere, stiamo trattando i colori come dei vettori che vengono moltiplicati con delle matrici. Abbiamo "spostato" i valori di colore come se avessimo spostato un vettore di posizione nello spazio. - -In questo capitolo abbiamo imparato come usare le trasformazioni di matrice per spostare, ruotare e ridimensionare i vettori. Queste trasformazioni saranno essenziali per creare delle composizioni con le figure che abbiamo visto nel capitolo precedente. Nel prossimo capitolo provvederemo ad applicare tutto quello che abbiamo imparato per fare dei bei pattern procedurali. Vedrete come la ripetizione e la variazione del codice possano diventare delle pratiche gratificanti. +## Matrici 2D + + + +### Traslare + +Nel capitolo precedente abbiamo imparato a fare alcune figure - il trucco per spostare quelle figure è stato di spostare il sistema di coordinate stesso. Siamo in grado d'ottenere questa trasformazione aggiungendo un vettore alla variabile ```st``` che contiene la posizione di ogni frammento. Ciò causa uno spostamento complessivo del sistema di coordinate. + +![](translate.jpg) + +Di sicuro è più facile da vedere che da spiegare: + +* Rimuovete il commento alla linea 35 del codice sottostante e osservate come il sistema di coordinate si muove. + +
+ +Ora provate il seguente esercizio: + +* Utilizzate ```u_time``` insieme alle funzioni di forma per spostare la piccola croce in un modo interessante. Pensate a un tipo di movimento e tentate di applicarlo alla croce. Prendete degli esempi dal "mondo reale", potrebbero esservi utili - per esempio l'andirivieni delle onde, un movimento a pendolo, una palla che rimbalza, una macchina che accelera, una bicicletta che si ferma. + +### Rotazioni + +Anche per ruotare degli oggetti abbiamo bisogno di spostare l'intero sistema spaziale. Per questo utilizzeremo una [matrice](https://it.wikipedia.org/wiki/Matrice). Una matrice è un insieme di numeri organizzato in colonne e righe. Quando si moltiplica un vettore per una matrice, la matrice esegue una serie di operazioni e trasforma il vettore in funzione dei valori che questa contiene. + +[![Wikipedia entry for Matrix (mathematics) ](matrixes.png)](https://it.wikipedia.org/wiki/Matrice) + +GLSL ha un supporto nativo per le matrici a due, tre e quattro dimensioni: [```mat2```](../glossary/?search=mat2) (2x2), [```mat3```](../glossary/?search=mat3) (3x3) e [```mat4```](../glossary/?search=mat4) (4x4). GLSL supporta anche la moltiplicazione di matrici (```*```) e una funzione specifica chiamata ([```matrixCompMult()```](../glossary/?search=matrixCompMult)). + +Le matrici possono essere usate per produrre dei comportamenti specifici. Per esempio per traslare un vettore: + +![](3dtransmat.png) + +Ancora più interessante è la possibilità di utilizzare una matrice per ruotare il sistema di coordinate: + +![](rotmat.png) + +Il seguente codice mostra come costruire una matrice di rotazione 2D. Questa funzione segue la [formula](http://en.wikipedia.org/wiki/Rotation_matrix) per vettori a due dimensioni e fa ruotare le coordinate intorno al punto ```vec2(0.0)```. + +```glsl +mat2 rotate2d(float _angle){ + return mat2(cos(_angle),-sin(_angle), + sin(_angle),cos(_angle)); +} +``` + +Questa maniera d'effettuare una rotazione (intorno all'origine) non funziona con l'approccio che abbiamo utilizzato finora per disegnare le figure. La nostra croce viene disegnata al centro della tela, che corrisponde alla posizione ```vec2(0.5)```. Quindi, prima di ruotare lo spazio, abbiamo bisogno di spostare la figura dal `centro` alla coordinata ```vec2(0.0)```, poi di ruotare lo spazio, e infine di spostarla di nuovo nella posizione originale. + +![](rotate.jpg) + +Date un'occhiata al codice: + +
+ +Provate i seguenti esercizi: + +* Rimuovete il commento alla linea 45 del codice qui sopra e prestate attenzione a ciò che accade. + +* Commentate le traslazioni, prima e dopo la rotazione, alle linee 37 e 39, e osservate le conseguenze. + +* Utilizzate delle rotazioni per migliorare l'animazione che avete simulato nell'esercizio sulla traslazione. + +### Scalare + +Abbiamo visto come le matrici sono usate per traslare e ruotare gli oggetti nello spazio. (O più precisamente come trasformare il sistema di coordinate per ruotare e spostare gli oggetti.) Se avete utilizzato un software di modellazione 3D o le funzioni push e pop delle matrici in Processing, si sa che le matrici possono essere utilizzati anche per scalare la dimensione di un oggetto. + +![](scale.png) + +Usando la formula precedente, siamo in grado di scrivere una matrice a due dimensioni per scalare una figura: + +```glsl +mat2 scale(vec2 _scale){ + return mat2(_scale.x,0.0, + 0.0,_scale.y); +} +``` + +
+ +Provate i seguenti esercizi per capirne il funzionamento. + +* Rimuovete il commento alla linea 42 del codice per vedere come funziona la messa in scala attraverso l'uso di colori. + +* Osservate cosa succede quando si commentano le traslazioni, prima e dopo il ridimensionamento alle linee 37 e 39. + +* Provate a combinare una matrice di rotazione insieme con una matrice di scala. Attenzione, l'ordine delle operazioni è importante: per prima cosa moltiplicate le matrici fra di loro e poi moltiplicate la matrice finale per i vettori. + +* Ora che sapete come disegnare, spostare, ruotare, scalare molteplici forme, è il momento di fare una bella composizione. Progettate e realizzate una [falsa UI o HUD (heads up display)](https://www.pinterest.com/patriciogonzv/huds/). Utilizzate il seguente esempio su ShaderToy di [Ndel](https://www.shadertoy.com/user/ndel) per avere un riferimento. + + + +### Altri usi delle matrici: il colore YUV + +Lo [YUV](https://it.wikipedia.org/wiki/YUV) è uno spazio colore utilizzato per la codifica analogica di foto e video che tenga conto della gamma di percezione umana per ridurre la larghezza di banda dei componenti della crominanza. + +Nel seguente codice utilizzeremo delle operazioni di matrice in GLSL per trasformare i colori da uno spazio colore all'altro. + +
+ +Come si può vedere, stiamo trattando i colori come dei vettori che vengono moltiplicati con delle matrici. Abbiamo "spostato" i valori di colore come se avessimo spostato un vettore di posizione nello spazio. + +In questo capitolo abbiamo imparato come usare le trasformazioni di matrice per spostare, ruotare e ridimensionare i vettori. Queste trasformazioni saranno essenziali per creare delle composizioni con le figure che abbiamo visto nel capitolo precedente. Nel prossimo capitolo provvederemo ad applicare tutto quello che abbiamo imparato per fare dei bei pattern procedurali. Vedrete come la ripetizione e la variazione del codice possano diventare delle pratiche gratificanti. diff --git a/08/README-jp.md b/08/README-jp.md index ef0883d..a8d86cc 100644 --- a/08/README-jp.md +++ b/08/README-jp.md @@ -100,4 +100,3 @@ mat2 scale(vec2 _scale){ 見てのとおり色をベクトルとして扱い行列を掛け合わせています。このようにして色の値を「動かす」ことができるのです。 この章では行列を使ってベクトルを移動、回転、拡大・縮小する方法を学びました。これらの変形は、前章で学んだ図形を組み合わせてより複雑な図を作成するのに欠かせない技術です。次の章ではこれまで学んだことを全て活かして、規則に基づいた美しいパターンを作成します。コードによる反復と変化の楽しさを発見しましょう。 - diff --git a/08/README.md b/08/README.md index ccb2eac..9f5b764 100644 --- a/08/README.md +++ b/08/README.md @@ -4,7 +4,7 @@ ### Translate -In the previous chapter we learned how to make some shapes - the trick to moving those shapes is to move the coordinate system itself. We can achieve that by simply adding a vector to the ```st``` variable that contains the location of each fragment. This causes the whole space coordinate system to move. +In the previous chapter we learned how to make some shapes - the trick to moving those shapes is to move the coordinate system itself. We can achieve that by simply adding a vector to the ```st``` variable that contains the location of each fragment. This causes the whole space coordinate system to move. ![](translate.jpg) @@ -13,7 +13,7 @@ This is easier to see than to explain, so to see for yourself: * Uncomment line 35 of the code below to see how the space itself moves around.
- + Now try the following exercise: * Using ```u_time``` together with the shaping functions move the small cross around in an interesting way. Search for a specific quality of motion you are interested in and try to make the cross move in the same way. Recording something from the "real world" first might be useful - it could be the coming and going of waves, a pendulum movement, a bouncing ball, a car accelerating, a bicycle stopping. @@ -30,11 +30,11 @@ Based on how matrices behave it's possible to construct matrices to produce spec ![](3dtransmat.png) -More interestingly, we can use a matrix to rotate the coordinate system: +More interestingly, we can use a matrix to rotate the coordinate system: ![](rotmat.png) -Take a look at the following code for a function that constructs a 2D rotation matrix. This function follows the above [formula](http://en.wikipedia.org/wiki/Rotation_matrix) for two dimentional vectors to rotate the coordinates around the ```vec2(0.0)``` point. +Take a look at the following code for a function that constructs a 2D rotation matrix. This function follows the above [formula](http://en.wikipedia.org/wiki/Rotation_matrix) for two dimentional vectors to rotate the coordinates around the ```vec2(0.0)``` point. ```glsl mat2 rotate2d(float _angle){ @@ -57,11 +57,11 @@ Try the following exercises: * Comment the translations before and after the rotation, on lines 37 and 39, and observe the consequences. -* Use rotations to improve the animation you simulated in the translation exercise. +* Use rotations to improve the animation you simulated in the translation exercise. ### Scale -We've seen how matrices are used to translate and rotate objects in space. (Or more precisely to transform the coordinate system to rotate and move the objects.) If you've used 3D modeling software or the push and pop matrix functions in Processing, you will know that matrices can also be used to scale the size of an object. +We've seen how matrices are used to translate and rotate objects in space. (Or more precisely to transform the coordinate system to rotate and move the objects.) If you've used 3D modeling software or the push and pop matrix functions in Processing, you will know that matrices can also be used to scale the size of an object. ![](scale.png) @@ -74,7 +74,7 @@ mat2 scale(vec2 _scale){ } ``` -
+
Try the following exercises to understand more deeply how this works. diff --git a/08/cross-animated.frag b/08/cross-animated.frag index 5f3f313..f7c9f1f 100644 --- a/08/cross-animated.frag +++ b/08/cross-animated.frag @@ -26,21 +26,21 @@ float box(in vec2 _st, in vec2 _size){ } float cross(in vec2 _st, float _size){ - return box(_st, vec2(_size,_size/4.)) + + return box(_st, vec2(_size,_size/4.)) + box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + // move space from the center to the vec2(0.0) st -= vec2(0.5); // rotate the space st = rotate2d( sin(u_time*0.5)*PI ) * st; // move it back to the original place st += vec2(0.5); - + // To move the cross we move the space vec2 translate = vec2(cos(u_time),sin(u_time)); st += translate*0.35; @@ -52,4 +52,4 @@ void main(){ color += vec3(cross(st,0.25)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/08/cross-rotate.frag b/08/cross-rotate.frag index b20686a..df1e5d6 100644 --- a/08/cross-rotate.frag +++ b/08/cross-rotate.frag @@ -26,14 +26,14 @@ float box(in vec2 _st, in vec2 _size){ } float cross(in vec2 _st, float _size){ - return box(_st, vec2(_size,_size/4.)) + + return box(_st, vec2(_size,_size/4.)) + box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + // move space from the center to the vec2(0.0) st -= vec2(0.5); // rotate the space @@ -48,4 +48,4 @@ void main(){ color += vec3(cross(st,0.4)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/08/cross-scale.frag b/08/cross-scale.frag index 703e96f..4cbfe46 100644 --- a/08/cross-scale.frag +++ b/08/cross-scale.frag @@ -26,14 +26,14 @@ float box(in vec2 _st, in vec2 _size){ } float cross(in vec2 _st, float _size){ - return box(_st, vec2(_size,_size/4.)) + + return box(_st, vec2(_size,_size/4.)) + box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + st -= vec2(0.5); st = scale( vec2(sin(u_time)+1.0) ) * st; st += vec2(0.5); @@ -45,4 +45,4 @@ void main(){ color += vec3(cross(st,0.2)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/08/cross-translate.frag b/08/cross-translate.frag index c7fad90..60fccb6 100644 --- a/08/cross-translate.frag +++ b/08/cross-translate.frag @@ -19,14 +19,14 @@ float box(in vec2 _st, in vec2 _size){ } float cross(in vec2 _st, float _size){ - return box(_st, vec2(_size,_size/4.)) + + return box(_st, vec2(_size,_size/4.)) + box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + // To move the cross we move the space vec2 translate = vec2(cos(u_time),sin(u_time)); st += translate*0.35; @@ -38,4 +38,4 @@ void main(){ color += vec3(cross(st,0.25)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/08/cross.frag b/08/cross.frag index ab317f7..4f0792b 100644 --- a/08/cross.frag +++ b/08/cross.frag @@ -24,4 +24,4 @@ void main(){ vec3 color = vec3( box(st, vec2(0.4,0.1)) + box(st, vec2(0.1,0.4)) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/08/index.php b/08/index.php index 9ae20b0..e9b3539 100644 --- a/08/index.php +++ b/08/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); -?> \ No newline at end of file + include($path."/footer.php"); +?> diff --git a/08/matrices.frag b/08/matrices.frag index 1688e34..04c2f65 100644 --- a/08/matrices.frag +++ b/08/matrices.frag @@ -80,4 +80,4 @@ mat4 translate4D(float x, float y, float z){ vec4(0.0, 0.0, 1.0, 0.0), vec4(x, y, z, 1.0) ); -} \ No newline at end of file +} diff --git a/08/matrix.frag b/08/matrix.frag index 63dbabe..fa25838 100644 --- a/08/matrix.frag +++ b/08/matrix.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; @@ -31,7 +31,7 @@ vec3 matrix(in vec2 st){ ipos += vec2(.0,floor(u_time*20.*random(ipos.x))); - + vec2 fpos = fract(st*rows); vec2 center = (.5-fpos); @@ -50,4 +50,4 @@ void main(){ color = matrix(st); gl_FragColor = vec4( 1.-color , 1.0); -} \ No newline at end of file +} diff --git a/08/tmp/circleWave.frag b/08/tmp/circleWave.frag index 7309a08..4fb0996 100644 --- a/08/tmp/circleWave.frag +++ b/08/tmp/circleWave.frag @@ -39,4 +39,4 @@ void main() { color = mix(color,vec3(1.0),circleWaveLine(st,0.8,0.02)); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/08/tmp/circleWave2.frag b/08/tmp/circleWave2.frag index 6bcd801..af0eba8 100644 --- a/08/tmp/circleWave2.frag +++ b/08/tmp/circleWave2.frag @@ -47,4 +47,4 @@ void main() { color += vec3(0.489,0.630,1.000) * circleWaveLine(st,size,width) * alpha; gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/08/tmp/cross-doted.frag b/08/tmp/cross-doted.frag index 2eb4f23..b2d15c3 100644 --- a/08/tmp/cross-doted.frag +++ b/08/tmp/cross-doted.frag @@ -38,7 +38,7 @@ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(0.0); - + st -= vec2(0.5); st = rotate2d( sin(u_time)*PI ) * st; st += vec2(0.5); @@ -47,4 +47,4 @@ void main(){ color += cross(st,(1.0-abs(sin(u_time)))*.5); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/08/tmp/cross.frag b/08/tmp/cross.frag index 0c4c8de..992a307 100644 --- a/08/tmp/cross.frag +++ b/08/tmp/cross.frag @@ -23,4 +23,4 @@ void main(){ float pct = box(st, vec2(0.9,0.3)) + box(st, vec2(0.3,0.9)); gl_FragColor = vec4( vec3(1.-pct),pct ); -} \ No newline at end of file +} diff --git a/08/tmp/linesWave.frag b/08/tmp/linesWave.frag index 4584767..63176b1 100644 --- a/08/tmp/linesWave.frag +++ b/08/tmp/linesWave.frag @@ -32,4 +32,4 @@ void main() { pattern = mix(stripes(st,-0.786375),stripes(st,0.786375),pattern); gl_FragColor = vec4( vec3(smoothstep(.4,.5,pattern)), 1.0 ); -} \ No newline at end of file +} diff --git a/08/yuv.frag b/08/yuv.frag index 7ab282f..1991ce9 100644 --- a/08/yuv.frag +++ b/08/yuv.frag @@ -8,13 +8,13 @@ uniform vec2 u_resolution; uniform float u_time; // YUV to RGB matrix -mat3 yuv2rgb = mat3(1.0, 0.0, 1.13983, - 1.0, -0.39465, -0.58060, +mat3 yuv2rgb = mat3(1.0, 0.0, 1.13983, + 1.0, -0.39465, -0.58060, 1.0, 2.03211, 0.0); // RGB to YUV matrix mat3 rgb2yuv = mat3(0.2126, 0.7152, 0.0722, - -0.09991, -0.33609, 0.43600, + -0.09991, -0.33609, 0.43600, 0.615, -0.5586, -0.05639); void main(){ @@ -22,14 +22,14 @@ void main(){ vec3 color = vec3(0.0); // UV values goes from -1 to 1 - // So we need to remap st (0.0 to 1.0) + // So we need to remap st (0.0 to 1.0) st -= 0.5; // becomes -0.5 to 0.5 st *= 2.0; // becomes -1.0 to 1.0 - // we pass st as the y & z values of + // we pass st as the y & z values of // a three dimentional vector to be // properly multiply by a 3x3 matrix color = yuv2rgb * vec3(0.5, st.x, st.y); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/README-ch.md b/09/README-ch.md index de313b9..c594cb9 100755 --- a/09/README-ch.md +++ b/09/README-ch.md @@ -34,7 +34,7 @@ void main(){ * 把画布分成 3 行 3 列。 指出如何定义行和列的线程的,并用这种方式改变显示着的图形。试着做一个井字棋。 -### 在图案内部应用矩阵 +### 在图案内部应用矩阵 鉴于每个细分或者说单元都是我们正在使用的单位化坐标系的小单元,我们可以对每个内部空间施以矩阵变换来平移,旋转和缩放。 diff --git a/09/README-de.md b/09/README-de.md index a64c5bc..f7679e8 100644 --- a/09/README-de.md +++ b/09/README-de.md @@ -1,116 +1,115 @@ -## Muster - -Weil Shader-Programme Bildpunkt für Bildpunkt ausgeführt werden, spielt es keine große Rolle, wie oft man ein bestimmtes Muster innerhalb der Zeichenfläche wiederholt – die Anzahl der Berechnungen bleibt gleich. Aus diesem Grund eignen sich Fragment-Shader ganz hervorragend für die Erzeugung sich wiederholender Kachelmuster. - -[ ![Nina Warmerdam – Das IMPRINT Projekt (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag) - -In diesem Kapitel werden wir anwenden, was wir bislang gelernt haben, und es über den gesamten Raum unserer Zeichenfläche wiederholen. Wie schon in den vorhergehenden Kapiteln wird unsere Strategie darin bestehen, die Koordinaten zu vervielfältigen. Dadurch werden sich Formen, die wir innerhalb des Koordinatenraumes zwischen ```0.0``` und ```1.0``` zeichnen, vervielfältigen lassen, so dass ein kontinuierliches Muster entlang eines Rasters entsteht. - -*"Das Gitternetz eröffnet einen Rahmen, innerhalb dessen sich die menschliche Intuition und Schöpfungskraft entfalten kann. Inmitten des Chaos der Natur stellen Muster einen Kontrastpunkt dar, indem sie eine vorhersehbare, sich wiederholende Ordnung realisieren. Schon seit frühen Mustern auf Keramikflächen in antiken Bädern haben die Menschen Gitternetze genutzt, um ihr Leben durch repetitive Dekorationen zu verschönen.“* [*10 PRINT*, Mit Press, (2013)](http://10print.org/) - -Lasst uns zunächst noch einmal die [```fract()```](../glossary/?search=fract)-Funktion ins Gedächtnis rufen. Sie liefert den Nachkommateil einer Zahl zurück, wodurch ```fract()``` effektiv den Modulo (Rest) einer Division durch 1 ergibt ([```mod(x,1.0)```](../glossary/?search=mod)). Unsere normalisierte Variable für das Koordinatensystem (```st```) bewegt sich ohnehin zwischen ```0.0``` und ```1.0```. Deshalb macht es wenig Sinn, Berechnungen wie die folgende anzustellen: - -```glsl -void main(){ - vec2 st = gl_FragCoord.xy/u_resolution; - vec3 color = vec3(0.0); - st = fract(st); - color = vec3(st,0.0); - gl_FragColor = vec4(color,1.0); -} -``` - -Wenn wir aber das Koordinatensystem hochskalieren – sagen wir einmal um den Faktor drei – erhalten wir drei interpolierende Sequenzen: die Erste mit Fließkommawerten von ```0``` bis ```1```, die Zweite mit Werten von ```1``` bis ```2``` und die Dritte mit Werten zwischen ```2``` und ```3```. - -
- -Jetzt ist es an der Zeit, in jedem dieser Drei mal Drei „Unterräume“ zu zeichnen, indem Du die Kommentarzeichen in *Programmzeile 27* entfernst. (Weil wir die *x*- und *y*-Ordinate gleichermaßen skalieren, bleibt das Seitenverhältnis erhalten.) - -Probiere einige der folgenden Übungen aus, um Dein Verständnis zu vertiefen: - -* Multipliziere die Koordinaten (den Raum) mit anderen Faktoren. Probiere auch einmal nicht ganzzahlige Werte, sowie unterschiedliche Faktoren für *x* und *y* aus. - -* Verwandle diesen „Muster-Trick“ in eine wiederverwendbare Funktion. - -* Teile den Raum in drei Spalten und drei Zeilen auf. Finde einen Weg, wie Dein Programmcode erkennen kann, an welcher Zeile und Spalte er gerade arbeitet und nutze dies, um die gezeichneten Formen zu variieren. Versuche, ein Tick-Tack-Toe-Spielfeld nachzuempfinden. - -### Anwendung von Matrizen innerhalb von Mustern - -Weil jeder „Unterraum“ und jede Gitterzelle eine verkleinerte Fassung des normalisierten Koordinatensystems darstellt, mit dem wir bereits gearbeitet haben, können wir auch Matrizenoperationen darauf anwenden. So lässt sich der Koordinatenraum innerhalb einer Gitterzelle verschieben, rotieren und auch skalieren. - -
- -* Überlege Dir interessante Wege, um dieses Muster zu animieren. Denke z.B. an die Animation von Farbe, Form oder Bewegung. Erstelle drei unterschiedliche Animationen. - -* Erzeuge komplexere Muster durch das Zusammenfügen unterschiedlicher Formen. - -[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag) - -* Vereine unterschiedliche Schichten von Mustern, um Dein eigenes Karomuster entstehen zu lassen, wie es [für schottische Tartans typisch ist](http://de.wikipedia.org/wiki/Tartan_(Muster)). - -[ ![Vektormuster eines schottischen Tartans von Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076) - -### Versetzte Muster - -Sagen wir einmal, wir wollen ein Mauerwerk zeichnen. Beim Blick auf eine solche Wand fällt sofort auf, dass die Steine in jeder Reihe jeweils um eine halbe Steinlänge versetzt sind. Stellt sich natürlich die Frage, wie wir so etwas per Programmcode umsetzen können? - -![](brick.jpg) - -Im ersten Schritt müssen wir zunächst einmal wissen, ob die Zeile, an der unser Thread gerade arbeitet, gerade oder ungerade ist. Denn darüber können wir den Versatz der Muster entlang der *x-Achse* bestimmen. Dafür können wir [```mod()```](../glossary/?search=mod) mit ```2.0``` verwenden und schauen, ob das Ergebnis weniger als ```1.0``` beträgt oder nicht. Wirf einen Blick auf die folgende Formel und entferne nacheinander die Kommentarzeichen in den letzten beiden Zeilen. - -
- -Wie Du siehst, können wir den [ternären Operator](http://de.wikipedia.org/wiki/Bedingte_Anweisung_und_Verzweigung#Auswahloperator) nutzen, um zu prüfen, ob das Ergebnis von [```mod()```](../glossary/?search=mod) mit ```2.0``` unter dem Wert von ```1.0``` liegt. Oder wir können die [```step()```](../glossary/?search=step)-Funktion nutzen, um das gleiche Ergebnis zu erzielen. Und ```step()``` ist in der konkreten Ausführung sogar noch etwas schneller. Doch wie kommt das? Obwohl es schwer vorhersehbar ist, wie eine bestimmte Grafikkarte Shader-Code kompiliert und optimiert, können wir davon ausgehen, dass eingebaute Funktionen schneller ausgeführt werden, also solche, die erst in mehrere Einzelschritte aufgelöst werden müssen. Wann immer Du eine eingebaute Funktion für Deine Zwecke nutzen kannst, tue dies deshalb auch! - -Nun haben wir also unsere „Ungerade-Funktion“ beisammen, sodass wir den ungeraden Reihen unseres Mauerwerks einen Versatz geben können. In der *Programmzeile 14* des folgenden Listings befindet sich der entsprechende Programmcode. Beachte, dass das Ergebnis unserer Berechnung für gerade Reihen ```0.0``` lautet und die Multiplikation mit dem Versatz von ```0.5``` dann eben auch ```0.0``` ergibt. Bei ungeraden Reihen multiplizieren wir den Versatz von ```0.5``` hingegen mit ```1.0```, so dass daraus eine entsprechende Verschiebung der *x-Achse* des Koordinatensystems folgt. - -Entferne jetzt die Kommentarzeichen in der *Programmzeile 32*, wodurch das Seitenverhältnis unseres Koordinatensystems gestreckt wird und wir die Anmutung eines modernen Mauerwerks erhalten. Wenn Du die Kommentarzeichen in *Programmzeile 40* entfernst, erkennst Du die Anordnung und Wiederholung des Koordinatensystems anhand der Farben Rot und Grün. - -
- -* Versuche diese Grafik zu animieren, indem Du den Versatz auf Basis der Zeit veränderst. - -* Baue eine weitere Animation, bei der sich die geraden Reihen nach links und die ungeraden Reihen nach rechts bewegen. - -* Gelingt es Dir, diesen Effekt auch in Bezug auf die Spalten zu wiederholen? - -* Versuche einen Versatz entlang der *x-Achse* mit einem entlang der *y-Achse* zu kombinieren, um so etwas wie die folgende Animation zu erhalten: - - - -## Truchet-Kacheln - -Wir haben nun gelernt, wie man feststellt, ob sich die zu zeichnende Gitterzelle in einer geraden oder ungeraden Zeile bzw. Spalte befindet, Auf Basis dieser Information können wir ein einzelnes Designelement in Abhängigkeit seiner Position wiederverwenden. Wirf einen Blick auf die sogenannten [Truchet-Kacheln](http://en.wikipedia.org/wiki/Truchet_tiles), bei denen eine einzelne Form in vier unterschiedlichen Anordnungen dargestellt wird: - -![](truchet-00.png) - -Indem wir die Anordnung des Musters von Kachel zu Kachel variieren, können wir eine unendliche Menge von Designs erzeugen. - -![](truchet-01.png) - -Schaue Die die Funktion ```rotateTilePattern()``` genau an. Sie unterteilt den Raum jeweils in vier Zellen und dreht jede davon in eine unterschiedliche Richtung. - -
- -* Kommentiere die *Programmzeilen 69 bis 72*, entferne die Kommentare wieder und vervielfältige diese Zeilen, um neue Designs entstehen zu lassen. - -* Ersetze das Schwarzweiß-Dreieck durch andere Formen, beispielsweise Halbkreise, gedrehte Quadrate oder Linien. - -* Kodiere andere Muster, bei denen die Elemente in Abhängigkeit ihrer Position unterschiedlich gedreht werden. - -* Entwickle ein Muster, das weitere Merkmale in Abhängigkeit der Elementposition verändert. - -* Denke an andere Darstellungen, die nicht notwendigerweise Muster verkörpern müssen, aber die Konzepte aus diesem Abschnitt aufgreifen, beispielsweise an das [chinesische I-Ging](http://de.wikipedia.org/wiki/I_Ging). - - - -## Erschaffe Deine eigenen Regeln - -Prozedurale, sich wiederholende Muster zu kreieren, ist eine interessante Übung für den Geist. Es geht darum, den minimalen Satz an Elementen zu finden, die sich wiederholen müssen, um ein größeres komplexes Ganzes zu erschaffen. Diese Vorgehensweise ist sehr alt. Die Menschheit benutzt Muster und Gitternetze schon seit tausenden von Jahren, um Wände und Böden, Textilien und andere Objekte zu verzieren. Angefangen von mäandernden Mustern im alten Griechenland bis hin zu chinesischen Gitterfenstern, ist es immer wieder das Spiel aus Wiederholung bei gleichzeitiger Variation, die unsere Fantasie anregt. Nimm Dir ein wenig Zeit, um diese Art von [Dekorationen](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) und [Mustern](https://www.pinterest.com/patriciogonzv/paterns/) zu studieren. Von geometrischen Mustern aus Arabien bis hin zu prachtvollen Stoffmustern aus dem afrikanischem Kulturkreis eröffnet sich Dir ein ganzes Universum an Mustern, von denen Du lernen kannst. - -![Franz Sales Meyer – Handbuch der Ornamentik (1920)](geometricpatters.png) - -Mit diesem Kapitel enden die Abschnitte zum algorithmischen Zeichnen. In den folgenden Kapiteln werden wir sehen, wie man ein wenig mehr Zufall in unsere Shader bringt, um die Natur nachzuempfinden. - +## Muster + +Weil Shader-Programme Bildpunkt für Bildpunkt ausgeführt werden, spielt es keine große Rolle, wie oft man ein bestimmtes Muster innerhalb der Zeichenfläche wiederholt – die Anzahl der Berechnungen bleibt gleich. Aus diesem Grund eignen sich Fragment-Shader ganz hervorragend für die Erzeugung sich wiederholender Kachelmuster. + +[ ![Nina Warmerdam – Das IMPRINT Projekt (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag) + +In diesem Kapitel werden wir anwenden, was wir bislang gelernt haben, und es über den gesamten Raum unserer Zeichenfläche wiederholen. Wie schon in den vorhergehenden Kapiteln wird unsere Strategie darin bestehen, die Koordinaten zu vervielfältigen. Dadurch werden sich Formen, die wir innerhalb des Koordinatenraumes zwischen ```0.0``` und ```1.0``` zeichnen, vervielfältigen lassen, so dass ein kontinuierliches Muster entlang eines Rasters entsteht. + +*"Das Gitternetz eröffnet einen Rahmen, innerhalb dessen sich die menschliche Intuition und Schöpfungskraft entfalten kann. Inmitten des Chaos der Natur stellen Muster einen Kontrastpunkt dar, indem sie eine vorhersehbare, sich wiederholende Ordnung realisieren. Schon seit frühen Mustern auf Keramikflächen in antiken Bädern haben die Menschen Gitternetze genutzt, um ihr Leben durch repetitive Dekorationen zu verschönen.“* [*10 PRINT*, Mit Press, (2013)](http://10print.org/) + +Lasst uns zunächst noch einmal die [```fract()```](../glossary/?search=fract)-Funktion ins Gedächtnis rufen. Sie liefert den Nachkommateil einer Zahl zurück, wodurch ```fract()``` effektiv den Modulo (Rest) einer Division durch 1 ergibt ([```mod(x,1.0)```](../glossary/?search=mod)). Unsere normalisierte Variable für das Koordinatensystem (```st```) bewegt sich ohnehin zwischen ```0.0``` und ```1.0```. Deshalb macht es wenig Sinn, Berechnungen wie die folgende anzustellen: + +```glsl +void main(){ + vec2 st = gl_FragCoord.xy/u_resolution; + vec3 color = vec3(0.0); + st = fract(st); + color = vec3(st,0.0); + gl_FragColor = vec4(color,1.0); +} +``` + +Wenn wir aber das Koordinatensystem hochskalieren – sagen wir einmal um den Faktor drei – erhalten wir drei interpolierende Sequenzen: die Erste mit Fließkommawerten von ```0``` bis ```1```, die Zweite mit Werten von ```1``` bis ```2``` und die Dritte mit Werten zwischen ```2``` und ```3```. + +
+ +Jetzt ist es an der Zeit, in jedem dieser Drei mal Drei „Unterräume“ zu zeichnen, indem Du die Kommentarzeichen in *Programmzeile 27* entfernst. (Weil wir die *x*- und *y*-Ordinate gleichermaßen skalieren, bleibt das Seitenverhältnis erhalten.) + +Probiere einige der folgenden Übungen aus, um Dein Verständnis zu vertiefen: + +* Multipliziere die Koordinaten (den Raum) mit anderen Faktoren. Probiere auch einmal nicht ganzzahlige Werte, sowie unterschiedliche Faktoren für *x* und *y* aus. + +* Verwandle diesen „Muster-Trick“ in eine wiederverwendbare Funktion. + +* Teile den Raum in drei Spalten und drei Zeilen auf. Finde einen Weg, wie Dein Programmcode erkennen kann, an welcher Zeile und Spalte er gerade arbeitet und nutze dies, um die gezeichneten Formen zu variieren. Versuche, ein Tick-Tack-Toe-Spielfeld nachzuempfinden. + +### Anwendung von Matrizen innerhalb von Mustern + +Weil jeder „Unterraum“ und jede Gitterzelle eine verkleinerte Fassung des normalisierten Koordinatensystems darstellt, mit dem wir bereits gearbeitet haben, können wir auch Matrizenoperationen darauf anwenden. So lässt sich der Koordinatenraum innerhalb einer Gitterzelle verschieben, rotieren und auch skalieren. + +
+ +* Überlege Dir interessante Wege, um dieses Muster zu animieren. Denke z.B. an die Animation von Farbe, Form oder Bewegung. Erstelle drei unterschiedliche Animationen. + +* Erzeuge komplexere Muster durch das Zusammenfügen unterschiedlicher Formen. + +[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag) + +* Vereine unterschiedliche Schichten von Mustern, um Dein eigenes Karomuster entstehen zu lassen, wie es [für schottische Tartans typisch ist](http://de.wikipedia.org/wiki/Tartan_(Muster)). + +[ ![Vektormuster eines schottischen Tartans von Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076) + +### Versetzte Muster + +Sagen wir einmal, wir wollen ein Mauerwerk zeichnen. Beim Blick auf eine solche Wand fällt sofort auf, dass die Steine in jeder Reihe jeweils um eine halbe Steinlänge versetzt sind. Stellt sich natürlich die Frage, wie wir so etwas per Programmcode umsetzen können? + +![](brick.jpg) + +Im ersten Schritt müssen wir zunächst einmal wissen, ob die Zeile, an der unser Thread gerade arbeitet, gerade oder ungerade ist. Denn darüber können wir den Versatz der Muster entlang der *x-Achse* bestimmen. Dafür können wir [```mod()```](../glossary/?search=mod) mit ```2.0``` verwenden und schauen, ob das Ergebnis weniger als ```1.0``` beträgt oder nicht. Wirf einen Blick auf die folgende Formel und entferne nacheinander die Kommentarzeichen in den letzten beiden Zeilen. + +
+ +Wie Du siehst, können wir den [ternären Operator](http://de.wikipedia.org/wiki/Bedingte_Anweisung_und_Verzweigung#Auswahloperator) nutzen, um zu prüfen, ob das Ergebnis von [```mod()```](../glossary/?search=mod) mit ```2.0``` unter dem Wert von ```1.0``` liegt. Oder wir können die [```step()```](../glossary/?search=step)-Funktion nutzen, um das gleiche Ergebnis zu erzielen. Und ```step()``` ist in der konkreten Ausführung sogar noch etwas schneller. Doch wie kommt das? Obwohl es schwer vorhersehbar ist, wie eine bestimmte Grafikkarte Shader-Code kompiliert und optimiert, können wir davon ausgehen, dass eingebaute Funktionen schneller ausgeführt werden, also solche, die erst in mehrere Einzelschritte aufgelöst werden müssen. Wann immer Du eine eingebaute Funktion für Deine Zwecke nutzen kannst, tue dies deshalb auch! + +Nun haben wir also unsere „Ungerade-Funktion“ beisammen, sodass wir den ungeraden Reihen unseres Mauerwerks einen Versatz geben können. In der *Programmzeile 14* des folgenden Listings befindet sich der entsprechende Programmcode. Beachte, dass das Ergebnis unserer Berechnung für gerade Reihen ```0.0``` lautet und die Multiplikation mit dem Versatz von ```0.5``` dann eben auch ```0.0``` ergibt. Bei ungeraden Reihen multiplizieren wir den Versatz von ```0.5``` hingegen mit ```1.0```, so dass daraus eine entsprechende Verschiebung der *x-Achse* des Koordinatensystems folgt. + +Entferne jetzt die Kommentarzeichen in der *Programmzeile 32*, wodurch das Seitenverhältnis unseres Koordinatensystems gestreckt wird und wir die Anmutung eines modernen Mauerwerks erhalten. Wenn Du die Kommentarzeichen in *Programmzeile 40* entfernst, erkennst Du die Anordnung und Wiederholung des Koordinatensystems anhand der Farben Rot und Grün. + +
+ +* Versuche diese Grafik zu animieren, indem Du den Versatz auf Basis der Zeit veränderst. + +* Baue eine weitere Animation, bei der sich die geraden Reihen nach links und die ungeraden Reihen nach rechts bewegen. + +* Gelingt es Dir, diesen Effekt auch in Bezug auf die Spalten zu wiederholen? + +* Versuche einen Versatz entlang der *x-Achse* mit einem entlang der *y-Achse* zu kombinieren, um so etwas wie die folgende Animation zu erhalten: + + + +## Truchet-Kacheln + +Wir haben nun gelernt, wie man feststellt, ob sich die zu zeichnende Gitterzelle in einer geraden oder ungeraden Zeile bzw. Spalte befindet, Auf Basis dieser Information können wir ein einzelnes Designelement in Abhängigkeit seiner Position wiederverwenden. Wirf einen Blick auf die sogenannten [Truchet-Kacheln](http://en.wikipedia.org/wiki/Truchet_tiles), bei denen eine einzelne Form in vier unterschiedlichen Anordnungen dargestellt wird: + +![](truchet-00.png) + +Indem wir die Anordnung des Musters von Kachel zu Kachel variieren, können wir eine unendliche Menge von Designs erzeugen. + +![](truchet-01.png) + +Schaue Die die Funktion ```rotateTilePattern()``` genau an. Sie unterteilt den Raum jeweils in vier Zellen und dreht jede davon in eine unterschiedliche Richtung. + +
+ +* Kommentiere die *Programmzeilen 69 bis 72*, entferne die Kommentare wieder und vervielfältige diese Zeilen, um neue Designs entstehen zu lassen. + +* Ersetze das Schwarzweiß-Dreieck durch andere Formen, beispielsweise Halbkreise, gedrehte Quadrate oder Linien. + +* Kodiere andere Muster, bei denen die Elemente in Abhängigkeit ihrer Position unterschiedlich gedreht werden. + +* Entwickle ein Muster, das weitere Merkmale in Abhängigkeit der Elementposition verändert. + +* Denke an andere Darstellungen, die nicht notwendigerweise Muster verkörpern müssen, aber die Konzepte aus diesem Abschnitt aufgreifen, beispielsweise an das [chinesische I-Ging](http://de.wikipedia.org/wiki/I_Ging). + + + +## Erschaffe Deine eigenen Regeln + +Prozedurale, sich wiederholende Muster zu kreieren, ist eine interessante Übung für den Geist. Es geht darum, den minimalen Satz an Elementen zu finden, die sich wiederholen müssen, um ein größeres komplexes Ganzes zu erschaffen. Diese Vorgehensweise ist sehr alt. Die Menschheit benutzt Muster und Gitternetze schon seit tausenden von Jahren, um Wände und Böden, Textilien und andere Objekte zu verzieren. Angefangen von mäandernden Mustern im alten Griechenland bis hin zu chinesischen Gitterfenstern, ist es immer wieder das Spiel aus Wiederholung bei gleichzeitiger Variation, die unsere Fantasie anregt. Nimm Dir ein wenig Zeit, um diese Art von [Dekorationen](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) und [Mustern](https://www.pinterest.com/patriciogonzv/paterns/) zu studieren. Von geometrischen Mustern aus Arabien bis hin zu prachtvollen Stoffmustern aus dem afrikanischem Kulturkreis eröffnet sich Dir ein ganzes Universum an Mustern, von denen Du lernen kannst. + +![Franz Sales Meyer – Handbuch der Ornamentik (1920)](geometricpatters.png) + +Mit diesem Kapitel enden die Abschnitte zum algorithmischen Zeichnen. In den folgenden Kapiteln werden wir sehen, wie man ein wenig mehr Zufall in unsere Shader bringt, um die Natur nachzuempfinden. diff --git a/09/README-it.md b/09/README-it.md index c983dbe..ccbb777 100644 --- a/09/README-it.md +++ b/09/README-it.md @@ -1,119 +1,119 @@ -## Motivi - -Siccome i programmi shader sono eseguiti pixel per pixel non importa quante volte voi ripetiate una forma, infatti il numero dei calcoli rimane costante. Questo significa che i fragment shader sono particolarmente adatti per creare dei motivi ripetitivi. - -[ ![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag) - -In questo capitolo applicheremo ciò che abbiamo imparato fin ad ora e lo ripeteremo all'interno del canvas. Così come nel capitolo precedente, la nostra strategia sarà basata sulla moltiplicazione delle coordinate spaziali (tra 0.0 e 0.1), in modo che le forme che disegniamo tra i valori 0.0 e 1.0 saranno ripetute per creare una griglia. - -*"The grid provides a framework within which human intuition and invention can operate and that it can subvert. Within the chaos of nature patterns provide a constrast and promise of order. From early patterns on pottery to geometric mosaics in Roman baths, people have long used grids to enhance their lives with decoration."* [*10 PRINT*, Mit Press, (2013)](http://10print.org/) - -Prima ricordiamo la funzione [```fract()```](../glossary/?search=fract). Questa restituisce la parte frazionale di un numero, facendo in sostanza ```fract()``` il modulo di uno ([```mod(x,1.0)```](../glossary/?search=mod)). In altre parole, [```fract()```](../glossary/?search=fract) restituisce il numero dopo la virgola mobile. Il nostro sistema variabile di coordinate (```st```) va già da 0.0 a 1.0, quindi non ha senso fare una cosa simile a: - -```glsl -void main(){ - vec2 st = gl_FragCoord.xy/u_resolution; - vec3 color = vec3(0.0); - st = fract(st); - color = vec3(st,0.0); - gl_FragColor = vec4(color,1.0); -} -``` - -Ma se ingrandiamo il sistema di coordinate, diciamo di tre volte, otterremo tre sequenze di interpolazioni lineari tra 0-1: la prima tra 0-1, la seconda per le virgole mobili tra 1-2 e la terza per le virgole mobili tra 2-3. - -
- -È arrivato il momento di disegnare qualcosa in ciascuno sottospazio, togliendo il commento alla riga 27 (Siccome stiamo moltiplicando sia in x sia in y, il rapporto di forma dello spazio non cambia e le forme saranno come previste). - -Provate alcuni dei seguenti esercizi per capire meglio: - -* Moltiplicate lo spazio per numeri diversi. Provate con valori con la virgola mobile e anche con valori diversi per x e y. - -* Create una funzione riutilizzabile con questo trucco di piastrellatura. - -* Suddividete lo spazio in 3 righe e 3 colonne. Trovate un modo di sapere in quale colonna e quale riga si trova il thread e usatelo per cambiare la forma che è mostrata. Provate a creare una griglia per il tris. - -### Applicare le matrici all'interno dei motivi - -Siccome ciascuna suddivisione, o cella, è una versione più piccola del sistema normalizzato di coordinate che abbiamo già usato, possiamo applicarle una trasformazione matrice per traslare, ruotare o ridimensionare lo spazio interno. - -
- -* Pensate a modi interessanti di animare questo motivo. Considerate le animazioni di colore, forma e movimento. Fate tre animazioni diverse. - -* Riproducete dei motivi più complicati componendo forme diverse. - -[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag) - -* Combinate diversi livelli di motivi per comporre il vostro personale motivo di [Tartan Scozzese](https://www.google.com/search?q=scottish+patterns+fabric&tbm=isch&tbo=u&source=univ&sa=X&ei=Y1aFVfmfD9P-yQTLuYCIDA&ved=0CB4QsAQ&biw=1399&bih=799#tbm=isch&q=Scottish+Tartans+Patterns). - -[ ![Vector Pattern Scottish Tartan di Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076) - -### Compensare i motivi - -Immaginiamo di voler imitare un muro di mattoni. Guardando il muro, potete vedere un offset a mezzo mattone sull'asse x a file alternate. Come possiamo farlo? - -![](brick.jpg) - -Come primo passo dobbiamo sapere se la riga del nostro thread è un numero pari o dispari, perché possiamo usare ciò per determinare se abbiamo bisogno di compensare con un offset le x in quella fila. - -____dobbiamo unire i prossimi due paragrafi____ - -Per determinare se il nostro thread è in una fila pari o dispari, useremo [```mod()```](../glossary/?search=mod) di ```2.0``` e poi vedremo se il risultato è inferiore a ```1.0``` o no. Osservate la formula seguente e togliete il commento alle ultime due righe. - -
- -Come potete vedere, usiamo un [operatore ternario](https://it.wikipedia.org/wiki/%3F:) per controllare se il [```mod()```](../glossary/?search=mod) di ```2.0``` sia al di sotto di ```1.0``` (seconda riga) o potremmo anche usare una funzione [```step()```](../glossary/?search=step) che fa la stessa operazione ma più velocemente. Perché? Nonostante sia difficile sapere come ciascuna carta grafica ottimizza e compila il codice, è sicuro assumere che questa funzione built-in sia più veloce di una non built-in. Ogni volta che potete usare una funzione built-in, fatelo! - -Ora che abbiamo la formula per il numero dispari, possiamo applicare un offset alle file dispari per dare l'effetto *muro di mattoni* alla nostra piastrellatura. La riga 14 del codice seguente è dove stiamo usando la funzione per "rilevare" le file dispari e dare loro un offset di mezza unità sulle ```x```. Notate che per le file pari, il risultato della nostra funzione è ```0.0```, e moltiplicando ```0.0``` per l'offset di ```0.5```, otteniamo una compensazione di ```0.0```; sulle file dispari moltiplichiamo il risultato della nostra funzione, ```1.0```, per l'offset di ```0.5```, che sposta di ```0.5``` l'asse delle ```x``` del sistema. - -Ora provate a togliere il commento alla riga 32 - questo allunga il rapporto di forma del sistema di coordinate per simulare l'aspetto di un "mattone moderno". Togliendo il commento alla riga 40 potete vedere come il sistema di coordinate appaia mappato con il rosso e il verde. - -
- -* Provate ad animare questo motivo spostando l'offset in base al tempo. - -* Fate un'altra animazione dove le file pari si spostano a sinistra e le file dispari si spostano a destra. - -* Riuscite a ripetere quest'effetto con le colonne? - -* Provate a combinare un offset sugli assi delle ```x``` e delle ```y``` per ottenere qualcosa di simile a questo: - - - -## Tessere di Truchet - -Ora che abbiamo imparato come dire se la nostra cella è in una fila o colonna pari o dispari. È possibile riutilizzare un singolo motivo in relazione alla sua posizione. Considerate il caso delle tessere di [Truchet Tiles](http://en.wikipedia.org/wiki/Truchet_tiles), dove un singolo motivo può essere rappresentato in quattro modi diversi: - -![](truchet-00.png) - -Cambiando il motivo lungo le tessere, è possibile costruire una serie infinita di motivi complessi. - -![](truchet-01.png) - -Osservate più da vicino la funzione ```rotateTilePattern()```, che suddivide lo spazio in quattro celle e assegna un angolo di rotazione a ciascuna di esse. - -
- -* Commentate, togliete il commento e duplicate le righe da 69 a 72 per comporre nuovi motivi. - -* Cambiate il triangolo bianco e nero con un altro elemento, ad esempio: semicerchi, quadrati o linee ruotati. - -* Codificate altri motivi dove gli elementi siano ruotati a seconda della loro posizione. - -* Create un motivo che cambi altre proprietà a seconda della posizione degli elementi. - -* Immaginate qualcos'altro, che non sia necessariamente un motivo, dove potete applicare i principi visti in questa sezione (es. esagrammi di I Ching). - - - -## Create il vostro insieme di tessere - -Creare motivi procedurali è un esercizio mentale nel trovare il più piccole elemento riutilizzabile. Questa è una pratica antica; nel corso della storia abbiamo usato schemi e motivi per decorare tessuti, i fondi e i bordi di oggetti: dai motivi nell'antica Grecia al motivo reticolare cinese, il piacere della ripetizione e della variazione affascina la nostra immaginazione. Prendete del tempo per guardare i [motivi](https://www.pinterest.com/patriciogonzv/paterns/) [decorativi](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) e osservate come artisti e designers nel corso della loro lunga tradizione abbiano saputo navigare tra predicibilità dell'ordine e la sorpresa della variazione e del caos. Dai motivi geometrici arabi, ai bellissimi motivi delle stoffe africane, esiste un intero universo di motivi dal quale imparare. - -![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png) - -Con questo capitolo terminiamo la sezione sul disegno algoritmico. Nei prossimi capitoli impareremo a portare dell'entropia nei nostri shader e a produrre motivi generativi. \ No newline at end of file +## Motivi + +Siccome i programmi shader sono eseguiti pixel per pixel non importa quante volte voi ripetiate una forma, infatti il numero dei calcoli rimane costante. Questo significa che i fragment shader sono particolarmente adatti per creare dei motivi ripetitivi. + +[ ![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag) + +In questo capitolo applicheremo ciò che abbiamo imparato fin ad ora e lo ripeteremo all'interno del canvas. Così come nel capitolo precedente, la nostra strategia sarà basata sulla moltiplicazione delle coordinate spaziali (tra 0.0 e 0.1), in modo che le forme che disegniamo tra i valori 0.0 e 1.0 saranno ripetute per creare una griglia. + +*"The grid provides a framework within which human intuition and invention can operate and that it can subvert. Within the chaos of nature patterns provide a constrast and promise of order. From early patterns on pottery to geometric mosaics in Roman baths, people have long used grids to enhance their lives with decoration."* [*10 PRINT*, Mit Press, (2013)](http://10print.org/) + +Prima ricordiamo la funzione [```fract()```](../glossary/?search=fract). Questa restituisce la parte frazionale di un numero, facendo in sostanza ```fract()``` il modulo di uno ([```mod(x,1.0)```](../glossary/?search=mod)). In altre parole, [```fract()```](../glossary/?search=fract) restituisce il numero dopo la virgola mobile. Il nostro sistema variabile di coordinate (```st```) va già da 0.0 a 1.0, quindi non ha senso fare una cosa simile a: + +```glsl +void main(){ + vec2 st = gl_FragCoord.xy/u_resolution; + vec3 color = vec3(0.0); + st = fract(st); + color = vec3(st,0.0); + gl_FragColor = vec4(color,1.0); +} +``` + +Ma se ingrandiamo il sistema di coordinate, diciamo di tre volte, otterremo tre sequenze di interpolazioni lineari tra 0-1: la prima tra 0-1, la seconda per le virgole mobili tra 1-2 e la terza per le virgole mobili tra 2-3. + +
+ +È arrivato il momento di disegnare qualcosa in ciascuno sottospazio, togliendo il commento alla riga 27 (Siccome stiamo moltiplicando sia in x sia in y, il rapporto di forma dello spazio non cambia e le forme saranno come previste). + +Provate alcuni dei seguenti esercizi per capire meglio: + +* Moltiplicate lo spazio per numeri diversi. Provate con valori con la virgola mobile e anche con valori diversi per x e y. + +* Create una funzione riutilizzabile con questo trucco di piastrellatura. + +* Suddividete lo spazio in 3 righe e 3 colonne. Trovate un modo di sapere in quale colonna e quale riga si trova il thread e usatelo per cambiare la forma che è mostrata. Provate a creare una griglia per il tris. + +### Applicare le matrici all'interno dei motivi + +Siccome ciascuna suddivisione, o cella, è una versione più piccola del sistema normalizzato di coordinate che abbiamo già usato, possiamo applicarle una trasformazione matrice per traslare, ruotare o ridimensionare lo spazio interno. + +
+ +* Pensate a modi interessanti di animare questo motivo. Considerate le animazioni di colore, forma e movimento. Fate tre animazioni diverse. + +* Riproducete dei motivi più complicati componendo forme diverse. + +[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag) + +* Combinate diversi livelli di motivi per comporre il vostro personale motivo di [Tartan Scozzese](https://www.google.com/search?q=scottish+patterns+fabric&tbm=isch&tbo=u&source=univ&sa=X&ei=Y1aFVfmfD9P-yQTLuYCIDA&ved=0CB4QsAQ&biw=1399&bih=799#tbm=isch&q=Scottish+Tartans+Patterns). + +[ ![Vector Pattern Scottish Tartan di Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076) + +### Compensare i motivi + +Immaginiamo di voler imitare un muro di mattoni. Guardando il muro, potete vedere un offset a mezzo mattone sull'asse x a file alternate. Come possiamo farlo? + +![](brick.jpg) + +Come primo passo dobbiamo sapere se la riga del nostro thread è un numero pari o dispari, perché possiamo usare ciò per determinare se abbiamo bisogno di compensare con un offset le x in quella fila. + +____dobbiamo unire i prossimi due paragrafi____ + +Per determinare se il nostro thread è in una fila pari o dispari, useremo [```mod()```](../glossary/?search=mod) di ```2.0``` e poi vedremo se il risultato è inferiore a ```1.0``` o no. Osservate la formula seguente e togliete il commento alle ultime due righe. + +
+ +Come potete vedere, usiamo un [operatore ternario](https://it.wikipedia.org/wiki/%3F:) per controllare se il [```mod()```](../glossary/?search=mod) di ```2.0``` sia al di sotto di ```1.0``` (seconda riga) o potremmo anche usare una funzione [```step()```](../glossary/?search=step) che fa la stessa operazione ma più velocemente. Perché? Nonostante sia difficile sapere come ciascuna carta grafica ottimizza e compila il codice, è sicuro assumere che questa funzione built-in sia più veloce di una non built-in. Ogni volta che potete usare una funzione built-in, fatelo! + +Ora che abbiamo la formula per il numero dispari, possiamo applicare un offset alle file dispari per dare l'effetto *muro di mattoni* alla nostra piastrellatura. La riga 14 del codice seguente è dove stiamo usando la funzione per "rilevare" le file dispari e dare loro un offset di mezza unità sulle ```x```. Notate che per le file pari, il risultato della nostra funzione è ```0.0```, e moltiplicando ```0.0``` per l'offset di ```0.5```, otteniamo una compensazione di ```0.0```; sulle file dispari moltiplichiamo il risultato della nostra funzione, ```1.0```, per l'offset di ```0.5```, che sposta di ```0.5``` l'asse delle ```x``` del sistema. + +Ora provate a togliere il commento alla riga 32 - questo allunga il rapporto di forma del sistema di coordinate per simulare l'aspetto di un "mattone moderno". Togliendo il commento alla riga 40 potete vedere come il sistema di coordinate appaia mappato con il rosso e il verde. + +
+ +* Provate ad animare questo motivo spostando l'offset in base al tempo. + +* Fate un'altra animazione dove le file pari si spostano a sinistra e le file dispari si spostano a destra. + +* Riuscite a ripetere quest'effetto con le colonne? + +* Provate a combinare un offset sugli assi delle ```x``` e delle ```y``` per ottenere qualcosa di simile a questo: + + + +## Tessere di Truchet + +Ora che abbiamo imparato come dire se la nostra cella è in una fila o colonna pari o dispari. È possibile riutilizzare un singolo motivo in relazione alla sua posizione. Considerate il caso delle tessere di [Truchet Tiles](http://en.wikipedia.org/wiki/Truchet_tiles), dove un singolo motivo può essere rappresentato in quattro modi diversi: + +![](truchet-00.png) + +Cambiando il motivo lungo le tessere, è possibile costruire una serie infinita di motivi complessi. + +![](truchet-01.png) + +Osservate più da vicino la funzione ```rotateTilePattern()```, che suddivide lo spazio in quattro celle e assegna un angolo di rotazione a ciascuna di esse. + +
+ +* Commentate, togliete il commento e duplicate le righe da 69 a 72 per comporre nuovi motivi. + +* Cambiate il triangolo bianco e nero con un altro elemento, ad esempio: semicerchi, quadrati o linee ruotati. + +* Codificate altri motivi dove gli elementi siano ruotati a seconda della loro posizione. + +* Create un motivo che cambi altre proprietà a seconda della posizione degli elementi. + +* Immaginate qualcos'altro, che non sia necessariamente un motivo, dove potete applicare i principi visti in questa sezione (es. esagrammi di I Ching). + + + +## Create il vostro insieme di tessere + +Creare motivi procedurali è un esercizio mentale nel trovare il più piccole elemento riutilizzabile. Questa è una pratica antica; nel corso della storia abbiamo usato schemi e motivi per decorare tessuti, i fondi e i bordi di oggetti: dai motivi nell'antica Grecia al motivo reticolare cinese, il piacere della ripetizione e della variazione affascina la nostra immaginazione. Prendete del tempo per guardare i [motivi](https://www.pinterest.com/patriciogonzv/paterns/) [decorativi](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) e osservate come artisti e designers nel corso della loro lunga tradizione abbiano saputo navigare tra predicibilità dell'ordine e la sorpresa della variazione e del caos. Dai motivi geometrici arabi, ai bellissimi motivi delle stoffe africane, esiste un intero universo di motivi dal quale imparare. + +![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png) + +Con questo capitolo terminiamo la sezione sul disegno algoritmico. Nei prossimi capitoli impareremo a portare dell'entropia nei nostri shader e a produrre motivi generativi. diff --git a/09/README.md b/09/README.md index 6240e47..eaf8728 100644 --- a/09/README.md +++ b/09/README.md @@ -1,10 +1,10 @@ ## Patterns -Since shader programs are executed by pixel-by-pixel no matter how much you repeat a shape the number of calculations stays constant. This means that fragment shaders are particulary suitable for tile patterns. +Since shader programs are executed by pixel-by-pixel no matter how much you repeat a shape the number of calculations stays constant. This means that fragment shaders are particulary suitable for tile patterns. [ ![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag) -In this chapter we are going to apply what we've learned so far and repeat it along a canvas. Like in previous chapters, our strategy will be based on multiplying the space coordinates (between 0.0 and 1.0), so that the shapes we draw between the values 0.0 and 1.0 will be repeated to make a grid. +In this chapter we are going to apply what we've learned so far and repeat it along a canvas. Like in previous chapters, our strategy will be based on multiplying the space coordinates (between 0.0 and 1.0), so that the shapes we draw between the values 0.0 and 1.0 will be repeated to make a grid. *"The grid provides a framework within which human intuition and invention can operate and that it can subvert. Within the chaos of nature patterns provide a constrast and promise of order. From early patterns on pottery to geometric mosaics in Roman baths, people have long used grids to enhance their lives with decoration."* [*10 PRINT*, Mit Press, (2013)](http://10print.org/) @@ -34,9 +34,9 @@ Try some of the following exercises to get a deeper understanding: * Divide the space into 3 rows and 3 columns. Find a way to know in which column and row the thread is and use that to change the shape that is displaying. Try to compose a tic-tac-toe match. -### Apply matrices inside patterns +### Apply matrices inside patterns -Since each subdivision or cell is a smaller version of the normalized coordinate system we have already been using, we can apply a matrix transformation to it in order to translate, rotate or scale the space inside. +Since each subdivision or cell is a smaller version of the normalized coordinate system we have already been using, we can apply a matrix transformation to it in order to translate, rotate or scale the space inside.
@@ -91,7 +91,7 @@ Now that we've learned how to tell if our cell is in an even or odd row or colum ![](truchet-00.png) -By changing the pattern across tiles, it's possible to construct an infinite set of complex designs. +By changing the pattern across tiles, it's possible to construct an infinite set of complex designs. ![](truchet-01.png) @@ -113,7 +113,7 @@ Pay close attention to the function ```rotateTilePattern()```, which subdivides ## Making your own rules -Making procedural patterns is a mental exercise in finding minimal reusable elements. This practice is old; we as a species have been using grids and patterns to decorate textiles, floors and borders of objects for a long time: from meanders patterns in ancient Greece, to Chinese lattice design, the pleasure of repetition and variation catches our imagination. Take some time to look at [decorative](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) [patterns](https://www.pinterest.com/patriciogonzv/paterns/) and see how artists and designers have a long history of navigating the fine edge between the predictability of order and the surprise of variation and chaos. From Arabic geometrical patterns, to gorgeous African fabric designs, there is an entire universe of patterns to learn from. +Making procedural patterns is a mental exercise in finding minimal reusable elements. This practice is old; we as a species have been using grids and patterns to decorate textiles, floors and borders of objects for a long time: from meanders patterns in ancient Greece, to Chinese lattice design, the pleasure of repetition and variation catches our imagination. Take some time to look at [decorative](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) [patterns](https://www.pinterest.com/patriciogonzv/paterns/) and see how artists and designers have a long history of navigating the fine edge between the predictability of order and the surprise of variation and chaos. From Arabic geometrical patterns, to gorgeous African fabric designs, there is an entire universe of patterns to learn from. ![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png) diff --git a/09/bricks.frag b/09/bricks.frag index bff66de..9aef79f 100644 --- a/09/bricks.frag +++ b/09/bricks.frag @@ -40,4 +40,4 @@ void main(void){ // color = vec3(st,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/checks.frag b/09/checks.frag index 6d22549..118fcf2 100644 --- a/09/checks.frag +++ b/09/checks.frag @@ -45,4 +45,4 @@ void main(void){ // color = vec3(st,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/cross.frag b/09/cross.frag index 1566f81..7fa15a1 100644 --- a/09/cross.frag +++ b/09/cross.frag @@ -25,7 +25,7 @@ float box(in vec2 _st, in vec2 _size){ } float cross(in vec2 _st, float _size){ - return box(_st, vec2(_size*0.5,_size*0.125)) + + return box(_st, vec2(_size*0.5,_size*0.125)) + box(_st, vec2(_size*0.125,_size*0.5)); } @@ -37,4 +37,4 @@ void main(){ vec3 color = vec3( clamp(cross(fract(st),0.3),0.0,1.0) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/deco.frag b/09/deco.frag index 908bc61..307fd20 100644 --- a/09/deco.frag +++ b/09/deco.frag @@ -31,7 +31,7 @@ void main(){ vec3 color = vec3(0.0); st = mirrorTile(st,10.); - float x = st.x*2.; + float x = st.x*2.; float a = floor(1.+sin(x*3.14)); float b = floor(1.+sin((x+1.)*3.14)); float f = fract(x); @@ -39,4 +39,4 @@ void main(){ color = vec3( fillY(st,mix(a,b,f),0.01) ); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/09/diamondtiles.frag b/09/diamondtiles.frag index d727d66..70a7ad9 100644 --- a/09/diamondtiles.frag +++ b/09/diamondtiles.frag @@ -1,4 +1,4 @@ -// Author @patriciogv ( patriciogonzalezvivo.com ) - 2015 +// Author @patriciogv ( patriciogonzalezvivo.com ) - 2015 // Title: Diamond Tiles #ifdef GL_ES @@ -38,13 +38,13 @@ vec2 offset(vec2 _st, vec2 _offset){ uv.x = _st.x - 0.5; } else { uv.x = _st.x + 0.5; - } + } if(_st.y>0.5){ uv.y = _st.y - 0.5; } else { uv.y = _st.y + 0.5; - } + } return uv; } @@ -61,5 +61,5 @@ void main(void){ vec3 color = vec3( box(offsetSt,vec2(0.95),0.01) - box(st,vec2(0.3),0.01) + 2.*box(st,vec2(0.2),0.01) ); - gl_FragColor = vec4(color,1.0); -} \ No newline at end of file + gl_FragColor = vec4(color,1.0); +} diff --git a/09/dots.frag b/09/dots.frag index 3604a74..77ed704 100644 --- a/09/dots.frag +++ b/09/dots.frag @@ -27,4 +27,4 @@ void main(){ vec3 color = vec3(circle(st, 0.2)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/dots1.frag b/09/dots1.frag index 4f31a56..c62bb0d 100644 --- a/09/dots1.frag +++ b/09/dots1.frag @@ -30,4 +30,4 @@ void main(){ circle(st+vec2(.5,0.), 0.35)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/dots2.frag b/09/dots2.frag index 3117bd7..1f8a7e1 100644 --- a/09/dots2.frag +++ b/09/dots2.frag @@ -28,9 +28,9 @@ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + st = brickTile(st,5.); vec3 color = vec3(1.0-circle(st, 0.11)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/dots3.frag b/09/dots3.frag index d1363e4..d97fba3 100644 --- a/09/dots3.frag +++ b/09/dots3.frag @@ -31,11 +31,11 @@ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + st = brickMirrorTile(st,5.); - vec3 color = vec3(circle(st+vec2(0.,0.05), 0.007)+ - circle(st+vec2(0.075,-0.07), 0.007)+ + vec3 color = vec3(circle(st+vec2(0.,0.05), 0.007)+ + circle(st+vec2(0.075,-0.07), 0.007)+ circle(st+vec2(-0.075,-0.07), 0.007)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/dots4.frag b/09/dots4.frag index d35a54e..8148f5b 100644 --- a/09/dots4.frag +++ b/09/dots4.frag @@ -30,12 +30,12 @@ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + st = brickTile(st,5.); - vec3 color = vec3(circle(st+vec2(0.,0.1), 0.007)+ - circle(st+vec2(0.00,-0.1), 0.007)+ - circle(st+vec2(-0.1,0.), 0.007)+ + vec3 color = vec3(circle(st+vec2(0.,0.1), 0.007)+ + circle(st+vec2(0.00,-0.1), 0.007)+ + circle(st+vec2(-0.1,0.), 0.007)+ circle(st+vec2(0.1,0), 0.007)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/dots5.frag b/09/dots5.frag index 4ccb880..3803d7a 100644 --- a/09/dots5.frag +++ b/09/dots5.frag @@ -41,4 +41,4 @@ void main(){ color = mix(color, vec3(0.761,0.247,0.102), circlePattern(grid2,0.2)) - circlePattern(grid2,0.05), gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/grid-making.frag b/09/grid-making.frag index 48e0962..1b6b3b8 100644 --- a/09/grid-making.frag +++ b/09/grid-making.frag @@ -25,8 +25,6 @@ void main() { color = vec3(st,0.0); //color = vec3(circle(st,0.5)); - + gl_FragColor = vec4(color,1.0); } - - diff --git a/09/grid-side.frag b/09/grid-side.frag index 9ce6dae..a671ff9 100644 --- a/09/grid-side.frag +++ b/09/grid-side.frag @@ -29,8 +29,8 @@ float X(vec2 _st, float _width){ void main(void){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st = tile(st,10.0); - + vec3 color = vec3(X(st,0.03)); - gl_FragColor = vec4(color,1.0); -} \ No newline at end of file + gl_FragColor = vec4(color,1.0); +} diff --git a/09/grid.frag b/09/grid.frag index a90335b..df314b1 100644 --- a/09/grid.frag +++ b/09/grid.frag @@ -23,7 +23,7 @@ void main(void){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - // Repat the space + // Repat the space st = tile(st,10.0); // Draw a rectangle in each one @@ -32,5 +32,5 @@ void main(void){ // Show the space coordinates // color = vec3(st,0.0); - gl_FragColor = vec4(color,1.0); -} \ No newline at end of file + gl_FragColor = vec4(color,1.0); +} diff --git a/09/iching-01.frag b/09/iching-01.frag index 72cdd7c..92906ff 100644 --- a/09/iching-01.frag +++ b/09/iching-01.frag @@ -70,10 +70,10 @@ void main(){ st *= 10.0; vec2 fpos = fract(st); vec2 ipos = floor(st); - + float t = u_time*5.0; float df = 1.0; df = hex(fpos,ipos.x+ipos.y+t)+(1.0-rect(fpos,vec2(0.7))); gl_FragColor = vec4(mix(vec3(0.),vec3(1.),step(0.7,df)),1.0); -} \ No newline at end of file +} diff --git a/09/index.php b/09/index.php index f8612e5..b7c3eff 100644 --- a/09/index.php +++ b/09/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> - diff --git a/09/lines-wave.frag b/09/lines-wave.frag index 8162b06..ba0d486 100644 --- a/09/lines-wave.frag +++ b/09/lines-wave.frag @@ -27,9 +27,9 @@ float line(vec2 st, float width) { void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + st *= 10.; st = wave(st, 3.); vec3 color = vec3(line(st,.5)); gl_FragColor = vec4(color, 1.0); -} \ No newline at end of file +} diff --git a/09/lines.frag b/09/lines.frag index 3280a44..c423f2f 100644 --- a/09/lines.frag +++ b/09/lines.frag @@ -23,7 +23,7 @@ float stripes(vec2 st){ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec3 color = vec3(stripes(st)); gl_FragColor = vec4(color, 1.0); -} \ No newline at end of file +} diff --git a/09/marching_dots.frag b/09/marching_dots.frag index 54337ac..e1ebd25 100644 --- a/09/marching_dots.frag +++ b/09/marching_dots.frag @@ -18,13 +18,13 @@ vec2 movingTiles(vec2 _st, float _zoom, float _speed){ _st.x += fract(time)*2.0; } else { _st.x -= fract(time)*2.0; - } + } } else { if (fract( _st.x * 0.5) > 0.5){ _st.y += fract(time)*2.0; } else { _st.y -= fract(time)*2.0; - } + } } return fract(_st); } @@ -43,4 +43,4 @@ void main() { vec3 color = vec3( 1.0-circle(st, 0.3 ) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/mirrortiles.frag b/09/mirrortiles.frag index a56e307..a23f40f 100644 --- a/09/mirrortiles.frag +++ b/09/mirrortiles.frag @@ -33,4 +33,4 @@ void main(){ color = vec3(fillY(st,0.5+sin(st.x*PI*2.0)*0.45,0.02)); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/09/nuts.frag b/09/nuts.frag index bb1c04b..a20bc5b 100644 --- a/09/nuts.frag +++ b/09/nuts.frag @@ -46,4 +46,4 @@ void main(){ vec3 color = vec3( 1.0-smoothstep( 0.5,0.6, pow(pct,st.y) ) * 1.0-smoothstep( 0.79,0.81, pow(pct,2.0-st.y ) ) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/rotatedtiles.frag b/09/rotatedtiles.frag index 99189b4..5988124 100644 --- a/09/rotatedtiles.frag +++ b/09/rotatedtiles.frag @@ -26,7 +26,7 @@ vec2 tile (vec2 _st, float _zoom) { vec2 rotateTile(vec2 _st){ _st *= 2.0; - float index = 0.0; + float index = 0.0; if (fract(_st.x * 0.5) > 0.5){ index += 1.0; } @@ -48,8 +48,8 @@ vec2 rotateTile(vec2 _st){ } // Based on https://www.shadertoy.com/view/4sSSzG -float triangle (vec2 _st, - vec2 _p0, vec2 _p1, vec2 _p2, +float triangle (vec2 _st, + vec2 _p0, vec2 _p1, vec2 _p2, float _smoothness) { vec3 e0, e1, e2; @@ -65,8 +65,8 @@ float triangle (vec2 _st, float b = max(0.0, dot(e1.xy, _st) - e1.z); float c = max(0.0, dot(e2.xy, _st) - e2.z); - return smoothstep(_smoothness * 2.0, - 1e-7, + return smoothstep(_smoothness * 2.0, + 1e-7, length(vec3(a, b, c))); } @@ -75,17 +75,17 @@ void main (void) { st = tile(st,3.0); st = rotateTile(st); - + float pattern = 0.0; st = rotate2D(st,-PI*u_time*0.25); - pattern = triangle(st, - vec2(0.30,-0.5), - vec2(0.70,0.-0.5), - vec2(0.5,1.0), + pattern = triangle(st, + vec2(0.30,-0.5), + vec2(0.70,0.-0.5), + vec2(0.5,1.0), 0.01); vec3 color = vec3(pattern); - gl_FragColor = vec4(color,1.0); -} \ No newline at end of file + gl_FragColor = vec4(color,1.0); +} diff --git a/09/tmp/checker.frag b/09/tmp/checker.frag index 00251a5..910a707 100644 --- a/09/tmp/checker.frag +++ b/09/tmp/checker.frag @@ -29,4 +29,4 @@ void main(){ pct += abs(mod(st_i.x,2.)-mod(st_i.y,2.)); gl_FragColor = vec4(vec3(pct),1.0); -} \ No newline at end of file +} diff --git a/09/tmp/dots-animation.frag b/09/tmp/dots-animation.frag index cb66e55..ed105cd 100644 --- a/09/tmp/dots-animation.frag +++ b/09/tmp/dots-animation.frag @@ -28,11 +28,11 @@ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec2 pos = vec2(0.5)-st; st = brickTile(st,20.); - + float t = u_time*.5; float r = dot(pos,pos)*4.; @@ -42,4 +42,4 @@ void main(){ vec3 color = vec3(circle(st, pattern)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/tmp/dots-texture.frag b/09/tmp/dots-texture.frag index 58441bf..5d9932a 100644 --- a/09/tmp/dots-texture.frag +++ b/09/tmp/dots-texture.frag @@ -39,9 +39,9 @@ void main(){ st.x += 0.5; pos.x += 0.5/grid; } - + float pattern = texture2D(u_tex0,clamp(floor(pos*grid)/grid+vec2(.5,.5)/grid,vec2(0.),vec2(1.))).r; pattern = circle(fract(st), smoothstep(0.1,1.,pattern)); gl_FragColor = vec4(pattern,0.,0.,pattern); -} \ No newline at end of file +} diff --git a/09/tmp/dots-tide.frag b/09/tmp/dots-tide.frag index d704fda..6a0b78a 100644 --- a/09/tmp/dots-tide.frag +++ b/09/tmp/dots-tide.frag @@ -30,4 +30,4 @@ void main(){ pct += circle(st,size); gl_FragColor = vec4(vec3(pct),1.0); -} \ No newline at end of file +} diff --git a/09/tmp/dots-zoom-00.frag b/09/tmp/dots-zoom-00.frag index bbf18af..03518b1 100644 --- a/09/tmp/dots-zoom-00.frag +++ b/09/tmp/dots-zoom-00.frag @@ -18,7 +18,7 @@ float aastep(float threshold, float value) { return smoothstep(threshold-afwidth, threshold+afwidth, value); #else return step(threshold, value); - #endif + #endif } vec2 brickTile(vec2 st, float zoom){ st *= zoom; @@ -53,7 +53,7 @@ void main(){ vec2 IN = st; vec2 OUT = st*2.; - + float pct = 1.0-fract(u_mouse.y/u_resolution.y); pct = pow(pct,6.); @@ -65,4 +65,4 @@ void main(){ color = vec3(d); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/tmp/dots-zoom-01.frag b/09/tmp/dots-zoom-01.frag index 7df2b6b..7ab6421 100644 --- a/09/tmp/dots-zoom-01.frag +++ b/09/tmp/dots-zoom-01.frag @@ -18,7 +18,7 @@ float aastep(float threshold, float value) { return smoothstep(threshold-afwidth, threshold+afwidth, value); #else return step(threshold, value); - #endif + #endif } vec2 brickTile(vec2 st, float zoom){ st *= zoom; @@ -39,7 +39,7 @@ void main(){ vec2 IN = st; vec2 OUT = st*2.; - + float pct = 1.0-fract(u_mouse.y/u_resolution.y); float A = circleDF(vec2(0.5)-st); @@ -55,4 +55,4 @@ void main(){ color = vec3(d); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/tmp/dots.frag b/09/tmp/dots.frag index 3604a74..77ed704 100644 --- a/09/tmp/dots.frag +++ b/09/tmp/dots.frag @@ -27,4 +27,4 @@ void main(){ vec3 color = vec3(circle(st, 0.2)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/tmp/grid-fine.frag b/09/tmp/grid-fine.frag index 952e0ec..1b8d2c9 100644 --- a/09/tmp/grid-fine.frag +++ b/09/tmp/grid-fine.frag @@ -18,11 +18,11 @@ bool grid(vec2 _pos, float _res){ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy-vec2(.5); st.x *= u_resolution.x/u_resolution.y; - + vec3 color = vec3(0.0); if(grid(st,0.01)) color += vec3(0.25); if(grid(st,0.1)) color += vec3(0.15); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/09/tmp/grid-warp.frag b/09/tmp/grid-warp.frag index 6e0d9ed..10dbab1 100644 --- a/09/tmp/grid-warp.frag +++ b/09/tmp/grid-warp.frag @@ -29,5 +29,5 @@ void main(void){ vec2 xy = st-vec2(.5); float grid = 1.0-X(tile(xy,10.+20.0*dot(xy,xy)),0.05); - gl_FragColor = vec4(vec3(grid),1.0); -} \ No newline at end of file + gl_FragColor = vec4(vec3(grid),1.0); +} diff --git a/09/tmp/lines-thin.frag b/09/tmp/lines-thin.frag index 414795c..756d3db 100644 --- a/09/tmp/lines-thin.frag +++ b/09/tmp/lines-thin.frag @@ -16,7 +16,7 @@ float aastep(float threshold, float value) { return smoothstep(threshold-afwidth, threshold+afwidth, value); #else return step(threshold, value); - #endif + #endif } mat2 rotate2d(float angle){ @@ -32,7 +32,7 @@ float stripes(vec2 st){ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec3 color = vec3(stripes(st)); gl_FragColor = vec4(color, 1.0); -} \ No newline at end of file +} diff --git a/09/tmp/lines-wave.frag b/09/tmp/lines-wave.frag index 325a9d3..0cfc62b 100644 --- a/09/tmp/lines-wave.frag +++ b/09/tmp/lines-wave.frag @@ -16,7 +16,7 @@ float aastep(float threshold, float value) { return smoothstep(threshold-afwidth, threshold+afwidth, value); #else return step(threshold, value); - #endif + #endif } float stripes(vec2 st, float width){ @@ -26,9 +26,9 @@ float stripes(vec2 st, float width){ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec2 pos = st; pos.y += sin(pos.x*30.)*.01; vec3 color = vec3(stripes(pos*92.,.4)); gl_FragColor = vec4(color, 1.0); -} \ No newline at end of file +} diff --git a/09/tmp/lines-zigzag.frag b/09/tmp/lines-zigzag.frag index b456467..603aa03 100644 --- a/09/tmp/lines-zigzag.frag +++ b/09/tmp/lines-zigzag.frag @@ -16,7 +16,7 @@ float aastep(float threshold, float value) { return smoothstep(threshold-afwidth, threshold+afwidth, value); #else return step(threshold, value); - #endif + #endif } float stripes(vec2 st, float width){ @@ -26,10 +26,10 @@ float stripes(vec2 st, float width){ void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec2 pos = fract(st*30.); pos.y += mix(fract(pos.x),fract(1.0-pos.x),step(.5,pos.x))*3.; vec3 color = vec3(stripes(pos,.3)); gl_FragColor = vec4(color, 1.0); -} \ No newline at end of file +} diff --git a/09/tmp/seamless-tile.frag b/09/tmp/seamless-tile.frag index 1d02feb..99a6b1b 100644 --- a/09/tmp/seamless-tile.frag +++ b/09/tmp/seamless-tile.frag @@ -14,7 +14,7 @@ vec2 tile (vec2 st, float _zoom) { vec2 seamlessTile(vec2 st){ st *= 2.0; - float index = 0.0; + float index = 0.0; index += step(1., mod(st.x,2.0)); index += step(1., mod(st.y,2.0))*2.0; st = fract(st); @@ -36,6 +36,6 @@ void main (void) { // step(st.x,st.y) just makes a b&w triangles - // but you can use whatever design you want. + // but you can use whatever design you want. gl_FragColor = vec4(vec3(step(st.x,st.y)),1.0); -} \ No newline at end of file +} diff --git a/09/truchet.frag b/09/truchet.frag index a3aedb7..4d99e22 100644 --- a/09/truchet.frag +++ b/09/truchet.frag @@ -24,15 +24,15 @@ vec2 tile (vec2 _st, float _zoom) { vec2 rotateTilePattern(vec2 _st){ - // Scale the coordinate system by 2x2 + // Scale the coordinate system by 2x2 _st *= 2.0; // Give each cell an index number // according to its position - float index = 0.0; + float index = 0.0; index += step(1., mod(_st.x,2.0)); index += step(1., mod(_st.y,2.0))*2.0; - + // | // 2 | 3 // | @@ -72,6 +72,6 @@ void main (void) { // st = rotate2D(st,PI*u_time*0.25); // step(st.x,st.y) just makes a b&w triangles - // but you can use whatever design you want. + // but you can use whatever design you want. gl_FragColor = vec4(vec3(step(st.x,st.y)),1.0); -} \ No newline at end of file +} diff --git a/09/zigzag.frag b/09/zigzag.frag index 6a010d9..fddfa1c 100644 --- a/09/zigzag.frag +++ b/09/zigzag.frag @@ -28,7 +28,7 @@ void main(){ vec3 color = vec3(0.0); st = mirrorTile(st*vec2(1.,2.),5.); - float x = st.x*2.; + float x = st.x*2.; float a = floor(1.+sin(x*3.14)); float b = floor(1.+sin((x+1.)*3.14)); float f = fract(x); @@ -36,4 +36,4 @@ void main(){ color = vec3( fillY(st,mix(a,b,f),0.01) ); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/10/1d-random.frag b/10/1d-random.frag index e07cb1c..3cbaebe 100644 --- a/10/1d-random.frag +++ b/10/1d-random.frag @@ -10,7 +10,7 @@ uniform vec2 u_mouse; uniform float u_time; float plot(vec2 _st, float _pct){ - return smoothstep( _pct-0.01, _pct, _st.y) - + return smoothstep( _pct-0.01, _pct, _st.y) - smoothstep( _pct, _pct+0.01, _st.y); } @@ -30,4 +30,4 @@ void main() { color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/10/2d-random-dots.frag b/10/2d-random-dots.frag index 83170a3..51e3c31 100644 --- a/10/2d-random-dots.frag +++ b/10/2d-random-dots.frag @@ -21,7 +21,7 @@ float random(in vec2 st){ return fract(sin(dot(st.xy ,vec2(12.9898,78.233))) * 4 void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + st *= 10.0; // Offset every other row st.x -= step(1., mod(st.y,2.0)) * 0.5; @@ -38,4 +38,4 @@ void main(){ // pct = 1.-pct; gl_FragColor = vec4(vec3(pct),1.0); -} \ No newline at end of file +} diff --git a/10/2d-random-mosaic.frag b/10/2d-random-mosaic.frag index 945f929..e613ac0 100644 --- a/10/2d-random-mosaic.frag +++ b/10/2d-random-mosaic.frag @@ -9,9 +9,9 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -float random (vec2 st) { +float random (vec2 st) { return fract(sin(dot(st.xy, - vec2(12.9898,78.233)))* + vec2(12.9898,78.233)))* 43758.5453123); } @@ -23,10 +23,10 @@ void main() { vec2 fpos = fract(st); // get the fractional coords // Assign a random value based on the integer coord - vec3 color = vec3(random( ipos )); + vec3 color = vec3(random( ipos )); // Uncomment to see the subdivided grid // color = vec3(fpos,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/10/2d-random-truchet.frag b/10/2d-random-truchet.frag index 5a2915f..f125a35 100644 --- a/10/2d-random-truchet.frag +++ b/10/2d-random-truchet.frag @@ -1,5 +1,5 @@ // Author @patriciogv - 2015 -// Title: Truchet - 10 print +// Title: Truchet - 10 print #ifdef GL_ES precision mediump float; @@ -11,9 +11,9 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -float random (in vec2 _st) { +float random (in vec2 _st) { return fract(sin(dot(_st.xy, - vec2(12.9898,78.233)))* + vec2(12.9898,78.233)))* 43758.5453123); } @@ -56,4 +56,4 @@ void main() { // color = step(tile.x,tile.y); gl_FragColor = vec4(vec3(color),1.0); -} \ No newline at end of file +} diff --git a/10/2d-random.frag b/10/2d-random.frag index ce15143..13a1447 100644 --- a/10/2d-random.frag +++ b/10/2d-random.frag @@ -21,4 +21,4 @@ void main() { float rnd = random( st ); gl_FragColor = vec4(vec3(rnd),1.0); -} \ No newline at end of file +} diff --git a/10/README-de.md b/10/README-de.md index 9a59a1b..4cf95a2 100644 --- a/10/README-de.md +++ b/10/README-de.md @@ -1,93 +1,92 @@ -# Generative Designs - -Nachdem wir in den vorangegangenen Kapiteln so viel über Wiederholungen und wohlgeformte Ordnungen gelernt haben, ist es nur konsequent, nun eine kleine Exkursion in das Reich des Chaotischen zu unternehmen. - -## Zufall - -[![Ryoji Ikeda – Testmuster (2008) ](ryoji-ikeda.jpg) ](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set) - -Zufälligkeit ist der konsequenteste Ausdruck von Entropie. Doch wie können wir Zufälle innerhalb einer so vorhersehbaren Umgebung wie die der Programmiersprache GLSL erzeugen? - -Lass uns damit beginnen, die folgende Funktion zu analysieren: - -
- -Oben sehen wir das Ergebnis, wenn man nur den Nachkommateil der Werte einer *Standardsinuskurve* betrachtet. Die Funktionswerte von [```sin()```](../glossary/?search=sin) oszillieren zwischen ```-1.0``` und ```1.0```. Hier wurde der Vorkommateil abgeschnitten, so dass wir es nur noch mit positiven Werten zwischen ```0.0``` und ```0.99999999...``` zu tun haben. Wir können diesen Effekt nutzen, um „pseudo-zufällige“ Zahlen zu generieren, indem wir die Sinuswelle in kleine Teilstücke „aufbrechen“. Wie das geht? Indem wir das Resultat von [```sin(x)```](../glossary/?search=sin) mit großen Zahlen multiplizieren. Füge dem Faktor ```1.0``` in der obigen Formel einfach ein paar Nullen vor dem Komma hinzu – eine nach der anderen – und beobachte die Auswirkungen auf den Funktionsgraphen. - -Spätestens, wenn Du bei ```100000.0``` angekommen bist (und die Formel so aussieht ```y = fract(sin(x)*100000.0)``` ), wirst Du die zugrundeliegende Sinuswelle nicht mehr erkennen können. Die Granularität des Nachkommaergebnisses hat den stetigen Fluss der Sinuswelle in ein pseudo-zufälliges Chaos verwandelt. - -## Wir steuern das - -Zufälligkeit für die Shader-Programmierung nutzbar zu machen, kann ganz schön kompliziert sein. Manchmal ist der Zufall zu chaotisch, dann wieder nicht zufällig genug. Schau Dir den folgenden Funktionsgraphen an. Wir haben ihn mit Hilfe der ```rand()```-Funktion konstruiert, die nach eben jenem Prinzip aufgebaut ist, das wir eben beschrieben haben. - -Bei einem genauen Blick erkennst Du, dass die [```sin()```](../glossary/?search=sin)-Funktion ihren Scheitel bei ```-1.5707``` und ```1.5707``` hat. Ich wette, Du ahnst bereits warum – weil dort das Maximum und Minimum einer Sinuswelle liegt, nämlich bei *PI /2.0*. - -Außerdem wirst Du im Hinblick auf die Zufallsverteilung feststellen, dass es eine gewisse Häufung im mittleren Bereich im Vergleich zu den äußeren Bereichen gibt. - -
- -Vor einiger Zeit hat der Autor mit dem Pseudonym [Pixelero](https://pixelero.wordpress.com) einen interessanten [Artikel über Zufallsverteilungen](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) veröffentlicht. Ich habe einige der Funktionen, die er dort anspricht, in dem obigen Graphen aufgeführt. Du kannst die Kommentare in den einzelnen Zeilen entfernen, um Dir diese Funktionen und ihre Zufallsverteilung anzuschauen. - -Wenn Du den bereits zitierten Artikel von [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) liest, darfst Du nicht vergessen, das unsere ```rand()```-Funktionen deterministische Zufallswerte erzeugt, die als „pseudo-zufällig“ bezeichnet werden. Damit ist unter anderem gemeint, das beispielsweise ```rand(1.)``` immer den gleichen Wert zurückliefern wird. Pixelero geht in seinem Artikel auch auf die Funktion ```Math.random()```unter *ActionScript* ein, die beispielsweise nicht-deterministisch ist. Jeder Aufruf mit einem gegebenen Wert als Funktionsargument liefert bei ihr andere Werte zurück. - -## 2D-Zufall - -Mit diesem vertieften Verständnis von Zufall im Gepäck ist es an der Zeit, den Zufall in zwei Dimensionen wirken zu lassen – entlang der *x-Achse* und der *y-Achse*. Dafür müssen wir einen zweidimensionalen Vektor in einen eindimensionalen Fließkommawert verwandeln. Man kann dies auf verschiedenen Wegen erreichen, aber die Nutzung der [```dot()```](../glossary/?search=dot)-Funktion ist in diesem Fall besonders hilfreich. Sie liefert einen Fließkommawert zwischen ```0.0``` und ```1.0``` zurück, je nachdem wie die beiden Vektoren, deren Skalarprodukt sie bildet, zueinander stehen. - -
- -Bitte schaue Dir die *Programmzeilen 13 bis 15* an und beobachte, wie wir den ```vec2 st``` mit einem anderen (konstanten) Vektor (```vec2(12.9898,78.233)```) verknüpfen. - -* Verändere die konstanten Werte in den *Programmzeilen 14 und 15*. Beobachte, wie sich das Zufallsmuster dadurch ändert und überlege, was wir daraus lernen können. - -* Verknüpfe die Zufallsfunktion mit der Mausposition (```u_mouse```) und der Zeit (```u_time```), damit der Zufall noch weniger vorhersehbar wird. - -## Das Chaos nutzen - -Zufallswerte in zwei Dimensionen erinnern stark an das Rauschen im analogen TV, wenn das Antennensignal fehlt, nicht wahr? Als Ausgangsmaterial für die Erzeugung von Grafiken scheint es nur wenig geeignet. Aber lass uns einmal schauen, ob wir nicht doch etwas Sinnvolles damit anfangen können. - -Unser erster Schritt besteht darin, ein Gitternetz zu unterlegen. Mit Hilfe der [```floor()```](../glossary/?search=floor)-Funktion werden wir eine Integer-Tabelle der Zellen erzeugen. Schau Dir den folgenden Programmcode an, insbesondere die *Programmzeilen 22 und 23*. - -
- -Nachdem wir den Koordinatenraum in ein Gitternetz mit 10 x 10 Feldern unterteilt haben (in *Programmzeile 21*), separieren wir den Vorkommateil der jeweiligen Koordinate von ihrem Nachkommateil. Wir kennen das bereits aus der Unterteilung des Koordinatenraums in kleinere Zellen, die sich jeweils von ```0.0``` bis ```1.0``` erstrecken. Indem wir den ganzzahligen Teil der Koordinate isolieren, erhalten wir einen gemeinsamen Wert für alle Pixel innerhalb eines Feldes des Gitternetzes. Diesen Wert nutzen wir dann, um einen Zufallswert für diese Region zu generieren. Weil unsere Zufallsfunktion deterministisch ist, wird der Zufallswert für alle Bildpunkte innerhalb dieser Zelle gleich sein. - -Entferne die Kommentierung von *Programmzeile 29*, um zu beobachten, wie wir den Nachkommateil der Koordinate behalten. Dadurch können wir diesen Wert weiterhin nutzen, um innerhalb der Zellen zu zeichnen. - -Indem wir diese beiden Werte kombinieren – den Vorkomma- und den Nachkommateil der Koordinate – können wir Ordnung und Chaos zusammenbringen. - -Schau Dir einmal die GLSL-Portierung des berühmten Labyrinth-Generators in BASIC an, der dort nur aus einer einzigen Programmierzeile besteht: ```10 PRINT CHR$(205.5+RND(1)); : GOTO 10``` - -
- -Hier nutze ich die Zufallswerte der Zellen, um innerhalb der Zellen eine Linie mal in die eine, mal in die andere Richtung zu zeichnen. Ich setze dafür die ```truchetPattern()```-Funktion aus dem vorangehenden Kapitel ein (es geht um die *Programmzeilen 41 bis 47*). - -Du erhältst ein sehenswertes animiertes Muster, wenn Du die Kommentarzeichen aus den *Programmzeilen 35 und 36* entfernst. - -## Meister des Zufalls - -[Ryoji Ikeda](http://www.ryojiikeda.com/), ein japanischer Komponist elektronischer Musik und Grafikkünstler, ist ein Meister des Zufälligen. Es fällt schwer, von seinen Arbeiten nicht berührt zu werden. Der Einsatz des Zufalls in seinen Werken ist so gestaltet, dass nicht verwirrendes Chaos, sondern ein Abbild der Komplexität unserer technischen Kultur entsteht. - - - -Schau Dir die Arbeiten von [Ikeda](http://www.ryojiikeda.com/) an und versuche Dich an den folgenden Aufgaben: - -* Erzeuge Zeilen sich gegenläufig bewegender Zellen mit Farben aus Zufallswerten. Stelle nur die Zellen mit helleren Werten dar. Lasse sich die Geschwindigkeit der Bewegung im Laufe der Zeit verändern. - - - -* Erzeuge auf ganz ähnliche Weise mehrere Zeilen, von denen sich jede mit unterschiedlicher Geschwindigkeit und Richtung seitwärts bewegt. Verknüpfe die Mausposition mit dem Schwellenwert für die Anzeige der Zellen aufgrund ihrer Helligkeit. - - - -* Erzeuge weitere interessante Effekte, bei denen der Zufall eine Rolle spielt. - - - -Zufallswerte auf ästhetische Art und Weise einzusetzen, kann schwierig sein, besonders wenn man Simulationen erstellen möchten, die die Natur nachahmen. Zufall ist einfach zu chaotisch und nur sehr wenige Dinge ums uns herum entstehen wirklich komplett zufällig. Wenn Du Dir beispielsweise das Muster von Regentropfen oder den Verlauf eines Aktienkurses anschaust – zwei Vorgänge, die Beide sicherlich eine Menge mit Zufall zu tun haben – wirst Du eben doch kein Chaos, sondern komplexe Strukturen und Abhängigkeiten erkennen. Schließlich sind hier jenseits des Zufälligen immer auch systemabhängige Korrelationen und ein Bezug auf vorherige Systemzustände am Werk. - -Das nächste Kapitel beschäftigt sich deshalb mit Rauschen, dem sanften und der Natur nachempfunden Weg, um Dinge dynamisch und innerhalb des Chaotischen auch ein wenig strukturiert wirken zu lassen. - +# Generative Designs + +Nachdem wir in den vorangegangenen Kapiteln so viel über Wiederholungen und wohlgeformte Ordnungen gelernt haben, ist es nur konsequent, nun eine kleine Exkursion in das Reich des Chaotischen zu unternehmen. + +## Zufall + +[![Ryoji Ikeda – Testmuster (2008) ](ryoji-ikeda.jpg) ](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set) + +Zufälligkeit ist der konsequenteste Ausdruck von Entropie. Doch wie können wir Zufälle innerhalb einer so vorhersehbaren Umgebung wie die der Programmiersprache GLSL erzeugen? + +Lass uns damit beginnen, die folgende Funktion zu analysieren: + +
+ +Oben sehen wir das Ergebnis, wenn man nur den Nachkommateil der Werte einer *Standardsinuskurve* betrachtet. Die Funktionswerte von [```sin()```](../glossary/?search=sin) oszillieren zwischen ```-1.0``` und ```1.0```. Hier wurde der Vorkommateil abgeschnitten, so dass wir es nur noch mit positiven Werten zwischen ```0.0``` und ```0.99999999...``` zu tun haben. Wir können diesen Effekt nutzen, um „pseudo-zufällige“ Zahlen zu generieren, indem wir die Sinuswelle in kleine Teilstücke „aufbrechen“. Wie das geht? Indem wir das Resultat von [```sin(x)```](../glossary/?search=sin) mit großen Zahlen multiplizieren. Füge dem Faktor ```1.0``` in der obigen Formel einfach ein paar Nullen vor dem Komma hinzu – eine nach der anderen – und beobachte die Auswirkungen auf den Funktionsgraphen. + +Spätestens, wenn Du bei ```100000.0``` angekommen bist (und die Formel so aussieht ```y = fract(sin(x)*100000.0)``` ), wirst Du die zugrundeliegende Sinuswelle nicht mehr erkennen können. Die Granularität des Nachkommaergebnisses hat den stetigen Fluss der Sinuswelle in ein pseudo-zufälliges Chaos verwandelt. + +## Wir steuern das + +Zufälligkeit für die Shader-Programmierung nutzbar zu machen, kann ganz schön kompliziert sein. Manchmal ist der Zufall zu chaotisch, dann wieder nicht zufällig genug. Schau Dir den folgenden Funktionsgraphen an. Wir haben ihn mit Hilfe der ```rand()```-Funktion konstruiert, die nach eben jenem Prinzip aufgebaut ist, das wir eben beschrieben haben. + +Bei einem genauen Blick erkennst Du, dass die [```sin()```](../glossary/?search=sin)-Funktion ihren Scheitel bei ```-1.5707``` und ```1.5707``` hat. Ich wette, Du ahnst bereits warum – weil dort das Maximum und Minimum einer Sinuswelle liegt, nämlich bei *PI /2.0*. + +Außerdem wirst Du im Hinblick auf die Zufallsverteilung feststellen, dass es eine gewisse Häufung im mittleren Bereich im Vergleich zu den äußeren Bereichen gibt. + +
+ +Vor einiger Zeit hat der Autor mit dem Pseudonym [Pixelero](https://pixelero.wordpress.com) einen interessanten [Artikel über Zufallsverteilungen](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) veröffentlicht. Ich habe einige der Funktionen, die er dort anspricht, in dem obigen Graphen aufgeführt. Du kannst die Kommentare in den einzelnen Zeilen entfernen, um Dir diese Funktionen und ihre Zufallsverteilung anzuschauen. + +Wenn Du den bereits zitierten Artikel von [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) liest, darfst Du nicht vergessen, das unsere ```rand()```-Funktionen deterministische Zufallswerte erzeugt, die als „pseudo-zufällig“ bezeichnet werden. Damit ist unter anderem gemeint, das beispielsweise ```rand(1.)``` immer den gleichen Wert zurückliefern wird. Pixelero geht in seinem Artikel auch auf die Funktion ```Math.random()```unter *ActionScript* ein, die beispielsweise nicht-deterministisch ist. Jeder Aufruf mit einem gegebenen Wert als Funktionsargument liefert bei ihr andere Werte zurück. + +## 2D-Zufall + +Mit diesem vertieften Verständnis von Zufall im Gepäck ist es an der Zeit, den Zufall in zwei Dimensionen wirken zu lassen – entlang der *x-Achse* und der *y-Achse*. Dafür müssen wir einen zweidimensionalen Vektor in einen eindimensionalen Fließkommawert verwandeln. Man kann dies auf verschiedenen Wegen erreichen, aber die Nutzung der [```dot()```](../glossary/?search=dot)-Funktion ist in diesem Fall besonders hilfreich. Sie liefert einen Fließkommawert zwischen ```0.0``` und ```1.0``` zurück, je nachdem wie die beiden Vektoren, deren Skalarprodukt sie bildet, zueinander stehen. + +
+ +Bitte schaue Dir die *Programmzeilen 13 bis 15* an und beobachte, wie wir den ```vec2 st``` mit einem anderen (konstanten) Vektor (```vec2(12.9898,78.233)```) verknüpfen. + +* Verändere die konstanten Werte in den *Programmzeilen 14 und 15*. Beobachte, wie sich das Zufallsmuster dadurch ändert und überlege, was wir daraus lernen können. + +* Verknüpfe die Zufallsfunktion mit der Mausposition (```u_mouse```) und der Zeit (```u_time```), damit der Zufall noch weniger vorhersehbar wird. + +## Das Chaos nutzen + +Zufallswerte in zwei Dimensionen erinnern stark an das Rauschen im analogen TV, wenn das Antennensignal fehlt, nicht wahr? Als Ausgangsmaterial für die Erzeugung von Grafiken scheint es nur wenig geeignet. Aber lass uns einmal schauen, ob wir nicht doch etwas Sinnvolles damit anfangen können. + +Unser erster Schritt besteht darin, ein Gitternetz zu unterlegen. Mit Hilfe der [```floor()```](../glossary/?search=floor)-Funktion werden wir eine Integer-Tabelle der Zellen erzeugen. Schau Dir den folgenden Programmcode an, insbesondere die *Programmzeilen 22 und 23*. + +
+ +Nachdem wir den Koordinatenraum in ein Gitternetz mit 10 x 10 Feldern unterteilt haben (in *Programmzeile 21*), separieren wir den Vorkommateil der jeweiligen Koordinate von ihrem Nachkommateil. Wir kennen das bereits aus der Unterteilung des Koordinatenraums in kleinere Zellen, die sich jeweils von ```0.0``` bis ```1.0``` erstrecken. Indem wir den ganzzahligen Teil der Koordinate isolieren, erhalten wir einen gemeinsamen Wert für alle Pixel innerhalb eines Feldes des Gitternetzes. Diesen Wert nutzen wir dann, um einen Zufallswert für diese Region zu generieren. Weil unsere Zufallsfunktion deterministisch ist, wird der Zufallswert für alle Bildpunkte innerhalb dieser Zelle gleich sein. + +Entferne die Kommentierung von *Programmzeile 29*, um zu beobachten, wie wir den Nachkommateil der Koordinate behalten. Dadurch können wir diesen Wert weiterhin nutzen, um innerhalb der Zellen zu zeichnen. + +Indem wir diese beiden Werte kombinieren – den Vorkomma- und den Nachkommateil der Koordinate – können wir Ordnung und Chaos zusammenbringen. + +Schau Dir einmal die GLSL-Portierung des berühmten Labyrinth-Generators in BASIC an, der dort nur aus einer einzigen Programmierzeile besteht: ```10 PRINT CHR$(205.5+RND(1)); : GOTO 10``` + +
+ +Hier nutze ich die Zufallswerte der Zellen, um innerhalb der Zellen eine Linie mal in die eine, mal in die andere Richtung zu zeichnen. Ich setze dafür die ```truchetPattern()```-Funktion aus dem vorangehenden Kapitel ein (es geht um die *Programmzeilen 41 bis 47*). + +Du erhältst ein sehenswertes animiertes Muster, wenn Du die Kommentarzeichen aus den *Programmzeilen 35 und 36* entfernst. + +## Meister des Zufalls + +[Ryoji Ikeda](http://www.ryojiikeda.com/), ein japanischer Komponist elektronischer Musik und Grafikkünstler, ist ein Meister des Zufälligen. Es fällt schwer, von seinen Arbeiten nicht berührt zu werden. Der Einsatz des Zufalls in seinen Werken ist so gestaltet, dass nicht verwirrendes Chaos, sondern ein Abbild der Komplexität unserer technischen Kultur entsteht. + + + +Schau Dir die Arbeiten von [Ikeda](http://www.ryojiikeda.com/) an und versuche Dich an den folgenden Aufgaben: + +* Erzeuge Zeilen sich gegenläufig bewegender Zellen mit Farben aus Zufallswerten. Stelle nur die Zellen mit helleren Werten dar. Lasse sich die Geschwindigkeit der Bewegung im Laufe der Zeit verändern. + + + +* Erzeuge auf ganz ähnliche Weise mehrere Zeilen, von denen sich jede mit unterschiedlicher Geschwindigkeit und Richtung seitwärts bewegt. Verknüpfe die Mausposition mit dem Schwellenwert für die Anzeige der Zellen aufgrund ihrer Helligkeit. + + + +* Erzeuge weitere interessante Effekte, bei denen der Zufall eine Rolle spielt. + + + +Zufallswerte auf ästhetische Art und Weise einzusetzen, kann schwierig sein, besonders wenn man Simulationen erstellen möchten, die die Natur nachahmen. Zufall ist einfach zu chaotisch und nur sehr wenige Dinge ums uns herum entstehen wirklich komplett zufällig. Wenn Du Dir beispielsweise das Muster von Regentropfen oder den Verlauf eines Aktienkurses anschaust – zwei Vorgänge, die Beide sicherlich eine Menge mit Zufall zu tun haben – wirst Du eben doch kein Chaos, sondern komplexe Strukturen und Abhängigkeiten erkennen. Schließlich sind hier jenseits des Zufälligen immer auch systemabhängige Korrelationen und ein Bezug auf vorherige Systemzustände am Werk. + +Das nächste Kapitel beschäftigt sich deshalb mit Rauschen, dem sanften und der Natur nachempfunden Weg, um Dinge dynamisch und innerhalb des Chaotischen auch ein wenig strukturiert wirken zu lassen. diff --git a/10/README-it.md b/10/README-it.md index 650da8b..3cac2a8 100644 --- a/10/README-it.md +++ b/10/README-it.md @@ -1,92 +1,92 @@ -# Progettazione generativa - -Non è una sorpresa che dopo aver passato tanto tempo a organizzare e a definire precisamente le cose, l'autore voglia introdurre un po' di caos. - -## Random - -[![Ryoji Ikeda - test pattern (2008) ](ryoji-ikeda.jpg) ](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set) - -La casualità è la massima espressione d'entropia. Come possiamo generare casualità all'interno di un ambiente apparentemente prevedibile e rigido? - -Iniziamo analizzando la seguente funzione: - -
- -Qui sopra abbiamo estratto il contenuto frazionario di una sinusoide. I valori di [```sin()```](../glossary/?search=sin) che oscillano tra ```-1.0``` e ```1.0``` sono stati tagliati dopo la virgola mobile, restituendo tutti i valori positivi tra ```0.0``` e ```1.0```. Possiamo usare questo effetto per ottenere alcuni valori pseudo-casuali per "rompere" questa onda sinusoidale in pezzi più piccoli. Come? Moltiplicando la risultante di [```sin(x)```](../glossary/?search=sin) con numeri più grandi. Provate ad aggiungere alcuni zeri alla funzione qui sopra. - -Arrivando a ```100000.0``` ( l'equazione si presenta così: ```y = fract(sin(x)*100000.0)``` ) non si è più in grado di distinguere l'onda sinusoidale. La granularità della parte frazionaria ha corrotto il flusso della sinusoide al punto di trasformarla in caos pseudo-casuale. - -## Controllare il caos - -L'utilizzo della casualità può essere difficile; è sia troppo caotica e a volte non abbastanza casuale. Date un'occhiata al grafico seguente. Per farlo, stiamo utilizzando una funzione ```rand()``` che viene implementata esattamente come si è descritto in precedenza. - -Dando uno sguardo più da vicino, si può vedere i picchi dell'onda di [```sin()```](../glossary/?search=sin) sono fra ```-1.5707``` e ```1.5707```. Scommetto che ora sapete il perché: è dove la sinusoide raggiunge i suoi valori massimi e minimi. - -Se guardate la distribuzione del funzione random, si nota che vi è una certa concentrazione intorno a 0.5 rispetto che a 0.0 e 1.0. - -
- -Qualche tempo fa [Pixelero](https://pixelero.wordpress.com) ha pubblicato un [interessante articolo sulla distribuzione random](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/). Ho aggiunto per voi alcune delle funzioni che ha usato nel grafico precedente per vedere come la distribuzione può essere modificata. Decommentate le funzioni e guardate cosa succede. - -Se andate a leggere [l'articolo di Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/), è importante tenere a mente che la nostra funzione ```rand()``` è deterministica casuale, in altre parole pseudo-casuale. Il che significa, per esempio, che ```rand(1.)``` restituisce sempre lo stesso valore. [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) fa riferimento alla funzione ActionScript ```Math.random()``` che è non-deterministica; cioè ogni chiamata restituirà un valore diverso. - -## 2D Random - -Ora che abbiamo una migliore comprensione della casualità, è il momento d'applicarla alle dimensioni ```x``` e ```y```. Per fare ciò abbiamo bisogno di trasformare un vettore di due dimensioni in un float unidimensionale. Ci sono diversi modi per farlo, ma la funzione [```dot()```](../glossary/?search=dot) è particolarmente utile in questo caso. Questa funzione restituisce un singolo valore decimale compreso tra ```0.0``` e ```1.0``` a seconda dell'allineamento dei due vettori. - -
- -Date un'occhiata al codice a partire della linea 13 fino alla 15 e noterete come stiamo confrontando il ```vec2 st``` con un altro vettore a due dimensioni (```vec2(12.9898,78.233)```). - -* Provate a cambiare i valori delle linee 14 e 15. Vedrete come i pattern random cambiano e provate a trarne una conclusione. - -* Collegate questa funzione random alla posizione del mouse (```u_mouse```) e al tempo (```u_time```) per capire meglio il suo funzionamento. - -## Usare il caos - -Il random in due dimensioni assomiglia molto al rumore TV, giusto? Si tratta di un materiale grezzo difficile da usare se si vuole comporre delle immagini. Impariamo come usarlo. - -Il primo passo è quello di applicargli una griglia; usando la funzione [```floor()```](../glossary/?search=floor) saremo in grado di generare una tabella di celle composta da integer. Date un'occhiata al seguente codice, in particolare alle linee 22 e 23. - -
- -Dopo il ridimensionamento dello spazio per 10 (alla linea 21), separiamo dalla parte frazionaria i numeri interi delle coordinate. Abbiamo una certa familiarità con questa ultima operazione, perché l'abbiamo utilizzata per suddividere lo spazio in celle più piccole che vanno da ```0.0``` a ```1.0```. Il valore intero della coordinata è un valore comune per una regione di pixel, che sarà simile a una singola cella. Quindi possiamo usare che il valore intero in comune per ottenere un valore random per quella zona. Poiché la nostra funzione random è deterministica, il valore restituito sarà costante per tutti i pixel in quella cella. - -Rimuovete il commento alla linea 29 per mantenere la parte float della coordinata, in modo da poterla usare come un sistema di coordinate per disegnare delle cose all'interno di ogni cellula. - -Se combinate questi due valori - la parte intera e la parte frazionaria della coordinata - sarete in grado di mixare variabilità e ordine. - -Date un'occhiata all'implementazione del famoso generatore di labirinti ```10 PRINT CHR$(205.5+RND(1)); : GOTO 10``` . - -
- -Qui sto usando i valori random delle celle per disegnare una linea in una direzione o nell'altra utilizzando la funzione ```truchetPattern()``` del capitolo precedente (linee da 41 a 47). - -È possibile ottenere un altro pattern interessante decommentando il blocco di righe tra la linea 50 a 53, o animare il pattern decommentando le linee 35 e 36. - -## Padroneggiare il Random - -[Ryoji Ikeda](http://www.ryojiikeda.com/), compositore elettronico e artista visivo giapponese, è diventato un maestro nell'uso del random; è difficile non essere colpiti ed ipnotizzati dal suo lavoro. Nelle sue opere d'arte audio e visive è riuscito ad utilizzare la casualità in modo tale da non ottenere un fastidioso caos, ma uno specchio della complessità della nostra cultura tecnologica. - - - -Date un'occhiata al lavoro di [Ikeda](http://www.ryojiikeda.com/) e provate i seguenti esercizi: - -* Create delle righe di celle in movimento (in direzioni opposte) con valori random. Mostrate solo le celle con valori più luminosi. Provate a rendere costante nel tempo la velocità delle righe. - - - -* Fate la stessa cosa con varie righe ma ogni volta con velocità e direzione diverse. Collegate la posizione del mouse alla soglia per decidere quale celle visualizzare. - - - -* Creare altri effetti interessanti. - - - -L'utilizzo del random può essere problematico dal punto di vista estetico, soprattutto se si vuole creare simulazioni che sembrano naturali. Il random è semplicemente troppo caotico e poche cose nella vita di tutti i giorni sembrano ```random()```. Se si considera un pattern generato dalla pioggia o un grafico azionario, che sono entrambi abbastanza casuali, questi non assomigliano per niente al pattern random che abbiamo fatto all'inizio di questo capitolo. La ragione? Beh, i valori random non hanno alcuna correlazione tra di loro e la maggior parte dei motivi naturali conserva una certa memoria dello stato precedente. - -Nel prossimo capitolo impareremo di più a proposito del rumore, una maniera semplice e dall'*aspetto naturale* di creare il caos computazionale. +# Progettazione generativa + +Non è una sorpresa che dopo aver passato tanto tempo a organizzare e a definire precisamente le cose, l'autore voglia introdurre un po' di caos. + +## Random + +[![Ryoji Ikeda - test pattern (2008) ](ryoji-ikeda.jpg) ](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set) + +La casualità è la massima espressione d'entropia. Come possiamo generare casualità all'interno di un ambiente apparentemente prevedibile e rigido? + +Iniziamo analizzando la seguente funzione: + +
+ +Qui sopra abbiamo estratto il contenuto frazionario di una sinusoide. I valori di [```sin()```](../glossary/?search=sin) che oscillano tra ```-1.0``` e ```1.0``` sono stati tagliati dopo la virgola mobile, restituendo tutti i valori positivi tra ```0.0``` e ```1.0```. Possiamo usare questo effetto per ottenere alcuni valori pseudo-casuali per "rompere" questa onda sinusoidale in pezzi più piccoli. Come? Moltiplicando la risultante di [```sin(x)```](../glossary/?search=sin) con numeri più grandi. Provate ad aggiungere alcuni zeri alla funzione qui sopra. + +Arrivando a ```100000.0``` ( l'equazione si presenta così: ```y = fract(sin(x)*100000.0)``` ) non si è più in grado di distinguere l'onda sinusoidale. La granularità della parte frazionaria ha corrotto il flusso della sinusoide al punto di trasformarla in caos pseudo-casuale. + +## Controllare il caos + +L'utilizzo della casualità può essere difficile; è sia troppo caotica e a volte non abbastanza casuale. Date un'occhiata al grafico seguente. Per farlo, stiamo utilizzando una funzione ```rand()``` che viene implementata esattamente come si è descritto in precedenza. + +Dando uno sguardo più da vicino, si può vedere i picchi dell'onda di [```sin()```](../glossary/?search=sin) sono fra ```-1.5707``` e ```1.5707```. Scommetto che ora sapete il perché: è dove la sinusoide raggiunge i suoi valori massimi e minimi. + +Se guardate la distribuzione del funzione random, si nota che vi è una certa concentrazione intorno a 0.5 rispetto che a 0.0 e 1.0. + +
+ +Qualche tempo fa [Pixelero](https://pixelero.wordpress.com) ha pubblicato un [interessante articolo sulla distribuzione random](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/). Ho aggiunto per voi alcune delle funzioni che ha usato nel grafico precedente per vedere come la distribuzione può essere modificata. Decommentate le funzioni e guardate cosa succede. + +Se andate a leggere [l'articolo di Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/), è importante tenere a mente che la nostra funzione ```rand()``` è deterministica casuale, in altre parole pseudo-casuale. Il che significa, per esempio, che ```rand(1.)``` restituisce sempre lo stesso valore. [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) fa riferimento alla funzione ActionScript ```Math.random()``` che è non-deterministica; cioè ogni chiamata restituirà un valore diverso. + +## 2D Random + +Ora che abbiamo una migliore comprensione della casualità, è il momento d'applicarla alle dimensioni ```x``` e ```y```. Per fare ciò abbiamo bisogno di trasformare un vettore di due dimensioni in un float unidimensionale. Ci sono diversi modi per farlo, ma la funzione [```dot()```](../glossary/?search=dot) è particolarmente utile in questo caso. Questa funzione restituisce un singolo valore decimale compreso tra ```0.0``` e ```1.0``` a seconda dell'allineamento dei due vettori. + +
+ +Date un'occhiata al codice a partire della linea 13 fino alla 15 e noterete come stiamo confrontando il ```vec2 st``` con un altro vettore a due dimensioni (```vec2(12.9898,78.233)```). + +* Provate a cambiare i valori delle linee 14 e 15. Vedrete come i pattern random cambiano e provate a trarne una conclusione. + +* Collegate questa funzione random alla posizione del mouse (```u_mouse```) e al tempo (```u_time```) per capire meglio il suo funzionamento. + +## Usare il caos + +Il random in due dimensioni assomiglia molto al rumore TV, giusto? Si tratta di un materiale grezzo difficile da usare se si vuole comporre delle immagini. Impariamo come usarlo. + +Il primo passo è quello di applicargli una griglia; usando la funzione [```floor()```](../glossary/?search=floor) saremo in grado di generare una tabella di celle composta da integer. Date un'occhiata al seguente codice, in particolare alle linee 22 e 23. + +
+ +Dopo il ridimensionamento dello spazio per 10 (alla linea 21), separiamo dalla parte frazionaria i numeri interi delle coordinate. Abbiamo una certa familiarità con questa ultima operazione, perché l'abbiamo utilizzata per suddividere lo spazio in celle più piccole che vanno da ```0.0``` a ```1.0```. Il valore intero della coordinata è un valore comune per una regione di pixel, che sarà simile a una singola cella. Quindi possiamo usare che il valore intero in comune per ottenere un valore random per quella zona. Poiché la nostra funzione random è deterministica, il valore restituito sarà costante per tutti i pixel in quella cella. + +Rimuovete il commento alla linea 29 per mantenere la parte float della coordinata, in modo da poterla usare come un sistema di coordinate per disegnare delle cose all'interno di ogni cellula. + +Se combinate questi due valori - la parte intera e la parte frazionaria della coordinata - sarete in grado di mixare variabilità e ordine. + +Date un'occhiata all'implementazione del famoso generatore di labirinti ```10 PRINT CHR$(205.5+RND(1)); : GOTO 10``` . + +
+ +Qui sto usando i valori random delle celle per disegnare una linea in una direzione o nell'altra utilizzando la funzione ```truchetPattern()``` del capitolo precedente (linee da 41 a 47). + +È possibile ottenere un altro pattern interessante decommentando il blocco di righe tra la linea 50 a 53, o animare il pattern decommentando le linee 35 e 36. + +## Padroneggiare il Random + +[Ryoji Ikeda](http://www.ryojiikeda.com/), compositore elettronico e artista visivo giapponese, è diventato un maestro nell'uso del random; è difficile non essere colpiti ed ipnotizzati dal suo lavoro. Nelle sue opere d'arte audio e visive è riuscito ad utilizzare la casualità in modo tale da non ottenere un fastidioso caos, ma uno specchio della complessità della nostra cultura tecnologica. + + + +Date un'occhiata al lavoro di [Ikeda](http://www.ryojiikeda.com/) e provate i seguenti esercizi: + +* Create delle righe di celle in movimento (in direzioni opposte) con valori random. Mostrate solo le celle con valori più luminosi. Provate a rendere costante nel tempo la velocità delle righe. + + + +* Fate la stessa cosa con varie righe ma ogni volta con velocità e direzione diverse. Collegate la posizione del mouse alla soglia per decidere quale celle visualizzare. + + + +* Creare altri effetti interessanti. + + + +L'utilizzo del random può essere problematico dal punto di vista estetico, soprattutto se si vuole creare simulazioni che sembrano naturali. Il random è semplicemente troppo caotico e poche cose nella vita di tutti i giorni sembrano ```random()```. Se si considera un pattern generato dalla pioggia o un grafico azionario, che sono entrambi abbastanza casuali, questi non assomigliano per niente al pattern random che abbiamo fatto all'inizio di questo capitolo. La ragione? Beh, i valori random non hanno alcuna correlazione tra di loro e la maggior parte dei motivi naturali conserva una certa memoria dello stato precedente. + +Nel prossimo capitolo impareremo di più a proposito del rumore, una maniera semplice e dall'*aspetto naturale* di creare il caos computazionale. diff --git a/10/README.md b/10/README.md index 6eccb69..28da45d 100644 --- a/10/README.md +++ b/10/README.md @@ -18,9 +18,9 @@ By the time you get to ```100000.0``` ( and the equation looks like this: ```y = ## Controlling chaos -Using random can be hard; it is both too chaotic and sometimes not random enough. Take a look at the following graph. To make it, we are using a ```rand()``` function which is implemented exactly like we describe above. +Using random can be hard; it is both too chaotic and sometimes not random enough. Take a look at the following graph. To make it, we are using a ```rand()``` function which is implemented exactly like we describe above. -Taking a closer look, you can see the [```sin()```](../glossary/?search=sin) wave crest at ```-1.5707``` and ```1.5707```. I bet you now understand why - it's where the maximum and minimum of the sine wave happens. +Taking a closer look, you can see the [```sin()```](../glossary/?search=sin) wave crest at ```-1.5707``` and ```1.5707```. I bet you now understand why - it's where the maximum and minimum of the sine wave happens. If look closely at the random distribution, you will note that the there is some concentration around the middle compared to the edges. @@ -41,7 +41,7 @@ Now that we have a better understanding of randomness, it's time to apply it in Take a look at lines 13 to 15 and notice how we are comparing the ```vec2 st``` with another two dimensional vector ( ```vec2(12.9898,78.233)```). -* Try changing the values on lines 14 and 15. See how the random pattern changes and think about what we can learn from this. +* Try changing the values on lines 14 and 15. See how the random pattern changes and think about what we can learn from this. * Hook this random function to the mouse interaction (```u_mouse```) and time (```u_time```) to understand better how it works. @@ -65,7 +65,7 @@ Take a look at this GLSL port of the famouse ```10 PRINT CHR$(205.5+RND(1)); : G Here I'm using the random values of the cells to draw a line in one direction or the other using the ```truchetPattern()``` function from the previous chapter (lines 41 to 47). -You can get another interesting pattern by uncommenting the block of lines between 50 to 53, or animate the pattern by uncommenting lines 35 and 36. +You can get another interesting pattern by uncommenting the block of lines between 50 to 53, or animate the pattern by uncommenting lines 35 and 36. ## Master Random @@ -87,6 +87,6 @@ Take a look at [Ikeda](http://www.ryojiikeda.com/)'s work and try the following -Using random aesthetically can be problematic, especially if you want to make natural-looking simulations. Random is simply too chaotic and very few things look ```random()``` in real life. If you look at a rain pattern or a stock chart, which are both quite random, they are nothing like the random pattern we made at the begining of this chapter. The reason? Well, random values have no correlation between them what so ever, but most natural patterns have some memory of the previous state. +Using random aesthetically can be problematic, especially if you want to make natural-looking simulations. Random is simply too chaotic and very few things look ```random()``` in real life. If you look at a rain pattern or a stock chart, which are both quite random, they are nothing like the random pattern we made at the begining of this chapter. The reason? Well, random values have no correlation between them what so ever, but most natural patterns have some memory of the previous state. -In the next chapter we will learn about noise, the smooth and *natural looking* way of creating computational chaos. +In the next chapter we will learn about noise, the smooth and *natural looking* way of creating computational chaos. diff --git a/10/iching-02.frag b/10/iching-02.frag index 25ed526..47d8f2c 100644 --- a/10/iching-02.frag +++ b/10/iching-02.frag @@ -72,10 +72,10 @@ void main(){ st *= 10.0; vec2 fpos = fract(st); vec2 ipos = floor(st); - + float t = u_time*5.0; float df = 1.0; df = hex(fpos,ipos.x+ipos.y+t*random(ipos))+(1.0-rect(fpos,vec2(0.7))); gl_FragColor = vec4(mix(vec3(0.),vec3(1.),step(0.7,df)),1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-00.frag b/10/ikeda-00.frag index 4d5f000..561e65b 100644 --- a/10/ikeda-00.frag +++ b/10/ikeda-00.frag @@ -13,7 +13,7 @@ float random (in float x) { return fract(sin(x)*1e4); } -float random (in vec2 st) { +float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123); } @@ -24,7 +24,7 @@ float randomSerie(float x, float freq, float t) { void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec3 color = vec3(0.0); float cols = 2.; @@ -43,4 +43,4 @@ void main() { randomSerie(st.x, freq*100., t-offset)); gl_FragColor = vec4(1.0-color,1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-01.frag b/10/ikeda-01.frag index 2803b95..85c6d85 100644 --- a/10/ikeda-01.frag +++ b/10/ikeda-01.frag @@ -15,7 +15,7 @@ float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec3 color = vec3(0.0); vec2 grid = vec2(100.0,2.0); @@ -33,4 +33,4 @@ void main() { color += step(fpos.y*1.5,value); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-02.frag b/10/ikeda-02.frag index 9ca1bea..1c94555 100644 --- a/10/ikeda-02.frag +++ b/10/ikeda-02.frag @@ -20,13 +20,13 @@ void main() { vec2 ipos = floor(st); // integer vec2 fpos = fract(st); // fraction - + vec2 vel = floor(vec2(u_time*10.)); // time vel *= vec2(-1.,0.); // direction vel *= (step(1., mod(ipos.y,2.0))-0.5)*2.; // Oposite directions vel *= random(ipos.y); // random speed - + // Move ipos += floor(vel); // Assign a random value base on the integer coord @@ -37,4 +37,4 @@ void main() { pct = step(0.001+u_mouse.x/u_resolution.x,pct); // threshold gl_FragColor = vec4(vec3(pct),1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-03.frag b/10/ikeda-03.frag index 6545020..b8d2d31 100644 --- a/10/ikeda-03.frag +++ b/10/ikeda-03.frag @@ -13,7 +13,7 @@ float random (in float x) { return fract(sin(x)*1e4); } -float random (in vec2 st) { +float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123); } @@ -28,10 +28,10 @@ void main() { vec2 grid = vec2(100.0,50.); st *= grid; - + vec2 ipos = floor(st); // integer vec2 fpos = fract(st); // fraction - + vec2 vel = vec2(u_time*2.*max(grid.x,grid.y)); // time vel *= vec2(-1.,0.0) * random(1.0+ipos.y); // direction @@ -47,4 +47,4 @@ void main() { color *= step(0.2,fpos.y); gl_FragColor = vec4(1.0-color,1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-04.frag b/10/ikeda-04.frag index c25d68c..a88fdba 100644 --- a/10/ikeda-04.frag +++ b/10/ikeda-04.frag @@ -21,13 +21,13 @@ void main() { st *= grid; vec2 ipos = floor(st); // integer - + vec2 vel = floor(vec2(u_time*10.)); // time vel *= vec2(-1.,0.); // direction vel *= (step(1., mod(ipos.y,2.0))-0.5)*2.; // Oposite directions vel *= random(ipos.y); // random speed - + // 100% float totalCells = grid.x*grid.y; float t = mod(u_time*max(grid.x,grid.y)+floor(1.0+u_time*u_mouse.y),totalCells); @@ -52,4 +52,4 @@ void main() { color *= step(.1,fract(st.x+vel.x))*step(.1,fract(st.y+vel.y)); gl_FragColor = vec4(1.0-color,1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-digits.frag b/10/ikeda-digits.frag index e209e75..f20b824 100644 --- a/10/ikeda-digits.frag +++ b/10/ikeda-digits.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; @@ -34,15 +34,15 @@ float char(vec2 st, float n){ n = floor(mod(n,10.)); float digit = 0.0; - if (n < 1. ) { digit = 31600.; } - else if (n < 2. ) { digit = 9363.0; } - else if (n < 3. ) { digit = 31184.0; } - else if (n < 4. ) { digit = 31208.0; } - else if (n < 5. ) { digit = 23525.0; } - else if (n < 6. ) { digit = 29672.0; } - else if (n < 7. ) { digit = 29680.0; } - else if (n < 8. ) { digit = 31013.0; } - else if (n < 9. ) { digit = 31728.0; } + if (n < 1. ) { digit = 31600.; } + else if (n < 2. ) { digit = 9363.0; } + else if (n < 3. ) { digit = 31184.0; } + else if (n < 4. ) { digit = 31208.0; } + else if (n < 5. ) { digit = 23525.0; } + else if (n < 6. ) { digit = 29672.0; } + else if (n < 7. ) { digit = 29680.0; } + else if (n < 8. ) { digit = 31013.0; } + else if (n < 9. ) { digit = 31728.0; } else if (n < 10. ) { digit = 31717.0; } float pct = bin(ipos, digit); @@ -67,4 +67,4 @@ void main(){ color = mix(color,vec3(color.r,0.,0.),step(.99,pct)); gl_FragColor = vec4( color , 1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-numered-grid.frag b/10/ikeda-numered-grid.frag index f95bc72..d53635f 100644 --- a/10/ikeda-numered-grid.frag +++ b/10/ikeda-numered-grid.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; @@ -34,15 +34,15 @@ float char(vec2 st, float n){ n = floor(mod(n,10.)); float digit = 0.0; - if (n < 1. ) { digit = 31600.; } - else if (n < 2. ) { digit = 9363.0; } - else if (n < 3. ) { digit = 31184.0; } - else if (n < 4. ) { digit = 31208.0; } - else if (n < 5. ) { digit = 23525.0; } - else if (n < 6. ) { digit = 29672.0; } - else if (n < 7. ) { digit = 29680.0; } - else if (n < 8. ) { digit = 31013.0; } - else if (n < 9. ) { digit = 31728.0; } + if (n < 1. ) { digit = 31600.; } + else if (n < 2. ) { digit = 9363.0; } + else if (n < 3. ) { digit = 31184.0; } + else if (n < 4. ) { digit = 31208.0; } + else if (n < 5. ) { digit = 23525.0; } + else if (n < 6. ) { digit = 29672.0; } + else if (n < 7. ) { digit = 29680.0; } + else if (n < 8. ) { digit = 31013.0; } + else if (n < 9. ) { digit = 31728.0; } else if (n < 10. ) { digit = 31717.0; } float pct = bin(ipos, digit); @@ -79,7 +79,7 @@ void main(){ st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(0.0); - + // Grid vec2 grid_st = st*300.; color += vec3(0.5,0.,0.)*grid(grid_st,0.01); @@ -108,4 +108,4 @@ void main(){ color += vec3(char(digits_st_f,100.*pct)); } gl_FragColor = vec4( color , 1.0); -} \ No newline at end of file +} diff --git a/10/ikeda-simple-grid.frag b/10/ikeda-simple-grid.frag index a749e51..8bf293b 100644 --- a/10/ikeda-simple-grid.frag +++ b/10/ikeda-simple-grid.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; @@ -37,7 +37,7 @@ void main(){ st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(0.0); - + // Grid vec2 grid_st = st*300.; color += vec3(0.5,0.,0.)*grid(grid_st,0.01); @@ -59,4 +59,4 @@ void main(){ color.rgb += step(0.9,random(blocks_st+time_i))*(1.0-time_f); gl_FragColor = vec4( color , 1.0); -} \ No newline at end of file +} diff --git a/10/index.php b/10/index.php index b57b66f..d693fb9 100644 --- a/10/index.php +++ b/10/index.php @@ -1,4 +1,4 @@ -< < Previous - + '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/10/matrix.frag b/10/matrix.frag index e24e0a1..248872e 100644 --- a/10/matrix.frag +++ b/10/matrix.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; @@ -41,4 +41,4 @@ void main(){ color = vec3(pct); gl_FragColor = vec4( color , 1.0); -} \ No newline at end of file +} diff --git a/10/notes.md b/10/notes.md index 5226ebb..cfb17ae 100644 --- a/10/notes.md +++ b/10/notes.md @@ -7,4 +7,4 @@ also, if the result is positive, both vectors point in the same direction, if zero, they're perpendicualer, if negative, they point in opposite directions. - * L62 famous**e** typo en \ No newline at end of file + * L62 famous**e** typo en diff --git a/10/tmp/barcode.frag b/10/tmp/barcode.frag index ca93313..c6429e5 100644 --- a/10/tmp/barcode.frag +++ b/10/tmp/barcode.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; @@ -33,15 +33,15 @@ float char (vec2 st, float n) { n = floor(mod(n,10.)); float digit = 0.0; - if (n < 1. ) { digit = 31600.; } - else if (n < 2. ) { digit = 9363.0; } - else if (n < 3. ) { digit = 31184.0; } - else if (n < 4. ) { digit = 31208.0; } - else if (n < 5. ) { digit = 23525.0; } - else if (n < 6. ) { digit = 29672.0; } - else if (n < 7. ) { digit = 29680.0; } - else if (n < 8. ) { digit = 31013.0; } - else if (n < 9. ) { digit = 31728.0; } + if (n < 1. ) { digit = 31600.; } + else if (n < 2. ) { digit = 9363.0; } + else if (n < 3. ) { digit = 31184.0; } + else if (n < 4. ) { digit = 31208.0; } + else if (n < 5. ) { digit = 23525.0; } + else if (n < 6. ) { digit = 29672.0; } + else if (n < 7. ) { digit = 29680.0; } + else if (n < 8. ) { digit = 31013.0; } + else if (n < 9. ) { digit = 31728.0; } else if (n < 10. ) { digit = 31717.0; } float pct = binChar(ipos, digit); @@ -81,8 +81,8 @@ float bar (vec2 st, float n, bool L) { else if (n < 5. ) { digit = 92.0; } else if (n < 6. ) { digit = 78.0; } else if (n < 7. ) { digit = 80.0; } - else if (n < 8. ) { digit = 68.0; } - else if (n < 9. ) { digit = 72.0; } + else if (n < 8. ) { digit = 68.0; } + else if (n < 9. ) { digit = 72.0; } else if (n < 10. ) { digit = 116.0; } float pct = binBar(ipos, digit+1.); @@ -149,8 +149,8 @@ void main(){ color += barCode(fpos,12.,value); } else { - color += 1.; + color += 1.; } gl_FragColor = vec4( color , 1.0); -} \ No newline at end of file +} diff --git a/10/tmp/digits.frag b/10/tmp/digits.frag index 5269a6f..2346990 100644 --- a/10/tmp/digits.frag +++ b/10/tmp/digits.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; @@ -33,15 +33,15 @@ float char(vec2 st, float n){ n = floor(mod(n,10.)); float digit = 0.0; - if (n < 1. ) { digit = 31600.; } - else if (n < 2. ) { digit = 9363.0; } - else if (n < 3. ) { digit = 31184.0; } - else if (n < 4. ) { digit = 31208.0; } - else if (n < 5. ) { digit = 23525.0; } - else if (n < 6. ) { digit = 29672.0; } - else if (n < 7. ) { digit = 29680.0; } - else if (n < 8. ) { digit = 31013.0; } - else if (n < 9. ) { digit = 31728.0; } + if (n < 1. ) { digit = 31600.; } + else if (n < 2. ) { digit = 9363.0; } + else if (n < 3. ) { digit = 31184.0; } + else if (n < 4. ) { digit = 31208.0; } + else if (n < 5. ) { digit = 23525.0; } + else if (n < 6. ) { digit = 29672.0; } + else if (n < 7. ) { digit = 29680.0; } + else if (n < 8. ) { digit = 31013.0; } + else if (n < 9. ) { digit = 31728.0; } else if (n < 10. ) { digit = 31717.0; } float pct = bin(ipos, digit); @@ -66,4 +66,4 @@ void main(){ color = mix(color,vec3(color.r,0.,0.),step(.99,pct)); gl_FragColor = vec4( color , 1.0); -} \ No newline at end of file +} diff --git a/10/tmp/glitch.sh b/10/tmp/glitch.sh index bf57f5c..df454f6 100755 --- a/10/tmp/glitch.sh +++ b/10/tmp/glitch.sh @@ -7,7 +7,7 @@ COUNTER=0 for i in `seq -w 0.01 .031 $SEC`; do echo $i `glslViewer $SHADER -s $i -o frame-$COUNTER.png` - let COUNTER=COUNTER+1 + let COUNTER=COUNTER+1 done convert -delay 3.5 -loop 1 frame-*.png animated.gif diff --git a/10/tmp/ikeda-01.frag b/10/tmp/ikeda-01.frag index 655a9e7..388eee0 100644 --- a/10/tmp/ikeda-01.frag +++ b/10/tmp/ikeda-01.frag @@ -20,7 +20,7 @@ float noise (in float x) { void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; - + vec3 color = vec3(0.0); vec2 grid = vec2(20.0,2.0); @@ -39,4 +39,4 @@ void main() { color += step(fpos.y*1.5,value)*step(.5,fpos.x); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/10/tmp/ikeda-03.frag b/10/tmp/ikeda-03.frag index 70974f0..71433d9 100644 --- a/10/tmp/ikeda-03.frag +++ b/10/tmp/ikeda-03.frag @@ -26,10 +26,10 @@ void main() { } vec2 grid = vec2(100.0,50.); st *= grid; - + vec2 ipos = floor(st); // integer vec2 fpos = fract(st); // fraction - + vec2 vel = vec2(u_time*2.*max(grid.x,grid.y)); // time vel *= vec2(-1.,0.0) * random(1.0+ipos.y); // direction diff --git a/10/tmp/ikeda-04.frag b/10/tmp/ikeda-04.frag index 756fa06..480311c 100644 --- a/10/tmp/ikeda-04.frag +++ b/10/tmp/ikeda-04.frag @@ -21,13 +21,13 @@ void main() { st *= grid; vec2 ipos = floor(st); // integer - + vec2 vel = floor(vec2(u_time*10.)); // time vel *= vec2(-1.,0.); // direction vel *= (step(1., mod(ipos.y,2.0))-0.5)*2.; // Oposite directions vel *= random(ipos.y); // random speed - + // 100% float totalCells = grid.x*grid.y; float t = mod(u_time*max(grid.x,grid.y)+floor(1.0+u_time*u_mouse.y),totalCells); diff --git a/10/tmp/img-glitch.frag b/10/tmp/img-glitch.frag index e3def29..7fa1bdd 100644 --- a/10/tmp/img-glitch.frag +++ b/10/tmp/img-glitch.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform sampler2D u_tex; uniform vec2 u_resolution; uniform float u_time; @@ -41,7 +41,7 @@ float fbm( in vec2 p ){ void main(){ vec2 st = gl_FragCoord.st/u_resolution.xy; float aspect = u_resolution.x/u_resolution.y; - + vec2 grain_st = st-.5; float grain = 0.0; grain = mix(1., 0.9, dot(grain_st,grain_st) + (fbm(gl_FragCoord.xy*0.6)*0.1) ); @@ -68,4 +68,4 @@ void main(){ color.rgb *= 0.4+sin((st.y*3.1415+u_time)*500.); gl_FragColor = color; -} \ No newline at end of file +} diff --git a/10/tmp/matrix.frag b/10/tmp/matrix.frag index 594175e..b93d2dd 100644 --- a/10/tmp/matrix.frag +++ b/10/tmp/matrix.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; diff --git a/10/tmp/numered-grid.frag b/10/tmp/numered-grid.frag index dadf9b8..d64cdd7 100644 --- a/10/tmp/numered-grid.frag +++ b/10/tmp/numered-grid.frag @@ -4,7 +4,7 @@ #ifdef GL_ES precision mediump float; #endif - + uniform vec2 u_resolution; uniform float u_time; @@ -59,15 +59,15 @@ float char(vec2 st, float n){ n = floor(mod(n,10.)); float digit = 0.0; - if (n < 1. ) { digit = 31600.; } - else if (n < 2. ) { digit = 9363.0; } - else if (n < 3. ) { digit = 31184.0; } - else if (n < 4. ) { digit = 31208.0; } - else if (n < 5. ) { digit = 23525.0; } - else if (n < 6. ) { digit = 29672.0; } - else if (n < 7. ) { digit = 29680.0; } - else if (n < 8. ) { digit = 31013.0; } - else if (n < 9. ) { digit = 31728.0; } + if (n < 1. ) { digit = 31600.; } + else if (n < 2. ) { digit = 9363.0; } + else if (n < 3. ) { digit = 31184.0; } + else if (n < 4. ) { digit = 31208.0; } + else if (n < 5. ) { digit = 23525.0; } + else if (n < 6. ) { digit = 29672.0; } + else if (n < 7. ) { digit = 29680.0; } + else if (n < 8. ) { digit = 31013.0; } + else if (n < 9. ) { digit = 31728.0; } else if (n < 10. ) { digit = 31717.0; } float pct = bin(ipos, digit); @@ -108,7 +108,7 @@ float cross(in vec2 st, vec2 size){ void main(){ vec2 st = gl_FragCoord.st/u_resolution.xy; float aspect = u_resolution.x/u_resolution.y; - + vec2 grain_st = st-.5; vec3 color = vec3(0.0); float grain = 0.0; @@ -153,7 +153,7 @@ void main(){ // Digits vec2 digits_st = mod(st*60.,20.); vec2 digits_st_i = floor(digits_st); - float digits_n = ceil(block*5.); + float digits_n = ceil(block*5.); offset *= 10.; if (block > 0.0 && digits_st_i.y == 1. && @@ -175,4 +175,4 @@ void main(){ color.b += block*char(digits_st_f-offset,100.*pct); } gl_FragColor = vec4( (1.0-color) * grain, 1.0); -} \ No newline at end of file +} diff --git a/11/1d-noise.frag b/11/1d-noise.frag index dcb9115..c1dbae9 100644 --- a/11/1d-noise.frag +++ b/11/1d-noise.frag @@ -10,7 +10,7 @@ uniform vec2 u_mouse; uniform float u_time; float plot(vec2 st, float pct){ - return smoothstep( pct-0.01, pct, st.y) - + return smoothstep( pct-0.01, pct, st.y) - smoothstep( pct, pct+0.01, st.y); } @@ -21,7 +21,7 @@ float random (in float x) { float noise (in float x) { float i = floor(x); float f = fract(x); - + // Cubic Hermine Curve float u = f * f * (3.0 - 2.0 * f); @@ -42,4 +42,4 @@ void main() { color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/2d-gnoise.frag b/11/2d-gnoise.frag index 6255162..1dcdadb 100644 --- a/11/2d-gnoise.frag +++ b/11/2d-gnoise.frag @@ -20,9 +20,9 @@ float noise(vec2 st) { vec2 u = f*f*(3.0-2.0*f); - return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), + return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x), - mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), + mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y); } @@ -36,4 +36,4 @@ void main() { color = vec3( noise(pos)*.5+.5 ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/2d-noise.frag b/11/2d-noise.frag index b206e16..74be372 100644 --- a/11/2d-noise.frag +++ b/11/2d-noise.frag @@ -7,7 +7,7 @@ uniform vec2 u_mouse; uniform float u_time; // 2D Random -float random (in vec2 st) { +float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); @@ -32,8 +32,8 @@ float noise (in vec2 st) { // u = smoothstep(0.,1.,f); // Mix 4 coorners porcentages - return mix(a, b, u.x) + - (c - a)* u.y * (1.0 - u.x) + + return mix(a, b, u.x) + + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } @@ -48,4 +48,4 @@ void main() { float n = noise(pos); gl_FragColor = vec4(vec3(n), 1.0); -} \ No newline at end of file +} diff --git a/11/2d-pnoise.frag b/11/2d-pnoise.frag index cd6b5ba..fa4a97f 100644 --- a/11/2d-pnoise.frag +++ b/11/2d-pnoise.frag @@ -48,10 +48,10 @@ float cnoise(vec2 P) { vec2 g11 = vec2(gx.w,gy.w); vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; float n00 = dot(g00, vec2(fx.x, fy.x)); float n10 = dot(g10, vec2(fx.y, fy.y)); @@ -88,10 +88,10 @@ float pnoise(vec2 P, vec2 rep) { vec2 g11 = vec2(gx.w,gy.w); vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; float n00 = dot(g00, vec2(fx.x, fy.x)); float n10 = dot(g10, vec2(fx.y, fy.y)); @@ -113,4 +113,4 @@ void main() { color = vec3( cnoise(pos) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/2d-snoise-clear.frag b/11/2d-snoise-clear.frag index 15ce951..cb37471 100644 --- a/11/2d-snoise-clear.frag +++ b/11/2d-snoise-clear.frag @@ -16,21 +16,21 @@ vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); } // Author : Ian McEwan, Ashima Arts // Maintainer : ijm // Lastmod : 20110822 (ijm) -// License : +// License : // Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// float snoise(vec2 v) { // Precompute values for skewed triangular grid const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, + 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, + -0.577350269189626, // -1.0 + 2.0 * C.x - 0.024390243902439); + 0.024390243902439); // 1.0 / 41.0 // First corner (x0) @@ -51,17 +51,17 @@ float snoise(vec2 v) { + i.x + vec3(0.0, i1.x, 1.0 )); vec3 m = max(0.5 - vec3( - dot(x0,x0), - dot(x1,x1), + dot(x0,x0), + dot(x1,x1), dot(x2,x2) ), 0.0); m = m*m ; m = m*m ; - // Gradients: + // Gradients: // 41 pts uniformly over a line, mapped onto a diamond - // The ring size 17*17 = 289 is close to a multiple + // The ring size 17*17 = 289 is close to a multiple // of 41 (41*7 = 287) vec3 x = 2.0 * fract(p * C.www) - 1.0; @@ -92,4 +92,4 @@ void main() { color = vec3(snoise(st)*.5+.5); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/2d-snoise.frag b/11/2d-snoise.frag index abba274..29c085e 100644 --- a/11/2d-snoise.frag +++ b/11/2d-snoise.frag @@ -11,19 +11,19 @@ uniform float u_time; // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm // Lastmod : 20110822 (ijm) -// License : +// License : // Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); } float snoise(vec2 v) { const vec4 C = vec4(0.211324865405187, - 0.366025403784439, - -0.577350269189626, - 0.024390243902439); + 0.366025403784439, + -0.577350269189626, + 0.024390243902439); vec2 i = floor(v + dot(v, C.yy) ); vec2 x0 = v - i + dot(i, C.xx); vec2 i1 = vec2(0.0); @@ -35,8 +35,8 @@ float snoise(vec2 v) { permute( i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0 )); vec3 m = max(0.5 - vec3( - dot(x0,x0), - dot(x12.xy,x12.xy), + dot(x0,x0), + dot(x12.xy,x12.xy), dot(x12.zw,x12.zw) ), 0.0); m = m*m ; @@ -61,4 +61,4 @@ void main() { color = vec3(snoise(pos)*.5+.5); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/3d-noise.frag b/11/3d-noise.frag index 3d47e3c..755bfbc 100644 --- a/11/3d-noise.frag +++ b/11/3d-noise.frag @@ -17,10 +17,10 @@ float noise (in vec3 p) { vec3 i = floor(p); vec3 f = fract(p); - - // For performance, compute the base input to a - // 1D random from the integer part of the - // argument and the incremental change to the + + // For performance, compute the base input to a + // 1D random from the integer part of the + // argument and the incremental change to the // 1D based on the 3D -> 1D wrapping float n = dot(i, step); @@ -30,7 +30,7 @@ float noise (in vec3 p) { u.x), mix(random(n + dot(step, vec3(0,1,0))), random(n + dot(step, vec3(1,1,0))), - u.x), + u.x), u.y), mix(mix(random(n + dot(step, vec3(0,0,1))), random(n + dot(step, vec3(1,0,1))), @@ -51,4 +51,4 @@ void main() { color = vec3(noise(pos)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/3d-pnoise.frag b/11/3d-pnoise.frag index a1eb366..9e561f4 100644 --- a/11/3d-pnoise.frag +++ b/11/3d-pnoise.frag @@ -91,7 +91,7 @@ float cnoise(vec3 P) { vec3 fade_xyz = fade(Pf0); vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); - float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return 2.2 * n_xyz; } @@ -160,7 +160,7 @@ float pnoise(vec3 P, vec3 rep) { vec3 fade_xyz = fade(Pf0); vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); - float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return 2.2 * n_xyz; } @@ -174,4 +174,4 @@ void main() { // color = vec3(pnoise(pos,vec3(0.0))); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/3d-snoise.frag b/11/3d-snoise.frag index d6629b0..4d61367 100644 --- a/11/3d-snoise.frag +++ b/11/3d-snoise.frag @@ -7,7 +7,7 @@ uniform vec2 u_mouse; uniform float u_time; // -// Description : Array and textureless GLSL 2D/3D/4D simplex +// Description : Array and textureless GLSL 2D/3D/4D simplex // noise functions. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm @@ -15,13 +15,13 @@ uniform float u_time; // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } -float snoise(vec3 v) { +float snoise(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); @@ -40,10 +40,10 @@ float snoise(vec3 v) { vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations - i = mod289(i); - vec4 p = permute( permute( permute( + i = mod289(i); + vec4 p = permute( permute( permute( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients: 7x7 points over a square, mapped onto an octahedron. @@ -85,7 +85,7 @@ float snoise(vec3 v) { // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; - return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), + return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } @@ -98,4 +98,4 @@ void main() { color = vec3(snoise(pos)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/README-ch.md b/11/README-ch.md index 836e0c1..d4c5b6c 100644 --- a/11/README-ch.md +++ b/11/README-ch.md @@ -37,7 +37,7 @@ y = rand(i); //rand() 在之前的章节提过 ```glsl y = mix(rand(i), rand(i + 1.0), f); -``` +``` 试试取消这句的注释,看一下会变成什么样子。注意我们储存在 `f` 中的 [```fract()```](.../glossary/?search=fract) 值[```mix()```](.../glossary/?search=mix)了两个随机值。 @@ -140,7 +140,7 @@ Noise 算法的设计初衷是将难以言说的自然质感转化成数字图 第三种方法是用 noise 函数来变换一个形状。这个也需要我们在[第七章](../07/)学到的技术。 - + 给你的练习: @@ -205,11 +205,11 @@ y = x*x*(3.0-2.0*x); * 做一个 shader 来表现流体的质感。比如像[熔岩灯](https://en.wikipedia.org/wiki/Lava_lamp?oldformat=true),墨水滴,水,等等。 - + * 用 Simplex Noise 给你现在的作品添加更多的材质效果。 - + 在本章我们介绍了一些操控混沌的方法。这并不是一件简单的工作!成为 noise 超级大师需要时间和努力。 @@ -217,4 +217,4 @@ y = x*x*(3.0-2.0*x);

“和树聊聊天吧,和它交个朋友。” Bob Ross -

+

diff --git a/11/README-de.md b/11/README-de.md index f6e417d..178e0d1 100644 --- a/11/README-de.md +++ b/11/README-de.md @@ -1,230 +1,229 @@ -![NASA / WMAP Wissenschaftsteam](mcb.jpg) - -## Rauschen - -Im letzten Kapitel haben wir mit Zufallsfunktionen gearbeitet, die wie weißes Rauschen auf dem Fernsehbildschirm wirken. Nach so vielen Shader-Funktionen auf einmal dreht sich Dir bestimmt der Kopf und vielleicht sind auch Deine Augen etwas müde. Jetzt ist ein guter Moment, um einen kleinen Spaziergang zu unternehmen und ein wenig nach Luft zu schnappen. - -Draußen im Freien spüren wir den Luftzug auf unserer Haut und die Sonne in unserem Gesicht. Die Erde ist ein so lebendiger und vielgestaltiger Ort voller Farben, Texturen und Klängen. Während wir uns in der Natur bewegen, können wir gar nicht anders, als die unterschiedlichen Oberflächen von Straßen, Gestein, Bäumen und Wolken wahrzunehmen. - -![](texture-00.jpg) -![](texture-01.jpg) -![](texture-02.jpg) -![](texture-03.jpg) -![](texture-04.jpg) -![](texture-05.jpg) -![](texture-06.jpg) - -Die Unvorhersehbarkeit dieser Texturen könnte man als „zufällig“ auffassen. Dabei wirken sie so gar nicht wie die Zufallsstrukturen, mit denen wir uns im letzten Kapitel befasst haben. Die Wirklichkeit ist ein so komplexer Ort! Wir kann es uns gelingen, ihr Antlitz mit Hilfe von Algorithmen nachzuahmen? - -Diese Frage beschäftigte [Ken Perlin](https://mrl.nyu.edu/~perlin/) in den frühen 1980er Jahren, als er den Auftrag erhielt, realistische Texturen für den Hollywood-Film „Tron“ zu erschaffen. Er entwickelte damals eine elegante Vorgehensweise, die als „Noise Algorithmus“ bekannt und sogar mit einem Oskar prämiert wurde (kein Witz). - -![Disney - Tron (1982)](tron.jpg) - -Die folgende Funktion entspricht nicht dem klassischen Noise-Algorithmus von Perlin, aber sie ist ein guter Ausgangspunkt, um die Erzeugung „verrauschter“-Strukturen zu begreifen. - -
- -In diesen Zeilen gehen wir ähnlich vor, wie im vorangegangenen Kapitel. Wir teilen eine fortlaufende Fließkommazahl (```x```) in ihren ganzzahligen Vorkommateil (```i```) und ihren Nachkommateil (```f```) auf. Wir nutzen dabei [```floor()```](.../glossary/?search=floor), um ```i``` zu erhalten, sowie [```fract()```](.../glossary/?search=fract) für die Berechnung von ```f```. Dann wenden wir ```rand()``` auf den ganzzahligen Teil von ```x``` an, wodurch wir für jede Ganzzahl eine einzigartige Zufallszahl erhalten. - -Dahinter folgen zwei Programmzeilen, die zunächst auskommentiert sind. Die Erste davon interpoliert zwischen dem Zufallswert (```rand(i)```) und dem Zufallswert von (```rand(i+1)```) (also zwischen zwei ganz unterschiedlichen Zahlen) auf lineare Weise, wobei der Abstand für die Interpolation jeweils durch (```f```) bestimmt wird. - -```glsl -y = mix(rand(i), rand(i + 1.0), f); -``` - -Fahre fort, indem Du die Kommentarzeichen für diese Zeile entfernst und Dir das Ergebnis anschaust. - -An diesem Punkt unseres kleinen GLSL-Kurses wissen wir bereits, dass es noch etwas besseres als eine simple lineare Interpolation gibt, nicht wahr? Entferne deshalb die Kommentarzeichen aus der nächsten Zeile, die [```smoothstep()```](.../glossary/?search=smoothstep) nutzt, um bei der Interpolation weichere Verläufe und Übergänge zu erzielen. - -```glsl -y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); -``` - -Sobald Du die Kommentarzeichen aus dieser Zeile entfernt hast, erscheint ein anderes Ergebnis. In einigen Implementationen für Rausch-Funktionen verwenden die Autoren lieber ihre eigenen kubischen Kurven an Stelle von [```smoothstep()```](.../glossary/?search=smoothstep), wie etwa im folgenden Beispiel. - -```glsl -float u = f * f * (3.0 - 2.0 * f ); // kubische Verlaufskurve -y = mix(rand(i), rand(i + 1.0), u); // angewandt auf die Interpolation -``` - -Diese *sanfte Zufälligkeit* ist das entscheidende Merkmal, auf das es vielen Grafikkünstlern ankommt. Erst dadurch wird es möglich, geometrische Formen und Bilder zu erstellen, die so organisch wirken, als kämen sie direkt aus der Natur. Perlins Noise-Algorithmus wurde seit seiner Veröffentlichung immer wieder in ganz unterschiedlichen Programmiersprachen und für verschiedene Dimensionen implementiert. Er hat Grafiker und Grafikkünstler auf der ganzen Welt bei ihren Arbeiten unterstützt. - -![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg) - -Und nun bist Du dran: - -* Entwickle Deine eigene ```float noise(float x)```-Funktion. - -* Nutze Deine Noise-Funktion, um Formen zu animieren, indem Du sie bewegst, rotierst oder skalierst. - -* Erstelle eine animierte Komposition aus mehreren Formen, die „miteinander“ tanzen, indem Du auf Noise-Funktionen zurückgreifst. - -* Baue organisch wirkende Formen mit Hilfe der Noise-Funktion. - -* Sobald Du auf diese Weise eine eigene „Kreatur“ erschaffen hast, versuche ihr Lebendigkeit einzuhauchen, indem Du sie auf ganz charakteristische Weise bewegst. - -## 2D-Rauschen - -![](02.png) - -Jetzt, wo wir wissen, wie man Rauschen in einer Dimension erzeugt, können wir uns dem zweidimensionalen Rauschen zuwenden. Während wir im eindimensionalen Raum entlang einer Linie zwischen zwei Punkten (```fract(x)``` und ```fract(x)+1.0```) interpolieren, geschieht dies im zweidimensionalen Raum zwischen den vier Eckpunkten eines Vierecks innerhalb einer Ebene (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` und ```fract(st)+vec2(1.,1.)```). - -![](01.png) - -In ähnlicher Weise müssen wir im dreidimensionalen Raum vorgehen. Hier sind es die acht Ecken eines Kubus, zwischen denen es zu interpolieren gilt. Dabei dreht sich alles um die Interpolation von Zufallswerten (engl. random values), weshalb man in diesem Zusammenhang auch von **Value Noise** spricht. - -![](04.jpg) - -Wie schon bei unserem Beispiel für den eindimensionalen Raum, erfolgt die Interpolation auch hier nicht linear, sondern kubisch, damit ein sanfter Verlauf zwischen allen Punkten des viereckigen Rasters entsteht. - -![](05.jpg) - -Schau Dir die folgende Noise-Funktion an. - -
- -Wir „blasen“ den Raum zunächst auf das Fünffache auf (*Programmzeile 45*), damit wir die Interpolation zwischen den einzelnen Elementen unseres Rasters besser erkennen können. Innerhalb der Noise-Funktion erfolgt dann die Einteilung des Raumes in einzelne Zellen. Wir speichern die Integer-Position der Zelle, ebenso den Nachkommateil für die Position innerhalb der Zelle. Die Integer-Position nutzen wir, um einen Zufallswert für alle vier Eckpunkte der Zelle zu erhalten (*Programmzeilen 23-26*). Schließlich interpolieren wir in der *Programmzeile 35* zwischen den vier zufällig gewählten Eckpunkten auf Basis des Nachkommateils, den wir zuvor gespeichert haben. - -Jetzt bist Du wieder dran. Versuche Dich an den folgenden Aufgaben: - -* Ändere den Multiplikationsfaktor in *Programmzeile 45*. Versuche ihn zu animieren. - -* Versuche herauszufinden, ab welcher Vergrößerungsstufe das Rauschen wieder vollkommen zufällig und unzusammenhängend (chaotisch) wirkt. - -* Ab welcher Vergrößerungsstufe ist das Rauschen nicht mehr wahrnehmbar? - -* Versuche die Noise-Funktion sinnvoll mit den Mauskoordinaten in Verbindung zu bringen. - -* Was wäre, wenn wir den Farbverlauf des Rauschens als Distanzfeld behandeln? Versuche etwas Interessantes damit anzufangen. - -* Nun, da wir ein gewisses Maß an Kontrolle über Ordnung und Chaos erzielt haben, ist es an der Zeit, dieses Wissen umzusetzen. Erstelle eine Komposition aus Rechtecken, Farben und Rauschen, die an die Struktur eines Kunstwerks von [Mark Rothko](http://de.wikipedia.org/wiki/Mark_Rothko) erinnert. - -![Mark Rothko - Three (1950)](rothko.jpg) - -## Rauschen und seine Verwendung für generative Designs - -Noise-Algorithmen wurden ursprünglich entwickelt, um digitalen Texturen ein natürliches Aussehen zu verleihen. Die ein- und zweidimensionale Implementation, die wir bislang betrachtet haben, verwendet dafür Interpolationen zwischen Zufallswerten (engl. *random values*), weshalb sie als **Value Noise** bezeichnet wird. Doch es gibt noch andere Verfahren, um Rauschen zu erzeugen. - -[ ![Inigo Quilez - Value Noise](value-noise.png) ](../edit.php#11/2d-vnoise.frag) - -Wie die vorangegangenen Abschnitte gezeigt haben, tendiert *Value Noise* zur Erzeugung blockartiger Strukturen. Um diesen Blockeffekt zu reduzieren, hat [Ken Perlin](https://mrl.nyu.edu/~perlin/) im Jahre 1985 einen weiteren Algorithmus mit Namen **Gradient Noise** entwickelt. Ken hatte herausgefunden, wie man zwischen zufälligen Gradienten (Verläufen) interpoliert, anstatt zwischen einfachen Zufallszahlen. Diese Gradienten waren das Ergebnis einer 2D-Zufallsfunktion, die Richtungsvektoren (bei GLSL in Form eines ```vec2```) anstelle einfacher Fließkommazahlen (```float```) zurückliefert. Klicke auf das folgende Bild, um einen Blick auf den dahinterstehenden Programmcode zu werfen und zu verstehen, wie das Ganze funktioniert. - -[ ![Inigo Quilez - Gradient Noise](gradient-noise.png) ](../edit.php#11/2d-gnoise.frag) - -Nimm Dir einen Moment Zeit, um die beiden folgenden Beispiele von [Inigo Quilez](http://www.iquilezles.org/) zu studieren und richte Deine Aufmerksamkeit dabei besonders auf die Unterschiede zwischen [*Value Noise*](https://www.shadertoy.com/view/lsf3WH) und [*Gradient Noise*](https://www.shadertoy.com/view/XdXGW8). - -Wie ein Maler, der genau weiß, wie die Farben auf seiner Staffelei miteinander harmonieren, werden auch wir die Noise-Funktionen umso besser nutzen können, je mehr wir deren Vorgehensweise verstehen. Wenn wir beispielsweise eine zweidimensionale Noise-Funktion nutzen, um den Raum zu drehen, während wir gerade Linien zeichnen, entsteht der folgende Dreheffekt, der stark an die Maserung von Holz erinnert. Auch hier kannst Du wieder auf die Grafik klicken, um der den Shader-Code dahinter anzuschauen. - -[ ![Holzmaserung](wood-long.png) ](../edit.php#11/wood.frag) - -```glsl - pos = rotate2d( noise(pos) ) * pos; // drehe den Raum - pattern = lines(pos,.5); // zeichne Linien -``` - -Ein anderer Weg zur Erzeugung interessanter Muster mit Hilfe von Noise-Funktionen besteht in ihrer Behandlung als Distanzfeld und der Anwendung einiger Tricks, die wir im [Kapitel über Formen](../07/) kennengelernt haben. - -[ ![Farbspritzer-Textur](splatter-long.png) ](../edit.php#11/splatter.frag) - -```glsl - color += smoothstep(.15,.2,noise(st*10.)); // schwarze Spritzer - color -= smoothstep(.35,.4,noise(st*10.)); // Löcher in den Spritzern -``` - -Ein dritter Weg basiert auf der Modulation einer Form mit Hilfe einer Noise-Funktion. Auch dabei kommen einige der Techniken zum Einsatz, die wir im [Kapitel über Formen](../07/) kennengelernt haben. - - - -Empfohlene Übungen: - -* Welche anderen generativen Designs fallen Dir ein? Was ist mit Granitgestein? Marmor? Magma? Wasser? Suche Dir drei Fotos entsprechender Materialien und entwickle die zugehörigen Algorithmen unter Einbeziehung von Noise-Funktionen. - -* Nutze Noise-Funktionen, um eine Form zu modulieren. - -* Wie steht es um die Nutzung von Noise-Funktionen für Bewegungsabläufe? Schlage noch einmal im [Kapitel über Matrizenoperationen](../08/) nach. Nutze das dortige Beispiel, in welchem das Kreuz über die Zeichenfläche bewegt wird, und füge dem Ganzen etwas Zufall und Noise hinzu. - -* Erzeuge ein generatives Design wie bei Jackson Pollocks Bildern. - -![Jackson Pollock - Number 14 gray (1948)](pollock.jpg) - -## Verbesserte Noise-Funktionen - -Eine Verbesserung von Perlin an seinem ursprünglichen **Non-Simplex Noise**-Algorithmus hin zu einem **Simplex Noise** ist der Ersatz der kubischen Hermite-Funktionn ( _f(x) = 3x^2-2x^3_, die der [```smoothstep()```](.../glossary/?search=smoothstep)-Funktion in GLSL entspricht) durch eine quintische Interpolationsfunktion ( _f(x) = 6x^5-15x^4+10x^3_ ). - -Diese lässt die Interpolationskurve an ihren Enden flacher werden, so dass sie nahtloser in die nächste Interpolationskurve übergeht. Man erhält dadurch kontinuierlichere Übergänge zwischen den einzelnen Zellen. Du kannst Dir ein Bild davon machen, indem Du die Kommentare an der zweiten Formel in dem folgenden Graphen entfernst. ([Beide Graphen in einem Bild siehst Du auch hier](https://www.desmos.com/calculator/2xvlk5xp8b)). Entscheidend ist wie immer der Bereich zwischen ```0.0``` und ```1.0``` auf der *x-Achse*. - - -
- -Beachte, wie die beiden unterschiedlichen Kurven an ihren Endbereichen voneinander abweichen. Mehr dazu erfährst du in [Ken s eigenen Worten hier](http://mrl.nyu.edu/~perlin/paper445.pdf). - -## Simplex Noise - -Für Ken Perlin war der Erfolg seines ersten Noise-Algorithmus noch nicht genug. Er suchte weiter nach Verbesserungen. Auf der berühmten Grafik-Konferenz *Siggraph* präsentierte er im Jahre 2001 den „Simplex Noise“-Algorithmus, mit dem er die folgenden Optimierungen gegenüber dem Vorgänger erzielte: - -* Geringerer Rechenaufwand und weniger Multiplikationen. - -* Ein Rauschen, das sich auch für höhere Dimensionen berechnen lässt, ohne dass der Aufwand ins Astronomische steigt. - -* Ein Rauschen ohne sichtbare Richtungsartefakte. - -* Ein Rauschen mit sauber definierten und nahtlosen Übergangen, das sich einfach berechnen lässt. - -* Ein Algorithmus, der auch in der Hardware einfach zu implementieren ist. - -Ich weiß, was Du jetzt denkst... „Wow, wer ist dieser Mann?“ Ja, seine Leistungen sind wirklich großartig. Aber mal ganz im Ernst, wie ist es ihm gelungen, seinen Algorithmus zu verbessern? Nun, wir haben gesehen, dass er zur Berechnung des Rauschens in zwei Dimensionen zwischen den vier Eckpunkten eines Vierecks interpoliert. Man darf deshalb zurecht davon ausgehen, dass er für die Berechnung in drei Dimensionen ([eine Implementierung in GLSL findest Du hier](../edit.php#11/3d-noise.frag)) und vier Dimensionen zwischen 8 bzw. 16 einzelnen Eckpunkten interpolieren muss. Korrekt? - -In anderen Worten: Für die Berechnung des Rauschens in N Dimensionen muss man zwischen *2 hoch N* (_2^N_) verschiedenen Punkten interpolieren. Ken war jedoch aufgefallen, dass die offensichtliche „Bauweise“ für eine flächenfüllende Form zwar fraglos ein Viereck darstellt, die einfachste Form der Abdeckung jedoch mit gleichseitigen Dreiecken erzielt wird. Deshalb ersetzte er das rechtwinklige Gitternetz durch ein Netz aus gleichseitigen Dreiecken. - -![](simplex-grid-00.png) - -Mit gleichseitigen Dreiecken besteht die einfachste Form für *N Dimensionen* aus einer Konstruktion mit *N+1 Eckpunkten*. Das bedeutet einen Eckpunkt weniger für zweidimensionales Rauschen, vier Eckpunkte weniger für dreidimensionales Rauschen und elf Eckpunkte weniger für vierdimensionales Rauschen. Diese „Ersparnis“ bringt einen enorm reduzierten Rechenaufwand und dadurch einen großen Geschwindigkeitszuwachs mit sich! - -In zwei Dimensionen erfolgt die Interpolation genau wie bei der Standard Noise-Funktion. Weil wir aber ein gleichseitiges Dreieck nutzen, müssen wir dabei nur drei Punkte einbeziehen. - -![](simplex-grid-01.png) - -Doch wie wird dieses vereinfachte Gitternetz aufgebaut? In einem weiteren brillanten und äußerst eleganten Schritt, werden die Zellen des viereckigen Gitternetzes jeweils in zwei gleichschenklige Dreiecke (mit jeweils zwei gleich langen Seiten) aufgeteilt. Anschließend wird das Netz so verzerrt, dass alle Dreiecke auch gleichseitig sind (also mit jeweils drei gleich langen Seiten). Denn damit lässt sich am einfachsten interpolieren. - -![](simplex-grid-02.png) - -Anschließend fahren wir fort, wie es [Stefan Gustavson in seinen Ausführungen beschreibt](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): "*... indem wir uns die ganzzahligen Anteile der transformierten Koordinaten (x,y) des zu berechnenden Punktes anschauen, denn darüber können wir leicht feststellen, zu welchen zwei Dreiecken der Punkt gehört. Indem wir die Werte von x und y vergleichen, erfahren wir, ob sich der Punkt in dem oberen oder in dem unteren Dreieck befindet. So können wir die drei korrekten Eckpunkte in die Berechnung einbeziehen.*“ - -Im folgenden Programmcode kannst Du die Kommentarzeichen aus der *Programmzeile 44* entfernen, um zu sehen, wie das Gitternetz gezerrt wird. Und sobald Du die Kommentierung von *Zeile 47* aufhebst, erkennst Du die Aufteilung der Fläche in gleichschenklige Dreiecke. Beachte, wie wir in *Zeile 22* das verzerrte Rechteck einfach in zwei gleichseitige Dreiecke aufteilen, indem wir testen, ob ```x > y``` ist („unteres“ Dreieck) oder ```y > x``` („oberes“ Dreieck). - -
- -All diese Verbesserungen münden in das Meisterwerk, das als **Simplex Noise**-Algorithmus bekannt ist. Der folgende Programmcode ist eine Implementation dieses Algorithmus in GLSL, die von Ian McEwan und Stefan Gustavson entwickelt wurde ([hier nachzulesen](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)). Für unsere Lernzwecke ist diese theoretische Erklärung vielleicht etwas zu aufwändig. Allerdings wirst Du beim Anklicken der Grafik und einem Blick auf den dahinterstehenden Programmcode feststellen, dass dieser weniger kryptisch daherkommt, als Du vielleicht erwartet hast. Außerdem ist der Code vergleichsweise kompakt und kann schnell ausgeführt werden. - -[ ![Ian McEwan von Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.php#11/2d-snoise-clear.frag) - -Nun aber genug der technischen Spitzfindigkeiten. Es ist an der Zeit, dass Du den Simplex Noise-Algorithmus als eine wertvolle Ressource im Rahmen Deiner eigenen Projekte zum Einsatz bringst: - -* Versuche das Besondere an den verschiedenen Implementationen von Noise zu erkennen. Stelle Sie Dir wie Rohmaterialien vor, aus denen ein Bildhauer seine Skulptur herausschält. Wie fühlen sich die unterschiedlichen Ergebnisse für Dich an? Verziehe beim Betrachten deine Augen, um der Vorstellungskraft Raum zu geben, so wie Du die Wolken nach Mustern absuchst. Was erkennst Du? Woran erinnert es Dich? Was könnte man wohl mit den verschiedenen Noise-Implementationen anstellen? Höre auf Deine innere Stimme und probiere es einfach aus! - -* Entwickle einen Shader, der die Illusion einer Strömung von Flüssigkeiten erweckt. Etwa wie bei einer Lava-Lampe, Tintentropfen, Wasser etc. - - - -* Nutze den Simplex Noise-Algorithmus um Deinen bisherigen Arbeiten mehr Textur zu verleihen. - - - -In diesem Kapitel haben wir versucht, Kontrolle über das Chaos zu erlangen. Das war keine leichte Aufgabe. Es braucht seine Zeit, um ein Meister des Rauschens und der Raumkrümmung zu werden. - -In den folgenden Kapiteln werden wir einige bekannte Techniken aufgreifen, mit Denen Du deine Fähigkeiten weiter verbessern kannst. Bis dahin genieße ein wenig Zeit draußen an der frischen Luft und lasse Dich von den Mustern und Strukturen der Natur inspirieren. Denn Deine Fähigkeiten zur Beobachtung müssen ähnlich gut entwickelt sein, wie Deine Programmierfähigkeiten. Vielleicht sogar noch besser. Genieße die wertvolle Zeit abseits des Computers! - -

"Sprich mit den Bäumen und werdet Freunde." Bob Ross -

- +![NASA / WMAP Wissenschaftsteam](mcb.jpg) + +## Rauschen + +Im letzten Kapitel haben wir mit Zufallsfunktionen gearbeitet, die wie weißes Rauschen auf dem Fernsehbildschirm wirken. Nach so vielen Shader-Funktionen auf einmal dreht sich Dir bestimmt der Kopf und vielleicht sind auch Deine Augen etwas müde. Jetzt ist ein guter Moment, um einen kleinen Spaziergang zu unternehmen und ein wenig nach Luft zu schnappen. + +Draußen im Freien spüren wir den Luftzug auf unserer Haut und die Sonne in unserem Gesicht. Die Erde ist ein so lebendiger und vielgestaltiger Ort voller Farben, Texturen und Klängen. Während wir uns in der Natur bewegen, können wir gar nicht anders, als die unterschiedlichen Oberflächen von Straßen, Gestein, Bäumen und Wolken wahrzunehmen. + +![](texture-00.jpg) +![](texture-01.jpg) +![](texture-02.jpg) +![](texture-03.jpg) +![](texture-04.jpg) +![](texture-05.jpg) +![](texture-06.jpg) + +Die Unvorhersehbarkeit dieser Texturen könnte man als „zufällig“ auffassen. Dabei wirken sie so gar nicht wie die Zufallsstrukturen, mit denen wir uns im letzten Kapitel befasst haben. Die Wirklichkeit ist ein so komplexer Ort! Wir kann es uns gelingen, ihr Antlitz mit Hilfe von Algorithmen nachzuahmen? + +Diese Frage beschäftigte [Ken Perlin](https://mrl.nyu.edu/~perlin/) in den frühen 1980er Jahren, als er den Auftrag erhielt, realistische Texturen für den Hollywood-Film „Tron“ zu erschaffen. Er entwickelte damals eine elegante Vorgehensweise, die als „Noise Algorithmus“ bekannt und sogar mit einem Oskar prämiert wurde (kein Witz). + +![Disney - Tron (1982)](tron.jpg) + +Die folgende Funktion entspricht nicht dem klassischen Noise-Algorithmus von Perlin, aber sie ist ein guter Ausgangspunkt, um die Erzeugung „verrauschter“-Strukturen zu begreifen. + +
+ +In diesen Zeilen gehen wir ähnlich vor, wie im vorangegangenen Kapitel. Wir teilen eine fortlaufende Fließkommazahl (```x```) in ihren ganzzahligen Vorkommateil (```i```) und ihren Nachkommateil (```f```) auf. Wir nutzen dabei [```floor()```](.../glossary/?search=floor), um ```i``` zu erhalten, sowie [```fract()```](.../glossary/?search=fract) für die Berechnung von ```f```. Dann wenden wir ```rand()``` auf den ganzzahligen Teil von ```x``` an, wodurch wir für jede Ganzzahl eine einzigartige Zufallszahl erhalten. + +Dahinter folgen zwei Programmzeilen, die zunächst auskommentiert sind. Die Erste davon interpoliert zwischen dem Zufallswert (```rand(i)```) und dem Zufallswert von (```rand(i+1)```) (also zwischen zwei ganz unterschiedlichen Zahlen) auf lineare Weise, wobei der Abstand für die Interpolation jeweils durch (```f```) bestimmt wird. + +```glsl +y = mix(rand(i), rand(i + 1.0), f); +``` + +Fahre fort, indem Du die Kommentarzeichen für diese Zeile entfernst und Dir das Ergebnis anschaust. + +An diesem Punkt unseres kleinen GLSL-Kurses wissen wir bereits, dass es noch etwas besseres als eine simple lineare Interpolation gibt, nicht wahr? Entferne deshalb die Kommentarzeichen aus der nächsten Zeile, die [```smoothstep()```](.../glossary/?search=smoothstep) nutzt, um bei der Interpolation weichere Verläufe und Übergänge zu erzielen. + +```glsl +y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); +``` + +Sobald Du die Kommentarzeichen aus dieser Zeile entfernt hast, erscheint ein anderes Ergebnis. In einigen Implementationen für Rausch-Funktionen verwenden die Autoren lieber ihre eigenen kubischen Kurven an Stelle von [```smoothstep()```](.../glossary/?search=smoothstep), wie etwa im folgenden Beispiel. + +```glsl +float u = f * f * (3.0 - 2.0 * f ); // kubische Verlaufskurve +y = mix(rand(i), rand(i + 1.0), u); // angewandt auf die Interpolation +``` + +Diese *sanfte Zufälligkeit* ist das entscheidende Merkmal, auf das es vielen Grafikkünstlern ankommt. Erst dadurch wird es möglich, geometrische Formen und Bilder zu erstellen, die so organisch wirken, als kämen sie direkt aus der Natur. Perlins Noise-Algorithmus wurde seit seiner Veröffentlichung immer wieder in ganz unterschiedlichen Programmiersprachen und für verschiedene Dimensionen implementiert. Er hat Grafiker und Grafikkünstler auf der ganzen Welt bei ihren Arbeiten unterstützt. + +![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg) + +Und nun bist Du dran: + +* Entwickle Deine eigene ```float noise(float x)```-Funktion. + +* Nutze Deine Noise-Funktion, um Formen zu animieren, indem Du sie bewegst, rotierst oder skalierst. + +* Erstelle eine animierte Komposition aus mehreren Formen, die „miteinander“ tanzen, indem Du auf Noise-Funktionen zurückgreifst. + +* Baue organisch wirkende Formen mit Hilfe der Noise-Funktion. + +* Sobald Du auf diese Weise eine eigene „Kreatur“ erschaffen hast, versuche ihr Lebendigkeit einzuhauchen, indem Du sie auf ganz charakteristische Weise bewegst. + +## 2D-Rauschen + +![](02.png) + +Jetzt, wo wir wissen, wie man Rauschen in einer Dimension erzeugt, können wir uns dem zweidimensionalen Rauschen zuwenden. Während wir im eindimensionalen Raum entlang einer Linie zwischen zwei Punkten (```fract(x)``` und ```fract(x)+1.0```) interpolieren, geschieht dies im zweidimensionalen Raum zwischen den vier Eckpunkten eines Vierecks innerhalb einer Ebene (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` und ```fract(st)+vec2(1.,1.)```). + +![](01.png) + +In ähnlicher Weise müssen wir im dreidimensionalen Raum vorgehen. Hier sind es die acht Ecken eines Kubus, zwischen denen es zu interpolieren gilt. Dabei dreht sich alles um die Interpolation von Zufallswerten (engl. random values), weshalb man in diesem Zusammenhang auch von **Value Noise** spricht. + +![](04.jpg) + +Wie schon bei unserem Beispiel für den eindimensionalen Raum, erfolgt die Interpolation auch hier nicht linear, sondern kubisch, damit ein sanfter Verlauf zwischen allen Punkten des viereckigen Rasters entsteht. + +![](05.jpg) + +Schau Dir die folgende Noise-Funktion an. + +
+ +Wir „blasen“ den Raum zunächst auf das Fünffache auf (*Programmzeile 45*), damit wir die Interpolation zwischen den einzelnen Elementen unseres Rasters besser erkennen können. Innerhalb der Noise-Funktion erfolgt dann die Einteilung des Raumes in einzelne Zellen. Wir speichern die Integer-Position der Zelle, ebenso den Nachkommateil für die Position innerhalb der Zelle. Die Integer-Position nutzen wir, um einen Zufallswert für alle vier Eckpunkte der Zelle zu erhalten (*Programmzeilen 23-26*). Schließlich interpolieren wir in der *Programmzeile 35* zwischen den vier zufällig gewählten Eckpunkten auf Basis des Nachkommateils, den wir zuvor gespeichert haben. + +Jetzt bist Du wieder dran. Versuche Dich an den folgenden Aufgaben: + +* Ändere den Multiplikationsfaktor in *Programmzeile 45*. Versuche ihn zu animieren. + +* Versuche herauszufinden, ab welcher Vergrößerungsstufe das Rauschen wieder vollkommen zufällig und unzusammenhängend (chaotisch) wirkt. + +* Ab welcher Vergrößerungsstufe ist das Rauschen nicht mehr wahrnehmbar? + +* Versuche die Noise-Funktion sinnvoll mit den Mauskoordinaten in Verbindung zu bringen. + +* Was wäre, wenn wir den Farbverlauf des Rauschens als Distanzfeld behandeln? Versuche etwas Interessantes damit anzufangen. + +* Nun, da wir ein gewisses Maß an Kontrolle über Ordnung und Chaos erzielt haben, ist es an der Zeit, dieses Wissen umzusetzen. Erstelle eine Komposition aus Rechtecken, Farben und Rauschen, die an die Struktur eines Kunstwerks von [Mark Rothko](http://de.wikipedia.org/wiki/Mark_Rothko) erinnert. + +![Mark Rothko - Three (1950)](rothko.jpg) + +## Rauschen und seine Verwendung für generative Designs + +Noise-Algorithmen wurden ursprünglich entwickelt, um digitalen Texturen ein natürliches Aussehen zu verleihen. Die ein- und zweidimensionale Implementation, die wir bislang betrachtet haben, verwendet dafür Interpolationen zwischen Zufallswerten (engl. *random values*), weshalb sie als **Value Noise** bezeichnet wird. Doch es gibt noch andere Verfahren, um Rauschen zu erzeugen. + +[ ![Inigo Quilez - Value Noise](value-noise.png) ](../edit.php#11/2d-vnoise.frag) + +Wie die vorangegangenen Abschnitte gezeigt haben, tendiert *Value Noise* zur Erzeugung blockartiger Strukturen. Um diesen Blockeffekt zu reduzieren, hat [Ken Perlin](https://mrl.nyu.edu/~perlin/) im Jahre 1985 einen weiteren Algorithmus mit Namen **Gradient Noise** entwickelt. Ken hatte herausgefunden, wie man zwischen zufälligen Gradienten (Verläufen) interpoliert, anstatt zwischen einfachen Zufallszahlen. Diese Gradienten waren das Ergebnis einer 2D-Zufallsfunktion, die Richtungsvektoren (bei GLSL in Form eines ```vec2```) anstelle einfacher Fließkommazahlen (```float```) zurückliefert. Klicke auf das folgende Bild, um einen Blick auf den dahinterstehenden Programmcode zu werfen und zu verstehen, wie das Ganze funktioniert. + +[ ![Inigo Quilez - Gradient Noise](gradient-noise.png) ](../edit.php#11/2d-gnoise.frag) + +Nimm Dir einen Moment Zeit, um die beiden folgenden Beispiele von [Inigo Quilez](http://www.iquilezles.org/) zu studieren und richte Deine Aufmerksamkeit dabei besonders auf die Unterschiede zwischen [*Value Noise*](https://www.shadertoy.com/view/lsf3WH) und [*Gradient Noise*](https://www.shadertoy.com/view/XdXGW8). + +Wie ein Maler, der genau weiß, wie die Farben auf seiner Staffelei miteinander harmonieren, werden auch wir die Noise-Funktionen umso besser nutzen können, je mehr wir deren Vorgehensweise verstehen. Wenn wir beispielsweise eine zweidimensionale Noise-Funktion nutzen, um den Raum zu drehen, während wir gerade Linien zeichnen, entsteht der folgende Dreheffekt, der stark an die Maserung von Holz erinnert. Auch hier kannst Du wieder auf die Grafik klicken, um der den Shader-Code dahinter anzuschauen. + +[ ![Holzmaserung](wood-long.png) ](../edit.php#11/wood.frag) + +```glsl + pos = rotate2d( noise(pos) ) * pos; // drehe den Raum + pattern = lines(pos,.5); // zeichne Linien +``` + +Ein anderer Weg zur Erzeugung interessanter Muster mit Hilfe von Noise-Funktionen besteht in ihrer Behandlung als Distanzfeld und der Anwendung einiger Tricks, die wir im [Kapitel über Formen](../07/) kennengelernt haben. + +[ ![Farbspritzer-Textur](splatter-long.png) ](../edit.php#11/splatter.frag) + +```glsl + color += smoothstep(.15,.2,noise(st*10.)); // schwarze Spritzer + color -= smoothstep(.35,.4,noise(st*10.)); // Löcher in den Spritzern +``` + +Ein dritter Weg basiert auf der Modulation einer Form mit Hilfe einer Noise-Funktion. Auch dabei kommen einige der Techniken zum Einsatz, die wir im [Kapitel über Formen](../07/) kennengelernt haben. + + + +Empfohlene Übungen: + +* Welche anderen generativen Designs fallen Dir ein? Was ist mit Granitgestein? Marmor? Magma? Wasser? Suche Dir drei Fotos entsprechender Materialien und entwickle die zugehörigen Algorithmen unter Einbeziehung von Noise-Funktionen. + +* Nutze Noise-Funktionen, um eine Form zu modulieren. + +* Wie steht es um die Nutzung von Noise-Funktionen für Bewegungsabläufe? Schlage noch einmal im [Kapitel über Matrizenoperationen](../08/) nach. Nutze das dortige Beispiel, in welchem das Kreuz über die Zeichenfläche bewegt wird, und füge dem Ganzen etwas Zufall und Noise hinzu. + +* Erzeuge ein generatives Design wie bei Jackson Pollocks Bildern. + +![Jackson Pollock - Number 14 gray (1948)](pollock.jpg) + +## Verbesserte Noise-Funktionen + +Eine Verbesserung von Perlin an seinem ursprünglichen **Non-Simplex Noise**-Algorithmus hin zu einem **Simplex Noise** ist der Ersatz der kubischen Hermite-Funktionn ( _f(x) = 3x^2-2x^3_, die der [```smoothstep()```](.../glossary/?search=smoothstep)-Funktion in GLSL entspricht) durch eine quintische Interpolationsfunktion ( _f(x) = 6x^5-15x^4+10x^3_ ). + +Diese lässt die Interpolationskurve an ihren Enden flacher werden, so dass sie nahtloser in die nächste Interpolationskurve übergeht. Man erhält dadurch kontinuierlichere Übergänge zwischen den einzelnen Zellen. Du kannst Dir ein Bild davon machen, indem Du die Kommentare an der zweiten Formel in dem folgenden Graphen entfernst. ([Beide Graphen in einem Bild siehst Du auch hier](https://www.desmos.com/calculator/2xvlk5xp8b)). Entscheidend ist wie immer der Bereich zwischen ```0.0``` und ```1.0``` auf der *x-Achse*. + + +
+ +Beachte, wie die beiden unterschiedlichen Kurven an ihren Endbereichen voneinander abweichen. Mehr dazu erfährst du in [Ken s eigenen Worten hier](http://mrl.nyu.edu/~perlin/paper445.pdf). + +## Simplex Noise + +Für Ken Perlin war der Erfolg seines ersten Noise-Algorithmus noch nicht genug. Er suchte weiter nach Verbesserungen. Auf der berühmten Grafik-Konferenz *Siggraph* präsentierte er im Jahre 2001 den „Simplex Noise“-Algorithmus, mit dem er die folgenden Optimierungen gegenüber dem Vorgänger erzielte: + +* Geringerer Rechenaufwand und weniger Multiplikationen. + +* Ein Rauschen, das sich auch für höhere Dimensionen berechnen lässt, ohne dass der Aufwand ins Astronomische steigt. + +* Ein Rauschen ohne sichtbare Richtungsartefakte. + +* Ein Rauschen mit sauber definierten und nahtlosen Übergangen, das sich einfach berechnen lässt. + +* Ein Algorithmus, der auch in der Hardware einfach zu implementieren ist. + +Ich weiß, was Du jetzt denkst... „Wow, wer ist dieser Mann?“ Ja, seine Leistungen sind wirklich großartig. Aber mal ganz im Ernst, wie ist es ihm gelungen, seinen Algorithmus zu verbessern? Nun, wir haben gesehen, dass er zur Berechnung des Rauschens in zwei Dimensionen zwischen den vier Eckpunkten eines Vierecks interpoliert. Man darf deshalb zurecht davon ausgehen, dass er für die Berechnung in drei Dimensionen ([eine Implementierung in GLSL findest Du hier](../edit.php#11/3d-noise.frag)) und vier Dimensionen zwischen 8 bzw. 16 einzelnen Eckpunkten interpolieren muss. Korrekt? + +In anderen Worten: Für die Berechnung des Rauschens in N Dimensionen muss man zwischen *2 hoch N* (_2^N_) verschiedenen Punkten interpolieren. Ken war jedoch aufgefallen, dass die offensichtliche „Bauweise“ für eine flächenfüllende Form zwar fraglos ein Viereck darstellt, die einfachste Form der Abdeckung jedoch mit gleichseitigen Dreiecken erzielt wird. Deshalb ersetzte er das rechtwinklige Gitternetz durch ein Netz aus gleichseitigen Dreiecken. + +![](simplex-grid-00.png) + +Mit gleichseitigen Dreiecken besteht die einfachste Form für *N Dimensionen* aus einer Konstruktion mit *N+1 Eckpunkten*. Das bedeutet einen Eckpunkt weniger für zweidimensionales Rauschen, vier Eckpunkte weniger für dreidimensionales Rauschen und elf Eckpunkte weniger für vierdimensionales Rauschen. Diese „Ersparnis“ bringt einen enorm reduzierten Rechenaufwand und dadurch einen großen Geschwindigkeitszuwachs mit sich! + +In zwei Dimensionen erfolgt die Interpolation genau wie bei der Standard Noise-Funktion. Weil wir aber ein gleichseitiges Dreieck nutzen, müssen wir dabei nur drei Punkte einbeziehen. + +![](simplex-grid-01.png) + +Doch wie wird dieses vereinfachte Gitternetz aufgebaut? In einem weiteren brillanten und äußerst eleganten Schritt, werden die Zellen des viereckigen Gitternetzes jeweils in zwei gleichschenklige Dreiecke (mit jeweils zwei gleich langen Seiten) aufgeteilt. Anschließend wird das Netz so verzerrt, dass alle Dreiecke auch gleichseitig sind (also mit jeweils drei gleich langen Seiten). Denn damit lässt sich am einfachsten interpolieren. + +![](simplex-grid-02.png) + +Anschließend fahren wir fort, wie es [Stefan Gustavson in seinen Ausführungen beschreibt](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): "*... indem wir uns die ganzzahligen Anteile der transformierten Koordinaten (x,y) des zu berechnenden Punktes anschauen, denn darüber können wir leicht feststellen, zu welchen zwei Dreiecken der Punkt gehört. Indem wir die Werte von x und y vergleichen, erfahren wir, ob sich der Punkt in dem oberen oder in dem unteren Dreieck befindet. So können wir die drei korrekten Eckpunkte in die Berechnung einbeziehen.*“ + +Im folgenden Programmcode kannst Du die Kommentarzeichen aus der *Programmzeile 44* entfernen, um zu sehen, wie das Gitternetz gezerrt wird. Und sobald Du die Kommentierung von *Zeile 47* aufhebst, erkennst Du die Aufteilung der Fläche in gleichschenklige Dreiecke. Beachte, wie wir in *Zeile 22* das verzerrte Rechteck einfach in zwei gleichseitige Dreiecke aufteilen, indem wir testen, ob ```x > y``` ist („unteres“ Dreieck) oder ```y > x``` („oberes“ Dreieck). + +
+ +All diese Verbesserungen münden in das Meisterwerk, das als **Simplex Noise**-Algorithmus bekannt ist. Der folgende Programmcode ist eine Implementation dieses Algorithmus in GLSL, die von Ian McEwan und Stefan Gustavson entwickelt wurde ([hier nachzulesen](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)). Für unsere Lernzwecke ist diese theoretische Erklärung vielleicht etwas zu aufwändig. Allerdings wirst Du beim Anklicken der Grafik und einem Blick auf den dahinterstehenden Programmcode feststellen, dass dieser weniger kryptisch daherkommt, als Du vielleicht erwartet hast. Außerdem ist der Code vergleichsweise kompakt und kann schnell ausgeführt werden. + +[ ![Ian McEwan von Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.php#11/2d-snoise-clear.frag) + +Nun aber genug der technischen Spitzfindigkeiten. Es ist an der Zeit, dass Du den Simplex Noise-Algorithmus als eine wertvolle Ressource im Rahmen Deiner eigenen Projekte zum Einsatz bringst: + +* Versuche das Besondere an den verschiedenen Implementationen von Noise zu erkennen. Stelle Sie Dir wie Rohmaterialien vor, aus denen ein Bildhauer seine Skulptur herausschält. Wie fühlen sich die unterschiedlichen Ergebnisse für Dich an? Verziehe beim Betrachten deine Augen, um der Vorstellungskraft Raum zu geben, so wie Du die Wolken nach Mustern absuchst. Was erkennst Du? Woran erinnert es Dich? Was könnte man wohl mit den verschiedenen Noise-Implementationen anstellen? Höre auf Deine innere Stimme und probiere es einfach aus! + +* Entwickle einen Shader, der die Illusion einer Strömung von Flüssigkeiten erweckt. Etwa wie bei einer Lava-Lampe, Tintentropfen, Wasser etc. + + + +* Nutze den Simplex Noise-Algorithmus um Deinen bisherigen Arbeiten mehr Textur zu verleihen. + + + +In diesem Kapitel haben wir versucht, Kontrolle über das Chaos zu erlangen. Das war keine leichte Aufgabe. Es braucht seine Zeit, um ein Meister des Rauschens und der Raumkrümmung zu werden. + +In den folgenden Kapiteln werden wir einige bekannte Techniken aufgreifen, mit Denen Du deine Fähigkeiten weiter verbessern kannst. Bis dahin genieße ein wenig Zeit draußen an der frischen Luft und lasse Dich von den Mustern und Strukturen der Natur inspirieren. Denn Deine Fähigkeiten zur Beobachtung müssen ähnlich gut entwickelt sein, wie Deine Programmierfähigkeiten. Vielleicht sogar noch besser. Genieße die wertvolle Zeit abseits des Computers! + +

"Sprich mit den Bäumen und werdet Freunde." Bob Ross +

diff --git a/11/README-fr.md b/11/README-fr.md index 745d355..970fd68 100644 --- a/11/README-fr.md +++ b/11/README-fr.md @@ -46,7 +46,7 @@ Après quoi, vous voyez deux lignes commentées, la première fait une interpola ```glsl y = mix(rand(i), rand(i + 1.0), f); -``` +``` Décommentez cette ligne pour voir ce que ça donne. Nous utilisons la partie fractionnelle `f` pour mélanger ([```mix()```](.../glossary/?search=mix)) les deux valeurs aléatoires. @@ -160,7 +160,7 @@ Une autre approche pour créer des motifs consiste à les considérer comme des Une troisième approche consiste consiste à moduler une forme. Cela fait également appel aux techniques vues au [chapitre des formes](../07/?lan=fr). - + Entraînement: @@ -243,11 +243,11 @@ Que voyez vous? qu'est ce que ça vous rappelle? quelles utilisations potentiell * Créez un shader qui donne l'illusion d'un flux ; une lava-lamp, des goutes d'encre, de l'eau, etc. - + * Utilisez le bruit simplexe pour texturer un de vos exercices précédents. - + Dans ce chapitre, nous avons appris à contrôler le chaos et ce n'était pas chose aisée! Devenir maître du Bruit demande temps et énergie. @@ -258,4 +258,4 @@ La capacité d'observation est au moins aussi importante (sinon plus) que la cap Sortez et profitez du reste de votre journée!

"Parler à l'arbre, s'en faire un ami." Bob Ross -

+

diff --git a/11/README-it.md b/11/README-it.md index 617a8ea..e124519 100644 --- a/11/README-it.md +++ b/11/README-it.md @@ -1,217 +1,217 @@ - -![NASA / WMAP science team](mcb.jpg) - -## Rumore - -È tempo di fare una pausa! Abbiamo giocato con le funzioni random che sembrano creare del rumore bianco di una televisione, la testa ci gira ancora solo al pensiero degli shader e i nostri occhi sono stanchi. È ora di andare a fare una passeggiata! - -Sentiamo l'aria sulla nostra pelle, il sole in faccia. Il mondo è un posto così vivido e ricco: colori, texture, suoni. Mentre camminiamo, non possiamo evitare di notare la superficie delle strade, rocce, alberi e nuvole. - -![](texture-00.jpg) -![](texture-01.jpg) -![](texture-02.jpg) -![](texture-03.jpg) -![](texture-04.jpg) -![](texture-05.jpg) -![](texture-06.jpg) - -L'imprevedibilità di queste texture potrebbe essere intesa come "random", ma non sembrano di certo il risultato delle funzioni random che abbiamo sperimentato in precedenza. Il "mondo reale" è un posto così ricco e complesso! Come possiamo approssimare questa varietà computazionale? - -Questa è stata la domanda che [Ken Perlin](https://mrl.nyu.edu/~perlin/) stava cercando di risolvere nei prima anni '80 quando gli fu commissionato di generare delle texture più realistiche per il film "Tron". Il risultato delle sue ricerche fu un elegante algoritmo di rumore *vincitore del premio Oscar*. (Non disperatevi.) - -![Disney - Tron (1982)](tron.jpg) - -Quanto segue non è il classico algoritmo di Perlin, ma è un buon punto di partenza per capire come generare del rumore. - -
- -In queste righe stiamo facendo qualcosa di simile a quello che abbiamo fatto nel capitolo precedente. Stiamo suddividendo un numero floating continuo (```x```) nel suo intero (```i```) e nelle componenti frazionarie (```f```). Usiamo [```floor()```](../glossary/?search=floor) per ottenere ```i``` e [```fract()```](../glossary/?search=fract) per ottenere ```f```. Poi applichiamo ```rand()``` per la parte intera di ```x```, che dà un valore random unico a ogni integer. - -Dopo di che si osservino le due righe commentate. La prima interpola ogni valore random in modo lineare. - -```glsl -y = mix(rand(i), rand(i + 1.0), f); -``` - -Andate avanti e rimuovete il commento di questa linea per vedere che cosa succede. Utilizziamo la parte frazionale `f` per mischiare ([```mix()```](../glossary/?search=mix)) i due valori random. - -A questo punto del libro, abbiamo imparato che possiamo fare meglio d'una interpolazione lineare, giusto? -Ora provate a decommentare la riga seguente, che utilizza una interpolazione [```smoothstep()```](../glossary/?search=smoothstep) invece di una lineare. - -```glsl -y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); -``` - -Tolto il commento, si noti che la transizione tra i picchi diventa armoniosa. In alcune implementazioni del rumore, troverete che i programmatori preferiscono creare le proprie curve cubiche (come la seguente formula) invece di utilizzare la funzione [```smoothstep()```](../glossary/?search=smoothstep). - -```glsl -float u = f * f * (3.0 - 2.0 * f ); // curva cubica personalizzata -y = mix(rand(i), rand(i + 1.0), u); // e con un'interpolazione -``` - -Questo *casualità armoniosa* è un punto di svolta per gli ingegneri grafici o artisti perché fornisce la capacità di generare delle immagini e delle geometrie con un tocco organico. L'Algoritmo del Rumore di Perlin è stato implementato più e più volte in diversi linguaggi e spazio dimensionale per ottenere ogni tipo di uso creativo. - -![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg) - -Ora è il vostro turno: - -* Create la vostra funzione ```float noise(float x)```. - -* Utilizzate la funzione di rumore per animare una forma geometrica spostandola, ruotandola o ridimensionandola. - -* Fate 'ballare' diverse forme geometriche usando il rumore. - -* Costruite forme "organiche" utilizzando la funzione di rumore. - -* Una volta che avete la vostra "creatura", cercate di svilupparla ulteriormente assegnandogli un particolare movimento. - -## Rumore 2D - -![](02.png) - -Ora che sappiamo come creare il rumore in una dimensione, è il momento di passare alla 2D. Nelle due dimensioni, invece di interpolare tra due punti di una linea (```fract(x)``` e ```fract(x)+1.0```), interpoleremo tra i quattro angoli di un piano quadrato (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` e ```fract(st)+vec2(1.,1.)```). - -![](01.png) - -Allo stesso modo, se si vuole ottenere del rumore 3D dobbiamo interpolare tra gli otto angoli di un cubo. Questa tecnica consiste nell'interpolazione di valori random, che è il motivo per cui si chiama **rumore del valore** (**value noise**) . - -![](04.jpg) - -Come per l'esempio 1D, questa interpolazione non è lineare, ma cubica, e interpola senza problemi tutti i punti all'interno di una griglia quadrata. - -![](05.jpg) - -Date un'occhiata alla seguente funzione di rumore. - -
- -Iniziamo scalando lo spazio di 5 (linea 45) per vedere l'interpolazione tra i quadrati della griglia. Poi all'interno della funzione rumore suddividiamo lo spazio in celle. Memorizziamo la posizione "integer" della cella insieme alle posizioni frazionarie all'interno della cella. Usiamo la posizione dell'integer per calcolare le coordinate dei quattro angoli e ottenere un valore random per ciascuno di essi (linee 23-26). Infine, alla linea 35 interpoliamo tra i 4 valori random degli angoli utilizzando le posizioni frazionarie che abbiamo ricavato in precedenza. - -Ora è il vostro turno. Provate i seguenti esercizi: - -* Cambiate il moltiplicatore alla linea 45. Provate ad animarlo. - -* A quale livello di zoom il rumore comincia a sembrare di nuovo random? - -* A che livello di zoom il rumore è impercettibile? - -* Provate a collegare questa funzione rumore alle coordinate del mouse. - -* Che cosa succede se utilizziamo il gradiente del rumore come un campo di distanza? Fatene qualcosa di interessante. - -* Ora che avete raggiunto un certo controllo sull'ordine e il caos, è il momento di utilizzare tale conoscenza. Effettuate una composizione di rettangoli, colori e rumore che assomiglia a un dipinto di [Mark Rothko](https://it.wikipedia.org/wiki/Mark_Rothko). - -![Mark Rothko - Three (1950)](rothko.jpg) - -## Usare il Rumore nella Progettazione Generativa - -Gli algoritmi di rumore sono stati originariamente progettati per dare un naturale *je ne sais quoi* alle texture digitali. Le implementazioni 1D e 2D che abbiamo visto fino ad ora erano interpolazioni tra *valori random*, che è il motivo per cui sono chiamate **valore di rumore**, ma ci sono altri modi per ottenere il rumore... - -[ ![Inigo Quilez - Value Noise](value-noise.png) ](../edit.php#11/2d-vnoise.frag) - -Come avete scoperto negli esercizi precedenti, il valore del rumore tende a sembrare a dei "blocchi". Per ridurre questo effetto, nel 1985 [Ken Perlin](https://mrl.nyu.edu/~perlin/) ha sviluppato un'altra implementazione dell'algoritmo denominato **Rumore di Gradiente** (**Gradient Noise**). Ken aveva capito come interpolare dei *gradienti* random invece che dei valori. Questi gradienti sono stati il risultato d'una funzione random 2D che restituisce le direzioni (rappresentata da un ```vec2```) al posto di singoli valori (```float```). Clicca sull'immagine seguente per vedere il codice e come funziona. - -[ ![Inigo Quilez - Gradient Noise](gradient-noise.png) ](../edit.php#11/2d-gnoise.frag) - -Guardate questi due esempi di [Inigo Quilez](http://www.iquilezles.org/) e prestate attenzione alle differenze tra il [valore del rumore](https://www.shadertoy.com/view/lsf3WH) e il [gradiente del rumore](https://www.shadertoy.com/view/XdXGW8). - -Come un pittore che capisce come i pigmenti funzionano, più sappiamo sulle varie implementazioni del rumore e meglio saremo in grado di usarle. Ad esempio, se si usa un'implementazione del rumore in due dimensioni per ruotare lo spazio in cui sono visualizzate delle linee rette, otterremo il seguente effetto visuale che sembra del legno. Anche in questo caso è possibile fare clic sull'immagine per vedere il codice. - -[ ![Wood texture](wood-long.png) ](../edit.php#11/wood.frag) - -```glsl - pos = rotate2d( noise(pos) ) * pos; // ruota lo spazio - pattern = lines(pos,.5); // disegna delle linee -``` - -Un altro modo per ottenere dal rumore dei pattern interessanti è quello di trattarlo come un campo di distanza e applicare alcuni dei trucchi descritti nel [capitolo sulle Figure](../07/). - -[ ![Splatter texture](splatter-long.png) ](../edit.php#11/splatter.frag) - -```glsl - color += smoothstep(.15,.2,noise(st*10.)); // schizzo nero - color -= smoothstep(.35,.4,noise(st*10.)); // buchi sugli schizzi -``` - -Un terzo modo di utilizzare la funzione di rumore è di modulare una forma. Questo richiede anche alcune delle tecniche che abbiamo imparato nel [capitolo sulle figure](../07/). - - - -Per la vostra pratica: - -* Quali altri pattern generativi si possono fare? Che dire del granito? marmo? magma? acqua? Trovate tre immagini di texture di vostro interesse e come poterle realizzare algoritmicamente usando il rumore. -* Utilizzate il rumore per modulare una forma. -* Cosa succede se usate il rumore per il movimento? Tornate al [capitolo sulle Matrici](../08/). Utilizzate l'esempio per traslare il "+", e applicateci alcuni movimenti *random* e derivati dal *rumore*. -* Fate un dipinto generativo alla Jackson Pollock. - -![Jackson Pollock - Number 14 gray (1948)](pollock.jpg) - -## Rumore Simplesso - -Per Ken Perlin il successo del suo algoritmo non è stato sufficiente. Ha pensato che avrebbe potuto funzionare meglio. Al Siggraph 2001 ha presentato il "rumore simplesso", in cui ha ottenuto i seguenti miglioramenti rispetto al precedente algoritmo: - -* Un algoritmo con una minore complessità computazionale e un minor numero di moltiplicazioni. -* Un rumore in grado di scalare a dimensioni superiori con meno costo computazionale. -* Un rumore senza artefatti direzionali. -* Un rumore con gradienti ben definiti e continui che possono essere calcolati abbastanza facilmente. -* Un algoritmo che è facile da implementare sull'hardware. - -So cosa state pensando... "Chi è costui?" Sì, il suo lavoro è fantastico! Ma sul serio, come ha fatto a migliorare l'algoritmo? Beh, abbiamo visto come per le due dimensioni ha interpolato 4 punti (angoli di un quadrato); allo stesso modo possiamo indovinare che per [tre (vedi un'implementazione qui)](../edit.php#11/3d-noise.frag) e quattro dimensioni abbiamo bisogno di interpolare rispettivamente 8 e 16 punti. Giusto? In altre parole per N dimensioni è necessario interpolare agevolmente dai 2 agli N punti(2^N). Ma Ken ha elegantemente notato che, anche se il quadrato è la scelta ovvia per riempire lo spazio, la figura più semplice in 2D è il triangolo equilatero. Così ha iniziato a sostituire la griglia quadrata (abbiamo appena appreso come usarla) per una griglia simplessa di triangoli equilateri. - -![](simplex-grid-00.png) - -La figura simplessa per N dimensioni è una figura con N + 1 angoli. In altre parole, un angolo in meno da calcolare in 2D, 4 in meno in 3D e 11 in meno in 4D! Questo è un enorme miglioramento! - -In due dimensioni l'interpolazione avviene in modo simile al rumore regolare, interpolando i valori degli angoli di una sezione. Ma in questo caso, utilizzando una griglia simplessa, abbiamo solo bisogno di interpolare la somma di 3 angoli. - -![](simplex-grid-01.png) - -Come è fatta la griglia simplessa? Con un'altra mossa brillante ed elegante, la griglia simplessa può essere ottenuta suddividendo le celle di una regolare griglia a 4 angoli in due triangoli isosceli e poi distorcendola finché ogni triangolo sia equilatero. - -![](simplex-grid-02.png) - -Poi, come [Stefan Gustavson descrive in questo articolo](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _".. cercando le parti intere delle coordinate trasformate (x,y) per il punto che vogliamo valutare, siamo in grado di determinare rapidamente quale cella di due simplessi contiene il punto. Confrontando anche le grandezze di x e y, siamo in grado di determinare se il punto è nel simplesso più alto o più basso, e percorrere i tre punti d'angolo corretti."_ - -Nel seguente codice è possibile rimuovere il commento alla linea 44 per vedere come la griglia è distorta, e poi rimuovere il commento alla linea 47 per vedere come una griglia simplessa può essere costruita. Notate come alla linea 22 stiamo suddividendo il quadrato distorto in due triangoli equilateri semplicemente controllando se ```x > y``` (triangolo "inferiore") oppure ```y > x``` (triangolo "superiore"). - -
- -Un altro miglioramento introdotto da Perlin con il **Rumore Simplesso**, è la sostituzione della Curva Cubica di Hermite ( _f(x) = 3x^2-2x^3_ , che è identica alla funzione [```smoothstep()```](../glossary/?search=smoothstep) ) con una Curva Quintica di Hermite ( _f(x) = 6x^5-15x^4+10x^3_ ). In questo modo entrambe le estremità della curva sono più "piatte" così che ogni limite si unisce con grazia con quello successivo. In altre parole si ottiene una transizione più continua tra le celle. Si può osservare ciò decommentando la seconda formula nel seguente esempio grafico (o osservando le [due equazioni fianco a fianco cliccando qui](https://www.desmos.com/calculator/2xvlk5xp8b)). - -
- -Si noti come le estremità della curva cambino. Si può leggere di più a proposito [sul sito di Ken](http://mrl.nyu.edu/~perlin/paper445.pdf). - -Tutti questi miglioramenti si traducono in un capolavoro algoritmico noto come **Rumore Simplesso**. La seguente è una implementazione GLSL di questo algoritmo fatta da Ian McEwan(e presentato in [questo articolo](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) che è troppo complicata per scopi didattici, ma sarete felici di fare un clic su di esso e vedere che è meno criptica di quanto si possa pensare. - -[ ![Ian McEwan of Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.php#11/2d-snoise-clear.frag) - -Beh... direi che abbiamo avuto abbastanza tecnicismi, è il momento d'utilizzare queste risorse in modo creativo: - -* Osservate ogni implementazione del rumore. Immaginatele come delle materie grezze, come delle rocce di marmo per uno scultore. Che cosa si può dire a proposito delle "sensazione" che ci trasmettono? Chiudete gli occhi per far scattare la vostra immaginazione, come quando si cercano delle forme in una nuvola. Cosa vedi? Cosa ricorderai? Che cosa si potrebbe creare da ogni implementazione del rumore? Seguite le vostre ispirazioni e cercate di realizzarle con il codice. - -* Fate uno shader che crea l'illusione di un flusso. Come una lampada di lava, gocce d'inchiostro, dell'acqua, ecc. - - - -* Utilizzate il rumore simplesso per aggiungere delle texture a dei lavori precedenti. - - - -In questo capitolo abbiamo preso controllo sul caos. Non è stato un lavoro facile! Diventare un maestro del rumore richiede tempo e impegno. - -Nei capitoli seguenti vedremo alcune tecniche ben note per perfezionare le proprie competenze e ottenere di più dal vostro rumore per progettare del contenuto generativo di qualità. Fino ad allora godetevi un po' di tempo all'aria aperta, contemplate la natura e i suoi pattern complicati. La capacità d'osservazione è altrettanto importante (se non di più) rispetto a quella di creare dei pattern. Andate fuori e godetevi il resto della giornata! - -

"Parla con l'albero, per farsi un amico." Bob Ross -

+ +![NASA / WMAP science team](mcb.jpg) + +## Rumore + +È tempo di fare una pausa! Abbiamo giocato con le funzioni random che sembrano creare del rumore bianco di una televisione, la testa ci gira ancora solo al pensiero degli shader e i nostri occhi sono stanchi. È ora di andare a fare una passeggiata! + +Sentiamo l'aria sulla nostra pelle, il sole in faccia. Il mondo è un posto così vivido e ricco: colori, texture, suoni. Mentre camminiamo, non possiamo evitare di notare la superficie delle strade, rocce, alberi e nuvole. + +![](texture-00.jpg) +![](texture-01.jpg) +![](texture-02.jpg) +![](texture-03.jpg) +![](texture-04.jpg) +![](texture-05.jpg) +![](texture-06.jpg) + +L'imprevedibilità di queste texture potrebbe essere intesa come "random", ma non sembrano di certo il risultato delle funzioni random che abbiamo sperimentato in precedenza. Il "mondo reale" è un posto così ricco e complesso! Come possiamo approssimare questa varietà computazionale? + +Questa è stata la domanda che [Ken Perlin](https://mrl.nyu.edu/~perlin/) stava cercando di risolvere nei prima anni '80 quando gli fu commissionato di generare delle texture più realistiche per il film "Tron". Il risultato delle sue ricerche fu un elegante algoritmo di rumore *vincitore del premio Oscar*. (Non disperatevi.) + +![Disney - Tron (1982)](tron.jpg) + +Quanto segue non è il classico algoritmo di Perlin, ma è un buon punto di partenza per capire come generare del rumore. + +
+ +In queste righe stiamo facendo qualcosa di simile a quello che abbiamo fatto nel capitolo precedente. Stiamo suddividendo un numero floating continuo (```x```) nel suo intero (```i```) e nelle componenti frazionarie (```f```). Usiamo [```floor()```](../glossary/?search=floor) per ottenere ```i``` e [```fract()```](../glossary/?search=fract) per ottenere ```f```. Poi applichiamo ```rand()``` per la parte intera di ```x```, che dà un valore random unico a ogni integer. + +Dopo di che si osservino le due righe commentate. La prima interpola ogni valore random in modo lineare. + +```glsl +y = mix(rand(i), rand(i + 1.0), f); +``` + +Andate avanti e rimuovete il commento di questa linea per vedere che cosa succede. Utilizziamo la parte frazionale `f` per mischiare ([```mix()```](../glossary/?search=mix)) i due valori random. + +A questo punto del libro, abbiamo imparato che possiamo fare meglio d'una interpolazione lineare, giusto? +Ora provate a decommentare la riga seguente, che utilizza una interpolazione [```smoothstep()```](../glossary/?search=smoothstep) invece di una lineare. + +```glsl +y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); +``` + +Tolto il commento, si noti che la transizione tra i picchi diventa armoniosa. In alcune implementazioni del rumore, troverete che i programmatori preferiscono creare le proprie curve cubiche (come la seguente formula) invece di utilizzare la funzione [```smoothstep()```](../glossary/?search=smoothstep). + +```glsl +float u = f * f * (3.0 - 2.0 * f ); // curva cubica personalizzata +y = mix(rand(i), rand(i + 1.0), u); // e con un'interpolazione +``` + +Questo *casualità armoniosa* è un punto di svolta per gli ingegneri grafici o artisti perché fornisce la capacità di generare delle immagini e delle geometrie con un tocco organico. L'Algoritmo del Rumore di Perlin è stato implementato più e più volte in diversi linguaggi e spazio dimensionale per ottenere ogni tipo di uso creativo. + +![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg) + +Ora è il vostro turno: + +* Create la vostra funzione ```float noise(float x)```. + +* Utilizzate la funzione di rumore per animare una forma geometrica spostandola, ruotandola o ridimensionandola. + +* Fate 'ballare' diverse forme geometriche usando il rumore. + +* Costruite forme "organiche" utilizzando la funzione di rumore. + +* Una volta che avete la vostra "creatura", cercate di svilupparla ulteriormente assegnandogli un particolare movimento. + +## Rumore 2D + +![](02.png) + +Ora che sappiamo come creare il rumore in una dimensione, è il momento di passare alla 2D. Nelle due dimensioni, invece di interpolare tra due punti di una linea (```fract(x)``` e ```fract(x)+1.0```), interpoleremo tra i quattro angoli di un piano quadrato (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` e ```fract(st)+vec2(1.,1.)```). + +![](01.png) + +Allo stesso modo, se si vuole ottenere del rumore 3D dobbiamo interpolare tra gli otto angoli di un cubo. Questa tecnica consiste nell'interpolazione di valori random, che è il motivo per cui si chiama **rumore del valore** (**value noise**) . + +![](04.jpg) + +Come per l'esempio 1D, questa interpolazione non è lineare, ma cubica, e interpola senza problemi tutti i punti all'interno di una griglia quadrata. + +![](05.jpg) + +Date un'occhiata alla seguente funzione di rumore. + +
+ +Iniziamo scalando lo spazio di 5 (linea 45) per vedere l'interpolazione tra i quadrati della griglia. Poi all'interno della funzione rumore suddividiamo lo spazio in celle. Memorizziamo la posizione "integer" della cella insieme alle posizioni frazionarie all'interno della cella. Usiamo la posizione dell'integer per calcolare le coordinate dei quattro angoli e ottenere un valore random per ciascuno di essi (linee 23-26). Infine, alla linea 35 interpoliamo tra i 4 valori random degli angoli utilizzando le posizioni frazionarie che abbiamo ricavato in precedenza. + +Ora è il vostro turno. Provate i seguenti esercizi: + +* Cambiate il moltiplicatore alla linea 45. Provate ad animarlo. + +* A quale livello di zoom il rumore comincia a sembrare di nuovo random? + +* A che livello di zoom il rumore è impercettibile? + +* Provate a collegare questa funzione rumore alle coordinate del mouse. + +* Che cosa succede se utilizziamo il gradiente del rumore come un campo di distanza? Fatene qualcosa di interessante. + +* Ora che avete raggiunto un certo controllo sull'ordine e il caos, è il momento di utilizzare tale conoscenza. Effettuate una composizione di rettangoli, colori e rumore che assomiglia a un dipinto di [Mark Rothko](https://it.wikipedia.org/wiki/Mark_Rothko). + +![Mark Rothko - Three (1950)](rothko.jpg) + +## Usare il Rumore nella Progettazione Generativa + +Gli algoritmi di rumore sono stati originariamente progettati per dare un naturale *je ne sais quoi* alle texture digitali. Le implementazioni 1D e 2D che abbiamo visto fino ad ora erano interpolazioni tra *valori random*, che è il motivo per cui sono chiamate **valore di rumore**, ma ci sono altri modi per ottenere il rumore... + +[ ![Inigo Quilez - Value Noise](value-noise.png) ](../edit.php#11/2d-vnoise.frag) + +Come avete scoperto negli esercizi precedenti, il valore del rumore tende a sembrare a dei "blocchi". Per ridurre questo effetto, nel 1985 [Ken Perlin](https://mrl.nyu.edu/~perlin/) ha sviluppato un'altra implementazione dell'algoritmo denominato **Rumore di Gradiente** (**Gradient Noise**). Ken aveva capito come interpolare dei *gradienti* random invece che dei valori. Questi gradienti sono stati il risultato d'una funzione random 2D che restituisce le direzioni (rappresentata da un ```vec2```) al posto di singoli valori (```float```). Clicca sull'immagine seguente per vedere il codice e come funziona. + +[ ![Inigo Quilez - Gradient Noise](gradient-noise.png) ](../edit.php#11/2d-gnoise.frag) + +Guardate questi due esempi di [Inigo Quilez](http://www.iquilezles.org/) e prestate attenzione alle differenze tra il [valore del rumore](https://www.shadertoy.com/view/lsf3WH) e il [gradiente del rumore](https://www.shadertoy.com/view/XdXGW8). + +Come un pittore che capisce come i pigmenti funzionano, più sappiamo sulle varie implementazioni del rumore e meglio saremo in grado di usarle. Ad esempio, se si usa un'implementazione del rumore in due dimensioni per ruotare lo spazio in cui sono visualizzate delle linee rette, otterremo il seguente effetto visuale che sembra del legno. Anche in questo caso è possibile fare clic sull'immagine per vedere il codice. + +[ ![Wood texture](wood-long.png) ](../edit.php#11/wood.frag) + +```glsl + pos = rotate2d( noise(pos) ) * pos; // ruota lo spazio + pattern = lines(pos,.5); // disegna delle linee +``` + +Un altro modo per ottenere dal rumore dei pattern interessanti è quello di trattarlo come un campo di distanza e applicare alcuni dei trucchi descritti nel [capitolo sulle Figure](../07/). + +[ ![Splatter texture](splatter-long.png) ](../edit.php#11/splatter.frag) + +```glsl + color += smoothstep(.15,.2,noise(st*10.)); // schizzo nero + color -= smoothstep(.35,.4,noise(st*10.)); // buchi sugli schizzi +``` + +Un terzo modo di utilizzare la funzione di rumore è di modulare una forma. Questo richiede anche alcune delle tecniche che abbiamo imparato nel [capitolo sulle figure](../07/). + + + +Per la vostra pratica: + +* Quali altri pattern generativi si possono fare? Che dire del granito? marmo? magma? acqua? Trovate tre immagini di texture di vostro interesse e come poterle realizzare algoritmicamente usando il rumore. +* Utilizzate il rumore per modulare una forma. +* Cosa succede se usate il rumore per il movimento? Tornate al [capitolo sulle Matrici](../08/). Utilizzate l'esempio per traslare il "+", e applicateci alcuni movimenti *random* e derivati dal *rumore*. +* Fate un dipinto generativo alla Jackson Pollock. + +![Jackson Pollock - Number 14 gray (1948)](pollock.jpg) + +## Rumore Simplesso + +Per Ken Perlin il successo del suo algoritmo non è stato sufficiente. Ha pensato che avrebbe potuto funzionare meglio. Al Siggraph 2001 ha presentato il "rumore simplesso", in cui ha ottenuto i seguenti miglioramenti rispetto al precedente algoritmo: + +* Un algoritmo con una minore complessità computazionale e un minor numero di moltiplicazioni. +* Un rumore in grado di scalare a dimensioni superiori con meno costo computazionale. +* Un rumore senza artefatti direzionali. +* Un rumore con gradienti ben definiti e continui che possono essere calcolati abbastanza facilmente. +* Un algoritmo che è facile da implementare sull'hardware. + +So cosa state pensando... "Chi è costui?" Sì, il suo lavoro è fantastico! Ma sul serio, come ha fatto a migliorare l'algoritmo? Beh, abbiamo visto come per le due dimensioni ha interpolato 4 punti (angoli di un quadrato); allo stesso modo possiamo indovinare che per [tre (vedi un'implementazione qui)](../edit.php#11/3d-noise.frag) e quattro dimensioni abbiamo bisogno di interpolare rispettivamente 8 e 16 punti. Giusto? In altre parole per N dimensioni è necessario interpolare agevolmente dai 2 agli N punti(2^N). Ma Ken ha elegantemente notato che, anche se il quadrato è la scelta ovvia per riempire lo spazio, la figura più semplice in 2D è il triangolo equilatero. Così ha iniziato a sostituire la griglia quadrata (abbiamo appena appreso come usarla) per una griglia simplessa di triangoli equilateri. + +![](simplex-grid-00.png) + +La figura simplessa per N dimensioni è una figura con N + 1 angoli. In altre parole, un angolo in meno da calcolare in 2D, 4 in meno in 3D e 11 in meno in 4D! Questo è un enorme miglioramento! + +In due dimensioni l'interpolazione avviene in modo simile al rumore regolare, interpolando i valori degli angoli di una sezione. Ma in questo caso, utilizzando una griglia simplessa, abbiamo solo bisogno di interpolare la somma di 3 angoli. + +![](simplex-grid-01.png) + +Come è fatta la griglia simplessa? Con un'altra mossa brillante ed elegante, la griglia simplessa può essere ottenuta suddividendo le celle di una regolare griglia a 4 angoli in due triangoli isosceli e poi distorcendola finché ogni triangolo sia equilatero. + +![](simplex-grid-02.png) + +Poi, come [Stefan Gustavson descrive in questo articolo](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _".. cercando le parti intere delle coordinate trasformate (x,y) per il punto che vogliamo valutare, siamo in grado di determinare rapidamente quale cella di due simplessi contiene il punto. Confrontando anche le grandezze di x e y, siamo in grado di determinare se il punto è nel simplesso più alto o più basso, e percorrere i tre punti d'angolo corretti."_ + +Nel seguente codice è possibile rimuovere il commento alla linea 44 per vedere come la griglia è distorta, e poi rimuovere il commento alla linea 47 per vedere come una griglia simplessa può essere costruita. Notate come alla linea 22 stiamo suddividendo il quadrato distorto in due triangoli equilateri semplicemente controllando se ```x > y``` (triangolo "inferiore") oppure ```y > x``` (triangolo "superiore"). + +
+ +Un altro miglioramento introdotto da Perlin con il **Rumore Simplesso**, è la sostituzione della Curva Cubica di Hermite ( _f(x) = 3x^2-2x^3_ , che è identica alla funzione [```smoothstep()```](../glossary/?search=smoothstep) ) con una Curva Quintica di Hermite ( _f(x) = 6x^5-15x^4+10x^3_ ). In questo modo entrambe le estremità della curva sono più "piatte" così che ogni limite si unisce con grazia con quello successivo. In altre parole si ottiene una transizione più continua tra le celle. Si può osservare ciò decommentando la seconda formula nel seguente esempio grafico (o osservando le [due equazioni fianco a fianco cliccando qui](https://www.desmos.com/calculator/2xvlk5xp8b)). + +
+ +Si noti come le estremità della curva cambino. Si può leggere di più a proposito [sul sito di Ken](http://mrl.nyu.edu/~perlin/paper445.pdf). + +Tutti questi miglioramenti si traducono in un capolavoro algoritmico noto come **Rumore Simplesso**. La seguente è una implementazione GLSL di questo algoritmo fatta da Ian McEwan(e presentato in [questo articolo](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) che è troppo complicata per scopi didattici, ma sarete felici di fare un clic su di esso e vedere che è meno criptica di quanto si possa pensare. + +[ ![Ian McEwan of Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.php#11/2d-snoise-clear.frag) + +Beh... direi che abbiamo avuto abbastanza tecnicismi, è il momento d'utilizzare queste risorse in modo creativo: + +* Osservate ogni implementazione del rumore. Immaginatele come delle materie grezze, come delle rocce di marmo per uno scultore. Che cosa si può dire a proposito delle "sensazione" che ci trasmettono? Chiudete gli occhi per far scattare la vostra immaginazione, come quando si cercano delle forme in una nuvola. Cosa vedi? Cosa ricorderai? Che cosa si potrebbe creare da ogni implementazione del rumore? Seguite le vostre ispirazioni e cercate di realizzarle con il codice. + +* Fate uno shader che crea l'illusione di un flusso. Come una lampada di lava, gocce d'inchiostro, dell'acqua, ecc. + + + +* Utilizzate il rumore simplesso per aggiungere delle texture a dei lavori precedenti. + + + +In questo capitolo abbiamo preso controllo sul caos. Non è stato un lavoro facile! Diventare un maestro del rumore richiede tempo e impegno. + +Nei capitoli seguenti vedremo alcune tecniche ben note per perfezionare le proprie competenze e ottenere di più dal vostro rumore per progettare del contenuto generativo di qualità. Fino ad allora godetevi un po' di tempo all'aria aperta, contemplate la natura e i suoi pattern complicati. La capacità d'osservazione è altrettanto importante (se non di più) rispetto a quella di creare dei pattern. Andate fuori e godetevi il resto della giornata! + +

"Parla con l'albero, per farsi un amico." Bob Ross +

diff --git a/11/README-jp.md b/11/README-jp.md index 0d92611..faafa81 100644 --- a/11/README-jp.md +++ b/11/README-jp.md @@ -228,4 +228,4 @@ y = x*x*(3.0-2.0*x); 続く章ではスキルを完璧なものにし、シェーダーによる質の高い作品作りにノイズをさらに生かすため、幾つかの有名なテクニックを見ていくことになります。それまでの間、少し外で自然とその複雑なパターンをじっくり眺めて楽しんでください。物事を観察するスキルは、何かを作り出すスキルと同じくらいの(もしかするともっと)献身を必要とします。外に出かけて残りの一日を楽しみましょう。

「木に話しかけて、友達になりましょう。」 - ボブの絵画教室

\ No newline at end of file + ボブの絵画教室

diff --git a/11/README.md b/11/README.md index 983e562..391c3cf 100644 --- a/11/README.md +++ b/11/README.md @@ -5,7 +5,7 @@ It's time for a break! We've been playing with random functions that look like TV white noise, our head is still spinning thinking about shaders, and our eyes are tired. Time to go out for a walk! -We feel the air on our skin, the sun in our face. The world is such a vivid and rich place. Colors, textures, sounds. While we walk we can't avoid noticing the surface of the roads, rocks, trees and clouds. +We feel the air on our skin, the sun in our face. The world is such a vivid and rich place. Colors, textures, sounds. While we walk we can't avoid noticing the surface of the roads, rocks, trees and clouds. ![](texture-00.jpg) ![](texture-01.jpg) @@ -37,18 +37,18 @@ After that you see two commented lines. The first one interpolates each random v ```glsl y = mix(rand(i), rand(i + 1.0), f); -``` +``` Go ahead and uncomment this line to see how this looks. We use the [```fract()```](../glossary/?search=fract) value store in `f` to [```mix()```](../glossary/?search=mix) the two random values. -At this point in the book, we've learned that we can do better than a linear interpolation, right? +At this point in the book, we've learned that we can do better than a linear interpolation, right? Now try uncommenting the following line, which uses a [```smoothstep()```](../glossary/?search=smoothstep) interpolation instead of a linear one. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` -After uncommenting it, notice how the transition between the peaks gets smooth. In some noise implementations you will find that programmers prefer to code their own cubic curves (like the following formula) instead of using the [```smoothstep()```](../glossary/?search=smoothstep). +After uncommenting it, notice how the transition between the peaks gets smooth. In some noise implementations you will find that programmers prefer to code their own cubic curves (like the following formula) instead of using the [```smoothstep()```](../glossary/?search=smoothstep). ```glsl float u = f * f * (3.0 - 2.0 * f ); // custom cubic curve @@ -87,7 +87,7 @@ Like the 1D example, this interpolation is not linear but cubic, which smoothly ![](05.jpg) -Take a look at the following noise function. +Take a look at the following noise function.
@@ -121,7 +121,7 @@ As you discovered in the previous exercises, value noise tends to look "blocky." Take a minute to look at these two examples by [Inigo Quilez](http://www.iquilezles.org/) and pay attention to the differences between [value noise](https://www.shadertoy.com/view/lsf3WH) and [gradient noise](https://www.shadertoy.com/view/XdXGW8). -Like a painter who understands how the pigments of their paints work, the more we know about noise implementations the better we will be able to use them. For example, if we use a two dimensional noise implementation to rotate the space where straight lines are rendered, we can produce the following swirly effect that looks like wood. Again you can click on the image to see what the code looks like. +Like a painter who understands how the pigments of their paints work, the more we know about noise implementations the better we will be able to use them. For example, if we use a two dimensional noise implementation to rotate the space where straight lines are rendered, we can produce the following swirly effect that looks like wood. Again you can click on the image to see what the code looks like. [ ![Wood texture](wood-long.png) ](../edit.php#11/wood.frag) @@ -141,7 +141,7 @@ Another way to get interesting patterns from noise is to treat it like a distanc A third way of using the noise function is to modulate a shape. This also requires some of the techniques we learned in the [chapter about shapes](../07/). - + For you to practice: @@ -154,7 +154,7 @@ For you to practice: ## Improved Noise -An improvement by Perlin to his original non-simplex noise **Simplex Noise**, is the replacement of the cubic Hermite curve ( _f(x) = 3x^2-2x^3_ , which is identical to the [```smoothstep()```](../glossary/?search=smoothstep) function) with a quintic interpolation curve ( _f(x) = 6x^5-15x^4+10x^3_ ). This makes both ends of the curve more "flat" so each border gracefully stitches with the next one. In other words, you get a more continuous transition between the cells. You can see this by uncommenting the second formula in the following graph example (or see the [two equations side by side here](https://www.desmos.com/calculator/2xvlk5xp8b)). +An improvement by Perlin to his original non-simplex noise **Simplex Noise**, is the replacement of the cubic Hermite curve ( _f(x) = 3x^2-2x^3_ , which is identical to the [```smoothstep()```](../glossary/?search=smoothstep) function) with a quintic interpolation curve ( _f(x) = 6x^5-15x^4+10x^3_ ). This makes both ends of the curve more "flat" so each border gracefully stitches with the next one. In other words, you get a more continuous transition between the cells. You can see this by uncommenting the second formula in the following graph example (or see the [two equations side by side here](https://www.desmos.com/calculator/2xvlk5xp8b)).
y``` ("lower" triangle) or ```y > x``` ("upper" triangle). @@ -206,15 +206,15 @@ Well... enough technicalities, it's time for you to use this resource in your ow * Make a shader that projects the illusion of flow. Like a lava lamp, ink drops, water, etc. - + * Use Simplex Noise to add some texture to a work you've already made. - + -In this chapter we have introduced some control over the chaos. It was not an easy job! Becoming a noise-bender-master takes time and effort. +In this chapter we have introduced some control over the chaos. It was not an easy job! Becoming a noise-bender-master takes time and effort. In the following chapters we will see some well known techniques to perfect your skills and get more out of your noise to design quality generative content with shaders. Until then enjoy some time outside contemplating nature and its intricate patterns. Your ability to observe needs equal (or probably more) dedication than your making skills. Go outside and enjoy the rest of the day!

"Talk to the tree, make friends with it." Bob Ross -

+

diff --git a/11/circleWave-noise.frag b/11/circleWave-noise.frag index 5605f31..51acfde 100644 --- a/11/circleWave-noise.frag +++ b/11/circleWave-noise.frag @@ -26,9 +26,9 @@ float noise(vec2 st) { vec2 u = f*f*(3.0-2.0*f); - return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), + return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x), - mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), + mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y); } @@ -60,4 +60,4 @@ void main() { vec3 color = vec3(1.0) * shapeBorder(st,0.8,0.02); gl_FragColor = vec4( 1.-color, 1.0 ); -} \ No newline at end of file +} diff --git a/11/iching-03.frag b/11/iching-03.frag index 8653775..e8bfbee 100644 --- a/11/iching-03.frag +++ b/11/iching-03.frag @@ -111,4 +111,4 @@ void main(){ df = mix(hex(st,t),hex(st,t+1.),fract(t)); df += snoise(vec3(st*75.,t*0.1))*0.03; gl_FragColor = vec4(mix(vec3(0.),vec3(1.),step(0.7,df)),1.0); -} \ No newline at end of file +} diff --git a/11/index.php b/11/index.php index 4245102..99aad27 100644 --- a/11/index.php +++ b/11/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/11/lava-lamp.frag b/11/lava-lamp.frag index d8e8126..5760515 100644 --- a/11/lava-lamp.frag +++ b/11/lava-lamp.frag @@ -63,4 +63,4 @@ void main() { color = vec3( smoothstep(.7,.75,fract(DF)) ); gl_FragColor = vec4(1.0-color,1.0); -} \ No newline at end of file +} diff --git a/11/notes.md b/11/notes.md index 58a06ba..4ee18ae 100644 --- a/11/notes.md +++ b/11/notes.md @@ -1,2 +1,2 @@ ### nicolas -* L78 replace `fract()` with `floor()` to match the prvious definition \ No newline at end of file +* L78 replace `fract()` with `floor()` to match the prvious definition diff --git a/11/simplex-grid.frag b/11/simplex-grid.frag index 978e600..8e9368f 100644 --- a/11/simplex-grid.frag +++ b/11/simplex-grid.frag @@ -47,4 +47,4 @@ void main() { // color = simplexGrid(st); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/splatter.frag b/11/splatter.frag index dea10fa..86a9bb3 100644 --- a/11/splatter.frag +++ b/11/splatter.frag @@ -20,9 +20,9 @@ float noise(vec2 st) { vec2 u = f*f*(3.0-2.0*f); - return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), + return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x), - mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), + mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y); } @@ -41,4 +41,4 @@ void main() { color -= smoothstep(.35,.4,noise(st*10.)); // Holes on splatter gl_FragColor = vec4(1.-color,1.0); -} \ No newline at end of file +} diff --git a/11/tmp/2d-snoise-normal.frag b/11/tmp/2d-snoise-normal.frag index 3706a76..063a23d 100644 --- a/11/tmp/2d-snoise-normal.frag +++ b/11/tmp/2d-snoise-normal.frag @@ -58,11 +58,11 @@ float snoise(vec2 v) { void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; - + float scale = 10.0; st += vec2(u_time*0.1); st *= scale; - + vec2 offset = vec2(1.)/u_resolution.xy; float center = snoise(vec2(st.x, st.y)); float topLeft = snoise(vec2(st.x - offset.x, st.y - offset.y)); @@ -73,11 +73,11 @@ void main(){ float topRight = snoise(vec2(st.x + offset.x, st.y - offset.y)); float right = snoise(vec2(st.x + offset.x, st.y)); float bottomRight= snoise(vec2(st.x + offset.x, st.y + offset.y)); - + float dX = topRight + 2.0 * right + bottomRight - topLeft - 2.0 * left - bottomLeft; float dY = bottomLeft + 2.0 * bottom + bottomRight - topLeft - 2.0 * top - topRight; - + vec3 N = normalize(vec3( dX, dY, 0.01))*.5+.5; gl_FragColor= vec4(N,1.); -} \ No newline at end of file +} diff --git a/11/tmp/3d-snoise-normal.frag b/11/tmp/3d-snoise-normal.frag index ba33196..430a6eb 100644 --- a/11/tmp/3d-snoise-normal.frag +++ b/11/tmp/3d-snoise-normal.frag @@ -13,7 +13,7 @@ vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } -float snoise(vec3 v) { +float snoise(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); @@ -32,10 +32,10 @@ float snoise(vec3 v) { vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations - i = mod289(i); - vec4 p = permute( permute( permute( + i = mod289(i); + vec4 p = permute( permute( permute( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients: 7x7 points over a square, mapped onto an octahedron. @@ -77,17 +77,17 @@ float snoise(vec3 v) { // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; - return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), + return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; - + float scale = 10.0; st *= scale; float t = u_time*0.3; - + vec2 offset = vec2(1.)/u_resolution.xy; float center = snoise(vec3(st.x, st.y, t)); float topLeft = snoise(vec3(st.x - offset.x, st.y - offset.y, t)); @@ -98,11 +98,11 @@ void main(){ float topRight = snoise(vec3(st.x + offset.x, st.y - offset.y, t)); float right = snoise(vec3(st.x + offset.x, st.y, t)); float bottomRight= snoise(vec3(st.x + offset.x, st.y + offset.y, t)); - + float dX = topRight + 2.0 * right + bottomRight - topLeft - 2.0 * left - bottomLeft; float dY = bottomLeft + 2.0 * bottom + bottomRight - topLeft - 2.0 * top - topRight; - + vec3 N = normalize(vec3( dX, dY, 0.01))*.5+.5; gl_FragColor= vec4(N,1.); -} \ No newline at end of file +} diff --git a/11/tmp/circleDistortion.frag b/11/tmp/circleDistortion.frag index 46d4063..51ee869 100644 --- a/11/tmp/circleDistortion.frag +++ b/11/tmp/circleDistortion.frag @@ -90,7 +90,7 @@ float shapeBorder(vec2 st, float radius, float width) { void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; - + vec3 color = vec3(0.0); vec3 normals = nNoise(st*6.+u_time); color = vec3(1.) * shapeBorder(st,0.8,0.02); @@ -98,4 +98,4 @@ void main() { color.g = shapeBorder(st+normals.xy*.01,0.81,0.03); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/11/tmp/circleWave-noiseChannels.frag b/11/tmp/circleWave-noiseChannels.frag index cb573cd..ded8162 100644 --- a/11/tmp/circleWave-noiseChannels.frag +++ b/11/tmp/circleWave-noiseChannels.frag @@ -86,7 +86,7 @@ void main() { float t = u_time*.1; color.r = shapeBorder(st,vec2(0.1,t),0.8,0.02); color.g = shapeBorder(st,vec2(0.2,t),0.8,0.02); - color.b = shapeBorder(st,vec2(0.3,t),0.8,0.02); + color.b = shapeBorder(st,vec2(0.3,t),0.8,0.02); gl_FragColor = vec4( color, 1.0 ); -} \ No newline at end of file +} diff --git a/11/tmp/displace-grid.frag b/11/tmp/displace-grid.frag index 3de7b53..de0b7d2 100644 --- a/11/tmp/displace-grid.frag +++ b/11/tmp/displace-grid.frag @@ -67,10 +67,10 @@ vec3 nNoise(vec2 st) { float topRight = snoise(vec2(st.x + offset.x, st.y - offset.y)); float right = snoise(vec2(st.x + offset.x, st.y)); float bottomRight= snoise(vec2(st.x + offset.x, st.y + offset.y)); - + float dX = topRight + 2.0 * right + bottomRight - topLeft - 2.0 * left - bottomLeft; float dY = bottomLeft + 2.0 * bottom + bottomRight - topLeft - 2.0 * top - topRight; - + return normalize(vec3( dX, dY, 0.01))*.5+.5; } @@ -96,6 +96,6 @@ void main(){ st += nNoise(st*10.).xy*.02*sin(u_time); float grid = 1.0-X(tile(st,10.),0.05); - + gl_FragColor= vec4(vec3(grid),1.); -} \ No newline at end of file +} diff --git a/11/tmp/displace-lines.frag b/11/tmp/displace-lines.frag index fb71d88..5f995c4 100644 --- a/11/tmp/displace-lines.frag +++ b/11/tmp/displace-lines.frag @@ -67,10 +67,10 @@ vec3 nNoise(vec2 st) { float topRight = snoise(vec2(st.x + offset.x, st.y - offset.y)); float right = snoise(vec2(st.x + offset.x, st.y)); float bottomRight= snoise(vec2(st.x + offset.x, st.y + offset.y)); - + float dX = topRight + 2.0 * right + bottomRight - topLeft - 2.0 * left - bottomLeft; float dY = bottomLeft + 2.0 * bottom + bottomRight - topLeft - 2.0 * top - topRight; - + return normalize(vec3( dX, dY, 0.01))*.5+.5; } @@ -82,6 +82,6 @@ void main(){ st += nNoise(st).xy*.1*sin(u_time); float df = sin(fract(st.y)*10.); - + gl_FragColor= vec4(vec3(1.0-smoothstep(.9,.99,df)),1.); -} \ No newline at end of file +} diff --git a/11/tmp/makegif.sh b/11/tmp/makegif.sh index d2edaf8..19bb662 100755 --- a/11/tmp/makegif.sh +++ b/11/tmp/makegif.sh @@ -7,7 +7,7 @@ COUNTER=0 for i in `seq -w 0.01 .031 $SEC`; do echo $i `glslViewer $FILE -s $i -o frame-$COUNTER.png` - let COUNTER=COUNTER+1 + let COUNTER=COUNTER+1 done convert -delay 3.5 -loop 1 frame-*.png animated.gif diff --git a/11/tmp/noise-move.frag b/11/tmp/noise-move.frag index 0d82c7f..f6b18c9 100644 --- a/11/tmp/noise-move.frag +++ b/11/tmp/noise-move.frag @@ -34,14 +34,14 @@ float box(in vec2 _st, in vec2 _size){ } float cross(in vec2 _st, float _size){ - return box(_st, vec2(_size,_size/4.)) + + return box(_st, vec2(_size,_size/4.)) + box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); - + // To move the cross we move the space vec2 translate = vec2(cos(noise(u_time)*3.1415*2.0), sin(noise(u_time)*3.1415*2.0)); @@ -54,4 +54,4 @@ void main(){ color += vec3(cross(st,0.25)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/tmp/simplex-pattern-00.frag b/11/tmp/simplex-pattern-00.frag index 401223a..d624658 100644 --- a/11/tmp/simplex-pattern-00.frag +++ b/11/tmp/simplex-pattern-00.frag @@ -114,4 +114,4 @@ void main() { gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/tmp/simplex-pattern-01.frag b/11/tmp/simplex-pattern-01.frag index c08a2e7..c28a068 100644 --- a/11/tmp/simplex-pattern-01.frag +++ b/11/tmp/simplex-pattern-01.frag @@ -61,4 +61,4 @@ void main() { color += step(.5,abs(sin(.5-S.b*3.1415*5.-t))); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/tmp/simplex-pattern-02.frag b/11/tmp/simplex-pattern-02.frag index ce86045..4b42c69 100644 --- a/11/tmp/simplex-pattern-02.frag +++ b/11/tmp/simplex-pattern-02.frag @@ -84,4 +84,4 @@ void main() { color = 1.-vec3(color.r + color.g + color.b); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/tmp/simplex-pattern-03.frag b/11/tmp/simplex-pattern-03.frag index 1860728..28b0ebd 100644 --- a/11/tmp/simplex-pattern-03.frag +++ b/11/tmp/simplex-pattern-03.frag @@ -84,7 +84,7 @@ vec2 sphereCoords(vec2 _st, float _scale){ } // -// Description : Array and textureless GLSL 2D/3D/4D simplex +// Description : Array and textureless GLSL 2D/3D/4D simplex // noise functions. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm @@ -92,13 +92,13 @@ vec2 sphereCoords(vec2 _st, float _scale){ // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } -float snoise(vec3 v) { +float snoise(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); @@ -117,10 +117,10 @@ float snoise(vec3 v) { vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations - i = mod289(i); - vec4 p = permute( permute( permute( + i = mod289(i); + vec4 p = permute( permute( permute( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients: 7x7 points over a square, mapped onto an octahedron. @@ -162,7 +162,7 @@ float snoise(vec3 v) { // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; - return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), + return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } @@ -187,4 +187,4 @@ void main() { color *= step(0.001,radius); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/tmp/simplex-pattern-04.frag b/11/tmp/simplex-pattern-04.frag index f6d9e50..6644063 100644 --- a/11/tmp/simplex-pattern-04.frag +++ b/11/tmp/simplex-pattern-04.frag @@ -59,7 +59,7 @@ vec3 aastep(float threshold, vec3 value) { } // -// Description : Array and textureless GLSL 2D/3D/4D simplex +// Description : Array and textureless GLSL 2D/3D/4D simplex // noise functions. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm @@ -67,13 +67,13 @@ vec3 aastep(float threshold, vec3 value) { // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } -float snoise(vec3 v) { +float snoise(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); @@ -92,10 +92,10 @@ float snoise(vec3 v) { vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations - i = mod289(i); - vec4 p = permute( permute( permute( + i = mod289(i); + vec4 p = permute( permute( permute( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients: 7x7 points over a square, mapped onto an octahedron. @@ -137,7 +137,7 @@ float snoise(vec3 v) { // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; - return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), + return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } @@ -155,4 +155,4 @@ void main() { pct = S.r * S.g * S.b; color = vec3(pct); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/11/tmp/vortex.frag b/11/tmp/vortex.frag index e2f2550..fdff5cd 100644 --- a/11/tmp/vortex.frag +++ b/11/tmp/vortex.frag @@ -17,7 +17,7 @@ uniform float u_time; // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } diff --git a/11/tmp/warp-grid.frag b/11/tmp/warp-grid.frag index 067e684..29b3d8a 100644 --- a/11/tmp/warp-grid.frag +++ b/11/tmp/warp-grid.frag @@ -20,9 +20,9 @@ float noise(vec2 st) { vec2 u = f*f*(3.0-2.0*f); - return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), + return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x), - mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), + mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y); } @@ -43,7 +43,7 @@ float X(vec2 _st, float _width){ // -// Description : Array and textureless GLSL 2D/3D/4D simplex +// Description : Array and textureless GLSL 2D/3D/4D simplex // noise functions. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm @@ -51,13 +51,13 @@ float X(vec2 _st, float _width){ // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } -float snoise(vec3 v) { +float snoise(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); @@ -76,10 +76,10 @@ float snoise(vec3 v) { vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations - i = mod289(i); - vec4 p = permute( permute( permute( + i = mod289(i); + vec4 p = permute( permute( permute( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients: 7x7 points over a square, mapped onto an octahedron. @@ -121,7 +121,7 @@ float snoise(vec3 v) { // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; - return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), + return 42.0 * dot( m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } @@ -132,4 +132,4 @@ void main() { float grid = 1.0-X(tile(st,15.+snoise(vec3(st,u_time*.1))),0.05); gl_FragColor = vec4(vec3(grid),1.0); -} \ No newline at end of file +} diff --git a/11/wood.frag b/11/wood.frag index 2afdf05..93554de 100644 --- a/11/wood.frag +++ b/11/wood.frag @@ -9,9 +9,9 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -float random (in vec2 st) { +float random (in vec2 st) { return fract(sin(dot(st.xy, - vec2(12.9898,78.233))) + vec2(12.9898,78.233))) * 43758.5453123); } @@ -21,9 +21,9 @@ float noise(vec2 st) { vec2 i = floor(st); vec2 f = fract(st); vec2 u = f*f*(3.0-2.0*f); - return mix( mix( random( i + vec2(0.0,0.0) ), + return mix( mix( random( i + vec2(0.0,0.0) ), random( i + vec2(1.0,0.0) ), u.x), - mix( random( i + vec2(0.0,1.0) ), + mix( random( i + vec2(0.0,1.0) ), random( i + vec2(1.0,1.0) ), u.x), u.y); } @@ -50,9 +50,9 @@ void main() { // Add noise pos = rotate2d( noise(pos) ) * pos; - + // Draw lines pattern = lines(pos,.5); gl_FragColor = vec4(vec3(pattern),1.0); -} \ No newline at end of file +} diff --git a/12/2d-voronoi.frag b/12/2d-voronoi.frag index bb7a902..c47f16e 100644 --- a/12/2d-voronoi.frag +++ b/12/2d-voronoi.frag @@ -26,7 +26,7 @@ vec3 voronoi( in vec2 x ) { vec2 g = vec2(float(i),float(j)); vec2 o = random2( n + g ); o = 0.5 + 0.5*sin( u_time + 6.2831*o ); - + vec2 r = g + o - f; float d = dot(r,r); @@ -61,17 +61,17 @@ void main() { st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(0.); - // Scale + // Scale st *= 3.; vec3 c = voronoi(st); // isolines color = c.x*(0.5 + 0.5*sin(64.0*c.x))*vec3(1.0); - // borders + // borders color = mix( vec3(1.0), color, smoothstep( 0.01, 0.02, c.x ) ); // feature points float dd = length( c.yz ); color += vec3(1.)*(1.0-smoothstep( 0.0, 0.04, dd)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/12/2d-voronoise.frag b/12/2d-voronoise.frag index e06336e..2db2271 100644 --- a/12/2d-voronoise.frag +++ b/12/2d-voronoise.frag @@ -10,8 +10,8 @@ uniform float u_time; // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. // http://iquilezles.org/www/articles/voronoise/voronoise.htm vec3 hash3( vec2 p ) { - vec3 q = vec3( dot(p,vec2(127.1,311.7)), - dot(p,vec2(269.5,183.3)), + vec3 q = vec3( dot(p,vec2(127.1,311.7)), + dot(p,vec2(269.5,183.3)), dot(p,vec2(419.2,371.9)) ); return fract(sin(q)*43758.5453); } @@ -19,9 +19,9 @@ vec3 hash3( vec2 p ) { float iqnoise( in vec2 x, float u, float v ) { vec2 p = floor(x); vec2 f = fract(x); - + float k = 1.0+63.0*pow(1.0-v,4.0); - + float va = 0.0; float wt = 0.0; for (int j=-2; j<=2; j++) { @@ -35,7 +35,7 @@ float iqnoise( in vec2 x, float u, float v ) { wt += ww; } } - + return va/wt; } @@ -48,4 +48,4 @@ void main() { float n = iqnoise(st, u_mouse.x/u_resolution.x, u_mouse.y/u_resolution.y); gl_FragColor = vec4(vec3(n),1.0); -} \ No newline at end of file +} diff --git a/12/README-de.md b/12/README-de.md index 7ac6d85..7255f4e 100644 --- a/12/README-de.md +++ b/12/README-de.md @@ -10,7 +10,7 @@ Lass uns dazu am besten ein Beispiel anschauen. ### Punkte für ein Distanzfeld -Zelluläres Rauschen basiert auf Distanzfeldern, konkret auf der Berechnung der Entfernung zum nächstgelegenen Bezugspunkt aus einer gegebenen Menge von Punkten. Lass uns annehmen, wir wollten ein Distanzfeld aus vier Punkten erzeugen. Was benötigen wir dafür? Nun, **für jeden zu berechnenden Bildpunkt auf unserer Zeichenfläche wollen wir die Entfernung zum nächstgelegenen der vier Bezugspunkte berechnen **. Das bedeutet, dass wir alle vier Bezugspunkte durchlaufen, ihre Entfernung zum aktuell bearbeiteten Pixel berechnen und uns die kleinste dieser Entfernungen merken müssen. +Zelluläres Rauschen basiert auf Distanzfeldern, konkret auf der Berechnung der Entfernung zum nächstgelegenen Bezugspunkt aus einer gegebenen Menge von Punkten. Lass uns annehmen, wir wollten ein Distanzfeld aus vier Punkten erzeugen. Was benötigen wir dafür? Nun, **für jeden zu berechnenden Bildpunkt auf unserer Zeichenfläche wollen wir die Entfernung zum nächstgelegenen der vier Bezugspunkte berechnen **. Das bedeutet, dass wir alle vier Bezugspunkte durchlaufen, ihre Entfernung zum aktuell bearbeiteten Pixel berechnen und uns die kleinste dieser Entfernungen merken müssen. ```glsl float min_dist = 100.; // speichert die kleineste Entf. zu einem der 4 Bezugspunkte @@ -41,7 +41,7 @@ In dem obigen Shader wird einer der Bezugspunkte des Distanzfelds auf die Mauspo - Gelingt es Dir, die Position der anderen Bezugspunkte zu animieren? - Nachdem Du [das Kapitel über Formen](../07/?lan=de) ja vermutlich bereits gelesen hast, stelle Dir einen interessanten Weg vor, was man mit dem vorliegenden Distanzfeld anstellen könnte. -- Was muss man tun, um das Distanzfeld um weitere Bezugspunkte zu erweitern? Wie können wir dynamisch einzelne Bezugspunkte hinzufügen oder entfernen? +- Was muss man tun, um das Distanzfeld um weitere Bezugspunkte zu erweitern? Wie können wir dynamisch einzelne Bezugspunkte hinzufügen oder entfernen? ### Kachelung und Wiederholung @@ -53,16 +53,16 @@ Ein Ansatz, um sich dieser Herausforderung zu stellen, ist die Unterteilung der Weil die Farbe für jeden Pixel in einem eigenen Thread berechnet wird, können wir die Zeichenfläche in einzelne Zellen unterteilen - jede mit einem Bezugspunkt. -Um Anomalien an den Schnittflächen zwischen den Zellen zu vermeiden, müssen wir jeweils die Entfernung zum Bezugspunkt der benachbarten Zellen überprüfen. Das ist im Wesentlichen die brillante Idee hinter dem [Ansatz von Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). +Um Anomalien an den Schnittflächen zwischen den Zellen zu vermeiden, müssen wir jeweils die Entfernung zum Bezugspunkt der benachbarten Zellen überprüfen. Das ist im Wesentlichen die brillante Idee hinter dem [Ansatz von Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Letztendlich muss jeder Pixel nur die Entfernung zu neun Bezugspunkten berechnen: Dem seiner eigenen Zelle und jene der acht umliegenden Zellen. Alle anderen Zellen sind zu weit entfernt. -Wir haben bereits in den Kapiteln über [Muster](../09/?lan=de), [Generative Designs](../10/?lan=de) und [Rauschen](../11/?lan=de) gesehen, wie man die Zeichenfläche in einzelne Zellen unterteilt, von daher bist Du mit diesem Prinzip wahrscheinlich schon vertraut. +Wir haben bereits in den Kapiteln über [Muster](../09/?lan=de), [Generative Designs](../10/?lan=de) und [Rauschen](../11/?lan=de) gesehen, wie man die Zeichenfläche in einzelne Zellen unterteilt, von daher bist Du mit diesem Prinzip wahrscheinlich schon vertraut. ```glsl // den Raum aufblaehen ... st *= 3.; - + // ... und in Zellen unterteilen vec2 i_st = floor(st); vec2 f_st = fract(st); @@ -83,7 +83,7 @@ Der jeweils zu zeichnende Bildpunkt innerhalb der Zelle (gespeichert in dem Flie Das Ergebnis sieht dann wie folgt aus: - + Aber wir wollen ja zusätzlich noch die Entfernung zu den Bezugspunkten in den umliegenden Zellen einbeziehen. Dafür müssen wir diese Zellen **durchlaufen**. Aber nicht alle, sondern nur die unmittelbar angrenzenden. Das heißt die Zellen mit den Abständen von ```-1``` (links) bis ```1``` (rechts) entlang der ```x```-Achse, sowie die Zellen mit den Abständen von ```-1``` (unten) bis ```1``` (oben) entlang der ```y```-Achse. Dieser Bereich von 3x3 Zellen lässt sich leicht mit Hilfe einer doppelten ```for```-Schleife abarbeiten, so wie im Folgenden gezeigt: @@ -103,7 +103,7 @@ Nun können wir die Bezugspunkte aus jeder der benachbarten Zellen in unserer do ```glsl ... - // Zufallsposition von der aktuellen + der benachbarten Zelle im Raster + // Zufallsposition von der aktuellen + der benachbarten Zelle im Raster vec2 point = random2(i_st + neighbor); ... ``` @@ -113,7 +113,7 @@ Dann bleibt nur noch, die Entfernung vom aktuell zu zeichnenden Punkt zu dem jew ```glsl ... vec2 diff = neighbor + point - f_st; - + // Entfernung zu diesem Punkt float dist = length(diff); @@ -126,7 +126,7 @@ Der obige Programmcode wurde durch einen [Artikel von Inigo Quilez](http://www.i „... es ist vielleicht interessant darauf hinzuweisen, dass in dem obigen Code ein netter Trick steckt. Die meisten Implementationen dieses Algorithmus leiden unter einer schlechten Präzision der Berechnungen, weil sie die zufälligen Bezugspunkte auf den gesamten Koordinatenraum beziehen, so dass die Koordinaten sehr weit vom Ursprung entfernt sind. Man kann dagegen ansteuern, indem man Variablentypen mit besonders hoher Genauigkeit verwendet, was sich jedoch negativ auf die Geschwindigkeit der Berechnungen auswirkt. Oder man macht es etwas cleverer, indem man die Koordinaten nicht auf den gesamten Koordinatenraum bezieht, sondern auf die Ebene der einzelnen Zellen: Sobald der ganzzahlige Teil und der Nachkommateil des zu zeichnenden Punktes berechnet sind und dadurch die Zelle feststeht, in der sich der Punkt befindet, beschäftigen wir uns nur noch damit, was um diese Zelle herum geschieht. Dadurch müssen wir uns nicht mehr um den ganzzahligen Teil der Koordinaten kümmern, wodurch man viele Bits bei den weiteren Berechnungen einspart. Tatsächlich steuern bei herkömmlichen Voronoi-Implementierungen die ganzzahligen Anteile der Punktkoordinaten ebenfalls dem Wert 0 entgegen, sobald die zufälligen Bezugspunkte der Zellen vom aktuell zu zeichnenden Punkt abgezogen werden. In der obigen Implementation lassen wir es gar nicht erst so weit kommen, weil wir alle Koordinatenberechnungen auf den Raum der Zellen beziehen. Mit diesem Trick kann man sogar einen ganzen Planeten mit derartig geformten Voronoi-Zellen überziehen, indem man die Punktkoordinaten einfach in doppelter Fließkommagenauigkeit darstellt, die Berechnungen von ```floor()``` und ```fract()``` durchführt, und dann mit einfacher Fließkommagenauigkeit fortfährt. So erspart man sich den (Zeit-) Aufwand, die gesamte Berechnung mit doppelter Fließkommagenauigkeit auszuführen. Natürlich kann man diesen Trick auch auf Perlins Noise-Algorithmus anwenden (allerdings habe ich noch nie ein solche Implementation gesehen). “ -Um es noch einmal zusammenzufassen: Wir unterteilen den Raum in einzelne Zellen. Für jeden zu zeichnenden Punkt berechnen wir die kleinste Entfernung zum Bezugspunkt seiner Zelle bzw. zu den Bezugspunkten der acht umliegenden Zellen. Als Ergebnis erhalten wir ein Distanzfeld, so wie in dem folgenden Beispiel: +Um es noch einmal zusammenzufassen: Wir unterteilen den Raum in einzelne Zellen. Für jeden zu zeichnenden Punkt berechnen wir die kleinste Entfernung zum Bezugspunkt seiner Zelle bzw. zu den Bezugspunkten der acht umliegenden Zellen. Als Ergebnis erhalten wir ein Distanzfeld, so wie in dem folgenden Beispiel:
@@ -155,19 +155,19 @@ Die Erzeugung von Voronoi-Diagrammen auf Basis von zellulärem Rauschen ist weni ... ``` -Bitte beachte, dass wir in dem folgenden Programmcode die geringste Entfernung nicht mehr mit Hilfe der ```min```-Funktion berechnen, sondern einen herkömmlichen ```if```-Befehl einsetzen. Warum wir das tun? Weil wir diesmal etwas mehr unternehmen wollen, sobald ein neuer näherliegender Punkt auftaucht, nämlich seine Position speichern (*Programmzeilen 32 bis 37*). +Bitte beachte, dass wir in dem folgenden Programmcode die geringste Entfernung nicht mehr mit Hilfe der ```min```-Funktion berechnen, sondern einen herkömmlichen ```if```-Befehl einsetzen. Warum wir das tun? Weil wir diesmal etwas mehr unternehmen wollen, sobald ein neuer näherliegender Punkt auftaucht, nämlich seine Position speichern (*Programmzeilen 32 bis 37*).
Du wirst sehen, dass die Farbe der beweglichen Zelle (die dem Mauszeiger folgt) auf Basis ihrer Position wechselt. Die Ursache dafür ist, dass hier die Farbe aufgrund des Wertes (der Position) des nächstgelegenen Bezugspunktes zugewiesen wird. -Genau wie zuvor ist es nun an der Zeit, das Ganze zu erweitern, indem wir zu dem Algorithmus aus dem [Papier von Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf) übergehen. Versuche doch einmal selbst, diesen Algorithmus zu implementieren. Du kannst dabei auf das folgende Beispiel zurückgreifen, indem Du darauf klickst. +Genau wie zuvor ist es nun an der Zeit, das Ganze zu erweitern, indem wir zu dem Algorithmus aus dem [Papier von Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf) übergehen. Versuche doch einmal selbst, diesen Algorithmus zu implementieren. Du kannst dabei auf das folgende Beispiel zurückgreifen, indem Du darauf klickst. -Bitte beachte, dass der ursprüngliche Ansatz von Steven Worley eine variable Anzahl von Bezugspunkten für jede Zelle vorsieht. In seiner Implementation des Algorithmus in C nutzt er dies für einen zeitigen Abbruch der Schleife. Schleifen in GLSL erlauben jedoch keinen vorzeitigen Ausstieg oder eine variable Anzahl von Schleifendurchläufen, deshalb wirst Du vielleicht besser bei einem Bezugspunkt pro Zelle bleiben. +Bitte beachte, dass der ursprüngliche Ansatz von Steven Worley eine variable Anzahl von Bezugspunkten für jede Zelle vorsieht. In seiner Implementation des Algorithmus in C nutzt er dies für einen zeitigen Abbruch der Schleife. Schleifen in GLSL erlauben jedoch keinen vorzeitigen Ausstieg oder eine variable Anzahl von Schleifendurchläufen, deshalb wirst Du vielleicht besser bei einem Bezugspunkt pro Zelle bleiben. -Sobald Du die Funktionsweise dieses Algorithmus verstanden hast, kannst Du über interessante und kreative Einsatzmöglichkeiten nachdenken. +Sobald Du die Funktionsweise dieses Algorithmus verstanden hast, kannst Du über interessante und kreative Einsatzmöglichkeiten nachdenken. ![Extended Voronoi - Leo Solaas (2011)](solas.png) @@ -187,16 +187,15 @@ Im Jahre 2011 hat [Stefan Gustavson eine Optimierung von Steven Worleys Algorith Im Jahre 2012 präsentierte [Inigo Quilez einen interessanten Artikel über die Erzeugung präziser Voronoi-Abgrenzungen](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm). - + Inigos Experimente zu diesem Thema hörten damit nicht auf. Im Jahr 2014 verfasste er einen schönen Beitrag über das, was er als [Voro-Noise, dt. „Voro-Rauschen“](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm) bezeichnet - eine Funktion, die einen graduellen Übergang zwischen normalem Rauschen und Voronoi-Rauschen ermöglicht. Er schrieb: „Abgesehen von ihrer Ähnlichkeit ist es entscheidend, dass das Raster aus Zellen in beiden Mustern unterschiedlich verwendet wird. Interpoliertes Rauschen mit Zufallswerten (wie bei Value-Noise) oder mit Gradienten (wie bei Gradient-Noise) unterscheidet sich von Voronoi, wo es auf die Entfernung zum nächstgelegenen Bezugspunkt ankommt. Schließlich sind die bilineare Interpolation und die Minima-Berechnung zwei ganz unterschiedliche Operationen, nicht wahr? Doch vielleicht kann man sie in einem größeren Rahmen vereinigen? Sollte das möglich sein, könnte man sowohl Rauschmuster als auch Voronoi-Muster als Spezialfälle eines allgemeineren rasterbasierten Mustergenerators betrachten.“ - + Nun ist die Zeit gekommen, dass Du Dir die Dinge genau anschaust, Dich von der Natur inspirieren lässt und Deine eigene Nutzungsmöglichkeiten dieser Techniken entdeckst! ![Deyrolle glass film - 1831](DeyrolleFilm.png)
- diff --git a/12/README-fr.md b/12/README-fr.md index dc1cdca..73b12f8 100644 --- a/12/README-fr.md +++ b/12/README-fr.md @@ -190,13 +190,13 @@ Cela amoindrit la charge de manière significative mais peut créer des artefact Plus tard, en 2012 [Inigo Quilez a écrit un article expliquant comment trouver des frontières précises](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm). - + Inigio ne s'est pas arrété là et en 2014, il a écrit un article sur ce qu'il a appelé le [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm) ; une exploration combinant bruit et cellules de Voronoi. Je cite: *"Despite this similarity, the fact is that the way the grid is used in both patterns is different. Noise interpolates/averages random values (as in value noise) or gradients (as in gradient noise), while Voronoi computes the distance to the closest feature point. Now, smooth-bilinear interpolation and minimum evaluation are two very different operations, or... are they? Can they perhaps be combined in a more general metric? If that was so, then both Noise and Voronoi patterns could be seen as particular cases of a more general grid-based pattern generator?"* - + Il est temps de revenir à la nature, d'être inspiré par elle et de trouver votre propre voie au travers de cette technique. diff --git a/12/README.md b/12/README.md index 8f85ad2..0832294 100644 --- a/12/README.md +++ b/12/README.md @@ -52,9 +52,9 @@ You probably notice that ```for``` loops and *arrays* are not very good friends One way to approach this problem is to divide the space into tiles. Not every pixel needs to check the distance to every single point, right? Given the fact that each pixel runs in its own thread, we can subdivide the space into cells, each one with one unique point to watch. Also, to avoid aberrations at the edges between cells we need to check for the distances to the points on the neighboring cells. That's the main brillant idea of [Steven Worley's paper](http://www.rhythmiccanvas.com/research/papers/worley.pdf). At the end, each pixel needs to check only nine positions: their own cell's point and the points in the 8 cells around it. We already subdivide the space into cells in the chapters about: [patterns](../09/), [random](../10/) and [noise](../11/), so hopefully you are familiar with this technique by now. ```glsl - // Scale + // Scale st *= 3.; - + // Tile the space vec2 i_st = floor(st); vec2 f_st = fract(st); @@ -66,7 +66,7 @@ So, what's the plan? We will use the tile coordinates (stored in the integer coo vec2 point = random2(i_st); ``` -Each pixel inside that tile (stored in the float coordinate, ```f_st```) will check their distance to that random point. +Each pixel inside that tile (stored in the float coordinate, ```f_st```) will check their distance to that random point. ```glsl vec2 diff = point - f_st; @@ -75,7 +75,7 @@ Each pixel inside that tile (stored in the float coordinate, ```f_st```) will ch The result will look like this: - + We still need to check the distances to the points in the surrounding tiles, not just the one in the current tile. For that we need to **iterate** through the neighbor tiles. Not all tiles, just the ones immediately around the current one. That means from ```-1``` (left) to ```1``` (right) tile in ```x``` axis and ```-1``` (bottom) to ```1``` (top) in ```y``` axis. A 3x3 region of 9 tiles can be iterated through using a double ```for``` loop like this one: @@ -105,7 +105,7 @@ The rest is all about calculating the distance to that point and store the close ```glsl ... vec2 diff = neighbor + point - f_st; - + // Distance to the point float dist = length(diff); @@ -147,11 +147,11 @@ Constructing Voronoi diagrams from cellular noise is less hard that what it migh ... ``` -Note that in the following code that we are not longer using ```min``` to calculate the closest distance, but a regular ```if``` statement. Why? Because we actually want to do something more every time a new closer point appears, namely store its position (lines 32 to 37). +Note that in the following code that we are not longer using ```min``` to calculate the closest distance, but a regular ```if``` statement. Why? Because we actually want to do something more every time a new closer point appears, namely store its position (lines 32 to 37).
-Note how the color of the moving cell (bound to the mouse position) changes color according to its position. That's because the color is assigned using the value (position) of the closest point. +Note how the color of the moving cell (bound to the mouse position) changes color according to its position. That's because the color is assigned using the value (position) of the closest point. Like we did before, now is the time to scale this up, switching to [Steven Worley's paper approach](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Try implementing it yourself. You can use the help of the following example by clicking on it. Note that Steven Worley's original approach uses a variable number of feature points for each tile, more than one in most tiles. In his software implementation in C, this is used to speed up the loop by making early exits. GLSL loops don't allow variable number of iterations, so you probably want to stick to one feature point per tile. @@ -176,12 +176,12 @@ In 2011, [Stefan Gustavson optimized Steven Worley's algorithm to GPU](http://we Later in 2012 [Inigo Quilez wrote an article on how to make precise Voronoi borders](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm). - + Inigo's experiments with Voronoi didn't stop there. In 2014 he wrote this nice article about what he calls [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), an function that allows a gradual blend between regular noise and voronoi. In his words: *"Despite this similarity, the fact is that the way the grid is used in both patterns is different. Noise interpolates/averages random values (as in value noise) or gradients (as in gradient noise), while Voronoi computes the distance to the closest feature point. Now, smooth-bilinear interpolation and minimum evaluation are two very different operations, or... are they? Can they perhaps be combined in a more general metric? If that was so, then both Noise and Voronoi patterns could be seen as particular cases of a more general grid-based pattern generator?"* - + Now it's time for you to look closely at things, be inspired by nature and find your own take on this technique! diff --git a/12/TITLE.md b/12/TITLE.md index 9894e48..6e21476 100644 --- a/12/TITLE.md +++ b/12/TITLE.md @@ -1 +1 @@ -Cellular Noise \ No newline at end of file +Cellular Noise diff --git a/12/cellnoise-00.frag b/12/cellnoise-00.frag index fb93204..f835985 100644 --- a/12/cellnoise-00.frag +++ b/12/cellnoise-00.frag @@ -22,22 +22,22 @@ void main() { point[2] = vec2(0.28,0.64); point[3] = vec2(0.31,0.26); point[4] = u_mouse/u_resolution; - + float m_dist = 1.; // minimun distance // Iterate through the points positions for (int i = 0; i < 5; i++) { float dist = distance(st, point[i]); - + // Keep the closer distance m_dist = min(m_dist, dist); } - + // Draw the min distance (distance field) color += m_dist; // Show isolines // color -= step(.7,abs(sin(50.0*m_dist)))*.3; - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/12/cellnoise-01.frag b/12/cellnoise-01.frag index 4d19964..81b03fd 100644 --- a/12/cellnoise-01.frag +++ b/12/cellnoise-01.frag @@ -17,17 +17,17 @@ void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(.0); - - // Scale + + // Scale st *= 3.; - + // Tile the space vec2 i_st = floor(st); vec2 f_st = fract(st); vec2 point = random2(i_st); vec2 diff = point - f_st; - + float dist = length(diff); // Draw the min distance (distance field) @@ -35,12 +35,12 @@ void main() { // Draw cell center color += 1.-step(.02, dist); - + // Draw grid color.r += step(.98, f_st.x) + step(.98, f_st.y); - + // Show isolines // color -= step(.7,abs(sin(27.0*dist)))*.5; - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/12/cellnoise-02.frag b/12/cellnoise-02.frag index 0ac68f6..cf79de2 100644 --- a/12/cellnoise-02.frag +++ b/12/cellnoise-02.frag @@ -17,30 +17,30 @@ void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(.0); - - // Scale + + // Scale st *= 3.; - + // Tile the space vec2 i_st = floor(st); vec2 f_st = fract(st); float m_dist = 1.; // minimun distance - + for (int y= -1; y <= 1; y++) { for (int x= -1; x <= 1; x++) { // Neighbor place in the grid vec2 neighbor = vec2(float(x),float(y)); - + // Random position from current + neighbor place in the grid vec2 point = random2(i_st + neighbor); // Animate the point point = 0.5 + 0.5*sin(u_time + 6.2831*point); - + // Vector between the pixel and the point vec2 diff = neighbor + point - f_st; - + // Distance to the point float dist = length(diff); @@ -54,12 +54,12 @@ void main() { // Draw cell center color += 1.-step(.02, m_dist); - + // Draw grid color.r += step(.98, f_st.x) + step(.98, f_st.y); - + // Show isolines // color -= step(.7,abs(sin(27.0*m_dist)))*.5; - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/12/index.php b/12/index.php index bb36815..300bfee 100644 --- a/12/index.php +++ b/12/index.php @@ -1,4 +1,4 @@ -0.00001 ) @@ -72,15 +72,15 @@ void main() { st.x -= (u_resolution.x*.5-u_resolution.y*.5)/u_resolution.y; } vec3 color = vec3(0.0); - + float d = dot(st-.5,st-.5); vec3 c = voronoi( 20.*st, pow(d,.4) ); - // borders + // borders color = mix( vec3(1.0), color, smoothstep( 0.01, 0.02, c.x ) ); // feature points float dd = length( c.yz ); color += vec3(1.)*(1.0-smoothstep( 0.0, 0.1, dd)); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/12/tmp/particle-gradient.frag b/12/tmp/particle-gradient.frag index b922744..524e6d6 100755 --- a/12/tmp/particle-gradient.frag +++ b/12/tmp/particle-gradient.frag @@ -59,7 +59,7 @@ void main(void) { n = step(pct,F.x*2.); vec2 p = vec2(2./u_resolution.xy); - + float avg = 0.0; avg += getIntensity(st+vec2(p.x,0.0)); avg += getIntensity(st+vec2(-p.x,0.0)); diff --git a/12/vorono-00.frag b/12/vorono-00.frag index 4eea952..51df08b 100644 --- a/12/vorono-00.frag +++ b/12/vorono-00.frag @@ -22,7 +22,7 @@ void main() { point[2] = vec2(0.28,0.64); point[3] = vec2(0.31,0.26); point[4] = u_mouse/u_resolution; - + float m_dist = 1.; // minimun distance vec2 m_point; // minimum position @@ -38,17 +38,17 @@ void main() { } } - // Add distance field to closest point center + // Add distance field to closest point center color += m_dist*2.; // tint acording the closest point position color.rg = m_point; - + // Show isolines color -= abs(sin(80.0*m_dist))*0.07; - + // Draw point center color += 1.-step(.02, m_dist); - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/12/vorono-01.frag b/12/vorono-01.frag index 3fdd7fe..d6feb04 100644 --- a/12/vorono-01.frag +++ b/12/vorono-01.frag @@ -17,17 +17,17 @@ void main() { vec2 st = gl_FragCoord.xy/u_resolution.xy; st.x *= u_resolution.x/u_resolution.y; vec3 color = vec3(.0); - - // Scale + + // Scale st *= 5.; - + // Tile the space vec2 i_st = floor(st); vec2 f_st = fract(st); float m_dist = 10.; // minimun distance vec2 m_point; // minimum point - + for (int j=-1; j<=1; j++ ) { for (int i=-1; i<=1; i++ ) { vec2 neighbor = vec2(float(i),float(j)); @@ -45,18 +45,18 @@ void main() { // Assign a color using the closest point position color += dot(m_point,vec2(.3,.6)); - - // Add distance field to closest point center + + // Add distance field to closest point center // color.g = m_dist; // Show isolines color -= abs(sin(40.0*m_dist))*0.07; - + // Draw cell center color += 1.-step(.05, m_dist); - + // Draw grid color.r += step(.98, f_st.x) + step(.98, f_st.y); - + gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/13/1d-fbm.frag b/13/1d-fbm.frag index f7606dc..add80b6 100644 --- a/13/1d-fbm.frag +++ b/13/1d-fbm.frag @@ -10,7 +10,7 @@ uniform vec2 u_mouse; uniform float u_time; float plot(vec2 st, float pct){ - return smoothstep( pct-0.01, pct, st.y) - + return smoothstep( pct-0.01, pct, st.y) - smoothstep( pct, pct+0.01, st.y); } @@ -56,4 +56,4 @@ void main() { color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/13/2d-fbm.frag b/13/2d-fbm.frag index 84efb7f..d4fdfca 100644 --- a/13/2d-fbm.frag +++ b/13/2d-fbm.frag @@ -9,9 +9,9 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -float random (in vec2 st) { +float random (in vec2 st) { return fract(sin(dot(st.xy, - vec2(12.9898,78.233)))* + vec2(12.9898,78.233)))* 43758.5453123); } @@ -29,8 +29,8 @@ float noise (in vec2 st) { vec2 u = f * f * (3.0 - 2.0 * f); - return mix(a, b, u.x) + - (c - a)* u.y * (1.0 - u.x) + + return mix(a, b, u.x) + + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } @@ -58,4 +58,4 @@ void main() { color += fbm(st*3.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/13/README-de.md b/13/README-de.md index 8c43783..c79a9ad 100644 --- a/13/README-de.md +++ b/13/README-de.md @@ -32,7 +32,7 @@ y += sin(x*frequenz*3.1122+ t*4.269)*2.5; y *= amplitude*0.06; ">
-* Experimentiere mit Veränderungen der Amplitude und der Frequenz bei den hinzuaddierten Wellen. +* Experimentiere mit Veränderungen der Amplitude und der Frequenz bei den hinzuaddierten Wellen. * Gelingt es Dir, zwei Wellen zu erschaffen, die sich gegenseitig aufheben? Wie würde das aussehen? * Ist es möglich, Wellen auf eine bestimmte Art und Weise zu addieren, so dass sie sich gegenseitig verstärken? @@ -70,15 +70,15 @@ Der folgende Programmcode liefert ein Beispiel dafür, wie man eine fBm in zwei
-* Reduziere die Anzahl der Oktaven, indem Du den Wert der Konstanten in *Zeile 37* änderst. +* Reduziere die Anzahl der Oktaven, indem Du den Wert der Konstanten in *Zeile 37* änderst. * Ändere die Porosität der fBm in *Zeile 47*. * Untersuche die Auswirkungen, wenn Du die Verstärkung in *Zeile 48* veränderst. -Diese Technik wird in der Computergrafik häufig angewandt, um auf prozedurale Weise künstliche Landschaften zu erzeugen. Die Selbstähnlichkeit als Merkmal einer fBm ist perfekt für die Erzeugung von Bergen, Bergketten und ihren Tälern geeignet. Schließlich erzeugt die Erosion, die diese Strukturen in der Natur hervorbringt, ebenfalls eine Selbstähnlichkeit in mehreren unterschiedlichen Größenordnungen – im Großen wie im Kleinen. Falls Dich das Thema interessiert, empfehle ich Dir diesen [hervorragenden Beitrag von Inigo Quiles über hochentwickeltes Rauschen](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm). +Diese Technik wird in der Computergrafik häufig angewandt, um auf prozedurale Weise künstliche Landschaften zu erzeugen. Die Selbstähnlichkeit als Merkmal einer fBm ist perfekt für die Erzeugung von Bergen, Bergketten und ihren Tälern geeignet. Schließlich erzeugt die Erosion, die diese Strukturen in der Natur hervorbringt, ebenfalls eine Selbstähnlichkeit in mehreren unterschiedlichen Größenordnungen – im Großen wie im Kleinen. Falls Dich das Thema interessiert, empfehle ich Dir diesen [hervorragenden Beitrag von Inigo Quiles über hochentwickeltes Rauschen](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm). ![Blackout - Dan Holdsworth (2010)](holdsworth.jpg) -Mit mehr oder weniger derselben Technik lassen sich auch andere Effekte nachahmen, beispielsweise **Turbulenzen**. Dies geschieht mit einer fBm, wobei allerdings der Absolutwert einer vorzeichenbehafteten Rauschfunktion genutzt wird, um starke Täler zu erzeugen. +Mit mehr oder weniger derselben Technik lassen sich auch andere Effekte nachahmen, beispielsweise **Turbulenzen**. Dies geschieht mit einer fBm, wobei allerdings der Absolutwert einer vorzeichenbehafteten Rauschfunktion genutzt wird, um starke Täler zu erzeugen. ```glsl for (int i = 0; i < OKTAVEN; i++) { @@ -88,7 +88,7 @@ for (int i = 0; i < OKTAVEN; i++) { } ``` - + Ein weiteres Mitglied aus dieser Familie von Funktionen ist der **Bergrücken**, bei dem die tiefen Täler nach oben gekehrt werden, um scharfe Bergrücken bzw. Bergkämme zu erzeugen: @@ -98,15 +98,15 @@ Ein weiteres Mitglied aus dieser Familie von Funktionen ist der **Bergrücken**, n = n * n; // intensiviere die Ausbuchtung ``` - + Eine andere Variante dieses Verfahrens mit interessanten Ergebnissen besteht in der Multiplikation der einzelnen Rauschelemente anstelle der Addition. Man kann außerdem die Skalierung nicht gleichförmig mit jeder Detailebene (jedem Schleifendurchlauf) fortsetzen, sondern von den Ergebnissen vorheriger Schleifendurchläufe abhängig machen. Damit verlässt man allerdings die Welt klassischer Fraktale und dringt in das noch wenig erforschte Feld der „Multifraktale“ vor. Diese sind mathematisch nicht streng definiert, aber das macht sie für die Computergrafik nicht weniger nützlich. Tatsächlich werden Multifraktale bereits vielfältig in Software für die künstliche Erzeugung von Landschaftsstrukturen eingesetzt. -Falls Dich dieses Thema interessiert, kannst Du darüber z.B. in Kapitel 16 des Buches „Texturing and Modeling: a Procedural Approach“ (dritte Auflage) von Kenton Musgrave, mehr erfahren. Leider ist das Buch seit einigen Jahren vergriffen, aber man findet es noch in Bibliotheken und auf dem Gebrauchtmarkt. (Eine PDF-Version der ersten Auflage wird im Internet verkauft, aber die stammt von 1994 und enthält leider noch nicht die hier empfohlenen Kapitel.) +Falls Dich dieses Thema interessiert, kannst Du darüber z.B. in Kapitel 16 des Buches „Texturing and Modeling: a Procedural Approach“ (dritte Auflage) von Kenton Musgrave, mehr erfahren. Leider ist das Buch seit einigen Jahren vergriffen, aber man findet es noch in Bibliotheken und auf dem Gebrauchtmarkt. (Eine PDF-Version der ersten Auflage wird im Internet verkauft, aber die stammt von 1994 und enthält leider noch nicht die hier empfohlenen Kapitel.) ### Raumkrümmung -[Inigo Quiles hat einen weiteren faszinierenden Artikel](http://www.iquilezles.org/www/articles/warp/warp.htm) darüber verfasst, wie man ein fBm einsetzen kann, um einen Raum aus fBm zu verzerren. Abgefahren, nicht wahr? Das ist wie ein Traum über einen Traum, in dem es richtig rundgeht. +[Inigo Quiles hat einen weiteren faszinierenden Artikel](http://www.iquilezles.org/www/articles/warp/warp.htm) darüber verfasst, wie man ein fBm einsetzen kann, um einen Raum aus fBm zu verzerren. Abgefahren, nicht wahr? Das ist wie ein Traum über einen Traum, in dem es richtig rundgeht. ![ f(p) = fbm( p + fbm( p + fbm( p ) ) ) - Inigo Quiles (2002)](quiles.jpg) diff --git a/13/README-fr.md b/13/README-fr.md index 0224bec..4a3e393 100644 --- a/13/README-fr.md +++ b/13/README-fr.md @@ -114,7 +114,7 @@ for (int i = 0; i < OCTAVES; i++) { } ``` - + Une seconde variante dite *ridge noise* (bruit de *crête* ou d'*arête*) consiste à inverser les vallées: @@ -124,7 +124,7 @@ Une seconde variante dite *ridge noise* (bruit de *crête* ou d'*arête*) consis n = n * n; // sharpen creases ``` - + Une autre variante consiste à multiplier les valeurs de bruit au lieu de les additionner. Il est intéressant de modifier l'échelle d'une itération de bruit en fonction du bruit de l'itération precédente. diff --git a/13/README.md b/13/README.md index f639111..aad318c 100644 --- a/13/README.md +++ b/13/README.md @@ -32,7 +32,7 @@ y *= amplitude*0.06; * Experiment by changing the frequency and amplitude for the additional waves. * Is it possible to make two waves cancel each other out? What will that look like? -* Is it possible to add waves in such a way that they will amplify each other? +* Is it possible to add waves in such a way that they will amplify each other? In music, each note is associated with a specific frequency. The frequencies for these notes follow a pattern which we call a scale, where a doubling or halving of the frequency corresponds to a jump of one octave. @@ -70,7 +70,7 @@ The following code is an example of how fBm could be implemented in two dimensio * Modify the lacunarity of the fBm on line 47 * Explore by changing the gain on line 48 -This technique is commonly used to construct procedural landscapes. The self-similarity of the fBm is perfect for mountains, because the erosion processes that create mountains work in a manner that yields this kind of self-similarity across a large range of scales. If you are interested in this, use you should definitly read [this great article by Inigo Quiles about advance noise](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm). +This technique is commonly used to construct procedural landscapes. The self-similarity of the fBm is perfect for mountains, because the erosion processes that create mountains work in a manner that yields this kind of self-similarity across a large range of scales. If you are interested in this, use you should definitly read [this great article by Inigo Quiles about advance noise](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm). ![Blackout - Dan Holdsworth (2010)](holdsworth.jpg) @@ -84,7 +84,7 @@ for (int i = 0; i < OCTAVES; i++) { } ``` - + Another member of this family of algorithms is the **ridge**, where the sharp valleys are turned upside down to create sharp ridges instead: @@ -94,13 +94,13 @@ Another member of this family of algorithms is the **ridge**, where the sharp va n = n * n; // sharpen creases ``` - + Another variant which can create useful variations is to multiply the noise components together instead of adding them. It's also interesting to scale subsequent noise functions with something that depends on the previous terms in the loop. When we do things like that, we are moving away from the strict definition of a fractal and into the relatively unknown field of "multifractals". Multifractals are not as strictly defined mathematically, but that doesn't make them less useful for graphics. In fact, multifractal simulations are very common in modern commercial software for terrain generation. For further reading, you could read chapter 16 of the book "Texturing and Modeling: a Procedural Approach" (3rd edition), by Kenton Musgrave. Sadly, that book is out of print since a few years back, but you can still find it in libraries and on the second hand market. (There's a PDF version of the 1st edition available for purchase online, but don't buy that - it's a waste of money. It's from 1994, and it doesn't contain any of the terrain modeling stuff from the 3rd edition.) ### Domain Warping -[Inigo Quiles wrote this other fascinating article](http://www.iquilezles.org/www/articles/warp/warp.htm) about how it's possible to use fBm to warp a space of a fBm. Mind blowing, Right? It's like the dream inside the dream of Inception. +[Inigo Quiles wrote this other fascinating article](http://www.iquilezles.org/www/articles/warp/warp.htm) about how it's possible to use fBm to warp a space of a fBm. Mind blowing, Right? It's like the dream inside the dream of Inception. ![ f(p) = fbm( p + fbm( p + fbm( p ) ) ) - Inigo Quiles (2002)](quiles.jpg) diff --git a/13/clouds.frag b/13/clouds.frag index 68a6701..ee1cdde 100644 --- a/13/clouds.frag +++ b/13/clouds.frag @@ -9,9 +9,9 @@ uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; -float random (in vec2 _st) { +float random (in vec2 _st) { return fract(sin(dot(_st.xy, - vec2(12.9898,78.233)))* + vec2(12.9898,78.233)))* 43758.5453123); } @@ -29,8 +29,8 @@ float noise (in vec2 _st) { vec2 u = f * f * (3.0 - 2.0 * f); - return mix(a, b, u.x) + - (c - a)* u.y * (1.0 - u.x) + + return mix(a, b, u.x) + + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } @@ -41,7 +41,7 @@ float fbm ( in vec2 _st) { float a = 0.5; vec2 shift = vec2(100.0); // Rotate to reduce axial bias - mat2 rot = mat2(cos(0.5), sin(0.5), + mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.50)); for (int i = 0; i < NUM_OCTAVES; ++i) { v += a * noise(_st); @@ -79,4 +79,4 @@ void main() { clamp(length(r.x),0.0,1.0)); gl_FragColor = vec4((f*f*f+.6*f*f+.5*f)*color,1.); -} \ No newline at end of file +} diff --git a/13/index.php b/13/index.php index 31d9d3e..79d6056 100644 --- a/13/index.php +++ b/13/index.php @@ -1,4 +1,4 @@ - Home '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/13/noise.frag b/13/noise.frag index f73dafe..1538b4d 100644 --- a/13/noise.frag +++ b/13/noise.frag @@ -15,9 +15,9 @@ float random (in float x) { return fract(sin(x)*1e4); } -float random (in vec2 _st) { +float random (in vec2 _st) { // return fract(sin(dot(_st.xy ,vec2(12.9898,78.233))) * 43758.5453123); - return fract( 1e4 * sin(17.0 * _st.x + _st.y * 0.1) * (0.1 + abs(sin(_st.y * 13.0 + _st.x)))); + return fract( 1e4 * sin(17.0 * _st.x + _st.y * 0.1) * (0.1 + abs(sin(_st.y * 13.0 + _st.x)))); } float noise (in float x) { @@ -53,8 +53,8 @@ float noise (in vec3 _p) { vec3 i = floor(_p); vec3 f = fract(_p); - - // For performance, compute the base input to a 1D random from the integer part of the argument and the + + // For performance, compute the base input to a 1D random from the integer part of the argument and the // incremental change to the 1D based on the 3D -> 1D wrapping float n = dot(i, step); @@ -114,4 +114,4 @@ void main() { color = vec3( fbm(vec3(st*10.,u_time*0.1)) ); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/13/ridge.frag b/13/ridge.frag index 4734277..1ef7980 100644 --- a/13/ridge.frag +++ b/13/ridge.frag @@ -19,21 +19,21 @@ vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); } // Author : Ian McEwan, Ashima Arts // Maintainer : ijm // Lastmod : 20110822 (ijm) -// License : +// License : // Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// float snoise(vec2 v) { // Precompute values for skewed triangular grid const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, + 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, + -0.577350269189626, // -1.0 + 2.0 * C.x - 0.024390243902439); + 0.024390243902439); // 1.0 / 41.0 // First corner (x0) @@ -54,17 +54,17 @@ float snoise(vec2 v) { + i.x + vec3(0.0, i1.x, 1.0 )); vec3 m = max(0.5 - vec3( - dot(x0,x0), - dot(x1,x1), + dot(x0,x0), + dot(x1,x1), dot(x2,x2) ), 0.0); m = m*m ; m = m*m ; - // Gradients: + // Gradients: // 41 pts uniformly over a line, mapped onto a diamond - // The ring size 17*17 = 289 is close to a multiple + // The ring size 17*17 = 289 is close to a multiple // of 41 (41*7 = 287) vec3 x = 2.0 * fract(p * C.www) - 1.0; @@ -98,7 +98,7 @@ float ridgedMF(vec2 p) { float lacunarity = 2.0; float gain = 0.5; float offset = 0.9; - + float sum = 0.0; float freq = 1.0, amp = 0.5; float prev = 1.0; @@ -121,4 +121,4 @@ void main() { color += ridgedMF(st*3.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/13/turbulence.frag b/13/turbulence.frag index 2f52167..7478a56 100644 --- a/13/turbulence.frag +++ b/13/turbulence.frag @@ -19,21 +19,21 @@ vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); } // Author : Ian McEwan, Ashima Arts // Maintainer : ijm // Lastmod : 20110822 (ijm) -// License : +// License : // Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // https://github.com/ashima/webgl-noise -// +// float snoise(vec2 v) { // Precompute values for skewed triangular grid const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, + 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, + -0.577350269189626, // -1.0 + 2.0 * C.x - 0.024390243902439); + 0.024390243902439); // 1.0 / 41.0 // First corner (x0) @@ -54,17 +54,17 @@ float snoise(vec2 v) { + i.x + vec3(0.0, i1.x, 1.0 )); vec3 m = max(0.5 - vec3( - dot(x0,x0), - dot(x1,x1), + dot(x0,x0), + dot(x1,x1), dot(x2,x2) ), 0.0); m = m*m ; m = m*m ; - // Gradients: + // Gradients: // 41 pts uniformly over a line, mapped onto a diamond - // The ring size 17*17 = 289 is close to a multiple + // The ring size 17*17 = 289 is close to a multiple // of 41 (41*7 = 287) vec3 x = 2.0 * fract(p * C.www) - 1.0; @@ -107,4 +107,4 @@ void main() { color += turbulence(st*3.0); gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +} diff --git a/14/README.md b/14/README.md index 591d31e..be1f73f 100644 --- a/14/README.md +++ b/14/README.md @@ -24,4 +24,4 @@ https://www.shadertoy.com/view/XdBSWw https://www.shadertoy.com/view/llfGD2 -https://www.shadertoy.com/view/Mlf3RX \ No newline at end of file +https://www.shadertoy.com/view/Mlf3RX diff --git a/14/fractal-tile.frag b/14/fractal-tile.frag index 2d183b2..ec16081 100644 --- a/14/fractal-tile.frag +++ b/14/fractal-tile.frag @@ -54,7 +54,7 @@ void main() { vec3 color = vec3(0.0); st = tileFractal(st,3,2); - + float pct = 0.; pct = circle(st,.999); // pct = box(st,vec2(.95)); @@ -64,4 +64,4 @@ void main() { color.rgb += vec3(1.)*pct; gl_FragColor = vec4(color,1.); -} \ No newline at end of file +} diff --git a/14/index.php b/14/index.php index 09345b5..d17c39c 100644 --- a/14/index.php +++ b/14/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/15/NOTES.md b/15/NOTES.md index 9c3fe4e..f96b683 100644 --- a/15/NOTES.md +++ b/15/NOTES.md @@ -2,4 +2,3 @@ No tile images https://www.shadertoy.com/view/4tsGzf https://www.shadertoy.com/view/lt2GDd - diff --git a/15/README.md b/15/README.md index cd21648..3f0b0be 100644 --- a/15/README.md +++ b/15/README.md @@ -6,7 +6,7 @@ Graphic cards (GPUs) have special memory types for images. Usually on CPUs images are stores as arrays of bites but on GPUs store images as ```sampler2D``` which is more like a table (or matrix) of floating point vectors. More interestingly is that the values of this *table* of vectors are continously. That means that value between pixels are interpolated in a low level. -In order to use this feature we first need to *upload* the image from the CPU to the GPU, to then pass the ```id``` of the texture to the right [```uniform```](../05). All that happens outside the shader. +In order to use this feature we first need to *upload* the image from the CPU to the GPU, to then pass the ```id``` of the texture to the right [```uniform```](../05). All that happens outside the shader. Once the texture is loaded and linked to a valid ```uniform sampler2D``` you can ask for specific color value at specific coordinates (formated on a [```vec2```](index.html#vec2.md) variable) usin the [```texture2D()```](index.html#texture2D.md) function which will return a color formated on a [```vec4```](index.html#vec4.md) variable. @@ -18,7 +18,7 @@ Check the following code where we load Hokusai's Wave (1830) as ```uniform sampl
-If you pay attention you will note that the coordinates for the texture are normalized! What a surprise right? Textures coordenates are consisten with the rest of the things we had saw and their coordenates are between 0.0 and 1.0 whitch match perfectly with the normalized space coordinates we have been using. +If you pay attention you will note that the coordinates for the texture are normalized! What a surprise right? Textures coordenates are consisten with the rest of the things we had saw and their coordenates are between 0.0 and 1.0 whitch match perfectly with the normalized space coordinates we have been using. Now that you have seen how we load correctly a texture is time to experiment to discover what we can do with it, by trying: @@ -26,9 +26,9 @@ Now that you have seen how we load correctly a texture is time to experiment to * Rotating the previus texture 90 degrees. * Hooking the mouse position to the coordenates to move it. -Why you should be excited about textures? Well first of all forget about the sad 255 values for channel, once your image is trasformed into a ```uniform sampler2D``` you have all the values between 0.0 and 1.0 (depending on what you set the ```precision``` to ). That's why shaders can make really beatiful post-processing effects. +Why you should be excited about textures? Well first of all forget about the sad 255 values for channel, once your image is trasformed into a ```uniform sampler2D``` you have all the values between 0.0 and 1.0 (depending on what you set the ```precision``` to ). That's why shaders can make really beatiful post-processing effects. -Second, the [```vec2()```](index.html#vec2.md) means you can get values even between pixels. As we said before the textures are a continum. This means that if you set up your texture correctly you can ask for values all arround the surface of your image and the values will smoothly vary from pixel to pixel with no jumps! +Second, the [```vec2()```](index.html#vec2.md) means you can get values even between pixels. As we said before the textures are a continum. This means that if you set up your texture correctly you can ask for values all arround the surface of your image and the values will smoothly vary from pixel to pixel with no jumps! Finnally, you can setup your image to repeat in the edges, so if you give values over or lower of the normalized 0.0 and 1.0, the values will wrap around starting over. @@ -54,7 +54,7 @@ Uncomment line 21 of the following code to see this in action. ![](03.jpg) -You may be thinking that this is unnesesary complicated... and you are probably right. Also this way of working with images leave a enought room to different hacks and creative tricks. Try to imagine that you are an upholster and by streaching and folding a fabric over a structure you can create better and new patterns and techniques. +You may be thinking that this is unnesesary complicated... and you are probably right. Also this way of working with images leave a enought room to different hacks and creative tricks. Try to imagine that you are an upholster and by streaching and folding a fabric over a structure you can create better and new patterns and techniques. ![Eadweard's Muybridge study of motion](muybridge.jpg) @@ -75,4 +75,4 @@ Now is your turn: * What other optical toys can you re-create using textures? -In the next chapters we will learn how to do some image processing using shaders. You will note that finnaly the complexity of shader makes sense, because was in a big sense designed to do this type of process. We will start doing some image operations! \ No newline at end of file +In the next chapters we will learn how to do some image processing using shaders. You will note that finnaly the complexity of shader makes sense, because was in a big sense designed to do this type of process. We will start doing some image operations! diff --git a/15/index.php b/15/index.php index 5a557ab..3ee01f6 100644 --- a/15/index.php +++ b/15/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/15/texture-kaleidoscope.frag b/15/texture-kaleidoscope.frag index 5186445..50680a7 100644 --- a/15/texture-kaleidoscope.frag +++ b/15/texture-kaleidoscope.frag @@ -41,4 +41,4 @@ void main () { color = texture2D(u_tex0,st); gl_FragColor = color; -} \ No newline at end of file +} diff --git a/15/texture-noise.frag b/15/texture-noise.frag index da14a38..81870bd 100644 --- a/15/texture-noise.frag +++ b/15/texture-noise.frag @@ -16,9 +16,9 @@ uniform float u_time; // Based on Morgan // https://www.shadertoy.com/view/4dS3Wd -float random (in vec2 st) { +float random (in vec2 st) { return fract(sin(dot(st.xy, - vec2(12.9898,78.233)))* + vec2(12.9898,78.233)))* 43758.5453123); } @@ -34,8 +34,8 @@ float noise (in vec2 st) { vec2 u = f * f * (3.0 - 2.0 * f); - return mix(a, b, u.x) + - (c - a)* u.y * (1.0 - u.x) + + return mix(a, b, u.x) + + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } @@ -44,7 +44,7 @@ void main () { float scale = 2.0; float offset = 0.5; - + float angle = noise( st + u_time * 0.1 )*PI; float radius = offset; @@ -54,4 +54,4 @@ void main () { vec4 color = texture2D(u_tex0,st); gl_FragColor = color; -} \ No newline at end of file +} diff --git a/15/texture-resolution.frag b/15/texture-resolution.frag index 3a59b95..9a151b5 100644 --- a/15/texture-resolution.frag +++ b/15/texture-resolution.frag @@ -23,4 +23,4 @@ void main () { color = texture2D(u_tex0,st); gl_FragColor = color; -} \ No newline at end of file +} diff --git a/15/texture-sprite.frag b/15/texture-sprite.frag index 24e7fed..8d884cb 100644 --- a/15/texture-sprite.frag +++ b/15/texture-sprite.frag @@ -22,20 +22,20 @@ void main () { // Resolution of one frame vec2 fRes = u_tex0Resolution/vec2(float(col),float(row)); - // Normalize value of the frame resolution + // Normalize value of the frame resolution vec2 nRes = u_tex0Resolution/fRes; // Scale the coordenates to a single frame st = st/nRes; // Calculate the offset in cols and rows - float timeX = u_time*15.; + float timeX = u_time*15.; float timeY = floor(timeX/float(col)); - vec2 offset = vec2( floor(timeX)/nRes.x, + vec2 offset = vec2( floor(timeX)/nRes.x, 1.0-(floor(timeY)/nRes.y) ); st = fract(st+offset); color = texture2D(u_tex0,st); gl_FragColor = color; -} \ No newline at end of file +} diff --git a/15/texture-stereo.frag b/15/texture-stereo.frag index ddc0820..9bf9cda 100644 --- a/15/texture-stereo.frag +++ b/15/texture-stereo.frag @@ -28,4 +28,4 @@ void main () { color = mix(A, B, abs(sin(t))); gl_FragColor = color; -} \ No newline at end of file +} diff --git a/15/texture.frag b/15/texture.frag index 29c4c3c..81a8dd9 100644 --- a/15/texture.frag +++ b/15/texture.frag @@ -19,4 +19,4 @@ void main () { color = texture2D(u_tex0,st); gl_FragColor = color; -} \ No newline at end of file +} diff --git a/16/README.md b/16/README.md index d225217..622ed23 100644 --- a/16/README.md +++ b/16/README.md @@ -15,4 +15,4 @@ ![](03.jpg) -
\ No newline at end of file +
diff --git a/16/add.frag b/16/add.frag index 261f7fc..5fbd9f9 100644 --- a/16/add.frag +++ b/16/add.frag @@ -14,7 +14,7 @@ uniform vec2 u_resolution; void main (void) { vec2 st = gl_FragCoord.xy/u_resolution.xy; - + vec3 colorA = texture2D(u_tex0,st).rgb; vec3 colorB = texture2D(u_tex1,st).rgb; diff --git a/16/diff.frag b/16/diff.frag index c91c9b6..5d3d700 100644 --- a/16/diff.frag +++ b/16/diff.frag @@ -19,6 +19,6 @@ void main (void) { vec3 colorB = texture2D(u_tex1,st).rgb; vec3 color = abs(colorA-colorB); - + gl_FragColor = vec4(color,1.0); } diff --git a/16/div.frag b/16/div.frag index 79e9e00..52fa7d7 100644 --- a/16/div.frag +++ b/16/div.frag @@ -14,7 +14,7 @@ uniform vec2 u_resolution; void main (void) { vec2 st = gl_FragCoord.xy/u_resolution.xy; - + vec3 colorA = texture2D(u_tex0,st).rgb; vec3 colorB = texture2D(u_tex1,st).rgb; diff --git a/16/index.php b/16/index.php index 5a557ab..3ee01f6 100644 --- a/16/index.php +++ b/16/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/16/inv.frag b/16/inv.frag index 1fc3200..fcc9c8e 100644 --- a/16/inv.frag +++ b/16/inv.frag @@ -14,7 +14,7 @@ uniform vec2 u_resolution; void main (void) { vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = texture2D(u_tex0,st).rgb; - + // color = 1.0-color; gl_FragColor = vec4(color,1.0); diff --git a/16/sub.frag b/16/sub.frag index 9f2f4cf..dce07b4 100644 --- a/16/sub.frag +++ b/16/sub.frag @@ -19,6 +19,6 @@ void main (void) { vec3 colorB = texture2D(u_tex1,st).rgb; vec3 color = colorA*colorB; - + gl_FragColor = vec4(color,1.0); } diff --git a/17/index.php b/17/index.php index 5a557ab..3ee01f6 100644 --- a/17/index.php +++ b/17/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/18/grain.frag b/18/grain.frag index 522b407..1098c04 100644 --- a/18/grain.frag +++ b/18/grain.frag @@ -78,8 +78,8 @@ float luma(vec4 color) { // https://github.com/mattdesl/glsl-blend-soft-light/blob/master/index.glsl vec3 blendSoftLight(vec3 base, vec3 blend) { return mix( - sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend), - 2.0 * base * blend + base * base * (1.0 - 2.0 * blend), + sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend), + 2.0 * base * blend + base * base * (1.0 - 2.0 * blend), step(base, vec3(0.5)) ); } @@ -88,7 +88,7 @@ void main (void) { vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = texture2D(u_tex0,st).rgb; vec3 grain = vec3( grain(st,u_resolution/7.) ); - + color = blendSoftLight(color,grain); float luminance = luma(color); diff --git a/18/hatch.frag b/18/hatch.frag index 4f9c0a5..b7165fb 100644 --- a/18/hatch.frag +++ b/18/hatch.frag @@ -1,7 +1,7 @@ #ifdef GL_ES precision highp float; #endif - + uniform sampler2D u_tex0; uniform vec2 u_tex0Resolution; @@ -21,4 +21,4 @@ void main(){ vec3 color = vec3(1.0); color -= hatch(u_tex0,st,b).a; gl_FragColor = vec4(color,1.); -} \ No newline at end of file +} diff --git a/18/index.php b/18/index.php index 5a557ab..3ee01f6 100644 --- a/18/index.php +++ b/18/index.php @@ -1,4 +1,4 @@ -Next > > '; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/18/lut-plain.frag b/18/lut-plain.frag index 73be2ef..362325a 100644 --- a/18/lut-plain.frag +++ b/18/lut-plain.frag @@ -1,7 +1,7 @@ #ifdef GL_ES precision highp float; #endif - + uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; @@ -11,7 +11,7 @@ const float size = 8.0; void main(){ vec2 st = gl_FragCoord.st/u_resolution.xy; vec3 color = vec3(.0); - + float red = fract(st.x*size); float green = fract((1.-st.y)*size); float blue = floor((1.-st.y)*size)/size; @@ -19,4 +19,4 @@ void main(){ color = vec3(red,green,blue); gl_FragColor = vec4( color , 1.0); -} \ No newline at end of file +} diff --git a/18/lut.frag b/18/lut.frag index 923d209..b3a135f 100644 --- a/18/lut.frag +++ b/18/lut.frag @@ -1,7 +1,7 @@ #ifdef GL_ES precision highp float; #endif - + uniform sampler2D u_tex0; uniform sampler2D u_tex1; @@ -15,7 +15,7 @@ uniform float u_time; #define LUT_NO_CLAMP #define LUT_FLIP_Y -vec4 lookup(in vec4 textureColor, in sampler2D lookupTable) { +vec4 lookup(in vec4 textureColor, in sampler2D lookupTable) { #ifndef LUT_NO_CLAMP textureColor = clamp(textureColor, 0.0, 1.0); #endif @@ -57,6 +57,6 @@ void main(){ vec2 st = gl_FragCoord.st/u_resolution.xy; vec4 srcColor = texture2D(u_tex0, st); vec3 dstcolor = lookup(srcColor,u_tex1).rgb; - + gl_FragColor = vec4( dstcolor , 1.0); -} \ No newline at end of file +} diff --git a/makefile b/Makefile similarity index 92% rename from makefile rename to Makefile index e04bae6..36354b6 100644 --- a/makefile +++ b/Makefile @@ -1,6 +1,6 @@ default: clean all -clean: +clean: rm -rf */tmp.md rm -rf */tmp*.png rm -rf book.* diff --git a/README-de.md b/README-de.md index a5bef8c..e098ccb 100644 --- a/README-de.md +++ b/README-de.md @@ -1,107 +1,106 @@ - - -# The Book of Shaders -*von [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) und [Jen Lowe](http://jenlowe.net/)* - -Dies ist eine behutsame Schritt-für-Schritt-Einführung in die komplexe und vielfach abstrakte Welt der Fragment Shader. - -
- -
- -## Inhalt - -* [Über dieses Buch](00/?lan=de) - -* Jetzt geht’s los - * [Was ist ein Shader?](01/?lan=de) - * [“Hallo Welt!”](02/?lan=de) - * [Uniforms](03/?lan=de) - * [Ausführung Deiner Shader](04/?lan=de) - -* Algorithmisches Zeichnen - * [Formgebende Funktionen](05/?lan=de) - * [Farben](06/?lan=de) - * [Formen](07/?lan=de) - * [Matrizen](08/?lan=de) - * [Muster](09/?lan=de) - -* Generative Designs - * [Zufall](10/?lan=de) - * [Rauschen](11/?lan=de) - * [Zelluläres Rauschen](12/?lan=de) - * [Gebrochene Brownsche Bewegung](13/?lan=de) - * Fraktale - -* Bildverarbeitung - * Texturen - * Bildbearbeitungsfunktionen - * Kernel Verwindungen - * Filter - * Weitere Effekte - -* Simulationen - * Pingpong - * Conway - * Wellen - * Wasserfarben - * Reaktionsausbreitung - -* 3D Grafiken - * Licht - * Normal Mapping - * Bump-Mapping - * Ray Marching - * Environmental-Maps (sphärisch und kubisch) - * Reflektionen und Ablenkungen - -* [Anhang:](appendix/?lan=de) Weitere Wege zur Nutzung dieses Buches - * [Wie kann ich dieses Buch offline lesen?](appendix/00/?lan=de) - * [Wie lasse ich die Beispielprogramme auf einem Raspberry Pi ablaufen?](appendix/01/?lan=de) - * [Wie drucke ich dieses Buch aus?](appendix/02/?lan=de) - * [Wie kann ich zu diesem Buch beitragen?](appendix/03/?lan=de) - * [Eine Einführung für alle, die von JavaScript kommen](appendix/04/?lan=de) von [Nicolas Barradeau](http://www.barradeau.com/) (Englisch) - -* [Beispielgalerien](examples/) - -* [Glossar](glossary/) (Englisch) - -## Über die Autoren - -[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentinien) ist ein Künstler und Entwickler, der in New York lebt. Er erforscht die Räume zwischen Organischem und Synthetischem, Analogem und Digitalem, Individuen und Kollektiven. In seinen Arbeiten nutzt er Programmcode als Ausdrucksform, um das Zusammenwirken von Menschen zu verbessern. - -Patricio hat Psychologie studiert, außerdem kunstorientiertes Handeln, die sogenannte „Expressive Arts Therapy“. Er hat einen MFA-Abschluss in „Design & Technology“ von der „Parsons The New School“, wo er auch unterrichtet. Zur Zeit arbeitet Patricio als Grafikingenieur bei der Firma Mapzen und entwickelt dort Open Source Werkzeuge für die Computer-Kartographie. -
Webseite - Twitter - GitHub - Vimeo - Flickr
- -[Jen Lowe](http://jenlowe.net/) ist eine unabhängige Datenwissenschaftlerin und Datenkommunikatorin bei der Firma Datatelling, wo sie Menschen, Zahlen und Sprache zusammenführt. Sie unterrichtet im Rahmen des „SVA Design for Social Innovation“-Programms, hat die Schule für „Poetic Computation“ mitbegründet, Mathematik für Künstler an der New Yorker ITP-Universität unterrichtet, Forschungen am „Spatial Information Design Lab“ der Columbia Universität durchgeführt und Beiträge für das „White House Office of Science and Technology“ geliefert, das den US-Präsidenten in Fragen des technischen Fortschritts berät. Als Sprecherin ist Jen auf Konferenzen wie der SXSW und der Eyeo aufgetreten. Von ihren Arbeiten hat unter anderem die New York Times, sowie das Magazin FastCompany berichtet. Ihre Forschungsarbeiten, Publikationen und Vorträge kreisen um die Versprechungen und Folgen von Daten und Technologien für die gesellschaftliche Entwicklung. Sie hat einen „Bachelor of Science“-Abschluss in angewandter Mathematik und einen Master-Abschluss in Informatik. Obwohl man angesichts dieser Biographie vielleicht etwas anderes vermuten könnte, schlägt sich Jen immer auf die Seite der Liebe. -
Webseite - Twitter - GitHub
- -## Danksagungen - -Dank an [Scott Murray](http://alignedleft.com/) für die Inspirationen und Ratschläge. - -Dank an [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere) und [Karim Naaji](http://karim.naaji.fr/) für ihre Unterstützung, Anregungen und Programmcode. - -Dank an [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) und [Sawako](https://twitter.com/sawakohome) für die [japanische Übersetzung des Textes (日本語訳)](?lan=jp) - -Dank an [Tong Li](https://www.facebook.com/tong.lee.9484) und [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) für die [chinesische Übersetzung des Textes (中文版)](?lan=ch) - -Dank an [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) für die [koreanische Übersetzung des Textes (한국어)](?lan=kr) - -Dank an [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) für die -[spanische Übersetzung des Textes (español)](?lan=es) - -Dank an [Nicolas Barradeau](https://twitter.com/nicoptere) und [Karim Naaji](http://karim.naaji.fr/) für die [französische Übersetzung des Textes (français)](?lan=fr) - -Dank an [Andrea Rovescalli](https://www.earove.info) für die [italienische Übersetzung des Textes (italiano)](?lan=it) - -Dank an [Michael Tischer](http://www.mitinet.de) für die [deutsche Übersetzung des Textes](?lan=de) - -Und natürlich Danke an alle, die an dieses Projekt geglaubt, dafür gespendet oder durch Hinweise und Korrekturen [daran mitgewirkt haben](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors). - -## Hol Dir die neuen Kapitel - -Melde Dich für den Newsletter an oder [folge uns auf Twitter](https://twitter.com/bookofshaders) - -

- + + +# The Book of Shaders +*von [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) und [Jen Lowe](http://jenlowe.net/)* + +Dies ist eine behutsame Schritt-für-Schritt-Einführung in die komplexe und vielfach abstrakte Welt der Fragment Shader. + +
+ +
+ +## Inhalt + +* [Über dieses Buch](00/?lan=de) + +* Jetzt geht’s los + * [Was ist ein Shader?](01/?lan=de) + * [“Hallo Welt!”](02/?lan=de) + * [Uniforms](03/?lan=de) + * [Ausführung Deiner Shader](04/?lan=de) + +* Algorithmisches Zeichnen + * [Formgebende Funktionen](05/?lan=de) + * [Farben](06/?lan=de) + * [Formen](07/?lan=de) + * [Matrizen](08/?lan=de) + * [Muster](09/?lan=de) + +* Generative Designs + * [Zufall](10/?lan=de) + * [Rauschen](11/?lan=de) + * [Zelluläres Rauschen](12/?lan=de) + * [Gebrochene Brownsche Bewegung](13/?lan=de) + * Fraktale + +* Bildverarbeitung + * Texturen + * Bildbearbeitungsfunktionen + * Kernel Verwindungen + * Filter + * Weitere Effekte + +* Simulationen + * Pingpong + * Conway + * Wellen + * Wasserfarben + * Reaktionsausbreitung + +* 3D Grafiken + * Licht + * Normal Mapping + * Bump-Mapping + * Ray Marching + * Environmental-Maps (sphärisch und kubisch) + * Reflektionen und Ablenkungen + +* [Anhang:](appendix/?lan=de) Weitere Wege zur Nutzung dieses Buches + * [Wie kann ich dieses Buch offline lesen?](appendix/00/?lan=de) + * [Wie lasse ich die Beispielprogramme auf einem Raspberry Pi ablaufen?](appendix/01/?lan=de) + * [Wie drucke ich dieses Buch aus?](appendix/02/?lan=de) + * [Wie kann ich zu diesem Buch beitragen?](appendix/03/?lan=de) + * [Eine Einführung für alle, die von JavaScript kommen](appendix/04/?lan=de) von [Nicolas Barradeau](http://www.barradeau.com/) (Englisch) + +* [Beispielgalerien](examples/) + +* [Glossar](glossary/) (Englisch) + +## Über die Autoren + +[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentinien) ist ein Künstler und Entwickler, der in New York lebt. Er erforscht die Räume zwischen Organischem und Synthetischem, Analogem und Digitalem, Individuen und Kollektiven. In seinen Arbeiten nutzt er Programmcode als Ausdrucksform, um das Zusammenwirken von Menschen zu verbessern. + +Patricio hat Psychologie studiert, außerdem kunstorientiertes Handeln, die sogenannte „Expressive Arts Therapy“. Er hat einen MFA-Abschluss in „Design & Technology“ von der „Parsons The New School“, wo er auch unterrichtet. Zur Zeit arbeitet Patricio als Grafikingenieur bei der Firma Mapzen und entwickelt dort Open Source Werkzeuge für die Computer-Kartographie. +
Webseite - Twitter - GitHub - Vimeo - Flickr
+ +[Jen Lowe](http://jenlowe.net/) ist eine unabhängige Datenwissenschaftlerin und Datenkommunikatorin bei der Firma Datatelling, wo sie Menschen, Zahlen und Sprache zusammenführt. Sie unterrichtet im Rahmen des „SVA Design for Social Innovation“-Programms, hat die Schule für „Poetic Computation“ mitbegründet, Mathematik für Künstler an der New Yorker ITP-Universität unterrichtet, Forschungen am „Spatial Information Design Lab“ der Columbia Universität durchgeführt und Beiträge für das „White House Office of Science and Technology“ geliefert, das den US-Präsidenten in Fragen des technischen Fortschritts berät. Als Sprecherin ist Jen auf Konferenzen wie der SXSW und der Eyeo aufgetreten. Von ihren Arbeiten hat unter anderem die New York Times, sowie das Magazin FastCompany berichtet. Ihre Forschungsarbeiten, Publikationen und Vorträge kreisen um die Versprechungen und Folgen von Daten und Technologien für die gesellschaftliche Entwicklung. Sie hat einen „Bachelor of Science“-Abschluss in angewandter Mathematik und einen Master-Abschluss in Informatik. Obwohl man angesichts dieser Biographie vielleicht etwas anderes vermuten könnte, schlägt sich Jen immer auf die Seite der Liebe. +
Webseite - Twitter - GitHub
+ +## Danksagungen + +Dank an [Scott Murray](http://alignedleft.com/) für die Inspirationen und Ratschläge. + +Dank an [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere) und [Karim Naaji](http://karim.naaji.fr/) für ihre Unterstützung, Anregungen und Programmcode. + +Dank an [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) und [Sawako](https://twitter.com/sawakohome) für die [japanische Übersetzung des Textes (日本語訳)](?lan=jp) + +Dank an [Tong Li](https://www.facebook.com/tong.lee.9484) und [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) für die [chinesische Übersetzung des Textes (中文版)](?lan=ch) + +Dank an [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) für die [koreanische Übersetzung des Textes (한국어)](?lan=kr) + +Dank an [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) für die +[spanische Übersetzung des Textes (español)](?lan=es) + +Dank an [Nicolas Barradeau](https://twitter.com/nicoptere) und [Karim Naaji](http://karim.naaji.fr/) für die [französische Übersetzung des Textes (français)](?lan=fr) + +Dank an [Andrea Rovescalli](https://www.earove.info) für die [italienische Übersetzung des Textes (italiano)](?lan=it) + +Dank an [Michael Tischer](http://www.mitinet.de) für die [deutsche Übersetzung des Textes](?lan=de) + +Und natürlich Danke an alle, die an dieses Projekt geglaubt, dafür gespendet oder durch Hinweise und Korrekturen [daran mitgewirkt haben](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors). + +## Hol Dir die neuen Kapitel + +Melde Dich für den Newsletter an oder [folge uns auf Twitter](https://twitter.com/bookofshaders) + +

diff --git a/README-it.md b/README-it.md index c55965f..b9007a1 100644 --- a/README-it.md +++ b/README-it.md @@ -70,7 +70,7 @@ Questa è una guida passo passo attraverso l'universo astratto e complesso dei F [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) è un artista e sviluppatore con sede a New York. Esplora lo spazio interstiziale fra organico e sintetico, analogico e digitale, individuale e collettivo. Nel suo lavoro usa il codice come un linguaggio espressivo con l'intenzione di creare un migliore vivere insieme. -Patricio studiò e praticò la psicoterapia e l'arteterapia. Ha conseguito un MFA in Design e Tecnologia alla Parsons The New School dove ora insegna. Attualmente lavora come Ingegnere Grafico alla Mapzen realizzando strumenti cartografici openSource. +Patricio studiò e praticò la psicoterapia e l'arteterapia. Ha conseguito un MFA in Design e Tecnologia alla Parsons The New School dove ora insegna. Attualmente lavora come Ingegnere Grafico alla Mapzen realizzando strumenti cartografici openSource.
WebSite - Twitter - GitHub - Vimeo - Flickr
diff --git a/README-kr.md b/README-kr.md index 55806d7..a24cca8 100644 --- a/README-kr.md +++ b/README-kr.md @@ -3,7 +3,7 @@ # The Book of Shaders *by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/)* -이것은 황량하게 넓고 복잡한 Fragment Shader의 세계를 한단계씩 살펴보는 지침서입니다. +이것은 황량하게 넓고 복잡한 Fragment Shader의 세계를 한단계씩 살펴보는 지침서입니다. ## 번역에 대하여 diff --git a/appendix/00/README-de.md b/appendix/00/README-de.md index 31832b8..2e75a14 100644 --- a/appendix/00/README-de.md +++ b/appendix/00/README-de.md @@ -9,7 +9,7 @@ Unter **MacOSX** benötigst Du dafür [homebrew](http://brew.sh/). Sobald das Pa ```bash brew update brew upgrade -brew install git +brew install git ``` Auf einem **RaspberryPi** gibst Du folgendes ein: diff --git a/appendix/01/README-de.md b/appendix/01/README-de.md index 93824be..332fa5d 100644 --- a/appendix/01/README-de.md +++ b/appendix/01/README-de.md @@ -1,20 +1,20 @@ -## 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 glslviewer -cd ~ -git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git -cd thebookofshaders -``` +## 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 glslviewer +cd ~ +git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git +cd thebookofshaders +``` diff --git a/appendix/01/README-it.md b/appendix/01/README-it.md index 65eca12..ced8d55 100644 --- a/appendix/01/README-it.md +++ b/appendix/01/README-it.md @@ -6,7 +6,7 @@ Grazie al [progetto Raspberry Pi](http://www.raspberrypi.org/) una nuova generaz Facendo una copia locale del repository di questo libro (vedi paragrafo precedente) e con [```glslViewer``` installato](https://github.com/patriciogonzalezvivo/glslViewer), gli utenti possono eseguire gli esempi con ```glslviewer```. Inoltre usando il flag ```-l``` si può visualiizare l'esempio in un angolo dello schermo mentre lo si modifica con un qualsiasi editor di testo (come ```nano```, ```pico```, ```vi```, ```vim``` or ```emacs```). Questo funziona anche quando l'utente è collegato tramite ssh/sftp. -Per installare e configurare tutto ciò sul Raspberry Pi, dopo l'installazione del sistema operativo e il login, digitate i seguenti comandi: +Per installare e configurare tutto ciò sul Raspberry Pi, dopo l'installazione del sistema operativo e il login, digitate i seguenti comandi: ```bash sudo apt-get update @@ -15,4 +15,4 @@ sudo apt-get install git-core glslviewer cd ~ git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git cd thebookofshaders -``` \ No newline at end of file +``` diff --git a/appendix/01/README.md b/appendix/01/README.md index 3a7bf20..04d41c2 100644 --- a/appendix/01/README.md +++ b/appendix/01/README.md @@ -1,6 +1,6 @@ ## How to run the examples on a Raspberry Pi? -A few years ago, assuming that everybody has a computer with a graphical processing unit was a long shot. Now, most computers have a GPU, but it's still a high bar for a requirement in a workshop or class, for example. +A few years ago, assuming that everybody has a computer with a graphical processing unit was a long shot. Now, most computers have a GPU, but it's still a high bar for a requirement in a workshop or class, for example. Thanks to the [Raspberry Pi Foundation](http://www.raspberrypi.org/) a new type of small and cheap generation of computers (around $35 each) has found its way into classrooms. More importantly for the purposes of this book, the [Raspberry Pi](http://www.raspberrypi.org/) comes with a decent Broadcom GPU that can be accessed directly from the console. I made a [flexible GLSL live coding tool call **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer) that runs all the examples in this book. This program also has the ability to update automatically when the user saves a change to their code. What does this mean? You can edit the shader and every time you save it, the shader will be re-compile and render for you. diff --git a/appendix/02/README-de.md b/appendix/02/README-de.md index d83043b..8b1ce6f 100644 --- a/appendix/02/README-de.md +++ b/appendix/02/README-de.md @@ -1,64 +1,63 @@ -## 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 glslviewer -``` - -#### 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. - +## 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 glslviewer +``` + +#### 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. diff --git a/appendix/02/README-fr.md b/appendix/02/README-fr.md index c726397..30b0a3f 100644 --- a/appendix/02/README-fr.md +++ b/appendix/02/README-fr.md @@ -13,7 +13,7 @@ brew update brew upgrade brew tap homebrew/versions brew install glfw3 -cd ~ +cd ~ git clone http://github.com/patriciogonzalezvivo/glslViewer.git cd glslViewer make @@ -35,7 +35,7 @@ Pour analyser les chapitres Markdown dans Latex, puis dans un fichier PDF, nous Sous **MacOSX**: Téléchargez et installez [basictex & MacTeX-Additions](http://www.tug.org/mactex/morepackages.html), puis installez [Pandoc](http://johnmacfarlane.net/pandoc/) et Python avec : - + ```bash brew install pandoc python2.7 ``` diff --git a/appendix/02/README-it.md b/appendix/02/README-it.md index 5772b93..c5f0cc9 100644 --- a/appendix/02/README-it.md +++ b/appendix/02/README-it.md @@ -1,7 +1,7 @@ ## Come posso stampare questo libro? Diciamo che non si vuole navigare o interagire con gli esempi e si desidera solo un buon vecchio libro di testo che si può leggere sulla spiaggia o sul vostro tragitto verso la città. In questo caso è possibile stampare questo libro. - + #### Installare glslViewer Per la stampa di questo libro è necessario in primo luogo trasformarlo. Per questo è necessario [```glslViewer```](https://github.com/patriciogonzalezvivo/glslViewer) uno strumento console per gli shader che compilerà e trasformare gli esempi in immagini. @@ -13,7 +13,7 @@ brew update brew upgrade brew tap homebrew/versions brew install glfw3 -cd ~ +cd ~ git clone http://github.com/patriciogonzalezvivo/glslViewer.git cd glslViewer make @@ -35,7 +35,7 @@ Per trasformare i capitoli Markdown in Latex e poi in un file PDF useremo Xetex Su **MacOSX**: Scarica e Installa [basictex & MacTeX-Additions](http://www.tug.org/mactex/morepackages.html) e poi installa [Pandoc](http://johnmacfarlane.net/pandoc/) facendo: - + ```bash brew install pandoc ``` diff --git a/appendix/02/README.md b/appendix/02/README.md index 175bd05..c030b16 100644 --- a/appendix/02/README.md +++ b/appendix/02/README.md @@ -1,7 +1,7 @@ ## How to print this book? Let’s say you don’t want to navigate or interact with the examples and you just want a good old fashion text book which you can read on the beach or on your commute to the city. In that case you can print this book. - + #### Installing glslViewer @@ -14,7 +14,7 @@ brew update brew upgrade brew tap homebrew/versions brew install glfw3 -cd ~ +cd ~ git clone http://github.com/patriciogonzalezvivo/glslViewer.git cd glslViewer make @@ -36,7 +36,7 @@ For parsing the Markdown chapters into Latex and then into a PDF file we will us In **MacOSX**: Download and Install [basictex & MacTeX-Additions](http://www.tug.org/mactex/morepackages.html) and then install [Pandoc](http://johnmacfarlane.net/pandoc/) and Python by: - + ```bash brew install pandoc python2.7 ``` @@ -60,4 +60,4 @@ cd thebookofshaders make ``` -If everything goes well, you will see a `book.pdf` file which you can read on your favorite device or print. +If everything goes well, you will see a `book.pdf` file which you can read on your favorite device or print. diff --git a/appendix/03/README-de.md b/appendix/03/README-de.md index 37d5954..59d6285 100644 --- a/appendix/03/README-de.md +++ b/appendix/03/README-de.md @@ -1,65 +1,63 @@ -## 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 -
-``` - -oder - -```html -
-``` - -#### 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. - - +## 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 +
+``` + +oder + +```html +
+``` + +#### 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. diff --git a/appendix/03/README-it.md b/appendix/03/README-it.md index 2aff529..3ad3c89 100644 --- a/appendix/03/README-it.md +++ b/appendix/03/README-it.md @@ -60,4 +60,4 @@ Siamo tutti esseri umani. Se vedete qualcosa, ditelo e fate un Pull Request oppu ### Condividete i vostri esempi di shaders Vedrete un sacco di link verso [l'editor on-line](http://editor.thebookofshaders.com/) e verso delle sue istanze integrate alla pagina. -Una volta che si scrive un codice che vi rende orgoglioso, fate clic su "Esporta" (o sull' icona ```⇪```) e quindi copiate l' "URL verso il codice..." ("URL to code..."). Inviatelo a [@bookofshaders](https://twitter.com/bookofshaders) o a [@kyndinfo](https://twitter.com/kyndinfo). Non vediamo l'ora di vederlo e aggiungerlo alla [sezione galleria di esempi](https://thebookofshaders.com/examples/). \ No newline at end of file +Una volta che si scrive un codice che vi rende orgoglioso, fate clic su "Esporta" (o sull' icona ```⇪```) e quindi copiate l' "URL verso il codice..." ("URL to code..."). Inviatelo a [@bookofshaders](https://twitter.com/bookofshaders) o a [@kyndinfo](https://twitter.com/kyndinfo). Non vediamo l'ora di vederlo e aggiungerlo alla [sezione galleria di esempi](https://thebookofshaders.com/examples/). diff --git a/appendix/03/README.md b/appendix/03/README.md index 2cb03a0..4bfc65d 100644 --- a/appendix/03/README.md +++ b/appendix/03/README.md @@ -5,17 +5,17 @@ Thanks for being willing to collaborate! There are plenty of ways you can: - Translating content - Improving the [```glossary/``` section](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary) - Editing content -- Sharing your shaders examples through [the on-line editor](http://editor.thebookofshaders.com/) to +- Sharing your shaders examples through [the on-line editor](http://editor.thebookofshaders.com/) to ### Translating content -This book is written in [Markdown language](https://daringfireball.net/projects/markdown/syntax) so it's very easy to edit and work on it. +This book is written in [Markdown language](https://daringfireball.net/projects/markdown/syntax) so it's very easy to edit and work on it. 1. Start by going to [github's repository at ```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Take a look at the files and folders inside it. You will note that the content is in the ```README.md``` and other files with capital letters like: ```TITLE.md```, ```SUMMARY.md```, etc. Also note that translations are hosted in files with names ending in two letters referencing the language they are for, ex.: ```README-jp.md```, ```README-es.md```, etc. 2. Fork the repository and clone it in your computer. -3. Duplicate the content of the files want to translate. Remember to add to the two letters that makes reference to the language you are translating to the files you will work on. +3. Duplicate the content of the files want to translate. Remember to add to the two letters that makes reference to the language you are translating to the files you will work on. 4. Translate the content line by line (see **Translation notes**). @@ -45,7 +45,7 @@ Start running a local PHP server inside the local repository folder: php -S localhost:8000 ``` -Then in your browser search for ```localhost:8000``` go to the chapter you are translating and add ```?lan=``` followed by the two letters you used to mark the language you are translating to. +Then in your browser search for ```localhost:8000``` go to the chapter you are translating and add ```?lan=``` followed by the two letters you used to mark the language you are translating to. For example, if you are translating the chapter ```03``` to french you had been working with the file ```03/README-fr.md``` and you can test it by going to: ```http://localhost:8000/03/?lan=fr``` @@ -61,4 +61,3 @@ We are all humans. If you see something say something and make a Pull Request or You will see a lot of links to [the on-line editor](http://editor.thebookofshaders.com/) and embedded instances of it. Once you code something that makes you proud, click the "Export" (or the ```⇪``` icon) and then copy the "URL to code...". Send it to [@bookofshaders](https://twitter.com/bookofshaders) or [@kyndinfo](https://twitter.com/kyndinfo). We are looking forward to see it and add it to [the example gallery section](https://thebookofshaders.com/examples/). - diff --git a/appendix/README-de.md b/appendix/README-de.md index f22b006..b4dff87 100644 --- a/appendix/README-de.md +++ b/appendix/README-de.md @@ -1,15 +1,15 @@ -# Appendix - -1. [Wie kann ich dieses Buch offline lesen?](00/?lan=de) - -2. [Wie kann ich die Beispielprogramme auf einem Raspberry Pi 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 ... +# Appendix + +1. [Wie kann ich dieses Buch offline lesen?](00/?lan=de) + +2. [Wie kann ich die Beispielprogramme auf einem Raspberry Pi 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 ... diff --git a/appendix/README.md b/appendix/README.md index 0db3025..0a0bed5 100644 --- a/appendix/README.md +++ b/appendix/README.md @@ -12,4 +12,4 @@ 6. [An introduction for vectors](05/) by ... -7. [An introduction to interpolation](06) by ... \ No newline at end of file +7. [An introduction to interpolation](06) by ... diff --git a/edit.php b/edit.php index 845e6fe..903c8ca 100644 --- a/edit.php +++ b/edit.php @@ -74,7 +74,7 @@ - diff --git a/glossary/README.md b/glossary/README.md index 4499de5..3e4f96f 100644 --- a/glossary/README.md +++ b/glossary/README.md @@ -160,13 +160,13 @@ [distance()](./?search=distance) [dot()](./?search=dot) -* E +* E [equal()](./?search=equal) [exp()](./?search=exp) [exp2()](./?search=exp2) -* F +* F [faceforward()](./?search=faceforward) [float](./?search=float) @@ -214,7 +214,7 @@ [log2()](./?search=log2) [lowp](./?search=lowp) -* M +* M [matrixCompMult()](./?search=matrixCompMult) [mat2](./?search=mat2) diff --git a/glossary/abs/README.md b/glossary/abs/README.md index 775bffe..90e1068 100644 --- a/glossary/abs/README.md +++ b/glossary/abs/README.md @@ -18,4 +18,4 @@ vec4 abs(vec4 x)
### See Also -[sign()](/glossary/?search=sign), [min()](/glossary/?search=min), [max()](/glossary/?search=max), [Chapter 05: Shaping Functions](../05/) \ No newline at end of file +[sign()](/glossary/?search=sign), [min()](/glossary/?search=min), [max()](/glossary/?search=max), [Chapter 05: Shaping Functions](../05/) diff --git a/glossary/acos/README.md b/glossary/acos/README.md index 84f11e0..3128024 100644 --- a/glossary/acos/README.md +++ b/glossary/acos/README.md @@ -18,4 +18,4 @@ vec4 acos(vec4 x)
### See Also -[cos()](/glossary/?search=cos), [sin()](/glossary/?search=sin), [asin()](/glossary/?search=asin), [tan()](/glossary/?search=tan), [atan()](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[cos()](/glossary/?search=cos), [sin()](/glossary/?search=sin), [asin()](/glossary/?search=asin), [tan()](/glossary/?search=tan), [atan()](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/asin/README.md b/glossary/asin/README.md index 837e02a..00f064d 100644 --- a/glossary/asin/README.md +++ b/glossary/asin/README.md @@ -18,4 +18,4 @@ vec4 asin(vec4 x)
### See Also -[cos](/glossary/?search=cos), [sin](/glossary/?search=sin), [acos](/glossary/?search=acos), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[cos](/glossary/?search=cos), [sin](/glossary/?search=sin), [acos](/glossary/?search=acos), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/attribute/README.md b/glossary/attribute/README.md index 7201158..10e93fe 100644 --- a/glossary/attribute/README.md +++ b/glossary/attribute/README.md @@ -12,4 +12,4 @@ attribute vec4 v_color; Because the vertex shader is executed one time for each vertex, attributes are specify per vertex data typically with information such as: space position, color, normal direction and texture coordinates of a vertex. ### See Also -[const](/glossary/?search=const), [uniform](/glossary/?search=uniform), [varying](/glossary/?search=varying), [Chapter 03: Uniforms](/03/) \ No newline at end of file +[const](/glossary/?search=const), [uniform](/glossary/?search=uniform), [varying](/glossary/?search=varying), [Chapter 03: Uniforms](/03/) diff --git a/glossary/bool/README.md b/glossary/bool/README.md index 9b8411e..8bc630a 100644 --- a/glossary/bool/README.md +++ b/glossary/bool/README.md @@ -12,4 +12,4 @@ bool cBool = bool(aFloat); ```bool``` data type is either true or false. ### See Also -[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [struct](/glossary/?search=struct) \ No newline at end of file +[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [struct](/glossary/?search=struct) diff --git a/glossary/ceil/README.md b/glossary/ceil/README.md index cbebb1d..affed94 100644 --- a/glossary/ceil/README.md +++ b/glossary/ceil/README.md @@ -18,4 +18,4 @@ vec4 ceil(vec4 x)
### See Also -[floor](/glossary/?search=floor), [fract](/glossary/?search=fract), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[floor](/glossary/?search=floor), [fract](/glossary/?search=fract), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/clamp/README.md b/glossary/clamp/README.md index f6d9fb6..32013ae 100644 --- a/glossary/clamp/README.md +++ b/glossary/clamp/README.md @@ -10,7 +10,7 @@ vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal) vec2 clamp(vec2 x, float minVal, float maxVal) vec3 clamp(vec3 x, float minVal, float maxVal) -vec4 clamp(vec4 x, float minVal, float maxVal) +vec4 clamp(vec4 x, float minVal, float maxVal) ``` ### Parameters @@ -26,4 +26,4 @@ vec4 clamp(vec4 x, float minVal, float maxVal)
### See Also -[min](/glossary/?search=min), [abs](/glossary/?search=abs), [max](/glossary/?search=max) \ No newline at end of file +[min](/glossary/?search=min), [abs](/glossary/?search=abs), [max](/glossary/?search=max) diff --git a/glossary/const/README.md b/glossary/const/README.md index ccf1a2a..3cb0c57 100644 --- a/glossary/const/README.md +++ b/glossary/const/README.md @@ -10,4 +10,4 @@ const float PI = 3.14159265359; ```const``` qualifier can be applied to the declaration of any variable to specify that its value will not be changed. ### See also -[attribute](/glossary/?search=attribute), [uniform](/glossary/?search=uniform), [varying](/glossary/?search=varying) \ No newline at end of file +[attribute](/glossary/?search=attribute), [uniform](/glossary/?search=uniform), [varying](/glossary/?search=varying) diff --git a/glossary/cos/README.md b/glossary/cos/README.md index 2545ce1..dffaed2 100644 --- a/glossary/cos/README.md +++ b/glossary/cos/README.md @@ -18,4 +18,4 @@ vec4 cos(vec4 angle)
### See Also -[acos](/glossary/?search=acos), [sin](/glossary/?search=sin), [asin](/glossary/?search=asin), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[acos](/glossary/?search=acos), [sin](/glossary/?search=sin), [asin](/glossary/?search=asin), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/cross/README.md b/glossary/cross/README.md index 9022878..e57353f 100644 --- a/glossary/cross/README.md +++ b/glossary/cross/README.md @@ -16,4 +16,4 @@ vec3 cross(vec3 x, vec3 y) ### See Also -[dot()](/glossary/?search=dot) \ No newline at end of file +[dot()](/glossary/?search=dot) diff --git a/glossary/dFdx/README.md b/glossary/dFdx/README.md index 2621568..80a1c18 100644 --- a/glossary/dFdx/README.md +++ b/glossary/dFdx/README.md @@ -13,4 +13,4 @@ genType dFdx(float x); Available only in the fragment shader, ```dFdx``` return the partial derivative of expression ```p``` in ```x```. Deviatives are calculated using local differencing. Expressions that imply higher order derivatives such as ```dFdx(dFdx(n))``` have undefined results, as do mixed-order derivatives such as ```dFdx(dFdy(n))```. It is assumed that the expression ```p``` is continuous and therefore, expressions evaluated via non-uniform control flow may be undefined. ### See Also -[dFdy()](/glossary/?search=dFdy) \ No newline at end of file +[dFdy()](/glossary/?search=dFdy) diff --git a/glossary/dFdy/README.md b/glossary/dFdy/README.md index e58c6f0..1edb54d 100644 --- a/glossary/dFdy/README.md +++ b/glossary/dFdy/README.md @@ -13,4 +13,4 @@ genType dFdy(float y); Available only in the fragment shader, ```dFdy``` return the partial derivative of expression ```p``` in ```y```. Deviatives are calculated using local differencing. Expressions that imply higher order derivatives such as ```dFdy(dFdy(n))``` have undefined results, as do mixed-order derivatives such as ```dFdy(dFdx(n))```. It is assumed that the expression ```p``` is continuous and therefore, expressions evaluated via non-uniform control flow may be undefined. ### See Also -[dFdx()](/glossary/?search=dFdx) \ No newline at end of file +[dFdx()](/glossary/?search=dFdx) diff --git a/glossary/degrees/README.md b/glossary/degrees/README.md index de4048c..a782b2b 100644 --- a/glossary/degrees/README.md +++ b/glossary/degrees/README.md @@ -8,7 +8,7 @@ vec2 degrees(vec2 radians) vec3 degrees(vec3 radians) vec4 degrees(vec4 radians) ``` - + ### Parameters ```radians``` specify the quantity, in radians, to be converted to degrees. @@ -16,4 +16,4 @@ vec4 degrees(vec4 radians) ```degrees()``` converts a quantity, specified in radians into degrees. That is, the return value is ```(180.0*radians)/PI``` ### See Also -[radians](/glossary/?search=radians) \ No newline at end of file +[radians](/glossary/?search=radians) diff --git a/glossary/distance/README.md b/glossary/distance/README.md index 7c83a81..84e4b81 100644 --- a/glossary/distance/README.md +++ b/glossary/distance/README.md @@ -21,4 +21,4 @@ float distance(vec4 p0, vec4 p1) ### See Also -[length()](/glossary/?search=length), [normalize()](/glossary/?search=normalize), [Chapter 07: Shapes](/07/) \ No newline at end of file +[length()](/glossary/?search=length), [normalize()](/glossary/?search=normalize), [Chapter 07: Shapes](/07/) diff --git a/glossary/dot/README.md b/glossary/dot/README.md index af44c3a..7dc06b2 100644 --- a/glossary/dot/README.md +++ b/glossary/dot/README.md @@ -15,11 +15,11 @@ float dot(vec4 x, vec4 y) ```y``` specifies the second of two vectors ### Description -```dot()``` returns the dot product of two vectors, ```x``` and ```y```. i.e., ```x[0]⋅y[0]+x[1]⋅y[1]+...``` +```dot()``` returns the dot product of two vectors, ```x``` and ```y```. i.e., ```x[0]⋅y[0]+x[1]⋅y[1]+...``` If ```x``` and ```y``` are the same the square root of the dot product is equivalent to the length of the vector. The input parameters can be floating scalars or float vectors. In case of floating scalars the dot function is trivial and returns the product of x and y.
### See Also -[cross()](/glossary/?search=cross), [Chapter 07: Shapes](/07/) \ No newline at end of file +[cross()](/glossary/?search=cross), [Chapter 07: Shapes](/07/) diff --git a/glossary/exp/README.md b/glossary/exp/README.md index c7bd819..2f6d42d 100644 --- a/glossary/exp/README.md +++ b/glossary/exp/README.md @@ -19,4 +19,4 @@ vec4 exp(vec4 x) ### See Also -[log](/glossary/?search=log), [log2](/glossary/?search=log2), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[log](/glossary/?search=log), [log2](/glossary/?search=log2), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/exp2/README.md b/glossary/exp2/README.md index 98433f9..1c508dc 100644 --- a/glossary/exp2/README.md +++ b/glossary/exp2/README.md @@ -19,4 +19,4 @@ vec4 exp2(vec4 x) ### See Also -[log](/glossary/?search=log), [log2](/glossary/?search=log2), [exp](/glossary/?search=exp), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[log](/glossary/?search=log), [log2](/glossary/?search=log2), [exp](/glossary/?search=exp), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/faceforward/README.md b/glossary/faceforward/README.md index 8a721af..766062a 100644 --- a/glossary/faceforward/README.md +++ b/glossary/faceforward/README.md @@ -20,4 +20,4 @@ vec4 faceforward(vec4 N, vec4 I, vec4 Nref) ```faceforward()``` orients a vector to point away from a surface as defined by its normal. ```If dot(Nref, I) < 0``` faceforward returns ```N```, otherwise it returns ```-N```. ### See Also -[reflect()](/glossary/?search=reflect), [refract()](/glossary/?search=refract) \ No newline at end of file +[reflect()](/glossary/?search=reflect), [refract()](/glossary/?search=refract) diff --git a/glossary/float/README.md b/glossary/float/README.md index cf88ac0..d9dd6bf 100644 --- a/glossary/float/README.md +++ b/glossary/float/README.md @@ -8,8 +8,8 @@ float bFloat = float(aBool); float cFloat = float(aInt); ``` -### Description +### Description ```float``` is used for floating point values. ### See Also -[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [struct](/glossary/?search=struct) \ No newline at end of file +[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [struct](/glossary/?search=struct) diff --git a/glossary/floor/README.md b/glossary/floor/README.md index 9b39cc2..8b496d0 100644 --- a/glossary/floor/README.md +++ b/glossary/floor/README.md @@ -18,4 +18,4 @@ vec4 floor(vec4 x)
### See Also -[ceil](/glossary/?search=ceil), [fract](/glossary/?search=fract), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[ceil](/glossary/?search=ceil), [fract](/glossary/?search=fract), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/fract/README.md b/glossary/fract/README.md index 6f6783d..68fd266 100644 --- a/glossary/fract/README.md +++ b/glossary/fract/README.md @@ -18,4 +18,4 @@ vec4 fract(vec4 x)
### See Also -[floor](/glossary/?search=floor), [ceil](/glossary/?search=ceil), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[floor](/glossary/?search=floor), [ceil](/glossary/?search=ceil), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/gl_FragCoord/README.md b/glossary/gl_FragCoord/README.md index e4b5b8f..8aac4f7 100644 --- a/glossary/gl_FragCoord/README.md +++ b/glossary/gl_FragCoord/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_FrontFacing/README.md b/glossary/gl_FrontFacing/README.md index 10d0fbc..0abc889 100644 --- a/glossary/gl_FrontFacing/README.md +++ b/glossary/gl_FrontFacing/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_MaxCombinedTextureImageUnits/README.md b/glossary/gl_MaxCombinedTextureImageUnits/README.md index 1441068..377bffe 100644 --- a/glossary/gl_MaxCombinedTextureImageUnits/README.md +++ b/glossary/gl_MaxCombinedTextureImageUnits/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_MaxDrawBuffers/README.md b/glossary/gl_MaxDrawBuffers/README.md index ce9c2f6..2552884 100644 --- a/glossary/gl_MaxDrawBuffers/README.md +++ b/glossary/gl_MaxDrawBuffers/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_MaxFragmentUniformVectors/README.md b/glossary/gl_MaxFragmentUniformVectors/README.md index 6c53e1d..b4be9bb 100644 --- a/glossary/gl_MaxFragmentUniformVectors/README.md +++ b/glossary/gl_MaxFragmentUniformVectors/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_MaxTextureImageUnits/README.md b/glossary/gl_MaxTextureImageUnits/README.md index cef4274..5a20830 100644 --- a/glossary/gl_MaxTextureImageUnits/README.md +++ b/glossary/gl_MaxTextureImageUnits/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_MaxVaryingVectors/README.md b/glossary/gl_MaxVaryingVectors/README.md index ce55e01..542161c 100644 --- a/glossary/gl_MaxVaryingVectors/README.md +++ b/glossary/gl_MaxVaryingVectors/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_MaxVertexAttribs/README.md b/glossary/gl_MaxVertexAttribs/README.md index f9ed58d..2f0c679 100644 --- a/glossary/gl_MaxVertexAttribs/README.md +++ b/glossary/gl_MaxVertexAttribs/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_MaxVertexTextureImageUnits/README.md b/glossary/gl_MaxVertexTextureImageUnits/README.md index 6e665af..2e6552b 100644 --- a/glossary/gl_MaxVertexTextureImageUnits/README.md +++ b/glossary/gl_MaxVertexTextureImageUnits/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_PointCoord/README.md b/glossary/gl_PointCoord/README.md index ed280da..27444dd 100644 --- a/glossary/gl_PointCoord/README.md +++ b/glossary/gl_PointCoord/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_PointSize/README.md b/glossary/gl_PointSize/README.md index af47b5d..85b4826 100644 --- a/glossary/gl_PointSize/README.md +++ b/glossary/gl_PointSize/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/gl_Position/README.md b/glossary/gl_Position/README.md index 7724015..6bdf503 100644 --- a/glossary/gl_Position/README.md +++ b/glossary/gl_Position/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/highp/README.md b/glossary/highp/README.md index 21c004e..5e47762 100644 --- a/glossary/highp/README.md +++ b/glossary/highp/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/in/README.md b/glossary/in/README.md index 9f60041..68f7db8 100644 --- a/glossary/in/README.md +++ b/glossary/in/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/index.php b/glossary/index.php index 02ecfd1..505fa6b 100644 --- a/glossary/index.php +++ b/glossary/index.php @@ -1,7 +1,7 @@ -
-text(file_get_contents ('README.md')); - else + else echo $Parsedown->text(file_get_contents ( $_GET['search'].'/README.md' )); echo '

'; - include($path."/footer.php"); + include($path."/footer.php"); ?> diff --git a/glossary/inout/README.md b/glossary/inout/README.md index c6b5205..7917016 100644 --- a/glossary/inout/README.md +++ b/glossary/inout/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/int/README.md b/glossary/int/README.md index b65de5e..298a33c 100644 --- a/glossary/int/README.md +++ b/glossary/int/README.md @@ -12,4 +12,4 @@ int cInt = int(aFloat); ```int``` is used for integer values. ### See Also -[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4) \ No newline at end of file +[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4) diff --git a/glossary/inversesqrt/README.md b/glossary/inversesqrt/README.md index 6cb20c5..676278a 100644 --- a/glossary/inversesqrt/README.md +++ b/glossary/inversesqrt/README.md @@ -1,4 +1,4 @@ -## Inversesqrt +## Inversesqrt Return the inverse of the square root of the parameter ### Declaration @@ -19,4 +19,4 @@ vec4 inversesqrt(vec4 x) ### See Also -[pow](/glossary/?search=pow), [sqrt](/glossary/?search=sqrt), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[pow](/glossary/?search=pow), [sqrt](/glossary/?search=sqrt), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/ivec2/README.md b/glossary/ivec2/README.md index 3a12688..bd3727f 100644 --- a/glossary/ivec2/README.md +++ b/glossary/ivec2/README.md @@ -18,4 +18,4 @@ bvec2 dIvec2 = ivec2(aIvec3.x, aIvec3.y); - Providing a vector of higher dimension. The respective values are used to initialize the components. ### See Also -[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) \ No newline at end of file +[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) diff --git a/glossary/ivec3/README.md b/glossary/ivec3/README.md index 9333f89..3fc54db 100644 --- a/glossary/ivec3/README.md +++ b/glossary/ivec3/README.md @@ -22,4 +22,4 @@ vec3 fIvec3 = ivec3(aIvec2.x, aIvec2.y, aInt); - Providing a combination of vectors and/or scalars. The respective values are used to initialize the vector. The arguments of the constructor must have at least as many components as the vector that is initialized. ### See Also -[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) \ No newline at end of file +[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) diff --git a/glossary/ivec4/README.md b/glossary/ivec4/README.md index f4bec82..9abeb7f 100644 --- a/glossary/ivec4/README.md +++ b/glossary/ivec4/README.md @@ -18,4 +18,4 @@ vec4 dIvec4 = ivec4(aIvec2.x, aIvec2.y, aInt, aIvec3.x); - Providing a combination of vectors and/or scalars. The respective values are used to initialize the vector. The arguments of the constructor must have at least as many components as the vector that is initialized. ### See Also -[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) \ No newline at end of file +[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) diff --git a/glossary/length/README.md b/glossary/length/README.md index f1284e9..e7a77e8 100644 --- a/glossary/length/README.md +++ b/glossary/length/README.md @@ -19,4 +19,4 @@ float length(vec4 x) ### See Also -[distance()](/glossary/?search=distance), [normalize()](/glossary/?search=normalize), [Chapter 07: Shapes](/07/) \ No newline at end of file +[distance()](/glossary/?search=distance), [normalize()](/glossary/?search=normalize), [Chapter 07: Shapes](/07/) diff --git a/glossary/log/README.md b/glossary/log/README.md index 8ce2c42..4ee7916 100644 --- a/glossary/log/README.md +++ b/glossary/log/README.md @@ -19,4 +19,4 @@ vec4 log(vec4 x) ### See Also -[log2](/glossary/?search=log2), [exp](/glossary/?search=exp), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[log2](/glossary/?search=log2), [exp](/glossary/?search=exp), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/log2/README.md b/glossary/log2/README.md index af8c6da..72856b9 100644 --- a/glossary/log2/README.md +++ b/glossary/log2/README.md @@ -19,4 +19,4 @@ vec4 log2(vec4 x) ### See Also -[log](/glossary/?search=log), [exp](/glossary/?search=exp), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[log](/glossary/?search=log), [exp](/glossary/?search=exp), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/lowp/README.md b/glossary/lowp/README.md index 23c6e29..a72b8d3 100644 --- a/glossary/lowp/README.md +++ b/glossary/lowp/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/main/README.md b/glossary/main/README.md index 974fa90..0e8ff74 100644 --- a/glossary/main/README.md +++ b/glossary/main/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/mat3/README.md b/glossary/mat3/README.md index 2c5ba4f..361d3a9 100644 --- a/glossary/mat3/README.md +++ b/glossary/mat3/README.md @@ -34,4 +34,4 @@ vec3 aVec3 = aMat3[0]; ``` ### See Also -[mat2](/glossary/?search=mat2), [mat4](/glossary/?search=mat4), [matrixCompMult()](/glossary/?search=matrixCompMult) \ No newline at end of file +[mat2](/glossary/?search=mat2), [mat4](/glossary/?search=mat4), [matrixCompMult()](/glossary/?search=matrixCompMult) diff --git a/glossary/mat4/README.md b/glossary/mat4/README.md index 07ba0e7..43812f9 100644 --- a/glossary/mat4/README.md +++ b/glossary/mat4/README.md @@ -33,4 +33,4 @@ vec4 aVec4 = aMat4[0]; ``` ### See Also -[mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [matrixCompMult()](/glossary/?search=matrixCompMult) \ No newline at end of file +[mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [matrixCompMult()](/glossary/?search=matrixCompMult) diff --git a/glossary/matrixCompMult/README.md b/glossary/matrixCompMult/README.md index 0d5b882..3fdd71d 100644 --- a/glossary/matrixCompMult/README.md +++ b/glossary/matrixCompMult/README.md @@ -17,4 +17,4 @@ mat4 matrixCompMult(mat4 x, mat4 y) ```matrixCompMult()``` performs a component-wise multiplication of two matrices, yielding a result matrix where each component, ```result[i][j]``` is computed as the scalar product of ```x[i][j]``` and ```y[i][j]```. ### See Also -[Chapter 08: Matrix](../08/) \ No newline at end of file +[Chapter 08: Matrix](../08/) diff --git a/glossary/max/README.md b/glossary/max/README.md index 770ec31..56f4da3 100644 --- a/glossary/max/README.md +++ b/glossary/max/README.md @@ -24,4 +24,4 @@ vec4 max(vec4 x, float y)
### See Also -[min](/glossary/?search=min), [abs](/glossary/?search=abs), [clamp](/glossary/?search=clamp), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[min](/glossary/?search=min), [abs](/glossary/?search=abs), [clamp](/glossary/?search=clamp), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/mediump/README.md b/glossary/mediump/README.md index 1129e2f..c049fda 100644 --- a/glossary/mediump/README.md +++ b/glossary/mediump/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/min/README.md b/glossary/min/README.md index 8310a6d..298e5ad 100644 --- a/glossary/min/README.md +++ b/glossary/min/README.md @@ -24,4 +24,4 @@ vec4 min(vec4 x, float y)
### See Also -[max](/glossary/?search=max), [abs](/glossary/?search=abs), [clamp](/glossary/?search=clamp), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[max](/glossary/?search=max), [abs](/glossary/?search=abs), [clamp](/glossary/?search=clamp), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/mod/README.md b/glossary/mod/README.md index d0d0a27..69fdf5a 100644 --- a/glossary/mod/README.md +++ b/glossary/mod/README.md @@ -23,4 +23,4 @@ vec4 mod(vec4 x, float y)
### See Also -[floor](/glossary/?search=floor), [fract](/glossary/?search=fract), [ceil](/glossary/?search=ceil), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[floor](/glossary/?search=floor), [fract](/glossary/?search=fract), [ceil](/glossary/?search=ceil), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/normalize/README.md b/glossary/normalize/README.md index 03ed151..7a27999 100644 --- a/glossary/normalize/README.md +++ b/glossary/normalize/README.md @@ -17,4 +17,4 @@ vec4 normalize(vec4 x) ### See Also -[length()](/glossary/?search=length) \ No newline at end of file +[length()](/glossary/?search=length) diff --git a/glossary/out/README.md b/glossary/out/README.md index 54c833f..dd85d89 100644 --- a/glossary/out/README.md +++ b/glossary/out/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/pow/README.md b/glossary/pow/README.md index 65fc714..b7fc9fb 100644 --- a/glossary/pow/README.md +++ b/glossary/pow/README.md @@ -21,4 +21,4 @@ vec4 pow(vec4 x, vec4 y) ### See Also -[inversesqrt](/glossary/?search=inversesqrt), [sqrt](/glossary/?search=sqrt), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[inversesqrt](/glossary/?search=inversesqrt), [sqrt](/glossary/?search=sqrt), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/precision/README.md b/glossary/precision/README.md index 0343239..f810251 100644 --- a/glossary/precision/README.md +++ b/glossary/precision/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/radians/README.md b/glossary/radians/README.md index 6ecbaac..bf29e72 100644 --- a/glossary/radians/README.md +++ b/glossary/radians/README.md @@ -8,7 +8,7 @@ vec2 radians(vec2 degrees) vec3 radians(vec3 degrees) vec4 radians(vec4 degrees) ``` - + ### Parameters ```degrees``` specify the quantity, in degrees, to be converted to radians. @@ -16,4 +16,4 @@ vec4 radians(vec4 degrees) ```radians()``` converts a quantity, specified in degrees into radians. That is, the return value is ```(PI * degrees)/180```. ### See Also -[degrees](/glossary/?search=degrees) \ No newline at end of file +[degrees](/glossary/?search=degrees) diff --git a/glossary/reflect/README.md b/glossary/reflect/README.md index be0d8ae..4455e22 100644 --- a/glossary/reflect/README.md +++ b/glossary/reflect/README.md @@ -21,4 +21,4 @@ For a given incident vector ```I``` and surface normal ```N``` reflect returns t ### See Also -[dot()](/glossary/?search=dot), [refract()](/glossary/?search=refract) \ No newline at end of file +[dot()](/glossary/?search=dot), [refract()](/glossary/?search=refract) diff --git a/glossary/refract/README.md b/glossary/refract/README.md index a1414b2..b428545 100644 --- a/glossary/refract/README.md +++ b/glossary/refract/README.md @@ -31,4 +31,4 @@ The input parameters ```I``` and ```N``` should be normalized in order to achiev ### See Also -[dot()](/glossary/?search=dot), [reflect()](/glossary/?search=reflect) \ No newline at end of file +[dot()](/glossary/?search=dot), [reflect()](/glossary/?search=reflect) diff --git a/glossary/return/README.md b/glossary/return/README.md index e252b86..76ab6b0 100644 --- a/glossary/return/README.md +++ b/glossary/return/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/sampler2D/README.md b/glossary/sampler2D/README.md index 76c7110..40622ed 100644 --- a/glossary/sampler2D/README.md +++ b/glossary/sampler2D/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/samplerCube/README.md b/glossary/samplerCube/README.md index 46c9505..ba0e7c8 100644 --- a/glossary/samplerCube/README.md +++ b/glossary/samplerCube/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/sign/README.md b/glossary/sign/README.md index d54a69e..656f2c4 100644 --- a/glossary/sign/README.md +++ b/glossary/sign/README.md @@ -18,4 +18,4 @@ vec4 sign(vec4 x)
### See Also -[abs](/glossary/?search=abs), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[abs](/glossary/?search=abs), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/sin/README.md b/glossary/sin/README.md index 59b5174..fb0c2e9 100644 --- a/glossary/sin/README.md +++ b/glossary/sin/README.md @@ -18,4 +18,4 @@ vec4 sin(vec4 angle)
### See Also -[acos](/glossary/?search=acos), [cos](/glossary/?search=cos), [asin](/glossary/?search=asin), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[acos](/glossary/?search=acos), [cos](/glossary/?search=cos), [asin](/glossary/?search=asin), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/sqrt/README.md b/glossary/sqrt/README.md index 741fce3..8895ba3 100644 --- a/glossary/sqrt/README.md +++ b/glossary/sqrt/README.md @@ -20,4 +20,4 @@ vec4 sqrt(vec4 x)
### See Also -[inversesqrt](/glossary/?search=inversesqrt), [pow](/glossary/?search=pow), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[inversesqrt](/glossary/?search=inversesqrt), [pow](/glossary/?search=pow), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/step/README.md b/glossary/step/README.md index 42e9558..baf78f5 100644 --- a/glossary/step/README.md +++ b/glossary/step/README.md @@ -28,4 +28,4 @@ For element ```i``` of the return value, ```0.0``` is returned ```if x[i] < edge
### See Also -[mix](/glossary/?search=mix), [smoothstep](/glossary/?search=smoothstep), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[mix](/glossary/?search=mix), [smoothstep](/glossary/?search=smoothstep), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/struct/README.md b/glossary/struct/README.md index 2782bfc..6338481 100644 --- a/glossary/struct/README.md +++ b/glossary/struct/README.md @@ -4,7 +4,7 @@ Structure variable type ### Example ```glsl struct matStruct { - vec4 ambientColor; + vec4 ambientColor; vec4 diffuseColor; vec4 specularColor; float specularExponent; @@ -17,4 +17,4 @@ newMaterial = matStruct(vec4(0.1, 0.1, 0.1, 1.0), ``` ### Description -```struct``` declare a custom data structures based on standard types. A constructor for the structure with the same name is created automatically. The declaration of a variable (in this case "newMaterial") is optional. \ No newline at end of file +```struct``` declare a custom data structures based on standard types. A constructor for the structure with the same name is created automatically. The declaration of a variable (in this case "newMaterial") is optional. diff --git a/glossary/tan/README.md b/glossary/tan/README.md index 13b2bb8..0430a8c 100644 --- a/glossary/tan/README.md +++ b/glossary/tan/README.md @@ -18,4 +18,4 @@ vec4 tan(vec4 angle)
### See Also -[cos](/glossary/?search=cos), [acos](/glossary/?search=acos), [sin](/glossary/?search=sin), [asin](/glossary/?search=asin), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) \ No newline at end of file +[cos](/glossary/?search=cos), [acos](/glossary/?search=acos), [sin](/glossary/?search=sin), [asin](/glossary/?search=asin), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/) diff --git a/glossary/texture2D/README.md b/glossary/texture2D/README.md index 964e74c..667010c 100644 --- a/glossary/texture2D/README.md +++ b/glossary/texture2D/README.md @@ -22,4 +22,4 @@ There is an optional third input parameter of the type float: bias. After calcul Side note: On iOS devices texture lookup functionality is only available in the fragment shader. ### See Also -[textureCube](/glossary/?search=textureCube) \ No newline at end of file +[textureCube](/glossary/?search=textureCube) diff --git a/glossary/textureCube/README.md b/glossary/textureCube/README.md index 4c20412..ee196a9 100644 --- a/glossary/textureCube/README.md +++ b/glossary/textureCube/README.md @@ -22,4 +22,4 @@ There is an optional third input parameter of the type float: bias. After calcul Side note: On iOS devices texture lookup functionality is only available in the fragment shader. ### See Also -[texture2D](/glossary/?search=texture2D) \ No newline at end of file +[texture2D](/glossary/?search=texture2D) diff --git a/glossary/uniform/README.md b/glossary/uniform/README.md index 1f88d12..04b632f 100644 --- a/glossary/uniform/README.md +++ b/glossary/uniform/README.md @@ -7,4 +7,4 @@ ### Description ### See Also -[Chapter 03: Uniforms](../05/) \ No newline at end of file +[Chapter 03: Uniforms](../05/) diff --git a/glossary/varying/README.md b/glossary/varying/README.md index 0a8da52..95fadcb 100644 --- a/glossary/varying/README.md +++ b/glossary/varying/README.md @@ -6,4 +6,4 @@ ### Description -### See Also \ No newline at end of file +### See Also diff --git a/glossary/vec2/README.md b/glossary/vec2/README.md index d768255..480703e 100644 --- a/glossary/vec2/README.md +++ b/glossary/vec2/README.md @@ -18,4 +18,4 @@ vec2 dVec2 = vec2(aVec3.x, aVec3.y); - Providing a vector of higher dimension. The respective values are used to initialize the components. ### See Also -[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) \ No newline at end of file +[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) diff --git a/glossary/vec3/README.md b/glossary/vec3/README.md index 573d646..aa207cc 100644 --- a/glossary/vec3/README.md +++ b/glossary/vec3/README.md @@ -22,4 +22,4 @@ vec3 fVec3 = vec3(aVec2.x, aVec2.y, aFloat); - Providing a combination of vectors and/or scalars. The respective values are used to initialize the vector. The arguments of the constructor must have at least as many components as the vector that is initialized. ### See Also -[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) \ No newline at end of file +[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) diff --git a/glossary/vec4/README.md b/glossary/vec4/README.md index d1bbfad..3947b2b 100644 --- a/glossary/vec4/README.md +++ b/glossary/vec4/README.md @@ -18,4 +18,4 @@ vec4 dBvec4 = bvec4(aBvec2.x, aBvec2.y, aBool, aBvec3.x); - Providing a combination of vectors and scalars. The respective values are used to initialize the components. The arguments of the constructor must have at least as many components as the vector that is initialized. ### See Also -[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) \ No newline at end of file +[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4) diff --git a/glossary/void/README.md b/glossary/void/README.md index 87168f3..558de4e 100644 --- a/glossary/void/README.md +++ b/glossary/void/README.md @@ -11,4 +11,4 @@ void bFunction(float); ```void``` is used when a function have no parameters or when a function does not return a value. ### See Also -[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float) \ No newline at end of file +[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float) diff --git a/graph.html b/graph.html index 105dfa1..9637ff9 100644 --- a/graph.html +++ b/graph.html @@ -9,7 +9,7 @@ - + ",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}}); \ No newline at end of file +!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&").replace(//gm,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){return/^(no-?highlight|plain|text)$/i.test(e)}function i(e){var n,t,r,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=/\blang(?:uage)?-([\w-]+)\b/i.exec(i))return w(t[1])?t[1]:"no-highlight";for(i=i.split(/\s+/),n=0,r=i.length;r>n;n++)if(w(i[n])||a(i[n]))return i[n]}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset"}function u(e){f+=""}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,f="",l=[];e.length||r.length;){var g=i();if(f+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){l.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);l.reverse().forEach(o)}else"start"==g[0].event?l.push(g[0].node):l.pop(),c(g.splice(0,1)[0])}return f+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\b\w+\b/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var f=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=f.length?t(f.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){for(var t=0;t";return i+=e+'">',i+n+o}function h(){if(!k.k)return n(M);var e="",t=0;k.lR.lastIndex=0;for(var r=k.lR.exec(M);r;){e+=n(M.substr(t,r.index-t));var a=g(k,r);a?(B+=a[1],e+=p(a[0],n(r[0]))):e+=n(r[0]),t=k.lR.lastIndex,r=k.lR.exec(M)}return e+n(M.substr(t))}function d(){var e="string"==typeof k.sL;if(e&&!R[k.sL])return n(M);var t=e?f(k.sL,M,!0,y[k.sL]):l(M,k.sL.length?k.sL:void 0);return k.r>0&&(B+=t.r),e&&(y[k.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=void 0!==k.sL?d():h(),M=""}function v(e,n){L+=e.cN?p(e.cN,"",!0):"",k=Object.create(e,{parent:{value:k}})}function m(e,n){if(M+=e,void 0===n)return b(),0;var t=o(n,k);if(t)return t.skip?M+=n:(t.eB&&(M+=n),b(),t.rB||t.eB||(M=n)),v(t,n),t.rB?0:n.length;var r=u(k,n);if(r){var a=k;a.skip?M+=n:(a.rE||a.eE||(M+=n),b(),a.eE&&(M=n));do k.cN&&(L+=""),k.skip||(B+=k.r),k=k.parent;while(k!=r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,k))throw new Error('Illegal lexeme "'+n+'" for mode "'+(k.cN||"")+'"');return M+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var x,k=i||N,y={},L="";for(x=k;x!=N;x=x.parent)x.cN&&(L=p(x.cN,"",!0)+L);var M="",B=0;try{for(var C,j,I=0;;){if(k.t.lastIndex=I,C=k.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),x=k;x.parent;x=x.parent)x.cN&&(L+="");return{r:B,value:L,language:e,top:k}}catch(O){if(-1!=O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function l(e,t){t=t||E.languages||Object.keys(R);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(w(n)){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function g(e){return E.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,E.tabReplace)})),E.useBR&&(e=e.replace(/\n/g,"
")),e}function p(e,n,t){var r=n?x[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n=i(e);if(!a(n)){var t;E.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):t=e;var r=t.textContent,o=n?f(n,r,!0):l(r),s=u(t);if(s.length){var h=document.createElementNS("http://www.w3.org/1999/xhtml","div");h.innerHTML=o.value,o.value=c(s,u(h),r)}o.value=g(o.value),e.innerHTML=o.value,e.className=p(e.className,n,o.language),e.result={language:o.language,re:o.r},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.r})}}function d(e){E=o(E,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,h)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=R[n]=t(e);r.aliases&&r.aliases.forEach(function(e){x[e]=n})}function N(){return Object.keys(R)}function w(e){return e=(e||"").toLowerCase(),R[e]||R[x[e]]}var E={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},R={},x={};return e.highlight=f,e.highlightAuto=l,e.fixMarkup=g,e.highlightBlock=h,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("php",function(e){var c={b:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},a={cN:"meta",b:/<\?(php)?|\?>/},i={cN:"string",c:[e.BE,a],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},t={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.HCM,e.C("//","$",{c:[a]}),e.C("/\\*","\\*/",{c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:/<<<['"]?\w+['"]?$/,e:/^\w+;?$/,c:[e.BE,{cN:"subst",v:[{b:/\$\w+/},{b:/\{\$/,e:/\}/}]}]},a,c,{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",c,e.CBCM,i,t]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},i,t]}});hljs.registerLanguage("perl",function(e){var t="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when",r={cN:"subst",b:"[$@]\\{",e:"\\}",k:t},s={b:"->{",e:"}"},n={v:[{b:/\$\d/},{b:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{b:/[\$%@][^\s\w{]/,r:0}]},i=[e.BE,r,n],o=[n,e.HCM,e.C("^\\=\\w","\\=cut",{eW:!0}),s,{cN:"string",c:i,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[e.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[e.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"function",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",eE:!0,r:5,c:[e.TM]},{b:"-\\w\\b",r:0},{b:"^__DATA__$",e:"^__END__$",sL:"mojolicious",c:[{b:"^@@.*",e:"$",cN:"comment"}]}];return r.c=o,s.c=o,{aliases:["pl"],k:t,c:o}});hljs.registerLanguage("apache",function(e){var r={cN:"number",b:"[\\$%]\\d+"};return{aliases:["apacheconf"],cI:!0,c:[e.HCM,{cN:"section",b:""},{cN:"attribute",b:/\w+/,r:0,k:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"meta",b:"\\s\\[",e:"\\]$"},{cN:"variable",b:"[\\$%]\\{",e:"\\}",c:["self",r]},r,e.QSM]}}],i:/\S/}});hljs.registerLanguage("java",function(e){var a=e.UIR+"(<"+e.UIR+"(\\s*,\\s*"+e.UIR+")*>)?",t="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",r="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",c={cN:"number",b:r,r:0};return{aliases:["jsp"],k:t,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",r:0},{cN:"function",b:"("+a+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},c,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("objectivec",function(e){var t={cN:"built_in",b:"(AV|CA|CF|CG|CI|MK|MP|NS|UI|XC)\\w+"},i={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},n=/[a-zA-Z@][a-zA-Z0-9_]*/,o="@interface @class @protocol @implementation";return{aliases:["mm","objc","obj-c"],k:i,l:n,i:""}]}]},{cN:"class",b:"("+o.split(" ").join("|")+")\\b",e:"({|$)",eE:!0,k:o,l:n,c:[e.UTM]},{b:"\\."+e.UIR,r:0}]}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("cs",function(e){var t="abstract as base bool break byte case catch char checked const continue decimal dynamic default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long null when object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async protected public private internal ascending descending from get group into join let orderby partial select set value var where yield",r=e.IR+"(<"+e.IR+">)?";return{aliases:["csharp"],k:t,i:/::/,c:[e.C("///","$",{rB:!0,c:[{cN:"doctag",v:[{b:"///",r:0},{b:""},{b:""}]}]}),e.CLCM,e.CBCM,{cN:"meta",b:"#",e:"$",k:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},e.ASM,e.QSM,e.CNM,{bK:"class interface",e:/[{;=]/,i:/[^\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:"namespace",e:/[{;=]/,i:/[^\s:]/,c:[e.inherit(e.TM,{b:"[a-zA-Z](\\.?\\w)*"}),e.CLCM,e.CBCM]},{bK:"new return throw await",r:0},{cN:"function",b:"("+r+"\\s+)+"+e.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.IR+"\\s*\\(",rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}});hljs.registerLanguage("makefile",function(e){var a={cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]};return{aliases:["mk","mak"],c:[e.HCM,{b:/^\w+\s*\W*=/,rB:!0,r:0,starts:{e:/\s*\W*=/,eE:!0,starts:{e:/$/,r:0,c:[a]}}},{cN:"section",b:/^[\w]+:\s*$/},{cN:"meta",b:/^\.PHONY:/,e:/$/,k:{"meta-keyword":".PHONY"},l:/[\.\w]+/},{b:/^\t+/,e:/$/,r:0,c:[e.QSM,a]}]}});hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke",e:/;/,eW:!0,k:{keyword:"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}});hljs.registerLanguage("python",function(e){var r={cN:"meta",b:/^(>>>|\.\.\.) /},b={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[r],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[r],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},e.ASM,e.QSM]},a={cN:"number",r:0,v:[{b:e.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:e.CNR+"[lLjJ]?"}]},l={cN:"params",b:/\(/,e:/\)/,c:["self",r,a,b]};return{aliases:["py","gyp"],k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[r,a,b,e.HCM,{v:[{cN:"function",bK:"def",r:10},{cN:"class",bK:"class"}],e:/:/,i:/[${=;\n,]/,c:[e.UTM,l,{b:/->/,eW:!0,k:"None"}]},{cN:"meta",b:/^[\t ]*@/,e:/$/},{b:/\b(print|exec)\(/}]}});hljs.registerLanguage("javascript",function(e){return{aliases:["js","jsx"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b://,sL:"xml",c:[{b:/<\w+\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:["self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("nginx",function(e){var r={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},b={eW:!0,l:"[a-z/_]+",k:{literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,r],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[r]},{cN:"regexp",c:[e.BE,r],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},r]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s+{",rB:!0,e:"{",c:[{cN:"section",b:e.UIR}],r:0},{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"attribute",b:e.UIR,starts:b}],r:0}],i:"[^\\s\\}]"}});hljs.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"meta",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"comment",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"addition",b:"^\\!",e:"$"}]}});hljs.registerLanguage("ini",function(e){var b={cN:"string",c:[e.BE],v:[{b:"'''",e:"'''",r:10},{b:'"""',e:'"""',r:10},{b:'"',e:'"'},{b:"'",e:"'"}]};return{aliases:["toml"],cI:!0,i:/\S/,c:[e.C(";","$"),e.HCM,{cN:"section",b:/^\s*\[+/,e:/\]+/},{b:/^[a-z0-9\[\]_-]+\s*=\s*/,e:"$",rB:!0,c:[{cN:"attr",b:/[a-z0-9\[\]_-]+/},{b:/=/,eW:!0,r:0,c:[{cN:"literal",b:/\bon|off|true|false|yes|no\b/},{cN:"variable",v:[{b:/\$[\w\d"][\w\d_]*/},{b:/\$\{(.*?)}/}]},b,{cN:"number",b:/([\+\-]+)?[\d]+_[\d_]+/},e.NM]}]}]}});hljs.registerLanguage("cpp",function(t){var e={cN:"keyword",b:"\\b[a-z\\d_]*_t\\b"},r={cN:"string",v:[t.inherit(t.QSM,{b:'((u8?|U)|L)?"'}),{b:'(u8?|U)?R"',e:'"',c:[t.BE]},{b:"'\\\\?.",e:"'",i:"."}]},i={cN:"number",v:[{b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)(u|U|l|L|ul|UL|f|F)"},{b:t.CNR}],r:0},s={cN:"meta",b:"#",e:"$",k:{"meta-keyword":"if else elif endif define undef warning error line pragma ifdef ifndef"},c:[{b:/\\\n/,r:0},{bK:"include",e:"$",k:{"meta-keyword":"include"},c:[t.inherit(r,{cN:"meta-string"}),{cN:"meta-string",b:"<",e:">",i:"\\n"}]},r,t.CLCM,t.CBCM]},a=t.IR+"\\s*\\(",c={keyword:"int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignof constexpr decltype noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong",built_in:"std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr",literal:"true false nullptr NULL"};return{aliases:["c","cc","h","c++","h++","hpp"],k:c,i:"",k:c,c:["self",e]},{b:t.IR+"::",k:c},{bK:"new throw return else",r:0},{cN:"function",b:"("+t.IR+"[\\*&\\s]+)+"+a,rB:!0,e:/[{;=]/,eE:!0,k:c,i:/[^\w\s\*&]/,c:[{b:a,rB:!0,c:[t.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:c,r:0,c:[t.CLCM,t.CBCM,r,i]},t.CLCM,t.CBCM,s]}]}});hljs.registerLanguage("http",function(e){var t="HTTP/[0-9\\.]+";return{aliases:["https"],i:"\\S",c:[{b:"^"+t,e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{b:"^[A-Z]+ (.*?) "+t+"$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0},{b:t},{cN:"keyword",b:"[A-Z]+"}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{e:"$",r:0}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}});hljs.registerLanguage("ruby",function(e){var b="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",c="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",r={cN:"doctag",b:"@[A-Za-z]+"},a={b:"#<",e:">"},s=[e.C("#","$",{c:[r]}),e.C("^\\=begin","^\\=end",{c:[r],r:10}),e.C("^__END__","\\n$")],n={cN:"subst",b:"#\\{",e:"}",k:c},t={cN:"string",c:[e.BE,n],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]},i={cN:"params",b:"\\(",e:"\\)",endsParent:!0,k:c},d=[t,a,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{b:"<\\s*",c:[{b:"("+e.IR+"::)?"+e.IR}]}].concat(s)},{cN:"function",bK:"def",e:"$|;",c:[e.inherit(e.TM,{b:b}),i].concat(s)},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":",c:[t,{b:b}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[a,{cN:"regexp",c:[e.BE,n],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(s),r:0}].concat(s);n.c=d,i.c=d;var o="[>?]>",l="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",w=[{b:/^\s*=>/,starts:{e:"$",c:d}},{cN:"meta",b:"^("+o+"|"+l+"|"+u+")",starts:{e:"$",c:d}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:c,i:/\/\*/,c:s.concat(w).concat(d)}});hljs.registerLanguage("dts",function(e){var a={cN:"string",v:[e.inherit(e.QSM,{b:'((u8?|U)|L)?"'}),{b:'(u8?|U)?R"',e:'"',c:[e.BE]},{b:"'\\\\?.",e:"'",i:"."}]},c={cN:"number",v:[{b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)(u|U|l|L|ul|UL|f|F)"},{b:e.CNR}],r:0},b={cN:"meta",b:"#",e:"$",k:{"meta-keyword":"if else elif endif define undef ifdef ifndef"},c:[{b:/\\\n/,r:0},{bK:"include",e:"$",k:{"meta-keyword":"include"},c:[e.inherit(a,{cN:"meta-string"}),{cN:"meta-string",b:"<",e:">",i:"\\n"}]},a,e.CLCM,e.CBCM]},i={cN:"variable",b:"\\&[a-z\\d_]*\\b"},r={cN:"meta-keyword",b:"/[a-z][a-z\\d-]*/"},d={cN:"symbol",b:"^\\s*[a-zA-Z_][a-zA-Z\\d_]*:"},n={cN:"params",b:"<",e:">",c:[c,i]},s={cN:"class",b:/[a-zA-Z_][a-zA-Z\d_@]*\s{/,e:/[{;=]/,rB:!0,eE:!0},t={cN:"class",b:"/\\s*{",e:"};",r:10,c:[i,r,d,s,n,e.CLCM,e.CBCM,c,a]};return{k:"",c:[t,i,r,d,s,n,e.CLCM,e.CBCM,c,a,b,{b:e.IR+"::",k:""}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("coffeescript",function(e){var c={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",built_in:"npm require console print module global window document"},n="[A-Za-z$_][0-9A-Za-z$_]*",r={cN:"subst",b:/#\{/,e:/}/,k:c},s=[e.BNM,e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,r]},{b:/"/,e:/"/,c:[e.BE,r]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[r,e.HCM]},{b:"//[gim]*",r:0},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{b:"@"+n},{b:"`",e:"`",eB:!0,eE:!0,sL:"javascript"}];r.c=s;var i=e.inherit(e.TM,{b:n}),t="(\\(.*\\))?\\s*\\B[-=]>",o={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:c,c:["self"].concat(s)}]};return{aliases:["coffee","cson","iced"],k:c,i:/\/\*/,c:s.concat([e.C("###","###"),e.HCM,{cN:"function",b:"^\\s*"+n+"\\s*=\\s*"+t,e:"[-=]>",rB:!0,c:[i,o]},{b:/[:\(,=]\s*/,r:0,c:[{cN:"function",b:t,e:"[-=]>",rB:!0,c:[o]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[i]},i]},{b:n+":",e:":",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage("glsl",function(e){return{k:{keyword:"break continue discard do else for if return whileattribute binding buffer ccw centroid centroid varying coherent column_major const cw depth_any depth_greater depth_less depth_unchanged early_fragment_tests equal_spacing flat fractional_even_spacing fractional_odd_spacing highp in index inout invariant invocations isolines layout line_strip lines lines_adjacency local_size_x local_size_y local_size_z location lowp max_vertices mediump noperspective offset origin_upper_left out packed patch pixel_center_integer point_mode points precise precision quads r11f_g11f_b10f r16 r16_snorm r16f r16i r16ui r32f r32i r32ui r8 r8_snorm r8i r8ui readonly restrict rg16 rg16_snorm rg16f rg16i rg16ui rg32f rg32i rg32ui rg8 rg8_snorm rg8i rg8ui rgb10_a2 rgb10_a2ui rgba16 rgba16_snorm rgba16f rgba16i rgba16ui rgba32f rgba32i rgba32ui rgba8 rgba8_snorm rgba8i rgba8ui row_major sample shared smooth std140 std430 stream triangle_strip triangles triangles_adjacency uniform varying vertices volatile writeonly",type:"atomic_uint bool bvec2 bvec3 bvec4 dmat2 dmat2x2 dmat2x3 dmat2x4 dmat3 dmat3x2 dmat3x3 dmat3x4 dmat4 dmat4x2 dmat4x3 dmat4x4 double dvec2 dvec3 dvec4 float iimage1D iimage1DArray iimage2D iimage2DArray iimage2DMS iimage2DMSArray iimage2DRect iimage3D iimageBufferiimageCube iimageCubeArray image1D image1DArray image2D image2DArray image2DMS image2DMSArray image2DRect image3D imageBuffer imageCube imageCubeArray int isampler1D isampler1DArray isampler2D isampler2DArray isampler2DMS isampler2DMSArray isampler2DRect isampler3D isamplerBuffer isamplerCube isamplerCubeArray ivec2 ivec3 ivec4 mat2 mat2x2 mat2x3 mat2x4 mat3 mat3x2 mat3x3 mat3x4 mat4 mat4x2 mat4x3 mat4x4 sampler1D sampler1DArray sampler1DArrayShadow sampler1DShadow sampler2D sampler2DArray sampler2DArrayShadow sampler2DMS sampler2DMSArray sampler2DRect sampler2DRectShadow sampler2DShadow sampler3D samplerBuffer samplerCube samplerCubeArray samplerCubeArrayShadow samplerCubeShadow image1D uimage1DArray uimage2D uimage2DArray uimage2DMS uimage2DMSArray uimage2DRect uimage3D uimageBuffer uimageCube uimageCubeArray uint usampler1D usampler1DArray usampler2D usampler2DArray usampler2DMS usampler2DMSArray usampler2DRect usampler3D samplerBuffer usamplerCube usamplerCubeArray uvec2 uvec3 uvec4 vec2 vec3 vec4 void",built_in:"gl_MaxAtomicCounterBindings gl_MaxAtomicCounterBufferSize gl_MaxClipDistances gl_MaxClipPlanes gl_MaxCombinedAtomicCounterBuffers gl_MaxCombinedAtomicCounters gl_MaxCombinedImageUniforms gl_MaxCombinedImageUnitsAndFragmentOutputs gl_MaxCombinedTextureImageUnits gl_MaxComputeAtomicCounterBuffers gl_MaxComputeAtomicCounters gl_MaxComputeImageUniforms gl_MaxComputeTextureImageUnits gl_MaxComputeUniformComponents gl_MaxComputeWorkGroupCount gl_MaxComputeWorkGroupSize gl_MaxDrawBuffers gl_MaxFragmentAtomicCounterBuffers gl_MaxFragmentAtomicCounters gl_MaxFragmentImageUniforms gl_MaxFragmentInputComponents gl_MaxFragmentInputVectors gl_MaxFragmentUniformComponents gl_MaxFragmentUniformVectors gl_MaxGeometryAtomicCounterBuffers gl_MaxGeometryAtomicCounters gl_MaxGeometryImageUniforms gl_MaxGeometryInputComponents gl_MaxGeometryOutputComponents gl_MaxGeometryOutputVertices gl_MaxGeometryTextureImageUnits gl_MaxGeometryTotalOutputComponents gl_MaxGeometryUniformComponents gl_MaxGeometryVaryingComponents gl_MaxImageSamples gl_MaxImageUnits gl_MaxLights gl_MaxPatchVertices gl_MaxProgramTexelOffset gl_MaxTessControlAtomicCounterBuffers gl_MaxTessControlAtomicCounters gl_MaxTessControlImageUniforms gl_MaxTessControlInputComponents gl_MaxTessControlOutputComponents gl_MaxTessControlTextureImageUnits gl_MaxTessControlTotalOutputComponents gl_MaxTessControlUniformComponents gl_MaxTessEvaluationAtomicCounterBuffers gl_MaxTessEvaluationAtomicCounters gl_MaxTessEvaluationImageUniforms gl_MaxTessEvaluationInputComponents gl_MaxTessEvaluationOutputComponents gl_MaxTessEvaluationTextureImageUnits gl_MaxTessEvaluationUniformComponents gl_MaxTessGenLevel gl_MaxTessPatchComponents gl_MaxTextureCoords gl_MaxTextureImageUnits gl_MaxTextureUnits gl_MaxVaryingComponents gl_MaxVaryingFloats gl_MaxVaryingVectors gl_MaxVertexAtomicCounterBuffers gl_MaxVertexAtomicCounters gl_MaxVertexAttribs gl_MaxVertexImageUniforms gl_MaxVertexOutputComponents gl_MaxVertexOutputVectors gl_MaxVertexTextureImageUnits gl_MaxVertexUniformComponents gl_MaxVertexUniformVectors gl_MaxViewports gl_MinProgramTexelOffset gl_BackColor gl_BackLightModelProduct gl_BackLightProduct gl_BackMaterial gl_BackSecondaryColor gl_ClipDistance gl_ClipPlane gl_ClipVertex gl_Color gl_DepthRange gl_EyePlaneQ gl_EyePlaneR gl_EyePlaneS gl_EyePlaneT gl_Fog gl_FogCoord gl_FogFragCoord gl_FragColor gl_FragCoord gl_FragData gl_FragDepth gl_FrontColor gl_FrontFacing gl_FrontLightModelProduct gl_FrontLightProduct gl_FrontMaterial gl_FrontSecondaryColor gl_GlobalInvocationID gl_InstanceID gl_InvocationID gl_Layer gl_LightModel gl_LightSource gl_LocalInvocationID gl_LocalInvocationIndex gl_ModelViewMatrix gl_ModelViewMatrixInverse gl_ModelViewMatrixInverseTranspose gl_ModelViewMatrixTranspose gl_ModelViewProjectionMatrix gl_ModelViewProjectionMatrixInverse gl_ModelViewProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixTranspose gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_Normal gl_NormalMatrix gl_NormalScale gl_NumSamples gl_NumWorkGroups gl_ObjectPlaneQ gl_ObjectPlaneR gl_ObjectPlaneS gl_ObjectPlaneT gl_PatchVerticesIn gl_Point gl_PointCoord gl_PointSize gl_Position gl_PrimitiveID gl_PrimitiveIDIn gl_ProjectionMatrix gl_ProjectionMatrixInverse gl_ProjectionMatrixInverseTranspose gl_ProjectionMatrixTranspose gl_SampleID gl_SampleMask gl_SampleMaskIn gl_SamplePosition gl_SecondaryColor gl_TessCoord gl_TessLevelInner gl_TessLevelOuter gl_TexCoord gl_TextureEnvColor gl_TextureMatrix gl_TextureMatrixInverse gl_TextureMatrixInverseTranspose gl_TextureMatrixTranspose gl_Vertex gl_VertexID gl_ViewportIndex gl_WorkGroupID gl_WorkGroupSize gl_in gl_out EmitStreamVertex EmitVertex EndPrimitive EndStreamPrimitive abs acos acosh all any asin asinh atan atanh atomicAdd atomicAnd atomicCompSwap atomicCounter atomicCounterDecrement atomicCounterIncrement atomicExchange atomicMax atomicMin atomicOr atomicXor barrier bitCount bitfieldExtract bitfieldInsert bitfieldReverse ceil clamp cos cosh cross dFdx dFdy degrees determinant distance dot equal exp exp2 faceforward findLSB findMSB floatBitsToInt floatBitsToUint floor fma fract frexp ftransform fwidth greaterThan greaterThanEqual groupMemoryBarrier imageAtomicAdd imageAtomicAnd imageAtomicCompSwap imageAtomicExchange imageAtomicMax imageAtomicMin imageAtomicOr imageAtomicXor imageLoad imageSize imageStore imulExtended intBitsToFloat interpolateAtCentroid interpolateAtOffset interpolateAtSample inverse inversesqrt isinf isnan ldexp length lessThan lessThanEqual log log2 matrixCompMult max memoryBarrier memoryBarrierAtomicCounter memoryBarrierBuffer memoryBarrierImage memoryBarrierShared min mix mod modf noise1 noise2 noise3 noise4 normalize not notEqual outerProduct packDouble2x32 packHalf2x16 packSnorm2x16 packSnorm4x8 packUnorm2x16 packUnorm4x8 pow radians reflect refract round roundEven shadow1D shadow1DLod shadow1DProj shadow1DProjLod shadow2D shadow2DLod shadow2DProj shadow2DProjLod sign sin sinh smoothstep sqrt step tan tanh texelFetch texelFetchOffset texture texture1D texture1DLod texture1DProj texture1DProjLod texture2D texture2DLod texture2DProj texture2DProjLod texture3D texture3DLod texture3DProj texture3DProjLod textureCube textureCubeLod textureGather textureGatherOffset textureGatherOffsets textureGrad textureGradOffset textureLod textureLodOffset textureOffset textureProj textureProjGrad textureProjGradOffset textureProjLod textureProjLodOffset textureProjOffset textureQueryLevels textureQueryLod textureSize transpose trunc uaddCarry uintBitsToFloat umulExtended unpackDouble2x32 unpackHalf2x16 unpackSnorm2x16 unpackSnorm4x8 unpackUnorm2x16 unpackUnorm4x8 usubBorrow",literal:"true false"},i:'"',c:[e.CLCM,e.CBCM,e.CNM,{cN:"meta",b:"#",e:"$"}]}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:"^\\[.+\\]:",rB:!0,c:[{cN:"symbol",b:"\\[",e:"\\]:",eB:!0,eE:!0,starts:{cN:"link",e:"$"}}]}]}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0}]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[t],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}}); diff --git a/src/main.js b/src/main.js index 7257047..70ed519 100644 --- a/src/main.js +++ b/src/main.js @@ -137,12 +137,12 @@ function loadGlslElements() { for(var i = 0; i < ccList.length; i++){ if (ccList[i].hasAttribute("data")){ var srcFile = ccList[i].getAttribute("data"); - var editor = new GlslEditor(ccList[i], { - canvas_size: 250, + var editor = new GlslEditor(ccList[i], { + canvas_size: 250, canvas_follow: true, canvas_float: 'right', - tooltips: true, - exportIcon: true + tooltips: true, + exportIcon: true }); editor.open(srcFile); glslEditors.push(editor); @@ -154,15 +154,15 @@ function loadGlslElements() { for(var i = 0; i < sfList.length; i++){ if (sfList[i].hasAttribute("data")){ var srcFile = sfList[i].getAttribute("data"); - glslGraphs.push(new GlslEditor(sfList[i], { - canvas_width: 800, - lineNumbers: false, - canvas_height: 250, + glslGraphs.push(new GlslEditor(sfList[i], { + canvas_width: 800, + lineNumbers: false, + canvas_height: 250, canvas_follow: true, canvas_float: false, - frag_header: preFunction, - frag_footer: postFunction, - tooltips: true + frag_header: preFunction, + frag_footer: postFunction, + tooltips: true }).open(srcFile)); } } diff --git a/src/moon/moon.frag b/src/moon/moon.frag index 4943a82..11c7988 100644 --- a/src/moon/moon.frag +++ b/src/moon/moon.frag @@ -18,11 +18,11 @@ float speedMoon = 0.01; float speedSun = 0.25; vec3 sphereNormals(in vec2 uv) { - uv = fract(uv)*2.0-1.0; + uv = fract(uv)*2.0-1.0; vec3 ret; ret.xy = sqrt(uv * uv) * sign(uv); ret.z = sqrt(abs(1.0 - dot(ret.xy,ret.xy))); - ret = ret * 0.5 + 0.5; + ret = ret * 0.5 + 0.5; return mix(vec3(0.0), ret, smoothstep(1.0,0.98,dot(uv,uv)) ); } @@ -57,13 +57,13 @@ vec4 sphereTexture(in sampler2D _tex, in vec2 _uv) { void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(1.0); - + color *= sphereTexture(u_tex0, st).rgb; // Calculate sun direction vec3 sunPos = normalize(vec3(cos(u_time*speedSun-HALF_PI),0.0,sin(speedSun*u_time-HALF_PI))); vec3 surface = normalize(sphereNormals(st)*2.0-1.0); - + // Add Shadows color *= dot(sunPos,surface); @@ -74,4 +74,4 @@ void main(){ color = 1.0-color; gl_FragColor = vec4(color,1.0); -} \ No newline at end of file +}