Home/ Corsi/ Siti 3D con GSAP e WebGL/ Lezione 5: Materiali e luci

Lezione 5: Materiali, luci e texture

La distanza fra un cubo da tutorial e un oggetto che sembra vero la fanno tre righe. Roughness e metalness, l'ambiente che illumina da tutte le direzioni, lo spazio colore delle texture e il tone mapping.

Materiali, luci e texture in una scena 3D
Indice dei contenuti
Lezione 5 di 7 · Resa Teoria + Laboratorio + Mini-test

Obiettivi della lezione

Il cubo della Lezione 4 gira, e sembra un cubo di un tutorial. La distanza fra quello e un oggetto che sembra una cosa vera la fanno tre righe, non tre settimane. Questa lezione è quelle tre righe, più il perché.

Quando arrivi in fondo hai imparato a:

  • Usare roughness e metalness sapendo che cosa muovono;
  • Mettere un ambiente alla scena, che è il singolo cambiamento con la resa più alta;
  • Scegliere fra le luci quella che serve, e sapere quanto costano le ombre;
  • Caricare una texture senza sbagliare lo spazio colore;
  • Accendere il tone mapping e capire perché prima le luci alte «bruciavano».

Perché una scena appena montata sembra finta

Tre ragioni, e si risolvono in ordine inverso alla fatica che costano.

Non c'è niente attorno. Nel mondo vero un oggetto è illuminato da tutto: il muro, il pavimento, la finestra. Nella tua scena c'è una lampadina nel vuoto. È la ragione principale, e si toglie con due righe.

Le superfici sono perfette. Una plastica vera ha micrograffi, una vernice ha buccia d'arancia. roughness serve a questo, e quasi nessuno lo muove dal valore di partenza.

I colori escono dal tubo. Senza tone mapping i punti luminosi vanno a bianco netto e il resto resta piatto, come una foto scattata male.

roughness e metalness, che sono quasi tutto

MeshStandardMaterial lavora a modo suo, che si chiama PBR: invece di farti regolare venti manopole ti chiede com'è fatta la superficie nel mondo vero, e i conti li fa lui.

Cosametalnessroughness
Plastica lucida00,1 - 0,25
Plastica opaca, gomma00,6 - 0,9
Legno verniciato00,4
Alluminio spazzolato10,35
Cromo10,05
Ferro arrugginito10,8

La regola che serve saper leggere: metalness sta a 0 oppure a 1, e i valori in mezzo servono quasi solo dove un metallo è coperto da qualcos'altro, per esempio della vernice scrostata. Le mezze misure messe a caso danno quel colore plasticoso che non si capisce cos'è.

Un metallo senza ambiente è nero

Un metallo non ha colore suo: fa vedere quello che gli sta attorno. Se metti metalness: 1 in una scena con due luci e nient'altro, ottieni un oggetto scuro con due puntini. Non hai sbagliato niente: attorno non c'è niente da riflettere. Per questo la prossima sezione viene prima di qualunque altra cosa.

L'ambiente: le due righe che cambiano tutto

Three.js ha una stanza finta già pronta, fatta apposta per questo: quattro pareti, un pavimento e qualche luce. La trasformi in illuminazione d'ambiente e la appendi alla scena.

import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';

const pmrem = new THREE.PMREMGenerator(renderer);
scena.environment = pmrem.fromScene(new RoomEnvironment(), 0.04).texture;

Da quel momento ogni materiale standard della scena è illuminato da tutte le direzioni, i metalli riflettono qualcosa e le superfici lucide hanno dei riflessi allungati invece di due puntini. Provalo togliendo tutte le altre luci: quasi sempre la scena migliora.

PMREMGenerator prende quella stanza e la macina in una forma che i materiali sanno usare in fretta. Lo 0,04 è quanto sfocare: più alto vuol dire riflessi morbidi.

Quando vorrai un ambiente vero al posto della stanza finta, si carica un file HDR con RGBELoader e si mette nello stesso scena.environment. Il resto del codice non cambia, ed è il momento in cui una scena comincia davvero a sembrare una fotografia.

Le luci, e quanto costano

  • AmbientLight: aggiunge la stessa quantità di luce dappertutto. Non fa volume, serve solo a schiarire le ombre. Costa zero.
  • HemisphereLight: un colore da sopra e uno da sotto. Con due righe dà l'idea del cielo e del terreno. Costa quasi zero.
  • DirectionalLight: raggi paralleli, come il sole. È quella che dà il volume e le ombre nette.
  • PointLight e SpotLight: una lampadina e un faretto. Belle, e ognuna con l'ombra accesa costa parecchio.

