netscape http://home.netscape.com/eng/live3d/howto/1crab2.wrl
iexplorer http://home.netscape.com/eng/live3d/howto/1crab2.wrlaus.
Leider ist für Linux zur Zeit kein Cosmoplayer Plugin verfügbar.
Unter den zahlreichen Alternativen raten wir zur Zeit zur Software
LibVRML97/Lookat
Obwohl lookat eigentlich nur ein Beispielsprogramm für LibVRML97 und noch
nicht ganz vollständig ist, scheint
es zur Zeit der brauchbarste VRML noch erhältliche Viewer für Linux zu
sein (der vermutlich am weitesten entwickelte VRML Browser "liquid reality"
wurde wegen einer Firmenübernahme durch Microsoft vom Markt genommen).
Wenn Sie lookat benutzen wollen, sollten Sie sich seine
Kommandobelegung ausdrucken....
Mit Hilfe
des
Xswallow Plugins für netscape haben wir lookat in auf dem Pool
des ICA direkt in Netscape integriert, so daß man eigentlich nur auf
einen www Link einer VRML-Seite zu klicken müsste. Leider versagt
häfig die MIME-Type Erkennung und das VRML-File wird als Text
dargestellt. In diesem Fall schnappen Sie sich die URL ("Webadresse")
per Cut und Paste der Maus und geben sie als Argument dem Programm "xmlookat"
an. In unserem VRML 1.0 Beispiel wäre das:
xmlookat http://home.netscape.com/eng/live3d/howto/1crab2.wrl
Aber VRML 1.0 ist inkompatibel zu neueren VRML-Versionen. Deshalb kann nicht
jeder moderne VRML-Viewer das
"richtige"
VRML 1.0 Beispiel http://home.netscape.com/eng/live3d/howto/1crab2.wrl
darstellen. Auch das auf dem Linux CIP-Pool installierte
LibVRML97/Lookat
versagt hier.
Existierende VRML-Browser basieren technisch auf der OpenGL Graphikbibleothek. Sie ist ein Industriestandard für technische Visualisierung. Auf dem Markt existieren Graphikkarten mit 3D Unterstützung. Mit einer solchen Karte wird die CPU des Rechners stark von Rechenarbeit entlastet, so dass die Hardware eines Rechners einen grossen Einfluss auf die Darstellung des Rechners haben kann. 3D-Fähigkeit der Graphikkarte allein reicht aber nicht aus: GL-Karten sind häufig für Welten mit vielen Ecken konzipiert, während bei PC-Spiele-Karten häfig für Welten mit vielen Texturen (2D-Bilder, mit denen man glatte Flächen einer 3D-Welt "bekleben" kann) gebaut werden.
Um die langweiligen VRML 1.0 Welten abzulösen wurden in VRML 2.0
und in der davon abgeleiteten Version VRML 97 neue
Features aufgenommen: Animation, Multimediafähigkeit und Interaktion.
Spätens hier vollzog sich aber der wichtige Schritt vom 3D Datenformat
zur Programmierung.
Allerdings handelt es sich bei VRML nicht um die gewohnte prozedurale
Programmierung, wie Sie es von C, C++, Fortran, Pascal, Basic, Java usw.
gewohnt sind. Bei dieser Prozeduralen Programmierung wird ein Programm
mit einzelnen Schritten in der Zeitachse abgearbeitet.
Bei der deklarativen Programmierung hingegen wird das Problem lediglich
vollständig beschrieben. Der Sprachinterpreter/compiler übernimmt dann
den Rest der Arbeit, um das gewünschte Ergebnis zu erreichen.
Bezogen auf die Welt der Musik und sieht man die Musiker als
Sprachinterpreter an, ist das komponieren eines Musikstücks auf einem
Notenblatt eine ganz klar eine prozedurale Programmierung, während der
Wunsch an den Dirigenten alle Stücke der Gruppe ACDC zu spielen,
eher deklaritivie Programmierung ist.
Übung 1:
Speichern Sie das folgende einfache VRML Version 2.0 File in ein eigenes File und stellen Sie es dar.
#VRML V2.0 utf8 # Der Kommentar der ersten Zeile ist zwingend vorgeschrieben # Einfaches Hello World Programm das einen String darstellt und # einen Link ins World Wide Web darauf legt Anchor { children [ Shape { geometry Text { string ["Hello World"] } } ] description "Hello World" url "http://www.fourmilab.ch/cgi-bin/uncgi/Earth?imgsize=320&opt=-l&lat=0.184093&ns=North&lon=359.53&ew=West&alt=1000000&img=learth.evif" } # dieser Befehl gestaltet lediglich das Aussehen des Browsers NavigationInfo { type "EXAMINE" }Download HelloWorld.wrl
Um die VRML Syntax zu verstehen, kommt man um den Ausdruck "Scenengraph" nicht
herum. Ein Scenengraph hat für die moderne 3D Visualisierung in etwa die
Bedeutung wie das Nassi-Shneiderman Diagramm für die prozedurale
Programmierung. Soweit zu erfahren ist, gibt es aber keine normierte
Darstellung für einen Scenengraph...
In einem Scenengraph werden ausgehend vom graphischen Ursprung ("Nullpunkt")
alle graphischen Knoten in Baumform angeordnet.
Zusätzlich zu den Knoten werden in den Scenengraph auch noch Events
eingetragen. Events sind Ereignisse, die von Knoten an andere Knoten
geschickt werden und so Nachrichten übertragen.
Der Scenengraph für die bekannte "HelloWorld.wrl" Welt sieht so aus:
Am graphischen Ursprungsknoten (für den es keinen extra VRML-Befehl gibt),
hängt (neben dem weggelassenen weil unwichtigen "NavigationInfo"-Knoten)
der "Anchor"-Knoten
für einen Link ins World Wide Web. Der "Anchor"-Knoten enthält einen
"Shape"-Knoten, der ein sichtbares Object beschreibt. Der "Shape"-Knoten
enthält einen "geometry" Knoten, der den Text "Hello World" beschreibt.
Die wichtigste Knotenform ist der "Shape" Knoten, der einen
3-dimensionalen Körper beschreibt. Er enthält einen "geometry" Knoten,
der die geometrische Form des Körpers beschreibt. Er kann auch einen
"appearance" Knoten enthalten, der das Aussehen (z.B. Farbe, Durchsichtigkeit,
aufgeprägtes Muster ("Textur") usw.) dieses Körpers beschreibt.
Als geometrische Form stehen ausser einfachen Formen wie Quadrat, Kugel,
Zylinder, Kegel usw. auch kompliziertere Formen wie Flächen- (Linien-,
Punkte-) Ansammlungen und Ausstülpungen zur Verfügung.
Mit Flächenansammlungen lassen sich beliebige Körper darstellen.
Am einfachsten geht das, indem man einen Körper mit Dreiecken
überzieht (sogenannte "Trianglulierung"). Um zu verhindern, dass
zu viele Dreiecke benötigt werden, können die Reflexionseigenschaften
der einzelnen Flächen so beeinflußt werden, daß die Kanten
schwer zu sehen sind.
Übung 2:
Benutzen Sie das Programm ac3d (shareware,
http://www.comp.lancs.ac.uk/computing/users/andy/ac3d.html)
um ein Kugelsegment und eine benachbarten volle Kugel zu erzeugen:
Laden Sie das erzeugte VRML-File in ihren Browser, und schauen Sie sich die erzeugten Objecte etwas genauer an. Zum Vergleich sollten Sie sich auch mal die gleichen Objekte mit dem Renderer Povray anschauen, der auch spiegelnde Oberflächen beherrscht.
Mit einem kleinen Befehl Spiegelung einschalten
gawk '{f=1}/#declare ac3d_col_1 / {sub("finish {","finish { reflection 0.3");print ;f=0} {if(f==1) print}' Povrayfile.pov > kugeln2.pov
Povray aufrufen
x-povray +ikugeln2.pov +d +v +w400 +h300 +x +p +a0.3 +R9
Weitere wichtige Knotentypen sind zum Beispiel Tranformationsknoten (um
einen Körper zu verschieben, zu rotieren oder in der Grösse zu verändern)
oder der "Anchor" Knoten der einen Verweis auf eine Adresse ("URL" == Unified
Resource Location") im World Wide Web enthält.
Knoten, die das Keyword "children" enthalten (das sind z.B. der "Group"-Knoten,
wie auch Transformations- und Anchorknoten) können benutzt werden, um
mehrere Knoten zusammenzufassen.
Eine weitere wichtige Gruppe von Knoten sind die Sensorknoten. Sie werden für die Interaktion mit dem Benutzer (bzw. der Knoten untereinander) benutzt. Es gibt zum Beispiel Sensoren für Mausbewegungen, für Sichtbarkeit, für Betreten oder Verlassen eines Bereichs und für Kollisionen zwischen Körpern. Auch die wichtige Timerfunktion zählt als Sensorknoten. Sensoren sind die Quellen für Events.
Die nächste Gruppe von Knoten sind Interpolatoren. Sie werden benutzt, um
bestimmte Werte (Farbe, Oberflächenreflexion, geometrische Position,
Bewegung und Drehung) "durchdrehen" zu können. Sie empfangen ein Event,
(typsicherweise aus einem Timersenor) und wählen dadurch ein Event eines
bestimmten Typs (z.B. Farbe, Oberflächenreflexion usw.) aus einer Liste aus.
Damit lassen sich Animationen leicht verwirklichen.
Ein einfaches Beispiel für Interpolatoren aus einem VRML-Tutorial im
Internet lässt sich
unter
http://www.vapourtech.com/vrmlguide/tutorial/worlds/tut19.wrl bewundern.
Mit dieser Methode wird nun das Hello-World Beispiel animiert:
#VRML V2.0 utf8 # Der Kommentar der ersten Zeile ist zwingend vorgeschrieben # Einfaches Hello World Programm das einen String darstellt und # einen Link ins World Wide Web darauf legt # Animiert ueber einen Tranformknoten DEF SCHRIFT Transform { children [ Anchor { children [ Shape { geometry Text { string ["Hello World"] } } ] description "Hello World" url "http://www.fourmilab.ch/cgi-bin/uncgi/Earth?imgsize=320&opt=-l&lat=0.184093&ns=North&lon=359.53&ew=West&alt=1000000&img=learth.evif" } ] } 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 # dieser Befehl gestaltet lediglich das Aussehen des Browsers NavigationInfo { type "EXAMINE" }Download HelloWorld_animated.wrl
Im Scenengraph sind jetzt neue Element hinzugekommen.
Die rot gemalten Verbindungen symbolisieren die Events der ROUTE Befehle.
Die ROUTE Befehle sind so zu interpretieren: Der Timesensor spuckt
dauernd Werte zwischen 0 und 1 aus (welche Werte das sind, hägt davon
ab, wie schnell die Welt dargestellt wird). Diese Werte werden in den
Orientation Interpolator geroutet. Damit werden vom anhand von 3 Punkten
Zwischenwerte errechnet. Der resultierende Vektor der Dimension 4 der
zum Transformknoten (zustädig für Position, Rotation und Scalierung)
geroutet wird, representiert eine Drehung: Die ersten 3 Werte beschreiben eine
Drehachse, der 4. Wert representiert einen Winkel.
Aufgabe: Programmieren Sie das VRML-File so um, dass bei der Drehung die Schrift auf dem Kopf steht. Benutzen Sie auch mal willkühlich gewählte Werte um die Schrift ins Taumeln zu bringen.
Das Schreiben von ROUTE Befehlen erfordert die Kenntnis der Interna der
einzelnen Knoten. Schlagen Sie in einer
Knotenliste die Interna der an den Routes beteiligten Knoten
Transform, OrientationInterpolator und TimeSensor nach.
Wie sie sehen, haben die entsprechenden Events einen Datentyp, dessen
Korrektheit von VMRL-Broswer überprüft wird. Drucken Sie den
Scenengraph aus und tragen Sie die Datentypen ein.
Es gibt noch weitere Knotenformen und entsprechende Erweiterungen im
Scencengraph für Geräusche, Lichter, Kameraposition, Knoten zum Abschalten
anderer Knoten, Knoten für eine "ungenaue Ansicht" (z.B. aus grosser
Entfernung),
Nebel, den Bildschirmhintergrund, die Betrachtungsposition, die Werkzeuge des
VRML Viewers (lassen Sie einfach mal den "NavigationInfo"-Knoten weg, wenn
Sie den cosmoplayer benutzen...) usw.
Sie werden gegebenenfalls im weiteren Verlauf diskutiert.
Ein wichtiger Knotentyp wurde bisher nicht angesprochen und das aus gutem Grund: Er durchbricht das Prinzip der deklarativen Programmierung. Obwohl in VRML sehr eindrucksvolle Animationen mit rein deklarativer Programmierung möglich sind (z.B. ), geht es doch nicht immer ganz ohne die gewohnte prozedurale Programmierung.
Prozedurale Programmierung ist implementiert als spezieller Script-Knoten, der Programme einer prozeduralen Programmiersprache, nämlich Java aufnimmt. Beide Java-Implementierungen sind möglich: "richtiges" Bytecode-Java in Form einer Java-Klasse als auch interpretiertes Javascript mit seinen eingeschr&aum;nkten Fähigkeiten. Wir benutzen Javascript, da es zur Zeit von den eingesetzen VRML-Viewern als normiertes "vrmlscript" besser unterstützt wird.
Um zu zeigen, wie Javascript eingesetzt wird, muss das folgende VRML-Programm umgeschrieben werden.
#VRML V2.0 utf8 # Der Kommentar der ersten Zeile ist zwingend vorgeschrieben # Einfaches Hello World Programm das einen String darstellt und # einen Link ins World Wide Web darauf legt # Animiert ueber einen Tranformknoten DEF SCHRIFT_POSITION Transform { children [ DEF SCHRIFT Transform { children [ Anchor { children [ Shape { geometry Text { string ["Hello World"] } } ] description "Hello World" url "http://www.csv.ica.uni-stuttgart.de/homes/js/javakurs/HelloWorld2.wrl" } ] } ] } DEF ROTOTATOR OrientationInterpolator { key [0, 0.5, 1] keyValue [ 0 1 0 0, 0 1 0 3.14, 0 1 0 6.28 ] } DEF POSITIONATOR Script { eventIn SFFloat eingang_float eventOut SFVec3f ausgang_3D_float_vektor url "vrmlscript: function initialize() { } function eingang_float(val) { ausgang_3D_float_vektor[0]=0; ausgang_3D_float_vektor[1]=0; ausgang_3D_float_vektor[2]=10*val; } " } DEF TIMER TimeSensor { cycleInterval 10 loop TRUE } ROUTE TIMER.fraction_changed TO ROTOTATOR.set_fraction ROUTE ROTOTATOR.value_changed TO SCHRIFT.set_rotation ROUTE TIMER.fraction_changed TO POSITIONATOR.eingang_float ROUTE POSITIONATOR.ausgang_3D_float_vektor TO SCHRIFT_POSITION.set_translation # dieser Befehl gestaltet lediglich das Aussehen des Browsers NavigationInfo { type "EXAMINE" }Download HelloWorld_script.wrl Unser Shapeknoten wird nun nicht nur gedreht, sondern zusätzlich bewegt. Der Scenengraph enthält dazu einen neuen Transformknoten.
Anstelle der langweiligen Bewegung vor und zuruück soll
der Shapeknoten auf eine Kurvenbahn geschickt werden.
Die Position einer Kreisbahn in der X-Z-Ebene ist:
Bedenken Sie, dass Sie mit Java Programmieren und Sie deswegen Math.sin(),Math.cos() und Math.PI benutzen müssen.
Ersetzen Sie jetzt den langweilig gewordenen Shape-Knoten mit der Schrift mit diesem interessanteren Box Knoten, der mit einer Textur beklebt ist.
Shape { appearance Appearance { texture ImageTexture { url "a149.png" } } geometry Box {} }
Um Modular programmieren zu können, enthält VRML auch Bestandteile, Programme auf mehrere Files auszuteilen. Die einfachste Konstruktion ist dabei die Inline-Konstruktion.
Benutzen Sie
Inline { url "das_file_aus_ac3d.wrl" }
statt dem Shapeknoten, um den schon oben benutzten VRML 2 Output von AC3D zu
animieren.
VRML besitzt mit dem PROTO Konstrukt auch die Möglichkeit, funktionsähnliche Konstruktionen für wiederverwendbare Software zu schreiben und diese Bestandteile mit dem EXTERN PROTO Konstrukt in einer Art nutzbaren Sourcecodelibrary abzuspeichern. Allerdings führt die Besprechung dieser Konstruktionen hier zu weit...
Als Abschlussaufgabe sollen Sie mit folgendem VRML-Script beschäftigen:
#VRML V2.0 utf8 # Der Kommentar der ersten Zeile ist zwingend vorgeschrieben # Einfaches Hello World Programm das einen String darstellt und # einen Link ins World Wide Web darauf legt # Animiert ueber einen Tranformknoten DEF POSITION Transform { children [ DEF QUERACHSE Transform { children [ DEF HOCHACHSE Transform { children [ Anchor { children [ DEF SCHALTER Switch { choice [ Transform { scale 0.1 0.1 0.1 children [ Inline { url "http://vrml.km-cd.com/Objects/Aircraft/Paper_Airplane.wrl" } ] } Shape { geometry Text { string ["Zensiert !"] } } ] } ] description "Hello World" url "http://www.csv.ica.uni-stuttgart.de/homes/js/javakurs/HelloWorld2.wrl" } ] } ] } ] } DEF HOCHROTATION OrientationInterpolator { key [0, 0.25, 0.375, 0.5, 0.75, 0.875, 1] keyValue [ 0 -1 0 3.14, # 0 - 0.25 0 -1 0 3.14, # 0.25 - 0.375 0 -1 0 -1.57, # 0.375 - 0.5 0 -1 0 0, # 0.5 - 0.75 0 -1 0 0, # 0.75 - 0.875 0 -1 0 1.57, # 0.875 - 1 0 -1 0 3.14, ] } DEF QUERROTATION OrientationInterpolator { key [0, 0.25, 0.375, 0.5, 0.75, 0.875, 1] keyValue [ 0 0 0 0, # 0 - 0.25 0 0 0 0, # 0.25 - 0.375 1 0 0 -1.57, # 0.375 - 0.5 0 0 0 0, # 0.5 - 0.75 0 0 0 0, # 0.75 - 0.875 1 0 0 1.57, # 0.875 - 1 0 0 0 0, ] } DEF POSITIONATOR Script { eventIn SFFloat eingang_float eventOut SFVec3f ausgang_3D_float_vektor field SFFloat radius 2 field SFFloat laenge 4 url "vrmlscript: function initialize() { } function eingang_float(val) { if (val<0.25) { ausgang_3D_float_vektor[0]=0; ausgang_3D_float_vektor[1]=0; ausgang_3D_float_vektor[2]=0; } else if (val<0.5) { ausgang_3D_float_vektor[0]=radius*Math.cos((val-0.25)*4*Math.PI); ausgang_3D_float_vektor[1]=0; ausgang_3D_float_vektor[2]=radius*Math.sin((val-0.25)*4*Math.PI) +laenge; } else if (val<0.75) { ausgang_3D_float_vektor[0]=0; ausgang_3D_float_vektor[1]=0; ausgang_3D_float_vektor[2]=0; } else if (val<1) { ausgang_3D_float_vektor[0]=radius*Math.cos((val-0.5)*4*Math.PI); ausgang_3D_float_vektor[1]=0; ausgang_3D_float_vektor[2]=radius*Math.sin((val-0.5)*4*Math.PI); } } " } DEF AUSWAHL Script { eventIn SFFloat eingang_float eventOut SFInt32 output url "vrmlscript: function initialize() { } function eingang_float(val) { if (val<0.25) { output=-1; } else if (val<0.5) { output=0; } else if (val<0.75) { output=1; } else if (val<1) { output=0; } } " } DEF BOX Transform { scale 0.5 0.5 0.2 children [ DEF touched TouchSensor {} Shape { appearance Appearance { texture ImageTexture { url "a149.png" } } geometry Box {} } ] } DEF TIMER TimeSensor { cycleInterval 10 loop TRUE } ROUTE TIMER.fraction_changed TO HOCHROTATION.set_fraction ROUTE HOCHROTATION.value_changed TO HOCHACHSE.set_rotation ROUTE TIMER.fraction_changed TO QUERROTATION.set_fraction ROUTE QUERROTATION.value_changed TO QUERACHSE.set_rotation ROUTE TIMER.fraction_changed TO POSITIONATOR.eingang_float ROUTE POSITIONATOR.ausgang_3D_float_vektor TO POSITION.set_translation ROUTE touched.hitPoint_changed TO BOX.set_translation ROUTE TIMER.fraction_changed TO AUSWAHL.eingang_float ROUTE AUSWAHL.output TO SCHALTER.whichChoice # dieser Befehl gestaltet lediglich das Aussehen des Browsers NavigationInfo { type "EXAMINE" }Download HelloWorld_aufgabe.wrl Es simuliert den Flug eines Flugzeugs. Liefert der Timesensor eine Zeit von 0 bis 0.25 oder 0.5 bis 0.75 sollte das Flugzeug geradeausfliegen und an den Endpunkten der Kurvenbahnen ankommen. Der Geradeausflug ist allerdings gelöscht worden.
Leider ist in diesem Praktikum der Punkt "Interation mit der Maus"
etwas zu kurz gekommen. Deshalb enthält die Aufgabe noch einen
Sensor, der sich bewegt, wenn er vom Mauszeiger berührt wird.
Überlegen Sie, ob sie diesen Sensor einsetzen können.
Um ein Testat für diesen Teil des AIM-Praktikums zu bekommen, schicken Sie bitte Ihr Programm per mail an scheurich@csv.ica.uni-stuttgart.de und vergessen Sie nicht, ihren Namen mit anzugeben.