In questo capitolo intendiamo realizzare una semplice
animazione: una sfera blu che si sposta lungo l'asse x. Ecco il sorgente:
#VRML V2.0 utf8
# prima animazione VRML
DEF SferaBlu transform {
translation 0 0 0
children [
Shape {
appearance Appearance {
material Material { diffuseColor .16 .33 1 }
}
geometry Sphere { radius 1.4 }
}
]
}
DEF Tempo TimeSensor {
cycleInterval 4
enabled trUE
loop trUE
startTime 1
}
DEF Posizione PositionInterpolator
{
key [0 .5 1]
keyValue [-3 0 0, 3 0 0, -3 0 0]
}
ROUTE Tempo.fraction_changed TO Posizione.set_fraction
ROUTE Posizione.value_changed TO SferaBlu.set_translation
Poiché in un mondo VRML si presume la presenza di più oggetti con relativi
campi, occorre poter identificare in maniera corretta i campi interessati dall'animazione.
Il comando DEF, come si è già visto, ha per l'appunto questa funzione:
definire in maniera univoca un campo.
L'esempio seguente ne mostra la sintassi:
DEF nome Nodo
Per il momento tralasciamo l'analisi del nodo della sfera, per concentrarci
sul nodo TimeSensor. Quindi nel nostro caso
si è in primo luogo definito il nodo TimeSensor con il nome Tempo.
Poi all'interno del campo cycleInterval si è specificato il numero
di secondi di un ciclo di tempo. Nel nostro caso quindi l'orologio è attivo
per 4 secondi.
Il campo enabled settato a trUE rende attivo l'orologio. Anche
il loop è stato impostato a trUE, di modo che una volta che l'orologio
avrà concluso un ciclo, ripeterà la sequenza. L'ultimo campo prescrive di partire
dal punto 1 con la scansione del tempo.
Analizziamo ora le caratteristiche del nodo interpolatore. Poiché il nostro
intento è quello di far spostare la sfera, si è utilizzato il PositionInterpolator.
Si sono quindi dichiarati i tre punti temporali chiave del movimento: il punto
di partenza, il punto intermedio e il punto finale, rispettivamente: 0,
.5, 1. A questi momenti chiave corrispondono altrettante posizioni
lungo l'asse x descritte nel campo keyValue: -3 0 0, 3 0 0, -3 0 0. In
pratica nel momento chiave iniziale 0 la nostra sfera si troverà nella posizione
chiave definita dalla prima tripletta di coordinate spaziali: X=-3, Y=0, Z=0.
Nel secondo momento chiave 0.5, la sfera dovrà trovarsi nella seconda posizione
descritta con la tripletta 3 0 0, e dovrà infine ritrovarsi nella identica posizione
di partenza al termine del ciclo. Per tutte le frazioni di tempo intermedie
l'interpolatore calcolerà le relative posizioni intermedie tra le tre posizioni
dichiarate.
Ora, per analizzare il comando ROUTE, occorre prendere in considerazione
il modo in cui si è descritta la posizione iniziale della sfera.
Per realizzare la nostra animazione infatti, dobbiamo modificare progressivamente
la posizione della sfera. E abbiamo già visto che per posizionare qualsiasi
tipo di oggetto in VRML occorre far ricorso al nodo transform. Quindi,
il nodo transform è responsabile del posizionamento di tutti i nodi contenuti
nel suo campo children; in questo caso della sfera.
Osserviamo i campi del nodo transform:
addChildren
removeChildren
center
children
rotation
scale
scaleOrientation
translation
bboxCenter
bboxsize
Il campo translation è il campo responsabile della posizione dei nodi
presenti nel prorpio campo children, inoltre, dalla lettura delle specifiche,
risulta avere un tipo di interfaccia exposedField. Ciò significa che
è possibile modificare i valori contenuti in questo campo, inserendo i nuovi
valori che gli verrano forniti. Quindi, elaborando una sequenza di posizioni
che definiscono l'animazione, è sufficiente trovare il modo di fornire progressivamente
nel tempo tali posizioni al campo translation del nodo transform.
Per fare ciò occorre in primo luogo individuare un nodo che abbia un campo
eventOut o exposedField, che abbia la proprietà cioè di esportare
via via questi valori. In secondo luogo è necessario un mezzo di comunicazione
trai due nodi in questione. A questo scopo si fa uso del comando ROUTE.
In pratica ROUTE si incarica di guidare l'evento prodotto da un certo
campo verso il campo di un altro nodo.
Per identificare un certo campo del nodo transform basta allora far precedere
al nome del campo il nome del nodo, separandoli con un punto (nomenodo.nomecampo).
In particolare, nel nostro caso vogliamo collegare il trascorrere del tempo
con l'interpolatore di posizione:
ROUTE tempo.fraction_changed TO posizione.set_fraction
Fraction_changed è un campo del nodo timeSensor, esso contiene la frazione
di tempo trascorsa rispetto ad un ciclo cioè un valore compreso tra 0 e 1, dove
0 rappresenta l'inizio del ciclo e 1 ne indica la fine.
Questo valore, emesso dal nodo che abbiamo denominato tempo, va a settare
un campo all'interno del nodo interpolatore. Questo secondo campo viene usato
per calcolare la nuova posizione. Nel momento iniziale, dove fraction_changed
è uguale a 0, l'interpolatore emetterà la posizione -3 0 0. Per una frazione
di tempo pari a 0.5 (e quindi dopo 2 secondi nel nostro esempio) la posizione
sarà 3 0 0. Per tutte le altre frazioni di tempo intermedie l'interpolatore
calcolerà le adeguate posizioni intermedie. Settando di volta in volta il campo
translation del nodo transform con il valore calcolato dall'interpolatore
infine si può descrivere l'animazione.
Per concludere, occorre collegare il valore in uscita del nodo interpolatore
con il campo translation.
In particolare, nel nostro caso vogliamo modificare la componente translation
del nodo transform che abbiamo chiamato SferaBlu:
ROUTE Posizione.value_changed TO SferaBlu.set_translation
Con questo concludiamo la prima analisi delle possibilità offerte dal VRML
per la realizzazione di animazioni tridimensionali.
Prima di passare al prossimo capitolo però, si consideri ancora la seguente
ipotesi: nell'animazione che si è appena realizzata si vogliono impostare diverse
velocità e tracciare percorsi più complessi. In questo caso sarà sufficiente
aumentare i punti su cui basare l'interpolazione e sfasare i relativi tempi
di percorso come nel seguente semplice esempio:
DEF Posizione PositionInterpolator
{
key [0 .25 0.33 1]
keyValue [-4 0 0, 4 2 -8, 0 0 4, -4 0 0]
}