Merge branch 'master' into translation-jp
@ -0,0 +1,50 @@
|
||||
# Introduzione
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="cmyk-halftone.frag" data-textures="vangogh.jpg" width="700px" height="320px"></canvas>
|
||||
|
||||
Le immagini qui sopra sono state realizzate in modi diversi. La prima è stata dipinta a mano da Van Gogh, aggiungendo strati di pittura uno dopo l'altro. Gli ci vollero ore. La seconda è stata prodotta in qualche secondo dalla combinazione di quattro matrici di pixel: una per il ciano, una per il magenta, una per il giallo e una per il nero. La differenza principale è che la seconda immagine è prodotta in modo non seriale (cioè non passo-passo, ma tutta allo stesso tempo).
|
||||
|
||||
Questo libro tratta della tecnica di calcolo rivoluzionario, i *fragment shaders*, che sta portando a un livello successivo le immagini generate digitalmente. Lo si può pensare come l'equivalente della stampa di Gutenberg per la grafica.
|
||||
|
||||
|
||||
![Stampa di Gutenberg](gutenpress.jpg)
|
||||
|
||||
I fragment shaders danno un controllo totale sui pixel, che sono resi sullo schermo a una super velocità. Questo è il motivo per cui sono utilizzati in molteplici applicazioni, dai filtri video sui cellulari ad incredibili videogiochi 3D.
|
||||
|
||||
![Journey di That Game Company](journey.jpg)
|
||||
|
||||
Nei capitoli seguenti scopriremo quanto veloce e potente sia questa tecnica e come poterla applicare al vostro lavoro professionale e personale.
|
||||
|
||||
## Per chi è questo libro?
|
||||
|
||||
Questo libro è scritto per programmatori creativi, sviluppatori di giochi e ingegneri che hanno esperienza di programmazione, una conoscenza di base di algebra lineare e di trigonometria, e che vogliono portare il loro lavoro ad un livello di qualità grafica ancora più emozionante. (Se si vuole imparare a programmare, vi raccomando di iniziare con [Processing](https://processing.org/) e tornare più tardi, quando avrete maggiore dimestichezza.)
|
||||
|
||||
Questo libro vi insegnerà come utilizzare e integrare shader nei vostri progetti, migliorando le loro prestazioni e la qualità grafica. Poiché gli GLSL (OpenGL Shading Language) shaders compilano e si eseguono su una grande varietà di piattaforme, si potrà applicare ciò che si impara qui a qualsiasi framework che utilizza OpenGL, OpenGL ES o WebGL. In altre parole, si sarà in grado di applicare e utilizzare la propria conoscenza negli sketches di [Processing](https://processing.org/), nelle applicazioni di [openFrameworks](http://openframeworks.cc/), nelle installazioni interattive di [Cinder](http://libcinder.org/), nei siti web con [Three.js](http://threejs.org/) o nei giochi iOS / Android.
|
||||
|
||||
|
||||
## Di che cosa tratta questo libro?
|
||||
|
||||
Questo libro si concentrerà su l'uso dei pixel shaders GLSL. Per prima cosa definiremo cosa sono gli shaders; poi impareremo come fare, grazie a loro, forme procedurali, motivi, texture e animazioni. Imparerete le basi del linguaggio shading ed ad applicarlo a scenari più utili, quali: l'elaborazione di immagini (operazioni di immagine, circonvoluzioni di matrice, sfocature, filtri colorati, tabelle di associazione e altri effetti) e simulazioni (il gioco della vita di Conway, la reazione-diffusione di Gray-Scott, le increspature d'acqua, gli effetti acquerello, le celle di Voronoi, etc.). Verso la fine del libro vedremo un insieme di tecniche avanzate basate sul Ray Marching.
|
||||
|
||||
*In ogni capitolo, ci sono degli esempi interattivi per imparare divertendosi. * Quando si modifica il codice, vedrete immediatamente sullo schermo i cambiamenti. I concetti possono essere astratti e confusi, perciò gli esempi interattivi sono essenziali per aiutarvi a capire gli argomenti trattati. Più velocemente i concetti si mettono in pratica e più facilmente si imparerà.
|
||||
|
||||
Di cosa non tratta questo libro:
|
||||
|
||||
* Questo * non è * un libro su OpenGL o WebGL. OpenGL / WebGL è un soggetto più vasto di GLSL o dei fragment shaders. Per ulteriori informazioni su OpenGL / WebGL vi consiglio di dare un'occhiata a: [OpenGL Introduzione](https://open.gl/introduction), [l'ottava edizione della guida sulla programmazione OpenGL](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) (noto anche come il libro rosso) o [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).
|
||||
|
||||
* Questo * non è* un libro di matematica. Anche se ci occuperemo di una serie di algoritmi e di tecniche che si basano su una comprensione dell'algebra e della trigonometria, non spiegheremo tutto in dettaglio. Per domande riguardanti la matematica vi consiglio di tenere vicino uno dei seguenti libri: [La terza edizione di Matematica per la programmazione di giochi 3D e la computer Grafica](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) o [La seconda edizione di Matematica Essenziale per Giochi e Applicazioni Interattive](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).
|
||||
|
||||
## Cosa ti serve per iniziare?
|
||||
|
||||
Non tanto! Se si dispone di un browser moderno che può far girare WebGL (come Chrome, Firefox o Safari) e una connessione Internet, fai clic sul bottone "Next" alla fine di questa pagina per iniziare.
|
||||
|
||||
In alternativa, in base a ciò di cui avete bisogno, è possibile:
|
||||
|
||||
- [Creare versione offline di questo libro](https://thebookofshaders.com/appendix/)
|
||||
|
||||
- [Eseguire gli esempi su un Raspberry Pi senza navigatore](https://thebookofshaders.com/appendix/)
|
||||
|
||||
- [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.
|
||||
|
@ -0,0 +1 @@
|
||||
# Introduction
|
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 338 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
@ -0,0 +1,84 @@
|
||||
# bien démarrer
|
||||
## qu'est-ce qu'un fragment shader?
|
||||
|
||||
Au chapitre précédent, nous avons décrit les shaders comme l'équivalent de l'avènement de la presse par Gutenberg pour l'impression. Pourquoi cette comparaison mais surtout: Qu'est-ce qu'un shader?
|
||||
|
||||
![de la copie manuelle, lettre à lettre, à l'édition page à page (gauche: William Blades 1891, droite: Rolt-Wheeler 1920)](print.png)
|
||||
|
||||
Si vous avez déjà dessiné avec un ordinateur, vous savez qu'il faut dessiner un cercle, puis un rectangle, une ligne, quelques triangles jusqu'à pouvoir composer l'image qu'on veut.
|
||||
Ce processus est très similaire à l'écriture d'une lettre ou d'un livre voire à la peinture, c'est un ensemble d'instructions, exécutées en série, l'une après l'autre.
|
||||
|
||||
Les shaders sont également des ensembles d'instructions, mais à la différence des API de dessin classiques, *toutes les instructions sont exécutées sur chaque pixel de l'écran*.
|
||||
Cela signifie que le code va devoir se comporter différemment selon la position du pixel à l'écran.
|
||||
Comme la presse d'imprimerie, le fragment shader est une fonction à laquelle on passe une position et qui nous renvoie une couleur.
|
||||
Une fois _compilé_, ce programme peut s'exécuter extrêmement rapidement.
|
||||
|
||||
|
||||
![presse chinoise à caractères amovibles](typepress.jpg)
|
||||
|
||||
## Pourquoi sont-ils si rapides?
|
||||
|
||||
La réponse est le *traitement parallèle*.
|
||||
|
||||
Imaginez le CPU de votre ordinateur comme un *tuyau* et chacune des tâches que vous lui demandez d'exécuter comme *quelque chose* qui passe par ce tuyau, comme dans une usine.
|
||||
Certaines tâches seront sans doute plus importantes que d'autres, elles demanderont plus de temps et d'énergie pour être traitées, on dit qu'elles nécessitent plus de ressources ou de puissance de calcul.
|
||||
Du fait de l'architecture des ordinateurs, les tâches sont traitées en série ; chaque tâche doit être terminée avant que le CPU puisse traiter la suivante.
|
||||
Les ordinateurs récents ont généralement plusieurs processeurs qui jouent le rôle de *tuyaux*, ce qui permet d'enchaîner les tâches en série tout en gardant une certaines fluidité, ces tuyaux s'appellent des *threads*.
|
||||
|
||||
![CPU](00.jpeg)
|
||||
|
||||
Les jeux vidéos et autres applications graphiques demandent beaucoup plus de puissance de calcul que les autres programmes.
|
||||
Par nature, ils demandent de grandes quantités d'opérations au pixel, chaque changement d'image demandent de recalculer l'ensemble des pixels de l'écran.
|
||||
Dans les applications 3D, on doit également mettre à jour les modèles, les textures, les transformations etc. ce qui rajoute encore du poids à la charge CPU.
|
||||
|
||||
Revenons à notre métaphore des tuyaux et des tâches où:*"trouver la couleur d'un pixel à l'écran"* représente une petite tâche toute simple.
|
||||
En soi, chaque tâche n'est pas bien méchante mais il faut l'appliquer sur chaque pixel de l'écran! et c'est là que ça se corse ; il nous faut à présent exécuter cette petite opération un nombre considérable de fois.
|
||||
Par exemple pour exécuter l'ensemble des tâches permettant de dessiner l'ensemble des pixels d'un vieux moniteur ayant une résolution de 800 x 600 pixels, il faut compter 800 x 600 = 480.000 appels à cette petite tâche.
|
||||
Ces 480.000 appels ne valent que pour dessiner une seule frame, si on veut animer notre écran à 30 images/seconde pendant une seconde, il nous en coûtera 11.520.000 appels et si on veut du 60fps, on passe à 28.800.000 de tâches à traiter.
|
||||
|
||||
Peut-être que le problème est plus facile à identifier lorsqu'on commence à parler de dizaines de millions d'opérations/seconde, si on prend une configuration moderne, 2880/1800 pixels devant tourner à 60 fps, on atteint 311.040.000 calculs / seconde.
|
||||
des centaines de millions d'opérations par seconde, ce sont des quantités propres à freezer voire à détruire un microprocesseur. alors comment fait-on?
|
||||
|
||||
|
||||
![](03.jpeg)
|
||||
|
||||
C'est là qu'intervient le traitement parallèle (parallel processing).
|
||||
Au lieu d'avoir quelques gros *tuyaux* (microprocesseurs), on préfère avoir de nombreux petits microprocesseurs qui tournent en parallèle et simultanément, c'est l'essence du GPU: Graphics Processing Unit.
|
||||
|
||||
![GPU](04.jpeg)
|
||||
|
||||
Imaginez ces petits microprocesseurs comme une trame de tuyaux, et les données de chaque pixel comme des balles de pingpong.
|
||||
14.400.000 balles de pingpong par secondes pourraient boucher à peu près n'importe quel tuyau.
|
||||
Mais une trame de 800 * 600 (480.000) petits tuyaux recevant 30 vagues de 480.000 balles de pingpong par secondes peuvent traiter la charge facilement.
|
||||
Et ça marche pour des résolutions plus élevées ; plus le matériel est capable de traiter d'informations en parallèle, plus il pourra traiter des flux importants.
|
||||
|
||||
Un autre pouvoir magique des GPU c'est l'accélération matérielle de certaines fonctions mathématiques.
|
||||
Certaines fonctions souvent un peu complexes seront traitées directement par le matériel au lieu de passer par la couche logicielle.
|
||||
Ce qui signifie que certaines opérations mathématiques un peu complexes comme les transformations de matrics et les opérations trigonométriques seront traitées très vite, en fait, à la vitesse de l'électricité.
|
||||
|
||||
## qu'est ce que le GLSL?
|
||||
|
||||
GLSL est l'acronyme de 'openGL Shading Language' (où GL signifie Graphics Library), c'est une norme servant à écrire les programmes de shaders que nous aborderons dans les chapitres suivants.
|
||||
Il existe d'autres types de shaders, selon les plateformes et le matériel utilisé, nous nous concentrerons sur l'OpenGL, dont les spécifications sont faites par le [Khronos Group](https://www.khronos.org/opengl/).
|
||||
|
||||
Comprendre l'histoire d'OpenGL peut être utile pour comprendre certaines conventions un peu bizarres, si ça vous intéresse, vous pouvez vous reporter à [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html).
|
||||
|
||||
## Pourquoi les gens tremblent en entendant le mot Shader?
|
||||
|
||||
Comme dit *Uncle Ben* dans Spiderman: "with great power comes great responsibility" ([merci à Nicolas Gans](https://en.m.wikipedia.org/wiki/Uncle_Ben)), le traitement parallèle ne déroge pas à cette règle et aussi puissante que soit la programmation GPU, elle apporte un cortège de contraintes et de restrictions.
|
||||
|
||||
Pour pouvoir travailler avec une *trame* de *threads*, il faut que chaque thread soit indépendant des autres. On dit que le thread est *aveugle* à ce que font les autres threads.
|
||||
Cette restriction implique que toutes les données doivent aller dans le même sens, il est donc impossible de se servir ou simplement de connaître les résultat d'un autre thread.
|
||||
Autoriser la communication entre threads au moment de l'exécution pourrait compromettre l'intégrité des données en cours de traitement.
|
||||
|
||||
Il faut également savoir que le GPU s'assure que tous ses microprocesseurs (la *trame de threads*) sont actifs en permanence ; dès qu'un thread a fini son traitement, le GPU lui ré-assigne une tâche à traiter.
|
||||
Le thread ne garde aucune trace de ce qu'il faisait la fois précédente ; s'il était en train de dessiner un le pixel d'un bouton sur une interface graphique, sa tâche suivante pourra être de rendre un bout du ciel dans un jeu, puis de rendre un bout de texte sur un client mail etc.
|
||||
Donc un thread est non seulement **aveugle** mais aussi **amnésique**
|
||||
|
||||
En plus du niveau d'abstraction élevé requis pour coder une fonction générique qui saura rendre une image entière uniquement à partir de la variation d'une position, les deux contraintes des threads, **aveuglement** et **amnésie** rendent la programmation de shaders assez impopulaire auprès des programmeurs débutants.
|
||||
|
||||
Mais n'ayez crainte! au cours des chapitres suivants, nous abordons les problèmes étape par étape et passerons d'un simple shader à des calculs avancés.
|
||||
Si vous lisez ceci dans un navigateur récent, vous apprécierez de pouvoir manipuler les exemples interactifs et beaucoup de ce qui vient d'être dit s'éclairera de soi même.
|
||||
Sans plus attendre, jetons nous dans le vif du sujet.
|
||||
|
||||
appuyez sur *Next >>* pour commencer!
|
@ -0,0 +1,48 @@
|
||||
# Introduzione
|
||||
## Che cosa è un fragment shader?
|
||||
|
||||
Nel capitolo precedente abbiamo descritto lo shader come l'equivalente della stampa di Gutenberg per la grafica. Perché? O meglio ancora: che cosa è uno shader?
|
||||
|
||||
![From Letter-by-Letter, Right: William Blades (1891). To Page-by-page, Left: Rolt-Wheeler (1920).](print.png)
|
||||
|
||||
Se hai già fatto disegni al computer, saprai che si inizia disegnando un cerchio, poi un rettangolo, una linea, alcuni triangoli fino a comporre l'immagine desiderata. Questo processo è molto simile a scrivere una lettera o un libro a mano - in altre parole è un insieme di istruzioni, che eseguono un compito uno dopo l'altro.
|
||||
|
||||
Gli shaders si possono considerare allo stesso modo un insieme di istruzioni, che sono eseguite tutte nello stesso momento per ogni singolo pixel sullo schermo. Ciò significa che il codice scritto deve comportarsi in modo diverso a seconda della posizione del pixel sullo schermo. Come nel processo della pressa tipografica, il tuo programma riceverà una posizione e restituirà un colore. Quando il codice è compilato, verrà eseguito a velocità straordinaria.
|
||||
|
||||
![Pressa tipografica cinese](typepress.jpg)
|
||||
|
||||
## Perché gli shaders sono così veloci?
|
||||
|
||||
Per rispondere a questa domanda, vi presento le meraviglie del *calcolo parallelo*.
|
||||
|
||||
Immaginate la CPU del computer come un grande tubo industriale, e ogni compito come qualcosa che passa attraverso di esso - come in una linea di produzione. Alcuni compiti sono più grandi di altri, il che significa che richiedono più tempo ed energia. Diciamo che necessitano una maggiore potenza di elaborazione. A causa dell'architettura dei computer alcuni compiti sono costretti ad essere eseguiti in serie; ogni compito deve essere completato, uno dopo l'altro. I computer moderni hanno solitamente gruppi di quattro processori che funzionano come questi tubi, eseguendo i compiti uno dopo l'altro per avere le cose funzionanti senza intoppi. Ogni tubo è anche conosciuto come *thread*.
|
||||
|
||||
![CPU](00.jpeg)
|
||||
|
||||
I videogiochi e le altre applicazioni grafiche richiedono molta più potenza di elaborazione rispetto ad altri programmi. A causa del loro contenuto grafico devono fare un gran numero di operazioni per pixel. Ogni singolo pixel sullo schermo deve essere calcolato, e nei giochi 3D le geometrie e le prospettive devono essere calcolate allo stesso tempo.
|
||||
|
||||
Torniamo alla nostra metafora dei tubi e dei compiti. Ogni pixel sullo schermo rappresenta un piccolo compito da realizzare. Individualmente ogni compito non è un problema per la CPU, ma (e qui sta il problema) il piccolo compito deve essere fatto per ogni pixel sullo schermo! Ciò significa che in un vecchio schermo 800x600, 480000 pixel devono elaborati per frame cioè 14400000 calcoli al secondo! Si! Questo è un problema abbastanza grande capace di sovraccaricare un microprocessore. In un moderno schermo retina 2880x1800 in esecuzione a 60 fotogrammi al secondo si possono raggiungere fino a 311040000 calcoli al secondo. Come fanno gli ingegneri grafici a risolvere questo problema?
|
||||
|
||||
![](03.jpeg)
|
||||
|
||||
E' in questo caso che il calcolo parallelo diventa una buona soluzione. Invece di avere un paio di grandi e potenti microprocessori, o *tubi*, è più intelligente avere parecchi minuscoli microprocessori che funzionano in parallelo allo stesso tempo. Questo è la Graphic Processor Unit (GPU).
|
||||
|
||||
![GPU](04.jpeg)
|
||||
|
||||
Immaginate i minuscoli microprocessori come un tavolo di tubi, ed i dati di ciascun pixel come una pallina da ping pong. 14400000 palline da ping pong in un secondo possono ostacolare qualsiasi tubo. Ma un tavolo di 800x600 piccoli tubi che riceve 30 ondate di 480000 pixel al secondo si può gestire senza problemi. Tutto ciò funziona anche a risoluzioni più elevate - più si possiede hardware in parallelo, più grande è il flusso che si può gestire.
|
||||
|
||||
Un altro "super potere" della GPU è che alcune speciali funzioni matematiche sono accelerate via hardware, in modo tale che le operazioni matematiche complesse sono risolte direttamente dai microchip invece che da un software. Ciò significa che avremo una velocità extra nel calcolo trigonometrico e nelle operazioni fra matrici, una velocità pari a quella dell'elettricità.
|
||||
|
||||
## Che cosa è GLSL?
|
||||
|
||||
GLSL è l'acronimo di openGL Shading Language, che è lo standard specifico dei programmi shaders che vedrete nei prossimi capitoli. Ci sono altri tipi di shaders a seconda del hardware e dei sistemi operativi. Qui lavoreremo con le specifiche openGL regolate dal [Khronos Group](https://www.khronos.org/opengl/). Comprendere la storia di OpenGL può essere utile per capire la maggior parte delle sue strane convenzioni, per questo vi consiglio di dare un'occhiata a: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html)
|
||||
|
||||
## Perché gli Shaders hanno notoriamente una brutta fama?
|
||||
|
||||
Come disse lo zio Ben "con un grande potere derivano grandi responsabilità", e il calcolo parallelo segue questa regola; la potente progettazione architettonica della GPU comporta specifici vincoli e restrizioni.
|
||||
|
||||
Affinché ogni tubo, o thread, venga eseguito in parallelo, è necessario che sia indipendente l'uno dall'altro. Diciamo i thread sono *ciechi* e non vedono ciò che gli altri thread stanno facendo. Questa restrizione implica che tutti i dati debbano affluire nella stessa direzione. Quindi è impossibile controllare il risultato di un altro thread, modificare i dati di input, o passare il risultato di un thread a un altro thread. Permettere la comunicazione fra thread metterebbe a rischio l'integrità dei dati.
|
||||
|
||||
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!
|
@ -0,0 +1,2 @@
|
||||
# Getting started
|
||||
## What is a fragment shader?
|
@ -1,3 +1,8 @@
|
||||
### Scott M
|
||||
|
||||
* You say “pipes” and also “threads”. This is a small thing but I wonder if you can reconcile those metaphors. I think in terms of threads, but “pipes” makes more sense with your illustration. Also works better with the concept of a “pipeline” or “graphics/rendering pipeline”.
|
||||
* You say “pipes” and also “threads”. This is a small thing but I wonder if you can reconcile those metaphors. I think in terms of threads, but “pipes” makes more sense with your illustration. Also works better with the concept of a “pipeline” or “graphics/rendering pipeline”.
|
||||
|
||||
### 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).
|
@ -0,0 +1,82 @@
|
||||
## Hello World
|
||||
|
||||
Généralement le "Hello World" est la première étape dans l'apprentissage d'un nouveau langage.
|
||||
C'est un programme court qui renvoie un message enthousiaste et fait miroiter un avenir radieux.
|
||||
|
||||
Au pays du GPU, rendre du texte est une tâche extrêmement complexe (et un champ de recherche très actif NDT) donc au lieu d'un message texte, nous allons choisir une couleur chatoyante pour déchaîner notre enthousiasme!
|
||||
|
||||
<div class="codeAndCanvas" data="hello_world.frag"></div>
|
||||
|
||||
Si vous lisez ceci dans un navigateur récent, le bloc précédent est interactif.
|
||||
Cela signifie que vous pouvez cliquer et éditer le code. Les changements seront pris en compte immédiatement, recompilés et si le shader est valide, il sera remplacé *à la volée*.
|
||||
Vous pouvez essayer de changer les chiffres de la ligne 6.
|
||||
|
||||
Si ce program paraît simple, nous pouvons déjà faire quelques observations intéressantes:
|
||||
|
||||
1. ça ressemble à du C, un shader possède une fonction ```main``` dont le seul but est d'assigner une couleur.
|
||||
|
||||
2. la couleur du pixel est assignée à une variable globale (réservée) ```gl_FragColor```.
|
||||
|
||||
3. ce langage aux allures de C, possède des *variables* (comme ```gl_FragColor```), des *fonctions* et des *types*.
|
||||
dans l'exemple, nous venons de voir le type ```vec4``` qui représente un vecteur de chiffres (des floats) à 4 dimensions. plus tard nous verrons d'autres types comme: ```vec3``` & ```vec2``` et d'autres plus fréquents comme: ```float```, ```int``` & ```bool```.
|
||||
|
||||
4. si l'on regarde ```vec4``` de plus près, on peut déduire que les 4 arguments correspondent aux 4 canaux: RED, GREEN, BLUE & ALPHA du pixel.
|
||||
On note également que les valeurs sont *normalisées*, ce qui signifie qu'elles vont de ```0.0``` à ```1.0```.
|
||||
plus tard nous verrons pourquoi c'est intéressant de manipuler des valeurs normalisées et comment *mapper* des valeurs entre elles.
|
||||
|
||||
5. une autre remarque importante est la présence de *macros de pré-traitement*
|
||||
les macros font partie de l'étape de précompilation, elles permettent de définir (```#define```) des variables globales et de faire des opérations conditionnelles de base ( avec ```#ifdef``` & ```#endif```).
|
||||
toutes les macros commencent par un hashtag (```#```).
|
||||
la précompilation se produit - comme son nom l'indique - avant la compilation du shader, elle copie et renseigne tous les ```#define``` et vérifie si les ```#ifdef``` sont définis et si les ```#ifndef``` ne sont pas définis.
|
||||
dans l'exemple ci-dessus, ligne 1, nous vérifions uniquement si ```GL_ES``` est défini, ce qui se produit principalement lorsque le code est compilé sur mobile ou dans un navigateur.
|
||||
|
||||
6. le type Float est vital dans les shaders, donc le niveau de *précision* des Float est crucial.
|
||||
une précision basse permet un rendu plus rapide mais une qualité moindre et inversement, une précision élevée permet un meilleur rendu au prix de performances réduites.
|
||||
on peut spécifier la précision de chaque variable se servant des Float, ligne 2 (```precision mediump float;```), nous assignons la précision *medium* à tous les floats de l'application.
|
||||
nous pourrions leur donner une valeur *low* (```precision lowp float;```) ou *high* (```precision highp float;```).
|
||||
|
||||
7. la dernière remarque, probablement la plus importante, est que les spécifications GLSL ne garantissent pas que les variables seront *castées* automatiquement.
|
||||
qu'est-ce que cela veut dire? si les fabricants ont des approches différentes pour accélérer leurs cartes graphiques, ils doivent toutefois se conformer à un ensemble de spécifications communes pour être utilisable par le plus grand nombre.
|
||||
le casting automatique des variables ne fait pas partie des spécifications.
|
||||
Dans notre exemple, ```vec4``` attend des ```floats``` et rien d'autre. si vous voulez obtenir un code homogène et éviter de passer des heures à débugger un écran blanc, prenez l'habitude de mettre des points ( ```.``` ) dans vos floats.
|
||||
ce genre de code ne marchera pas toujours:
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
gl_FragColor = vec4(1,0,0,1); // ERROR
|
||||
}
|
||||
```
|
||||
alors que celui ci à de plus grandes chances de marcher:
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
gl_FragColor = vec4( 1., .0, 0., 1. ); // BETTER
|
||||
}
|
||||
```
|
||||
notez que le point peut être placé avant ou après un *0*.
|
||||
|
||||
|
||||
Maintentant que nous avons passé en revue quelques éléments importants du programme "hello world!", il est temps de clicker sur le bloc de code et de mettre en application ce que nous venons d'apprendre.
|
||||
Vous remarquerez que le programme ne se recompilera pas tant qu'il restera des erreurs. voici quelques idées intéressantes à tester:
|
||||
|
||||
* essayez de remplacer les *float* par des *int* la carte graphique vous autorisera ou non à le faire.
|
||||
|
||||
* essayez de commenter ( ```//``` ) la ligne 6 ce qui n'assignera aucune valeur au pixel.
|
||||
|
||||
* essayez de créer une fonction qui retourne une couleur en dehors de ```main()``` et essayez de l'utiliser pour assigner la valeur de ```gl_FragColor``` dans ```main()```.
|
||||
pour vous aider, voici le code d'une fonction qui retourne une ```vec4``` de couleur rouge:
|
||||
|
||||
```glsl
|
||||
vec4 red(){
|
||||
return vec4(1.0,0.0,0.0,1.0);
|
||||
}
|
||||
```
|
||||
|
||||
* on peut construire un ```vec4``` de plusieurs façons, essayez de découvrir d'autres manières'. par exemple:
|
||||
|
||||
```glsl
|
||||
vec4 color = vec4(vec3(1.0,0.0,1.0),1.0);
|
||||
```
|
||||
|
||||
Bien que cet exemple ne soit pas très excitant, c'est le plus basique qui soit ; nous donnons à l'ensemble des pixels de l'image la même couleur.
|
||||
Dans le chapitre suivant, nous verrons comment changer cette couleur en fonction de 2 facteurs: l'espace (l'emplacement du pixel à l'écran) et le temps (le nombre de secondes écoulées depuis le chargement de la page).
|
@ -0,0 +1,54 @@
|
||||
## Ciao Mondo
|
||||
|
||||
Di solito l'esempio "Ciao Mondo!" è il primo passo per imparare un nuovo linguaggio. Si tratta di un semplice programma di una riga che visualizza un messaggio entusiastico di benvenuto.
|
||||
|
||||
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!
|
||||
|
||||
<div class="codeAndCanvas" data="hello_world.frag"></div>
|
||||
|
||||
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:
|
||||
|
||||
1. Gli Shaders hanno una unica funzione ```main``` che alla fine restituisce un colore. Questa caratteristica è molto simile al linguaggio C.
|
||||
|
||||
2. Il colore finale dei pixel viene assegnato a una variabile globale riservata ```gl_FragColor```.
|
||||
|
||||
3. Questo linguaggio è simile al C e ha *variabili* built-in (come ```gl_FragColor```), *funzioni* e *tipi*. In questo esempio abbiamo introdotto ```vec4``` che è un vettore a virgola mobile(float) di quattro dimensioni. Più avanti incontreremo altri tipi come ```vec3``` e ```vec2``` insieme ai più popolari: ```float```, ```int``` e ```bool```.
|
||||
|
||||
4. Se analizziamo il tipo ```vec4``` possiamo dedurre che i quattro argomenti corrispondono ai canali ROSSO, VERDE, BLU e ALFA. Inoltre possiamo notare che questi valori sono *normalizzati*, il che significa che vanno da ```0.0``` a ```1.0```. In seguito, impareremo che normalizzare i valori rendere più facile *mapparli* fra le variabili.
|
||||
|
||||
5. Un'altra importante *caratteristica del C* che si può vedere in questo esempio è la presenza di macro del preprocessore. Le macro sono parte di una fase di pre-compilazione. Con loro è possibile ```#define``` variabili globali e fare alcune funzioni condizionali di base (con ```#ifdef``` e ```#endif```). Tutti i comandi macro iniziano con un hashtag (```#```). La pre-compilazione avviene appena prima di compilare lo shader e copia tutte le chiamate a ```#defines``` e verifica ```#ifdef``` (è definito) e ```#ifndef``` (non è definito) nel caso di chiamate condizionali . Nel nostro esempio precedente "Ciao mondo!", abbiamo inserito solo la linea 2 per verificare se ```GL_ES``` è definito, chiamata che avviene soprattutto quando il codice viene compilato su dispositivi mobili e browser.
|
||||
|
||||
6. I tipi float sono vitali negli shader, dove il livello di *precisione* è fondamentale. Precisione inferiore significa resa più veloce, ma a scapito della qualità. Si può essere pignoli e specificare la precisione di ogni variabile che utilizza la virgola mobile. Nella prima riga (```precision mediump float;```) stiamo definendo tutti i float a media precisione. Ma possiamo impostare la loro precisione a un livello basso (```precision lowp float;```) o alto (```precision highp float;```).
|
||||
|
||||
7. L'ultimo, e forse più importante, dettaglio è che le specifiche GLSL non garantiscono che le variabili siano convertite automaticamente. Cosa significa? I produttori delle carte grafiche hanno differenti approcci per accelerare i processi delle carte grafiche, ma sono costretti a garantire delle specifiche minime. La conversione automatica non è una di queste. Nel nostro esempio "Ciao mondo", ```vec4``` ha precisione in virgola mobile e per questo ci si aspetta dei ```floats```. Se si vuole realizzare un codice omogeneo e non passare ore a fare il debug di schermi bianchi, abituatevi a mettere il punto ( ```.``` ) all'interno dei vostri float. Questo tipo di codice non funziona sempre:
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
gl_FragColor = vec4(1,0,0,1); // ERRORE
|
||||
}
|
||||
```
|
||||
|
||||
Ora che abbiamo descritto gli elementi più rilevanti del nostro programma "ciao mondo!", è il momento di cliccare sul blocco di codice e iniziare a mettere alla prova tutto quello che abbiamo imparato. Noterete che in caso di errore, il programma non sarà in grado di compilare e mostrerà uno schermo bianco. Ci sono alcune cose interessanti da provare, per esempio:
|
||||
|
||||
* Provate a sostituire i float con degli integer, la vostra scheda grafica potrebbe o non accettare questo comportamento.
|
||||
|
||||
* Commentate la linea 6 e non assegnate alcun valore ai pixel della funzione.
|
||||
|
||||
* Provate a fare una funzione separata che restituisce un colore specifico e utilizzarla all'interno del ```main()```. Piccolo suggerimento, ecco il codice per una funzione che restituisce un colore rosso:
|
||||
|
||||
```glsl
|
||||
vec4 red(){
|
||||
return vec4(1.0,0.0,0.0,1.0);
|
||||
}
|
||||
```
|
||||
|
||||
* Ci sono diversi modi per costruire dei tipi ```vec4```, prova a scoprire gli altri modi. Per esempio:
|
||||
|
||||
|
||||
```glsl
|
||||
vec4 color = vec4(vec3(1.0,0.0,1.0),1.0);
|
||||
```
|
||||
|
||||
Anche se questo esempio non è molto eccitante, è il più elementare possibile - stiamo cambiando tutti i pixel all'interno del canvas con il medesimo colore. Nel prossimo capitolo vedremo come cambiare i colori dei pixel utilizzando due tipi di input: spazio (cioè la posizione dei pixel sullo schermo) e il tempo (cioè il numero di secondi da quando la pagina è stata caricata).
|
@ -0,0 +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!
|
@ -0,0 +1 @@
|
||||
## Hello World
|
@ -0,0 +1,95 @@
|
||||
## Uniforms
|
||||
|
||||
Jusqu'à présent, nous avons vu comment le GPU gère un ensemble de threads parallèles dont le but est d'assigner la couleur d'une partie de l'image finale.
|
||||
Bien que chaque thread soit *aveugle*, nous devons être capables de passer certaines valeurs depuis le CPU vers le GPU et les threads en question.
|
||||
Du fait de l'architecture des cartes graphiques, ces valeurs vont devoir être également ( ou *uniform*-ément ) distribuées sur tous les threads et - comme décrit au chapitre 1 - utilisées en *lecture seule*.
|
||||
Autrement dit, _tous les threads reçoivent les mêmes données, chacun peut les lire mais pas les modifier_.
|
||||
|
||||
Ces données s'appellent des ```uniform``` et peuvent prendre les types suivants: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` & ```samplerCube```.
|
||||
Les uniforms se définissent généralement en haut du shader, juste après avoir défini la précision des floats (et autres macros de prétraitement ).
|
||||
|
||||
```glsl
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution; // taille du Canvas (x:largeur en pixels, y:hauteur en pixels)
|
||||
uniform vec2 u_mouse; // position de la souris (x,y) sur le canvas en pixels
|
||||
uniform float u_time; // temps écoulé depuis le lancement du shader
|
||||
```
|
||||
|
||||
On peut se représenter les uniforms comme de petits ponts à sens unique allant du CPU (notre programme principal) au GPU (là où sera exécuté le shader).
|
||||
Les noms peuvent varier selon les implémentations et les plateformes mais dans les exemples suivants, nous utiliserons toujours: ```u_time``` (le temps écoulé depuis le lancement du shader),
|
||||
```u_resolution``` (la taille du canvas sur lequel le shader est exécuté) & ```u_mouse``` (la position de la souris à l'intérieur du canvas).
|
||||
Le fait de préfixer les noms des uniforms par ```u_``` est une convention de nommage assez répandue, ça permet de reconnaître facilement le type de cette varibale mais ce n'est pas une obligation.
|
||||
|
||||
Par exemple [ShaderToy.com](https://www.shadertoy.com/) utilise les mêmes uniforms avec les noms suivants:
|
||||
|
||||
```glsl
|
||||
uniform vec3 iResolution; // taille du canvas (en pixels)
|
||||
uniform vec4 iMouse; // position de la souris. xy: courant, zw: au click
|
||||
uniform float iGlobalTime; // temps écoulé depuis le lancement du shader (en secondes)
|
||||
```
|
||||
|
||||
Notez qu'ils utilisent un ```i``` au lieu de notre ```u_```.
|
||||
|
||||
Assez parlé, voyons ce que les uiforms peuvent faire.
|
||||
dans l'exemple suivant, nous utilisons l'uniform la valeurs absolue ( ```abs( valeur )```) d'une fonction de sinus (```sin( valeur )```) qui prend ```u_time``` - le temps écoulé depuis le lancement du shader - comme argument pour animer la quantité de rouge que nous dessinons sur le canvas.
|
||||
|
||||
la fonction de sinus attend un angle comme argument, en utilisant le temps (valeur qui ne cesse de croître), on obtient une valeur qui va osciller infiniment entre ```-1.``` et ```1.```.
|
||||
la valeur *absolue* d'une fonction de sinus sera quant à elle toujours comprise entre ```0.``` et ```1.``` donc notre valeur de rouge oscillera entre ```0.``` et ```1.```.
|
||||
|
||||
<div class="codeAndCanvas" data="time.frag"></div>
|
||||
|
||||
On peut constater que ça va vite (par rapport au même traitement sur le CPU), cela vient de l'*accélération matérielle*.
|
||||
En effet, au chapitre 1 nous avons vu que les GPU implémentent parfois l'accélération *matérielle* de certaines opérations, certaines fonctions trigonométriques telles que:
|
||||
[```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) & [```clamp()```](../glossary/?search=clamp),
|
||||
sont donc exécutées _matériellement_ et peuvent aller très (très) vite.
|
||||
|
||||
Essayons de jouer avec le code ci dessus.
|
||||
|
||||
* Ralentissez la fréquence jusqu'à ce que le changement de couleur deviennent imperceptible.
|
||||
|
||||
* Accélérez la fréquence jusqu'à voir une couleur unique sans clignotement.
|
||||
|
||||
* donnez des fréquences différentes aux trois canaux (RGB) pour obtenir des motifs et des comportements intéressants.
|
||||
|
||||
## gl_FragCoord
|
||||
|
||||
De la même manière que la fonction main() du shader expose la variable de sortie: ```vec4 gl_FragColor```, elle nous donne accès à une variable d'entrée ```vec4 gl_FragCoord```
|
||||
qui contient les coordonnées à l'écran du *pixel*.
|
||||
ce *pixel* s'appelle en fait un *screen fragment*, qui donne son nom au *fragment shader*.
|
||||
le *screen fragment* ou plus simplement *fragment* est le _pixel en train d'être traité par le thread_.
|
||||
|
||||
la variable ```vec4 gl_FragCoord```, nous donne donc accès à l'emplacement _physique_ (à l'écran) du pixel sur lequel le thread est en train de travailler.
|
||||
cette variable n'est pas une *uniform* puisqu'elle ne conserve pas la même valeur d'un thread à l'autre, chaque pixel ayant par définition des coordonnées uniques.
|
||||
|
||||
la variable ```gl_FragCoord``` s'appelle *varying* puisqu'elle va *varier* d'un thread sur l'autre, c'est la seconde _famille_ de variables qu'on peut utiliser dans un shader.
|
||||
cette variable est déclarée *implicitement* dans les _vertex-shader_ et passée systématiquement à notre *fragment-shader*, autrement dit, elle est toujours là mais inutile de la chercher dans le code ci dessous.
|
||||
|
||||
deuxième chose importante, ```gl_FragColor```, ```gl_FragCoord``` et tous les noms de fonctions ( ```sin()```, ```abs()```, etc. ) sont des noms réservés ; on ne peut pas s'en servir pour créer nos variables.
|
||||
|
||||
<div class="codeAndCanvas" data="space.frag"></div>
|
||||
|
||||
Dans le code ci-dessus, nous *normalisons* les coordonnées du *fragment* en les divisant par la taille du canvas.
|
||||
En *normalisant* les coordonnées, elles vont se retrouver comprises entre ```0.0``` & ```1.0``` ce qui permet de *mapper* facilement les valeurs X et Y du *fragment* vers les canaux rouges et verts (R&G) de la couleur de sortie (```gl_FragColor```).
|
||||
|
||||
Au pays des shaders, nous avons peu de moyen de débugger une application à part assigner des valeurs criardes aux fragments et essayer de comprendre ce qui se passe.
|
||||
Vous découvrirez que parfois, coder un shader c'est comme de fabriquer un tout petit bateau dans une bouteille, c'est dur, c'est beau et c'est gratifiant.
|
||||
|
||||
![](08.png)
|
||||
|
||||
Voyons ce que nous avez appris et compris du code.
|
||||
|
||||
* pouvez dire où se trouvent les coordonnées XY ```(0.0,0.0)``` sur notre canvas?
|
||||
|
||||
* à votre avis où se trouvent les coordonnées```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` et ```(1.0,1.0)```?
|
||||
|
||||
* pouvez vous déduire comment utiliser l'uniform ```u_mouse``` sachant que ses valeurs sont passées au shader en _pixels_ et ne sont pas normalisées?
|
||||
|
||||
* pouvez vous utiliser ```u_mouse``` pour changer les couleurs?
|
||||
|
||||
* pouvez vous inventer une manière intéressante de combiner ```u_time``` et ```u_mouse``` pour créer un motif?
|
||||
|
||||
Après ces petits exercices, vous vous demandez sans doute où exercer vos nouveaux talents.
|
||||
Au chapitre suivant, nous verrons comment fabriquer nos propres outils dans THREE.js, Processing et OpenFrameworks.
|
@ -0,0 +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.
|
||||
|
||||
<div class="codeAndCanvas" data="time.frag"></div>
|
||||
|
||||
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*.
|
||||
|
||||
<div class="codeAndCanvas" data="space.frag"></div>
|
||||
|
||||
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.
|
@ -0,0 +1,7 @@
|
||||
Learn how to use Uniform variables. Uniform variables, or simply *uniforms* are the variables that carry information equally accessible from all of the threads of your shader. The [GSLS editor](http://editor.thebookofshaders.com/) has three uniforms set up for you.
|
||||
|
||||
```glsl
|
||||
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
|
||||
```
|
@ -0,0 +1 @@
|
||||
## Uniforms
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
@ -0,0 +1,220 @@
|
||||
## exécuter vos shaders
|
||||
|
||||
Pour les besoins de ce livre comme pour ma pratique artistique, j'ai créé un écosystème d'outils permettant de créer, d'afficher, de partager et d'organiser mes shaders.
|
||||
Ces outils fonctionnent de la même manière sur Linux Desktop, MacOS, [Raspberry Pi](https://www.raspberrypi.org/) et dans les navigateurs sans avoir besoin d'altérer le code.
|
||||
|
||||
**Affichage**: tous les exemples de ce livre sont affichés dans la page grâce à [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) qui facilite grandement la fabrication et l'affichage de shaders autonomes.
|
||||
|
||||
```html
|
||||
<canvas class="glslCanvas" data-fragment-url=“yourShader.frag" data-textures=“yourInputImage.png” width="500" height="500"></canvas>
|
||||
```
|
||||
Comme vous pouvez le voir, il suffit de créer un élément ```canvas``` auquel on applique la classe ```class="glslCanvas"``` et de lui passer l'url du fragment shader dans ```data-fragment-url```.
|
||||
Pour en savoir plus, [vous pouvez lire ceci](https://github.com/patriciogonzalezvivo/glslCanvas).
|
||||
|
||||
Si vous êtes comme moi, vous aurez sans doute envie de lancer vos shaders en lignes de commandes, dans ce cas vous devriez regarder [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer).
|
||||
Cette application permet d'incorporer un shader dans un script ```bash``` ou un pipeline Unix et de l'utiliser comme [ImageMagick](http://www.imagemagick.org/script/index.php).
|
||||
|
||||
[glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) est aussi un bon moyen de compiler vos shaders sur un [Raspberry Pi](https://www.raspberrypi.org/) et c'est la raison pour laquelle [openFrame.io](http://openframe.io/) l'utilise pour afficher les oeuvres.
|
||||
Pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/glslViewer).
|
||||
|
||||
```bash
|
||||
glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -s 1 -o yourOutputImage.png
|
||||
```
|
||||
|
||||
**Création**:
|
||||
Pour améliorer l'expérience de programmation des shaders, j'ai créé un éditeur disponible ici [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor).
|
||||
L'éditeur est embarqué dans les exemples de ce livre, il met à disposition une série de petits widgets qui rendent l'édition du code GLSL plus tangible et moins abstraite.
|
||||
Vous pouvez également le lancer dans une fenêtre de navigateur à cette adresse [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/).
|
||||
Pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/glslEditor).
|
||||
|
||||
![](glslEditor-01.gif)
|
||||
|
||||
Si vous préférez travailler avec [SublimeText](https://www.sublimetext.com/) vous pouvez installer le [package pour glslViewer](https://packagecontrol.io/packages/glslViewer).
|
||||
Pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/sublime-glslViewer).
|
||||
|
||||
![](glslViewer.gif)
|
||||
|
||||
**Partager**:
|
||||
l'éditeur en ligne([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) vous permet de partager vos shaders!
|
||||
La version autonome comme la version en ligne de l'éditeur permettent de sauver votre shader en ligne et d'obtenir une url unique.
|
||||
Il est également possible d'exporter le shader pour qu'il fonctionne sur [openFrame.io](http://openframe.io/).
|
||||
|
||||
![](glslEditor-00.gif)
|
||||
|
||||
**Organiser**:
|
||||
Pouvoir partager ses shaders est une bonne chose, en plus de l'export vers [openFrame.io](http://openframe.io/)
|
||||
j'ai fait un outil permettant d'organiser vos shaders dans une galerie et d'intégrer cette galerie dans n'importe quel site.
|
||||
il s'appelle [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery), pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/glslGallery).
|
||||
|
||||
![](glslGallery.gif)
|
||||
|
||||
## Lancer vos shaders depuis votre plateforme favorite
|
||||
|
||||
Si vous avez déjà programmé à l'aide de frameworks/APIS comme: [Processing](https://processing.org/), [Three.js](http://threejs.org/) ou [OpenFrameworks](http://openframeworks.cc/),
|
||||
vous êtes sans doute impatients de tester vos shaders dans ces environnements.
|
||||
Les exemples suivants montrent comment intégrer les shaders sur ces plateformes en conservant les conventions de nommage que nous utiliserons dans ce livre.
|
||||
Vous retrouverez le code source complet sur le [repo GitHub de ce chapitre](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04).
|
||||
|
||||
### Dans **THREE.js**
|
||||
|
||||
L'humble et brilliant Ricardo Cabello (alias [MrDoob](https://twitter.com/mrdoob)) a développé avec d'autres [contributeurs](https://github.com/mrdoob/three.js/graphs/contributors), l'un des frameworks WebGL les plus utilisés: [Three.js](http://threejs.org/).
|
||||
Il existe de nombreuses ressources pour apprendre à se servir de ce framework JavaScript.
|
||||
|
||||
L'exemple ci-dessous, vous donne le code nécessaire pour utiliser un shader dans THREE.js.
|
||||
Notez bien la balise de script appelée ```id="fragmentShader"```, c'est là qu'il faudra coller le code que vous trouverez dans ce livre.
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script src="js/three.min.js"></script>
|
||||
<script id="vertexShader" type="x-shader/x-vertex">
|
||||
void main() {
|
||||
gl_Position = vec4( position, 1.0 );
|
||||
}
|
||||
</script>
|
||||
<script id="fragmentShader" type="x-shader/x-fragment">
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;
|
||||
gl_FragColor=vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var container;
|
||||
var camera, scene, renderer;
|
||||
var uniforms;
|
||||
|
||||
init();
|
||||
animate();
|
||||
|
||||
function init() {
|
||||
container = document.getElementById( 'container' );
|
||||
|
||||
camera = new THREE.Camera();
|
||||
camera.position.z = 1;
|
||||
|
||||
scene = new THREE.Scene();
|
||||
|
||||
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
|
||||
|
||||
uniforms = {
|
||||
u_time: { type: "f", value: 1.0 },
|
||||
u_resolution: { type: "v2", value: new THREE.Vector2() },
|
||||
u_mouse: { type: "v2", value: new THREE.Vector2() }
|
||||
};
|
||||
|
||||
var material = new THREE.ShaderMaterial( {
|
||||
uniforms: uniforms,
|
||||
vertexShader: document.getElementById( 'vertexShader' ).textContent,
|
||||
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
|
||||
} );
|
||||
|
||||
var mesh = new THREE.Mesh( geometry, material );
|
||||
scene.add( mesh );
|
||||
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
|
||||
container.appendChild( renderer.domElement );
|
||||
|
||||
onWindowResize();
|
||||
window.addEventListener( 'resize', onWindowResize, false );
|
||||
|
||||
document.onmousemove = function(e){
|
||||
uniforms.u_mouse.value.x = e.pageX
|
||||
uniforms.u_mouse.value.y = e.pageY
|
||||
}
|
||||
}
|
||||
|
||||
function onWindowResize( event ) {
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
uniforms.u_resolution.value.x = renderer.domElement.width;
|
||||
uniforms.u_resolution.value.y = renderer.domElement.height;
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
uniforms.u_time.value += 0.05;
|
||||
renderer.render( scene, camera );
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
### Dans **Processing**
|
||||
|
||||
Initié par [Ben Fry](http://benfry.com/) et [Casey Reas](http://reas.com/) en 2001, [Processing](https://processing.org/) est un framework Java
|
||||
extraordinairement simple et très puissant qui vous aidera à faire vos premiers pas dans le code créatif (ça a été mon cas).
|
||||
[Andres Colubri](https://codeanticode.wordpress.com/) a contribué des mises à jour importantes concernant OpenGL et la gestion vidéo dans Processing.
|
||||
Ces ajouts simplifient énormément l'intégration des shaders GLSL dans l'environnement de développement.
|
||||
Processing va chercher le shader appelé ```"shader.frag"``` dans le dossier ```data``` du sketch.
|
||||
Assurez vous de copier les exemples du livre dans ce dossier et de les renommer correctement.
|
||||
|
||||
```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);
|
||||
}
|
||||
```
|
||||
|
||||
Pour que le shader fonctionne dans les versions antérieures à Processing 2.1, il faut ajouter la ligne suivante: ```#define PROCESSING_COLOR_SHADER``` au début du shader.
|
||||
il devrait ressembler à ça:
|
||||
|
||||
```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);
|
||||
}
|
||||
```
|
||||
|
||||
Pour en savoir plus sur les shaders dans Processing, vous pouvez vous reporter à ce [tutoriel](https://processing.org/tutorials/pshader/).
|
||||
|
||||
### Dans **openFrameworks**
|
||||
|
||||
Chacun a sa zone de confort, pour moi, ça reste [la communité openFrameworks](http://openframeworks.cc/).
|
||||
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());
|
||||
ofRect(0,0,ofGetWidth(), ofGetHeight());
|
||||
shader.end();
|
||||
}
|
||||
```
|
||||
|
||||
Pour plus d'informations sur les shader OpenFrameworks, vous pouvez vous reporter à cet [excellent tutoriel](http://openframeworks.cc/ofBook/chapters/shaders.html) écrit par [Joshua Noble](http://thefactoryfactory.com/).
|
@ -0,0 +1,190 @@
|
||||
## Eseguite il vostro shader
|
||||
|
||||
Nell'ambito della realizzazione di questo libro e della mia pratica artistica ho creato un ecosistema di strumenti per creare, visualizzare, condividere e curare gli shaders. Questo strumento funziona in modo coerente su Linux Desktop, MacOS, [Raspberry Pi](https://www.raspberrypi.org/) e browser, senza la necessità di dover cambiare il vostro codice.
|
||||
|
||||
**Visualizzare**: tutti gli esempi di questo libro vengono visualizzati utilizzando [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) che rende il processo di esecuzione dello shader standalone incredibilmente facile.
|
||||
|
||||
```html
|
||||
<canvas class="glslCanvas" data-fragment-url=“yourShader.frag" data-textures=“yourInputImage.png” width="500" height="500"></canvas>
|
||||
```
|
||||
|
||||
Come potete vedere, è solo necessario l'elemento ```canvas``` con l'attributo ```class="glslCanvas"``` e l'indirizzo verso il vostro shader nel ```data-fragment-url```. Scoprite di più a proposito [cliccando qui](https://github.com/patriciogonzalezvivo/glslCanvas).
|
||||
|
||||
Se siete come me, probabilmente vorrete eseguire gli shader direttamente dalla console. In questo caso date un'occhiata a [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Questa applicazione consente d'incorporare gli shader nel vostro script ```bash``` o pipelines UNIX e d?utilizzarli in modo simile a [ImageMagick](http://www.imagemagick.org/script/index.php). Anche [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) è un ottimo modo per compilare gli shader sul [Raspberry Pi](https://www.raspberrypi.org/), motivo per il quale [openFrame.io](http://openframe.io/) lo usa per visualizzare le opere d'arte di tipo shader. Potete trovare ulteriori informazioni su questa applicazione [cliccando qui](https://github.com/patriciogonzalezvivo/glslViewer).
|
||||
|
||||
```bash
|
||||
glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -s 1 -o yourOutputImage.png
|
||||
```
|
||||
|
||||
**Creare**: per migliorare la programmazione degli shader, ho realizzato un editor online chiamato [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Questo editor è integrato agli esempi del libro e mette a disposizione una serie di comodi widget per rendere più tangibile il codice astratto GLSL. È anche possibile eseguirlo come un'applicazione standalone web da [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Scoprite di più a proposito [cliccando qui](https://github.com/patriciogonzalezvivo/glslEditor).
|
||||
|
||||
![](glslEditor-01.gif)
|
||||
|
||||
Se si preferisce lavorare offline utilizzando [SublimeText](https://www.sublimetext.com/) è possibile installare questo [pacchetto per glslViewer](https://packagecontrol.io/packages/glslViewer). Scoprite di più [cliccando qui](https://github.com/patriciogonzalezvivo/sublime-glslViewer).
|
||||
|
||||
![](glslViewer.gif)
|
||||
|
||||
**Condividere**: l'editor online ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) può condividere i tuoi shader! Sia la versione standalone che quella integrata hanno un pulsante per esportare con il quale è possibile ottenere un URL unico verso il vostro shader. Avete anche la possibilità d'esportare direttamente verso un [openFrame.io](http://openframe.io/).
|
||||
|
||||
![](glslEditor-00.gif)
|
||||
|
||||
**Curare**: Condividere il vostro codice è la prima tappa per intendere il vostro shader come un'opera d'arte! Accanto alla possibilità di esportare verso [openFrame.io](http://openframe.io/) ho fatto uno strumento per curare i vostri shader in una galleria che può essere integrata su qualsiasi sito, il suo nome è [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Per saperne di più [cliccando qui](https://github.com/patriciogonzalezvivo/glslGallery).
|
||||
|
||||
![](glslGallery.gif)
|
||||
|
||||
## Eseguire i vostri shader nel vostro framework preferito
|
||||
|
||||
Nel caso in cui si dispone già di esperienze di programmazione in framework quali: [Processing](https://processing.org/), [Three.js](http://threejs.org/) o [OpenFrameworks](http://openframeworks.cc/), probabilmente sarete ansiosi di provare gli shader sulle piattaforme su cui vi trovate bene. I seguenti sono esempi di come impostare gli shader in alcuni dei framework più popolari con le stesse uniforms che andremo ad utilizzare in questo libro. (Nella [repository GitHub per questo capitolo](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), troverete il codice sorgente completo per questi tre framework.)
|
||||
|
||||
### In **Three.js**
|
||||
|
||||
Il brillante e molto umile Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob)) ha sviluppato insieme ad altri [collaboratori](https://github.com/mrdoob/three.js/graphs/contributors), probabilmente uno dei più famosi framework per WebGL, chiamato [Three.js](http://threejs.org/). Troverete un sacco di esempi, tutorial e libri che vi insegneranno come utilizzare questa libreria JavaScript per fare grafica 3D.
|
||||
|
||||
Di seguito è riportato un esempio di codice HTML e JS per iniziare con gli shader in three.js. Prestate attenzione allo script ```id="fragmentShader"```, qui è dove è possibile copiare gli shader che si trovano in questo libro.
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script src="js/three.min.js"></script>
|
||||
<script id="vertexShader" type="x-shader/x-vertex">
|
||||
void main() {
|
||||
gl_Position = vec4( position, 1.0 );
|
||||
}
|
||||
</script>
|
||||
<script id="fragmentShader" type="x-shader/x-fragment">
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;
|
||||
gl_FragColor=vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var container;
|
||||
var camera, scene, renderer;
|
||||
var uniforms;
|
||||
|
||||
init();
|
||||
animate();
|
||||
|
||||
function init() {
|
||||
container = document.getElementById( 'container' );
|
||||
|
||||
camera = new THREE.Camera();
|
||||
camera.position.z = 1;
|
||||
|
||||
scene = new THREE.Scene();
|
||||
|
||||
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
|
||||
|
||||
uniforms = {
|
||||
u_time: { type: "f", value: 1.0 },
|
||||
u_resolution: { type: "v2", value: new THREE.Vector2() },
|
||||
u_mouse: { type: "v2", value: new THREE.Vector2() }
|
||||
};
|
||||
|
||||
var material = new THREE.ShaderMaterial( {
|
||||
uniforms: uniforms,
|
||||
vertexShader: document.getElementById( 'vertexShader' ).textContent,
|
||||
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
|
||||
} );
|
||||
|
||||
var mesh = new THREE.Mesh( geometry, material );
|
||||
scene.add( mesh );
|
||||
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
|
||||
container.appendChild( renderer.domElement );
|
||||
|
||||
onWindowResize();
|
||||
window.addEventListener( 'resize', onWindowResize, false );
|
||||
|
||||
document.onmousemove = function(e){
|
||||
uniforms.u_mouse.value.x = e.pageX
|
||||
uniforms.u_mouse.value.y = e.pageY
|
||||
}
|
||||
}
|
||||
|
||||
function onWindowResize( event ) {
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
uniforms.u_resolution.value.x = renderer.domElement.width;
|
||||
uniforms.u_resolution.value.y = renderer.domElement.height;
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
uniforms.u_time.value += 0.05;
|
||||
renderer.render( scene, camera );
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
### In **Processing**
|
||||
|
||||
Iniziato da [Ben Fry](http://benfry.com/) e [Casey Reas](http://reas.com/) nel 2001, [Processing](https://processing.org/) è un framework straordinariamente semplice e potente in cui muovere i primi passi nel codice (o almeno lo è stato per me). [Andres Colubri](https://codeanticode.wordpress.com/) ha fatto importanti aggiornamenti a openGL e la gestione video in Processing, rendendo più facile che mai usare e giocare con i GLSL shader. Processing cercherà lo shader chiamato ```"shader.frag"``` nella cartella ```data``` dello sketch. Assicuratevi di copiare gli esempi che trovate qui in quella cartella e rinominate il file.
|
||||
|
||||
```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);
|
||||
}
|
||||
```
|
||||
|
||||
Affinché lo shader lavori su versioni precedenti alla 2.1, è necessario aggiungere la seguente riga all'inizio del vostro Shader: ```#define PROCESSING_COLOR_SHADER```. In questo modo dovrebbe assomigliare a:
|
||||
|
||||
```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);
|
||||
}
|
||||
```
|
||||
|
||||
Per ulteriori informazioni sugli shader in Processing controllate questo [tutorial](https://processing.org/tutorials/pshader/).
|
||||
|
||||
### 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());
|
||||
ofRect(0,0,ofGetWidth(), ofGetHeight());
|
||||
shader.end();
|
||||
}
|
||||
```
|
||||
|
||||
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/).
|
@ -0,0 +1 @@
|
||||
## Running your shader
|
@ -0,0 +1,189 @@
|
||||
# Dessin Algorithmique
|
||||
## fonctions de formes
|
||||
|
||||
Ce chapitre aurait pu s'appeler "la palissade de monsieur Miyagi" (ndt [pour ceux qui n'étaient pas nés en 1984](https://fr.wikipedia.org/wiki/Karat%C3%A9_Kid_(film,_1984))).
|
||||
|
||||
Au chapitre précédent, nous avons *mappé* les coordonnées *x* et *y* *normalisées* sur les canaux *rouge* et *vert*.
|
||||
Nous avons créé une *fonction* qui prend un vecteur à deux dimensions (x et y) et retourne un vecteur à quatre dimensions (r, g, b et a).
|
||||
Avant de transformer des données à plusieurs dimensions, il nous faut commencer par des choses simples... beaucoup plus simples.
|
||||
Concrètement, nous devons comprendre commment marchent les fonctions à une dimension.
|
||||
Plus vous passerez de temps à apprendre et à maîtriser ces fonctions, plus votre Karaté-Shader sera redoutable.
|
||||
|
||||
![The Karate Kid (1984)](mr_miyagi.jpg)
|
||||
|
||||
Le code suivant sera notre palissade.
|
||||
Sur cette palissade, nous visualisons la valeur normalisée de la position *x* (```st.x```) de deux façons: la luminosité (c'est le joli dégradé du noir au blanc en arrière plan) et une ligne verte dessinée par dessus (dans ce cas, la valeur *x* est assignée directement à *y*).
|
||||
Ne vous focalisez pas trop sur la fonction ```plot``` pour l'instant, nous y reviendrons en détail dans un moment.
|
||||
|
||||
<div class="codeAndCanvas" data="linear.frag"></div>
|
||||
|
||||
**Note**: Le constructeur du type ```vec3```, un vecteur à 3 dimensions (r,g,b ou x,y,z ; c'est la même chose), "comprend" que vous allez le construire avec la même valeur pour les trois canaux/dimensions.
|
||||
il est donc possible d'ecrire ```vec3 color = vec3( y );``` pour construire un vecteur à 3 dimensions. Ce vecteur aura la valeur ```y``` assignée à chaque canal/dimension soit: ```color.x = color.y = color.z = y``` ou ```color.r = color.g = color.b = y``` (puisqu'on peut accéder aux variables du vecteur des 2 manières).
|
||||
Le constructeur du type ```vec4``` en revanche, "comprend" que vous allez le construire, soit en passant quatre valeurs dinstinctes: ```vec4( 0.,0.5,1.,1.)```, soit en lui passant un ```vec3``` et un ```float``` (un nombre) : ```vec4( color, 1.)```.
|
||||
Dans notre cas, la valeur du second paramètre (le ```float```), permet de gérer l'*opacité* aussi appelé l'*alpha*.
|
||||
Référez vous aux lignes 20 et 26 dans l'exemple ci-dessus pour bien voir la différence de construction des 2 types.
|
||||
|
||||
Ce code sera votre palissade ; il est important de bien l'observer et de bien le comprendre.
|
||||
Vous reviendrez souvent dans cet espace entre *0.0* and *1.0* pour maîtriser l'art de le transformer et de sculpter cette ligne.
|
||||
|
||||
La relation entre *x* et *y* ( la luminosité du dégradé ), s'appelle une *interpolation*.
|
||||
Comme on passe une seule valeur (*y*) à la variable *color*, on obtient un niveau de gris et comme la valeur de *x* est *normalisée*, elle est comprise entre *0.0* et *1.0*, on obtient un dégradé du noir (*x=0.*) au blanc (*x=1.*).
|
||||
L'*interpolation* est un principe fondamental ; elle nous permet de faire passer progressivement une valeur de *A* vers *B* en fonction d'une troisième valeur *T* normalisée entre *0.0* et *1.0*.
|
||||
La ligne verte reflète ce qui se passe lors de l'interpolation, en l'occurrence, c'est une ligne droite puisque *x* passe de *0.0* à *1.0* de façon linéaire (*x* va de *0.0* à *1.0* de façon continue).
|
||||
A partir de là, nous pouvons utiliser des fonctions mathématiques pour *sculpter* la ligne. Par exemple, on peut passer *x* à la puissance 5 pour créer une ligne *courbe*.
|
||||
|
||||
<div class="codeAndCanvas" data="expo.frag"></div>
|
||||
|
||||
Intéressant n'est-ce-pas? A la ligne 19, au lieu de ```5.0``` essayez différents exposants, par exemple: 20.0, 2.0, 1.0, 0.0, 0.2 et 0.02.
|
||||
Comprendre la relation qui existe entre la valeur et l'exposant va nous être très utile.
|
||||
Ce genre de fonction mathématique nous donne un contrôle sur l'*expressivité* du code, c'est une sorte d'acupuncture qui permet de contrôle les flux de valeurs.
|
||||
|
||||
[```pow()```](../glossary/?search=pow) est une fonction native de GLSL et il y en a de nombreuses autres.
|
||||
La plupart sont accélérées matériellement, ce qui signifie que si on les utilise bien et avec parcimonie, elle permettent au code de s'exécuter plus vite.
|
||||
|
||||
Essayez de remplacer la fonction ```pow()``` ligne 19 par: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log) ou [```sqrt()```](../glossary/?search=sqrt).
|
||||
Certaines de ces fonctions deviennent vraiment intéressantes quand on les utilise avec PI. Vous pouvez voir que j'ai déclaré une macro qui remplacera chaque appel à ```PI``` par la valeur ```3.14159265359```.
|
||||
par exemple: ```sin( st.x * PI )```, produira une parabole, ```pow( sin( st.x * PI ), 5. )``` effectuera un *pincement* de la parabole.
|
||||
|
||||
### Step et Smoothstep
|
||||
|
||||
GLSL propose également des fonctions d'interpolation natives et accélrées matériellement.
|
||||
|
||||
La fonction [```step()```](../glossary/?search=step) prend 2 paramètres, le premier est une *limite* ou un *seuil* et le second est la valeur à tester.
|
||||
Toute valeur inférieure au *seuil* renverra ```0.0``` tandis que toute valeur supérieure au *seuil* renverra ```1.0```.
|
||||
|
||||
essayez de changer la valeur de *seuil* à la ligne 20 du code suivant.
|
||||
|
||||
<div class="codeAndCanvas" data="step.frag"></div>
|
||||
|
||||
L'autre fonction d'interpolation s'appelle [```smoothstep()```](../glossary/?search=smoothstep).
|
||||
Avec deux nombres *A* et *B* et une valeur d'interpolation *T* comprise entre *0.0* et *1.0*, elle nous permet de passer de progressivement (et en souplesse) de *A* à *B* en fonction de *T*.
|
||||
les deux premiers arguments sont les *bornes* ( *A* et *B* ) et le troisième est la valeur d'interpolation (*T*).
|
||||
|
||||
<div class="codeAndCanvas" data="smoothstep.frag"></div>
|
||||
|
||||
Dans l'exemple ci-dessus, ligne 12, vous remarquez qu'on a utilisé ```smoothstep()``` depuis le début dans la fonction ```plot()``` qui permet de dessiner la ligne verte.
|
||||
Pour chaque position le long de l'axe des *x*, cette fonction crée une *bosse* à un endroit précis de l'axe des *y*.
|
||||
Comment? en combinant deux appels à [```smoothstep()```](../glossary/?search=smoothstep).
|
||||
Remplacez la ligne 20 par la fonction suivante et regardez l'arrière plan, on dirait une ligne floutée non?
|
||||
En rapprochant les valeurs de *seuil* des ```smoothstep()``` ( *0.45,0.5* et *0.5,0.55* par exemple), la ligne devient plus fine et moins floue.
|
||||
|
||||
```glsl
|
||||
float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);
|
||||
```
|
||||
|
||||
### Sinus et Cosinus
|
||||
|
||||
Le mieux, si vous voulez utiliser les maths pour animer ou passer d'une valeur à une autre, c'est d'être copain avec les sinus/cosinus.
|
||||
|
||||
Ces deux fonctions trigonométriques combinées permettent de dessiner des cercles qui sont plus utiles que le couteau suisse de MacGyver.
|
||||
Il est important de comprendre ce qu'elles font et comment les combiner.
|
||||
Dans un mouchoir de poche, à partir d'un angle en radians (1 radian = PI / 180), le [cosinus](../glossary/?search=cos) renvoie la position *x* et le [sinus](../glossary/?search=sin) renvoie la position *y* d'un point sur un cercle de rayon 1.
|
||||
Le fait que ces fonctions renvoient des valeurs *normalisées* (entre -1 et 1) de manière très 'continue' ou très 'souple', en fait un outil indispensable.
|
||||
|
||||
![](sincos.gif)
|
||||
|
||||
S'il est difficile de comprendre cette relation entre sinus/cosinus et le cercle unitaire (de rayon 1), l'animation ci-dessus la résume assez bien visuellement.
|
||||
|
||||
<div class="simpleFunction" data="y = sin(x);"></div>
|
||||
|
||||
Regardez attentivement cette sinusoïde et surtout comment la valeur *y* oscille entre -1 et 1.
|
||||
Comme nous l'avons vu sur l'exemple du temps au chapitre 3, on peut utiliser cette propriété temporelle de [```sin()```](../glossary/?search=sin) pour animer une valeur.
|
||||
Si vous regardez cet exemple dans un navigateur, vous pouvez changer le code de la forumle ci-dessus pour voir comment la sinusoïde change (n'oubliez pas le point-virule en fin de ligne).
|
||||
|
||||
Essayez les changements suivants et regardez ce qui se passe:
|
||||
|
||||
* ajoutez le temps (```u_time```) à *x* avant de calculer ```sin```. Retenez ce **mouvement** le long des *x*.
|
||||
|
||||
* Multipliez *x* par ```PI``` avant de calculer ```sin```. remarquez comme les deux *phases* **rétrécissent** de manière à ce que chaque cycle (tour complet) se répète entre deux valeurs entières.
|
||||
|
||||
* Multipliez le temps (```u_time```) par *x* avant de calculer ```sin```. remarquez comme la **fréquence** entre phases se compresse. Notez qu'u_time peut déjà avoir une valeur très élevée, rendant le graphe illisible.
|
||||
|
||||
* Ajoutez 1.0 à [```sin(x)```](../glossary/?search=sin). Notez que toutes les vagues se **déplacent** vers le haut et comme toutes les valeurs sont maintenant comprises entre 0 et 2.
|
||||
|
||||
* Multipliez [```sin(x)```](../glossary/?search=sin) par 2.0 et notez comme l'**amplitude** doubles de taille.
|
||||
|
||||
* calculez la valeur absolue ([```abs()```](../glossary/?search=abs)) de ```sin(x)```, on dirait que le tracé **rebondit**.
|
||||
|
||||
* Utilisez la partie fractionnelle (uniquement les chiffres après la virgule) ([```fract()```](../glossary/?search=fract)) du résultat de [```sin(x)```](../glossary/?search=sin).
|
||||
|
||||
* Ajoutez l'entier le plus grand ([```ceil()```](../glossary/?search=ceil)) à l'entier le plus petit ([```floor()```](../glossary/?search=floor)) du résultat de [```sin(x)```](../glossary/?search=sin) pour obtenir des *créneaux* entre -1 et 1.
|
||||
|
||||
|
||||
### quelques fonctions indispensables
|
||||
|
||||
A la fin de l'exercice précédent, nous avons présenté quelques nouvelles fonctions, nous allons maintenant les tester.
|
||||
Pour ce faire, décommentez une ligne à la fois dans la liste suivante.
|
||||
Essayez de comprendre comment chacune fonctionne et comment vous pourriez les combiner.
|
||||
Vous vous demandez sans doute mais... pourquoi?
|
||||
Une petite recherche de "generative art" sur Google vous apportera la réponse.
|
||||
Gardez à l'esprit que ces fonctions sont votre palissade, nous apprenons à maîtriser le mouvement sur une dimension, de bas en haut, puis de haut en bas.
|
||||
Bientôt, nous utiliserons, deux, trois et même quatre dimensions!
|
||||
|
||||
![Anthony Mattox (2009)](anthony-mattox-ribbon.jpg)
|
||||
|
||||
<div class="simpleFunction" data="y = mod(x,0.5); // renvoie x modulo 0.5
|
||||
//y = fract(x); // renvoie uniquement la partie fractionnelle d'un chiffre (les chiffres après la virgule)
|
||||
//y = ceil(x); // renvoie le plus proche entier supérieur ou égal à x
|
||||
//y = floor(x); // renvoie le plus proche entier inférieur ou égal à x
|
||||
//y = sign(x); // renvoie le signe de x (-1 ou 1)
|
||||
//y = abs(x); // renvoie la valeur absolue de x
|
||||
//y = clamp(x,0.0,1.0); // force x à se retrouver entre 0.0 et 1.0
|
||||
//y = min(0.0,x); // renvoie le plus petit chiffre entre 0 et x
|
||||
//y = max(0.0,x); // renvoie le plus grand chiffre entre 0 et x"></div>
|
||||
|
||||
### fonctions de formes avancées
|
||||
|
||||
[Golan Levin](http://www.flong.com/) a écrit quelques articles très instructifs sur des fonctions plus complexes.
|
||||
Les porter en GLSL est une bonne idée si vous souhaitez construire votre boîte à outils.
|
||||
|
||||
* [fonctions Polynomiales: www.flong.com/texts/code/shapers_poly](http://www.flong.com/texts/code/shapers_poly/)
|
||||
|
||||
* [fonctions Exponentielles: www.flong.com/texts/code/shapers_exp](http://www.flong.com/texts/code/shapers_exp/)
|
||||
|
||||
* [fonctions Circulaires & Elliptiques: www.flong.com/texts/code/shapers_circ](http://www.flong.com/texts/code/shapers_circ/)
|
||||
|
||||
* [fonctions de Bezier et autres fonctions paramétriques: www.flong.com/texts/code/shapers_bez](http://www.flong.com/texts/code/shapers_bez/)
|
||||
|
||||
Comme un chef qui collectionnerait les épices et autres ingrédients exotiques, les artistes digitaux et les codeurs créatifs en particulier aiment travailler leurs propres fonctions de forme.
|
||||
|
||||
[Iñigo Quiles](http://www.iquilezles.org/) a écrit une liste de [fonctions utiles](http://www.iquilezles.org/www/articles/functions/functions.htm).
|
||||
Après avoir lu [cet article](http://www.iquilezles.org/www/articles/functions/functions.htm) regardez leur traduction en GLSL.
|
||||
Notez bien les petits changements nécessaires, comme le "." (point) sur les floats et l'utilisation des conventions de nommage GLSL pour les fonctions C ; par exemple ```powf()``` devient ```pow()```:
|
||||
|
||||
* [Impulse](../edit.php#05/impulse.frag)
|
||||
* [Cubic Pulse](../edit.php#05/cubicpulse.frag)
|
||||
* [Exponential Step](../edit.php#05/expstep.frag)
|
||||
* [Parabola](../edit.php#05/parabola.frag)
|
||||
* [Power Curve](../edit.php#05/pcurve.frag)
|
||||
|
||||
Pour vous motiver, voici un exemple élégant, fait par [Danguafer](https://www.shadertoy.com/user/Danguafer) qui montre le karaté des fonctions de formes.
|
||||
|
||||
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/XsXXDn?gui=true&t=10&paused=true" allowfullscreen></iframe>
|
||||
|
||||
au prochain chapitre, nous utiliserons ces nouveaux mouvements. D'abord pour mélanger des couleurs, puis pour dessiner des formes.
|
||||
|
||||
#### Exercices
|
||||
|
||||
Regardez cette table d'équations, réalisée par [Kynd](http://www.kynd.info/log/).
|
||||
Voyez comme il combine les fonctions et leurs propriétés pour contrôler les variations de valuer entre 0 et 1.
|
||||
A présent, c'est à votre tour de vous entraîner à reproduire ces fonctions.
|
||||
Souvenez vous que plus vous pratiquerez, meilleur sera votre karaté.
|
||||
|
||||
![Kynd - www.flickr.com/photos/kynd/9546075099/ (2013)](kynd.png)
|
||||
|
||||
#### Pour la boîte à outils
|
||||
|
||||
Voici quelques outils qui simplifient la visualisation des fonctions.
|
||||
|
||||
* Grapher: si vous avez un MAC, tapez ```grapher``` dans spotlight et vous pourrez utiliser cet outil très pratique.
|
||||
|
||||
![OS X Grapher (2004)](grapher.png)
|
||||
|
||||
* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): [Iñigo Quilez](http://www.iquilezles.org), encore lui, a créé un outil pour visualiser les fonctions GLSL en WebGL.
|
||||
|
||||
![Iñigo Quilez - GraphToy (2010)](graphtoy.png)
|
||||
|
||||
* [Shadershop](http://tobyschachman.com/Shadershop/): [Toby Schachman](http://tobyschachman.com/) a créé cet outil génial qui permet de construire des fonctions de façon très intuitive.
|
||||
|
||||
![Toby Schachman - Shadershop (2014)](shadershop.png)
|
@ -0,0 +1 @@
|
||||
Shaping functions is fundamental technique that is recursively used throughout this book that let you control the variation of the value at will. Study how different functions of x are used to create different shapes and try making your own function.
|
@ -0,0 +1,2 @@
|
||||
# Algorithmic drawing
|
||||
## Shaping functions
|
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 76 KiB |
@ -0,0 +1 @@
|
||||
<div class="glslGallery" data="160414041542,160414041933,160414041756" data-properties="clickRun:editor,hoverPreview:false"></div>
|
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 110 KiB |
@ -0,0 +1,268 @@
|
||||
## Couleurs
|
||||
|
||||
![Paul Klee - Charte Couleur (1931)](klee.jpg)
|
||||
|
||||
Jusqu'ici, nous avons manipulé des vecteurs mais nous n'avons pas encore pris le temps de voir comment marchent ces variables.
|
||||
Avant d'aller plus loin, il est important d'en savoir plus sur ces variables.
|
||||
Aborder la couleur est un bon moyen de se pencher sur la question.
|
||||
|
||||
Si vous connaissez la Programmation Orientée Objet, vous aurez remarqué que nous accédons aux données des vecteurs comme on le ferait avec des ```struct``` en C, grâce à des **accesseurs / mutateurs** ( **getters / setters** en anglais).
|
||||
|
||||
[NDT]bien que cette pratique soit méconnue, il es possible d'utiliser des ```struct``` en GLSL, [plus d'informations ici](https://github.com/KhronosGroup/WebGL/blob/master/sdk/tests/conformance/glsl/misc/shader-with-array-of-structs-uniform.html) [/NDT]
|
||||
|
||||
```glsl
|
||||
vec3 red = vec3(1.0,0.0,0.0);
|
||||
red.x = 1.0;
|
||||
red.y = 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```.
|
||||
|
||||
Définir une couleur avec *x*, *y* et *z* peut être un peu déroutant, c'est pourquoi il existe différentes manières d'accéder aux valeurs des propriétés des vectuers.
|
||||
Les valeurs de ```.x```, ```.y``` et ```.z``` peuvent être récupérées avec les **accesseurs** ```.r```, ```.g``` et ```.b```, ou ```.s```, ```.t``` et ```.p```. (```.s```, ```.t``` et ```.p``` sont généralement utilisées pour encoder les coordonnées spatiales des textures, nous verrons ça dans les chapitres suivants).
|
||||
Il est également possible d'accéder aux valeurs des propriétés des vecteurs par leur position d'index dans l'objet: ```[0]```, ```[1]``` and ```[2]```.
|
||||
|
||||
Les lignes suivantes montrent les différentes manières d'accéder aux données:
|
||||
|
||||
```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;
|
||||
```
|
||||
|
||||
[NDT]on peut les utiliser ces **accesseurs** de façon indépendante ; le code suivant crée un clone *newColor* du vecteur *color* en utilisant chaque fois un accesseur différent.
|
||||
```glsl
|
||||
vec4 color = vec4( 1.,0.,0.5,1. );
|
||||
vec4 newColor = vec4( color[0], color.g, color.z, color.q );
|
||||
```
|
||||
|
||||
Il est possible de combiner les propriétés en **concaténant** les accesseurs: si on veut exploiter les valeurs ```.r```, ```.g``` et ```.b``` d'un vecteur 4 sans se soucier de ```.a``` (l'alpha), on peut écrire:
|
||||
|
||||
```glsl
|
||||
vec4 color = vec4( 1.,0.,0.5,1. );
|
||||
vec4 newColor = vec4( color.rgb, 1.0 );
|
||||
```
|
||||
|
||||
Ce qui revient à cloner chaque proriété ```.r```, ```.g``` et ```.b``` du vecteur ```color``` sauf la dernière ```.a```.
|
||||
|
||||
Dans ce cas, ```color.rgb``` est interprété comme un vecteur de type ```vec3``` et il contient les valeurs ```.r```, ```.g``` et ```.b``` du ```vec4``` *color*.
|
||||
De même, si on écrit:
|
||||
|
||||
```glsl
|
||||
vec4 color = vec4( 1.,0.,0.5,1. );
|
||||
vec3 newColor = vec3( color.xy, 1.0 );
|
||||
```
|
||||
On va utiliser les valeurs ```.x``` et ```.y``` de *color* pour construire un ```vec3``` dont les valeurs ```.r``` et ```.g``` seront les mêmes que les valeurs ```.r``` et ```.g``` du vecteur *color* et où la valeur ```.b``` sera ```1.0```.
|
||||
|
||||
Dernière chose, l'ordre dans lequel on **concatène** les accesseurs est important.
|
||||
Si on veut construire un vecteur à partir d'un autre mais en inversant l'ordre des propriétés, on peut l'écrire comme suit:
|
||||
|
||||
```glsl
|
||||
vec3 color = vec3( 1.0, 0.0, 0.5 );
|
||||
vec3 newColor = color.bgr;
|
||||
```
|
||||
|
||||
le vecteur *newColor* va copier les propriétés de *color* mais au lieu de les copier dans l'ordre "normal":```.r```, ```.g``` et ```.b```,
|
||||
il va les copier dans l'ordre inverse: ```.b```, ```.g``` et ```.r```.
|
||||
|
||||
```glsl
|
||||
color.r => 1.0
|
||||
color.g => 0.0
|
||||
color.b => 0.5
|
||||
et
|
||||
newColor.r => 0.5
|
||||
newColor.g => 0.0
|
||||
newColor.b => 1.0
|
||||
```
|
||||
|
||||
Il en découle que si les déclarations suivantes sont équivalentes:
|
||||
|
||||
```glsl
|
||||
color.rgba = color.xyzw = color.stpq
|
||||
```
|
||||
|
||||
ces déclarations ne le sont pas:
|
||||
|
||||
```glsl
|
||||
color.rgba != color.argb != color.rbga != color.abgr etc.
|
||||
color.xyzw != color.wxyz != color.xzyw != color.wzyx etc.
|
||||
color.stpq != color.qstp != color.sptq != color.qpts etc.
|
||||
```
|
||||
|
||||
C'est une fonctionnalité très puissante ; elle permet de stocker les informations dans un format compact.
|
||||
Un exemple d'utilisation, si on veut décrire un rectangle, on peut se servir soit de 2 ```vec2``` décrivant respectivement le coin supérieur gauche et le coin inférieur droit,
|
||||
ou bien, utiliser un seul ```vec4``` dont l'**accesseur** ```.xy``` renverra un ```vec2``` décrivant le coin supérieur gauche, et l'**accesseur** ```.zw``` renverra un ```vec2``` décrivant le coin inférieur droit.
|
||||
|
||||
[/NDT]
|
||||
|
||||
Ces différentes manière d'accéder aux variables à l'intérieur des vecteurs sont simplement là pour nous aider à écrire un code lisible.
|
||||
|
||||
Cette souplesse d'utilisation est le point d'entrée qui vous permettra de penser aux espaces cartésiens (le "vrai" espace) et colorimétriques de façon interchangeable.
|
||||
|
||||
La concaténation prend tout son sens lorsqu'on veut pouvoir combiner des vecteurs dans un ordre arbitraire pour les mélanger (cette propriété s'appelle le *swizzle*).
|
||||
|
||||
```glsl
|
||||
vec3 jaune, magenta, vert;
|
||||
|
||||
// crée le jaune
|
||||
jaune.rg = vec2(1.0); // Assigne 1. au canaux rouges et vert du vecteur jaune
|
||||
jaune[2] = 0.0; // Assigne 0. au canal bleu du vecteur jaune
|
||||
|
||||
// crée le magenta
|
||||
magenta = jaune.rbg; // Assigne the valeur en intervertissant le vert et le bleu ( rbg au lieu de rgb )
|
||||
|
||||
// crée le vert
|
||||
vert.rgb = jaune.bgb; // Assigne le canal bleu du jaune (0) aux canaux rouges et bleus
|
||||
```
|
||||
|
||||
#### Pour la boîte à outils
|
||||
|
||||
Si vous êtes incapables de choisir des couleurs par le biais des chiffres, c'est normal ; cela peut être très contre-intuitif.
|
||||
|
||||
Heureusement pour nous, il existe de nombreux programmes qui nous simplifient la tâche.
|
||||
Trouvez celui qui vous convient et apprenez à formater vos couleurs en ```vec3``` ou ```vec4```.
|
||||
Par exemple, voici les gabarits que j'utilise avec [Spectrum](http://www.eigenlogik.com/spectrum/mac):
|
||||
|
||||
```
|
||||
vec3({{rn}},{{gn}},{{bn}})
|
||||
vec4({{rn}},{{gn}},{{bn}},1.0)
|
||||
```
|
||||
|
||||
### Mélanger les couleurs
|
||||
|
||||
A présent que nous savons définir les couleurs, il est temps de les utiliser avec ce que nous avons déjà appris.
|
||||
|
||||
En GLSL, il existe une fonction extrêmement utile [```mix()```](../glossary/?search=mix), qui permet de mélanger deux valeurs en fonction d'un pourcentage.
|
||||
|
||||
[NDT]comme vu au chapitre précédent, ```mix()``` permet d'interpoler entre 2 valeurs grâce à une troisième valeur T.
|
||||
exactement comme ```smoothstep()``` à la différence que cette fois, la fonction ```mix()``` prend en argument des vecteurs au lieu de *floats*.
|
||||
[/NDT]
|
||||
|
||||
Pouvez vous deviner ce que devra être le pourcentage?
|
||||
Evidemment, une valeur normalisée entre *0.0* et *1.0*!
|
||||
Ce qui nous va très bien, après tout ce temps passé sur la palissade du chapitre précédent, il est enfin temps de frapper!
|
||||
|
||||
![](mix-f.jpg)
|
||||
|
||||
Observez la ligne 18: notez que nous utilisons la valeur absolue (```abs()```) d'une fonction de sinus (```sin()```) prenant le temps en argumanet pour contrôler le mélange entre ```colorA``` et ```colorB```.
|
||||
|
||||
<div class="codeAndCanvas" data="mix.frag"></div>
|
||||
|
||||
|
||||
Montrez de quoi vous êtes capable
|
||||
|
||||
* Créez une transition expressive entre les couleurs. Pensez à une émotion en particulier.
|
||||
* quelle couleur représente le mieux cette émotion? comment apparaît-elle? comment disparaît-elle?
|
||||
* pensez à une autre émotion et à la couleur correspondante, changez les couleur A et B dans le code puis utilisez les fonctions de formes pour opérer la transition.
|
||||
|
||||
Robert Penner a développé une série de fonctions destinées à créer des animations, connues sous le nom d'[easing functions](http://easings.net/).
|
||||
Vous pouvez utiliser [cet exemple](../edit.php#06/easing.frag) comme base de recherche mais les meilleures transitions seront celles que vous ferez vous mêmes.
|
||||
|
||||
### Jouer avec les dégradés
|
||||
|
||||
La fonction [```mix()```](../glossary/?search=mix) peut faire plus.
|
||||
Au lieu de passer un seul ```float``` pour faire l'interpolation, nous pouvons passer successivement plusieurs valeurs de transition.
|
||||
Dans l'exemple suivant, nous passons les valeurs ```r```, ```g``` et ```b``` d'un ```vec3``` (```pct``` pour *pourcentage* ) pour contrôler le mélange des canaux.
|
||||
|
||||
![](mix-vec.jpg)
|
||||
|
||||
Regardez l'exemple suivant.
|
||||
Comme au chapitre précédent, nous branchons la valeur de transition sur la valeur normalisée de *x* et nous la visualisons par une ligne.
|
||||
Au début, rien d'exceptionnel, le dégradé est linéaire sur les trois canaux.
|
||||
|
||||
A présent, décommentez la ligne 25 et regardez ce qui se passe, puis décommentez les lignes 26 et 27.
|
||||
Rappelez vous que les lignes représentent la quantité de mélange entre ```colorA``` et ```colorB``` par canal de couleur.
|
||||
|
||||
<div class="codeAndCanvas" data="gradient.frag"></div>
|
||||
|
||||
Vous aurez sans doute reconnu les 3 fonctions de forme du chapitre précédent aux lignes 25,26,27.
|
||||
A vous de jouer! Il est temps d'explorer et de créer des dégradés intéressants en ré-utilisant ce que nous avons vu au chapitre précédent.
|
||||
Essayez les exercices suivants:
|
||||
|
||||
![William Turner - The Fighting Temeraire (1838)](turner.jpg)
|
||||
|
||||
* Composez un dégradé qui ressemble au coucher de soleil ci-dessus
|
||||
|
||||
* Animez une transition entre lever et coucher de soleil en utilisant ```u_time```.
|
||||
|
||||
* pouvez vous créer un arc-en-ciel avec ce que vous avez appris jusqu'à présent?
|
||||
|
||||
* Utilisez la fonction ```step()``` pour créer un drapeau.
|
||||
|
||||
### HSB
|
||||
|
||||
On ne peut pas parler de couleur sans parler d'espace colorimétrique. Vous le savez sans doute mais il existe plusieurs façons d'organiser les canaux rouge, vert, bleu.
|
||||
|
||||
[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) signifie "Hue, Saturation, Brightness (ou Value)" soit en bon français "Teinte, Saturation, Luminosité", c'est une manière plus intuitive d'organiser les couleurs.
|
||||
Prenez un instant pour lire et essayer de comprendre les méthodes ```rgb2hsv()``` et ```hsv2rgb()``` dans le code suivant.
|
||||
|
||||
En indexant la Teinte (Hue) sur la position en *x* et la Luminosité (Brigthness) sur la position en *y*, nous obtenons un spectre des couleurs complet.
|
||||
Cette distribution spatiale des couleurs peut être très pratique ; il est plus simple de choisir une couleur dans un espace HSB que dans un espace RGB.
|
||||
|
||||
<div class="codeAndCanvas" data="hsb.frag"></div>
|
||||
|
||||
### HSB et coordonnées polaires
|
||||
|
||||
A l'origine, HSB a été conçu pour être représenté dans un système de coordonnées polaires.
|
||||
[NDT]Par opposition à un système de coordonnées cartésien décrit par 2 axes *X* et *Y* orthogonaux, un système de coordonnées polaires, est décrit par des *angles* et des *rayons*.[/NDT]
|
||||
Pour dessiner notre fonction HSB, nous devons obtenir la position du centre du canvas de manière à connaître l'*angle* et la *distance* de chaque fragment au centre.
|
||||
Pour cela nous allons utiliser la méthode [```length()```](../glossary/?search=length) et [```atan(y,x)```](../glossary/?search=atan) qui est l'équivalent GLSL de la méthode ```atan2(y,x)```.
|
||||
|
||||
Lorsqu'on utilise des vecteurs avec des fonctions trigonométriques les variables de type ```vec2```, ```vec3``` et ```vec4``` sont considérées comme des vecteurs géométriques même si elles représentent des couleurs.
|
||||
Nous commencerons à traiter les couleurs et les vecteurs géométriques de façon similaire, en fait, vous devriez comprendre assez vite que cette flexibilité d'utilisation est une force.
|
||||
|
||||
**Note:** Si vous vous demandez s'il existe d'autres fonctions géométriques que [```length```](../glossary/?search=length)
|
||||
comme: [```distance()```](../glossary/?search=distance), [```dot()```](../glossary/?search=dot), [```cross```](../glossary/?search=cross), [```normalize()```](../glossary/?search=normalize), [```faceforward()```](../glossary/?search=fraceforward), [```reflect()```](../glossary/?search=reflect) et [```refract()```](../glossary/?search=refract), la réponse est oui.
|
||||
GLSL expose également des méthodes pour comparer les vecteurs entres eux: [```lessThan()```](../glossary/?search=lessThan), [```lessThanEqual()```](../glossary/?search=lessThanEqual), [```greaterThan()```](../glossary/?search=greaterThan), [```greaterThanEqual()```](../glossary/?search=greaterThanEqual), [```equal()```](../glossary/?search=equal) et [```notEqual()```](../glossary/?search=notEqual).
|
||||
|
||||
Une fois que nous avons récupéré l'angle entre le centre et le fragment en cours, nous devons le normaliser.
|
||||
Ligne 27, [```atan(y,x)```](../glossary/?search=atan) nous retourne un angle en radians compris entre *-PI* et *PI* (~-3.14 to ~3.14), pour le normaliser, nous devons diviser cet angle par *2 x PI*, la macro ```TWO_PI``` en début de code nous permet de stocker cette valeur.
|
||||
En divisant l'angle par ```TWO_PI```, nous obtenons un chiffre compris entre *-0.5* (```-PI / TWO_PI```) et *0.5* (```PI / TWO_PI```) auquel il nous suffit d'ajouter 0.5 pour qu'il soit compris entre *0.0* et *1.0*.
|
||||
|
||||
Le rayon (la distance du centre au fragment) retournera une valeur max de 0.5 en *x* et en *y* (parce que nous calculons la distance depuis le centre du canvas),
|
||||
nous devons donc doubler cette valeur (en la multipliant par 2) pour obtenir un *rayon* compris entre *0.0* et *1.0*.
|
||||
|
||||
Vous voyez que tout est question de ramener les valeurs dans l'espace entre *0.0* et *1.0*, un espace *normalisé*.
|
||||
|
||||
<div class="codeAndCanvas" data="hsb-colorwheel.frag"></div>
|
||||
|
||||
Essayez les exercices suivants:
|
||||
|
||||
* Modifiez l'exemple des coordonnées polaires pour faire tourner les couleurs.
|
||||
|
||||
* Utilisez les fonctions de formes avec les fonctions de conversion HSB vers RGB pour étendre une valeur de teinte spécifique et rétrécir le reste.
|
||||
|
||||
![William Home Lizars - Red, blue and yellow spectra, with the solar spectrum (1834)](spectrums.jpg)
|
||||
|
||||
* si vous regardez attentivement la roue des couleurs qu'utilisent les sélecteurs de couleurs (voir l'image ci-dessous), ils affichent un spectre différent basé sur du RYB.
|
||||
Par exemple, la couleur opposée au rouge devrait être le vert mais dans nos exemples, c'est le Cyan.
|
||||
Pouvez vous trouver un moyen d'arranger ça de manière à obtenir exactement le meme rendu que sur l'image? [indice: c'est un bon moment pour vous servir des fonctions de formes.]
|
||||
|
||||
![](colorwheel.png)
|
||||
|
||||
* Lisez [le livre de Josep's Alvers: l'interaction des couleurs](http://www.goodreads.com/book/show/111113.Interaction_of_Color) et servez vous des exemples suivants pour vous entraîner à reproduire ses exemples.
|
||||
|
||||
<div class="glslGallery" data="160505191155,160505193939,160505200330,160507154604,160507160421" data-properties="clickRun:editor,openFrameIcon:false,showAuthor:false"></div>
|
||||
|
||||
#### A propos des fonctions et des arguments
|
||||
|
||||
Avant de passer au chapitre suivant, attardons nous un peu sur les fonctions du dernier exemple.
|
||||
Vous remarquerez un ```in``` avant les types des arguments.
|
||||
C'est ce qu'on appelle un [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) et dans ce cas précis, cela signifie que la variable est en lecture seule.
|
||||
Dans les exemples suivants, nous verrons qu'il est également possible de donner les *qualifiers* ```out``` et ```inout``` aux variables passées aux fonctions.
|
||||
Cette dernière, ```inout```, est équivalente à passer un argument *par référence* en C ; cela nous donne la possibilité de modifier la valeur de la variable passée en argument.
|
||||
|
||||
```glsl
|
||||
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.
|
||||
|
||||
|
||||
|
@ -0,0 +1,2 @@
|
||||
Familiarize yourself with how to express colors in shaders. The examples cover how to mix colors and beautifully animate them over time as well as conversion between two different models(RGB and HSB).
|
||||
In GLSL, colors are simply just vectors, which means you can easily apply the concepts and techniques you learn here to other
|
@ -0,0 +1 @@
|
||||
## Colors
|
@ -1 +0,0 @@
|
||||
Add some references and ideas from this IQ article: http://iquilezles.org/www/articles/palettes/palettes.htm
|
After Width: | Height: | Size: 40 KiB |
@ -0,0 +1,107 @@
|
||||
Add some references and ideas from this IQ article: http://iquilezles.org/www/articles/palettes/palettes.htm
|
||||
|
||||
### nicolas
|
||||
* struct exist in GLSL : this is valid
|
||||
```precision mediump float;
|
||||
struct my_struct {
|
||||
vec4 color;
|
||||
};
|
||||
uniform my_struct u_colors[2];
|
||||
void main(void) {
|
||||
gl_FragColor = u_colors[0].color;
|
||||
}
|
||||
```
|
||||
[source](https://github.com/KhronosGroup/WebGL/blob/master/sdk/tests/conformance/glsl/misc/shader-with-array-of-structs-uniform.html)
|
||||
|
||||
|
||||
[NICO]
|
||||
note: I had previously associated the name *accessor* to 'the way one can access the properties of an object'.
|
||||
|
||||
we can use those **accessors** independently ; the following code creates a clone *newColor* of the *color* vector by using a different accessor for each property.
|
||||
```glsl
|
||||
vec4 color = vec4( 1.,0.,0.5,1. );
|
||||
vec4 newColor = vec4( color[0], color.g, color.z, color.q );
|
||||
```
|
||||
|
||||
It is possible to combine the properties by **concatenating** different accessors:
|
||||
if we need to use the ```.r```, ```.g``` and ```.b``` values of a 4 dimensions vector but don't need the ```.a``` (alpha) value, we can write:
|
||||
|
||||
```glsl
|
||||
vec4 color = vec4( 1.,0.,0.5,1. );
|
||||
vec4 newColor = vec4( color.rgb, 1.0 );
|
||||
```
|
||||
|
||||
Which is the same as cloning each property ```.r```, ```.g``` and ```.b``` from ```color``` individually and dropping the last (```.a```).
|
||||
|
||||
In this case, ```color.rgb``` is interpreted as a vector of type ```vec3``` that contains the values ```.r```, ```.g``` and ```.b``` of the original ```vec4``` vector *color*.
|
||||
The same goes for:
|
||||
|
||||
```glsl
|
||||
vec4 color = vec4( 1.,0.,0.5,1. );
|
||||
vec3 newColor = vec3( color.xy, 1.0 );
|
||||
```
|
||||
|
||||
We use the values ```.x``` and ```.y``` from *color* to build a vector *newColors* of type ```vec3``` which ```.r``` and ```.g``` values will be the same as the *color* vector and ```.b``` value will be ```1.0```.
|
||||
|
||||
Last but not least, the order in which you **concatenate** the accessors matters.
|
||||
|
||||
If you want to build a vector from another vector but want to reverse the order of the properties, here's how you can write it:
|
||||
|
||||
```glsl
|
||||
vec3 color = vec3( 1.0, 0.0, 0.5 );
|
||||
vec3 newColor = color.bgr;
|
||||
```
|
||||
|
||||
the *newColor* vector will copy *color*'s properties but instead of copying them in the "regular" order: ```.r```, ```.g``` and ```.b```,
|
||||
it will copy them in the order defined by the concatenation: ```.b```, ```.g``` and ```.r```.
|
||||
|
||||
```glsl
|
||||
color.r => 1.0
|
||||
color.g => 0.0
|
||||
color.b => 0.5
|
||||
and
|
||||
newColor.r => 0.5
|
||||
newColor.g => 0.0
|
||||
newColor.b => 1.0
|
||||
```
|
||||
|
||||
On a side note, you can reuse the same accessor mutiple times and in whatever order in a concatenated accessor:
|
||||
|
||||
```glsl
|
||||
color.rrr => vec3( 1.0 )
|
||||
color.rrg => vec3( 1.0, 1.0, 0.0)
|
||||
color.bgg => vec3( 0.5, 0.0, 0.0)
|
||||
etc.
|
||||
```
|
||||
|
||||
This results in the fact that, if the following is true:
|
||||
|
||||
```glsl
|
||||
color.rgba = color.xyzw = color.stpq
|
||||
```
|
||||
|
||||
these statements are not necessarily true:
|
||||
|
||||
```glsl
|
||||
color.rgba != color.argb != color.rbga != color.abgr etc.
|
||||
color.xyzw != color.wxyz != color.xzyw != color.wzyx etc.
|
||||
color.stpq != color.qstp != color.sptq != color.qpts etc.
|
||||
```
|
||||
|
||||
This is a powerful feature ; it allows to store the data in compact forms and manipulate them in very flexible ways.
|
||||
Let's see a use case of the *compactness*: say you want to describe a rectangle, you can do so by using 2 ```vec2``` describing respectively the top left corner and the bottom right corner
|
||||
or you can instead, use a single ```vec4``` which ```.xy``` **accessor** will return a ```vec2``` describing the top left corner, and which ```.zw``` **accessor** will return a ```vec2``` describing the bottom right corner.
|
||||
|
||||
[/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.
|
||||
|
||||
[NICO]
|
||||
|
||||
rephrased this:
|
||||
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*.
|
||||
|
||||
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]
|
@ -1,2 +1,11 @@
|
||||
|
||||
- [Distance Transforms of Sampled Functions] (http://cs.brown.edu/~pff/papers/dt-final.pdf)
|
||||
|
||||
### nicolas
|
||||
* after the pseudocode, explain why not using 'if' instead of step( threshold, value ) as this is (fucking) counter-intuitive :)
|
||||
|
||||
* L 61 'That way the ```vec2(0.0,0.0)```' should rather be : 'That way the ```vec2``` *tl*' to disambiguate it from br which is also a vec2
|
||||
* 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'
|
@ -0,0 +1 @@
|
||||
Let's look at how to draw simple shapes in a parallel procedural way. In a nutshell, all you need to do is to determine if each pixel belongs to the shape you want to draw or not, and apply different colors accordingly. You can use coordinate system like a grid paper to draw rectangles and squares. We'll look at more advanced concept called distance field to draw more complex shapes.
|
@ -0,0 +1 @@
|
||||
## Shapes
|
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 241 KiB |
After Width: | Height: | Size: 40 KiB |
@ -0,0 +1 @@
|
||||
<div class="glslGallery" data="160414041142,160414040957,160414040804" data-properties="clickRun:editor,hoverPreview:false"></div>
|
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 139 KiB |
After Width: | Height: | Size: 54 KiB |
@ -0,0 +1,126 @@
|
||||
## Matrices 2D
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="matrix.frag" width="700px" height="200px"></canvas>
|
||||
|
||||
### Translation
|
||||
|
||||
Au chapitre précédent, nous avons vu comment créer des formes, l'astuce pour déplacer une forme consistait à déplacer le système de coordonnées lui-même.
|
||||
Nous opérions cette translation en ajoutant un vecteur 2d à la variable ```st``` contenant la position du fragment ce qui avait pour conséquence de décaler la position de l'ensemble des fragments en cours de traitement.
|
||||
|
||||
![](translate.jpg)
|
||||
|
||||
Un exemple sera sans doute plus explicite:
|
||||
|
||||
* Décommentez la ligne 35 du code ci-dessous pour voir le système de coordonnées bouger.
|
||||
|
||||
<div class="codeAndCanvas" data="cross-translate.frag"></div>
|
||||
|
||||
Essayez l'exercice suivant:
|
||||
|
||||
* servez vous d'```u_time``` et des fonctions de formes pour déplacer la croix de façon intéressante.
|
||||
Pensez à un type de mouvement et tentez de l'appliquer à la croix. Prenez des exemples de la "vraie vie", ça aide. par exemple un mouvement de vagues, un pendule, une balle qui rebondit, un vélo qui freine...
|
||||
|
||||
### Rotations
|
||||
|
||||
Pour effectuer une rotation, nous devons transformer tout le système de coordonnées.
|
||||
Pour nous aider, nous allons utiliser un objet [matrix](http://en.wikipedia.org/wiki/Matrix_%28mathematics%29) qui permet de manipuler une matrice de transformation 2d.
|
||||
Une matrice est un objet organisé en 'grille', elle se compose de colonnes et de rangées de chiffres.
|
||||
Lorsqu'on multiplie un Vecteur par une matrice, la matrice exécute une série d'opérations, dans un certain ordre et *transforme* le Vecteur en fonction des valeurs qu'elle contient.
|
||||
|
||||
[NDT]C'est pourquoi on les appelle souvent des *matrices de transformations*, la plupart des APIs graphiques - tout support confondu - proposent une matrice de transformation 2D, 3D ou 4D.
|
||||
Les matrices permettent de stocker plusieurs types de transformations (souvent: translation, rotation et échelle) dans un objet compact et utilisable avec des vecteurs.[/NDT]
|
||||
|
||||
pour en savoir plus, référez vous à l'article Wikipédia sur les matrices: [![article Wikipédia sur les matrices](matrixes.png)](https://fr.wikipedia.org/wiki/Matrice_(math%C3%A9matiques))
|
||||
|
||||
Le GLSL supporte nativement les matrices à deux, trois et quatre dimensions: [```mat2```](../glossary/?search=mat2) (2x2), [```mat3```](../glossary/?search=mat3) (3x3) et [```mat4```](../glossary/?search=mat4) (4x4).
|
||||
Le GLSL surcharge certains opérateurs, notamment la multiplication et offre des fonctions spécifiques comme [```matrixCompMult()```](../glossary/?search=matrixCompMult), qui effectue un produit scalaire des composants des matrices passées en argument.
|
||||
|
||||
Les matrices sont très utiles et permettent d'obtenir des transformations et des comportements spécifiques.
|
||||
Par exemple, on peut utiliser une matrice pour appliquer une translation à un vecteur:
|
||||
|
||||
![](3dtransmat.png)
|
||||
[NDT]la matrice est à gauche, les valeurs de translation *tx* et *ty* (la quantité de déplacement en x et en y) sont stockées à un endroit précis de la matrice (troisième colonne, rangées 1 et 2). le vecteur 2D que nous voulons transformer est au centre, le point entre les deux représente une multiplication et le résultat est à droite[/NDT]
|
||||
|
||||
Une matrice permet également d'effectuer une rotation:
|
||||
|
||||
![](rotmat.png)
|
||||
|
||||
[NDT]Notez que les valeurs de rotations (*cos()* et *sin()*) sont décrites à un endroit (colonnes, rangées) différent des valeurs de translation (*tx* et *ty*).
|
||||
C'est ce qui permet de stocker plusieurs transformations dans la même matrice.[/NDT]
|
||||
|
||||
Le code suivant montre comment construire une matrice de rotation 2D.
|
||||
Cette fonction s'appuie sur [la formule suivante](https://fr.wikipedia.org/wiki/Matrice_de_rotation) pour faire pivoter un vecteur 2D autour de l'origine du système d ecoordonnées ; le point ```vec2(0.0)```.
|
||||
|
||||
```glsl
|
||||
mat2 rotate2d(float _angle){
|
||||
return mat2(cos(_angle),-sin(_angle),
|
||||
sin(_angle),cos(_angle));
|
||||
}
|
||||
```
|
||||
|
||||
Cett manière d'effectuer un rotation (autour de l'origine) ne marche pas avec l'approche que nous avons eu jusqu'à présent pour dessiner les formes.
|
||||
En effet notre croix est dessinée au centre du canvas (le point ```vec2(0.5)```) alors sque la rotation se fait autour de l'origine (le point ```vec2(0.0)```).
|
||||
Donc, avant d'effectuer la rotation, nous devons déplacer la forme du `centre` vers l'origine ```vec2(0.0)```, appliquer la rotation puis re-déplacer la forme au `centre` du canvas.
|
||||
|
||||
![](rotate.jpg)
|
||||
|
||||
Le code ressemble à ça:
|
||||
|
||||
<div class="codeAndCanvas" data="cross-rotate.frag"></div>
|
||||
|
||||
Essayez les choses suivantes:
|
||||
|
||||
* Décommentez la ligne 45 du code ci-dessus et observez ce qui se passse.
|
||||
|
||||
* Commentez les translations avant et après la rotation aux lignes 37 et 39, observez ce qui se passe.
|
||||
|
||||
* Utilisez les rotations pour améliorer l'animation basée sur les translations que vous avez fait plus haut.
|
||||
|
||||
### Echelle
|
||||
|
||||
Nous avons vu que les matrices permettent de déplacer et de faire pivoter les objets dans l'espace ou plus exactement de déplacer l'origine et de lui appliquer une rotation avant de dessiner une forme.
|
||||
Si vous avez déjà fait de la 3D ou que vous vous êtes déjà servi des méthodes push et pop des matrices dans Processing, vous savez qu'on peut également se servir de matrices pour redimensionner un objet.
|
||||
|
||||
![](scale.png)
|
||||
|
||||
Voici à quoi ressemble une matrice 2D de mise à l'échelle:
|
||||
|
||||
```glsl
|
||||
mat2 scale(vec2 _scale){
|
||||
return mat2(_scale.x,0.0,
|
||||
0.0,_scale.y);
|
||||
}
|
||||
```
|
||||
|
||||
<div class="codeAndCanvas" data="cross-scale.frag"></div>
|
||||
|
||||
Pour mieux comprendre comment ça marche, essayez les choses suivantes:
|
||||
|
||||
* Décommentez la ligne 42 du code ci-dessus pour visualiser la mise à l'échelle en couleur.
|
||||
|
||||
* Regardez ce qui se passe quand vous commentez les translations avant et après la mise à l'échelle aux lignes 37 et 39.
|
||||
|
||||
* Essayez de combiner rotation et mise à l'échelle dans une seule matrice. Attention, l'ordre des opérations est important ; multipliez d'abord les matrices entre elles avant de multiplier le vecteur par la matrice finale.
|
||||
|
||||
* A présent que vous savez dessiner des formes et les transformer, essayez de faire une petite composition.
|
||||
Reprenez le design d'une de ces [fausses UI et HUD (Heads Up Display)](https://www.pinterest.com/patriciogonzv/huds/).
|
||||
Servez vous du sketch ShaderToy suivant (par [Ndel](https://www.shadertoy.com/user/ndel)) comme point de départ et/ou comme référence.
|
||||
|
||||
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/4s2SRt?gui=true&t=10&paused=true" allowfullscreen></iframe>
|
||||
|
||||
### Autres utilisations des matrices: l'espace colorimétrique YUV
|
||||
|
||||
[YUV](https://fr.wikipedia.org/wiki/YUV) est un espace colorimétrique utilisé pour l'encodage de photographies et de vidéos analogues.
|
||||
Il prend en compte ce que perçoit l'oeil humain de la lumière et modifie les plages du spectre lumineux pour s'y adapter.
|
||||
|
||||
Dans le code suivant, nous utilisons une matrice pour opérer la conversion d'un espace colorimétrique à l'autre (RGB est l'espace colorimétrique par défaut)
|
||||
|
||||
<div class="codeAndCanvas" data="yuv.frag"></div>
|
||||
|
||||
Comme vous pouvez le voir, nous traitons les couleurs comme des vecteurs et les multiplions par une matrice.
|
||||
Nous avons *déplacé* les valeurs de la couleur comme nous aurions déplacé une vecteur de position dans l'espace.
|
||||
|
||||
Dans ce chapitre, nous avons vu comment utiliser une matrice pour déplacer, faire pivoter et redimensionner un vecteur.
|
||||
Ces transformations sont essentielles lorsqu'on veut agencer les formes que nous avons appris à créer au chapitre précédent.
|
||||
Au chapitre suivant nous allons utiliser ce que nous venons de voir pour créer des motifs procéduraux.
|
||||
Vous verrez que créer des répétitions et des variations peut être très gratifiant.
|
@ -0,0 +1,101 @@
|
||||
## Matrici 2D
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="matrix.frag" width="700px" height="200px"></canvas>
|
||||
|
||||
### 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.
|
||||
|
||||
<div class="codeAndCanvas" data="cross-translate.frag"></div>
|
||||
|
||||
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:
|
||||
|
||||
<div class="codeAndCanvas" data="cross-rotate.frag"></div>
|
||||
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
<div class="codeAndCanvas" data="cross-scale.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/4s2SRt?gui=true&t=10&paused=true" allowfullscreen></iframe>
|
||||
|
||||
### 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.
|
||||
|
||||
<div class="codeAndCanvas" data="yuv.frag"></div>
|
||||
|
||||
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.
|
@ -0,0 +1,2 @@
|
||||
Matrix is a very powerful tool for manipulating vectors. By mastering how to use matrices, you can freely translate, scale and rotate shapes. Since the technique can be equally applied to anything expressed by vectors, we will look at many more advanced use of matrices later in this book.
|
||||
Matrices may look complex at a first glance, but you'll find it very handy and useful as you get used to the concept. Let's practice here and learn basics with simple examples.
|
@ -0,0 +1 @@
|
||||
## 2D Matrices
|
After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 38 KiB |
@ -0,0 +1,182 @@
|
||||
## Motifs
|
||||
|
||||
Les shaders sont exécutés au pixel et quel que soit le nombre de répétitions d'une forme, le nombre d'opérations effectuées restera constant.
|
||||
Cela signifie que les fragments shaders sont tout à fait indiqués pour la création de motifs répétitifs ; des *pavages* du plan.
|
||||
|
||||
[ ![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag)
|
||||
|
||||
Dans ce chapitre, nous allons mettre en application tout ce que nous avons vu jusqu'à présent et le répéter sur le canvas.
|
||||
Comme dans les chapitres précédents, notre stratégie consistera à multiplier les coordonnées pour que les formes que nous dessinons restent dans un espace normalisé entre 0 et 1.
|
||||
Le fait de multiplier les coordonnées du fragment en X et en Y créera une *grille* et le fait de diviser les coordonnées *étirera* une portion du canvas.
|
||||
|
||||
*"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/)
|
||||
|
||||
Pour commencer, rappelons nous de la méthode [```fract()```](../glossary/?search=fract).
|
||||
Elle retourne la partie fractionnelle d'un chiffre, ce qui revient à considérer ```fract()``` comme le modulo de 1 ([```mod(x,1.0)```](../glossary/?search=mod)).
|
||||
Autrement dit, [```fract()```](../glossary/?search=fract) retourne les chiffres après la virgule.
|
||||
Notre variable normalisée (```st```) va déjà de 0.0 à 1.0 donc il n'est pas très judicieux d'écrire quelque chose comme:
|
||||
|
||||
```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);
|
||||
}
|
||||
```
|
||||
En revanche, si nous multiplions la valeur de ```st``` par 3, l'utilisation de ```fract()``` nous permettra d'obtenir trois séries de valeurs normalisées entre 0 et 1:
|
||||
la première série correspondra au moment où ```st``` se trouve entre 0 et 1, la seconde série correspondra au moment où ```st``` se trouve entre 1 et 2 et la troisième série correspondra au moment où ```st``` se trouve entre 2 et 3.
|
||||
|
||||
[NDT]Une fois multiplié par 3, et au lieu de passer de 0 à 1 en X et Y, ```st``` passera de 0 à **3** en X et Y.
|
||||
Si nous utilisons ```st * 3.0``` tel quel, sa valeur va vite dépasser 1 et nous ne pourrons plus nous en servir comme nous l'avons fait jusqu'à présent ; il ne sera plus normalisé entre 0 et 1.
|
||||
Si on utilise seulement la partie fractionnelle, on retombe toujours dans un espace normalisé puisque la valeur de ```fract()``` (les chiffres après le virgule) sera toujours comprise entre 0 et 1.
|
||||
Voici un exemple des valeurs respectives de ```st```, ```st * 3``` et ```fract( st * 3 )```.
|
||||
```glsl
|
||||
premier bloc
|
||||
st = 0.00 | st * 3 = 0.00 | fract( st * 3 ) = 0.00
|
||||
st = 0.10 | st * 3 = 0.30 | fract( st * 3 ) = 0.30
|
||||
st = 0.20 | st * 3 = 0.60 | fract( st * 3 ) = 0.60
|
||||
st = 0.30 | st * 3 = 0.90 | fract( st * 3 ) = 0.90
|
||||
second bloc
|
||||
st = 0.40 | st * 3 = 1.20 | fract( st * 3 ) = 0.20
|
||||
st = 0.50 | st * 3 = 1.50 | fract( st * 3 ) = 0.50
|
||||
st = 0.60 | st * 3 = 1.80 | fract( st * 3 ) = 0.80
|
||||
troisième bloc
|
||||
st = 0.70 | st * 3 = 2.10 | fract( st * 3 ) = 0.10
|
||||
st = 0.80 | st * 3 = 2.40 | fract( st * 3 ) = 0.40
|
||||
st = 0.90 | st * 3 = 2.70 | fract( st * 3 ) = 0.70
|
||||
st = 1.00 | st * 3 = 3.00 | fract( st * 3 ) = 1.00
|
||||
```
|
||||
On voit bien que sur le premier bloc, la valeur ```st * 3``` est égale à ```fract( st * 3 )``` mais dès le second *bloc*, ```st * 3``` dépassse 1 alors que ```fract( st * 3 )``` reste toujours compris entre 0 et 1.
|
||||
[/NDT]
|
||||
|
||||
<div class="codeAndCanvas" data="grid-making.frag"></div>
|
||||
|
||||
Essayons de dessiner quelque chose dans chaque sous-espace en décommentant la ligne 27.
|
||||
Comme nous ne changeons pas le *ratio* (le rapport largeur/hauteur) en x et y, la forme ne change pas après la multiplication de taille et notre forme s'affiche correctement ; notre cercle est bien circulaire.
|
||||
|
||||
Essayez les choses suivantes pour mieux comprendre:
|
||||
|
||||
* Changez le facteur de multiplication des coordonnées ```st```, essayez des valeurs inférieures à zéro et des valeurs différentes en X et Y.
|
||||
|
||||
* Créez un fonction réutilisable pour cette manipulation.
|
||||
|
||||
* Divisez l'espace en 3 lignes et trois colonnes.
|
||||
Trouvez un moyen de connaître la case dans laquelle se trouve le fragment en cours de traitement et changez la forme dessinée dans la case en fonction de ça.
|
||||
Essayez de faire un morpion.
|
||||
|
||||
### Appliquer une matrice à l'intérieur d'une cellule
|
||||
|
||||
Sachant que chaque subdivision est une reproduction du motif original, nous pouvons appliquer une matrice de transformation pour déplacer, pivoter ou redimensionner l'espace dans chaque cellule.
|
||||
|
||||
<div class="codeAndCanvas" data="checks.frag"></div>
|
||||
|
||||
* Pensez à quelques façons intéressantes d'animer les couleurs et les formes de ce motif. Faites-en trois versions.
|
||||
|
||||
* Créez des motifs plus complexes en combinant plusieurs formes.
|
||||
|
||||
[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag)
|
||||
|
||||
* Combinez différentes couches de motifs pour composer votre propre [Tartan écossais](https://fr.wikipedia.org/wiki/Tartan).
|
||||
|
||||
[ ![Vector Pattern Scottish Tartan par Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076)
|
||||
|
||||
### Décaler les motifs
|
||||
|
||||
Imaginons que nous voulions reproduire un motif *mur de briques*. En regardant le mur, nous constatons que chaque rangées est décalée de moitié par rapport à la précédente.
|
||||
Comment pourrions-nous faire ça?
|
||||
|
||||
![](brick.jpg)
|
||||
|
||||
En premier lieu, nous devons savoir si la rangée sur laquelle se trouve notre fragment est paire ou impaire.
|
||||
Nous pourrons ensuite utiliser cette information pour savoir si on doit ou non se décaler sur l'axe X.
|
||||
|
||||
Pour déterminer si notre fragment est sur une ligne paire ou impaire, nous allons nous servir du résultat du modulo [```mod()```](../glossary/?search=mod) de ```2.0```.
|
||||
Si le modulo 2 est inférieur à 1, nous sommes sur une ligne paire, s'il est supérieur ou égal à 1, nous sommes sur une ligne impaire.
|
||||
|
||||
Pour illustrer l'effet du modulo, regardez la formule suivante et décommentez les deux dernières lignes.
|
||||
|
||||
<div class="simpleFunction" data="y = mod(x,2.0);
|
||||
// y = mod(x,2.0) < 1.0 ? 0. : 1. ;
|
||||
// y = step(1.0,mod(x,2.0));"></div>
|
||||
|
||||
On peut utiliser un [opérateur ternaire](https://fr.wikipedia.org/wiki/Op%C3%A9rateur_(informatique)) pour vérifier si le modulo ([```mod()```](../glossary/?search=mod)) renvoie une valeur inférieure à 1 (ligne 2)
|
||||
ou bien on peut se servir d'un [```step()```](../glossary/?search=step) qui renvoie le même résultat plus vite.
|
||||
|
||||
Pourquoi? Bien qu'il soit difficile de dire comment chaque carte graphique compile et optimise le code, on peut partir du principe que les fonctions natives sont plus rapides que les fonctions personnalisées.
|
||||
Chaque fois que vous pouvez utiliser une fonction native, faites le!
|
||||
|
||||
[NDT]En fait un opérateur ternaire est un ```if``` déguisé, le programme est obligé de créer et d'évaluer les deux branches du ```if``` ce qui ralentit son exécution. En l'occurrence, on pourrait écrire:
|
||||
```glsl
|
||||
y = floor( mod( x, 2.0 ) );
|
||||
```
|
||||
qui renverra également 0 si le modulo est inférieur à 1 et 1 si le modulo est compris entre 1 et 2. la différence étant qu'il n'y a besoin de charger qu'une seule valeur en mémoire contre 2 pour un step().
|
||||
on pourrait même se dispenser du ```floor``` en utilisant un ```cast``` (*transtypage*) en ```int``` (nombre entier):
|
||||
```glsl
|
||||
y = float( int( mod( x, 2.0 ) ) );
|
||||
```
|
||||
lorsqu'on *transtype* un ```float``` en ```int``` les chiffres après la virgule sont ignorés ce qui revient à appeler la méthode ```floor``` (en revanche, on doit re-caster le résultat en ```float```).
|
||||
[/NDT]
|
||||
|
||||
Maintenant que nous avons un moyen de déterminer si on a un chiffre pair ou impair, on peut s'en servir pour décaler les rangées impaires et obtenir notre *mur de briques*.
|
||||
Ligne 14, nous avons une fonction qui *détecte* les rangées impaires et leur ajoute un décalage de 0.5 en ```x```.
|
||||
Notez que pour les rangées paires, le résultat sera ```0.0``` et multiplier ```0.0``` par un décalage de ```0.5``` donnera un décalage de ```0.0```.
|
||||
Sur les rangées impaires, le résultat sera ```1.0``` qui, multiplié par ```0.5```, décalera la position ```st``` de ```0.5``` sur l'axe des ```x```.
|
||||
|
||||
Essayez à présent de commenter la ligne 32, cela va changer le *ratio* (rapport entre largeur et hauteur) et *étirer* les coorodnnées pour produire une brique *moderne*.
|
||||
En décommentant la ligne 40, on peut visualiser la distorsion grâce aux canaux rouge et vert.
|
||||
|
||||
<div class="codeAndCanvas" data="bricks.frag"></div>
|
||||
|
||||
* Essayez d'animer le motif en faisant varier la quantité de décalage en fonction du temps.
|
||||
|
||||
* Créez une autre animation où les rangées paires bougent vers la droite et les rangées impaires bougeant vers la gauche.
|
||||
|
||||
* Pouvez vous appliquer cet effet sur les colonnes?
|
||||
|
||||
* Essayez de combiner les décalages en ```x``` et ```y``` pour obtenir quelque chose comme ça:
|
||||
|
||||
<a href="../edit.php#09/marching_dots.frag"><canvas id="custom" class="canvas" data-fragment-url="marching_dots.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
## Pavage de Truchet
|
||||
|
||||
Maintenant que que nous avons vu comment déterminer si une cellule est sur une ligne ou une colonne paire ou impaire, il nous est possible de réutiliser un motif en fonction de sa position.
|
||||
Prenons le [pavage de Truchet](http://en.wikipedia.org/wiki/Truchet_tiles) [+](http://jean-luc.bregeon.pagesperso-orange.fr/Page%200-27.htm) où un élément simple est présent sous quatre formes:
|
||||
|
||||
![](truchet-00.png)
|
||||
|
||||
En changeant de motif d'une case à l'autre, on peut construire une infinité de pavages complexes.
|
||||
|
||||
![](truchet-01.png)
|
||||
|
||||
Regardez attentivement la fonction ```rotateTilePattern()```, qui subdivise l'espace en quatre cellules et assigne une rotation à chacune.
|
||||
|
||||
<div class="codeAndCanvas" data="truchet.frag"></div>
|
||||
|
||||
* Commentez / décommentez et dupliquez les lignes 69 à 72 pour composer de nouveaux motifs.
|
||||
|
||||
* Remplacez le triangle blanc par une autre forme: demi cercle, carré pivoté ou lignes.
|
||||
|
||||
* Créez d'autres motifs suivant la règle *pair/impair*.
|
||||
|
||||
* Variez les propriétés affectées par l'ordre *pair/impair* des cellules.
|
||||
|
||||
* Pensez à quelque chose d'autre qui ne soit pas nécessairement un pavage du plan et où vous pourriez appliquer les principes vus dans cette section (exemple: [les Hexagrammes YI Jing](https://fr.wikipedia.org/wiki/Hexagramme_Yi_Jing))
|
||||
|
||||
<a href="../edit.php#09/iching-01.frag"><canvas id="custom" class="canvas" data-fragment-url="iching-01.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
## Créer ses propres pavages
|
||||
|
||||
Créer des motifs procéduraux est un exercice cérébral consistant à trouver un ensemble minimal d'éléments réutilisables.
|
||||
C'est une pratique très ancienne, en tant qu'espèce, nous avons utilisé les grilles et les motifs pour décorer les textiles, les sols et les objets depuis la nuit des temps.
|
||||
Des frises grecques aux lattices chinoises, le plaisir des variations et des répétitions est une grande source d'inspiration.
|
||||
Prenez le temps de vous intéresser aux [motifs](https://www.pinterest.com/patriciogonzv/paterns/) [ornementaux](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up)
|
||||
et constatez que de tout temps, artistes et designers ont navigué entre un ordre prédictible et les variations, accidentelles et chaotiques.
|
||||
Des motifs islamiques aux textiles africains, nous disposons d'un univers de motifs à explorer.
|
||||
|
||||
![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png)
|
||||
|
||||
Ce chapitre clos le dessin algorithmique. Dans les chapitres suivants, nous apprendrons à ramener un peu d'entropie et à produire des designs génératifs.
|
@ -0,0 +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.
|
||||
|
||||
<div class="codeAndCanvas" data="grid-making.frag"></div>
|
||||
|
||||
È 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.
|
||||
|
||||
<div class="codeAndCanvas" data="checks.frag"></div>
|
||||
|
||||
* 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.
|
||||
|
||||
<div class="simpleFunction" data="y = mod(x,2.0);
|
||||
// y = mod(x,2.0) < 1.0 ? 0. : 1. ;
|
||||
// y = step(1.0,mod(x,2.0));"></div>
|
||||
|
||||
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.
|
||||
|
||||
<div class="codeAndCanvas" data="bricks.frag"></div>
|
||||
|
||||
* 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:
|
||||
|
||||
<a href="../edit.php#09/marching_dots.frag"><canvas id="custom" class="canvas" data-fragment-url="marching_dots.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
## 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.
|
||||
|
||||
<div class="codeAndCanvas" data="truchet.frag"></div>
|
||||
|
||||
* 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).
|
||||
|
||||
<a href="../edit.php#09/iching-01.frag"><canvas id="custom" class="canvas" data-fragment-url="iching-01.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
## 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.
|