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.
Checking the stable version of the documentation...
Il tuo primo shader 2D
Introduzione
Gli shader sono programmi speciali che vengono eseguiti sulla GPU e utilizzati per renderizzare la grafica. Tutto il rendering moderno è eseguiti con gli shader. Per una descrizione più dettagliata degli shader, consultare Cosa sono gli shader.
Questo tutorial si concentrerà sugli aspetti pratici della scrittura di programmi shader, guidandoti attraverso il processo di scrittura di uno shader con funzioni vertex e fragment. Questo tutorial è rivolto ai principianti assoluti nel campo degli shader.
Nota
Se hai esperienza nella scrittura di shader e stai semplicemente cercando una panoramica di come funzionano gli shader in Godot, consulta Shading Reference.
Configura
Gli shader CanvasItem servono per disegnare tutti gli oggetti 2D in Godot, mentre gli shader Spatial servono per disegnare tutti gli oggetti 3D.
Per utilizzare uno shader, questo deve essere associato a un materiale, che a sua volta deve essere associato a un oggetto. I materiali sono un tipo di risorsa. Per disegnare più oggetti con lo stesso materiale, il materiale deve essere associato a ciascun oggetto.
Tutti gli oggetti derivati da un CanvasItem hanno una proprietà materiale. Questa include tutti gli elementi GUI, Sprite2D, TileMapLayer, MeshInstance2D ecc. Hanno anche un'opzione per ereditare il materiale del nodo padre. Questo può essere utile se si dispone di un numero elevato di nodi che si desidera utilizzino lo stesso materiale.
Per cominciare, crea un nodo Sprite2D. Puoi usare qualsiasi CanvasItem, purché venga disegnato sul canvas. Per questo tutorial useremo uno Sprite2D, poiché è il CanvasItem più semplice con cui iniziare a disegnare.
Nell'Ispettore, clicca accanto a "Texture" dove c'è scritto "[empty]" e seleziona "Load", quindi seleziona "icon.svg". Per i nuovi progetti, questa è l'icona di Godot. Ora dovresti vedere l'icona nella viewport.
Quindi, guarda in basso nell'Ispettore, nella sezione CanvasItem, clicca accanto a "Material" e seleziona "Nuovo ShaderMaterial". Questo crea una nuova risorsa Materiale. Clicca sulla sfera che appare. Godot al momento non sa se stai scrivendo uno shader CanvasItem o uno shader Spatial e mostra in anteprima il risultato degli shader Spatial. Perciò quel che vedi è il risultato dello shader Spatial predefinito.
Nota
I materiali che ereditano dalla risorsa Material, come StandardMaterial3D e ParticleProcessMaterial, si possono convertire in un ShaderMaterial e le loro proprietà esistenti saranno convertite in uno shader di testo corrispondente. Per farlo, fai clic destro sul materiale nel pannello FileSystem e scegli Converti in ShaderMaterial. Puoi anche fare clic destro su qualsiasi proprietà che contenga un riferimento al materiale nell'ispettore.
Fai clic su "Shader" e seleziona "Nuovo Shader". Infine, fai clic sullo shader appena creato e si aprirà l'editor. Ora sei pronto per cominciare a scrivere il tuo primo shader.
Il tuo primo shader CanvasItem
In Godot, tutti gli shader iniziano con una riga che specifica il tipo di shader. Il formato utilizzato è il seguente:
shader_type canvas_item;
Poiché stiamo scrivendo uno shader CanvasItem, specifichiamo canvas_item nella prima riga. Tutto il nostro codice andrà sotto questa dichiarazione.
Questa riga indica al motore quali variabili e funzionalità integrate fornirti.
In Godot è possibile sovrascrivere tre funzioni per controllare il funzionamento dello shader: vertex, fragment e light. Questo tutorial ti guiderà nella scrittura di uno shader con funzioni sia di vertice sia di frammento. Le funzioni di luce sono vastamente più complesse delle funzioni di vertice e frammento e pertanto non saranno trattate in questo articolo.
La tua prima funzione fragment
La funzione fragment viene eseguita per ogni pixel in uno Sprite2D e determina il colore che dovrebbe avere quel pixel.
Sono limitati ai pixel coperti dallo Sprite2D, il che significa che non è possibile utilizzarne uno, ad esempio, per creare un contorno attorno a uno Sprite2D.
La funzione di frammento più basilare non fa altro che assegnare un singolo colore a ogni pixel.
Lo facciamo scrivendo vec4 nella variabile integrata COLOR. vec4 è un'abbreviazione per costruire un vettore con 4 numeri. Per maggiori informazioni sui vettori, consulta il tutorial sulla matematica vettoriale. COLOR è sia una variabile di input per la funzione fragment, sia il suo risultato finale.
void fragment(){
COLOR = vec4(0.4, 0.6, 0.9, 1.0);
}
Congratulazioni! Hai finito. Hai scritto con successo il tuo primo shader in Godot.
Ora rendiamo le cose più complesse.
Ci sono molti input nella funzione fragment che puoi usare per calcolare COLOR. UV è uno di questi. Le coordinate UV sono specificate nel tuo Sprite2D (senza che tu lo sappia!) e indicano allo shader dove leggere le texture per ogni parte della mesh.
Nella funzione fragment è possibile leggere solo da UV, ma si può usare in altre funzioni o per assegnare valori direttamente a COLOR.
UV varia tra 0-1 da sinistra a destra e dall'alto al basso.
void fragment() {
COLOR = vec4(UV, 0.5, 1.0);
}
Utilizzare la TEXTURE integrata
La funzione fragment predefinita legge la texture impostata dello Sprite2D e la visualizza.
Quando vuoi regolare un colore in uno Sprite2D puoi regolarlo manualmente dalla texture, come nel codice seguente.
void fragment(){
// This shader will result in a blue-tinted icon
COLOR.b = 1.0;
}
Alcuni nodi, come Sprite2D, hanno una variabile texture dedicata a cui è possibile accedere nello shader tramite TEXTURE. Se si desidera utilizzare la texture dello Sprite2D per combinarla con altri colori, è possibile utilizzare gli UV con la funzione texture per accedere a questa variabile. Utilizzali per ridisegnare lo Sprite2D con la texture.
void fragment(){
COLOR = texture(TEXTURE, UV); // Read from texture again.
COLOR.b = 1.0; //set blue channel to 1.0
}
Input uniforme
L'input uniforme serve per passare dati in uno shader che saranno gli stessi in tutto lo shader.
È possibile utilizzare le uniformi definendole in alto allo shader così:
uniform float size;
Per maggiori informazioni sull'uso vedi Shading Language doc.
Aggiungi un'uniforme per cambiare l'intensità del blu nel nostro Sprite2D.
uniform float blue = 1.0; // you can assign a default value to uniforms
void fragment(){
COLOR = texture(TEXTURE, UV); // Read from texture
COLOR.b = blue;
}
Ora puoi modificare l'intensità del blu nello Sprite2D dall'editor. Ritorna all'Ispettore sotto cui hai creato lo shader. Dovresti vedere una sezione chiamata "Parametri di shader". Espandi quella sezione e vedrai l'uniforme che hai appena dichiarato. Se modifichi il valore nell'editor, sovrascriverà il valore predefinito che hai fornito nello shader.
Interagire con gli shader da codice
È possibile modificare le uniformi da codice attraverso la funzione set_shader_parameter(), che si chiama sulla risorsa materiale del nodo. Con un nodo Sprite2D, è possibile utilizzare il codice seguente per impostare l'uniforme blue.
var blue_value = 1.0
material.set_shader_parameter("blue", blue_value)
var blueValue = 1.0;
((ShaderMaterial)Material).SetShaderParameter("blue", blueValue);
Nota che il nome dell'uniforme è una stringa. La stringa deve corrispondere esattamente a come è scritta nello shader, inclusi ortografia e maiuscole/minuscole.
La tua prima funzione vertex
Ora che abbiamo una funzione fragment, scriviamo una funzione vertex.
Utilizzare la funzione vertex per calcolare dove sullo schermo dovrebbe trovarsi ogni vertice.
La variabile più importante nella funzione vertex è VERTEX. Inizialmente, specifica le coordinate dei vertici nel modello, ma è anche possibile scriverci sopra per determinare dove effettivamente disegnare quei vertici. VERTEX è un vec2 che viene inizialmente presentato nello spazio locale (ovvero non relativo alla telecamera, alla viewport o ai nodi padre).
È possibile compensare i vertici aggiungendo direttamente a VERTEX.
void vertex() {
VERTEX += vec2(10.0, 0.0);
}
In combinazione con la variabile integrata TIME, si può usare per animazioni basilari.
void vertex() {
// Animate Sprite2D moving in big circle around its location
VERTEX += vec2(cos(TIME)*100.0, sin(TIME)*100.0);
}
Conclusione
In sostanza, gli shader fanno quello che hai visto finora: calcolano VERTEX e COLOR. Sta a te immaginare strategie matematiche più complesse per assegnare valori a queste variabili.
Per trovare ispirazione, dai un'occhiata ad alcuni dei tutorial più avanzati sugli shader e ad altri siti come Shadertoy e The Book of Shaders.