OpenGL.org 3Dsource.de: Infos rund um 3D-Computergrafik, OpenGL und VRML
space Telefon-Tarife space VDI - Arbeitskreis Fahrzeugtechnik space Beschallungsanlagen und Elektroakustik space Heise-News space

VRML-Programmbeispiel


VRML-Dateien mit OpenGL darstellen:

Vielleicht habt ihr schon festgestellt, dass das Programmieren mit OpenGL doch ziemlich zeitaufwendig ist, da jedes einzelne Objekt erstmal bis ins kleinste beschrieben werden muss.

Etwas einfacher wird es, wenn man deskriptive Erweiterungen wie den Open Inventor oder SGI's Performer nutzen kann. Der Nachteil dabei ist aber, dass sich deren Methoden nicht einfach in eigene Programme einbinden lassen (falls man überhaupt an diese Bibliotheken/Programme rankommt).

Hier findet ihr daher ein etwas komplexeres Beispiel, wie man VRML-Dateien in eigenen Programmen zur Beschreibung und Darstellung von Objekten verwenden kann. Der Quelltext steht unter der GPL zur Verfügung und kann daher auch von euch genutzt und geändert werden, solange eure Programme und Quelltexte wiederum der GPL unterliegen. Da ich weiss, dass das Beispiel noch lange nicht ausgereift ist, bin ich für (umgesetzte) Erweiterungsvorschläge jederzeit zu haben!

P.S.: Auf eine Beschreibung des VRML-Standards verzichte ich mal...

[zum Seitenanfang]


Dateien des Beispielprogramms:

Quelltext (Verzeichnis "GLviews")
VRMLControl.H/.cxx stellt die Basisklasse zur Auswertung von VRML-Dateien zur Verfügung
Objects.H/.cxx setzt die VRML-Aufrufe in OpenGL-Befehle um
Tools.H/.cxx stellt Hilfsfunktionen zum Laden von Bilddateien, für Vektorrechung und Tesselation sowie Ausgabefunktionen zur Verfügung
glutShell.cxx main() Funktion, die beispielhaft die Klasse VRMLConrol nutzt
GLSettings.H/.cxx ein paar einfache Darstellungs- und Berechnungsfunktionen
Unter MS Windows benötigte Bibliotheken (Verzeichnis "other")
libjpeg.lib,
jpeglib.h, jmorecfg.h, jerror.h, jconfig.h
Die JPEG-Bibliothek (*.h und *.lib kann man auch ins Compiler-Verzeichnis kopieren).
Linux bringt die Dateien normalerweise schon mit.
glut32.lib,
GLUT32.dll, GLUT.H
Die GLUT-Bibliothek (*.h und *.lib kann man auch ins Compiler-Verzeichnis, *.dll ins Windows-Verzeichnis kopieren).
Linux bringt die Dateien normalerweise schon mit.
General Public License und Compiler-Steuerungsdateien
License.de, License.en Die GPL in deutsch und englisch. Gilt für alle Quelltexte und damit auch für das endgültige Programm.
glut_vrml.dsw, glut_vrml.dsp Die Projektdatei für MS Visual C++ 6.0

[zum Seitenanfang]


