VRML ist eine deklarative Sprache. Im Vergleich zu einem traditionellen 3D-Programm in einer prozeduralen Sprache (z.B. ein OpenGL Programm in C) heisst das, dass man sich nicht über Dinge wie "jetzt mache ich ein Fenster auf dem Schirm auf", "jetzt will ich wissen, ob und wo ein Mausklick passiert ist" oder "jetzt verschiebe ich diesen Körper um 5 Einheiten" kümmern muss.
Stattdessen beschreibt man lediglich die Eigenschaften der gewünschten 3D Welt, um den Rest kümmert sich dann der VRML-Browser. Solche Eigenschaften sind zum Beispiel: "an dieser Stelle soll ein 3D-Körper mit der Geometrie einer Kugel erscheinen" oder "wenn auf die Kugel geklickt wurde, soll die Kugel langsam um 5 Einheiten verschoben werden".
Grundlage einer solchen Beschreibung bei 3D-Programmierung ist der Scenengraph. Er wird auch häufig als Dokumentationsform für traditionelle 3D-Programme in prozeduralen Sprachen benutzt.
Im Scenengraph werden ausgehend vom graphischen Ursprung ("Nullpunkt") alle graphischen Knoten (z.B. geometrischer Körper, Bewegung usw.) in Baumform angeordnet.
Zusätzlich zu den Knoten werden in den Scenengraph auch "Routes" eingetragen. Routes übertragen Ereignisse ("Events" z.B die Zeit, eine Verschiebung oder Rotation) von Knoten zu Knoten.
Knoten, die Events abhängig von einem äusseren Einfluss (z.B. Mausklick, Ablauf einer Uhr, ein Punkt im Raum wird für die Kamera sichtbar usw.) aussenden, nennt man "Sensoren".
Eine weitere wichtige Klasse von Knoten sind Interpolationsknoten. Sie empfangen Events und verarbeiten sie zu neuen Events. Dabei wird ausgehend vom Eingangsevent ein Mittelwert aus dem vorgegebenen Eingangsbereich des Interpolatorknotens gebildet. Dieser Mittelwert wird auf den vorgegebenen Ausgangsbereich der Interpolatorknotens übertragen und damit ein Ausgangsevent erzeugt.
Ein einfaches Beispiel eines Scenengraph:
Klicken Sie hier um die volle Fenstergröße ihres Browsers zu nutzen.
Im Scenengraph steht unterhalb des graphischenUrsprungs ein "Anchor" Knoten, so dass ein Mausklick auf folgende Körper im Scenengraph das Laden der entsprechenden HTML-Seite (oder auch VRML-Seite) im World Wide Web bewirkt. Danach folgt ein "Transform" Knoten, der für die Bewegung/Verzerrung der folgenden Knoten im Scenengraph zuständig ist. Der Transformknoten wirkt auf zwei weitere Knoten: einen "Shape" Knoten, der als geometrischen Körper einen Schriftzug enthält und einen "Inline" Knoten, der ein weiteres VRML File einhält, das von Steve Baker mit dem 3D-Modeller AC3D erstellt wurde.
Animiert wird diese VRML-Welt über einen "Timesensor" Knoten, der dauernd einen Time-Event (einWert zwischen 0 und 1) in eine Route leitet, die zu einem "OrientationInterpolator" Knoten führt. Daraus erzeugt der Orientationinterpolator einen Rotationsevent (eine Drehung, die aus dem Achsevektor (0 1 0) und einem Winkel zwischen 0 und 2*Pi besteht). Über eine Route wird der Rotationsevent in den Transformknoten geleitet, der den Shapeknoten und den Inlineknoten enthält.
Insgesamt ergibt sich also eine VRML-Welt mit einem sich drehenden Schriftzug und einem sich drehenden 3D-Modell.
Klicken Sie hier um die volle Fenstergröße ihres Browsers zu nutzen.
Betrachtet man den Quellcode dieses Programms, so erkennt man, dass der Inhalt eines VRML-Programms nichts anderes ist, als eine Abbildung des entsprechenden Scenengraphs.
#VRML V2.0 utf8
# Der Kommentar der ersten Zeile ist zwingend vorgeschrieben
# Einfaches Hello World Programm das einen String und ein 3D-VRML Modell
# darstellt animiert und einen Link ins World Wide Web darauf legt
Background
{
skyColor 0 0 1
}
Anchor
{
children
[
DEF SCHRIFT Transform
{
children
[
Inline { url "tux.wrl" }
Shape
{
geometry Text
{
string ["Hello World"]
}
}
]
}
]
description "Hello World"
url "http://www.csv.ica.uni-stuttgart.de/vrml/vrml_csv.html"
}
DEF ROTOTATOR OrientationInterpolator
{
key [0, 0.5, 1]
keyValue
[
0 1 0 0,
0 1 0 3.14,
0 1 0 6.28
]
}
DEF TIMER TimeSensor
{
cycleInterval 10
loop TRUE
}
ROUTE TIMER.fraction_changed TO ROTOTATOR.set_fraction
ROUTE ROTOTATOR.value_changed TO SCHRIFT.set_rotation
An Stelle eines eigentlich unnötigen "Nullpunkt"-Knotens tritt ein "Background"-Knoten, der die Hintergrundfarbe dieser VRML-Welt einstellt.
VRML unterstützt die Programmiersprachen
Javascript ("jscript", "vrmlscript", eigentlich "ECMA
Script" ISO/IEC 16262) und Java im Anhang der VRML
Spezifikation ISO/IEC 14772.
Sie werden sich fragen, wie diese prozeduralen Sprachen in das Konzept
der deklarativen Sprache passen. Programmcode in diesen prozeduralen Sprachen
werden in eigene "Script"-Knoten geschrieben, um damit Events gezielt zu
verarbeiten. Dabei kann so ein Scriptknoten mehrere Events aussenden oder
empfangen.
Im einfachen VRML Programm von oben lässt sich zum Beispiel der OrientationInterpolator
DEF ROTOTATOR OrientationInterpolator
{
key [0, 0.5, 1]
keyValue
[
0 1 0 0,
0 1 0 3.14,
0 1 0 6.28
]
}
durch einen gleichwertigen Scriptknoten
DEF ROTOTATOR Script
{
eventIn SFFloat set_fraction
eventOut SFRotation value_changed
url "vrmlscript:
function set_fraction(value)
{
value_changed[0]=0;
value_changed[1]=1;
value_changed[2]=0;
value_changed[3]=value*2.0*Math.PI;
}
"
}
austauschen, der vrmlscript ("ECMA-script","Javascript") benutzt.
Das Beispiel mit Javascript finden Sie hier
Mit den vrmlscript-Funktionen "createVrmlFromString", "createVrmlFromURL" und "addRoute" lassen sich neue VRML-Knoten in einen bestehenden Scenengraph einbauen und animieren.
Ansonsten sind die Möglichkeiten von vrmlscript ziemlich
beschränkt, da (laut Standard) nur VRML-spezifische Funktionen
zur Verfügung stehen.
Um diese Beschränkungen zu umgehen, benötigt man Scriptknoten,
die die Sprache Java unterstützen. Damit stehen alle
Möglichkeiten des Java API zur Verfügung.
Der gleichwertigen Scriptknoten in unserem Beispiel ergibt sich dann zu
DEF ROTOTATOR Script
{
eventIn SFFloat set_fraction
eventOut SFRotation value_changed
url "hello_java.class"
}
hello_java.class ist dabei eine Javabytecode Klasse. Sie muss aus dem Javaprogramm
import vrml.field.*;
import vrml.node.*;
import vrml.*;
public class hello_java extends vrml.node.Script
{
float[] rotation=new float[4];
public void processEvent(Event e)
{
if (e.getName().equals("set_fraction"))
{
//System.out.println("silly debug message");
rotation[0]=0.0f;
rotation[1]=1.0f;
rotation[2]=0.0f;
rotation[3]=((ConstSFFloat)e.getValue()).getValue()
*2.0f*(float)Math.PI;
SFRotation value_changed=(SFRotation)getEventOut("value_changed");
value_changed.setValue(rotation);
}
}
}
kompiliert werden. Beachten Sie dabei, dass der Java CLASSPATH die Klassen vrml.* usw. enthalten muss. Diese Klassen werden üblicherweise mit Ihrem VRML-Browser mitgeliefert.
Das Beispiel mit Java finden Sie hier
Ausserdem