VRML-Kurs, Teil 4
VRML-Kurs, Teil 4
VRML-Kurs, Teil 4
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
<strong>VRML</strong>-<strong>Kurs</strong>, <strong>Teil</strong> 4<br />
Interaktion zwischen Knoten<br />
Mehrere <strong>VRML</strong>-Knotentypen können Ereignisse (events)<br />
empfangen und/oder senden.<br />
Ereignisse enthalten einen Wert und eine Zeitmarke<br />
(timestamp).<br />
• Gesendete Ereignisse können die Änderung von Werten von<br />
Feldern mitteilen<br />
• Empfangene Ereignisse können Werte von Feldern ändern<br />
Ereignisse sind ihrerseits als Felder von Knoten definiert.<br />
Ereignis, das die Änderung eines Feldes mitteilt:<br />
Schlüsselwort eventOut<br />
Ereignisname meist = Feldname und Suffix "_changed"<br />
(Ausnahmen: Ereignisse mit den Typen SFBool und SFTime.)<br />
Ereignis, das ein Feld ändern kann:<br />
Schlüsselwort eventIn<br />
Ereignisname meist = Feldname und Präfix "set_"<br />
(Ausnahmen: addChildren, removeChildren, Ereignisse<br />
vom Typ SFTime).<br />
Bei Feldern, zu denen beide Typen von Ereignissen gehören,<br />
kann statt der Definition des Feldes und beider Ereignisse eine<br />
Kurzform verwendet werden: Voranstellen des Schlüsselwortes<br />
"exposedField" vor den Feldnamen. Beispiel:<br />
Bei einem Feld "position" innerhalb einer Knotendefinition<br />
kann statt der drei Angaben<br />
field position<br />
eventIn set_position<br />
eventOut position_changed<br />
abgekürzt geschrieben werden:<br />
exposedField position
Die Schlüsselwörter field, exposedField, eventIn,<br />
eventOut geben die Zugriffsart eines Feldes oder Ereignisses<br />
an.<br />
Schnittstellen-Schema eines Knotens:<br />
(Bei der Def. neuer Felder im Rahmen von Prototypen sind die<br />
Namenskonventionen für Präfix bzw. Suffix nicht zwingend<br />
vorgeschrieben, werden aber zur Verbesserung der Konsistenz<br />
und Lesbarkeit empfohlen.)<br />
Ereignistyp: Typ des geänderten bzw. des zu ändernden<br />
Feldes.<br />
Ereignisse werden durch Routen zwischen zwei Knoten<br />
übertragen.<br />
Dabei können nur Knoten verwendet werden, die mit dem<br />
Schlüsselwort DEF einen Namen zugeordnet bekommen haben<br />
(siehe <strong>Kurs</strong>teil 3a).<br />
Voraussetzung: Die Ereignistypen des Output- und des Input-<br />
Ereignisfeldes müssen übereinstimmen.
Syntax der Routen-Vereinbarung:<br />
ROUTE NameKnotenA.feld1_changed TO<br />
NameKnotenB.set_feld2<br />
Ausnahmen von der Namenskonvention "_changed" für<br />
Output- und "set_" für Inputereignisse:<br />
Ereignisse mit booleschen Werten: is... (z.B. isActive)<br />
Ereignisse mit Zeitwerten: ...Time (z.B. touchTime)<br />
Ereignisse zum Hinzufügen und Entfernen von Kindknoten:<br />
add_children, remove_children<br />
In der Routendefinition können "set_" und "_changed" bei<br />
Ereignissen von Feldern mit der Zugriffsart exposedField<br />
fortgelassen werden.<br />
Beispiel:<br />
bei<br />
DEF Schalter TouchSensor { enabled TRUE }<br />
DEF Licht DirectionalLight { on FALSE }<br />
ROUTE Schalter.enabled_changed TO Licht.set_on<br />
kann die letzte Zeile vereinfacht werden zu:<br />
ROUTE Schalter.enabled TO Licht.on
Ein per Route weitergeleitetes Ereignis kann bei der Verarbeitung<br />
durch den empfangenden Knoten ein weiteres<br />
Ereignis auslösen, das wiederum weitergeleitet wird, usw.:<br />
Ereignis-Kaskade.<br />
Alle Ereignisse einer Kaskade haben dieselbe Zeitmarke.<br />
Bei der Konstruktion von Ereignis-Kaskaden dürfen keine<br />
Schleifen gebildet werden!<br />
Zwei oder mehr Ereignisse gehen vom selben eventOut-<br />
Ereignis an verschiedene Knoten: "fan-out", erlaubt.<br />
Zwei oder mehr Ereignisse mit derselben Zeitmarke werden an<br />
dasselbe eventIn-Ereignis geleitet: "fan-in", Ergebnis<br />
undefiniert, deshalb verboten.<br />
Animation<br />
(seit <strong>VRML</strong> 2.0)<br />
Antrieb der Veränderung durch spezielle Knoten, z.B.<br />
TimeSensor, die Zeitwerte an Interpolator-Knoten senden.<br />
Diese erzeugen die gebrauchten (Zwischen-) Werte für Felder<br />
animierter Objekte.<br />
TimeSensor<br />
enabled<br />
cycleInterval<br />
loop<br />
<br />
startTime<br />
<br />
<br />
stopTime<br />
<br />
fraction_changed<br />
<br />
<br />
<br />
<br />
<br />
SFBool<br />
SFTime<br />
SFBool<br />
<br />
SFTime<br />
<br />
<br />
SFTime<br />
<br />
SFFloat<br />
<br />
<br />
<br />
<br />
<br />
Start/Stop<br />
Zykluszeit<br />
unendl.<br />
Wiederholung<br />
Start des<br />
Timer-<br />
Ablaufs<br />
Lebensdauer<br />
des Timers<br />
eventOut-<br />
Feld, Anteil<br />
des bereits<br />
verstrichenen<br />
Zeitintervalls<br />
(zw. 0 und 1)
isActive<br />
time<br />
cycleTime<br />
SFBool<br />
SFTime<br />
SFTime<br />
eventOut<br />
eventOut<br />
eventOut,<br />
Start eines<br />
Zyklus<br />
Die Interpolator-Knoten stellen anwendungsspezifische Interpolationswerte<br />
bereit:<br />
OrientationInterpolator<br />
Liste v.<br />
Zwischenwerten<br />
für<br />
die interpolierte<br />
Größe<br />
PositionInterpolator<br />
CoordinateInterpolator<br />
NormalInterpolator<br />
ScalarInterpolator<br />
ColorInterpolator<br />
set_fraction<br />
key<br />
<br />
<br />
<br />
<br />
keyValue<br />
<br />
<br />
<br />
<br />
<br />
value_changed<br />
set_fraction<br />
key<br />
keyValue<br />
value_changed<br />
set_fraction<br />
key<br />
keyValue<br />
value_changed<br />
set_fraction<br />
key<br />
keyValue<br />
value_changed<br />
set_fraction<br />
key<br />
keyValue<br />
value_changed<br />
SFFloat<br />
MFFloat<br />
<br />
<br />
<br />
<br />
MFRotation<br />
<br />
<br />
<br />
<br />
<br />
SFRotation<br />
SFFloat<br />
MFFloat<br />
MFVec3f<br />
SFVec3f<br />
SFFloat<br />
MFFloat<br />
MFVec3f<br />
MFVec3f<br />
SFFloat<br />
MFFloat<br />
MFFloat<br />
SFFloat<br />
SFFloat<br />
MFFloat<br />
MFColor<br />
SFColor<br />
eventIn<br />
Liste von<br />
Zwischenwerten<br />
(mindest.<br />
0 und 1)<br />
eventOut
Wirkung: Wert von key (zwischen 0 und 1) wird in Wert von<br />
keyValue "übersetzt" (durch lineare Interpolation zwischen<br />
den passenden Stützstellen). Die Länge der keyValue-Liste<br />
muss ein ganzzahliges Vielfaches der Länge der key-Liste sein<br />
(meist stimmen die Längen beider Listen überein). Die<br />
Kommunikation erfolgt über set_fraction (für den aktuellen<br />
Input) und value_changed (für den zugehörigen Output).<br />
Beachte: Bei der Interpolation von Farben wird intern das HSV-<br />
Modell benutzt (obwohl die Farbwerte in keyValue und<br />
value_changed als RGB-Farbwerte spezifiziert werden).<br />
Die Animation einer Szene mittels Interpolator-Knoten erfordert<br />
somit mindestens 2 ROUTE-Definitionen. Beispielsweise bei<br />
einer Positionsveränderung (Vektoren als Zwischenwerte):<br />
Beispiel:<br />
Animation eines ständig hüpfenden Balls. Das Zeitintervall für<br />
den Vorgang (der unendlich wiederholt wird) wird dem<br />
TimeSensor-Knoten mit 2 Sek. vorgegeben. Der<br />
PositionInterpolator-Knoten enthält äquidistante<br />
Stützstellen im Feld key und zugehörige Punkte auf einer<br />
umgekehrten Parabel im Feld keyValue, um bei der<br />
Bewegung des Balles den Eindruck von Schwerkraft zu<br />
vermitteln.
#<strong>VRML</strong> V2.0 utf8<br />
#Animation: Huepfender Ball<br />
<br />
DirectionalLight<br />
{direction 0 0 -1 }<br />
DEF Chronos TimeSensor<br />
{<br />
cycleInterval 2<br />
loop TRUE<br />
startTime 1<br />
}<br />
DEF PosCalc PositionInterpolator<br />
{<br />
key [ 0 0.1 0.2 0.3 0.4 0.5<br />
0.6 0.7 0.8 0.9 1 ]<br />
keyValue [ 0 0 0, 0 0.09 0, 0 0.16 0,<br />
00.21 0, 0 0.24 0, 0 0.25 0,<br />
00.24 0, 0 0.21 0, 0 0.16 0,<br />
00.09 0, 0 0 0 ]<br />
}<br />
DEF Verschieb Transform<br />
{<br />
children<br />
[<br />
Shape<br />
{<br />
geometry Sphere { radius 0.2 }<br />
appearance Appearance<br />
{<br />
material Material<br />
{diffuseColor 1 0 0 }<br />
}<br />
}<br />
]<br />
}<br />
ROUTE Chronos.fraction_changed TO <br />
PosCalc.set_fraction<br />
ROUTE PosCalc.value_changed TO <br />
Verschieb.set_translation
Ergebnis (2 Snapshots aus der Animationssequenz):<br />
Beispiel einer Farbinterpolation:<br />
Farbwechsel einer Kugel<br />
Die hierfür benötigten Ergebnisse des ColorInterpolator-<br />
Knotens werden an eines der Felder im Material-Knoten<br />
weitergeleitet, hier an diffuseColor (ein exposedField):<br />
#<strong>VRML</strong> V2.0 utf8<br />
#Animation: Farbwechsel einer Kugel<br />
<br />
DEF Chronos TimeSensor<br />
{<br />
cycleInterval 10<br />
loop TRUE<br />
startTime 1<br />
}
DEF FarbCalc ColorInterpolator<br />
{<br />
key [ 0 0.333 0.667 1 ]<br />
keyValue [ 1 0 0, 0 1 0, 0 0 1, 1 0 0 ]<br />
}<br />
Transform<br />
{<br />
children<br />
[<br />
DirectionalLight { }<br />
Shape<br />
{<br />
geometry Sphere { }<br />
appearance Appearance<br />
{<br />
material DEF KugelFarbe Material { }<br />
}<br />
}<br />
]<br />
}<br />
ROUTE Chronos.fraction_changed TO<br />
FarbCalc.set_fraction<br />
ROUTE FarbCalc.value_changed TO <br />
KugelFarbe.set_diffuseColor<br />
<br />
Ergebnis (3 Schnappschüsse):
Beispiel eines Blinkers:<br />
#<strong>VRML</strong> V2.0 utf8<br />
<br />
Transform<br />
{<br />
children<br />
[<br />
Shape<br />
{<br />
geometry Box { }<br />
appearance Appearance<br />
{<br />
material DEF Blinker Material { }<br />
}<br />
}<br />
]<br />
}<br />
DEF Timer TimeSensor<br />
{<br />
cycleInterval 5.0 # 5 Sek. Zyklusintervall<br />
loop TRUE<br />
}<br />
DEF Farbgeber ColorInterpolator<br />
{<br />
key [ 0.0, 1.0 ]<br />
keyValue [ 0 0 0, 1 0 0 ]<br />
}<br />
ROUTE Timer.fraction_changed TO <br />
Farbgeber.set_fraction<br />
ROUTE Farbgeber.value_changed TO <br />
Blinker.set_diffuseColor<br />
<br />
Ergebnis:
Interaktion<br />
Die Einbeziehung von Benutzer-Eingaben erfordert<br />
Sensorknoten (von denen der TimeSensor bereits ein<br />
Sonderfall war):<br />
TouchSensor Berührungssensor (wird aktiv bei<br />
Anklicken mit der Maus)<br />
ProximitySensor Annäherungssensor, spezifiziert durch<br />
umgebende Box<br />
PlaneSensor Abbildung der Mauscursor-Bewegung in<br />
eine Ebene parallel zur xy-Ebene<br />
CylinderSensor Abb. der Mauscursor-Bewegung auf<br />
eine Drehung einer Zylinderfläche mit<br />
Zylinderachse parallel zur y-Achse<br />
SphereSensor Abb. der Mauscursor-Bewegung auf<br />
eine Drehung einer Kugelfläche<br />
VisibilitySensor Ermittlung der Sichtbarkeit einer Box<br />
Touch-<br />
Sensor<br />
Proxi-<br />
mity-<br />
Sensor<br />
enabled<br />
SFBool<br />
<br />
<br />
hitPoint_changed SFVec3f<br />
hitNormal_changed SFVec3f<br />
hitTexCoord_changed SFVec2f<br />
isActive<br />
SFBool<br />
isOver<br />
SFBool<br />
touchTime<br />
SFTime<br />
center<br />
<br />
size<br />
enabled<br />
position_changed<br />
orientation_changed<br />
<br />
enterTime<br />
exitTime<br />
isActive<br />
SFVec3f<br />
<br />
SFVec3f<br />
SFBool<br />
SFVec3f<br />
SFRotation<br />
SFTime<br />
SFTime<br />
SFBool<br />
Start/Stop<br />
des Sensors<br />
)<br />
)<br />
) eventOut-<br />
) Felder<br />
)<br />
)<br />
Mittelpkt. der<br />
Box<br />
Ausdehnung<br />
Start/Stop<br />
)<br />
) eventOut-<br />
) Felder<br />
)<br />
)<br />
)
Plane-<br />
Sensor<br />
Cylin-<br />
der-<br />
Sensor<br />
Sphere-<br />
Sensor<br />
Visi-<br />
bility-<br />
Sensor<br />
autoOffset<br />
<br />
<br />
<br />
enabled<br />
offset<br />
<br />
maxPosition<br />
minPosition<br />
<br />
<br />
trackPoint_changed<br />
translation_changed<br />
isActive<br />
autoOffset<br />
enabled<br />
diskAngle<br />
offset<br />
maxAngle<br />
minAngle<br />
trackPoint_changed<br />
rotation_changed<br />
<br />
isActive<br />
autoOffset<br />
enabled<br />
offset<br />
<br />
trackPoint_changed<br />
rotation_changed<br />
<br />
isActive<br />
center<br />
size<br />
enabled<br />
enterTime<br />
exitTime<br />
isActive<br />
SFBool<br />
<br />
<br />
<br />
SFBool<br />
SFVec3f<br />
<br />
SFVec2f<br />
SFVec2f<br />
<br />
<br />
SFVec3f<br />
SFVec3f<br />
SFBool<br />
SFBool<br />
SFBool<br />
SFFloat<br />
SFFloat<br />
SFFloat<br />
SFFloat<br />
SFVec3f<br />
SFRotation<br />
SFBool<br />
SFBool<br />
SFBool<br />
SFRotation<br />
SFVec3f<br />
SFRotation<br />
SFBool<br />
SFVec3f<br />
SFVec3f<br />
SFBool<br />
SFTime<br />
SFTime<br />
SFBool<br />
Flag für Additivität<br />
der Bewegungskoordinaten<br />
Start/Stop<br />
Offset zur<br />
Koord.-ausg.<br />
Einschränkung<br />
der<br />
Sensoraktivität<br />
) eventOut-<br />
) Felder<br />
)<br />
analog zum<br />
Plane-<br />
Sensor-<br />
Knoten<br />
analog zum<br />
Plane-<br />
Sensor-<br />
Knoten<br />
Mittelpkt. Box<br />
Ausdehnung<br />
Start/Stop<br />
)<br />
) eventOut<br />
)
Skizze zur Bedeutung der Felder des ProximitySensor-<br />
Knotens:<br />
Beispiel:<br />
Einschalten einer Lichtquelle mit dem TouchSensor<br />
#<strong>VRML</strong> V2.0 utf8<br />
# Lichtschalter<br />
<br />
PointLight<br />
{location 0 0 10 }<br />
DEF Licht2 PointLight<br />
{<br />
location 0 2 0<br />
on FALSE<br />
}<br />
Transform<br />
{<br />
children<br />
[<br />
Shape<br />
{<br />
geometry Box { }<br />
appearance Appearance
{<br />
material Material<br />
{diffuseColor 1 1 0 }<br />
}<br />
}<br />
DEF Schalter TouchSensor { }<br />
]<br />
}<br />
ROUTE Schalter.isActive TO Licht2.on<br />
<br />
Ergebnis:<br />
ohne Benutzereingriff (Licht<br />
von oben ist ausgeschaltet):<br />
Benutzer hat durch Anklicken<br />
des Würfels mit der Maus das<br />
Licht von oben eingeschaltet:
Kollisionserkennung<br />
Generell sind alle Objekte außer IndexedLineSet-, PointSetund<br />
Text-Knoten mit der Fähigkeit des Erkennens von<br />
Kollisionen mit dem virtuellen Betrachter versehen.<br />
Beispiele: Simulation des Anstoßens an eine Wand, Berührung<br />
von Objekten, "realistisches" Begehen von Labyrinthen etc.<br />
Beachte: "Kollision" bezieht sich hier immer auf die Interaktion<br />
des Nutzers (bzw. seiner virtuellen Repräsentation im<br />
Cyberspace) mit einer (Objekt-) Geometrie, nicht auf Objekt-<br />
Objekt-Kollisionen!<br />
Die Kollisionserkennung ist als Default eingestellt.<br />
Das Verhalten bei einer erfolgten Kollision ist vom Browser<br />
abhängig.<br />
Die Reichweite der Prüfung auf Kollisionen zwischen Nutzer<br />
und virtuellen Objekten wird in einem NavigationInfo-<br />
Knoten im ersten Wert des Feldes avatarSize festgelegt.<br />
Objektspezifische Einstellungen des Kollisionsverhaltens<br />
erfolgen mittels des Collision-Knotens.<br />
Aufgaben dieses Knotens:<br />
• Ein- und Ausschalten der Kollisionserkennung für seine<br />
Kindknoten<br />
• Spezifikation eines Ersatzobjekts (proxy) mit einfacherer<br />
Geometrie oder einer bounding box zur Beschleunigung der<br />
Kollisionserkennung<br />
• Aussenden von Ereignissen an andere Knoten bei Kollision,<br />
um Effekte zu generieren<br />
• Setzen "unsichtbarer Wände" (wenn keine children,<br />
sondern nur ein proxy-Knoten definiert ist)
Felder des Collision-Knotens:<br />
children<br />
collide<br />
proxy<br />
bboxCenter<br />
bboxSize<br />
addChildren<br />
removeChildren<br />
collideTime<br />
MFNode<br />
SFBool<br />
SFNode<br />
SFVec3f<br />
SFVec3f<br />
MFNode<br />
MFNode<br />
SFTime<br />
Kindknoten<br />
Ein-Aus-Schalter<br />
Ersatzobjekt<br />
) boundig box-Spezifikation<br />
)<br />
eventIn<br />
eventIn<br />
eventOut (Zeitmarke der<br />
Kollision)<br />
Ist der Collision-Knoten der Wurzel-Knoten einer <strong>VRML</strong>-<br />
Szene und steht collide auf FALSE, so ist die Kollisionserkennung<br />
für die gesamte Szene deaktiviert, unabhängig<br />
davon, ob darunterliegende Knoten collide auf TRUE gesetzt<br />
haben oder nicht.<br />
Die bounding box wird deaktiviert durch den (Default-) Wert –1<br />
–1 –1 für bboxSize.<br />
Ist collide auf TRUE gesetzt und proxy nicht definiert (=<br />
NULL), so werden die children-Knoten zur Kollisionserkennung<br />
verwendet, sonst der proxy-Knoten, welcher aber<br />
nicht visuell dargestellt wird.<br />
Beispiel:<br />
Ein Würfel wird von einem größeren proxy-Würfel umgeben.<br />
Bei Kollision mit dem unsichtbaren, äußeren Würfel ändert der<br />
innere Würfel seine Farbe von Grün nach Rot:<br />
#<strong>VRML</strong> V2.0 utf8<br />
<br />
Transform<br />
{<br />
translation 0 0 -5<br />
children<br />
[
DEF Tabu_Zone Collision<br />
{<br />
collide TRUE<br />
children<br />
[<br />
Shape<br />
{<br />
geometry Box { }<br />
appearance Appearance<br />
{<br />
material DEF BoxFarbe<br />
Material <br />
{diffuseColor 0 1 0 }<br />
}<br />
}<br />
]<br />
proxy Shape<br />
{<br />
geometry Box { size 8 8 8 }<br />
}<br />
}<br />
]<br />
}<br />
DEF Timer TimeSensor { }<br />
DEF FarbCalc ColorInterpolator<br />
{<br />
key [ 0 1 ]<br />
keyValue [ 1 0 0, 1 0 0 ]<br />
}<br />
ROUTE Tabu_Zone.collideTime_changed TO<br />
Timer.startTime<br />
ROUTE Timer.fraction_changed TO<br />
FarbCalc.set_fraction<br />
ROUTE FarbCalc.value_changed TO<br />
BoxFarbe.set_diffuseColor<br />
<br />
Ergebnis (abhängig von Bewegungen des Benutzers):
Benutzer hält Abstand ein<br />
Benutzer ist mit dem<br />
unsichtbaren Außen-Würfel<br />
kollidiert<br />
Eine größere Annäherung als auf dem rechten Bild ist nicht<br />
mehr möglich.<br />
Switch-Knoten<br />
Funktion: Alternative Objekt-Auswahl je nach Zahlenwert eines<br />
Diskriminator-Feldes whichChoice (vgl. switch-Konstrukt in<br />
Java und C)<br />
Felder des Switch-Knotens:<br />
choice<br />
whichChoice<br />
MFNode<br />
SFInt32<br />
Liste der Alternativ-Knoten<br />
Diskriminator: Index des<br />
darzustellenden Kind-Knotens<br />
Die implizite Indizierung der Kind-Knoten ist 0; 1; 2; ... in der<br />
Reihenfolge ihrer Auflistung. Ist der Wert von whichChoice<br />
kleiner als 0 oder größer als die Anzahl der vorhandenen<br />
Kindknoten – 1, so erfolgt gar keine Wiedergabe.<br />
(Beispiel nach Einführung des Script-Knotens.)
Einbau von Scripten<br />
Der Script-Knoten ermöglicht die Kommunikation mit<br />
prozeduralen und objektorientierten Programmen und damit die<br />
Verfügbarmachung einer intelligenteren Programmierlogik in<br />
<strong>VRML</strong>-Szenen, als es mit den Mitteln von <strong>VRML</strong> allein möglich<br />
wäre.<br />
Anwendungen:<br />
• mathematische Operationen (Arithmetik, vektorielle<br />
Berechnungen)<br />
• Hilfsoperationen (z.B. Typkonvertierungen, Zerlegen<br />
zusammengesetzter Werte in ihre Komponenten u.<br />
umgekehrt)<br />
• Zwischenspeichern von Werten, die bestimmte Zustände<br />
beschreiben<br />
• Flexibilisierung der Ereignisverarbeitung<br />
• Simulationen<br />
• Multi-User-Anwendungen<br />
unterstützte Programmiersprachen:<br />
• Javascript (ECMAScript) und <strong>VRML</strong>Script (inline oder in<br />
externen Dateien)<br />
• Java (nur externe Bytecode-Dateien, Endung .class)<br />
Script-Knoten werden ähnlich wie Prototypen definiert: In<br />
ihrer Schnittstellen-Beschreibung können beliebig viele Felder<br />
und Ereignisse definiert werden, wobei die Felder zur<br />
Speicherung von Werten und die Ereignisse der Kommunikation<br />
mit Knoten der Szene dienen.<br />
Die Zugriffsart exposedField wird in Script-Knoten nicht<br />
unterstützt.<br />
Zu und von den Ereignissen der Script-Knoten können die<br />
üblichen Routen vereinbart werden. Darüberhinaus verfügen<br />
Script-Knoten über eine direkte Interaktionsmöglichkeit mit<br />
anderen Knoten, sofern diese direkt in einem seiner Felder<br />
definiert sind (Feldtyp SFNode oder MFNode) oder wenn aus
einem solchen Feld eine Referenz mit USE auf einen benannten<br />
Knoten (anderswo def.) hergestellt wurde. Für die direkte<br />
Interaktion muss das Feld directOutput auf TRUE gesetzt<br />
sein.<br />
Felder des Script-Knotens:<br />
url<br />
<br />
directOutput<br />
<br />
mustEvaluate<br />
beliebige Anzahl<br />
von:<br />
Feldname<br />
Ereignisname<br />
Ereignisname<br />
MFString<br />
<br />
SFBool<br />
<br />
SFBool<br />
Feldtyp (beliebig)<br />
eventIn<br />
eventOut<br />
eigentliches Skript<br />
(inline oder als url)<br />
ermöglicht direkte<br />
Interaktion mit Knoten<br />
steuert das<br />
Laufzeitverhalten<br />
+ Angabe von Defaultwert<br />
Beispiele verschiedener Typen von Codereferenzen im url-<br />
Feld:<br />
Script<br />
{<br />
url [<br />
"javascript: .... " # JavaScript-Protokoll, inline<br />
"file://test.js"# JavaScript-Protokoll aus Datei<br />
"file://test.class" ] # Java Bytecode aus Datei<br />
....<br />
}<br />
Das Scripting ermöglicht sehr vielfältige Interaktionsformen; hier<br />
nur ein sehr einfaches Beispiel:<br />
Eine Kugel soll sich auf einer Ellipse bewegen. Im Script-<br />
Knoten werden die Koordinaten berechnet unter Rückgriff auf<br />
trigonometrische Funktionen in JavaScript:
#<strong>VRML</strong> V2.0 utf8<br />
<br />
DEF Timer TimeSensor<br />
{<br />
cycleInterval 5<br />
loop TRUE<br />
}<br />
DEF Verschieb Transform<br />
{<br />
children<br />
[<br />
Shape<br />
{<br />
geometry Sphere { radius 0.2 }<br />
appearance Appearance<br />
{<br />
material Material<br />
{diffuseColor 1 1 0 }<br />
}<br />
}<br />
]<br />
}<br />
DEF Berechnung Script<br />
{<br />
eventIn SFFloat set_fraction<br />
eventOut SFVec3f value_changed<br />
url "javascript:<br />
//Funktionsberechnungen elliptische Bahn<br />
function set_fraction (wert, zeit)<br />
{<br />
value_changed[0] = <br />
Math.sin(wert * 6.283);<br />
value_changed[1] = <br />
0.5 * Math.cos(wert * 6.283);<br />
value_changed[2] = 5;<br />
}<br />
"<br />
}
ROUTE Timer.fraction_changed TO<br />
Berechnung.set_fraction<br />
ROUTE Berechnung.value_changed<br />
TO Verschieb.set_translation<br />
<br />
Der Name der JavaScript-Funktion entspricht demjenigen des<br />
zu verarbeitenden eventIn-Feldes (hier: set_fraction).<br />
An die Funktion wird immer ein Wert (der Wert des ankommenden<br />
Ereignisses) und eine Zeitmarke übergeben (die nicht<br />
notwendig verwendet werden müssen).<br />
Ergebnis des Beispiels (drei snapshots):<br />
Beispiel für die Anwendung des Script-Knotens zur<br />
Typumwandlung (hier: von SFFloat in SFInt32), zugleich<br />
Beispiel für einen Switch-Knoten:<br />
Ein Objekt verwandelt sich fortlaufend von einem Würfel in eine<br />
Kugel und umgekehrt.<br />
#<strong>VRML</strong> V2.0 utf8<br />
<br />
DEF Auswahl Switch<br />
{<br />
choice<br />
[<br />
Shape<br />
{geometry Box { } }<br />
Shape<br />
{geometry Sphere { } }<br />
]<br />
}
DEF Timer TimeSensor<br />
{<br />
cycleInterval 5 # Sekunden<br />
loop TRUE<br />
}<br />
DEF Berechnung Script<br />
{<br />
eventIn SFFloat set_fraction<br />
eventOut SFInt32 value_changed<br />
url "javascript:<br />
//Typkonvertierung<br />
function set_fraction (wert, zeit)<br />
{<br />
value_changed = wert+0.5;<br />
}<br />
"<br />
}<br />
ROUTE Timer.fraction_changed TO<br />
Berechnung.set_fraction<br />
ROUTE Berechnung.value_changed TO<br />
Auswahl.set_whichChoice<br />
<br />
Ergebnis (2 snapshots):