Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Introduzione agli shader

Questa pagina spiega cosa sono gli shader e fornisce una panoramica del loro funzionamento in Godot. Per un riferimento dettagliato al linguaggio di shading del motore, consultare Linguaggio di shading.

Gli shader sono un tipo speciale di programma che gira sulle unità di elaborazione grafica (GPU). Inizialmente erano utilizzati per ombreggiare scene 3D, ma oggi possono fare molto di più. È possibile utilizzarli per controllare il modo in cui il motore disegna geometrie e pixel sullo schermo, permettendo di ottenere effetti di ogni tipo.

I motori di rendering moderni come Godot disegnano tutto tramite shader: le schede grafiche possono eseguire migliaia di istruzioni in parallelo, ottenendo velocità di rendering incredibili.

A causa della loro natura parallela, tuttavia, gli shader non elaborano le informazioni come fa un tipico programma. Il codice di shader è eseguito su ogni vertice o pixel in maniera isolata. Non è possibile memorizzare dati tra i frame. Pertanto, quando si lavora con gli shader, è necessario programmare e pensare in modo diverso rispetto agli altri linguaggi di programmazione.

Supponiamo di voler aggiornare tutti i pixel di una texture con un determinato colore. In GDScript, il codice utilizzerebbe cicli for:

for x in range(width):
    for y in range(height):
        set_color(x, y, some_color)

Il tuo codice fa già parte di un ciclo in uno shader, quindi il codice corrispondente avrà questo aspetto.

void fragment() {
    COLOR = some_color;
}

Nota

La scheda grafica richiama la funzione fragment() una o più volte per ogni pixel che deve disegnare. Ne riparleremo più avanti.

Shader in Godot

Godot fornisce un linguaggio di shading basato sul popolare OpenGL Shading Language (GLSL), ma semplificato. Il motore gestisce parte del lavoro di inizializzazione di basso livello, il che facilita la scrittura di shader complessi.

In Godot, gli shader sono composti da funzioni principali chiamate "funzioni di processore". Le funzioni di processore rappresentano il punto di ingresso dello shader nel programma. Esistono sette diverse funzioni di processore.

  1. La funzione vertex() è eseguita su tutti i vertici della mesh e ne imposta la posizione e altre variabili per ogni vertice. Utilizzata negli shader canvas_item e negli shader spatial.

  2. La funzione fragment() è eseguita per ogni pixel coperto dalla mesh. Utilizza i valori generati dalla funzione vertex(), interpolati tra i vertici. Utilizzata negli shader canvas_item e negli shader spatial.

  3. La funzione light() è eseguita per ogni pixel e per ogni luce. Prende le variabili dalla funzione fragment() e dalle sue esecuzioni precedenti. Utilizzata negli shader canvas_item e negli shader spatial.

  4. La funzione start() è eseguita una volta per ogni particella in un sistema di particelle quando la particella viene generata. Utilizzata negli shader di particelle.

  5. La funzione process() è eseguita per ogni particella in un sistema di particelle a ogni frame. Utilizzata negli shader di particelle.

  6. La funzione sky() è eseguita per ogni pixel nella cubemap di radianza quando è necessario aggiornarla e per ogni pixel sullo schermo attuale. Utilizzata negli shader del cielo.

  7. La funzione fog() è eseguita per ogni froxel nel buffer dei froxel della nebbia volumetrica che interseca un FogVolume. Utilizzata dagli shader della nebbia.

Avvertimento

La funzione light() non sarà eseguita se la modalità di rendering vertex_lighting è abilitata o se Rendering > Quality > Shading > Force Vertex Shading è abilitata nelle Impostazioni del progetto. È abilitata in modo predefinito sulle piattaforme mobili.

Nota

Godot espone anche un'API che consente agli utenti di scrivere shader GLSL totalmente personalizzati. Per maggiori informazioni, consultare Using compute shaders.

Tipi di shader

Invece di fornire una configurazione generica per tutti gli usi (2D, 3D, particelle, cielo, nebbia), è necessario specificare il tipo di shader che si sta scrivendo. Diversi tipi supportano diverse modalità di rendering, variabili integrate e funzioni di elaborazione.

In Godot, tutti gli shader devono specificare il loro tipo nella prima riga, così:

shader_type spatial;

Ecco i tipi disponibili:

Modalità di rendering

Gli shader hanno modalità di rendering opzionali che si possono specificare sulla seconda riga, dopo il tipo di shader, così:

shader_type spatial;
render_mode unshaded, cull_disabled;

Le modalità di rendering alterano il modo in cui Godot applica lo shader. Ad esempio, la modalità unshaded fa ignorare al motore la funzione integrata di processore della luce.

Ogni tipo di shader ha diverse modalità di rendering. Consultare il riferimento di ogni tipo di shader per una lista completa delle modalità di rendering.

Processore di vertici

La funzione di elaborazione vertex() è chiamata una volta per ogni vertice negli shader spatial e canvas_item.

Ogni vertice nella geometria del mondo ha proprietà come posizione e colore. La funzione modifica questi valori e li passa alla funzione fragment. Si può anche usare per inviare dati aggiuntivi alla funzione fragment attraverso i varying.

Normalmente, Godot trasforma automaticamente le informazioni sui vertici, necessarie per proiettare la geometria sullo schermo. È possibile utilizzare certe modalità di rendering per trasformare manualmente i dati; consultare il documento sugli shader spatial per un esempio.

Processore di frammenti

La funzione di elaborazione fragment() è utilizzata per impostare i parametri del materiale Godot per pixel. Questo codice è eseguito su ogni pixel visibile disegnato dall'oggetto o dalla primitiva. È disponibile solo negli shader spatial e canvas_item.

L'uso standard della funzione fragment è quello di impostare le proprietà del materiale che saranno usate per calcolare l'illuminazione. Per esempio, si impostano i valori per ROUGHNESS, RIM, o TRANSMISSION che indicano alla funzione light come le luci rispondono a quel frammento. Questo rende possibile controllare una pipeline di shading complessa senza richiedere molto codice dall'utente. Se non c'è bisogno di questa funzionalità integrata, è possibile ignorarla e scrivere la propria funzione di elaborazione delle luci e Godot la ottimizzerà. Per esempio, se RIM non è impostato, Godot non calcolerà l'illuminazione sul bordo. Durante la compilazione, Godot verifica se RIM è utilizzato; se non, taglia fuori tutto il codice corrispondente. Pertanto, non si sprecheranno calcoli sugli effetti non usati.

Processore di luce

Anche il processore light() è eseguito per pixel, una volta per ogni luce che influenza l'oggetto. Non è eseguito se nessuna luce influenza l'oggetto. Esiste come funzione richiamata all'interno del processore fragment() e in genere opera in base alle proprietà del materiale configurate all'interno della funzione fragment().

Il processore light() funziona diversamente in 2D rispetto a 3D; per una descrizione di come funziona in entrambi, consultare la loro documentazione shader CanvasItem e shader Spatial, rispettivamente.