Stefan Omert Java Bindings for OpenGL Java Bindings for OpenGL (JOGL) Eine Ausarbeitung von Stefan Omert im Rahmen der Lehrveranstaltung Graphisch Interaktive Systeme 1 Stefan Omert Java Bindings for OpenGL Inhaltsverzeichnis 1. Einleitung.........................................................................................................................3 2. Was ist JOGL?.................................................................................................................3 3. Abgrenzung von JOGL zu anderen Bindings...............................................................4 4. Installation.......................................................................................................................5 4.1 Voraussetzungen...................................................................................................5 4.2 Windows XP............................................................................................................5 4.3 Einrichten der Entwicklungsumgebung Eclipse......................................................7 5. Aufbau von JOGL............................................................................................................8 5.1 Klassenhierarchie...................................................................................................8 5.2 Interfacehierarchie................................................................................................10 5.3 Wichtige Klassen und Interfaces...........................................................................10 6. Grundgerüst eines JOGL-Programm..........................................................................12 6.1 Verwendung von GLCanvas.................................................................................12 6.2 Verwendung von GLJPanel..................................................................................13 7. Tutorial............................................................................................................................14 7.1 Einfaches Fenster.................................................................................................14 7.2 Fenster mit RGB-Würfel........................................................................................17 7.3 Maussteuerung.....................................................................................................20 7.4 Tastatursteuerung.................................................................................................22 7.5 Animation (kreisende Kugel).................................................................................23 8. Schlusswort...................................................................................................................26 9. Anhang...........................................................................................................................27 9.1 Quellen..................................................................................................................27 2 Stefan Omert Java Bindings for OpenGL 1. Einleitung Im Mai 1995 wurde Java offiziell als Programmiersprache vorgestellt. Java ist eine objektorientierte und plattformunabhängige Hochsprache mit umfangreichen Bibliotheken und einer guten, übersichtlichen Dokumentation. Java kann für unterschiedlichste Aufgaben, wie z.B. zur Anwendungsentwicklung oder zur Netzwerkprogrammierung, eingesetzt werden. In der Entwicklung für Computerspiele konnte sich Java aber nicht durchsetzen, da es keine Unterstützung für OpenGL gab, und OpenGL als Standard für die Entwicklung von 2D- und 3D-Applikationen gilt. Deshalb versuchte man dies mit der Eigenentwicklung Java3D zu kompensieren. Diese konnte sich aber wegen der geringeren Performance bei der Umsetzung von 3D-Objekten nicht in der Spielentwicklung durchsetzen. Deshalb wurden verschiedene Bindings entwickelt, darunter auch das Java Binding for OpenGL (JSR 231, JOGL). 2. Was ist JOGL? JOGL ist ein Open-Source Projekt, welches 2003 von der Game Technology Group von Sun Microsystems ins Leben gerufen wurde. JOGL wurde mit dem Ziel entwickelt hardwarebeschleunigte 3D-Grafiken mit Hilfe einer low-level Grafikbibliothek in Java verwirklichen zu können. Da heutzutage OpenGL das Standard low-level 3D Application Programming Interface (API) auf dem Markt ist, hat man sich für ein Binding mit dieser Grafikbibliothek entschieden. Die Entwicklung wird von Sun Microsystems (Java) und Silicon Graphics Incorporated (OpenGL) unterstützt, wodurch die ständige Weiterentwicklung und Pflege des Projektes gesichert ist. Mithilfe von JOGL kann ein Programmierer in Java auf die Funktionen von OpenGL zugreifen. Zu diesem Zweck besitzt JOGL spezielle Java- Wrapperklassen, welche als Schnittstellen zu den nativen Funktionen von OpenGL dienen. Die Methoden dieser Schnittstellen führen dabei einfach den C-Code der entsprechenden Funktionen aus. Dies wird mit Hilfe des Java Native Interface (JNI) erreicht. Das JNI ermöglicht es betriebssystemspezifische Funktion und Methoden aus dem bertriebssystemunabhängigen Java heraus aufzurufen. So besteht die Möglichkeit auf Bibliotheken des Betriebssystems zuzugreifen die auch in einer anderen Sprache, wie z.B. C oder C++, verfasst sein können. Durch den direkten Zugriff auf den nativen 3 C-Code entstehen auch kaum Stefan Omert Java Bindings for OpenGL Geschwindigkeitseinbußen. JOGL stellt die meisten Features von OpenGL, der GLU und der GLUT Bibliotheken zur Verfügung. Funktionen der OpenGL Utility Library (GLU) sind z.B. die Unterstützung beim Rendern von Kugeln, Zylindern und anderen grafischen 3D-Objekten aber auch die Kamerapositionierung usw. JOGL implementiert aber nur einen Teil der Funktionen des OpenGL Utility Toolkit (GLUT) wie beispielsweise die Realisierung von grafischen Grundprimitiven. Die Fenstersystemfunktionen der GLUT wurden nicht mit übernommen, da Java sein eigenes high-level Fenstersystem mitbringt. Das heißt Java-Programmierer müssen sich nicht mit neuen Funktionen aus der GLUT befassen sondern können Fenster mit den AWT- und Swing-Komponenten realisieren, was den Einstieg in JOGL wesentlich erleichtert. 3. Abgrenzung von JOGL zu anderen Bindings Um 2D- und 3D-Grafiken mit Java realisieren zu können, wurden von den Entwicklern einige OpenGL-Bindings auf den Markt gebracht. Die drei bekanntesten sind gl4java (OpenGL for Java), Magician und LWJGL (Lightweight Java Game Library). Doch alle diese Bindings haben ihre Probleme oder verfolgen andere Ziele als JOGL. Gl4Java unterstützt OpenGL nur bis zur Version 1.3, neuere I/O-Geräte werden nur teilweise unterstützt, außerdem macht es die sehr umfangreiche API Entwicklern schwer den Einstieg zu finden. Das Problem von Magician liegt darin das es weder neue I/O-Geräte unterstützt noch wird es nicht weiterentwickelt. Zudem ist es kein Open-Source-Projekt, was einen weiteren Nachteil darstellt. Die LWJGL unterstützt zwar neuste I/O-Geräte und auch die aktuelle Version von OpenGL, jedoch liegt ihr Nachteil in der unzulässigen Einbindung von AWT- und Swing-Komponenten. Mit diesen Bindings war der Anfang gemacht. Nun versuchte man 2003 mit der Entwicklung von JOGL die Vorteile dieser Technologien zu vereinen und die Probleme zu beheben. Ken Russell und Kris Kline legten den Grundstein für JOGL. Die weitere Entwicklung wurde dann von der Game Technology Group, mit Unterstützung von Sun und SGI, übernommen. 4 Stefan Omert Java Bindings for OpenGL 4. Installation 4.1 Voraussetzungen JOGL setzt eine vorhandene Java Installation voraus. Falls diese nicht vorhanden ist muss im Vorfeld die J2SDK in der aktuellen Version von Sun (www.java.sun.com) heruntergeladen und installiert werden. 4.2 Windows XP a) Um JOGL verwenden zu können muss man sich das aktuelle JOGL- Paket von der Jogl-Seite (https://jogl.dev.java.net/) herunterladen. Hier findet man das Paket unter „Current nightly build“. Für Windows ist es zurzeit z.B. das Zip-Archiv „jogl-1.1.1-rc6-windows-i586.zip“. b) Im zweiten Schritt entpackt man das Archiv in einen beliebigen Ordner. Dieser sollte nun mindestens die folgende Dateien enthalten: Userguide.html (Kleines Handbuch mit Installationsanleitung) Im Unterordner lib: jogl.jar gluegen-rt.jar jogl.dll gluegen-rt.dll jogl_awt.dll jogl_cg.dll c) Nun müssen die kompletten Pfade zu den Dateien jogl.jar und gluegenrt.jar in die Umgebungsvariable CLASSPATH eingetragen werden. Die Umgebungsvariablen sind zu finden unter: Systemsteuerung à System à Erweitert à Umgebungsvariablen 5 Stefan Omert Java Bindings for OpenGL Bild1: Screenshots zum Einrichten der Umgebungsvariablen d) Im letzten Schritt muss nun noch der Pfad zum Unterordner lib in die Umgebungsvariable PATH eingetragen werden. Vorgehensweise siehe Punkt c. e) Nachdem man sein System neu gebootet hat kann man seine JOGL-Installation testen. Hierzu nimmt man sich eine JOGL-Datei, beispielsweise ein einfaches Beispiel aus dem Internet, hier Jogl_test.java, und führt diese aus. Dazu öffnet man sich ein Konsolenfenster, kompiliert die entsprechende Datei mit dem Befehl javac Jogl_test.java und führt diese mit dem Befehl java Jogl_test aus. Nun müsste sich ein Fenster mit dem, dem Programm entsprechenden Inhalt öffnen, hier ein leeres Fenster. 6 Stefan Omert Java Bindings for OpenGL Bild2: Screenshot des Installationstests 4.3 Einrichten der Entwicklungsumgebung Eclipse a) Zuerst muss man sich in Eclipse ein neues Javaprojekt für sein JOGLProgramm erstellen. b) Im zweiten Schritt muss man in seinem Projekt die Dateien jogl.jar und gluegen-rt.jar zum Java-Erstellungspfad hinzufügen. Dazu öffnet man die Eigenschaften seines Projekts, wählt hier Java-Erstellungspfad und klickt im Reiter Bibliotheken auf den Button „Externe JARs hinzufügen...“. 7 Stefan Omert Java Bindings for OpenGL Bild3: Screenshots zum Hinzufügen externer JARs 5. Aufbau von JOGL 5.1 Klassenhierarchie • class java.lang.Object • class com.sun.opengl.util.Animator • class com.sun.opengl.util.FPSAnimator • class javax.media.opengl.AWTGraphicsConfiguration (implements javax.media.opengl.AbstractGraphicsConfiguration) • class javax.media.opengl.AWTGraphicsDevice (implements javax.media.opengl.AbstractGraphicsDevice) • class com.sun.opengl.util.BufferUtil • class com.sun.opengl.cg.CGannotation • class com.sun.opengl.cg.CGcontext • class com.sun.opengl.cg.CGeffect • class com.sun.opengl.cg.CgGL • class com.sun.opengl.cg.CGparameter • class com.sun.opengl.cg.CGpass • class com.sun.opengl.cg.CGprogram • class com.sun.opengl.cg.CGstate • class com.sun.opengl.cg.CGstateassignment • class com.sun.opengl.cg.CGtechnique • class java.awt.Component (implements java.awt.image.ImageObserver, java.awt.MenuContainer, java.io.Serializable) • class java.awt.Canvas (implements javax.accessibility.Accessible) • class javax.media.opengl.GLCanvas (implements 8 Stefan Omert • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • Java Bindings for OpenGL javax.media.opengl.GLAutoDrawable) • class java.awt.Container • class javax.swing.JComponent (implements java.io.Serializable) • class javax.swing.JPanel (implements javax.accessibility.Accessible) • class javax.media.opengl.GLJPanel (implements javax.media.opengl.GLAutoDrawable) • class java.awt.Panel (implements javax.accessibility.Accessible) • class java.applet.Applet • class com.sun.opengl.util.JOGLAppletLauncher class com.sun.opengl.util.texture.spi.DDSImage class com.sun.opengl.util.texture.spi.DDSImage.ImageInfo class javax.media.opengl.DebugGL (implements javax.media.opengl.GL) class javax.media.opengl.DefaultGLCapabilitiesChooser (implements javax.media.opengl.GLCapabilitiesChooser) class com.sun.opengl.util.FileUtil class com.sun.opengl.util.Gamma class javax.media.opengl.GLCapabilities (implements java.lang.Cloneable) class javax.media.opengl.GLContext class javax.media.opengl.GLDrawableFactory class javax.media.opengl.glu.GLU class com.sun.opengl.util.GLUT class javax.media.opengl.glu.GLUtessellatorCallbackAdapter (implements javax.media.opengl.glu.GLUtessellatorCallback) class com.sun.opengl.util.ImageUtil class com.sun.opengl.util.j2d.Overlay class com.sun.opengl.util.Screenshot class com.sun.opengl.util.texture.spi.SGIImage class com.sun.opengl.util.StreamUtil class com.sun.opengl.util.j2d.TextRenderer class com.sun.opengl.util.j2d.TextRenderer.DefaultRenderDelegate (implements com.sun.opengl.util.j2d.TextRenderer.RenderDelegate) class com.sun.opengl.util.texture.Texture class com.sun.opengl.util.texture.TextureCoords class com.sun.opengl.util.texture.TextureData class com.sun.opengl.util.texture.TextureIO class com.sun.opengl.util.j2d.TextureRenderer class com.sun.opengl.util.texture.spi.TGAImage class com.sun.opengl.util.texture.spi.TGAImage.Header class com.sun.opengl.util.TGAWriter class javax.media.opengl.Threading class java.lang.Throwable (implements java.io.Serializable) • class java.lang.Exception • class java.lang.RuntimeException • class com.sun.opengl.cg.CgException • class javax.media.opengl.GLException class com.sun.opengl.util.TileRenderer class javax.media.opengl.TraceGL (implements javax.media.opengl.GL) Quelle: /JOAP/ 9 Stefan Omert Java Bindings for OpenGL 5.2 Interfacehierarchie • • • • • • • • • • • • • • • interface javax.media.opengl.AbstractGraphicsConfiguration interface javax.media.opengl.AbstractGraphicsDevice interface javax.media.opengl.ComponentEvents • interface javax.media.opengl.GLAutoDrawable (also extends javax.media.opengl.GLDrawable) • interface javax.media.opengl.GLPbuffer interface java.util.EventListener • interface javax.media.opengl.GLEventListener interface javax.media.opengl.GL interface javax.media.opengl.GLCapabilitiesChooser interface javax.media.opengl.GLDrawable • interface javax.media.opengl.GLAutoDrawable (also extends javax.media.opengl.ComponentEvents) • interface javax.media.opengl.GLPbuffer interface javax.media.opengl.glu.GLUnurbs interface javax.media.opengl.glu.GLUquadric interface javax.media.opengl.glu.GLUtessellator interface javax.media.opengl.glu.GLUtessellatorCallback interface com.sun.opengl.util.j2d.TextRenderer.RenderDelegate interface com.sun.opengl.util.texture.TextureData.Flusher interface com.sun.opengl.util.texture.spi.TextureProvider interface com.sun.opengl.util.texture.spi.TextureWriter Quelle: /JOAP/ 5.3 Wichtige Interfaces und Klassen Interface Beschreibung GLAutoDrawable Eine high-level Abstraktion, die einen eventbasierenden Mechanismus für OpenGL Rendering anbietet. GLEventListener Bietet Events an, welche im Code benutzt werden können um das OpenGL Rendering in GLAutoDrawable zu managen. OpenGLCallbackmethoden wie init(), display(), reshape() und displayChanged() sind im Interface zu implementieren. GL GL ist das Hauptinterface für OpenGL. Es bietet Zugang zur gesamten OpenGL-Funktionalität an. GLDrawable Eine Abstraktion für ein OpenGL Rendering Target. Kann einen OpenGL-Kontext erstellen, welcher benutzt werden kann um das Rendering auszuführen. 10 Stefan Omert Java Bindings for OpenGL Klasse Animator Beschreibung Ruft die display()-Methode einer oder mehrer GLAutoDrawable Insatzen in einer Schleife auf. Kreiert einen Hintergrund-Thread um diese Aufgabe zu erfüllen. FPSAnimator Direkte Unterklasse des Animator. Hier kann man eine Frames-PerSecond-Rate angeben und dadurch bestimmen wie oft die display()Methode aufgerufen wird. Dabei wird das Erfüllen der Rate nicht garantiert aber angestrebt. Component Component ist eine abstrakte Klasse. Ein Component repräsentiert ein Objekt, welches auf dem Ausgabefeld angezeigt werden kann und mit dem Benutzer interagieren kann. Beispiele für Components sind Buttons, Checkboxes oder Scrollbars. Canvas Canvas repräsentiert einen leeren rechteckigen Bereich auf dem Display. In diesen Bereich kann eine Applikation zeichnen oder von dort Benutzereingaben entgegen nehmen. Für eine sinnvolle Verwendung von Canvas muss eine Unterklasse erstellt werden, in der die paint()-Methode überschrieben wird, um entsprechende Grafiken auf der Canvas auszugeben. GLCanvas GLCanvas ist eine AWT-Komponente, welche OpenGL Renderingunterstützung anbietet. GLCanvas ist die Hauptimplementation des GLDrawable-Interfaces. Container Ein Container ist eine AWT-Komponente die andere AWTKomponenten enthalten kann. JPanel GLJPanel JPanel ist ein generischer leichtgewichtiger Container. Eine leichtgewichtige Swing Komponente, welche OpenGL Renderingunterstützung anbietet. Kompatibel mit Swing UserInterfaces. Panel Panel stellt einen einfachen Container dar. In diesen kann eine Applikation alle anderen möglichen Komponenten einfügen. GLU Über GLU hat man Zugriff auf die OpenGL Utility Library (GLU). Die Methoden entsprechen den Methoden der orginal C-Implementation. GLUT GLUT stellt eine Teilmenge des OpenGL Utility Toolkit dar. Nicht alle Methoden des GLUT wurden implementiert. Die Methoden weichen ein wenig von der orginal C-Implementation ab. 11 Stefan Omert Java Bindings for OpenGL 6. Grundgerüst eines JOGL-Programm JOGL besitzt die zwei Haupt-GUI-Klassen GLCanvas und GLJPanel. Diese implementieren das Interface GLAutoDrawable. Die beiden Klassen werden als „Zeichenfläche“ für die OpenGL Kommandos benutzt. GLCanvas ist der Canvas von AWT sehr ähnlich. Es ist eine heavyweigth Komponente, deswegen muss man aufpassen wenn man diese mit Swing Komponenten kombiniert. OpenGL Operationen werden durch die Hardwarebeschleunigung sehr schnell ausgeführt. GLJPanel ist eine lightweight Komponente, welche ohne Probleme mit Swing Komponenten klar kommt. Im Gegensatz zu GLCanvas ist GLJPanel etwas langsamer in der Ausführung der OpenGL Operationen. 6.1 Verwendung von GLCanvas Bild4: Grundaufbau eins JOGL-Fensters mit GLCanvas. Quelle: /PJ3D/ Die GLCanvas wird meist direkt ein JFrame eingefügt. Es besteht aber auch die Möglichkeit die GLCanvas in ein JPanel zu verpacken, dadurch ist es möglich mehrere lightweight GUI Komponenten in ein JFrame einzufügen. Die GLCanvas wird immer in Verbindung mit einem GLEventListener verwendet, welcher die Änderungen in der Canvas bearbeitet. Bei einem OpenGL-Programm übernimmt normalerweise OpenGL zur Laufzeit die Kontrolle über das Programm und ruft die entsprechenden Callback-Methoden auf. Diese Funktion wird bei JOGL durch den GLEventListener übernommen. Wenn die Canvas nun das erste Mal erstellt wird, wird die init()-Methode des GLEventListeners aufgerufen. Die init()-Methode wird 12 Stefan Omert Java Bindings for OpenGL deshalb im eigenen Programm überschrieben um den OpenGL Status zu initialisieren. Jedes Mal wenn die die Größe der Canvas oder deren Position verändert wird, wird die reshape()-Methode des Eventlisteners ausgeführt. Hier kann man den entsprechenden Code platzieren, um z.B. den Viewport zu initialisieren. Immer wenn die display()-Methode der Canvas aufgerufen wird, wird auch die Methode display() des Eventlisteners ausgeführt. In dieser Methode kann der Code für das Rendern der 3D Szene, die in der Canvas dargestellt werden soll platziert werden. displayChanged(). Der Diese Eventlistener wird enthält ausgeführt auch wenn noch sich die Methode beispielsweise die Einstellungen des Monitors ändern oder die Canvas auf einen anderen Monitor verschoben wird. Für einige grafische Anwendungen wie z.B. Animationen oder Spiele ist es nötig die Canvas regelmäßig zu aktualisieren. Mit einem FPSAnimator kann der Benutzer eine feste Frequenz einstellen mit der die display()-Methode der Canvas, und somit auch die des Eventlisteners, aufgerufen werden soll. Nach diesem Grundgerüst sind die meisten einfachen JOGL-Programme aufgebaut. 6.2 Verwendung von GLJPanel Bild5: Grundaufbau eins JOGL-Fensters mit GLJPanel. Quelle: /PJ3D/ Da das GLJPanel eine lightweight Swing Komponente ist kann sie direkt in das JFrame eingebettet werden, und es können auch noch weitere lightweight Komponenten hinzu gefügt werden. Der Rest dieses Aufbaus verhält sich ebenso wie der Aufbau mit einer GLCanvas. Das heißt man kombiniert das GLJPanel ebenfalls mit einem GLEventListener, welcher die Änderungen auf der Zeichenfläche bearbeitet. Mit einem FPSAnimator kann man wieder eine feste Rate einstellen mit der das GLJPanel aktualisiert werden soll. 13 Stefan Omert Java Bindings for OpenGL 7. Tutorial In diesem Abschnitt möchte ich die Programmierung mit JOGL etwas näher erläutern. Ich werde dazu ein einfaches Programm erstellen und Schritt für Schritt den Quellcode erklären. Für die Entwicklung dieses Programms benutze ich die Entwicklungsumgebung Eclipse in der Version 3.2 und das aktuelle JOGL-Paket in der Version 1.1.1-rc6. 7.1 Einfaches Fenster Ich möchte mit dem öffnen eines einfachen Fensters beginnen. Wie im Punkt 4.3 Einrichten der Entwicklungsumgebung Eclipse beschrieben erstellt man sich zunächst ein neues Projekt und fügt die beiden Dateien jogl.jar und gluegen-rt.jar zum Projekt hinzu. Nun erstellt man sich in seinem Projekt eine neue Klasse. Als Superklasse sollte die Klasse JFrame eingetragen werden und als Schnittstelle der GLEventListener. Die main-Methode sollte erstellt werden und die abstrakten Methoden der Schnittstelle sollten auch übernommen werden. Bild6: Screenshot zum Erstellen einer JOGL-Klasse 14 Stefan Omert Java Bindings for OpenGL Es müsste folgender Code entstanden sein. Um nun ein einfaches leeres Fenster zu erzeugen müssen wir in den Code einen Konstruktor einfügen. 15 Stefan Omert Java Bindings for OpenGL Zunächst werden zwei Datenfelder festgelegt, welche immer die aktuelle Größe des Fensters enthalten. Dem Konstruktor kann man zum erzeugen des Fensters die gewünschte Größe übergeben. Der Konstruktor erzeugt uns ein neues Objekt welches eine Unterklasse von JFrame ist. Dadurch haben wir uns eigentlich schon ein Fenster erzeugt. Mit der Methode setSize() der Klasse JFrame wird nun die Größe des Fensters gesetzt. Die Methode setTitle() legt einen Titel des Fensters fest, welcher in der obersten Leiste des Fensters erscheint. Im nächsten Schritt erzeugt man sich eine GLCanvas als Zeichenfläche für OpenGL-Befehle. Dieser fügt man den GLEventListener hinzu, der die Callbackfunktionen von OpenGL realisiert. Die Zeichenfläche muss natürlich in das Fenster eingefügt werden, dies geschieht mit der Methode add() von JFrame. Nun fügen wir noch einen WindowListener ein, der beim Schließen des Fensters das Programm beendet. Im letzten Schritt müssen wir das Fenster mit der Methode setVisible() noch sichtbar machen. Die Callbackfunktionen init(), displayChanged(), display() und reshape() bleiben zunächst leer, da wir ja ein leeres Fenster ohne Objekte wollen. Die mainMethode hat nur die Aufgabe ein Objekt der eigenen Klasse zu erzeugen. Nun kann man das Programm in Eclipse einfach als Java-Anwendung ausführen. Bild7: Screenshot zum Ausführen eines JOGL-Programms 16 Stefan Omert Java Bindings for OpenGL Anschließend öffnet sich ein einfaches leeres Fenster mit der Überschrift Mein_Tutorial. Bild8: Einfaches leeres Fenster mit JOGL erstellt 7.2 Fenster mit RGB-Würfel In diesem Abschnitt wollen wir unser erstes Objekt auf der Zeichenfläche im Fenster realisieren. Der Grundaufbau dieses Programms sieht genauso aus wie im Abschnitt zuvor. Wir müssen uns natürlich wieder ein Fenster mit einer Zeichenfläche schaffen, wie das funktioniert sollte nun jeder wissen. Der Konstruktor und die main-Methode können aus dem ersten Beispiel übernommen werden. Die init() Methode des GLEventListener wird zuerst und nur einmal beim erzeugen des Fensters aufgerufen. Der erste Schritt in jeder Callbackfunktion ist es sich ein GL-Objekt zu holen. Das Interface GL bietet nämlich alle Methoden von OpenGL an. Dann wird in der init()Methode zunächst die Hintergrundfarbe, wie aus OpenGL bekannt, gesetzt. Da es sich bei unserem RGB-Würfel um ein 3D-Objekt handelt, müssen wir natürlich den 17 Stefan Omert Java Bindings for OpenGL Tiefenbuffer aktivieren und eine Tiefenfunktion festlegen. Der Löschwert für den Tiefenbuffer wird stets auf die größte Tiefe gesetzt. Die reshape()-Methode wird aufgerufen wenn das Fenster verschoben wird oder die Größe des Fensters geändert wird, also auch beim Erzeugen des Fensters. Zunächst werden die Variablen für die Höhe und die Breite des Fensters aktualisiert. Mit glViewport() wird der Viewport an die Fenstergröße angepasst. Die Funktion glOrtho() legt das Viewingvolumen fest. Um den Betrachtungspunkt einstellen zu können, muss man sich erst ein GLU-Objekt erstellen, welches die OpenGL Utility Bibliothek darstellt. Mit der Methode gluLookAt() dieser Klasse kann man dann den Betrachtungspunkt einstellen. Um den Würfel als 3D-Objekt zu erkennen wird der Augpunkt nach links-vorne-oben gelegt. In der display()Methode wird die Hauptarbeit erledigt, nämlich das eigentliche zeichnen des Objektes. Der erste Schritt ist es den Colorbuffer und den Depthbuffer mit den in der init()Methode eingestellten Werten vorzuinitialisieren. Danach wird eine Hilfsfunktion aufgerufen die das Objekt zeichnet. Natürlich könnte man auch den ganzen Code zum Zeichnen des RGB-Würfels direkt in der display()-Methode unterbringen. Aber der besseren Übersichtlichkeit wegen habe ich diesen Code ausgelagert. In der 18 Stefan Omert Java Bindings for OpenGL Methode objektZeichnen() wird der RGB-Würfel aus sechs Rechtecken aufgebaut. Aus dieser Methode möchte ich nur einen Codeausschnitt für eines der Rechtecke zeigen. Die anderen Rechtecke werden genauso erzeugt nur mit entsprechend anderen Koordinaten und Farben. Mit den aus OpenGL bekannten Funktionen gl.Begin() und gl.End() kann man grafische Primitiven erstellen. Der Übergabe Wert GL_POLYGON erlaubt es Polygone über die Angabe von Vertexen (Koordinaten) zu realisieren. Über glColor3f() kann man die Farbe der Vertexe einstellen. Mit glVertex3f wird eine Koordinate festgelegt. Die Farben zwischen den Vertexen werden beim Shmoothshading, welches als Standard eingestellt ist, interpoliert. Über jeweils vier Koordinaten kann man dann die sechs Rechtecke erstellen aus denen sich der RGB-Würfel zusammensetzt. Beim Ausführen dieses Programms müsste sich dann folgendes Bild ergeben. Bild9: Fenster mit RGB-Würfel mit JOGL erstellt 19 Stefan Omert Java Bindings for OpenGL Es fällt auf das es kein richtiger Würfel ist sondern mehr ein Quader. Dies liegt daran, dass das Viewingvolumen nicht an die Seitenverhältnisse des Fensters angepasst ist. Dies baut man am besten in die reshape() Methode ein. Über eine if-Abfrage findet man zunächst heraus ob das Fenster höher als breit oder breiter als hoch ist. Im entsprechenden Fall passt man entweder die Höhe oder die Breite des Viewingvolumen an das Seitenverhältnis des Fensters an. 7.3 Maussteuerung In diesem Abschnitt möchte ich euch zeigen wie man mit JOGL Mauseingaben im Fenster verarbeiten kann. Dazu möchte ich den im vorherigen Abschnitt erstellten RGB-Würfel bei entsprechender Mausbewegung um die X- bzw. Y-Achse rotieren lassen. Mauseingaben werden wie von Java her bekannt bearbeitet. Dazu werden zunächst die beiden Interfaces MouseListener und MouseMotionListener zusätzlich implementiert. Natürlich muss man durch diesen Schritt alle abstrakten Methoden der Interfaces implementieren. Die meisten Methoden werden in unserem kleinen Beispiel allerdings leer bleiben. Die beiden Methoden mousePressed() und mouseDragged() werden unsere gewünschte Funktionalität erfüllen, da wir den Würfel nur mit gedrückter Maustaste bewegen wollen. Die beiden Listener müssen natürlich wissen wo sie ihre Eingaben her bekommen, deshalb müssen sie sich beim GLAutoDrawable-Interface anmelden. Diesen Code bringt man am besten in der init()-Methode unter. 20 Stefan Omert Java Bindings for OpenGL In der mousePressed-Methode werden nur die Koordinaten des Mauszeigers gespeichert sobald eine Taste der Maus betätigt wird. Die Methode mouseDragged() wird angesprochen wenn die Maus mir gedrückter Taste bewegt wird. In dieser Methode werden dann ständig die Koordinaten der Maus eingelesen. Aus der Startposition der Maus und der aktuellen Position werden dann die entsprechenden Rotationswinkel für den Würfel errechnet. Um die Rotation anzuzeigen muss am Ende noch die display()-Methode der Zeichenfläche angesprochen werden. In dieser Methode wird der Würfel dann entsprechend gedreht und neu in das Fenster gezeichnet. Wenn man das Programm nun ausführt kann man den Würfel ganz einfach mit der Maus um seine X- bzw. Y-Achse drehen. 21 Stefan Omert Java Bindings for OpenGL Bild10: Fenster mit verdrehtem RGB-Würfel mit JOGL erstellt 7.4 Tastatursteuerung Dieser Abschnitt befasst sich mit Tastatureingaben und wie man diese unter JOGL auswerten kann. In diesem Beispiel wollen wir die Tastatureingaben nutzen um den Shadingmode um zu schalten. Das Drücken der Taste 'f' soll Flatshading einstellen und die Taste 's' soll Smoothshading einstellen. Die Vorgehensweise ist ähnlich der im vorherigen Abschnitt besprochenen Maussteuerung. Zunächst wird noch das Interface KeyListener implementiert. In der init()-Methode meldet man den KeyListener genauso wie die MouseListener an. Die Methode des KeyListeners die wir mit Code versehen müssen ist keyTyped(). 22 Stefan Omert Java Bindings for OpenGL Diese Methode wird aufgerufen wenn eine Taste gedrückt wird. Durch die switchcase-Anweisung wird bestimmt welche Taste gedrückt wurde, und die Variable shadeMode wird entsprechend gesetzt. Natürlich muss bei jedem Tastendruck das Fenster aktualisiert werden, damit das Ergebnis auch am Bildschirm erscheint. Dies geschieht durch Aufruf der display()-Methode. In dieser Methode wird auch durch glShadeModel() der in der Variable shadeMode gespeicherte Shadingmodus eingestellt. Nun kann durch Drücken der entsprechenden Taste der Shadingmodus im Programm umgestellt werden. Bild10: Fenster mit RGB-Würfel mit JOGL erstellt. Links: Shmoothshading Rechts: Flatshading 7.5 Animation (kreisende Kugel) Im letzten Abschnitt meines Tutorials möchte ich eine Kugel um das bisherige Objekt, den RGB-Würfel, kreisen lassen. Für solche Animationen stellt JOGL zwei Animatorklassen zur Verfügung. Zum einen der FPSAnimator und zum anderen der normale Animator. Ich werde hier den FPSAnimator verwenden. Als erstes erzeugen wir uns im Konstruktor eine Instanz des FPSAnimator. 23 Stefan Omert Java Bindings for OpenGL Dem Konstruktor des FPSAnimator wird die Zeichenfläche und die Frames-PerSecond-Rate übergeben. Die nächste Anweisung startet den Animator. Das hat zur Folge, dass der Animator nun 60mal in der Sekunde die display()-Methode der Zeichenfläche aufruft. Der Animator läuft in einem seperaten Thread. Wenn das Fenster geschlossen wird muss man den Animator sicherheitshalber stoppen bevor man das Programm beendet. Dies geschieht im WindowListener durch die Methode stop() des Animators. Um nun die kreisende Kugel zu realisieren müssen in der display()-Methode noch einige Erweiterungen vorgenommen werden. Die OpenGL Utility Toolkit Library (GLUT) stellt eine Methode zum zeichnen einer Kugel zur Verfügung. Mit dem glut-Objekt können wir auf diese Methode zugreifen und so ganz einfach unsere Kugel realisieren. Mit glTranslated() wird die Kugel auf ihre Umlaufbahn um den Würfel verschoben. Mit glRotated() wird die Kugel um den entsprechenden Winkel rotiert. Der Rotationswinkel stammt aus der Variable winkel. Diese Variable wird bei jedem Aufruf der display()-Methode um den selben Wert erhöht. Somit ist eine gleichmäßige Rotation der Kugel garantiert, da die diese Methode mit einer festen Rate aufgerufen wird. GlPushMatrix() und glPopMatrix() sind dafür zuständig das nur die Kugel verschoben und gedreht wird und nicht auch noch der Würfel. GlPushMatrix() sichert die oberste Matrix auf den 24 Stefan Omert Java Bindings for OpenGL Stack und glPopMatrix() holt diese wieder zurück. Das Ergebnis dieser Erweiterungen im Code ist eine um den RGB-Würfel kreisende Kugel. Bild11: Fenster mit RGB-Würfel und umkreisender Kugel mit JOGL erstellt 25 Stefan Omert Java Bindings for OpenGL 8. Schlusswort Ich hoffe ich konnte mit meiner Ausarbeitung jedem einen kleinen Einblick in JOGL geben und zeigen, dass es durch dieses Binding sehr einfach ist Java und OpenGL zu vereinen. Vor allem die Verwendung von AWT- und Swingkomponenten macht den Einstieg für Javaprogrammierer sehr einfach. Auch Geschwindigkeitseinbußen im Gegensatz zu OpenGL-Programmen in C sind kaum vorhanden. Bei der Einrichtung und der Verwendung von JOGL sind keine nennenswerten Probleme aufgetreten. Das einzige was am Anfang für Verwirrung sorgte, sind veraltete JOGL-Beispiele und -Tutorials im Internet, welche veraltete JOGL-Pakete verwendeten und mit der aktuellen Version nicht mehr kompatibel sind. Auch wenn man nur geringe Vorkenntnisse in OpenGL und Java hat ist der Einstieg in Grafikprogrammierung mit JOGL sehr leicht. Im Internet gibt es einige gute Tutorials zu diesem Thema. Auch auf er Entwicklerseite und in verschiedenen Foren bekommt man sehr viel Information zu diesem Thema und auch Hilfe bei der Programmierung. 26 Stefan Omert Java Bindings for OpenGL 9. Anhang 9.1 Quellen /JODEV/ JOGL API Project, https://jogl.dev.java.net/ /JOAP/ JOGL API, http://download.java.net/media/jogl/builds/nightly/ javadoc_public/overview-summary.html /JOIN/ JOGL.info, http://www.jogl.info/ /PRIM/ JOGL Primer, http://sol.cs.hm.edu/rs/jogl-primer/index.html /WIK1/ Wikipedia Jogl, http://de.wikipedia.org/wiki/Jogl /WIK2/ Wikipedia Java Standard: OpenGL, http://de.wikibooks.org/wiki/Java_Standard:_OpenGL /PJ3D/ Pro Java 6 3D Game Development, http://fivedots.coe.psu.ac.th/~ad/jg2/index.html 27