Parliamo ora di tutto quello che concerne il rendering di oggetti a schermo, partendo da una breve introduzione sulle mesh 3D e su come importarle, e passando al componente Renderer, che sta alla base di tutti gli oggetti 3D visibili in scena.
Le mesh 3D
Le mesh 3D sono l'oggetto più comune nei videogiochi che incorporano grafica 3D, e sono, nella loro versione più basica, delle griglie 3D composte da una serie di vertici, edge, e triangoli/poligoni. Nello specifico:
- i vertici sono punti nello spazio 3D;
- gli edge (o segmenti) sono le linee che li connettono fra loro;
- i poligoni sono le superfici che si vengono a formare quando 3 o più vertici vengono uniti da edge.
Alla base delle mesh 3D per videogiochi ci sono sempre poligoni triangolari (i triangles, o tris), quindi di fatto anche un quadrato si può pensare come formato da due triangoli che condividono un edge. Un semplice cubo è infatti una mesh composta da 6 quadrati (e corrispondenti 8 vertici, 12 edge), ma una volta importato in Unity diventeranno 12 triangoli (e quindi 18 edge). Questo vale per tutti gli engine ed è sempre da tenere a mente quando bisogna specificare la "risoluzione poligonale" di un modello per i videogame.
Questa è un esempio di una scena più elaborata, composta da diverse mesh 3D:
In quest'immagine è possibile vedere chiaramente la struttura dei vari oggetti. Nella fascia centrale, oltre alla griglia dei vertici abbiamo visualizzato anche le texture (e le luci che le influenzano), ma di texture parleremo fra un po'. Per visualizzare la griglia delle mesh 3D come sopra, si possono utilizzare le opzioni di visualizzazione che si trovano in alto nel pannello Scene View:
Opzioni | Descrizione |
---|---|
Textured | permette di vedere la scena in maniera molto simile a come sarà in gioco, con luci e texture applicate |
Wireframe | mostra solo la griglia dei poligoni (il wireframe, appunto) |
Textured Wire | mostra un misto dei due (come sopra, nella fascia centrale) |
Importare una mesh 3D
Per utilizzare mesh 3D in Unity esistono due modi: il più semplice è usare le primitive che Unity mette a disposizione, come il cubo, la sfera, il piano, il quad, ecc. Per usare mesh personalizzate, bisogna importare un file 3D creato in un programma di modellazione come 3D Studio Max, Maya, Blender, Modo, ecc. I formati importati da Unity sono molti (si possono vedere qui) ed in generale equivalenti (vale a dire, il grafico che li crea può usare quello che vuole).
L'unica distinzione importante da fare riguarda i file proprietari (come il .max di 3D Studio Max, il .mb di Maya, o il .blend di Blender) contro quelli esportati più comuni (come l'.fbx, l'.obj). I file esportati comuni sono in genere più leggeri e non contengono dati inutili, e più rapidi da importare. I file di tipo proprietario sono generalmente più pesanti da importare, creano a volte dei GameObject inutili in scena, e soprattutto richiedono una copia del software in cui sono stati creati. Nel momento in cui il file va importato, Unity aprirà il software in background per la conversione, aggiungendo tempo ogni volta che bisogna reimportare (è un'operazione abbastanza comune).
Una volta creato il file, basta piazzarlo in una cartella qualunque sotto /Assets
e Unity lo importerà. Selezionando il file nel pannello Project, possiamo vedere nell'Inspector le proprietà di importazione, e modificarle (e reimportare premendo Apply
):
Nell'immagine di sopra, un modello .fbx
di un personaggio è stato importato, e come tale nel pannello Project mostra, oltre che alla mesh contenuta (l'oggetto chiamato _Gooy_UNW
), anche le clip di animazione che il grafico ha prodotto ed esportato nel file (quelle col simbolo di play, Default Take
, GooyIdle1
, etc.).
A destra, possiamo vedere le opzioni di importazione, divise in tre tab (Model, Rig ed Animations). Lo Scale Factor indica la scala alla quale viene importato il modello: spesso la scala in modellazione varia di programma in programma, quindi con questa opzione possiamo correggerla per adattarla a quella di altri modelli del gioco.
NOTA: la scala di importazione non è la scala in-game, vale a dire che un modello come questo, importato con Scale Factor 0.01
, avrà comunque scala (1,1,1)
una volta messo in scena. Se scegliessimo uno Scale Factor 1
in fase di importazione, sarebbe 100 volte più grande pur rimanendo come scala di scena (1,1,1)
nel proprio Transform.
Altro parametro degno di nota è Normals & Tangents: le normali sono dei vettori che indicano la direzione "uscente" da un poligono. Nel rendering 3D, vengono usate per indicare dove 'guarda' una faccia, al fine di determinare diverse cose: l'angolo della luce, la smussatura fra due facce, etc.
Immagine da Wikipedia
Di solito le normali vengono create nei software di modellazione in automatico. In caso di problemi però, possiamo chiedere a Unity di 'indovinare' le normali della superfice, scegliendo Calculate
dal menu a tendina di Normals
. In generale quest'opzione è la migliore, ma così facendo perderemo qualsiasi smusso personalizzato che potremmo aver creato nel programma di modellazione 3D.
Ad esempio, in quest'immagine ci sono due modelli identici di una semplice tastiera, con opzioni di importazione differente:
Quella a sinistra conserva le normali create in Modo, che essendo state create appositamente senza smusso gli danno un aspetto "cubettoso", molto lowpoly.
Quella a destra è stata importata con le normals su Calculate, e lo slider Smoothing Angle su 180. Questo vuol dire che le normali delle facce che creano un angolo fino a 180° vengono ricalcolate per far sembrare le facce smussate. In questo caso, la tastiera assume un look morbido, smussato, quasi gommoso, perché le normali danno l'impressione che gli angoli fra i tasti siano stati ammorbiditi (anche se la struttura 3D è identica per entrambi i modelli).
Altre opzioni di importazione degne di nota:
- Mesh Compression permette a Unity di cambiare la geometria al fine di ottimizzare, eliminando vertici rimasti soli, o poligoni inutili. Può essere utile farlo, ma solo se le geometrie risultanti non risultano rotte o mostrano artefatti grafici, nel qual caso è meglio lasciarlo su
Off
. - Optimize Mesh riordina gli indici dei vertici e dei poligoni, per permettere delle performance leggermente migliori. Anche qui, se è possibile utilizzarlo e non dà problemi - bene. Se capita che il gioco vada in crash per motivi sconosciuti, provate a togliere la spunta a quest'opzione per vedere se il problema nasce da questo.
I componenti Mesh Filter e Mesh Renderer
Per visualizzare un oggetto, servono una combinazione di due componenti: Mesh Filter e Mesh Renderer.
Il Mesh Filter ha una sola funzione: selezionare una mesh (fra le primitive di base, e quelle importate) che sarà poi renderizzata dal Mesh Renderer. Se si clicca sul cerchietto nel campo Mesh
, verrà aperto un browser delle mesh presenti nel progetto:
In rosso sono evidenziate le primitive di Unity, che sono interne al motore e non possono essere modificate (se non nella scalatura).
Il Mesh Filter definisce la forma di un oggetto: di fatto, un GameObject non ha una forma intrinseca, ma dipende solo dalla mesh selezionata. Così, un oggetto che rappresenta una casa può diventare un pallone da calcio se viene selezionata un'altra mesh, e mantenere tutte le altre proprietà (scala, rotazione, posizione, ma anche altri componenti, script, ecc.).
Il Mesh Renderer, come detto, si occupa di disegnare a schermo la mesh selezionata nel Mesh Filter. L'inspector è composto da tre parti (Shadow
, Material
e Light Probe
) e si presenta così:
Dedicheremo ad ognuno di questi argomenti una lezione, la cosa importante da sapere è che il Renderer ha bisogno sempre di 1 o più Material per definire come disegnare l'oggetto.
I Material, che sono degli asset presenti nel progetto sotto forma di file .mat
, contengono tutta una serie di informazioni che nell'immagine di sopra sono visualizzate in basso sotto al componente Mesh Renderer (in questo caso il material si chiama Default
). È importante però notare che i Material non sono componenti, anche se li si potrebbe confondere come tali perché visualizzati nell'Inspector.
Essi sono proprietà del Mesh Renderer, infatti cliccando su quel Default nel campo Element 0
, e premendo Delete (o Canc su Windows), rimuoveremo il materiale dal renderer. Unity adesso non sa come disegnare quest'oggetto, e lo mostra con il tipico colore magenta del materiale mancante:
Si noti come anche il materiale Default sia sparito dall'Inspector (ma possiamo trovarlo nel pannello Project). Sarà possibile riassegnare il materiale cliccando sul cerchietto a fianco di Element 0
, e selezionando di nuovo Default dal pannello di selezione materiali (simile a quello delle mesh visto sopra).
Visto che un materiale è solo una proprietà del Mesh Renderer, di fatto più renderer possono condividere un materiale, che hanno quindi tutti le stesse proprietà (come una volta o un muro, entrambi di mattoni). È anche bene che lo facciano, perché facendo così permettiamo a Unity di disegnare in una sola passata più oggetti con lo stesso materiale (quest'operazione si chiama batching, e se ne può leggere in dettaglio qui), e questo ottimizza di molto l'operazione di rendering.
Esistono altri componenti deputati al rendering di altri tipi di oggetti (ClothRenderer, TrailRenderer) che spesso non hanno bisogno del MeshFilter, ma ne parleremo più avanti.