Creare il
fianco di una montagna - Node displacement
by Gabriele
Rescaldani aka vashts
Questo tutorial fornisce un esempio da seguire passo
passo per iniziare a prendere confidenza con il nuovo Node
Editor di LightWave v9; in particolare, si farà
uso di quello fornito per il displacement degli oggetti.
1) Creazione dell'oggetto nel Modeler
Aprendo il Modeler,
creiamo un semplice oggetto che sarà la base per
il nostro displacement. Ognuno crei la forma che ha in mente:
io ho riprodotto a grandi linee il pendio di una montagna,
semplificandolo al massimo. L'unica considerazione da seguire
è quella di creare un oggetto con un discreto numero
di suddivisioni poligonali, create con gli strumenti che
si prefesce (Knife, Julienne,
Bandsaw, ...).
In seguito, scegliamo Catmull-Clark
come SubD-Type (in basso
a destra) e convertiamo il nostro oggetto in superifici
di suddivisione mediante il tasto Tab della tastiera.
| Nota: la scelta delle Catmull-Clark
non è obbligatoria; si tenga però presente
che il livello di suddivisione delle Catmull-Clark sale
molto più rapidamente rispetto a quello delle
Subpatch classiche, che richiedono quindi alti valori
per pareggiare quelli delle nuove SubD. |
Ecco come si presenta l'oggetto da me creato:

Figura 1: la mesh nel Modeler in versione poligonale e suddivisa
con Catmull-Clark SubD
2) Caricamento dell'oggetto, posizionamento
e alcune operazioni preliminari
Dopo aver salvato l'oggetto, passiamolo al Layout
e chiudiamo pure il Modeler
(non ne avremo più bisogno). A seconda di quello
che avete creato, posizionate oggetto e telecamera in modo
che il primo riempia la visuale, preoccupandosi di lasciare
un po' di geometria fuori dall'inquadratura: questo perchè
il displacement potrebbe deformare la mesh a tal punto da
spostare i poligoni e lasciare degli spazi vuoti nel nostro
render.
Ecco come si presenta nel mio caso la viewport OpenGL in
Wireframe:

Figura 2: l'oggetto posizionato senza displacement visto
dalla telecamera
Ora selezioniamo il nostro oggetto, apriamo le proprietà
(tasto p) ed aumentiamo
nel tab Geometry il Display
SubPatch Level a 4,
così da osservare meglio in realtime le deformazioni
che andremo ad applicare. Passando al tab Deform,
attiviamo il check di fianco a Edit
Nodes, quindi clicchiamo sul pulsante: si aprirà
quindi il Node Editor con
già un nodo presente, quello di Displacement,
ovvero quello che si occupa di ricevere le deformazioni
da applicare alla mesh (ha infatti solo un campo di input).
Un procedimento di base da effettuare ogni qual volta vogliamo
fare Normal Displacement, ovvero deformazioni che si propagano
sulla normale di ogni poligono (e non quindi su un asse
predefinito come X, Y o Z), è quello di aggiungere
2 nodi: Spot Info e Scale.
Spot Info (Add
Node > Spot >
Spot Info) fornisce i dati
sulla mesh corrente; in particolare, a noi servirà
quello relativo alle normali del nostro oggetto (output
Normal).
Scale (Add Node > Math > Vector > Scale) è
invece una funzione matematica che consente di scalare un
vettore tramite un valore numerico: nel nostro caso, i vettori
saranno le normali dell'oggetto e i valori numerici saranno
invece forniti dalle mappe di displacement, le quali producono
sia valori di colore (che noi ignoreremo) che valori scalari
(ovvero numeri, che a loro volta possono essere visti come
le tonalità di grigio che vanno dal nero, valore
0.0, al bianco, valore
1.0).
Colleghiamo quindi l'output Normal
del nodo Spot Info all'input
Vector del nodo Scale;
l'output Result di quest'ultimo
lo colleghiamo invece all'input Input
del nodo Displacement:
siamo così pronti (Figura
3) per applicare le nostre deformazioni, le quali
andranno tutte nell'input Scale
del nodo omonimo.

Figura 3: il Node Editor dopo
le operazioni preliminari
3) Primo passo di displacement
La prima idea che mi viene in mente osservando l'oggetto
è di rompere la regolarità della mesh originale
applicando un displacement non particolareggiato e di scala
piuttosto grande: nel Node Editor,
aggiungiamo un nodo di tipo Turbulence
(Add Node > 3D
Textures > Turbulence)
con le impostazioni in Figura
4 e colleghiamo l'output Alpha all'input Scale del
nodo Scale.