Programmablauf (grob skizziert):

  1. die main()-Funktion in glutShell.cxx erzeugt die grafische Oberfläche mit Hilfe von GLUT
  2. scannt danach das Verzeichnis "Modelle/" nach VRML-Dateien ab (*.wrl)
  3. erzeugt ein einfaches Koordinatensystem zur Orientierung
  4. nach Aufruf des Menüs (mittels rechter Maustaste) wird die entsprechende Beispieldatei geladen:
  5. die Funktion ReloadFromFile(int whichFile) erzeugt ein VRML-Objekt durch Aufruf von MyObjectControl = new VRMLControl( DateiListe[whichFile] );
  6. der Konstruktor von VRMLControl ruft die Funktion ScanFile(); auf, die mittels CheckFile(DateiName, "r") und extractDir(char *complete, char *directory, char *file) den Dateinamen vom Speicherort (Verzeichnis) trennt und das Verzeichnis für spätere Suchfunktionen speichert
  7. danach wird der Dateityp mittels CheckForType() überprüft (derzeit werden z.B. nur ungepackte VRML 2.0 Dateien unterstützt)
  8. ScanForRootNodes() durchsucht die Datei rekursiv nach Schlüsselwörtern:
    • zuerst nach Wurzelknoten (root nodes), wobei jeder Knoten einen eigenen Bezeichner mittels GenNodeName(NextNodeName) erhält
    • dann nach Schlüsselwörtern wie Group oder Transformation und ruft entsprechende Methoden auf:
      AddGroup(Ebene, Parent, NextNodeName) und AddTransform(Ebene, Parent, NextNodeName)
  9. AddGroup(Ebene, Parent, NextNodeName) aus Objects.H/.cxx erzeugt ein neues Objekt und speichert es in einer Objektliste:
    ThisNode = new GroupNode();            // Objekt "Group" anlegen
    ThisNode->SetName(ThisNodeName);  // Namen festlegen
    ObjectPtr[ObjectCount] = ThisNode;   // Objekt in die Objektliste aufnehmen
    
    // [snip]
    
    RootNode[RootNodeCount] = ThisNode;  // als Wurzeleintrag oder Kindobjekt festlegen
    Parent->AddChildren( (VRMLNode*)ThisNode );
    
    // [snip]
    
    ScanForBraces(Klammer2);                // Anzahl der öffnenden und schliessenden Klammern festhalten
    AddChildren( Ebene, (GroupingNode*)ThisNode ); // Kindobjekte "children" erfassen
  10. AddTransform(Ebene, Parent, NextNodeName); aus Objects.H/.cxx erzeugt ein neues Objekt und speichert es in einer Objektliste (wie AddGroup), unterscheidet aber andere Schlüsselworte ("center", "rotation", "translation", "scale" etc.) und ruft die entsprechenden Methoden auf:
    ThisNode->Rotation(Angle, Axle);
  11. AddChildren(int Ebene, GroupingNode *Parent) scannt nach weiteren Schlüsselworten ("USE", "DEF", "Shape", "Group", Transform") und legt entsprechende Objekte mittels AddShape, AddGroup und AddTransform an
  12. AddShape(GroupingNode *Parent, char ThisNodeName[]) erzeugt einen Körper (ShapeNode), und sucht nach den beschreibenden Angaben (KeyAppearance(ThisNode, NextNodeName);, KeyGeometry(ThisNode, NextNodeName); und AskForAppearance();)
  13. KeyAppearance(ShapeNode *MyShape, char ThisNodeName[]) nutzt die Merkmale anderer Objekte (USE) oder sucht nach neuen Objektmerkmalen (AddAppearance(MyShape, ThisNodeName);)
  14. AddAppearance(MyShape, ThisNodeName); erzeugt ein AppearanceNode() Objekt und registriert die Merkmale in der aufrufenden ShapeNode
    MyShape->AddAppearance(ThisNode);
    ThisNode->AddMaterial, AddTexture, AddTextureTransform // "erben" vom Elternteil
    KeyMaterial, KeyTexture, KeyTextureTransform // Merkmale ermitteln
  15. AddMaterial(AppearanceNode *MyAppearance, char ThisNodeName[]) erzeugt ein Materialobjekt, registriert es als Objekteigenschaft und speichert die Farb- und Transparenzwerte
  16. AddImageTexture(AppearanceNode *MyAppearance, char ThisNodeName[]) erzeugt ein Texturobjekt
    TextureNr = texture ID
    AddTextureURL(url)            // (url = Dateiname)
    ScanTextureImage()            // aus Objects.H/.cxx
    loadPPMfile und loadJPEGfile  // Ladefunktionen für PPM und JPEG Bilddateien aus Tools.H/.cxx
    PrepareTexture()              // OpenGL setup für diese texture ID
  17. AddTextureTransform( AppearanceNode *MyAppearance, char ThisNodeName[]) legt Transformationen für die Textur fest (Rotation, Translation, Verzerren)
  18. KeyGeometry( ShapeNode *MyShape, char ThisNodeName[]) scannt jetzt nach erkennbaren Geometrien wie Cone, Cylinder, Sphere, Box (für) einfache Objekte) und IndexedFaceSet und IndexedLineSet (für komplexe Objekte)
  19. die Add* Methoden für Cone, Cylinder, Sphere, Box erzeugen ein entsprechendes Objekt und registriert die Merkmale in der aufrufenden ShapeNode
  20. AddLineSet erzeugt eine Verbindungslinie zwischen vielen Eckpunkten und wertet dazu Koordinaten-, Farb- und Indexfelder aus
    KeyField(ThisNode, Color, NextNodeName);
    KeyField(ThisNode, Coordinate, NextNodeName);
    AddIndex(ThisNode, Color);
    AddIndex(ThisNode, Coordinate);
    PrepareForDraw()                    // Setup

  21. AddFaceSet arbeitet ähnlich LineSet, nur erzeugt es zwischen den Verbindungslinien farbige und schattierte Flächen

[zum Seitenanfang]


Hier sind die Dateien...:

Seite durchsuchen nach:

Fragen oder Ideen an:
Thomas.Kern@3Dsource.de
Linux-Counter
(C) Thomas Kern