|
||||||
ROBOTICA
video
immagini
papers
progettati
costruiti
toolbox
vrml
simulatori
Esempio di animazione |
Consideriamo ora un altro
esempio, leggermente più complesso dei precedenti, in modo tale da consolidare
le nozioni acquisite nei precedenti paragrafi.
Supponiamo di volere
realizzare una semplice stanza. La stanza è completamente vuota tranne che
per un orologio. Anziché avere un orologio sempre fermo, supponiamo di volerlo
dotare di lancette che segnano il trascorrere del tempo. In particolare colleghiamo
lo scorrere delle lancette al tempo effettivo, in modo che rappresenti in
maniera corretta l’ora corrente (se l’ora sul computer dell’utente è settata
in maniera corretta ovviamente).
Metteremo una lancetta
per i secondi, una per i minuti e una per le ore.
Questo è solo un pezzo
del mondo. Una stanza dovrebbe contenere qualcosa d’altro ; ma noi ci concentriamo
su questo oggetto, senz’altro il più complicato che abbiamo visto sino a questo
punto.
Analizziamo bene la struttura
delle lancette. Rappresentiamo le lancette con dei parallelepipedi molto stretti.
Il problema è che queste lancette devono poter ruotare. Ma attenzione ! Non
devono ruotare rispetto al loro centro. Una lancetta deve ruotare attorno
all’estremo connesso al centro dell’orologio.
Il trucco che ho utilizzato
in questi casi è quello di definire una sfera centrale a cui connetto rigidamente
la lancetta. A questo punto posso ruotare la sfera centrale (attorno al suo
centro) e la lancetta ruoterà con essa. Vi ricordate quando sottolineavo nei
primi paragrafi l’importanza di strutturare le dipendenze tra oggetti ? Allora
poteva sembrare un esercizio inutile. Ora, con le animazioni in gioco, strutturare
in maniera corretta il mondo risulta determinante.
Questa operazione va
ripetuta per tutte e tre le lancette. Non importa se le sfere si sovrappongono.
Basta che questo non sia visibile dall’esterno.
Ovviamente le rotazioni
da dare alle sfere saranno diverse, a seconda che siano collegate alla lancetta
dei secondi, dei minuti o delle ore.
Avremo la necessità di
definire tre sensori di tempo, ognuno con cicli diversi ; il sensore per i
secondi avrà un ciclo di 60 secondi, dopo i quali la lancetta ricomincia a
comportarsi nello stesso modo ; quello per i minuti avrà un ciclo di 60 minuti
e quello per le ore di 12 ore (dubito comunque che il vostro utente resterà
a vedere il completamento di questo ciclo).
Detto questo, la stesura
del sorgente risulta ora abbastanza banale. Per rendere l’orologio un po’
più realistico metterò le lancette in modo che non si compenetrino nel loro
spostamento (le pongo a z leggermente diverse, come un vero orologio del resto)
e porrò almeno quattro stanghette per segnare le ore : 3 - 6 - 9 - 12.
Per aggiungere un po’
di luce alla stanza aggiungo una lampadina attaccata al soffitto che genera
una luce tramite un nodo PointLight.
Ponete particolare attenzione
al modo di strutturare il mondo e a come vengono ridiretti gli eventi.
Per quanto riguarda l’ora
rappresentata, essa è quella corrente in quanto gli intervalli di ciclo del
nodo TimeSensor sono collegati con il clock dell’orologio.
L’esempio è un po’ più
corposo rispetto agli altri. In ogni caso andrebbe sviluppato ancora molto
in quanto tutto quello che abbiamo è una stanza vuota con una lampadina e
un orologio che riporta fedelmente l’ora corrente. L’arredamento è tutto da
inventare.
Con una dimensione di
circa 5Kb siamo riusciti ad avere un risultato abbastanza interessante. Ammobiliando
la stanza (magari anche con modelli presi da programmi di rendering esterni
o da librerie disponibili in rete) potremmo rendere l’ambiente molto più accogliente
e realistico.
Nel prossimo paragrafo
vedremo come si può iniziare ad interagire con il mondo in maniera molto semplice
tramite appositi sensori. Vedremo per esempio come aggiungere un semplice
sensore che ci sonsentirà di accendere e spegnere la luce della lampadina
nella stanza.
#VRML V2.0 utf8
# semplice stanza con un orologio che segna il trascorrere
# del tempo
# setto la posizione iniziale
Viewpoint {
position 0 1.5 2
}
# definisco ora le pareti della stanza. Per migliorare la
#visibilita’ coloro le pareti in maniera diversa
DEF appartamento Transform {
children [
Shape {
appearance Appearance {
material Material { diffuseColor 1 0 0 }
}
geometry IndexedFaceSet {
coord
DEF mycoords Coordinate {
point [-3 0 3, 3 0 3, 3 0 -3, -3 0 -3, -3 3 3, 3 3 3, 3 3 -3, -3 3 -3]
}
# pavimento e soffitto
coordIndex [ 0 1 2 3 -1, 7 6 5 4 -1]
}
}
Shape {
appearance Appearance {
material Material { diffuseColor .8 .8 .8 }
}
geometry IndexedFaceSet {
# usando USE riuso il nodo Coordinate definito in precedenza...
# le coordinate sono le stesse !
coord USE mycoords
# definisco le 2 pareti laterali
coordIndex [1 5 6 2 -1, 0 3 7 4 -1]
}
}
Shape {
appearance Appearance {
material Material { diffuseColor .6 .6 .6 }
}
geometry IndexedFaceSet {
coord USE mycoords
# definisco le pareti davanti e dietro
coordIndex [0 4 5 1 -1, 6 7 3 2 -1]
}
}
]
}
# creo ora una lampadina che scende dal soffitto e illumina la stanza.
Transform {
translation 0 2.7 0
children [
Shape {
appearance Appearance {
material Material { diffuseColor .3 .3 .3 }
}
# filo modellizzato come sottile cilindro
geometry Cylinder {
radius .005
height .6
}
}
# la lampadina e’ una sfera di colore giallo attaccata
# all’estremita’ del filo
Transform {
translation 0 -.325 0
children [
Shape {
appearance Appearance {
material Material { diffuseColor .8 .8 0 }
}
geometry Sphere { radius .05 }
}
# qui definisco la luce che scaturisce dalla lampadina.
PointLight {
location 0 2.35 0
radius .1
}
]
}
]
}
# creiamo ora l'orologio.
# il posizionamento e' dato dal nodo Transform che lo include.
# Lo posiziono sulla parete di fronte
DEF clock Transform {
translation 0 1.5 -2.98 # messo appoggiato sulla superficie della parete ad una altezza di 1.5 metri
children [
Transform {
rotation 1 0 0 1.57
children [
Shape {
appearance Appearance {
material Material { diffuseColor .3 .3 0 }
}
# ho usato un cilindro basso e ruotato in modo da avere la base
# verso l’osservatore. Ho quindi ottenuto
# la solita forma a cerchio degli orologi da muro.
geometry Cylinder {
radius .4
height .02
}
}
]
}
# definisco ora i quattro segni per le ore principali (3-6-9-12)
Transform {
translation -.27 0 .021
children [
DEF segno Shape {
appearance Appearance {
material Material { diffuseColor 0 0 1 }
}
geometry Box { size .08 .04 .002 }
}
]
}
Transform {
translation .27 0 .011
children [
# anche qui riuso il nodo definito in precedenza...
# le stanghette sono tutte uguali
USE segno
]
}
Transform {
translation 0 .27 .011
# due delle stanghette devono essere in verticale...
# per cui ruoto la stanghetta che riuso, la quale
# era definita in orizzontale
rotation 0 0 1 1.57
children [
USE segno
]
}
Transform {
translation 0 -.27 .011
rotation 0 0 1 1.57
children [
USE segno
]
}
#definisco ora le lancette
#lancetta delle ore
# sfera che funge da perno
DEF perno_ore Transform {
children [
Shape {
appearance Appearance {
material Material { diffuseColor 1 0 0 }
}
# molto piccola in modo che non sia visibile...
# ma la funzione che svolge e’ a noi molto utile !
geometry Sphere { radius .005 }
}
# si noti come la lancetta e' figlia del perno.
Transform {
translation 0 .08 .02
children [
Shape {
appearance Appearance {
material Material { diffuseColor 0 0 1 }
}
geometry Box { size .06 .16 .002 }
}
]
}
]
}
# sfera che funge da perno per la lancetta dei minuti...
# si va a sovrapporre al perno per i secondi... ma
# in ogni caso non si vede per cui non ho problemi
DEF perno_minuti Transform {
children [
Shape {
appearance Appearance {
material Material { diffuseColor 1 0 0 }
}
geometry Sphere { radius .005 }
}
# la lancetta deve essere figlia del perno dei minuti
Transform {
translation 0 .11 .04
children [
Shape {
appearance Appearance {
material Material { diffuseColor 0 1 0 }
}
geometry Box { size .03 .22 .002 }
}
]
}
]
}
# lo stesso ripetuto per i secondi.
DEF perno_secondi Transform {
children [
Shape {
appearance Appearance {
material Material { diffuseColor 1 0 0 }
}
geometry Sphere { radius .005 }
}
# lancetta dei secondi
Transform {
translation 0 .11 .06
children [
Shape {
appearance Appearance {
material Material { diffuseColor 1 0 0 }
}
geometry Box { size .01 .22 .001 }
}
]
}
]
}
]
}
# definisco ora i tre sensori di tempo
DEF secondi TimeSensor {
cycleInterval 60
enabled TRUE
loop TRUE
}
DEF minuti TimeSensor {
cycleInterval 3600
enabled TRUE
loop TRUE
}
DEF ore TimeSensor {
cycleInterval 86400
enabled TRUE
loop TRUE
}
# definisco ora i 3 interpolatori... qui dovrebbe essere tutto chiaro.
# Ruoto le sfere attorno all’asse z
# le lancette che sono attaccate ad esse ruotano solidalmente.
DEF rotsec OrientationInterpolator {
key [0 .25 .5 .75 1]
keyValue [0 0 1 0, 0 0 1 -1.57, 0 0 1 -3.14, 0 0 1 -4.71, 0 0 1 -6.28]
}
DEF rotmin OrientationInterpolator {
key [0 .25 .5 .75 1]
keyValue [0 0 1 0, 0 0 1 -1.57, 0 0 1 -3.14, 0 0 1 -4.71, 0 0 1 -6.28]
}
DEF rotore OrientationInterpolator {
key [0 .25 .5 .75 1]
keyValue [0 0 1 0, 0 0 1 -1.57, 0 0 1 -3.14, 0 0 1 -4.71, 0 0 1 -6.28]
}
# da ultimo indirizzo gli eventi in uscita in modo opportuno
# il sensore di tempo dei secondi manda l’uscita
# fraction_changed che va a settare la frazione
# nell’interpolatore
# l’interpolatore calcola di conseguenza il nuovo valore
# di rotazione e lo usa per settare il campo rotation del
# perno della lancetta dei secondi
# lo stesso vale per le altre coppie di ROUTE
ROUTE secondi.fraction_changed TO rotsec.set_fraction
ROUTE rotsec.value_changed TO perno_secondi.set_rotation
ROUTE minuti.fraction_changed TO rotmin.set_fraction
ROUTE rotmin.value_changed TO perno_minuti.set_rotation
ROUTE ore.fraction_changed TO rotore.set_fraction
ROUTE rotore.value_changed TO perno_ore.set_rotation
Stanza con orologio