Funzioni di modellazione
La logica dello shader è speciale, è diversa da quella a cui siamo abituati in JavaScript o in altri linguaggi di programmazione. Mentre la sintassi è simile, il modo in cui implementiamo la logica è differente. È un po' come una scatola nera, si inseriscono dei dati e si ottengono dei colori per il fragment shader, o delle posizioni per il vertex shader.
Ma come si controlla l'output? Come si fa a farlo sembrare come si desidera? È qui che entrano in gioco le funzioni di modellazione.
Ci concentreremo sul fragment shader per questa lezione, ma gli stessi principi si applicano al vertex shader.
Zona di pratica
Per padroneggiare l'arte della modellazione, sarà necessario praticare e sperimentare. Ci vorrà del tempo per abituarsi al modo in cui funziona lo shader, ma una volta che avrai preso la mano, sarai in grado di creare effetti sorprendenti.
Poiché voglio metterti nella migliore posizione per avere successo, ho preparato questa scena di una Galleria d'Arte 3D per visualizzare i tuoi shader in tempo reale in un ambiente gradevole.
Riesci a sentire la tua creatività fluire? Tutte quelle cornici vuote stanno aspettando i tuoi capolavori!
Il modello 3D utilizzato è VR Gallery di Maxim Mavrichev ed è concesso in licenza sotto Creative Commons Attribution.
Ho utilizzato <CameraControls />
per creare una telecamera in prima persona per navigare all'interno della galleria e Squoosh per ridurre le dimensioni delle texture.
SimpleShaderMaterial
Tutte le cornici della galleria sono copie del SimpleShaderMaterial
, è uno shader personalizzato di base che ho preparato per te con:
uColor
: un coloreuTime
: il tempo trascorso dall'inizio dell'applicazionevUv
: le coordinate UV del frammento (da 0 a 1 su entrambi gli assi)
Sono tutte estese nel <App.jsx />
per poterle usare dichiarativamente nella nostra scena.
Sono nominate in base alla loro posizione nella galleria, ma sentiti libero di rinominarle in modo più significativo una volta che avrai creato dei capolavori con esse!
Funzioni
Per ogni frammento del nostro shader, il nostro stesso codice verrà eseguito con input differenti.
Se volessimo disegnare una linea, potremmo utilizzare istruzioni if per verificare se il pixel è all'interno della linea o no. Ma realizzare forme più complesse sarebbe molto difficile e inefficiente.
Invece, utilizziamo le funzioni per modellare il nostro output. Non preoccuparti, non è necessario essere esperti di matematica per usarle. Devi solo capire quali funzioni hai a disposizione e cosa fanno.
Pensa a una funzione come a una macchina che prende un input e ti fornisce un output. Ad esempio, la funzione
f(x) = x * 2
prende un numerox
e ti restituiscex * 2
come risultato.
Per visualizzare l'effetto delle diverse funzioni, useremo Graphtoy, un semplice strumento per digitare funzioni e vederne l'output. Aiuta a convalidare la nostra comprensione delle funzioni quando le sperimentiamo nei nostri shader.
Visualizziamo la nostra funzione f(x) = x * 2
in Graphtoy:
Graphtoy diventerà rapidamente il tuo miglior amico quando sperimenti con gli shader.
È ora di sperimentare con le diverse funzioni a nostra disposizione.
Step
La funzione step è una funzione semplice che restituisce 0
se l'input è inferiore a una soglia e 1
se l'input è superiore alla soglia.
Prende due parametri:
edge
: la sogliax
: il valore di input
Proviamola nel framment shader del front frame ArtFront02Material.jsx
:
void main() { float pct = 1.0; pct = step(0.5, vUv.x); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Dichiariamo una variabile pct
per determinare la percentuale del colore che vogliamo visualizzare. La impostiamo a 1.0
di default, e poi usiamo la funzione step
per impostarla a 0.0
se vUv.x
è minore di 0.5
.
Possiamo vedere che la metà sinistra del frame è nera, mentre la metà destra è del colore impostato nell'uniform uColor
.
Applichiamola all'asse verticale con una soglia diversa:
void main() { float pct = 1.0; pct = step(0.2, vUv.y); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Possiamo vedere che il 20% della parte inferiore del frame è nero, mentre il resto è viola.
Le coordinate UV hanno origine nell'angolo in basso a sinistra del frame, quindi
[0, 0]
è l'angolo in basso a sinistra e[1, 1]
è l'angolo in alto a destra.
Se vuoi invertire l'effetto, puoi semplicemente scambiare i parametri della funzione step
:
void main() { float pct = 1.0; pct = step(vUv.y, 0.2); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Ora abbiamo l'effetto opposto.
Mix
La funzione mix è una semplice funzione che restituisce un'interpolazione lineare tra due valori.
Prende tre parametri:
x
: il primo valorey
: il secondo valorea
: il valore da interpolare trax
ey
Proviamolo:
void main() { float pct = 1.0; pct = mix(0.0, 1.0, vUv.x); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Possiamo vedere un bel gradiente dal nero al viola.
Come molte altre funzioni, puoi usarla su altri tipi di dati, come i componenti del vettore. Utilizziamola per creare un gradiente dal bianco al viola sull'asse verticale:
void main() { vec3 whiteColor = vec3(1.0); vec3 finalColor = mix(whiteColor, uColor, vUv.y); gl_FragColor = vec4(finalColor, 1.0); }
Possiamo vedere un bel gradiente dal bianco al viola.
Cambiamo il valore di interpolazione chiamando la funzione mix
una prima volta per ottenere il valore pct
, e poi usiamolo per interpolare tra il whiteColor
e il uColor
:
void main() { vec3 whiteColor = vec3(1.0); float pct = mix(0.0, 0.3, vUv.y); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
Il viola è molto chiaro poiché il valore massimo di pct
è 0.3
.
Usa Graphtoy per sperimentare con la funzione mix
e capire come funziona.
3 interpolazioni diverse con la funzione mix
danno risultati completamente diversi.
Smoothstep
La funzione smoothstep è una funzione semplice che restituisce un'interpolazione morbida tra due valori.
Essa accetta tre parametri:
edge0
: il limite inferioreedge1
: il limite superiorex
: il valore da interpolare traedge0
eedge1
Fornisce tre diversi risultati:
0.0
sex
è minore diedge0
1.0
sex
è maggiore diedge1
- un'interpolazione morbida tra
0.0
e1.0
sex
è compreso traedge0
eedge1
Utilizziamola per cambiare il nostro valore pct
:
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
La transizione è ora solo tra 0.4
e 0.6
. Tutto ciò che è al di sotto è bianco, e tutto ciò che è al di sopra è viola.
Min & Max
min
e max
sono funzioni semplici che restituiscono il valore minimo o massimo tra due input. Funzionano esattamente come le funzioni Math.min
e Math.max
in JavaScript.
Usiamole per regolare finemente il valore pct
. Iniziamo assicurandoci che non sia mai inferiore a 0.4
(il che significa mai totalmente bianco):
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); pct = max(pct, 0.4); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
E mai superiore a 0.6
(il che significa mai totalmente viola):
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); pct = max(pct, 0.4); pct = min(pct, 0.6); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
I colori sono attenuati e la transizione è molto fluida.
Visualizziamolo su Graphtoy:
Rappresentazione di max(x, 0.4)
Rappresentazione di min(x, 0.6)
E se li combiniamo:
Puoi vedere che i nostri valori non scendono mai sotto 0.4
e non superano mai 0.6
.
La nostra combinazione di funzioni
min
emax
può essere sostituita dalla funzione clamp, che è una scorciatoia permin(max(x, min), max)
.
Operazioni e pattern
Prima di scoprire molte altre funzioni utili, vediamo come possiamo usare le operazioni per creare pattern.
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.