Sistemi multimediali
Massimiliano Piscozzi – [email protected]
Prototipi (3)
• La definizione di un prototipo può essere contenuta in un
file diverso da quello in cui vengono create le istanze
File A
File X3D-XML contenente
la dichiarazione
di uno o più prototipi
File B
File X3D-XML contenente
la dichiarazione
di uno o più prototipi
File C
File X3D-XML contenente
la dichiarazione
di uno o più prototipi
File D
File X3D-XML che
utilizza istanze di
prototipi definiti
esternamente
 Maggiore riusabilità dei nodi definiti dall’utente
 Semplificazione nella scrittura dei file X3D-XML
ExternProtoDeclare
• La dichiarazione di un prototipo definito esternamente
avviene attraverso il tag ExternProtoDeclare
<ExternProtoDeclare name=“...” url=“...”/>
Indirizzo del file in cui è
definito il prototipo + nome
del prototipo:
nomeFile#nomePrototipo
Nome utilizzato localmente
per la creazione di istanze
del prototipo
• Esempio
FileA.x3d
...
<ProtoDeclare name=“oggetto”>
<ProtoInterface>
...
</ProtoInterface>
<ProtoBody>
...
</ProtoBody>
</ProtoDeclare>
...
FileB.x3d ...
<ExternProtoDeclare
name=“oggettoEsterno”
url=“FileA.x3d#oggetto”/>
...
<ProtoInstance name=“oggettoEsterno”>
...
</ProtoInstance>
...
Scripting
• Uno script:
– E’ un nodo facente parte dello scene graph
– Contiene un “comportamento” definito attraverso funzioni scritte
in ECMAScript
– Può generare eventi
• L’utilizzo di scripts permette di:
– Programmare comportamenti più evoluti rispetto a quelli ottenibili
tramite i nodi predefiniti (ex: pulsanti a più stati)
– Definire matematicamente delle traiettore (ex: parabole, ellissi)
– Automatizzare comportamenti (ex: creazione di un gran numero
di istanze di un oggetto)
– Convertire eventi (ex: rollOver button)
– Modificare dinamicamente lo scene graph e il behaviour graph
– ...
Nodo Script
<Script>
...
Interfaccia costituita da campi
<field name=“...” type=“...”
accessType=“...” value=“...”/>
<![CDATA[
...
]]>
</Script>
Funzioni definite in ECMAScript
<![CDATA[
ecmascript:
...lista funzioni...
]]>
• Per gestire gli eventi in input occorre definire delle funzioni
associate ai campi InputOnly o InputOutput
• Per spedire degli eventi associati ai campi OutputOnly o InputOutput
è sufficiente modificarne i valori all’interno delle funzioni
ECMAScript (1)
• Variabili
– Linguaggio debolmente tipizzato
– Tipi predefiniti:
boolean, number, string, object, ...
var a;
a = 5;
print(a);
a = ‘Hello World!’
print(a);
• Operatori
–
–
–
–
Unari: ! (NOT), -, ++ (incremento), -- (decremento)
Binari: +, - ,* ,/ ,% (modulo)
Relazionali: <, >, <=, >=, ==, !=
Logici: && (AND), || (OR)
• Strutture di controllo
– Condizionali: if..else, switch
– Iterative: for, while, do..while
if (condition) {
statements
}
else {
statements
}
switch (expr) {
case label:
statements
break;
...
default:
statements
}
for (expr1; epr2; expr3) {
statements
}
while (condition) {
statements
}
do {
statements
} while (condition)
ECMAScript (2)
• Funzioni
– Non occorre specificare il tipo del valore restituito
function myFunction(parameters) {
...
}
function somma(a,b) {
return (a+b);
}
• Oggetto Array
– Array dinamico costituito da elementi di qualsiasi tipo
– Proprietà: length
var a = new Array();
a[0] = 4;
a[1] = ‘BlaBlaBla’;
for (i=0; i < a.length; i++) {
print(a[i]);
}
• Oggetto Math
– Oggetto globale: non va istanziato tramite new
– Costanti matematiche (proprietà): PI, E, SQRT2, LN2, LN10, ...
– Funzioni matematiche (metodi): max(), min(), pow(), sqrt(),
sin(), cos(), tan(), random()
ECMAScript (3)
• ECMAScript e nodi “Script” (X3D)
– I tipi di dato booleani (SFBool), scalari (SFFloat, SFDouble,
SFInt32, SFTime) e le stringhe (SFString) sono rappresentati
attraverso i tipi base di ECMAScript (boolean, number, string)
– I restanti tipi di dato “singoli” (SFColor, SFVec3f, ...) sono
rappresentati attraverso degli oggetti
• Ex: verde = new SFColor(0,1,0);
• Ex: origine = new SFVec3f(0,0,0);
– I tipi di dato “multipli” (MFInt32, MFVec3f, ...) sono rappresentati
attraverso degli array
• Ex: v = new MFInt32(2,5,1,-3);
ECMAScript (4)
• ECMAScript e nodi “Script” (X3D)
– Per ogni campo di tipo InputOnly e InputOutput bisogna definire una
funzione con lo stesso nome
– E’ possibile definire due funzioni richiamate quando lo script è
caricato o eliminato dal Browser: initialize() e shutdown()
– La funzione print() permette di scrivere sulla console (debug)
– Tramite l’oggetto globale Browser() è possibile modificare
dinamicamente lo scene graph e il behaviour graph
• Browser.createFromVRMLString(stringVRML)
• Browser.addRoute(fromNode,fromField,toNode,toField)
• Browser.deleteRoute(fromNode,fromField,toNode,toField)
Script: esempio
• Movimento sinusoidale di un cubo
TimeSensor
Script
Transform
cycleInterval
set_fraction
translation
loop
value_changed
·· ·
fraction_changed
·· ·
·· ·
<Script DEF="MyScript">
<field name="set_fraction" type="SFFloat" accessType="inputOnly"/>
<field name="value_changed" type="SFVec3f" accessType="outputOnly"/>
<![CDATA[
ecmascript:
function initialize() {
print(‘Script inizializzato!’);
}
set_fraction(value)
oppure
set_fraction(value, timestamp)
function set_fraction(value) {
value_changed[0] = -3 + 6 * value;
value_changed[1] = 2 * Math.Sin(value*6.28);
value_changed[2] = 0;
}
]]>
</Script>
Esempio (1)
• Creazione di un prototipo di un pulsante a due stati
– Lo stato del pulsante deve essere rappresentato dal suo colore
(variazione del diffuseColor)
– Il pulsante deve illuminarsi al passaggio del mouse (variazione
dell’emissiveColor)
– Il pulsante può avere forme diverse
Button
Transform
·· ·
Shape
·· ·
geometry
TouchSensor
Appearance
·· ·
isOver
Script
touchTime
isOver
·· ·
touchTime
diffuseColor
emissiveColor
Sphere
·· ·
Material
diffuseColor
emissiveColor
·· ·
·· ·
Esempio (2)
• Dichiarazione del
prototipo
• Connessione del
campo geometry del
prototipo
<ProtoDeclare name=“Button”>
<ProtoInterface>
<field name="geometry" type="SFNode" accessType="inputOnly">
<Sphere/>
</field>
</ProtoInterface>
Campo costituito da un nodo:
<ProtoBody>
il valore di default non viene
...
specificato nell’attributo value,
</ProtoBody>
ma attraverso un tag innestato
</ProtoDeclare>
...
<Shape>
<Appearance>
<Material DEF=“materialButton”>
</Appearance>
<IS>
<connect nodeField="geometry" protoField="geometry"/>
</IS>
</Shape>
...
Esempio (3)
<Script DEF="MyScript">
• Nodo Script
<field name="isOver" type="SFBool"
accessType="inputOnly"/>
<field name="touchTime" type="SFTime"
accessType="inputOnly"/>
<field name="state" type="SFBool"
accessType="inputOutput"/>
<field name="emissiveColor_changed" type="SFColor"
accessType="outputOnly"/>
<field name="diffuseColor_changed" type="SFColor"
accessType="outputOnly"/>
<![CDATA[
ecmascript:
...
]]>
</Script>
Esempio (4)
function state(value) {}
• Funzioni definite
all’interno del nodo
Script
function touchTime(value) {
state = !state;
if (state) {
diffuseColor_changed = new SFColor(1, 0.2, 0.5);
}
else {
diffuseColor_changed = new SFColor(0.2, 1, 0.5);
}
}
function isOver(value)
{
if (value) {
emissiveColor_changed = new SFColor(0.2, 0.2, 0.2);
}
else {
emissiveColor_changed = new SFColor(0, 0, 0);
}
}
Esempio (5)
• Routing degli eventi
all’interno di
<ProtoBody>
• Creazione di istanze
del prototipo
<ROUTE fromNode="Sensor" fromField="isOver"
toNode="MyScript" toField="isOver"/>
<ROUTE fromNode="Sensor" fromField="touchTime"
toNode="MyScript" toField="touchTime"/>
<ROUTE fromNode="MyScript" fromField="emissiveColor_changed"
toNode="MaterialButton" toField="set_emissiveColor"/>
<ROUTE fromNode="MyScript" fromField="diffuseColor_changed"
toNode="MaterialButton" toField="set_diffuseColor"/>
<ProtoInstance name="button">
<fieldValue name="geometry">
<Box/>
</fieldValue>
</ProtoInstance>
Campo costituito da un nodo:
il valore di default non viene
specificato nell’attributo value,
ma attraverso un tag innestato
ProximitySensor
• Rileva quando l’avatar entra (ed esce) in una zona rappresentata da
un parallelepipedo
• Quando l’utente si trova all’interno del parallelepipedo il sensore
traccia la sua posizione e orientazione
ProximitySensor : X3DEnvironmentalSensorNode {
SFBool
[in,out] enabled
TRUE
SFVec3f
[in,out] center
000
SFVec3f
[in,out] size
000
SFTime
[out]
enterTime
SFTime
[out]
exitTime
SFRotation
[out]
orientation_changed
SFVec3f
[out]
position_changed
SFBool
[out]
isActive
...
}
 Permette di far iniziare (terminare) delle animazioni quando l’avatar si avvicina
