|
||||||
ROBOTICA
video
immagini
papers
progettati
costruiti
toolbox
vrml
simulatori
Creare oggetti di diversa forma : il nodo IndexedFaceSet e IndexedLineSet |
Finora abbiamo considerato
geometrie molto semplici. In particolare abbiamo visto negli esempi l'uso delle
primitive sfera, cono e cilindro. Un'altra primitiva molto semplice e utile
è la Box, che definisce un parallelepipedo. Ne vedremo un uso nell'esempio incluso
in questo paragrafo.
Anche se con queste semplici
primitive si possono realizzare dei mondi interessanti, mondi più complessi
si basano spesso su geometrie più complicate. Nella maggior parte dei casi,
quando ci troviamo nella situazione di dover modellizzare un oggetto del mondo
reale è difficile poterlo fare con semplici sfere, cilindri, parallelepipedi
e coni. L'ideale in questi casi sarebbe quello di poter definire i poligoni
che costituiscono l'oggetto che si vuole porre nella scena.
Ovvio che, una tale operazione,
se fatta a mano, può essere molto laboriosa e complicata ; basti considerare
che oggetti non molto complicati possono arrivare anche a migliaia di poligoni.
In tali casi l'uso di un tool di sviluppo opportuno risulta necessario. In
pratica si realizza il modello in un pacchetto grafico esterno e poi si converte
il file in formato vrml (esistono convertitori per i formati più conosciuti
come DXF o 3DS). Vediamo dunque come questo
sia possibile con un semplice esempio. Supponiamo di voler creare una casa
; o quanto meno un modello molto semplificato. Al massimo della semplificazione,
possiamo pensare ad una casa come ad un cubo con sopra una piramide (tralasciamo
porte e finestre ; non costerebbe comunque molto considerarle).
Come si può vedere il
numero di parentesi da chiudere cresce molto in fretta. Effettivamente il lavoro
da effettuare quando si vuole creare un oggetto dandone i poligoni risulta
essere piuttosto lungo. E' appunto per questo che, per oggetti più complessi
si ricorre di solito a pacchetti grafici esterni.
Analizziamo ora il listato
sopra riportato. In questo esempio ho usato una primitiva che ancora non avevamo
visto : Box. Quello che fa è molto semplice : crea una scatola di dimensioni
pari a quelle specificate nel campo size. Il field size necessita di 3 valori
; essi sono la dimensione lungo x, quella lungo y e quella lungo z. Si noti
che l'oggetto (come accade anche pe cilindro e sfera) viene posto in modo
tale da avere il baricentro nell'origine dell'attuale sistema di riferimento.
Una volta definita la
base passiamo a creare il tetto. Dato che il tetto appoggia sulla base e che
se si sposta la base il tetto la deve seguire, conviene strutturare questo
collegamento innestando il nodo Transform della piramide nel campo children
del primo Transform. In questo modo siamo sempre sicuri che il tetto andrà
sempre a posizionarsi sopra il cubo (ripeto ancora una volta che finchè faremo
mondi statici questi benefici non saranno evidenti). Direi che abbiamo detto
abbastanza sul nodo IndexedFaceSet.
Diamo ora una veloce
occhiata al nodo IndexedLineSet. Questo nodo consente di creare delle spezzate
3D.Basterà specificare i punti da raggiungere e quali punti connettere tra
di loro. Vediamo il seguente frammento di file vrml :
In questo caso, unendo
le spezzate creo un semplice quadrato (si badi bene NON un poligono quadrato:
ci si vede attraverso). La spezzata congiunge i punti nell'ordine fornito.
Se invece, tutto ciò di cui abbiamo bisogno è un semplice oggetto come una
piramide allora si può procedere anche ad editing diretto dei singoli poligoni
senza eccessivo sforzo.
Valgono ancora gli stessi discorsi fatti per l'esempio della freccia. Il tetto
deve appoggiare sul cubo sottostante, per cui dovrò considerare questo legame
nello sviluppo del mondo. Il seguente listato indica come realizzare questo
semplice oggetto ; si noti che il sorgente non è molto diverso dall'esempio
visto nel paragrafo precedente ; cambia solo la geometria dei singoli pezzi.
#VRML V2.0 utf8
#semplice casetta : uso del nodo IndexedFaceSet
Transform {
translation 0 0 -100 #pongo la casa ad una certa distanza
#dall'osservatore
rotation 0 1 0 .5 # ruoto leggermente per dare una migliore
#vista iniziale
children [
Shape {
appearance Appearance {
material Material { emissiveColor .5 .5 .5 } # come colore della base uso un grigio chiaro
}
geometry Box { size 20 20 20 }
}
Transform {
translation 0 10 0
children [
Shape {
appearance Appearance {
material Material { emissiveColor .8 0 0 }
}
geometry IndexedFaceSet {
coord Coordinate {
point [
-10 0 10, 10 0 10, 10 0 -10, -10 0 -10, 0 10 0
]
}
coordIndex [
0, 3, 2, 1, -1
0, 1, 4, -1
1, 2, 4, -1
2, 3, 4, -1
3, 0, 4, -1
]
}
}
]
}
]
}
Il risultato di questo listato si può vedere nella figura riportata (mondo
realizzato con Live3d 2.0).
Fatto questo, resta da definire quale sia la forma da dare al tetto. Abbiamo
deciso per una forma a piramide. Non esistendo una primitiva 'piramide' dobbiamo
definire l'oggetto specificandone i poligoni.
A tal fine, nel campo geometry indico allora il nodo IndexedFaceSet. Questo
nodo contiene due fields: il campo coord e il campo coordIndex. Il campo coord
specifica i punti che costituiscono i vertici dei poligoni che formano l'oggetto.
Si possono indicare questi vertici in qualsiasi ordine. In base alla posizione
che occupano nella lista, questi punti possono essere individuati da un numero.
Il primo vertice sarà il vertice 0, il secondo sarà il vertice 1 e così via.
In particolare il campo coord contiene il nodo Coordinate il cui field point
contiene i punti sottoforma di triplette di coordinate. Notate bene che le
coordinate sono fornite pensando di definire la piramide in modo cha abbia
centro nell'origine del sistema di riferimento. La traslazione sopra il cubo
non è di competenza del field geometry, bensì del nodo Transform ; se tenessi
qui conto della traslazione sopra il cubo, avrei una doppia traslazione (e
soprattutto non potrei riusare la piramide in altre parti).
Definiti i vertici, si deve procedere ad indicare quali sono le facce che
costituiscono l'oggetto. Per rappresentare una faccia si indicano i vertici
che la compongono. Questo viene fatto nel field coordIndex. In questo campo
indico i numeri dei vertici che compongono la faccia. Per indicare che non
vi sono altri vertici e che voglio chiudere la definizione di una faccia riporto
il numero -1.
L'ordine con cui riporto i vertici non è casuale ; ed è anzi molto importante.
I vertici di una faccia vanno riportati in modo tale che una faccia visibile
abbia i vertici listati in senso antiorario. Se si sbaglia l'orientamento
la faccia non verrà visualizzata (verrà visualizzata la faccia interna invece).
Questo meccanismo consente al browser di non doversi preoccupare delle facce
non visibili e quindi di non dover procedere al loro rendering, velocizzando
la resa della scena.
geometry IndexedLineSet {
coord Coordinate {
point [ 0 0 0, 0 10 0, 10 10 0, 10 0 0 ]
}
coordIndex [ 0 1 2 3 -1 ]
}