Figura 4: il nodo Turbulence fornisce
le informazioni di scala del displacement
Avendo usato l'output Alpha
per fornire le informazioni di scala, i primi 3 campi del
nodo Turbulence, ovvero
Bg Color, Fg
Color e Blending
sono per noi ininfluenti, visto che l'alpha prescinde da
qualsiasi informazione di colore. Infatti, essa opera come
se impostasse automaticamente il Bg
Color col colore nero ed il Fg
Color col colore bianco, fornendo quindi una mappa
in scala di grigi secondo i parametri Small
Scale, Contrast
e Frequencies. Bump
Amplitude è un altro campo ininfluente, visto
che non useremo l'output Bump.
Infine, la scala è impostata sui 3m
per ogni asse.
Il risultato di questo passaggio sul mio oggetto è
visibile in Figura 5.

Figura 5: il risultato del displacement
dato dal nodo Turbulence
Tale risultato presenta un primo effetto non voluto, dato
dal significato che LightWave assegna alla gamma di grigi
di una mappa di displacement: infatti, il nero significa
nessun displacement (il punto rimane nella sua posizione
originale), il bianco significa massimo displacement, mentre
tutti i grigi forniscono valori intermedi a questi due.
Ciò porta il nodo Turbulence
esclusivamente a “gonfiare” la mesh sulla direzione
delle normali dei poligoni dell'oggetto originale; invece,
io voglio che la mappa a volte gonfi la mesh, e a volte
la sposti nel verso opposto rispetto alla normale. Come
posso fare? Molto semplice: poiché la mappa procedurale
varia tra il colore nero, il quale ha valore numerico pari
a 0% o, meglio, 0.0,
e tra il colore bianco, che ha valore numerico 100%
o 1.0, allora sottraendo
ad ogni punto di tale mappa il valore medio 0.5
ne otterrò una con range da -0.5
a 0.5, che è proprio
quello che voglio per a volte gonfiare la mesh e a volte
sgonfiarla.
Nel Node Editor, aggiungiamo
un nodo di tipo Subtract
(Add Node > Math
> Scalar > Subtract),
colleghiamo l'output Alpha
del nodo Turbulence all'input
A del nodo Subtract,
quindi apriamo tale nodo (doppio click su di esso) ed impostiamo
nel campo B il valore 0.5;
infine, colleghiamo l'output Result
all'input Scale del nodo
Scale.

Figura 6: l'aggiunta del nodo
Subtract per variare l'output di Turbulence da 0.0__0.1
a -0.5__0.5
Ora la nostra mesh ha un displacement migliore:

Figura 7: il displacement dopo
l'aggiunta del nodo Subtract
4) Aggiungere dettaglio
Ora che abbiamo una buona deformazione generica del
fianco della montagna, passiamo ad aggiungere i dettagli.
Ci affidiamo ad una texture procedurale Crackle
(Add Node > 3D
Textures > Crackle)
modificandone i valori come in Figura
8. Come abbiamo fatto per Turbulence,
l'outpu Alpha di questo
nodo verrà collegato all'input A
di un nodo Subtract, mentre
in B metteremo il valore
0.5.
Come collegare quindi l'effetto dato da questa texture
con quello della Turbulence?
La risposta dipende da quello che vogliamo fare.. noi, in
questo caso, stiamo aggiungendo dettaglio, e per
raggiungere il nostro scopo posizioniamo un nodo Add
(Add Node > Math
> Scalar > Add),
i cui input saranno il Result
dei 2 Subtract (che a loro
volta sono “filtri” delle 2 texture procedurali),
ed il cui output finirà come valore di scalatura
del nodo Scale.

Figura 8: l'aggiunta di una seconda
texture procedurale per i dettagli di displacement
Guardiamo ora la mesh:

Figura 9: il risultato del displacement
di Figura 8
Beh.. interessante, ma esagerato: Crackle
influisce troppo sul displacement. Come possiamo fare per
diminuirne l'intensità? Semplicemente prendendone
una sua percentuale: aggiungiamo un nodo Multiply
(Add Node > Math
> Scalar > Multiply)
da sistemare tra Subtract
e Add come in Figura
10, ed assegnamo il valore 0.1
(ovvero il 10%) a B.

Figura 10: la procedurale Crackle
"pesata" dal nodo Multiply

