From: Kenneth B. R. <kbr...@al...> - 2001-12-01 04:12:16
|
> I am having problems getting GL4Java to perform quite as well as I = > expected it to. I created a small demo with a triangle that you can fly = > around the screen. It's just a single non-textured, non-lit polygon. = > But I can't seem to get a FPS higher than 83 or so on my Athlon 1.4 = > Geforce3 system (at 85Hz refresh and with VSYNC on). Also, every so = > often it'll just skip for a second, and the ship will appear somewhere = > else. If I turn VSYNC off the skipping is MUCH worse, but I get around = > 99.4 fps. On my friends' computer running Win98, it runs so crappily = > you can barely tell where the ship is at any given point. I think there are three problems. The first is that the system clock is being sampled each frame. On Windows the granularity of the system clock (as measured by the system call behind currentTimeMillis()) is 10 ms. You can decrease this to 1 ms by writing native code to use the multimedia timers, but a better and more portable strategy is to sample the clock only once every several frames. The second problem is that System.out.println is being called each frame. The Windows console is extremely slow and in a 3D application println should absolutely not be called each frame. The third problem is that in order to reach an FPS higher than the vertical scan rate (even though all of those rendered frames won't actually be displayed) it is necessary to have triple buffering enabled. It looks like in certain screen modes the driver automatically takes care of enabling triple buffering, but that there isn't any way to request that a given window be triple-buffered. Please email the mailing list if you know more about this. Even the fullscreen support in JDK 1.4 doesn't seem to enable whatever mode switch the driver is looking for. Incidentally, the fullscreen support in the Sun JDK is likely to only work properly with OpenGL on Windows when specifying -Dsun.java2d.noddraw=true on the command line. Attached is a version of your test which runs at the maximum framerate on my monitor when vertical sync is enabled, and which claims to be running at between 900-1000 FPS when it is disabled. import gl4java.*; import gl4java.awt.*; import gl4java.drawable.*; import java.awt.*; import java.util.*; import java.awt.event.*; import java.awt.image.*; import javax.swing.*; import java.net.*; public class GL4JavaTest implements GLEventListener, MouseListener, KeyListener { private static class MovingTriangle { // physics private double x; private double y; private double rotation; private double vx; private double vy; // display private static float[][][] mesh; private static int displayList = -1; // input private boolean bRotRight = false; private boolean bRotLeft = false; private boolean bAccel = false; private boolean bReverse = false; // default non-static parameters private double rotRate; private double accelRate; private double maxRate; // default static initialization static { float[][][] newMesh = { { { 3.0f, 0.0f, 0.0f }, { -2.598f, 1.5f, 0.0f }, { -2.598f,-1.5f, 0.0f } } }; mesh = newMesh; } // default non-static initialization { rotRate = 270.0; accelRate = 80.0; maxRate = 35.0; } public MovingTriangle() { this(0.0, 0.0, 0.0, 0.0, 90.0); } public MovingTriangle(double locX, double locY, double velX, double velY, double rot) { x = locX; y = locY; vx = velX; vy = velY; rotation = rot; } private void createDisplayList(GLAnimCanvas glc) { displayList = glc.gl.glGenLists(1); glc.gl.glNewList(displayList, GL_COMPILE); glc.gl.glBegin(GL_TRIANGLES); for (int i = 0; i < mesh.length; i++) { glc.gl.glVertex3f(mesh[i][0][0], mesh[i][0][1], mesh[i][0][2]); glc.gl.glVertex3f(mesh[i][1][0], mesh[i][1][1], mesh[i][1][2]); glc.gl.glVertex3f(mesh[i][2][0], mesh[i][2][1], mesh[i][2][2]); } glc.gl.glEnd(); glc.gl.glEndList(); } public void tick(double deltaTime) { x += vx * deltaTime; y += vy * deltaTime; if (bRotRight) addRotation(-rotRate * deltaTime); else if (bRotLeft) addRotation(rotRate * deltaTime); if (bAccel) accelerate(accelRate * deltaTime); } public void render(GLAnimCanvas glc) { if (displayList == -1) createDisplayList(glc); glc.gl.glTranslated(x , y, -100.0); glc.gl.glRotated(rotation, 0.0, 0.0, 1.0); glc.gl.glCallList(displayList); } public void addRotation(double addRot) { rotation = (rotation + addRot) % 360.0; if (rotation < 0.0) rotation = 360.0 + (rotation % 360.0); } public void accelerate(double deltaTime) { vx += deltaTime * Math.cos(Math.toRadians(rotation)); vy += deltaTime * Math.sin(Math.toRadians(rotation)); double length = Math.sqrt(vx*vx + vy*vy); if (length > maxRate) { vx = (vx / length) * maxRate; vy = (vy / length) * maxRate; } } public void setInput(boolean bRR, boolean bRL, boolean bA) { bRotRight = bRR; bRotLeft = bRL; bAccel = bA; } } private static GLAnimCanvas canvas; private static GL4JavaTest gl4JavaTest; private static GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); private static GraphicsDevice gd = ge.getDefaultScreenDevice(); private static int frameCount = 0; private static MovingTriangle myTriangle = new MovingTriangle(); private static boolean[] keys = new boolean[255]; private static long lastTime; private static long firstTime; private static double deltaTime = 33.0; private static long numFrames = 0; private static final int WIDTH = 1280; private static final int HEIGHT = 1024; public static void main(String args[]) { gl4JavaTest = new GL4JavaTest(); Frame glWindow = new Frame("Java Test - Moving Triangle!"); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Cursor hiddenCursor = null; GLCapabilities glCaps = new GLCapabilities(); glWindow.setUndecorated(true); glWindow.setLayout(new BorderLayout()); glWindow.setIgnoreRepaint(true); glWindow.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { gd.setFullScreenWindow(null); System.exit(0); } }); canvas = GLDrawableFactory.getFactory().createGLAnimCanvas(glCaps, WIDTH, HEIGHT); canvas.addGLEventListener((GLEventListener)gl4JavaTest); canvas.addKeyListener(gl4JavaTest); canvas.setUseRepaint(false); canvas.setUseFpsSleep(false); canvas.setUseYield(false); //canvas.setAnimateFps(85); glWindow.add("Center", canvas); glWindow.pack(); glWindow.setVisible(true); canvas.setVisible(true); canvas.setIgnoreRepaint(true); canvas.repaint(); canvas.start(); gd.setFullScreenWindow(glWindow); gd.setDisplayMode(new DisplayMode(WIDTH, HEIGHT, 32, 60)); canvas.requestFocus(); lastTime = firstTime = System.currentTimeMillis(); } public void reshape (GLDrawable glDrawable, int w, int h) { GLAnimCanvas glc = (GLAnimCanvas)glDrawable; glc.gl.glViewport(0,0,WIDTH,HEIGHT); // Reset The Current Viewport glc.gl.glMatrixMode(GL_PROJECTION); // Select The Projection Matrix glc.gl.glLoadIdentity(); // Reset The Projection Matrix glc.glu.gluPerspective(45.0f,(float)WIDTH/(float)HEIGHT,0.1f,100.0f); glc.gl.glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glc.gl.glLoadIdentity(); } public void display (GLDrawable glDrawable) { GLAnimCanvas glc = (GLAnimCanvas)glDrawable; glc.gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); myTriangle.setInput(keys[KeyEvent.VK_NUMPAD6], keys[KeyEvent.VK_NUMPAD4], keys[KeyEvent.VK_NUMPAD8]); if (keys[KeyEvent.VK_ESCAPE]) { gd.setFullScreenWindow(null); System.exit(0); } if ((++numFrames % 100) == 0) { long curTime = System.currentTimeMillis(); long diff = curTime - lastTime; deltaTime = diff / 100.0; System.out.println("Average FPS: " + (1000.0 / deltaTime)); System.out.println("Num Frames: " + numFrames); System.out.println("Elapsed Time: " + (curTime - firstTime)/1000.0); lastTime = curTime; } myTriangle.tick(deltaTime); glc.gl.glLoadIdentity(); myTriangle.render(glc); } public void init (GLDrawable glDrawable) { GLAnimCanvas glc = (GLAnimCanvas)glDrawable; glc.gl.glShadeModel(GL_SMOOTH); // Enable Smooth Shading glc.gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background glc.gl.glClearDepth(1.0f); // Depth Buffer Setup glc.gl.glEnable(GL_DEPTH_TEST); // Enables Depth Testing glc.gl.glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do glc.gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// Really Nice Perspective Calculations } public void preDisplay(GLDrawable canvas) {} public void postDisplay(GLDrawable canvas) {} public void cleanup(GLDrawable canvas) {} public void keyPressed (KeyEvent keyEvent) { keys[keyEvent.getKeyCode()] = true; } public void keyReleased (KeyEvent keyEvent) { keys[keyEvent.getKeyCode()] = false; } public void keyTyped (KeyEvent keyEvent) { } public void mouseExited (MouseEvent mouseEvent) { } public void mouseReleased (MouseEvent mouseEvent) { } public void mousePressed (MouseEvent mouseEvent) { } public void mouseClicked (MouseEvent mouseEvent) { } public void mouseEntered (MouseEvent mouseEvent) { } } |
From: Kenneth B. R. <kbr...@al...> - 2001-12-01 21:59:12
|
> Do you know of any existing multimedia timer wrappers for Java? It = > would probably be OS-specific (unless it was very thorough), but I don't = > really mind that much. If all else fails I'll write my own interface = > with JNI. It is trivial to write. One static initialization routine which calls timeBeginPeriod(1) and one getTime() routine which returns timeGetTime(). Note that increasing the timer resolution may decrease the performance of your application, which is why HotSpot does not do it by default. From what I have heard the performance hit for CPU-intensive applications is roughly 10%. > Also, on my system, I got 111fps max, instead of 800-900. Do you know = > what might be causing this? No. |