Java OpenGL Binding (JOGL)

Werbung
JOGL
Java Binding
for the
OpenGL API
Ausarbeitung im Rahmen der Lehrveranstaltung
“Graphisch Interaktive Systeme” (WS 08/09)
erstellt von Michael Kremer
Email: [email protected]
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
Inhalt
1.
Einleitung
3
2.
Über JOGL
4
2.1 Aufbau von JOGL
5
2.2 Die wichtigsten Klassen
7
Installation
9
3.
3.1
4.
Screenshots zur Einrichtung
10
Tutorial in Eclipse
11
4.1
Ein neues Projekt anlegen
11
4.2
Ein Swing-Fenster erzeugen
12
4.3
Einen GLEventListener implementieren
14
4.4
Ein Koordinatensystem zeichnen
15
4.5
Tastatur-Ereignisse verarbeiten
18
4.6
Maus-Ereignisse verarbeiten
20
4.7
Animation hinzufügen
21
5.
Eigenes Beispiel: ASURO-Roboter
24
6.
Fazit
25
7.
Quellen
25
Seite 2
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
1. Einleitung
Die Programmiersprache Java erfreut sich immer größerer Beliebtheit. Dank der
Objektorientierung und der Plattformunabhängigkeit sowie der großen Anzahl an
vielseitigen Erweiterungen ist sie für beinahe jede Problemstellung geeignet. Vor
allem die komfortablen Entwicklungswerkzeuge wie Eclipse oder die Netbeans IDE,
die kostenlos erhältlich sind und ständig von einer großen Benutzergemeinde
weiterentwickelt werden, machen diese Sprache für Entwickler interessant.
Dies galt allerdings lange Zeit nicht für die Spieleentwicklung, denn hier ist OpenGL
der Standard in 2D- und 3D-Applikationen. Zwar hat man versucht, mit Java3D eine
Alternative zu OpenGL zu etablieren, allerdings wurde die Weiterentwicklung
aufgrund der geringen Performance eingestellt.
An dieser Stelle tritt JOGL, das „Java Binding for the OpenGL API“, auf den Plan.
Neben anderen Bindings wie der „Lightweight Java Game Library“ (LWJGL) oder
„gl4java“ schlägt auch JOGL eine Brücke zwischen Java und den OpenGLFunktionalitäten und ermöglicht es, auch unter Java komplexe 2D- und 3D-Grafiken
zu realisieren. Dies ist vor allem für Internet-Anwendungen interessant, da die
Applikationen als Applets auf allen gängigen Betriebsystemen mit JavaUnterstützung ausgeführt werden können.
Diese Ausarbeitung soll JOGL vorstellen und hauptsächlich eine Einführung in die
Benutzung geben. Nach einer kurzen Beschreibung wird zunächst die Installation
und dann in einem einfachen Tutorial die Benutzung von JOGL erklärt. Mit diesen
Kenntnissen kann ein Entwickler, der seine OpenGL-Applikationen bisher nur in C
oder C++ geschrieben hat, seine Ideen sofort auf Java übertragen und dessen
Vorzüge nutzen. Außerdem soll dabei die große Ähnlichkeit zu der bisher gewohnten
Benutzung von OpenGL deutlich gemacht werden.
Als Beispiel für komplexere Anwendungen habe ich eine 3D-Simulation in Java
realisiert, die einen animierten ASURO-Roboter darstellt, der einer Linie auf dem
Fußboden hinterher fährt und dabei aus allen Richtungen betrachtet werden kann.
Dazu aber später mehr.
Seite 3
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
2. Über JOGL
JOGL ist ein Open-Source Projekt (Homepage: http://jogl.dev.java.net), das seit 2003
kontinuierlich weiterentwickelt wird. Da die Entwicklung von Sun Microsystems auf
der Java-Seite und Silicon Graphics Incorporated auf der OpenGL-Seite unterstützt
wird, ist eine hohe Qualität und Aktualität des Bindings gewährleistet. Probleme und
Fragen können in eigenen Foren mit einer großen Benutzergemeinde diskutiert und
gelöst werden.
Um die Lücke zwischen Java und dem C-Code von OpenGL zu schließen macht
JOGL sich das Java-Native-Interface, kurz JNI, zu Nutze. Das JNI ermöglicht es, aus
Java-Anwendungen heraus Code auszuführen, der in anderen Programmiersprachen geschrieben wurde und auf die jeweilige Plattform angepasst ist. Deshalb
gibt es unterschiedliche Versionen von JOGL, die auf die entsprechenden
Betriebssysteme ausgelegt sind. Unterstützt werden Windows, Linux, Solaris und
MacOS. JOGL besteht im Wesentlichen aus Java Klassen und Schnittstellen, die auf
den originalen C-Code von OpenGL zurückgreifen. Der größte Teil des C-Codes wird
dabei individuell von dem in JOGL enthaltenen Tool GlueGen während der
Kompilierung erzeugt. Der restliche C-Code dient hauptsächlich dazu, Plattformabhängige Schwierigkeiten zu umschiffen.
Die aktuelle JOGL-Version 1.1.2 unterstützt OpenGL in der Spezifikation 2.1. Man
findet fast alle Funktionen die man von OpenGL gewohnt ist wieder. Dazu zählen
auch die Funktionen der GLU-Bibliothek (OpenGL Utility Library) und der GLUTBibliothek (OpenGL Utility Toolkit). Weggefallen sind Funktionalitäten für das
Fenster- bzw. Menü-Management, da diese in Java ja bereits durch Swing und AWT
bereitgestellt werden und auch in einem JOGL Programm beliebig benutzt werden
können. Weiterhin fehlen Callback-Funktionen für Maus, Tastatur und andere
Geräte. Diese werden in Java durch die entsprechenden EventListener ersetzt.
Diese Bereiche werden später im Tutorial erneut angesprochen und praktisch
umgesetzt.
Im Übrigen hat sich seit der letzten Version 1.1.1 der Name des Projekts geändert.
Es hieß vorher „Java Bindings for OpenGL“.
Seite 4
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
2.1 Aufbau der JOGL-Library
Die Klassen-Hierarchie:
o
class java.lang.Object
o class com.sun.opengl.util.Animator
o class com.sun.opengl.util.FPSAnimator
o class javax.media.opengl.AWTGraphicsConfiguration (implements
javax.media.opengl.AbstractGraphicsConfiguration)
o class javax.media.opengl.AWTGraphicsDevice (implements
javax.media.opengl.AbstractGraphicsDevice)
o class com.sun.opengl.util.BufferUtil
o class com.sun.opengl.cg.CGannotation
o class com.sun.opengl.cg.CGcontext
o class com.sun.opengl.cg.CGeffect
o class com.sun.opengl.cg.CgGL
o class com.sun.opengl.cg.CGparameter
o class com.sun.opengl.cg.CGpass
o class com.sun.opengl.cg.CGprogram
o class com.sun.opengl.cg.CGstate
o class com.sun.opengl.cg.CGstateassignment
o class com.sun.opengl.cg.CGtechnique
o class java.awt.Component (implements java.awt.image.ImageObserver,
java.awt.MenuContainer, java.io.Serializable)
o class java.awt.Canvas (implements javax.accessibility.Accessible)
o class javax.media.opengl.GLCanvas (implements
javax.media.opengl.GLAutoDrawable)
o class java.awt.Container
o class javax.swing.JComponent (implements java.io.Serializable)
o class javax.swing.JPanel (implements
javax.accessibility.Accessible)
o class javax.media.opengl.GLJPanel (implements
javax.media.opengl.GLAutoDrawable)
o class java.awt.Panel (implements javax.accessibility.Accessible)
o class java.applet.Applet
o class com.sun.opengl.util.JOGLAppletLauncher
o class com.sun.opengl.util.texture.spi.DDSImage
o class com.sun.opengl.util.texture.spi.DDSImage.ImageInfo
o class javax.media.opengl.DebugGL (implements javax.media.opengl.GL)
o class javax.media.opengl.DefaultGLCapabilitiesChooser (implements
javax.media.opengl.GLCapabilitiesChooser)
o class com.sun.opengl.util.FileUtil
o class com.sun.opengl.util.Gamma
o class javax.media.opengl.GLCapabilities (implements java.lang.Cloneable)
o class javax.media.opengl.GLContext
o class javax.media.opengl.GLDrawableFactory
o class javax.media.opengl.glu.GLU
o class com.sun.opengl.util.GLUT
o class javax.media.opengl.glu.GLUtessellatorCallbackAdapter (implements
javax.media.opengl.glu.GLUtessellatorCallback)
o class com.sun.opengl.util.ImageUtil
o class com.sun.opengl.util.j2d.Overlay
o class com.sun.opengl.util.Screenshot
o class com.sun.opengl.util.texture.spi.SGIImage
o class com.sun.opengl.util.StreamUtil
Seite 5
JOGL
Java Binding for the OpenGL API
o
o
o
o
o
o
o
o
o
o
o
o
o
o
Michael Kremer
WS 2008/2009
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)
o class java.lang.Exception
o class java.lang.RuntimeException
o class com.sun.opengl.cg.CgException
o class javax.media.opengl.GLException
class com.sun.opengl.util.TileRenderer
class javax.media.opengl.TraceGL (implements javax.media.opengl.GL)
Die Schnittstellen-Hierarchie:
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
interface javax.media.opengl.AbstractGraphicsConfiguration
interface javax.media.opengl.AbstractGraphicsDevice
interface javax.media.opengl.ComponentEvents
o interface javax.media.opengl.GLAutoDrawable (also extends
javax.media.opengl.GLDrawable)
o interface javax.media.opengl.GLPbuffer
interface java.util.EventListener
o interface javax.media.opengl.GLEventListener
interface javax.media.opengl.GL
interface javax.media.opengl.GLCapabilitiesChooser
interface javax.media.opengl.GLDrawable
o interface javax.media.opengl.GLAutoDrawable (also extends
javax.media.opengl.ComponentEvents)
o 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
Wie man sieht ist JOGL relativ überschaubar und man entdeckt bereits unter den
Klassen und Schnittstellen bekannte Namen wie GL, GLU und GLUT. Im folgenden
Abschnitt werde ich die wichtigsten Klassen und Schnittstellen für ein einfaches
Programm kurz vorstellen.
Seite 6
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
2.2 Die wichtigsten Klassen und Schnittstellen:
Die im folgenden beschriebenen Schnittstellen und Klasse reichen aus, um selbst
OpenGL-Szenen unter JOGL zu erstellen. Sie werden alle später im Tutorial
eingesetzt und dort ggf. noch näer erläutert.
-
Schnittstelle GLAutoDrawable:
Stellt einen Event-basierten Kontext für das Rendering von Objekten bereit. Mit
dieser Schnittstelle hat der Programmierer selbst nicht viel zu tun, da sie
automatisch beim Einsatz eines GLEventListeners instanziiert wird und dort
automatisch als Parameter übergeben wird. Dazu im Tutorial mehr.
-
Schnittstelle GLEventListener:
Ein GLEventListener wird wie die bekannten Listener in Java an einen RenderKontext gebunden. Er beinhaltet die bekannten OpenGL-Funktionen „init“,
„reshape“ und „display“ und zusätzlich die Funktion „displayChanged“, mit der
man zum Beispiel auf Änderungen des Display-Modus des Bildschirms reagieren
kann. Diese sogenannten Callback-Methoden werden genau wie aus einem CProgramm bekannt eingesetzt.
-
Schnittstelle GL:
Diese Schnittstelle beinhaltet die Schnittstellen zu allen unterstützen OpenGL-CFunktionen. Eine fertige Instanz der Klasse erhält im man Programm stets von
einem GLAutoDrawable.
-
Klasse Animator bzw. FPSAnimator:
Stellt einen Thread bereit, der in bestimmten Abständen die Display-Funktion des
Programms aufruft um Animationen zu erzeugen. Der normale Animator macht
nur eine kurze Pause zwischen den Frames, dem FPSAnimator hingegen kann
man eine Framerate vorgeben. Die Klasse Animator ist wie später gezeigt wird
nicht immer geeignet.
Seite 7
JOGL
Java Binding for the OpenGL API
-
Michael Kremer
WS 2008/2009
Klasse GLCanvas:
Die Klasse ist Subklasse des normalen Canvas und stellt einen Rendering
Kontext bereit, d.h. eine Fläche zum Zeichnen der OpenGL-Szene. Sie wird wie
jede andere Swing- oder AWT-Komponente eingesetzt.
-
Klasse GLJPanel:
Diese Klasse ist Subklasse von JPanel und bietet dieselbe Funktionalität wie ein
GLCanvas. Jedoch erreicht ein GLJPanel nicht dieselbe Performance wie ein
GLCanvas.
-
Klasse GLU:
Stellt die bekannten Funktionen der GLU-Bibliothek bereit. Während man von der
Klasse GL wie bereits erwähnt automatisch eine Instanz erhält, muss GLU
speziell instanziiert werden um genutzt zu werden. Näheres im Tutorial.
-
Klasse GLUT:
Stellt analog zu GLU die entsprechenden Funktionen der GLUT-Bibliothek bereit.
Zwar gibt es noch weitere interessante Klassen wie Texture oder Screenshot, diese
sollen hier aber aus Zeitgründen nicht näher betrachtet werden. Sie würden das
Tutorial außerdem unnötig aufblähen.
Alle genannten Klassen sind wie von Java gewohnt im dazugehörigen Javadoc
ausführlich beschrieben. Die Dateien sind ebenfalls auf der JOGL-Projekt-Seite zum
Download erhältlich.
Erwähnenswert ist an dieser Stelle auch eine Erweiterung für die Sun Entwicklungsumgebung NetBeans, nämlich das NetBeans-OpenGL-Pack (https://netbeansopengl-pack.dev.java.net/), das JOGL direkt in die Entwicklungsumgebung integriert
und unter anderem einen Shader-Editor bietet.
Seite 8
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
3. Installation von JOGL
Um JOGL nutzen zu können muss selbstverständlich, falls noch nicht geschehen,
zunächst eine Java-Distribution installiert sein. JOGL erfordert mindestens das Java
2 SDK Version 1.4, besser natürlich die aktuellste Version. Das Java SDK ist
erhältlich unter http://java.sun.com.
Jetzt lädt man sich unter http://jogl.dev.java.net die aktuellste Version von JOGL für
sein Betriebssystem herunter. Im Moment ist das die Version 1.1.2, zu finden unter
dem Link „Current Nightly Builds“.
Ich werde an dieser Stelle nur auf die Installation unter Windows XP eingehen.
Hat man das Archiv heruntergeladen, entpackt man es in einen beliebigen Ordner
auf der Festplatte. Danach muss das Unterverzeichnis „/lib“ in die Umgebungsvariable PATH des Betriebssystems aufgenommen werden..
WICHTIG: Wenn man nicht nur in einer Entwicklungsumgebung wie Eclipse arbeitet
sondern auch auf der Kommandozeile JOGL-Programme kompilieren will, müssen
die vollständigen Pfade zu jogl.jar und gluegen-rt.jar zusätzlich in die
Umgebungsvariable CLASSPATH aufgenommen werden.
Im Anschluss muss der Rechner neu gestartet werden.
Zusammengefasst:
1. Aktuelle Java-SDK installieren, mindestens Version 1.4
2. Aktuelle JOGL-Version herunterladen und auf die Festplatte entpacken
3. Pfad zum Unterverzeichnis „/lib“ zur Umgebungsvariable PATH
hinzufügen
4. Optional die vollständigen Pfade zu jogl.jar und gluegen-rt.jar zur
Umgebungs-variable CLASSPATH hinzufügen, um auf der
Kommandozeile kompilieren zu können.
5. Rechner neu starten
Seite 9
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
3.1 Screenshots zur Einrichtung der Umgebungsvariablen:
Arbeitsplatz Eigenschaften Erweitert Umgebungvariablen
Systemvariable auswählen und auf „Bearbeiten“ klicken
Sollte die Umgebungsvarible CLASSPATH nicht existieren kann sie mit einem Klick
auf „Neu“ einfach erstellt werden.
Nicht vergessen: Rechner neu starten, sonst werden die Änderungen an den
Umgebungsvariablen nicht wirksam!!
Seite 10
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
4. Tutorial in Eclipse
Wir wollen nun Schritt für Schritt ein JOGL-Programm in der Entwicklungsumgebung
Eclipse erstellen und es mit allen grundlegenden Funktionen von OpenGL austatten.
Das fertige Programm soll die Achsen des Koordinatensystems darstellen sowie
einen Würfel im Zentrum, der auf Kommando ein- und ausgeblendet sowie in einer
Animation gedreht werden kann.
Ich benutze dabei die Eclipse-Version 3.4.1 (Englisch) und die JOGL-Version 1.1.2
unter Windows XP.
4.1 Neues Projekt anlegen
Wir erzeugen zunächst ein neues Java-Projekt auf herkömmliche Art und Weise. Ich
nenne das Projekt „JOGL Tutorial“. Ist dies geschehen klickt man mit der rechten
Maustaste auf das Projekt und wählt unter „Build Path“ den Punkt „Configure
Buildpath“ aus. Nun fügt man unter dem Punkt „Libraries“ mit der Schaltfläche „Add
external JARs“ die beiden Dateien „jogl.jar“ und „gluegen-rt.jar“ aus dem JOGLVerzeichnis dem Projekt hinzu und bestätigt mit „OK“.
Seite 11
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
4.2 Ein Swing-Fenster erzeugen
Wir wollen nun ein normales Swing-Fenster für unsere Anwendung erzeugen, in dem
später unsere Szene dargestellt werden kann. Dazu erstellen wir in unserem Projekt
eine neue Klasse „MyWindow“, die die Klasse „javax.swing.JFrame“ erweitert. Die
Klasse soll außerdem eine „main“-Funktion bekommen, um das Programm später zu
starten.
Anschließend können wir beginnen unser Fenster mit Leben zu füllen. Wir erstellen
einen parameterlosen Konstruktor in dem wir die Größe, den Titel sowie die ExitFunktion zum Beenden festlegen. Außerdem rufen wir bereits im Konstruktor die
Funktion setVisible auf, um das Fenster sofort anzuzeigen. Dadurch reicht es zum
starten aus, in der Main-Funktion mit „new MyWindow()“ eine anonyme Instanz zu
erzeugen.
Seite 12
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
Das Programm ließe sich jetzt bereits starten, allerdings fehlt noch etwas
Grundlegendes, nämlich die Zeichenfläche. Wir verwenden dazu ein Objekt der
Klasse GLCanvas, welches wir gleich global definieren, um später in anderen
Funktionen darauf zugreifen zu können. Alternativ könnte man auch die Klasse
GLJPanel benutzen. Diese sollte aus Kompatibilitätsgründen sogar benutzt werden,
falls das Fenster noch weitere Swing-Komponenten enthält. Da dies hier allerdings
nicht der Fall ist wählen wir die leistungsfähigere GLCanvas. Der Code müsste nun
ungefähr so aussehen:
package jogl;
import javax.media.opengl.GLCanvas;
import javax.swing.JFrame;
public class MyWindow extends JFrame {
private GLCanvas canvas;
private MyWindow() {
super();
setTitle("JOGL Tutorial");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480);
canvas = new GLCanvas();
add(canvas);
setVisible(true);
}
public static void main(String[] args) {
new MyWindow();
}
}
Startet man nun das Programm erscheint ein neues Fenster mit der Größe 640 x 480
das nur eine leere schwarze Fläche, nämlich den GLCanvas, enthält. Um zeichnen
zu können fügen wir deshalb im nächsten Schritt einen GLEventListener hinzu.
Seite 13
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
4.3 Einen GLEventListener implementieren
Um die GLCanvas nutzen zu können benötigen wir einen GLEventListener. Wie
bereits erwähnt enthält dieser die für OpenGL charakteristischen Callback-Methoden
„init“, „reshape“ und „display“. Außerdem die Methode „displayChanged“, die hier
allerdings nicht benutzt wird. Dadurch wird es erst möglich, etwas zu zeichnen.
GLEventListener ist ein Interface, es würde also genügen unsere Klasse
„MyWindow“ dieses Interface implementieren zu lassen und dessen Funktionen zu
überschreiben. Der Übersicht zuliebe erstellen wir aber eine Innere Klasse
MyGLEventListener am Ende der vorhandenen Klasse. Der Code dazu sieht
folgendermaßen aus:
private class MyGLEventListener implements GLEventListener {
public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged, boolean deviceChanged) {
}
public void init(GLAutoDrawable drawable) {
}
public void reshape(GLAutoDrawable drawable,
int x, int y, int width, int height) {
}
public void display(GLAutoDrawable drawable) {
}
}
Dieser GLEventListener wird nun an das GLCanvas-Objekt angehängt und steuert
von da an sein Verhalten. Dies geschieht mit folgender Zeile, die wir einfach in den
Konstruktor des Fensters einfügen:
canvas.addGLEventListener(new MyGLEventListener());
Im Gegensatz zu einem C-Programm muss man dem Programm nun nicht mehr
explizit die charakteristischen Funktionen vorgeben, die geschieht automatisch durch
den GLEventListener.
Wir können nun mit dem Zeichnen beginnen.
Seite 14
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
4.4 Ein Koordinatensystem zeichnen
Wie bereits angekündigt wollen wir zunächst die Achsen des Koordinatensystems in
die Szene einzeichnen. Dazu müssen zunächst die Funktion „init“ und „reshape“
ausfüllen, denn „init“ wird beim erstellen des Fensters aufgerufen und „reshape“ bei
jeder Größen- oder Positionsänderung. Wir verwenden die folgenden, bereits aus
den Vorlesungen bekannten Befehle:
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClearColor(0, 0, 0, 0);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glClearDepth(1.0);
gl.glDepthFunc(GL.GL_LESS);
}
public void reshape(GLAutoDrawable drawable,
int x, int y, int width, int height) {
GL gl = drawable.getGL();
GLU glu = new GLU();
gl.glViewport(x, y, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
if (width <= height)
gl.glOrtho(-2, 2, -2 * ((double) height) / (double) width,
2 * ((double) height) / (double) width, -5, 5);
else
gl.glOrtho(-2 * (double) width / ((double) height),
2 * (double) width / ((double) height),
-2, 2, -5, 5);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt(0.5, 0.5, 0.5, 0, 0, 0, 0, 1, 0);
}
Zu Beginn jeder Funktion holt man sich vom GLEventListener ein GL-Objekt für den
Rendering-Kontext. Sollten außerdem Objekte aus GLU oder GLUT benötigt werden,
können die beiden Klasse einfach instanziiert werden, wie in der Funktion „reshape“
zu sehen.
Wir löschen in der Funktion „init“ zunächst den Farb-Puffer und schalten den TiefenTest ein, da wir in 3D zeichnen wollen. In der Funktion „reshape“ legen wir den
Viewport und das Viewing-Volumen fest , stellen die Art der Projektion ein und
bestimmen den Betrachtungswinkel der Kamera mit „gluLookAt“. Diese Funktionen
dürften nicht neu sein.
Seite 15
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
Nun folgt die Funktion „display“, in der das Koordinatensystem gezeichnet wird:
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
GLUT glut = new GLUT();
gl.glColor3f(1.0f, 0.5f, 0.0f);
// ORANGE
for(int i = 0; i < 6; i++) {
gl.glPushMatrix();
if (i < 4) gl.glRotatef(i * 90.0f, 0.0f, 1.0f, 0.0f);
if (i == 4) gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
if (i == 5) gl.glRotatef(90.0f,-1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.5f);
gl.glBegin(GL.GL_LINES); {
gl.glVertex3f( 0.0f, 0.0f, 0.0f);
gl.glVertex3f( 0.0f, 0.0f,-1.5f);}
gl.glEnd();
glut.glutWireCone(0.05f, 0.25f, 10, 5);
gl.glRasterPos3f(-0.1f, 0.1f, 0.4f);
switch (i) {
case 0: drawText("Z"); break;
case 1: drawText("X"); break;
case 2: drawText("-Z"); break;
case 3: drawText("-X"); break;
case 4: drawText("-Y"); break;
case 5: drawText("Y"); break;
}
gl.glPopMatrix();
}
}
private void drawText(String text) {
GLUT glut = new GLUT();
for(int i = 0; i < text.length(); i++)
glut.glutBitmapCharacter(GLUT.BITMAP_9_BY_15, text.charAt(i));
}
Auch hier wird zunächst ein Objekt der Klasse GL geholt. Danach werden wie schon
bekannt die Puffer initialisiert. Außerdem erzeugen wir uns ein GLUT-Objekt und
stellen die Zeichenfarbe auf orange ein.
Jetzt wird sechs mal eine Linie (Verfahren ist bekannt) mit einer Pfeilspitze
(glutWireCone aus der GLUT) gezeichnet, mit einer Beschriftung versehen, aus dem
Ursprung herausgeschoben und dann in die entsprechende Richtung gedreht.
GLPushMatrix und GLPopMatrix werden eingesetzt, damit sich die Translationen und
Drehungen nur jeweils auf den aktuellen Pfeil auswirken. Die Hilfsfunktion „drawText“
zeichnet Buchstaben in die Szene ein mit Hilfe einer GLUT-Funktion. Die Funktion
„glRasterPos3f“ bestimmt dabei die Position des Textes in Abhängigkeit von der
letzten Stelle an der gezeichnet wurde.
Seite 16
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
Es müsste sich nach dem Starten des Programms folgendes Fenster öffnen:
Und schon haben wir unsere erste OpenGL-Szene erstellt. Das Fenster kann nun
dank der Funktion „reshape“ beliebig verschoben und in der Größe geändert werden,
ohne das das Bild zu verzerren.
Im nächsten Abschnitt wollen wir das Programm jetzt dahingehend erweitern, das im
Ursprung ein Würfel angezeigt wird, der mit einem Tastendruck aus- und wieder
eingeblendet werden kann.
Seite 17
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
4.5 Tastatur-Ereignisse verarbeiten
Unser Programm soll nun auf Tastatureingaben reagieren und einen Würfel im
Ursprung aus- und wieder einblenden können. Dazu benötigen wir wie aus Java
bekannt einen KeyListener. Wir erstellen dazu wiederum eine innere Klasse mit
Namen „MyKeyListener“, die das Interface KeyListener implementiert.
private class MyKeyListener implements KeyListener {
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
switch (e.getKeyChar()) {
case 0x1B:
System.exit(0);
break;
case 0x20:
showCube = !showCube;
canvas.display();
break;
default:
break;
}
}
}
Es soll folgende Eingabemöglichkeiten geben:
-
Escape-Taste (Hexcode 1B): Programm beenden
-
Leertaste (Hexcode 20): Würfel ein- und ausblenden
Das Ein- und Ausblenden des Würfels wird über eine globale, Boole’sche, mit „false“
initialisierte Variable „showCube“ realisiert. Dazu wird die Funktion „display“ des
GLEventListeners wie folgt ergänzt und bei jedem Druck auf die Leertaste erneut
aufgerufen (Die Funktion „canvas.display()“ ruft die „display“-Funktion des
angehängten GLEventListeners auf):
if (showCube) {
gl.glColor3f(1.0f, 1.0f, 1.0f);
glut.glutWireCube(0.8f);
}
Seite 18
// WEISS
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
Der KeyListener muss jetzt nur noch mit dem Fenster verknüpft werden. Dazu wird er
aber nicht etwa wie gewohnt an den JFrame oder die GLCanvas angehängt, sondern
an der Rendering-Kontext von OpenGL, also das Objekt der Klasse GLAutoDrawable
in der Funktion „init“ des GLEventListeners. Die Funktion wird um diese Zeile
ergänzt:
drawable.addKeyListener(new MyKeyListener());
Jetzt kann das Programm gestartet werden. Nach einem Klick auf das Zeichenfeld
kann mit der Leertaste ein Würfel eingeblendet und mit Escape das Programm
beendet werden.
Das entstandene Bild sieht durch den unglücklich gewählten Blickwinkel allerdings
nicht sehr dreidimensional aus. Dies wollen wir im nächsten Kapitel ändern, in dem
wir mit der Maus die Szene drehen.
Seite 19
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
4.6 Maus-Ereignisse verarbeiten
Es soll nun ermöglicht werden, mit der Maus die Szene zu drehen. Dazu benötigen
wir diesmal zwei Listener, nämlich einen MouseListener zur Überwachung der
Tasten und einen MouseMotionListener um auf Ziehen zu testen. Sie werden genau
wie der KeyListener an das GLAutoDrawable-Objekt angehängt. Ihr Code sieht so
aus:
private class MyMouseMotionListener implements MouseMotionListener {
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
viewRotY = ((x - dragStartX) / (float) getWidth()) * 360.0f;
viewRotX = ((y - dragStartY) / (float) getHeight()) * 360.0f;
dragStartX = e.getX();
dragStartY = e.getY();
canvas.display();
}
public void mouseMoved(MouseEvent arg0) {
}
}
private class MyMouseListener implements MouseListener {
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent e) {
dragStartX = e.getX();
dragStartY = e.getY();
}
public void mouseReleased(MouseEvent arg0) {
}
}
Die Variablen viewRotX/Y (Float) und dragStartX/Y (Integer) müssen global definiert
und mit 0 initialisiert werden. In der „display“-Funktion fügt man jetzt VOR dem
Zeichnen der Objekte folgendes ein:
gl.glRotatef(viewRotX, 1.0f, 0.0f, 0.0f);
gl.glRotatef(viewRotY, 0.0f, 1.0f, 0.0f);
Damit wird die gesamte Szene gedreht und währenddessen ständig neu gezeichnet.
Seite 20
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
4.7 Animation hinzufügen
Als Abschluss des Tutorials soll sich der Würfel in einer Animation um die Y-Achse
drehen. Dazu gibt es zwei Möglichkeiten. Zum einen könnte man die JOGL-Klassen
Animator oder FPSAnimator benutzen, die die „display“-Funktion ständig neu
aufrufen. Diese sind allerdings nur in einfachen Fällen geeignet, da man in dem
Thread nichts anderes ausführen kann, wie zum Beispiel Frames zählen. Deshalb
schreiben wir unseren eigenen Animations-Thread, der wie folgt aussieht:
private class AnimationThread extends Thread {
private int fps;
public AnimationThread(int fps) {
super();
this.fps = fps;
}
public void run() {
while (animation) {
viewRotX = 0;
viewRotY = 0;
cubeRot += 1.0f;
try {
sleep(1000 / fps);
} catch (Exception e) {;}
canvas.display();
}
}
}
Er bildet im Prinzip genau den FPSAnimator von JOGL nach, nur dass man die drei
Wertzuweisungen in der „display“-Funktion machen müsste. Bei manchen
Operationen ist dies allerdings nicht möglich. In unserem Fall würde die Variable
„cubeRot“, die die Drehung des Würfels bestimmt, auch beim Ändern des
Betrachtungswinkels hochgezählt. Oder will man zum Beispiel die Frames mitzählen
um den FPSAnimator zu testen kann man dies nicht in der „display“-Funktion tun,
denn diese wird auch beim Ziehen der Maus aufgerufen. Es empfiehlt sich daher
eigene Threads zu benutzen, da sie einfacher zu erweitern sind.
Seite 21
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
Für die Animation muss aber noch mehr Code geschrieben werden. Es muss eine
globale Boole’sche Variable „animation“ geben, um den Thread stoppen zu können.
Außerdem muss der KeyListener ergänzt werden:
case 0x0A:
if (!animation) {
animation = true;
new AnimationThread(50).start();
} else {
animation = false;
}
break;
Hier wird beim Drücken der Eingabetaste die Variable „animation“ geändert und ggf.
ein AnimationThread mit einer bestimmten Framerate gestartet.
Des Weiteren muss die „display“-Funktion angepasst werden:
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
GLUT glut = new GLUT();
gl.glRotatef(viewRotX, 1.0f, 0.0f, 0.0f);
gl.glRotatef(viewRotY, 0.0f, 1.0f, 0.0f);
gl.glColor3f(1.0f, 0.5f, 0.0f);
// ORANGE
for(int i = 0; i < 6; i++) {
gl.glPushMatrix();
if (i < 4) gl.glRotatef(i * 90.0f, 0.0f, 1.0f, 0.0f);
if (i == 4) gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
if (i == 5) gl.glRotatef(90.0f,-1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.5f);
gl.glBegin(GL.GL_LINES); {
gl.glVertex3f( 0.0f, 0.0f, 0.0f);
gl.glVertex3f( 0.0f, 0.0f,-1.5f);}
gl.glEnd();
glut.glutWireCone(0.05f, 0.25f, 10, 5);
gl.glRasterPos3f(-0.1f, 0.1f, 0.4f);
switch (i) {
case 0: drawText("Z"); break;
case 1: drawText("X"); break;
case 2: drawText("-Z"); break;
case 3: drawText("-X"); break;
case 4: drawText("-Y"); break;
case 5: drawText("Y"); break;
}
gl.glPopMatrix();
}
if (showCube) {
gl.glPushMatrix();
gl.glColor3f(1.0f, 1.0f, 1.0f);
// WEISS
gl.glRotatef(cubeRot, 0.0f, 1.0f, 0.0f);
glut.glutWireCube(0.8f);
gl.glPopMatrix();
}
Seite 22
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
Wie man sieht wird der Würfel jetzt noch um den Wert „cubeRot“ gedreht, welcher
global sein muss und in dem AnimationThread hochgezählt wird. Ausserdem wird
das Zeichnen des Würfels jetzt auch von glPushMatrix und glPopMatrix
eingeschlossen, das sich die glRotate-Funktionen sonst gegenseitig beeinflussen
würden.
Damit sind wir bereits am Ende des Tutorials angelangt und haben somit alle
grundlegenden Funktionen für die JOGL-Programmierung kennengelernt.
Seite 23
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
5. Eigenes Beispiel: ASURO-Roboter
Um eine praktische Anwendung zu zeigen, habe noch ein etwas komplexeres
Beispiel kreiert. Es handelt sich um eine Simulation eines ASURO-Roboters, der
einer Linie hinterherfährt.
Der ASURO ist ein etwa 10cm langer, frei programmierbarer Experimentier-Roboter,
der über zwei Motoren und diverse Sensoren und LEDs verfügt. Darunter auch zwei
Helligkeitssensoren an der Unterseite, die es ihm ermöglichen, bei entsprechender
Programmierung einer Linie zu folgen.
Mein Beispielprogramm erzeugt nach Benutzervorgaben eine Linie auf einem
Untergrund, der der ASURO animiert folgt, inklusive leuchtender LEDs, beweglichem
Schalter und drehenden Zahn- und Antriebsrädern. Die Linie kann zufällig verlaufen,
Zickzackförmig, Sinusförmig oder gerade. Der Benutzer kann zwischen den
einzelnen Modi per Taste wählen.
Das Programm beinhaltet außerdem alle Funktionen des Tutorials und hat insgesamt
circa 850 Zeilen inklusive Kommentaren. Es liegt dieser Ausarbeitung bei und kann
einfach in Eclipse importiert werden, vorausgesetzt JOGL ist installiert.
Folgende Aktionen sind möglich:
- Tasten „1“ – „4“: Art der Linie ändern (Gerade, Zufällig, Zickzack oder Sinus)
- Taste „a“: Koordinatensystem aus- und einblenden
- Taste „f“: Fußboden aus- und einblenden
- Taste „r“: Roboter aus- und einblenden
- Leertaste: Ansicht zurücksetzen
- Eingabetaste: Animation starten und stoppen
- Escape: Programm beenden
Mit der Maus kann der Blickwinkel geändert werden.
Statt zu Simulieren könnte man das Programm auch mit echten Daten füttern, leider
hat dafür aber die Zeit nicht gereicht.
Seite 24
JOGL
Java Binding for the OpenGL API
Michael Kremer
WS 2008/2009
6. Fazit
Mir hat die Arbeit mit JOGL viel Spaß gemacht. Wenn man bereits in C OpenGLAnwendungen geschrieben hat, ist es ein Leichtes sich auf JOGL umzustellen und
man findet schnell Gefallen an den Vorteilen von Java. Bei der Programmierung sind
keine nennenswerten Schwierigkeiten aufgetreten und alles hat wie beschrieben
funktioniert. Gerne wäre ich noch auf Texturen und Materialien eingegangen, aber
leider haben Zeit und Umfang der Ausarbeitung das verhindert. Ich kann aber jedem
nur empfehlen sich mit JOGL zu beschäftigen. Es gibt im Internet genug Beispiele
und Tutorials, damit auch Anfänger schnell einen Einstieg finden.
7. Quellen
https://jogl.dev.java.net/
Offizielle Projekt-Seite
http://de.wikipedia.org/wiki/Jogl
JOGL bei Wikipedia
http://www.jogl.info
Info-Seite mit Tutorial
http://www.google.de/
Die beste Bildersuchmaschine
JOGL Javadoc
Beschreibung der JOGL API
JOGL Userguide
Installationshinweise und Einführung
Seite 25
Herunterladen