The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe

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


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)

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)

Prima ricordiamo la funzione fract(). Questa restituisce la parte frazionale di un numero, facendo in sostanza fract() il modulo di uno (mod(x,1.0)). In altre parole, 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:

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

Ma se ingrandiamo il sistema di coordinate, diciamo di tre volte, otterremo tre sequenze di interpolazioni lineari tra 0-1: la prima tra 0-1, la seconda per le virgole mobili tra 1-2 e la terza per le virgole mobili tra 2-3.

È arrivato il momento di disegnare qualcosa in ciascuno sottospazio, togliendo il commento alla riga 27 (Siccome stiamo moltiplicando sia in x sia in y, il rapporto di forma dello spazio non cambia e le forme saranno come previste).

Provate alcuni dei seguenti esercizi per capire meglio:

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.

Vector Pattern Scottish Tartan di Kavalenkava

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?

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() di 2.0 e poi vedremo se il risultato è inferiore a 1.0 o no. Osservate la formula seguente e togliete il commento alle ultime due righe.

Come potete vedere, usiamo un operatore ternario per controllare se il mod() di 2.0 sia al di sotto di 1.0 (seconda riga) o potremmo anche usare una funzione 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.

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, dove un singolo motivo può essere rappresentato in quattro modi diversi:

Cambiando il motivo lungo le tessere, è possibile costruire una serie infinita di motivi complessi.

Osservate più da vicino la funzione rotateTilePattern(), che suddivide lo spazio in quattro celle e assegna un angolo di rotazione a ciascuna di esse.

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 decorativi 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)

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.