5.2 KiB
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!
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:
-
Gli Shaders hanno una unica funzione
main
che alla fine restituisce un colore. Questa caratteristica è molto simile al linguaggio C. -
Il colore finale dei pixel viene assegnato a una variabile globale riservata
gl_FragColor
. -
Questo linguaggio è simile al C e ha variabili built-in (come
gl_FragColor
), funzioni e tipi. In questo esempio abbiamo introdottovec4
che è un vettore a virgola mobile(float) di quattro dimensioni. Più avanti incontreremo altri tipi comevec3
evec2
insieme ai più popolari:float
,int
ebool
. -
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 da0.0
a1.0
. In seguito, impareremo che normalizzare i valori rendere più facile mapparli fra le variabili. -
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 seGL_ES
è definito, chiamata che avviene soprattutto quando il codice viene compilato su dispositivi mobili e browser. -
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;
). -
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 deifloats
. 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:
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:
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:
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).