(allontana) ad un particolare oggetto
 Permette di muovere un oggetto in modo da replicare il movimento dell’avatar
(utile per la creazione di interfacce)
Esempio (1)
• Animazione di un parallelepipedo in base alla vicinanza
dell’avatar
ProximitySensor
enterTime
TimeSensor
PositionInterp.
startTime
set_fraction
fraction_changed
value_changed
Transform
·· ·
·· ·
scale
·· ·
exitTime
·· ·
TimeSensor
PositionInterp.
startTime
set_fraction
fraction_changed
value_changed
·· ·
·· ·
Shape
·· ·
Appearance
·· ·
Box
·· ·
Material
·· ·
Esempio (2)
• Posizionamento di un oggetto in base alla posizione
dell’avatar
ProximitySensor
Transform
position_changed
translation
orientation_changed
rotation
·· ·
·· ·
La grandezza del sensore (campo size)
deve essere tale da racchiudere tutta la
scena virtuale
Occorre disabilitare il rilevamento delle
collisioni:
<Collision collide=“false”>
...
</Collision>
Sistema di coordinate locali
corrispondente alla posizione
dell’avatar
Collision
·· ·
Transform
·· ·
VisibilitySensor
• Rileva quando un’area rappresentata da un parallelepipedo è
visibile all’avatar
VisibilitySensor : X3DEnvironmentalSensorNode {
SFBool
[in,out] enabled
TRUE
SFVec3f
[in,out] center
000
SFVec3f
[in,out] size
000
SFTime
[out]
enterTime
SFTime
[out]
exitTime
...
}
 Permette di far iniziare (terminare) delle animazioni quando l’avatar può o meno
vedere un particolare oggetto (utile per attirare l’attenzione dell’utente)
Scarica

pps