Figura 11: il dettaglio è
ora meno invasivo
Con l'aggiunta della Crackle,
siamo già arrivati ad un grado di dettaglio difficilmente
visibile in realtime nella viewport OpenGL senza avere un
Layout pesante e lento (bisognerebbe infatti alzare il livello
di suddivisione Display SubPatch
Level per aumentare il numero di poligoni dell'oggetto);
perciò, per renderci conto di quello che abbiamo
fatto, dobbiamo affidarci ad un render di prova: nelle proprietà
dell'oggetto, impostiamo Render
SubPatch su Per Object
Level, quindi inseriamo un valore di 5
o 6 nel campo sottostante
e premiamo F9.

Figura 12: primo test di rendering
Come si vede, c'è molta differenza tra quanto visualizzato
dalla viewport OpenGL ed il render.
Il risultato non è male, ma troppo omogeneo. Per
spezzare questa omogeneità ci sono diversi metodi;
noi proviamo a variare l'influenza della Crackle
a seconda della pendenza del poligono su cui viene applicata,
lasciando l'attuale valore di displacement quando tale poligono
è in piano, mentre lo diminuiamo man mano che esso
si trova in posizione verticale. Per fare questo, aggiungiamo
un nodo Gradient (Add
Node > Gradient
> Gradient), apriamolo
e settiamo l'input su Slope;
ci serviremo per il nostro scopo dell'alpha di ogni chiave,
quindi il colore che andremo ad assegnare è ininfluente.
Nella prima chiave, lasciamo l'Alpha
al 100%, mentre aggiungiamone
una in fondo (Position
= 1.0) e mettiamo l'Alpha
al 30%. Aggiungiamo anche
un nodo Multiply e colleghiamo
l'output di quello già presente nel Node
Editor nell'input A
di questo nuovo, mentre l'output Alpha
del gradiente deve puntare all'input B
di questo nodo (Figura 13).

Figura 13: il gradiente con input
Slope e il suo inserimento nella rete dei nodi mediante
un nuovo nodo Multiply
Ecco il render di prova:

Figura 14: il render con il nuovo
nodo Gradient di tipo Slope
Ora che abbiamo un po' di diversità, aggiungiamo
ulteriore dettaglio al nostro displacement. L'idea è
quella di aggiungere particolari non nelle fessure già
presenti, ma solo nelle parti che la texture Crackle
fa sporgere. Per fare questo, aggiungiamo un altro nodo
Crackle con le impostazioni
che vedete in Figura 15;
colleghiamo quindi l'output Alpha del vecchio nodo Crackle
all'input Opacity di questo
nuovo nodo, in modo che quest'ultimo agisca solo nelle parti
grigio/bianche del vecchio, ovvero nelle parti della mesh
che già sporgono. Aggiungiamo anche un nodo Add,
quindi leghiamo l'output Result
dell'ultimo nodo Multiply
aggiunto precedentemente al suo input A
e l'output Alpha del nuovo
nodo Crackle nell'input
B; Result
punterà invece all'input B
dell'altro nodo Add in
scena, quello che lega il ramo delle Crackle
al ramo della Turbulence
e che finisce nel nodo Scale.
Come si può notare, al nuovo nodo Crackle
non ne è stato aggiunto uno di tipo Subtract:
questo perchè vogliamo che questa procedurale aggiunga
dettaglio sempre in positivo, e non a volte in
positivo e a volte in negativo.
Guardando la viewport OpenGL, però, ci accorgiamo
nuovamente (era già successo in precedenza) come
l'effetto ottenuto sia eccessivo. Aggiungiamo quindi un
nodo Multiply (Add
Node > Math >
Scalar > Multiply)
e settiamone il valore B
a 0.1, quindi lo interponiamo
tra la seconda Crackle
e il nodo Add cui esso
è collegato come in Figura
15.

Figura 15: il quadro completo
dei nodi di displacement
Abbiamo quindi terminato; ecco il render finale col semplice
displacement applicato alla nostra mesh:

Figura 16: render col solo displacement
Per conferire ulteriore realismo alla mesh, sarebbe ora
indispensabile agire sullo shading delle superfici. Questa
parte non è affrontata nel tutorial, ma il consiglio
è quello di partire da una copia dei nodi Turbulence
e i 2 Crackle ed impostare
nel Node Editor di shading
una superficie che segua come base il displacement. Di seguito,
un esempio di quanto ottenuto seguendo questa idea:

Figura 17: il render finale con
alcune impostazioni di shading
5) Conclusioni
L'editor nodale ha delle notevoli potenzialità,
che permettono la realizzazione di qualsiasi idea ci passi
per la mente. Questo può però ben presto rivelarsi
controproducente, poiché il rischio di perdersi è
altrettanto elevato: ecco perchè prima bisogna avere
bene in testa cosa si intende raggiungere, quindi trovare
il modo più semplice ed immediato per soddisfare
l'obiettivo. Questo tutorial è stato strutturato
proprio in questo modo, spiegando prima quello che si vuole
ottenere nei vari passaggi, e solo in seguito il modo e
con quali strumenti è stato raggiunto lo scopo: un
metodo lineare che permette soprattutto il controllo del
proprio operato minimizzando il rischio di perdersi.
|