上一章我们已经尝试制作了一个3D场景,但是也发现了一个严重问题,就是CPU使用率的问题,那是因为我们在上一章的代码中,GL是负责了大部分画图工作,每刷新一帧,就重画一次,以至CPU使用率急升,虽然OPENGL的速度已经很快,在C++里尚且非常需要优化,在JAVA里,优化的工作更是不可缺少的,下面用NEHE-JOGL里的第十二章:显示列表来稍微修改一下来说明显示列表的重要作用.先看看效果图
在这例子里的display()函数只加上了下面代码:
每移动一下画图点,就调用 gl.glCallList(String name); //调用保存在缓存里的物体.
CPU使用率始终是为00-05,最下面那个JAVA.EXE是netbeans .
用下面代码生成一个显示列表,String box可以随便定义.
box = gl.glGenLists(2);
gl.glNewList(box, GL2.GL_COMPILE);
..............................
gl.glEndList();
private void buildLists(GL2 gl) { box = gl.glGenLists(2); // Generate 2 Different Lists gl.glNewList(box, GL2.GL_COMPILE); // Start With The Box List gl.glBegin(GL2.GL_QUADS); gl.glNormal3f(0.0f, -1.0f, 0.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Face gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glNormal3f(0.0f, 0.0f, 1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); // Front Face gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glNormal3f(0.0f, 0.0f, -1.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); // Back Face gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, -1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); gl.glNormal3f(1.0f, 0.0f, 0.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); // Right face gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glNormal3f(-1.0f, 0.0f, 0.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); // Left Face gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, -1.0f); gl.glEnd(); gl.glEndList(); top = box + 1; // Storage For "Top" Is "Box" Plus One gl.glNewList(top, GL2.GL_COMPILE); // Now The "Top" Display List gl.glBegin(GL2.GL_QUADS); gl.glNormal3f(0.0f, 1.0f, 0.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, -1.0f);// Top Face gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); gl.glEnd(); gl.glEndList(); }
显示列表的原理就是预先画一次gl.glNewList()与gl.glEndList()里的物体,保存到缓存里,以后你再调用gl.glCallList从缓存里取出原先物体,取出过程几乎不占用CPU,效率就大大提高.
完整GL控制类代码:
package demos.nehe.lesson12; import demos.common.TextureReader; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLEventListener; import javax.media.opengl.glu.GLU; import java.io.IOException; import javax.media.opengl.GL2; class Renderer implements GLEventListener { private float[][] boxcol = {{1.0f, 0.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, {1.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 1.0f}}; private float[][] topcol = {{0.5f, 0.0f, 0.0f}, {0.5f, .25f, 0.0f}, {0.5f, 0.5f, 0.0f}, {0.0f, 0.5f, 0.0f}, {0.0f, 0.5f, 0.5f}}; private float xrot; // Rotates Cube On The X Axis private boolean increaseX; private boolean decreaseX; private float yrot; // Rotates Cube On The Y Axis private boolean increaseY; private boolean decreaseY; private int[] textures = new int[1]; // Storage For 1 Texture private int xloop; // Loop For X Axis private int yloop; // Loop For Y Axis private int box; // Storage For The Box Display List private int top; // Storage For The Top Display List private GLU glu = new GLU(); public void increaseXrot(boolean increase) { increaseX = increase; } public void decreaseXrot(boolean decrease) { decreaseX = decrease; } public void increaseYrot(boolean increase) { increaseY = increase; } public void decreaseYrot(boolean decrease) { decreaseY = decrease; } private void loadGLTexture(GL2 gl) { TextureReader.Texture texture = null; try { texture = TextureReader.readTexture("demos/data/images/cube.bmp"); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } gl.glGenTextures(1, textures, 0); // Create The Texture // Typical Texture Generation Using Data From The Bitmap gl.glBindTexture(GL2.GL_TEXTURE_2D, textures[0]); gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, 3, texture.getWidth(), texture.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, texture.getPixels()); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); } private void buildLists(GL2 gl) { box = gl.glGenLists(2); // Generate 2 Different Lists gl.glNewList(box, GL2.GL_COMPILE); // Start With The Box List gl.glBegin(GL2.GL_QUADS); gl.glNormal3f(0.0f, -1.0f, 0.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Face gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glNormal3f(0.0f, 0.0f, 1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); // Front Face gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glNormal3f(0.0f, 0.0f, -1.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); // Back Face gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, -1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); gl.glNormal3f(1.0f, 0.0f, 0.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); // Right face gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glNormal3f(-1.0f, 0.0f, 0.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); // Left Face gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, -1.0f); gl.glEnd(); gl.glEndList(); top = box + 1; // Storage For "Top" Is "Box" Plus One gl.glNewList(top, GL2.GL_COMPILE); // Now The "Top" Display List gl.glBegin(GL2.GL_QUADS); gl.glNormal3f(0.0f, 1.0f, 0.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, -1.0f);// Top Face gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); gl.glEnd(); gl.glEndList(); } public void init(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); gl.glEnable(GL2.GL_TEXTURE_2D); // Enable Texture Mapping gl.glShadeModel(GL2.GL_SMOOTH); // Enable Smooth Shading gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background gl.glClearDepth(1.0f); // Depth Buffer Setup gl.glEnable(GL.GL_DEPTH_TEST); //3D场景里记得要开深度测试 Enables Depth Testing gl.glDepthFunc(GL.GL_LEQUAL); // The Type Of Depth Testing To Do gl.glEnable(GL2.GL_LIGHT0); // Quick And Dirty Lighting (Assumes Light0 Is Set Up) gl.glEnable(GL2.GL_LIGHTING); // Enable Lighting gl.glEnable(GL2.GL_COLOR_MATERIAL); // Enable Material Coloring gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); // Really Nice Perspective Calculations loadGLTexture(gl); buildLists(gl); } private void update() { if (decreaseX) xrot -= 8f; if (increaseX) xrot += 8f; if (decreaseY) yrot -= 8f; if (increaseY) yrot += 8f; } public void display(GLAutoDrawable drawable) { update(); GL2 gl = drawable.getGL().getGL2(); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glBindTexture(GL2.GL_TEXTURE_2D, textures[0]); for (yloop = 1; yloop < 6; yloop++) { for (xloop = 0; xloop < yloop; xloop++) { gl.glLoadIdentity(); // Reset The View gl.glTranslatef(1.4f + ((float) xloop * 2.8f) - ((float) yloop * 1.4f), ((6.0f - (float) yloop) * 2.4f) - 7.0f, -20.0f); gl.glRotatef(45.0f - (2.0f * yloop) + xrot, 1.0f, 0.0f, 0.0f); gl.glRotatef(45.0f + yrot, 0.0f, 1.0f, 0.0f); gl.glColor3fv(boxcol[yloop - 1], 0); gl.glCallList(box); gl.glColor3fv(topcol[yloop - 1], 0); gl.glCallList(top); } } //显示1000个箱子 for(int i=0;i<1000;i++) { gl.glTranslatef(i*2,0.0f,0.0f); gl.glCallList(box); gl.glCallList(top); } } public void reshape(GLAutoDrawable drawable, int xstart, int ystart, int width, int height) { GL2 gl = drawable.getGL().getGL2(); height = (height == 0) ? 1 : height; gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(45, (float) width / height, 1, 1000); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); } public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void dispose(GLAutoDrawable arg0) { throw new UnsupportedOperationException("Not supported yet."); } }
分享自己的技术论坛http://www.itneng.com/forum.php