package cg; //----------------------------------------------------------------------------------------------------// import static javax.swing.JFrame.EXIT_ON_CLOSE; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.JFrame; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.glu.GLU; import com.jogamp.opengl.util.FPSAnimator; //----------------------------------------------------------------------------------------------------// public class Main implements GLEventListener, KeyListener { final GLU glu = new GLU(); int frames = 1; // Spalte float delta = 0.1f; static float camera_position[] = {0.0f, 0.0f, -10.0f}; static float camera_orientation[] = {0.0f, 0.0f, 0.0f}; float speed = 0.2f; float angle_incr = 1.0f; public static void main(String[] args) { GLCanvas canvas = new GLCanvas(); canvas.addGLEventListener(new Main()); canvas.addKeyListener(new Main()); FPSAnimator animator = new FPSAnimator(canvas, 60); animator.start(); final int width = 800; final int height = 600; JFrame frame = new JFrame("OpenGL Fenster"); frame.setSize(width, height); frame.setDefaultCloseOperation(EXIT_ON_CLOSE); frame.getContentPane().add(canvas); frame.setVisible(true); canvas.setFocusable(true); canvas.requestFocus(); } //Erste Lichtquelle: light_0, Typ: Richtungslichtquelle, Variablen mit Anfangswerten ------------------------- float light0_ambient[] = {0.3f, 0.3f, 0.3f, 1.0f}; float light0_diffuse[] = {0.7f, 0.7f, 0.7f, 1.0f}; float light0_specular[] = {0.5f, 0.5f, 0.5f, 1.0f}; float light0_position[] = {-2.0f, 2.0f, 0.0f, 1.0f}; //Weitere (zweite) Lichtquelle: light_1, Typ: Scheinwerferlicht, Variablen mit Anfangswerten ---------------- // Der Typ wird nur durch die bestimmten Eigenschaften definiert - zB richtet man die Eigenschaft GL_SPOT_CUTOFF für diese Lichtquelle ein, wird die Lichtquelle bedeutungsmäßig zum Scheinwerfer (Spotlight)) float light1_ambient[] = {0f, 0f, 0.2f, 1.0f}; float light1_diffuse[] = {0.7f, 0.7f, 0.7f, 1.0f}; float light1_specular[] = {1f, 1f, 1f, 1.0f}; float light1_position[] = {0.0f, 0.5f, 0.5f, 1.0f}; float light1_direction[] = {0.0f, 0.25f, 0f}; float light1_cutoff = 15f; float light1_exponent = 10f; //----------------------------------------------------------------------------------------------------// public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { } //----------------------------------------------------------------------------------------------------// @Override public void dispose(GLAutoDrawable drawable) { } //----------------------------------------------------------------------------------------------------// @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { final GL2 gl = drawable.getGL().getGL2(); final float h = (float) width / (float) height; gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(45.0f, h, 1.0f, 100.0f); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); //glu.gluLookAt(0.f, 0.f, -10.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f); } //----------------------------------------------------------------------------------------------------// @Override public void init(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); // background color gl.glClearColor(0.1f, 0.3f, 0.8f, 1.0f); // enable z-buffer (default is off) gl.glEnable(GL2.GL_DEPTH_TEST); // Einschalten von Beleuchtung in der Szene (Basisbefehl, macht die Lichtquellen funktionsfähig) ------- gl.glEnable(GL2.GL_LIGHTING); // Ersteinrichtung von light_0 --------------------------------------------------------------------- // Erfolgt mit dem Befehl glLightfv mit 4 Parametern: // symbolischer Name (in der Form GL_LIGHT und der Indexzahl am Ende) der einzurichtenden Lichtquelle (mindestens 8 Lichtquellen werden unterstützt: GL_LIGHT0 ... GL_LIGHT7) // Eigenschaft der Lichtquelle // Wert der Eigenschaft (fest oder durch eine Variable) // Ablesungsstelle des Wertes (zB wenn der Wert durch ein Datenfeld (engl. array) gegeben wird, bestimmt die Anfangsstelle der Ablesung von Werten/Komponenten in diesem Vektor) /** * Zwecks besserer Verständlichkeit des Codes wird stark empfohlen, die Lichter, sowie auch all die leicht isolierbare CodeSchnipsel, in einer oder auch mehrerer Methoden einzurichten * (eventuell auch in einer anderer Klasse) an den benötigten Stellen einfach aufzurufen. */ //Ambienter Lichtanteil (Streulicht - zerstreutes ungerichtetes Licht) gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, light0_ambient, 0); //Diffuser Lichtanteil (zerstreutes gerichtetes Licht) gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, light0_diffuse, 0); //Spekularer (spiegelnder) Lichtanteil (um die Reflexionsrichtung wenig zerstreutes, gerichtetes Licht) gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, light0_specular, 0); //Position in der Szene (wird durch 4 Koordinaten (hier durch die Variable light0_position) im homogenen Koordinatensystem gegeben) gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, light0_position, 0); // Einschaltung von light_0 -------------------------------------------------------------------------------------------- gl.glEnable(GL2.GL_LIGHT0); // Ersteinrichtung von light_1 -------------------------------------------------------------------------------------------- gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, light1_ambient, 0); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_DIFFUSE, light1_diffuse, 0); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, light1_specular, 0); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, light1_position, 0); //setzt den maximalen Streuungswinkel der Lichtquelle gl.glLightf(GL2.GL_LIGHT1, GL2.GL_SPOT_CUTOFF, light1_cutoff); //Intensitätsverteilung innerhalb des Streuungswinkels - bestimmt wie fokusiert soll das Licht sein gl.glLightf(GL2.GL_LIGHT1, GL2.GL_SPOT_EXPONENT, light1_exponent); //Beleuchtungsrichtung der Lichtquelle gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPOT_DIRECTION, light1_direction, 0); /** * weitere setzbare Eigenschaften (es wird empfohlen, die Liste unter https://wiki.delphigl.com/index.php/glLight zu sehen) */ //Lichtabschwächungfaktoren (mit den unten folgenden Werten kommt keine Abschwächung): gl.glLightf(GL2.GL_LIGHT1, GL2.GL_CONSTANT_ATTENUATION, 1.0f); gl.glLightf(GL2.GL_LIGHT1, GL2.GL_LINEAR_ATTENUATION, 0f); gl.glLightf(GL2.GL_LIGHT1, GL2.GL_QUADRATIC_ATTENUATION, 0.0f); // Einschaltung von light_1 -------------------------------------------------------------------------------------------- gl.glEnable(GL2.GL_LIGHT1); // die Normalen werden nach Transformation(en) normalisiert (standardmäßig ist dies deaktiviert) -------------------------------------------- gl.glEnable(GL2.GL_NORMALIZE); } //----------------------------------------------------------------------------------------------------// @Override public void display(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); frames++; gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glRotatef(camera_orientation[2], 0.0f, 0.0f, 1.0f); gl.glRotatef(camera_orientation[0], 1.0f, 0.0f, 0.0f); gl.glRotatef(camera_orientation[1], 0.0f, 1.0f, 0.0f); gl.glTranslatef(camera_position[0], camera_position[1], camera_position[2]); // Variablen für die bestimmten Materialien /** * Die Materialsammlung mit zugehörigen RGBA-Werten sowie auch Glänzen/Härten (engl. shininess) ist unter https://wiki.delphigl.com/index.php/Materialsammlung zu finden */ // grüne Kunststoff float[] mat_amb_green_plastic = {0.0f, 0.0f, 0.0f, 1.0f}; float[] mat_diff_green_plastic = {0.1f, 0.35f, 0.1f, 1.0f}; float[] mat_spec_green_plastic = {0.45f, 0.55f, 0.45f, 1.0f}; float shininess_green_plastic = 32.0f; // Kupfer float[] mat_amb_copper = {0.19125f, 0.0735f, 0.0225f, 1.0f}; float[] mat_diff_copper = {0.7038f, 0.27048f, 0.0828f, 1.0f}; float[] mat_spec_copper = {0.256777f, 0.137622f, 0.086014f, 1.0f}; float shininess_copper = 12.8f; /* // Rubin float[] mat_amb_ruby = {0.1745f, 0.01175f, 0.01175f, 0.8f}; float[] mat_diff_ruby = {0.61424f, 0.04136f, 0.04136f, 0.8f}; float[] mat_spec_ruby = {0.727811f, 0.626959f, 0.626959f, 0.8f}; float shininess_ruby = 76.8f; */ // Boden gl.glPushMatrix(); gl.glTranslatef(0.0f, -1.0f, 0.0f); //setzt ambiente (GL_AMBIENT) Eigenschaften für die Vorderseite (GL_FRONT) der Fläche //die Variable mat_amb_green_plastic wird dabei ab der ersten Komponente (0) abgelesen gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, mat_amb_green_plastic, 0); //setzt diffuse (GL_DIFFUSE) Eigenschaften für die Vorderseite (GL_FRONT) der Fläche //die Variable mat_diff_green_plastic wird dabei ab der ersten Komponente (0) abgelesen gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, mat_diff_green_plastic, 0); //setzt spekulare (GL_SPECULAR) Eigenschaften für die Vorderseite (GL_FRONT) der Fläche //die Variable mat_spec_green_plastic wird dabei ab der ersten Komponente (0) abgelesen gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, mat_spec_green_plastic, 0); //setzt die Härte für die Vorderseite (GL_FRONT) der Fläche gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, shininess_green_plastic); /** * statt GL_FRONT, könnte der Wert GL_FRONT_AND_BACK eingesetzt werden, sodass die beiden Seiten * der Fläche mit den etsprechenden Eigenschaften versehen werden können. * * Wir werden das Thema über die Seitenerkennung, sowie auch einige Befehle (zB "backface culling") * separat im letzten Unterricht besprechen. */ drawGround(gl); gl.glPopMatrix(); // Würfel aus Kupfer gl.glPushMatrix(); gl.glTranslatef(0.0f, 0.0f, 0.0f); gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, mat_amb_copper, 0); gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, mat_diff_copper, 0); gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, mat_spec_copper, 0); gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, shininess_copper); drawCube(gl); gl.glPopMatrix(); /* // Würfel aus Rubin * //hier wird Blending zusätzlich benötigt, da Rubin durchsichtig ist gl.glEnable(GL.GL_BLEND); // Beschreibt die Funktionen von Blending // Transparenz wird am besten mit den Parametern (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) umgesetzt gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, mat_amb_ruby, 0); gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mat_diff_ruby, 0); gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_spec_ruby, 0); gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, shininess_ruby); gl.glPushMatrix(); drawCube(gl); gl.glPopMatrix(); gl.glDisable(GL.GL_BLEND); */ } //----------------------------------------------------------------------------------------------------// // draw the ground void drawGround(GL2 gl) { gl.glBegin(GL2.GL_QUADS); //gl.glColor3f(0.0f, 0.0f, 0.0f); // black //setzt die aktuelle Normale (standardmäßig ist der Vektor (0,0,1) gegeben) entlang der positiven Richtung von Y-Achse /** * Bei der Nutzung von Normalen (absolut nötig für die korrekte Berechnung von Beleuchtung in der Szene) ist * zu beachten, dass sie sich nach den Transformationen (zB Rotation oder nicht homogene Skalierung) ändern * (sowohl in Länge als auch in Richtung) - genauer zu sagen, die werden mit der Inverse von der transponierten Modelview-Matrix multipliziert. * Deswegen sollte bei der Verwendung von Normalen die Reihenfolge von Transformationen sowie auch von glNormal3f Befehlen berücksichtigt werden. * */ // Alternativ könnte dieser Befehl innerhalb der Display-Methode, vor dem aufgerufenen drawGround(gl) iniziiert werden gl.glNormal3f(0f, 1f, 0f); gl.glVertex3f(-5.0f, 0.0f-delta, 5.0f); gl.glVertex3f( 5.0f, 0.0f-delta, 5.0f); gl.glVertex3f( 5.0f, 0.0f-delta,-5.0f); gl.glVertex3f(-5.0f, 0.0f-delta,-5.0f); gl.glEnd(); } //----------------------------------------------------------------------------------------------------// // draw the cube void drawCube(GL2 gl) { gl.glBegin( GL2.GL_QUADS ); // bei eingeschalteter Beleuchtung und Verwendung von glMaterial Befehlen, wird die Farbe allein durch die eingesetzten Eigenschaften von Lichtquellen sowie auch von den Materialeigenschaften bestimmt //gl.glColor3f( 1f,0f,0f ); //red color gl.glNormal3f(0.0f, 1.0f, 0.0f); gl.glVertex3f( 1.0f, 1.0f, -1.0f ); // Top Right Of The Quad (Top) gl.glVertex3f( -1.0f, 1.0f, -1.0f); // Top Left Of The Quad (Top) gl.glVertex3f( -1.0f, 1.0f, 1.0f ); // Bottom Left Of The Quad (Top) gl.glVertex3f( 1.0f, 1.0f, 1.0f ); // Bottom Right Of The Quad (Top) //gl.glColor3f( 0f,1f,0f ); //green color gl.glNormal3f(0.0f, -1.0f, 0.0f); gl.glVertex3f( 1.0f, -1.0f, 1.0f ); // Top Right Of The Quad (Bottom) gl.glVertex3f( -1.0f, -1.0f, 1.0f ); // Top Left Of The Quad (Bottom) gl.glVertex3f( -1.0f, -1.0f, -1.0f ); // Bottom Left Of The Quad (Bottom) gl.glVertex3f( 1.0f, -1.0f, -1.0f ); // Bottom Right Of The Quad (Bottom) //gl.glColor3f( 0f,0f,1f ); //blue color gl.glNormal3f(0.0f, 0.0f, 1.0f); gl.glVertex3f( 1.0f, 1.0f, 1.0f ); // Top Right Of The Quad (Front) gl.glVertex3f( -1.0f, 1.0f, 1.0f ); // Top Left Of The Quad (Front) gl.glVertex3f( -1.0f, -1.0f, 1.0f ); // Bottom Left Of The Quad (Front) gl.glVertex3f( 1.0f, -1.0f, 1.0f ); // Bottom Right Of The Quad (Front) //gl.glColor3f( 1f,1f,0f ); //yellow (red + green) gl.glNormal3f(0.0f, 0.0f, -1.0f); gl.glVertex3f( 1.0f, -1.0f, -1.0f ); // Bottom Left Of The Quad (Back) gl.glVertex3f( -1.0f, -1.0f, -1.0f ); // Bottom Right Of The Quad (Back) gl.glVertex3f( -1.0f, 1.0f, -1.0f ); // Top Right Of The Quad (Back) gl.glVertex3f( 1.0f, 1.0f, -1.0f ); // Top Left Of The Quad (Back) //gl.glColor3f( 1f,0f,1f ); //purple (red + green) gl.glNormal3f( -1.0f, 0.0f, 0.0f); gl.glVertex3f( -1.0f, 1.0f, 1.0f ); // Top Right Of The Quad (Left) gl.glVertex3f( -1.0f, 1.0f, -1.0f ); // Top Left Of The Quad (Left) gl.glVertex3f( -1.0f, -1.0f, -1.0f ); // Bottom Left Of The Quad (Left) gl.glVertex3f( -1.0f, -1.0f, 1.0f ); // Bottom Right Of The Quad (Left) //gl.glColor3f( 0f,1f, 1f ); //sky blue (blue + green) gl.glNormal3f( 1.0f, 0.0f, 0.0f); gl.glVertex3f( 1.0f, 1.0f, -1.0f ); // Top Right Of The Quad (Right) gl.glVertex3f( 1.0f, 1.0f, 1.0f ); // Top Left Of The Quad (Right) gl.glVertex3f( 1.0f, -1.0f, 1.0f ); // Bottom Left Of The Quad (Right) gl.glVertex3f( 1.0f, -1.0f, -1.0f ); // Bottom Right Of The Quad (Right) gl.glEnd(); } //----------------------------------------------------------------------------------------------------// @Override public void keyTyped(KeyEvent e) { int keyCo = e.getKeyCode(); if (keyCo == KeyEvent.VK_A) { System.out.println("typed " + e.getKeyChar() + " button"); } //----------------------------------------------------------------------------------------------------// } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); // move forward if (keyCode == KeyEvent.VK_UP) { camera_position[2]+=speed; } // move backward if (keyCode == KeyEvent.VK_DOWN) { camera_position[2]-=speed; } // move left else if (keyCode == KeyEvent.VK_LEFT) { camera_position[0]+=speed; } // move right else if (keyCode == KeyEvent.VK_RIGHT) { camera_position[0]-=speed; } // move up else if (keyCode == KeyEvent.VK_PAGE_UP) { camera_position[1]-=speed; } // move down else if (keyCode == KeyEvent.VK_PAGE_DOWN) { camera_position[1]+=speed; } // turn left else if (keyCode == KeyEvent.VK_A) { camera_orientation[1] -= angle_incr; if (camera_orientation[1] < -360.0f) camera_orientation[1] += 360.0f; } // turn right else if (keyCode == KeyEvent.VK_D) { camera_orientation[1] += angle_incr; if (camera_orientation[1] > 360.0f) camera_orientation[1] -= 360.0f; } // turn up else if (keyCode == KeyEvent.VK_W) { camera_orientation[0] -= angle_incr; if (camera_orientation[0] < -360.0f) camera_orientation[0] += 360.0f; } // turn down else if (keyCode == KeyEvent.VK_S) { camera_orientation[0] += angle_incr; if (camera_orientation[0] > 360.0f) camera_orientation[0] -= 360.0f; } // reset the camera position and orientation else if (keyCode == KeyEvent.VK_C) { camera_position[0] = 0.0f; camera_position[1] = 0.0f; camera_position[2] = -10.0f; camera_orientation[0] = 0.0f; camera_orientation[1] = 0.0f; camera_orientation[2] = 0.0f; } } //----------------------------------------------------------------------------------------------------// @Override public void keyReleased(KeyEvent e) { int keyCode = e.getKeyCode(); // move backward if (keyCode == KeyEvent.VK_DOWN) { System.out.println("released " + e.getExtendedKeyCode() + " button"); } } //----------------------------------------------------------------------------------------------------// }