21.10.2014 Aufrufe

VRML-Kurs, Teil 4

VRML-Kurs, Teil 4

VRML-Kurs, Teil 4

MEHR ANZEIGEN
WENIGER ANZEIGEN

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):

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!