Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
<strong>OpenGL</strong> <strong>for</strong> <strong>Java</strong>
Ziele<br />
Bewegte Simulationen grafisch darstellen können<br />
(effizient, realistisch, dreidimensional)<br />
Grundfunktionen von <strong>OpenGL</strong> beherrschen<br />
Mathematische Voraussetzungen für Computer Grafik verstehen
Computer Grafik<br />
Wozu <strong>OpenGL</strong>?<br />
Echtzeit 3D Grafik sehr rechenintensiv<br />
Einfache, leicht parallelisierbare Algorithmen<br />
(wenig Code, wenige Kontrollstrukturen)<br />
Viele wichtige Anwendungen<br />
geeignet für Spezialhardware (Grafikkarte)<br />
Weiterer Vorteil durch Grafik Karte:<br />
Weniger Hauptspeicherzugriffe, indem grafische Objekte<br />
direkt auf der Grafikkarte gespeichert werden.<br />
<strong>OpenGL</strong>: High level Software API für Grafik Hardware
Was ist <strong>OpenGL</strong>?<br />
Spezifikation einer Software Schnittstelle<br />
zur Grafik Hardware (API)<br />
System- und Programmiersprachen unabhängig<br />
ca. 250 Befehle<br />
…und was nicht?<br />
GUI Programmierung, Sound, Netzwerk, usw…
Wie funktioniert‘s?<br />
Benutzerprogramm: Aufruf von <strong>OpenGL</strong> API Funktionen<br />
<strong>OpenGL</strong><br />
Position, Form und Farbe von 3D Objekten (Würfel, Kugel, …)<br />
Position und Farbe von Lichtquellen<br />
Oberflächenbeschaffenheit (Textur) von Objekten<br />
Position und Blickrichtung der Kamera<br />
Koordinatensystem Trans<strong>for</strong>mationen (Drehung, Verschiebung…)<br />
Projektion der 3D Szene auf ein 2D Bild<br />
Farbverlauf auf Flächen (Licht/Schatten)<br />
Sichtbare/verdeckte Flächen<br />
Trans<strong>for</strong>mation von Texturen
Geschichte von <strong>OpenGL</strong><br />
1982 SGI beginnt mit der Entwicklung für<br />
High End Grafik Workstations<br />
1992 <strong>OpenGL</strong> Version 1.0<br />
Seit 1992 Open GL Architecture Review Board (ARB)<br />
Mitglieder: Compaq, ATI, nVidia, HP, IBM, Apple, Microsoft, …<br />
Heute: <strong>OpenGL</strong> Version 2.0<br />
Grafikkarten Wettbewerb, Erweiterungen
GLU (<strong>OpenGL</strong> Utilities)<br />
Zusätzliche Bibliotheken<br />
Einfache Funktionen zum Zeichnen komplexerer Objekte<br />
(Kugeln, Zylinder, Scheibe, …)<br />
Gekrümmte Flächen: NURBS<br />
Viele nützliche Hilfsfunktionen<br />
GLUT (<strong>OpenGL</strong> Utility Toolkit)<br />
Torus, Tetrahedron, Octahedron, …<br />
Text<br />
Platt<strong>for</strong>munabhängige GUI Funktionen (Fenster, Maus, Tastatur)<br />
Für GUI Funktionen verwenden wir <strong>Java</strong>!
GLUT<br />
WGL/GLX/AGL<br />
Window System<br />
Zusätzliche Bibliotheken<br />
Anwendungsprogramm<br />
<strong>OpenGL</strong><br />
Grafik Hardware<br />
GLU<br />
Systemunabhängig<br />
Systemabhängig
GLUT<br />
WGL/GLX/AGL<br />
Window System<br />
Anwendungsprogramm<br />
GL4<strong>Java</strong><br />
<strong>OpenGL</strong><br />
Grafik Hardware<br />
GLU<br />
JNI<br />
Systemunabhängig<br />
Systemabhängig
Canvas3D.java<br />
Das erste <strong>OpenGL</strong> Programm<br />
Starter.java<br />
Fenster erzeugen (JFrame)<br />
Zeichenfläche (Canvas3D) erzeugen und anzeigen<br />
Abgeleitet von GLAnimCanvas (GL4<strong>Java</strong> Klasse)<br />
preInit, init: Initialisierung<br />
display: Wird aufgerufen, um Bildschirm neu zu zeichnen<br />
reshape: Wird aufgerufen, wenn Fenstergröße geändert wird.<br />
Triang
import javax.swing.*;<br />
import java.awt.*;<br />
class Starter<br />
{<br />
public static void main(String[] args)<br />
{<br />
// Erzeugen des <strong>OpenGL</strong> Canvas<br />
Canvas3D canvas3D = new Canvas3D(640,480);<br />
}<br />
}<br />
// Erzeugen des Anwendungsfensters<br />
JFrame frame = new JFrame("Triangles <strong>for</strong> <strong>Java</strong>");<br />
// <strong>OpenGL</strong> Canvas dem Frame hinzufügen<br />
Container pane = frame.getContentPane();<br />
pane.add(canvas3D);<br />
// Frame Grösse setzen und anzeigen<br />
frame.setSize(640,480);<br />
frame.setVisible(true);<br />
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
Starter.java
import gl4java.awt.GLCanvas;<br />
class Canvas3D extends GLAnimCanvas<br />
{<br />
// Konstruktor für Gl4<strong>Java</strong> Klasse GLCanvas<br />
public Canvas3D(int w, int h) { super(w, h); }<br />
}<br />
// Globale <strong>OpenGL</strong> Optionen (z.B. double buffering) setzen<br />
public void preInit() { … }<br />
// Einmaliges Initialisieren (z.B. Farbe zum Löschen)<br />
public void init() { … }<br />
// Wird aufgerufen, wenn Bildschirm neu gezeichnet werden muss<br />
public void display() { … }<br />
// Wird aufgerufen, wenn Fenstergröße geändert wird<br />
public void reshape(int width, int height) { … }<br />
Canvas3D.java
eshape(int width, int height)<br />
Bildschirmbereich auf den gezeichnet werden soll in Pixel<br />
glViewport( 0,0,width,height );<br />
Matrix, die 3D nach 2D Projektion macht<br />
Perspektivische Projektion<br />
60 Grad Blickwinkel, Clipping Abstand 2 bis 4<br />
glMatrixMode( GL_PROJECTION );<br />
glLoadIdentity();<br />
gluPerspective(60, 1.0, 2.0, 4.0);<br />
// Matrix, die Zeichenkoordinatensystem positioniert<br />
glMatrixMode( GL_MODELVIEW );<br />
TriangleVie
display<br />
Löschen was zuvor gemalt wurde<br />
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />
Farbe rot einstellen<br />
glColor3f(1.0f,0.0f,0.0f);<br />
Zeichenkoordinatensystem 3 Einheiten nach hinten setzen<br />
glLoadIdentity();<br />
glTranslatef(0.0f, 0.0f, -3.0f);<br />
Dreieck durch Eckpunkte zeichnen<br />
glBegin(GL_TRIANGLES);<br />
glVertex3f(-1.0f, -1.0f, 0.0f); // links unten<br />
glVertex3f( 1.0f, -1.0f, 0.0f); // rechts unten<br />
glVertex3f( 0.0f, 1.0f, 0.0f); // mitte oben<br />
glEnd();
init<br />
Interpolation wenn Eckpunkte unterschiedliche Farbe haben<br />
glShadeModel(GL_FLAT);<br />
Hintergrundfarbe Weiss<br />
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);<br />
preinit<br />
Double Buffering (flüssiger bei bewegter Grafik)<br />
super.doubleBuffer = true;<br />
Für Stereo Brillen<br />
super.stereoView = false;
Schattierungsmodell auf GL_SMOOTH setzen<br />
Jedem Eckpunkt des Dreiecks eine andere Farbe geben<br />
gl.glBegin(GL_TRIANGLES);<br />
gl.glColor3f(1.0f,0.0f,0.0f); rot<br />
gl.glVertex3f(-1.0f, -1.0f, 0.0f); links unten<br />
gl.glColor3f(0.0f,1.0f,0.0f); grün<br />
gl.glVertex3f( 1.0f, -1.0f, 0.0f); rechts unten<br />
gl.glColor3f(0.0f,0.0f,1.0f); blau<br />
gl.glVertex3f( 0.0f, 1.0f, 0.0f); mitte oben<br />
gl.glEnd();<br />
TriangleInterpolatio
Dreieck um 20 Grad um z-Achse nach links drehen<br />
gl.glRotatef( 20.0f, 0.0f, 0.0f, 1.0f );<br />
z-Achse<br />
TriangleRotation, TriangleRotationVie
Matrizen in <strong>OpenGL</strong><br />
Model View Matrix glMatrixMode(GL_MODELVIEW);<br />
Legt Position und Orientierung des Koordinatensystems<br />
fest, in das als nächstes gezeichnet wird.<br />
glRotate(), glTranslate(), …<br />
3D nach 2D Projektions Matrix glMatrixMode(GL_PROJECTION);<br />
Bestimmt, wie eine 3D Szene auf ein 2D Bild projiziert wird.<br />
- Orthogonalprojektion: glOrtho()<br />
- Perspektivische Projektion: gluPerspective(), glFrustum()<br />
Wird i.a. nur einmal gesetzt und nicht mehr geändert.
Koordinatensystem Trans<strong>for</strong>mationen in <strong>OpenGL</strong><br />
glVertex(x,y,z)<br />
Objektkoordinaten<br />
Multiplikation mit Model View Matrix<br />
glRotate(),glTranslate()<br />
Kamerakoordinaten<br />
Multiplikation mit Projektions Matrix<br />
gluPerspective()<br />
2D Koordinaten<br />
Skalieren, Verschieben<br />
glViewPort()<br />
Bildschirmkoordinaten (Pixel)
Etwas Mathematik…<br />
Trans<strong>for</strong>mationen (Translation, Rotation, Projektion)<br />
Koordinatensysteme<br />
Homogene Koordinaten
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_TRIANGLES);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw.<br />
gl.glEnd();<br />
1<br />
2<br />
3<br />
5<br />
4<br />
6
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_POINTS);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
Größe der Punkte<br />
gl.glPointSize(float size)<br />
1<br />
3<br />
2
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_LINES);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
Liniendicke<br />
gl.glLineWidth(float size)<br />
1<br />
4<br />
3<br />
2
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_LINE_STRIP);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
1<br />
4<br />
3<br />
2
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_LINE_LOOP);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
1<br />
4<br />
3<br />
2
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_TRIANGLE_STRIP);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
1<br />
2<br />
3<br />
4 5
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_TRIANGLE_FAN);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
1<br />
2<br />
5<br />
3<br />
4
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_QUADS);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
1<br />
2<br />
6<br />
5<br />
4<br />
3<br />
8<br />
7
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_QUAD_STRIP);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
gl.glVertex(…); Punkt 4<br />
usw. …<br />
gl.glEnd();<br />
1<br />
2<br />
3<br />
6<br />
4<br />
5
<strong>OpenGL</strong> Primitive<br />
gl.glBegin(GL_POLYGON);<br />
gl.glVertex(…); Punkt 1<br />
gl.glVertex(…); Punkt 2<br />
gl.glVertex(…); Punkt 3<br />
usw. …<br />
gl.glEnd();<br />
Ränder dürfen sich nicht schneiden,<br />
sonst ist unklar was innen und außen ist!<br />
Die Eckpunkte müssen alle in einer Ebene liegen,<br />
sonst ist unklar welche Fläche gemalt werden soll!<br />
Polygone müssen konvex sein!<br />
1<br />
2<br />
3<br />
1<br />
5<br />
4<br />
2 3<br />
1<br />
4<br />
5<br />
4<br />
5<br />
2 3
Polygone<br />
GL_TRIANGLES, GL_QUADS, GL_POLYGON<br />
Def. Vorderseite: Reihenfolge der Eckpunkte gegen Uhrzeigersinn<br />
3<br />
3<br />
1 2<br />
Vorderseite<br />
Rückseite<br />
4 3<br />
1 2<br />
1 2<br />
2<br />
4<br />
3<br />
1
Polygone<br />
Polygone gefüllt, als Linien oder nur die Eckpunkte zeichnen<br />
gl.glPolygonMode( GL_FRONT, GL_POINT )<br />
GL_BACK GL_LINE<br />
GL_FRONT_AND_BACK GL_FILL<br />
Nur Vorderseite/Rückseite zeichnen<br />
Effizienz<br />
Verdeckte Flächen bei geschlossenen Körpern<br />
gl.glEnable(GL_CULL_FACE)<br />
gl.glCullFace( GL_FRONT )<br />
GL_BACK<br />
GL_FRONT_AND_BACK
In der init Methode<br />
Geschwindigkeit (Bilder pro Sekunde)<br />
Starten und anhalten<br />
super.start();<br />
super.stop();<br />
Bewegte Grafik<br />
super.setAnimateFps(60.0);<br />
// 60 Aufrufe von display() pro Sekunde
TriangleAnimation, TriangleAnimationVie<br />
Bewegte Grafik<br />
Rotierendes Dreieck um seine (lokale) y-Achse<br />
Vorderseite ausgefüllt, Rückseite Linien
3D Grafik<br />
Problem: Kein „richtiger“ 3D Eindruck wenn Flächen ausgefüllt sind!<br />
Lösung: Licht und Schatten<br />
Lichtquellen<br />
(Position, Richtung, Farbe, Ausbreitung, …)<br />
Oberflächen<br />
(Normalenvektor, Reflektionseigenschaften, Farbe, …)<br />
Cube, CubeLigh
Mehr Mathematik…<br />
Licht Reflektion<br />
Normalenvektoren
ohne Glanz<br />
Diffuse Reflektion…<br />
mit Glanz<br />
CubeLightVie
Normalenvektoren<br />
gl.glBegin(GL_QUADS);<br />
gl.glEnd()<br />
// Vorderseite<br />
gl.glNormal3f( 0.0f, 0.0f, 1.0f);<br />
gl.glVertex3f(-1.0f,-1.0f, 1.0f);<br />
gl.glVertex3f( 1.0f,-1.0f, 1.0f);<br />
gl.glVertex3f( 1.0f, 1.0f, 1.0f);<br />
gl.glVertex3f(-1.0f, 1.0f, 1.0f);<br />
// Rechte Seite<br />
gl.glNormal3f( 1.0f, 0.0f, 0.0f);<br />
gl.glVertex3f( 1.0f,-1.0f, 1.0f);<br />
gl.glVertex3f( 1.0f,-1.0f,-1.0f);<br />
gl.glVertex3f( 1.0f, 1.0f,-1.0f);<br />
gl.glVertex3f( 1.0f, 1.0f, 1.0f);<br />
// usw…
Normalenvektoren<br />
gl.glNormal3f( 0.0f, 0.0f, 1.0f);<br />
Aktuellen Normalenvektor setzen.<br />
Dieser bleibt so lange gültig,<br />
bis ein neuer Normalenvektor gesetzt wird<br />
Möglich: An jedem Eckpunkt ein anderer „Normalenvektor“.<br />
Anwendung: Gekrümmte Flächen, die aus vielen Einzelpolygonen bestehen.<br />
Lichtverlauf an den Kanten dann glatter („smooth shading“).
Licht<br />
// Licht aktivieren<br />
gl.glEnable(GL_LIGHTING);<br />
Ab jetzt Farbberechnung nur noch mit Licht und Oberflächen!<br />
Aufrufe von glColor werden ignoriert!<br />
// Einzelne Lichtquellen einschalten (maximal 8)<br />
gl.glEnable(GL_LIGHT0);<br />
gl.glEnable(GL_LIGHT1);<br />
gl.glEnable(GL_LIGHT2);
Licht<br />
// Position der i-ten Lichtquelle<br />
// Unendlich weit in z-Richtung, daher parallele Strahlen<br />
float[] position = { 0.0f, 0.0f, 1.0f, 0.0f };<br />
gl.glLightfv( i, GL_POSITION, position );<br />
// Farbe der i-ten Lichtquelle (RGBA)<br />
float[] color = { 1.0f, 1.0f, 1.0f, 1.0f }<br />
gl.glLightfv( i, GL_DIFFUSE, color);<br />
GL_AMBIENT<br />
GL_SPECULAR
osition<br />
Licht<br />
(Spotlight)<br />
// Richtung der Lichtstrahlen<br />
float[] direction = { 0.0f, 0.0f, -1.0f }<br />
gl.glLightfv( i, GL_SPOT_DIRECTION, direction );<br />
// Öffnungswinkel der Lichtstrahlen<br />
gl.glLightf( i, GL_SPOT_CUTOFF, angle);<br />
// Exponentielles Abfallen von der Mitte zum Rand<br />
gl.glLightf( i, GL_SPOT_Exponent, exp);<br />
angle<br />
direction
Material<br />
// Reflektionseigenschaften (RGBA)<br />
float[] color = { 1.0f, 0.0f, 0.0f, 1.0 }<br />
gl.glMaterialfv( GL_FRONT, GL_DIFFUSE, color );<br />
GL_BACK GL_AMBIENT<br />
GL_FRONT_AND_BACK GL_SPECULAR<br />
GL_AMBIENT_AND_DIFFUSE<br />
GL_EMISSION<br />
// Glanz (für specular reflection)<br />
gl.glMaterialf( GL_FRONT, GL_SHININESS, factor);<br />
GL_BACK<br />
GL_FRONT_AND_BACK
Material<br />
Weißen, rotierenden Würfel<br />
mit einem roten und einem blauen Spotlight<br />
anstrahlen. Die Lichtquellen drehen sich nicht mit!<br />
Was passiert wenn man backface culling abschaltet?<br />
Würde ein nicht-konvexes Objekt richtig dargestellt?<br />
CubeSpo
Texturen<br />
Idee: Bild auf die Oberflächen von Objekten kleben<br />
1<br />
0<br />
0<br />
1<br />
Texturbild<br />
Polygon<br />
Jedem Eckpunkt des Polygons einen Punkt der Textur zuordnen.<br />
Texturkoordinaten: glTexCoord2f()<br />
Farbwerte innerhalb des Polygons durch Interpolation.
Texturen<br />
import gl4java.utils.textures.PngTextureLoader;<br />
// Texturbild lesen (Abmessungen müssen 2er Potenz sein!)<br />
PngTextureLoader texload = new PngTextureLoader(gl, glu);<br />
texload.readTexture("textures/ambrosil.png");<br />
// Textur in Speicher auf Grafik Karte laden<br />
glTexImage2D( GL_TEXTURE_2D, 0 1 , GL_RGB,<br />
texload.getImageWidth(), texload.getImageHeight(),<br />
0 2 , GL_RGB, GL_UNSIGNED_BYTE, texload.getTexture() );<br />
1 Mip Maps<br />
2 Rand<br />
// Interpolation<br />
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );<br />
GL_TEXTURE_MIN_FILTER GL_NEAREST
Texturen<br />
CubeIntersect<br />
Zwei rotierende Marmorwürfel nebeneinander zeichnen<br />
so dass sie sich überschneiden.<br />
Jeder Würfel dreht sich um eine Achse durch seinen Mittelpunkt!<br />
Würfel zeichnen in eigene Methode kapseln und zweimal aufrufen.<br />
Momentane Matrix auf Stapel speichern bzw. zurück holen:<br />
glPushMatrix, glPopMatrix<br />
Hidden Surface Problem: gl.glEnable(GL_DEPTH_TEST);<br />
z-Puffer Algorithmus<br />
Warum reicht backface culling nicht mehr aus?
GLU Quadrics<br />
Kugel, Zylinder, Scheibe<br />
// Quadric erzeugen bzw. löschen<br />
long quad = glu.gluNewQuadric();<br />
glu.gluDeleteQuadric( quad );<br />
// Kugel<br />
glu.gluSphere( quad, radius, kuchenstücke, stapel );<br />
// Zylinder<br />
glu.gluCylinder( quad, radius_unten, radius_oben,<br />
höhe, kuchenstücke, stapel );<br />
// Scheibe<br />
glu.gluDisk( quad, radius_innen, radius_außen,<br />
kuchenstücke, ringe );
GLU Quadrics<br />
// Darstellung<br />
glu.gluQuadricDrawStyle( quad, GLU_FILL );<br />
GLU_POINT<br />
GLU_LINE<br />
GLU_SHILOUETTE<br />
// Normalenvektoren automatisch erzeugen<br />
glu.gluQuadricNormals( quad, GLU_SMOOTH );<br />
GLU_FLAT<br />
GLU_NONE<br />
// Texturkoordinaten automatisch erzeugen<br />
glu.gluQuadricTexture( quad, GL_TRUE );<br />
GL_FALSE<br />
Quadric
GLU Quadrics<br />
Flat shading statt smooth shading bei der<br />
Berechnung der Normalenvektoren<br />
Mond um Erde kreisen lassen (moon.png)<br />
Texturen in init-Methode laden und auf Grafikkarte speichern<br />
// Platz für ID’s für 2 Texturobjekte<br />
int[] textures = new int[2];<br />
// Texturobjekte erzeugen, ID’s in textures speichern<br />
gl.glGenTextures(2, textures);<br />
// i-te Textur zur aktuellen Textur machen<br />
gl.glBindTexture(GL_TEXTURE_2D, textures[i]);<br />
EarthMoon
Positionierung der Kamera<br />
glu.gluLookAt<br />
(<br />
double eyex, double eyey, double eyez, // Punktvektor<br />
double atx, double aty, double atz, // Punktvektor<br />
double upx, double upy, double upz // Richtungsvektor<br />
);<br />
eye<br />
up<br />
at
Positionierung der Kamera<br />
glu.gluLookAt<br />
(<br />
double eyex, double eyey, double eyez, // Punktvektor<br />
double atx, double aty, double atz, // Punktvektor<br />
double upx, double upy, double upz // Richtungsvektor<br />
);<br />
In „Wirklichkeit“ wird die gesamte Szene bewegt!<br />
Die Kamera steht nach wie vor im Koordinatenursprung<br />
und schaut in negative z-Richtung.<br />
Multiplikation der Model View Matrix mit einer<br />
entsprechenden Matrix von links.<br />
(Trans<strong>for</strong>mation bzgl. Ursprungskoordinatensystem!)<br />
Daher: gluLookAt gleich nach glLoadIdentity aufrufen!
Positionierung der Kamera<br />
Kamera mit Cursor Tasten in x- und y-Richtung bewegen.<br />
Kamera soll dabei immer gerade aus in negative z-Richtung schauen.<br />
import java.awt.event.KeyEvent;<br />
import java.awt.event.KeyListener;<br />
// Klasse Canvas3D ist Key Listener<br />
class Canvas3D extends GLAnimCanvas implements KeyListener<br />
// Im Konstruktor von Canvas3D<br />
addKeyListener(this);<br />
// Callback Funktionen<br />
public void keyTyped(KeyEvent e){}<br />
public void keyReleased(KeyEvent e){}<br />
public void keyPressed(KeyEvent e) { … }
LookAt, LookAtView
Ziel:<br />
3D Objekte mit der Maus anklicken<br />
Problem:<br />
Vorgehen:<br />
Picking & Selection<br />
Verdeckungen (welches Objekt wurde angeklickt?)<br />
Umrechnen von Mauskoordinaten in Weltkoordinaten<br />
Bild intern neu zeichnen, allerdings nur einen ca. 4x4 Pixel<br />
Ausschnitt um die aktuelle Mausposition.<br />
Mitprotokollieren welches Objekt in welcher Tiefe gemalt wurde.<br />
Ergebnisliste (Objekte mit Tiefenin<strong>for</strong>mation) auswerten.<br />
Pic
Picking & Selection<br />
Ausschnitt um die aktuelle Mausposition (x,y) zeichnen.<br />
Dazu PickMatrix links an Projektionsmatrix multiplizieren<br />
// Projektionsmatrix neu berechnen<br />
gl.glLoadIdentity();<br />
glu.gluPickMatrix(x,height-y, 4, 4, viewport);<br />
glu.gluPerspective(60, 1.0,2.0,4.0);<br />
Liste initialisieren, in der die getroffenen Objekte gespeichert werden.<br />
Render Mode auf GL_SELECT setzen.<br />
int[] nameBuffer = new int[100];<br />
gl.glSelectBuffer(100,nameBuffer);<br />
gl.glRenderMode(GL_SELECT);<br />
gl.glInitNames();<br />
gl.glPushName(0);
Picking & Selection<br />
Bild intern neu zeichnen. Objekte durch Zahlen benennen, z.B.<br />
gl.glLoadName(42);<br />
gl.glRectf(-1.0,1.0,-1.0,1.0);<br />
Auf Render Mode GL_RENDER zurückschalten.<br />
int hits = gl.glRenderMode(GL_RENDER);<br />
Für jedes getroffene Objekt enthält nameBuffer nun vier Zahlen:<br />
1<br />
minimale und maximale Tiefe des getroffenen Ausschnitts<br />
Objektname, der während des Zeichnens mit glLoadName gesetzt wurde
Picking & Selection<br />
Projektionsmatrix muss danach wieder hergestellt werden!<br />
Angeklicktes Objekt ist dasjenige mit geringster Tiefe<br />
(nameBuffer durchsuchen!)<br />
Tiefenin<strong>for</strong>mation ist unsigned int. Gibt‘s in <strong>Java</strong> aber nicht!<br />
int<br />
2 30<br />
unsigned int
Picking & Selection<br />
Erde- Mond System erweitern so dass die Planeten<br />
angeklickt werden können.<br />
Angeklickter Planet soll stehen bleiben und sich beim<br />
nächsten Klick weiterbewegen.