Lo schema che funziona quasi sempre: l'ambiente fa il grosso, una direzionale dà la direzione, e basta. Tre o quattro luci in una scena da sito sono quasi sempre il segno che manca l'ambiente.

Le ombre, che si pagano a parte

renderer.shadowMap.enabled = true;
sole.castShadow = true;
sole.shadow.mapSize.set(1024, 1024);   // 2048 e' gia' caro, 512 spesso basta
cubo.castShadow = true;
pavimento.receiveShadow = true;

Ogni luce che proietta ombre fa ridisegnare la scena una volta in più, dal suo punto di vista. Due luci con le ombre vuol dire tre disegni per fotogramma invece di uno. Su un oggetto che gira in una pagina, quasi sempre l'ombra non serve: quello che serve è il volume, e quello lo dà l'ambiente.

Le texture, e l'errore che fanno tutti

const loader = new THREE.TextureLoader();

const colore = loader.load('/texture/legno-colore.jpg');
colore.colorSpace = THREE.SRGBColorSpace;   // ⚠️ SOLO sulla mappa del colore

const rugosita = loader.load('/texture/legno-roughness.jpg');
const normali  = loader.load('/texture/legno-normal.jpg');

const materiale = new THREE.MeshStandardMaterial({
  map: colore,
  roughnessMap: rugosita,
  normalMap: normali
});

Quella riga con colorSpace è l'errore più comune del mestiere, e si vede come un oggetto slavato o troppo scuro senza capire perché. La regola è secca: le mappe che contengono un colore vanno dichiarate sRGB, quelle che contengono dei numeri no. Colore ed emissione sono colori; rugosità, metallicità, normali e occlusione sono numeri, e trattarli come colori li storce.

Le tre mappe che rendono di più, in ordine: la normal, che dà il rilievo senza aggiungere un triangolo; la roughness, che fa variare la lucidità sulla superficie ed è quello che distingue un oggetto usato da uno appena modellato; la color, che è la più ovvia e da sola fa meno di quanto sembri.

Le texture sono il peso

Quattro mappe da 2048x2048 in JPG fanno qualche megabyte, e in memoria sulla scheda grafica occupano molto di più, perché lì stanno decompresse. Su un oggetto che in pagina è grande 500 pixel, 1024 basta e avanza. Nella Lezione 7 vediamo i formati compressi per la GPU, che è la risposta vera.

Il tone mapping

renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.0;   // la manopola dell'esposizione

Il calcolo della luce produce valori che vanno oltre il bianco dello schermo. Senza tone mapping quei valori vengono tagliati di netto: i riflessi diventano macchie bianche piatte e tutto il resto sembra spento. Con ACES vengono compressi come li comprime una pellicola, quindi i punti luminosi restano leggibili e conservano un po' di colore.

Cambia tutta la faccia della scena, e toneMappingExposure diventa la manopola con cui regoli il chiaro e lo scuro senza toccare le luci una per una.

Laboratorio: dal cubo del tutorial a un oggetto

Obiettivo: lo stesso oggetto della Lezione 4 che smette di sembrare un esercizio.

Consegna

  1. Fai la prova del metallo: metti metalness: 1, roughness: 0.15 sul tuo oggetto, senza ambiente. Guarda com'è scuro. Poi aggiungi le due righe dell'ambiente e guarda di nuovo. È il confronto che spiega la lezione.
  2. Togli tutte le luci lasciando solo l'ambiente. Quasi sempre è già meglio di prima. Poi rimetti una sola direzionale per dare la direzione.
  3. Accendi il tone mapping e muovi toneMappingExposure fra 0,6 e 1,6 finché la scena non ti convince.
  4. Percorri la tabella dei materiali: prova il tuo oggetto come plastica opaca, alluminio e cromo, tenendo tutto il resto fermo.
  5. Metti una normal map presa da un archivio libero e guarda il rilievo comparire senza un triangolo in più. Poi dichiarala per sbaglio come SRGBColorSpace e guarda come si sporca: così quell'errore lo riconosci a vista.
  6. Prova le ombre e misura i fotogrammi al secondo prima e dopo, con mapSize a 512, 1024 e 2048.

Risultato atteso

