上一章我们已经尝试制作了一个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