OpenGL har i prinsipp ikke noe apparat for å handtere geometriske figurer.
Noen slike finnes i glu-biblioteket (quadricene),
men vi må være forberedte på selv å lage funksjoner som tegner ut ulike romfigurer.
En kloss er nyttig å ha, så vi lager en klossfunksjon.
Du kan betrakte dette som en nyttig øvelse i å konstruere uttegningsrutiner.
Utgangspunktet er følgende figur som viser en kloss i utbrettet tilstand
Vi må tegne ut de 6 flatene F1..F6.
Vi må passe på at vi holder styr på hva som er forsiden ( front ) og hva som er baksiden (back) på flatene.
OpenGL skiller mellom dette og vi kan blant annet tildele ulike materialegenskaper til forsiden og baksiden.
I dette tilfellet skal vi tegne en lukket boks, og konsentrerer oss om utsiden.
Vi må være systematiske under uttegningen og vi bestemmer oss for at vi vil
tegne hver flate slik at vi angir punktene med klokka, når vi betrakter flaten utenfra.
Da er flatene beskrevet slik:
F1: |
adcb |
F4: |
fcde |
F2. |
abgh |
F5: |
ahed |
F3: |
gfeh |
F6: |
bcfg |
Vi må bestemme oss for hvordan vi skal forholde oss til klossens størrelse.
Vi kan enten la klossens dimensjoner og plassering inngå som parametrre til en kloss-funksjon.
I så fall vil det kanskje være naturlig å velge et punkt, og utstrekningen i x-, y- og z-retningen som parametre.
Dette vil gjøre rotasjon vanskelig.
Vi velger den siste strategien og bestemmer oss for å legge origo i a, x-aksen langs ab, y-aksen langs ah og z-aksen langs ad.
Punktkoordinatene blir:
a: |
0,0,0 |
e: |
1,0,1 |
b: |
0,1,0 |
f: |
1,1,1 |
c: |
0,1,1 |
g: |
1,1,0 |
d: |
0,0,1 |
h: |
1,0,0 |
Vi pakker uttegningen inn i enklasse så vi kan gjenbruke den enkelt:
public class oneBox
{
static void drawMe(GL gl)
{
/* draws the sides of a unit cube (0,0,0)-(1,1,1) */
gl.glBegin(GL.GL_POLYGON);/* f1: front */
gl.glNormal3f(-1.0f,0.0f,0.0f);
gl.glVertex3f(0.0f,0.0f,0.0f);
gl.glVertex3f(0.0f,0.0f,1.0f);
gl.glVertex3f(1.0f,0.0f,1.0f);
gl.glVertex3f(1.0f,0.0f,0.0f);
gl.glEnd();
gl.glBegin(GL.GL_POLYGON);/* f2: bottom */
gl.glNormal3f(0.0f,0.0f,-1.0f);
gl.glVertex3f(0.0f,0.0f,0.0f);
gl.glVertex3f(1.0f,0.0f,0.0f);
gl.glVertex3f(1.0f,1.0f,0.0f);
gl.glVertex3f(0.0f,1.0f,0.0f);
gl.glEnd();
gl.glBegin(GL.GL_POLYGON);/* f3:back */
gl.glNormal3f(1.0f,0.0f,0.0f);
gl.glVertex3f(1.0f,1.0f,0.0f);
gl.glVertex3f(1.0f,1.0f,1.0f);
gl.glVertex3f(0.0f,1.0f,1.0f);
gl.glVertex3f(0.0f,1.0f,0.0f);
gl.glEnd();
gl.glBegin(GL.GL_POLYGON);/* f4: top */
gl.glNormal3f(0.0f,0.0f,1.0f);
gl.glVertex3f(1.0f,1.0f,1.0f);
gl.glVertex3f(1.0f,0.0f,1.0f);
gl.glVertex3f(0.0f,0.0f,1.0f);
gl.glVertex3f(0.0f,1.0f,1.0f);
gl.glEnd();
gl.glBegin(GL.GL_POLYGON);/* f5: left */
gl.glNormal3f(0.0f,1.0f,0.0f);
gl.glVertex3f(0.0f,0.0f,0.0f);
gl.glVertex3f(0.0f,1.0f,0.0f);
gl.glVertex3f(0.0f,1.0f,1.0f);
gl.glVertex3f(0.0f,0.0f,1.0f);
gl.glEnd();
gl.glBegin(GL.GL_POLYGON);/* f6: right */
gl.glNormal3f(0.0f,-1.0f,0.0f);
gl.glVertex3f(1.0f,0.0f,0.0f);
gl.glVertex3f(1.0f,0.0f,1.0f);
gl.glVertex3f(1.0f,1.0f,1.0f);
gl.glVertex3f(1.0f,1.0f,0.0f);
gl.glEnd();
}
}
Minimal version
Vi lager et minimalt program uten interaksjon.
Urtgangspunktet er NetBeans javaproject: JOGL Application.
Den komplette koden i den eneste kodefila (foruten oneBox) er:
package box1;
import com.sun.opengl.util.Animator;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
/**
* Box1.java
* author: BS
*
*/
public class Box1 implements GLEventListener
{
public static void main(String[] args)
{
Frame frame = new Frame("Showing a box");
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(new Box1());
frame.add(canvas);
frame.setSize(640, 480);
final Animator animator = new Animator(canvas);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// Run this on another thread than the AWT event queue to
// make sure the call to Animator.stop() completes before
// exiting
new Thread(new Runnable() {
public void run() {
animator.stop();
System.exit(0);
}
}).start();
}
});
// Center frame
frame.setLocationRelativeTo(null);
frame.setVisible(true);
animator.start();
}
public void init(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
// Set backgroundcolor and shading mode
gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gl.glShadeModel(GL.GL_FLAT);
// give me some light
float ambient[] = {1.0f,1.0f,1.0f,1.0f };
float diffuse[] = {1.0f,1.0f,1.0f,1.0f };
float specular[]= {0.2f,1.0f,0.2f,1.0f};
float position[] = {20.0f,30.0f,20.0f,0.0f };
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT,ambient,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position,0);
// and some green material
float amb[]={0.3f,0.9f,0.3f,1.0f};
float diff[]={0.3f,1.0f,0.3f,1.0f};
gl.glMaterialfv(GL.GL_FRONT,GL.GL_AMBIENT,amb,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_DIFFUSE,diff,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_SPECULAR, specular, 0);
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_LIGHT0);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glEnable(GL.GL_NORMALIZE);
}
public void reshape(GLAutoDrawable drawable,
int x, int y, int width, int height)
{
GL gl = drawable.getGL();
GLU glu = new GLU();
if (height <= 0) // no divide by zero
height = 1;
// keep ratio
final float h = (float) width / (float) height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0f, h, 1.0, 20.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void display(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
GLU glu = new GLU(); // needed for lookat
// Clear the drawing area
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Reset the current matrix to the "identity"
gl.glLoadIdentity();
glu.gluLookAt(4,4,4, // eye pos
0,0,0, // look at
0,0,1); // up
gl.glRotatef(50.0f, 0.0f, 0.0f, 1.0f);
gl.glRotatef(40.0f, 1.0f, 0.0f, 0.0f);
oneBox.drawMe(gl);
gl.glFlush();
}
public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged, boolean deviceChanged)
{ }
}
Bruk av mus
Vi introduserer interaksjon ved å peke og dra med
musa på tegningen
Vi bruker det samme utgangspunktet med legger til MouseListener og MouseMotionListener.
Den komplette koden i den eneste kodefila (foruten oneBox) er:
package box2;
import com.sun.opengl.util.Animator;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
/**
* Box2.java
* author: BS
*
*/
public class Box2 implements GLEventListener,
MouseListener,
MouseMotionListener
{
public static void main(String[] args) {
Frame frame = new Frame("Simple JOGL Application");
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(new Box2());
frame.add(canvas);
frame.setSize(640, 480);
final Animator animator = new Animator(canvas);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// Run this on another thread than the AWT event queue to
// make sure the call to Animator.stop() completes before
// exiting
new Thread(new Runnable() {
public void run() {
animator.stop();
System.exit(0);
}
}).start();
}
});
// Center frame
frame.setLocationRelativeTo(null);
frame.setVisible(true);
animator.start();
}
// rotating the scene
private float view_rotx = 20.0f;
private float view_roty = 30.0f;
// remember last mouse position
private int oldMouseX;
private int oldMouseY;
public void init(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
// Set backgroundcolor and shading mode
gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gl.glShadeModel(GL.GL_FLAT);
// give me some light
float ambient[] = {1.0f,1.0f,1.0f,1.0f };
float diffuse[] = {1.0f,1.0f,1.0f,1.0f };
float specular[]= {0.2f,1.0f,0.2f,1.0f};
float position[] = {20.0f,30.0f,20.0f,0.0f };
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT,ambient,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_SPECULAR, specular, 0);
// and some red material
float[] mambient ={ 0.1745f, 0.01175f, 0.01175f, 0.55f };
float[] mdiffuse ={0.61424f, 0.04136f, 0.04136f, 0.55f };
float[] mspecular ={0.727811f, 0.626959f, 0.626959f, 0.55f };
float mshine =76.8f ;
gl.glMaterialfv(GL.GL_FRONT,GL.GL_AMBIENT,mambient,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_DIFFUSE,mdiffuse,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_SPECULAR,mspecular, 0);
gl.glMaterialf (GL.GL_FRONT,GL.GL_SHININESS,mshine);
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_LIGHT0);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glEnable(GL.GL_NORMALIZE);
drawable.addMouseListener(this);
drawable.addMouseMotionListener(this);
}
public void reshape(GLAutoDrawable drawable,
int x, int y, int width, int height)
{
GL gl = drawable.getGL();
GLU glu = new GLU();
if (height <= 0) // no divide by zero
height = 1;
// keep ratio
final float h = (float) width / (float) height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0f, h, 1.0, 20.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void display(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
GLU glu = new GLU(); // needed for lookat
// Clear the drawing area
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Reset the current matrix to the "identity"
gl.glLoadIdentity();
glu.gluLookAt(4,4,4, // eye pos
0,0,0, // look at
0,0,1); // up
gl.glTranslatef(0.5f, 0.5f, 0.5f);
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(-0.5f, -0.5f, -0.5f);
oneBox.drawMe(gl);
gl.glFlush();
}
public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged, boolean deviceChanged)
{ }
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) { }
public void mousePressed(MouseEvent e) {
oldMouseX = e.getX();
oldMouseY = e.getY();
}
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
Dimension size = e.getComponent().getSize();
float thetaY = 360.0f * ( (float)(x-oldMouseX)/(float)size.width);
float thetaX = 360.0f * ( (float)(oldMouseY-y)/(float)size.height);
oldMouseX = x;
oldMouseY = y;
view_rotx += thetaX;
view_roty += thetaY;
}
public void mouseMoved(MouseEvent e) {}
}
Bruk av dialogelementer
Vi introdusrere interaksjon via GUI-elementer, slidere, i vinduet.
Dette prosjektet er bygd med utgangspunkt i NetBeans javaproject: JOGL Application (Form Designer, GL_JPanel)
Delere av hovedklassen:
public class Box3 extends JFrame {
private Animator animator;
GLRenderer glr;
/** Creates new form MainFrame */
public Box3() {
initComponents();
setTitle("Simple JOGL Application");
glr=new GLRenderer();
panel.addGLEventListener(glr);
animator = new Animator(panel);
animator.start();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// Run this on another thread than the AWT event queue to
// make sure the call to Animator.stop() completes before
// exiting
new Thread(new Runnable() {
public void run() {
animator.stop();
System.exit(0);
}
}).start();
}
});
}
@Override
public void setVisible(boolean show){
if(!show)
animator.stop();
super.setVisible(show);
if(!show)
animator.start();
}
Den komplette koden i GLrenderer:
package box3;
import com.sun.opengl.util.GLUT;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
/**
* GLRenderer.java
* author: bs
*/
public class GLRenderer implements GLEventListener {
private float view_rotx=0;
private float view_roty=0;
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
// Set backgroundcolor and shading mode
gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gl.glShadeModel(GL.GL_FLAT);
// give me some light
float ambient[] = {1.0f,1.0f,1.0f,1.0f };
float diffuse[] = {1.0f,1.0f,1.0f,1.0f };
float specular[]= {0.2f,1.0f,0.2f,1.0f};
float position[] = {20.0f,30.0f,20.0f,0.0f };
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT,ambient,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_SPECULAR, specular, 0);
// and some red material
float[] mambient ={ 0.1745f, 0.01175f, 0.01175f, 0.55f };
float[] mdiffuse ={0.61424f, 0.04136f, 0.04136f, 0.55f };
float[] mspecular ={0.727811f, 0.626959f, 0.626959f, 0.55f };
float mshine =76.8f ;
gl.glMaterialfv(GL.GL_FRONT,GL.GL_AMBIENT,mambient,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_DIFFUSE,mdiffuse,0);
gl.glMaterialfv(GL.GL_FRONT,GL.GL_SPECULAR,mspecular, 0);
gl.glMaterialf (GL.GL_FRONT,GL.GL_SHININESS,mshine);
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_LIGHT0);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glEnable(GL.GL_NORMALIZE);
gl.setSwapInterval(1);
}
public void reshape(GLAutoDrawable drawable,
int x, int y, int width, int height)
{
GL gl = drawable.getGL();
GLU glu = new GLU();
if (height <= 0) // no divide by zero
height = 1;
// keep ratio
final float h = (float) width / (float) height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0f, h, 1.0, 20.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
GLU glu = new GLU(); // needed for lookat
// Clear the drawing area
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Reset the current matrix to the "identity"
gl.glLoadIdentity();
glu.gluLookAt(3,3,3, // eye pos
0,0,0, // look at
0,0,1); // up
gl.glTranslatef(0.5f, 0.5f, 0.5f);
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(-0.5f, -0.5f, -0.5f);
oneBox.drawMe(gl);
// draw ateapot
/*
GLUT glut=new GLUT();
glut.glutSolidTeapot(1.0);
*/
gl.glFlush();
}
public void displayChanged(GLAutoDrawable drawable,
boolean modeChanged, boolean deviceChanged)
{
}
public void setRotation(float xrot, float yrot)
{
view_rotx=xrot;
view_roty=yrot;
}
}