Due schermate a confronto, prima e dopo, e tre numeri sul costo delle ombre. Se dopo tutto questo l'oggetto sembra ancora finto, il problema non è più l'illuminazione: è il modello, che ha spigoli troppo perfetti. Nel mondo vero non esiste uno spigolo vivo, e un piccolo raccordo su ogni bordo è la cosa che il tuo occhio cerca senza saperlo.

Mini-test di autoverifica

Istruzioni

Sezione A: 6 domande a risposta multipla (1 punto). Sezione B: 2 domande aperte (3 punti). Totale 12. Soglia: 60% (8/12).

Sezione A: risposta multipla

  1. metalness di solito vale:
    a) un valore a caso fra 0 e 1   b) 0 oppure 1   c) sempre 0,5   d) dipende dal colore
  2. Un oggetto con metalness: 1 e nessun ambiente appare:
    a) bianco   b) scuro, con qualche puntino   c) uguale a prima   d) trasparente
  3. scena.environment serve a:
    a) mettere uno sfondo   b) illuminare da tutte le direzioni   c) caricare i modelli   d) fare le ombre
  4. colorSpace = THREE.SRGBColorSpace va messo:
    a) su tutte le texture   b) solo su quelle che contengono un colore   c) solo sulle normal map   d) mai
  5. Una luce con le ombre accese:
    a) costa come le altre   b) fa ridisegnare la scena una volta in più   c) rallenta solo il caricamento   d) non si può fare in WebGL
  6. Senza tone mapping, i punti luminosi:
    a) spariscono   b) diventano macchie bianche piatte   c) diventano neri   d) lampeggiano

Sezione B: risposta aperta

  1. (3 punti) Descrivi il materiale del tuo oggetto con metalness, roughness e le mappe che useresti, e di' a che cosa somiglia nel mondo vero.
  2. (3 punti) Spiega perché l'ambiente cambia la scena più di quanto la cambi aggiungere una terza luce.
Mostra risposte corrette

Sezione A

  1. b: 0 o 1; le mezze misure servono dove un metallo è coperto.
  2. b: scuro, perché un metallo fa vedere quello che ha attorno e attorno non c'è niente.
  3. b: illumina da tutte le direzioni, come le pareti di una stanza.
  4. b: solo colore ed emissione; rugosità, normali e metallicità sono numeri.
  5. b: la scena viene ridisegnata dal punto di vista della luce.
  6. b: vengono tagliati di netto e diventano bianco piatto.

Sezione B, risposte modello

7. Esempio: scocca in plastica opaca, metalness: 0, roughness: 0.7, con una normal map leggera per la grana e una roughness map per le zone consumate dalle mani. Somiglia al corpo di un elettrodomestico, dove la plastica vicino ai pulsanti è più lucida per l'uso.

8. Perché una terza luce aggiunge un'altra sorgente puntiforme, cioè un altro riflesso isolato, mentre l'ambiente dà luce da tutte le direzioni: è quello che succede davvero in una stanza, dove un oggetto è illuminato dal muro e dal pavimento. I metalli e le superfici lucide hanno bisogno di qualcosa da riflettere, e una luce puntiforme da riflettere offre un punto.

Valutazione (su 12)

  • 11-12: ottimo. 8-10: sufficiente. < 8: rifai la prova del metallo con e senza ambiente.

Riassunto della lezione

Cosa hai imparato

  • Una scena sembra finta perché non ha niente attorno, ha superfici perfette e nessun tone mapping.
  • metalness sta a 0 o a 1; roughness è la manopola che si muove davvero.
  • L'ambiente è il cambiamento con la resa più alta, e sono due righe.
  • Le ombre si pagano a parte, e su un oggetto in pagina quasi sempre non servono.
  • Lo spazio colore va dichiarato solo sulle mappe di colore.
  • ACES più esposizione danno la manopola con cui regoli tutta la scena.

Prossimi passi

Nella Lezione 6, Il 3D che segue lo scorrimento si chiude il cerchio: la scena della Lezione 4 vestita come nella 5, comandata dal dito con gli strumenti della 3. È il sito 3D vero e proprio.

Lo stesso lavoro, sul tuo progetto, in aula

Si parte dal modello che hai già, si monta la scena e si misura: quello che esce si può pubblicare.

Guarda le date
Federico BoggiaRispondo io, in giornata

Ciao! Dimmi che ti serve: un corso online, un workshop di AI in aula a Livorno o la formazione per la tua azienda.

Scrivimi su WhatsApp