VRML & Java | |
Mit der Virtual Reality Modeling Language (VRML) ist man in der Lage komplexe 3D-Welten bzw. 3D-Objekte zu beschreiben. Diese Objekte können statisch oder animiert sein. Man kann dabei auf vordefinierte Objekte zurückgreifen oder sich benutzerdefinierte Objekte selbst erstellen. Objekte werden durch ihre Eigenschaften beschrieben (Aussehen, Material, Geometrie).
Skript-Knoten ermöglichen es auf Benutzereingaben (Ereignisse) zu reagieren.
Ereignisse werden über Sensoren (die an Objekte gebunden sind) ausgelöst.
Die Verarbeitung der Ereignisse kann dabei durch die Skript-Sprachen Java- bzw. VRML-Skript oder durch die Programmiersprache Java erfolgen.
Eine VRML-Datei beginnt grundsätzlich mit folgendem File-Header
#VRML V2.0 utf8
Dieser Eintrag darf nicht fehlen, da die Datei ansonsten nicht vom VRML-Browser interpretiert wird !
#VRML | Kennzeichnung, daß die Datei VRML-Code enthält |
V2.0 | konform zur VRML-Syntax 2.0 |
utf8 | gecodet nach dem internationalen utf8-Zeichensatz UCS (Universal Character Set) Transformation Format, 8-bit |
# Ein Kommentar
Um die Lesbarkeit des Quellcodes zu verbessern, lassen sich Kommentare in den Text einfügen, die vom Browser nicht interpretiert werden. Ein Kommentar beginnt mit einem (#)-Zeichen und endet am Zeilenende.
Box {
}
Eine VRML-Datei besitzt eine Baumstruktur ( Szenegraph ).
Jeder Knoten
Eingehende Ereignisse werden durch das Schlüsselwort set_ (set_color, set_position) und ausgehende Ereignisse durch das Schlüsselwort _changed beschrieben (color_changed, position_changed).
Über das Schlüsselwort DEF kann einem Knoten ein Name zugewiesen werden, der dann von einem anderen Knoten über das Schlüsselwort USE referenziert werden kann.
So ist es zum Beispiel möglich einer Box eine Farbe zuzuweisen und diesen Farbknoten zu benennen (Box1 ..... material DEF ROT Material...). Bei der Deklaration einer weiteren Box kann man dann auf diese Farbeigenschaft über USE zugreifen (Box2 ..... material USE ROT). Eine Änderung der Farbe der ersten Box zieht natürlich eine Änderung der Farbe der zweiten Box mit sich, da es sich um eine Referenzierung handelt.
Es ist wichtig, daß man seine Knoten benennt, da man so später durch die Verbindung der Knoten mit ROUTES eine Ereignisweiterleitung ermöglicht.
Man kann sich das folgendermaßen vorstellen:
"Angenommen man hätte einen Schalter, ein Kabel und eine Lampe. Würde man auf den Schalter drücken ohne vorher das Kabel mit dem Schalter und der Lampe zu verbinden, würde rein gar nichts passieren."
Box { height 2.0
}
Felder beschreiben Knotenattribute, d.h. sie sind vergleichbar mit den Variablen einer Programmiersprache.
Jedes Feld besitzt
Werden bei der Knotendeklaration Felder nicht parametrisiert, werden automatisch die dafür in der Spezifikation festgelegten Default-Werte genommen.
Felder werden weiterhin untergliedert in
ExposedFields können folgendermaßen beschrieben werden.
Die Deklaration von einem
exposedField Name
ist äquivalent zu
eventIn set_Name
field Name
eventOut Name_changed
Wenn z.B. ein Script-Knoten den Feldinhalt eines exposedField Name ändern will, kann man sich das folgendermaßen vorstellen:
Gruppenknoten fassen mehrere Kind-Knoten zusammen Damit lassen sich komplexe Objekte beschreiben, die aus mehreren Geometrie-Knoten (Shapes) zusammengesetzt sind (Box, Sphere etc.). Man könnte natürlich auch alle Knoten (aus denen ein komplexes Gebilde besteht) einzeln deklarieren. Der Nachteil dabei wäre aber, daß man bei einer Bewegung des ganzen Objektes die Position der Knoten einzeln verändern müßte. Wenn allerdings die Position eines Gruppenknotens verändert wird, ändern sich automatisch alle Kind-Knoten relativ zum Gruppenknoten mit.
Es gibt folgende Gruppenknoten:
Hyperlinkfunktion zu anderen VRML-Welten | |
Ändern des lokalen Koordinatensystems in Abhängigkeit zur Bewegung des Benutzers | |
Kollisionserkennung | |
Gruppierungsknoten | |
Translation / Rotation / Skalierung von Objekten | |
Inhalt von anderen VRML-Dateien in den Quelltext einbinden | |
Level of Detail (steuert den Detailierungsgrad eines Objektes in Abhängigkeit von der Entfernung des Betrachters zum Objekt). | |
Beinhaltet mehrere Knoten, von denen jedoch nur einer angezeigt wird (je nach Auswahl). |
Einer der am häufigsten verwendeten Gruppenknoten ist der Transform-Knoten. Wird z.B. ein neues Geometrie-Objekt erzeugt, so wird es im Mittelpunkt der VRML-Welt (Koordinaten 0 0 0) plaziert.
Über den Transform-Knoten wird es ermöglicht, die Position des Objektes relativ zum Vorgänger (in der Hierarchie) zu setzen/verändern - das betrifft natürlich auch die Kinder, die ein Knoten hat. Dieser Knoten ermöglicht auch die Rotation und Skalierung von Objekten.
Beschreibung
Blatt-Knoten bilden die untersten Ebenen eines Szenegraphen. Sie können keine Kinder mehr erzeugen, d.h. sie bilden die Endpunkte (Blätter) einer Baumstruktur (des Szenegraphen).
|
Die Objekte in einer VRML-Welt bestehen aus Shapes, die durch ihre
Geometrie-Eigenschaft (geometry) und ihr Erscheinungsbild (apperance) beschrieben werden. So ist es möglich entweder einfache geometrische Objekte (Box, Cone, Cylinder, Sphere) oder auch komplexere Gebilde wie Extrusionen (Extrusion) oder Verbundobjekte (IndexedFaceSet ...) zu erzeugen und diesen dann ein bestimmtes Erscheinungsbild zu geben (Materialeigenschaften [Farbe, Transparenz, Spiegelung] oder Oberflächeneigenschaften [Texturen]). |
|
Mit Sound-Knoten kann die gesamte Soundkulisse definiert werden (Intensität, Richtung etc.) bzw. es können Musik / Samples abgespielt werden. |
|
Über Sensoren ist es möglich Benutzereingaben zu erkennen, um dann
Ereignisse auszulösen, die eine Veränderung der Welt herbeiführen sollen
(Interaktivität).
|
|
Interpolatoren bieten eine einfache Möglichkeit Animationen durch Interpolation zu erzeugen. |
|
Die unabhängigen Knoten haben vielfältige Eigenschaften. Sie definieren z.B. Lichtquellen, ermöglichen es verschiedene Kamerapositionen festzulegen, zwischen denen der Benutzer wechseln kann, oder erstellen einen Hintergrund für die Welt (Boden, Himmel etc.). |
Der Script-Knoten letztendlich ist die Ein-Ausgabeschnittstelle für Script- bzw. Programmiersprachen. |
Eine ROUTE bildet eine explizite Verbindung zwischen zwei Feldern von zwei Knoten
Durch diese Verbindung können Ereignisse ( Events ) zwischen den verbundenen Knoten transportiert werden.
|
kein externer Zugriff möglich |
|
Schreibrechte |
|
Leserechte |
|
Lese - und Schreibrechte |
ROUTE fromNode.eventOutField TO toNode.eventInField
So wird ein Knoten (fromNode), der ein Ereignis senden kann, mit einem anderen Knoten (toNode), der ein Ereignis empfangen kann, verbunden.
ROUTES können in jeder beliebigen Reihenfolge im Quelltext stehen, jedoch müssen erst die zu verbindenden Knoten ( mit DEF ) benannt worden sein.
Ein Knoten kann auch mit mehreren ROUTES verknüpft sein, d.h. es können mehrere Verbindungen von einem Knoten wegführen (fan-out) oder mehrere Verbindungen zu einem Knoten hinführen (fan-in).
Sensoren reagieren auf das Eingabemedium des Anwenders und erzeugen so Ereignisse, die Veränderungen in der VRML-Welt zur Folge haben.
Man unterscheidet dabei folgende Sensoren
|
erlaubt eine zylindrische Rotationsbewegung des Objektes um seine Y-Achse (isActive, rotation_changed) |
|
erlaubt eine Verschiebung des Objektes in der X-Y Ebene (isActive, translation_changed) |
|
wird ausgelöst, wenn sich der Benutzer dem Sensor nähert (enterTime, isActive, exitTime) |
|
erlaubt eine Rotationsbewegung um alle Achsen (isActive, rotation_changed) |
generiert Zeitereignisse, die zyklisch ausgelöst / gesendet werden | |
|
reagiert auf die Berührung durch das Eingabemedium (isOver, isActive, touchTime) |
|
überprüft, ob ein Objekt sichtbar ist oder nicht. Dadurch werden nur die
Objekte berechnet, die sichtbar sind (CPU-Entlastung). (enterTime, isActive, exitTime) |
Ein Sensor ist allerdings kein Guppenknoten, sondern ein Blatt-Knoten und wird immer in der Gruppe plaziert, in der das Shape-Objekt deklariert wird, an das er gebunden werden soll. Ist ein Sensor an einen Gruppenknoten gebunden, dann reagieren auch alle Kinder dieses Knotens auf den Sensor.
Wenn sich unterschiedliche Sensoren im selben Gruppenknoten befinden, so reagieren sie alle auf einmal.
Ereignisse ( Events ) werden über Sensoren erzeugt. Das geschieht entweder über den Anwender, indem er einen Sensor auslöst, oder durch ein zyklisch generiertes Event von einem TimeSensor.
Ereignisse setzen sich aus 2 Werten zusammen:
Der Zeitstempel speichert den Zeitpunkt, an dem das Event erzeugt worden ist. So wird die Reihenfolge festgelegt, in der die Events abgearbeitet werden.
Man legt Start- Zwischen- und Endwerte fest und VRML berechnet die Zwischenschritte. Eine Berechnung erfolgt in einem bestimmten Zyklus - immer genau dann, wenn ein TimeSensor ein set_fraction Event an einen Interpolator routet. Der Interpolator vergleicht dann den erhaltenen Zeitwert mit der Schrittliste [key list], berechnet den Rückgabewert und sendet dann ein value_changed Event, an das zu animierende Objekt
.
|
wandelt Zeitereignisse in Farbänderungen um. (Material node - set_diffuseColor, set_emissiveColor) |
|
Interpolationsmethoden, die mehrere Rückgabewerte liefern. |
|
|
|
wandelt Zeitereignisse in Rotationsbewegungen um. (Transform node - set_rotation) |
|
wandelt Zeitereignisse in Translationen um. (Transform node - set_translation, set_scale) |
|
wandelt Zeitereignisse in Transparenz um. (Material node - set_transparency) |
Für eine Interpolation werden 2 Listen benötigt:
Beispiel (Zeitpunkte 0.0 und 1.0 sind vorgegeben)
Zeit | Position | |
0.0 | 0.0 0.0 0.0 | |
0.1 | 0.4 0.1 0.0 | |
0.2 | 0.8 0.2 0.0 | |
... | ... | |
1.0 | 4.0 1.0 0.0 |
PositionInterpolator {
key [ 0.0 , 1.0 ]
keyValue [ 0.0 0.0 0.0 , 4.0 1.0 0.0 ]
}
PROTO / EXTERNPROTO
Bei Proto´s handelt es sich um benutzerdefinierte Knoten, die durch Instantiierung wiederverwendet werden können. (Konzept der Kapselung und Parametrisierung)Dazu wird eine allgemeine Schnittstelle festgelegt, die aus mehreren Variablen bestehen kann.
PROTO KnotenName [
field | Datentyp | Name | Default |
exposedField | Datentyp | Name | Default |
eventIn | Datentyp | Name | |
eventOut | Datentyp | Name |
]
{ Quellcode }
Im Quellcode kann auf die in der Schnittstelle definierten Variablen über das Schlüsselwort IS zugegriffen werden.
Der Aufruf eines Prototyps erfolgt wie auch bei anderen Knoten durch Angabe des Namens gefolgt von einer Parameterliste in geschweiften Klammern.
KnotenName { Parameter }
Prototypen, die in anderen VRML-Dateien definiert sind, können auch importiert werden. Dazu muß lediglich die Schnittstelle des Prototypen (ohne Default-Werte) mit dem Schlüsselwort EXTERNPROTO angegeben werden, gefolgt von der URL, an der die Datei mit dem Prototypen zu finden ist.
EXTERNPROTO KnotenName [
field | Datentyp | Name |
exposedField | Datentyp | Name |
eventIn | Datentyp | Name |
eventOut | Datentyp | Name |
]
"URL"