Im trying to make a Java screensaver of a 3D rotating Lorenz Attractor Im using java and jogl (OPENGL) to render the graphics... i have 2 classes one is the main program setup OPENGL etc... and another that just stores a LinkedList of Point3d's That are the vertex of the line.. Only one new point is added to the List every frame render.....
The problem i am having is render speed is very slow, my question is this... 1. Is there a Better / Easy way of buffering either the screen or the line strip so i only need to draw the last line.... 2. Can VBO's be used for LINE_STRIP's and if i have to add one vertex to the buffer every step is this really going to speed things up...?
Its really quite annoying... glBegin()/ glEnd() works fine up to about 100 lines then crashes badly. Help much needed to speed up render and would be greatly apreaciated.....
Ive added the working code below to get it to work you have to link to JOGL opengl lib's
CODE
LorenzSim.java
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import javax.media.opengl.glu.GLU;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.vecmath.Point3d;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.*;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.util.gl2.GLUT;
import java.util.*;
import java.awt.event.*;
import sun.misc.*;
public class LorenzSim implements GLEventListener, KeyListener {
private static final int MIN_X = -20;
private static final int MAX_X = 20;
private static final int MIN_Y = -20;
private static final int MAX_Y = 20;
private static final double MIN_Z = 0;
private static final double MAX_Z = 40;
/**
* @param args
*/
// GLOBAL PARTS
boolean started = false;
int index = 0; // ANIMATOR COUNTER
String consoleLine = "";
// GENERAL OPEN GL
GLProfile glp = null;
GLCapabilities caps = null;
GLCanvas canvas = null;
GraphicsEnvironment ge = null;
GraphicsDevice gd = null;
Frame frame = null;
// GL _ CAM
double camX = 30;
double camY = 30;
double camZ = 50;
Lorenz myLorenz = null;
public LorenzSim ()
{
// GENERAL OPEN GL AND AWT SETUP
glp = GLProfile.getDefault();
caps = new GLCapabilities(glp);
canvas = new GLCanvas(caps);
ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
gd = ge.getDefaultScreenDevice();
frame = new Frame("QuadSim");
frame.setSize(600,600);
//frame.setUndecorated(true);
//gd.setFullScreenWindow(frame);
frame.setVisible(true);
canvas.setSize(frame.getWidth(),frame.getHeight());
frame.add(canvas);
// SETUP EVENT LISTENERS
canvas.addGLEventListener(this);
canvas.addKeyListener(this);
frame.addWindowListener(new WindowAdapter() {
public voi开发者_开发技巧d windowClosing(WindowEvent e) {
frame.dispose();
System.exit(0);
}
});
started = true;
FPSAnimator animator = new FPSAnimator(canvas, 60);
animator.add(canvas);
animator.start();
caps.setDoubleBuffered(true);
myLorenz = new Lorenz();
myLorenz.doSteps(0);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Welcome to Quad Simulator v0.1 - by Phil Poore");
LorenzSim mySim = new LorenzSim();
}
//############################################
// GL EVENT INTERFACE
//############################################
@Override
public void display(GLAutoDrawable drawable) {
// TODO Auto-generated method stub
if (started)
{
update();
render(drawable);
//System.out.println("Drisplay_index:"+index);
}
}
private void update() {
// TODO Auto-generated method stub
index++;
myLorenz.step();
}
private void render(GLAutoDrawable drawable) {
// TODO Auto-generated method stub
GL2 gl = drawable.getGL().getGL2();
GLU glu = new GLU();
drawable.swapBuffers();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// START OF RENDER CYCLE
setCamera(gl,glu);
drawAxis(gl);
drawBox(gl);
drawLorenz(gl);
drawHUD(gl);
}
private void drawLorenz(GL2 gl) {
// TODO Auto-generated method stub
gl.glBegin(GL.GL_LINE_STRIP);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glLineWidth(0.1f);
for (int i = 0; i < myLorenz.myPoints.size() - 1; i++)
{
//float dx = (float) (myLorenz.myPoints.get(i).x - myLorenz.myPoints.get(i+1).x);
//float dy = (float) (myLorenz.myPoints.get(i).y - myLorenz.myPoints.get(i+1).y);
//float dz = (float) (myLorenz.myPoints.get(i).z - myLorenz.myPoints.get(i+1).z);
//float dc = (Math.abs(dx) + Math.abs(dy) + Math.abs(dz))/3.0f;
//gl.glColor3d(dc,dc,dc);
gl.glVertex3d(
myLorenz.myPoints.get(i).x,
myLorenz.myPoints.get(i).y,
myLorenz.myPoints.get(i).z);
}
gl.glEnd();
}
private void drawBox(GL2 gl) {
// TODO Auto-generated method stub
Point3d a = new Point3d(MIN_X,MIN_Y,MIN_Z);
Point3d b = new Point3d(MAX_X,MIN_Y,MIN_Z);
Point3d c = new Point3d(MAX_X,MAX_Y,MIN_Z);
Point3d d = new Point3d(MIN_X,MAX_Y,MIN_Z);
Point3d aa = new Point3d(MIN_X,MIN_Y,MAX_Z);
Point3d ab = new Point3d(MAX_X,MIN_Y,MAX_Z);
Point3d ac = new Point3d(MAX_X,MAX_Y,MAX_Z);
Point3d ad = new Point3d(MIN_X,MAX_Y,MAX_Z);
gl.glBegin(GL.GL_LINE_STRIP);
gl.glVertex3d(a.x, a.y, a.z);
gl.glVertex3d(b.x, b.y, b.z);
gl.glVertex3d(c.x, c.y, c.z);
gl.glVertex3d(d.x, d.y, d.z);
gl.glVertex3d(a.x, a.y, a.z);
gl.glEnd();
gl.glBegin(GL.GL_LINE_STRIP);
gl.glVertex3d(aa.x, aa.y, aa.z);
gl.glVertex3d(ab.x, ab.y, ab.z);
gl.glVertex3d(ac.x, ac.y, ac.z);
gl.glVertex3d(ad.x, ad.y, ad.z);
gl.glVertex3d(aa.x, aa.y, aa.z);
gl.glEnd();
gl.glBegin(GL.GL_LINES);
gl.glVertex3d(a.x, a.y, a.z);
gl.glVertex3d(aa.x, aa.y, aa.z);
gl.glVertex3d(b.x, b.y, b.z);
gl.glVertex3d(ab.x, ab.y, ab.z);
gl.glVertex3d(c.x, c.y, c.z);
gl.glVertex3d(ac.x, ac.y, ac.z);
gl.glVertex3d(d.x, d.y, d.z);
gl.glVertex3d(ad.x, ad.y, ad.z);
gl.glEnd();
}
private void drawHUD(GL2 gl) {
// TODO Auto-generated method stub
gl.glRasterPos2d(10,10);
gl.glWindowPos2d(10, 10);
gl.glColor3d(0.8, 0.8, 0.8);
GLUT glut = new GLUT();
//DecimalFormat df = new DecimalFormat("#.##");
glut.glutBitmapString(GLUT.BITMAP_8_BY_13,
":");
}
@Override
public void dispose(GLAutoDrawable arg0) {
// TODO Auto-generated method stub
}
@Override
public void init(GLAutoDrawable drawable) {
// TODO Auto-generated method stub
GL2 gl = drawable.getGL().getGL2();
//gl.glOrtho(0,100,-5,25,0,100);
gl.glEnable( GL.GL_LINE_SMOOTH );
gl.glHint( GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST );
}
@Override
public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3,
int arg4) {
// TODO Auto-generated method stub
}
private void drawAxis(GL2 gl) {
gl.glLineWidth((float) 1.0);
gl.glBegin(GL.GL_LINES);
// X
gl.glColor3f(1, 0, 0);
gl.glVertex3d(0,0,0);
gl.glVertex3d(1,0,0);
// Y
gl.glColor3f(0, 1, 0);
gl.glVertex3d(0,0,0);
gl.glVertex3d(0,1,0);
// Z
gl.glColor3f(0, 0, 1);
gl.glVertex3d(0,0,0);
gl.glVertex3d(0,0,1);
gl.glEnd();
}
private void setCamera(GL2 gl,GLU glu)
{
gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(120, 1.0, 5, 100);
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt(camX, camY, camZ,
0.0,0.0 ,0.0 ,
0.0,0.0, 1.0);
gl.glRotated(0.0+index, 0, 0, 1);
// gl.glTranslated(MAX_X-MIN_X, MAX_Y-MIN_Y, MAX_Z-MIN_Z);
}
//############################################
// KEY LISTENER INTERFACE
//############################################
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == 27)
System.exit(0);
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Lorenz.java
import javax.vecmath.*;
import java.awt.geom.; import java.util.;
public class Lorenz {
public static final double rho = 28.0;
public static final double sigma = 10.0;
public static final double beta = 8.0/3.0;
private static final double step = 200.0;
public LinkedList<Point3d> myPoints = null;
public Lorenz ()
{
myPoints = new LinkedList<Point3d>();
Point3d first = new Point3d(0.1,0.1,0.1);
myPoints.add(first);
}
public void step()
{
System.out.println("stepping..."+myPoints.size());
Point3d last = myPoints.get(myPoints.size()-1);
double dx = (sigma * (last.y - last.x))/step;
double dy = ((last.x*(rho-last.z))-last.y)/step;
double dz = ((last.x*last.y - beta*last.z))/step;
Point3d next = new Point3d(last.x+dx,last.y+dy,last.z+dz);
myPoints.add(next);
}
public void doSteps(int count)
{
for (int i = 0; i < count; i++)
{
step();
}
}
public void dump()
{
System.out.println(myPoints.toString());
}
}
Phil
Try creating multiple VBOs for your set of lines. That way you only have to update a smaller number of vertices for each new line and the bulk of your geometry is already (probably) in video memory.
this may sound funny but try to remove the System.out.println() in the step() method. Printing to console is fairly slow/unpredictable in java so don't do this every frame.
to answer your question: 2) VBOs are fast for large(er) datasets and best used with rarely or partly updating data. They can represent any primitive you like, triangles, line strips etc. Adding one vertex every frame is not a good idea since they are allocated statically. You can still use them by predicting the maximum amount of vertices you would like to render and simply allocate this buffer a-priory.
if you decide to use VBOs you will have to make this changes: - allocate a VBO which will determine the max amount of vertices of the graph - upload only the new vertices per frame - stop at max or think about a ringbuffer, but you will probably need an additional buffer used as indexbuffer to implement this
tipp: use JOGL's debug pipeline, it will try to throw an exception as soon as OpenGL sets an error code. This will may help to fix the crash issue you mentioned. http://michael-bien.com/mbien/entry/jogl_2_composeable_pipline
精彩评论