OpenGL显示列表:原理、应用与优化
发布时间: 2025-08-16 02:10:23 阅读量: 1 订阅数: 6 

### OpenGL显示列表:原理、应用与优化
#### 1. 显示列表概述
显示列表是一组已存储以供后续执行的OpenGL命令。当调用显示列表时,其中的命令将按照发出的顺序执行。大多数OpenGL命令既可以存储在显示列表中,也可以以立即模式发出,立即模式会使命令立即执行。在单个程序中,你可以自由混合立即模式编程和显示列表的使用。
显示列表的主要部分包括:
- “为何使用显示列表”:解释何时使用显示列表。
- “使用显示列表的示例”:给出一个简短示例,展示使用显示列表的基本命令。
- “显示列表设计理念”:解释某些设计选择的原因(如使显示列表不可编辑),以及使用显示列表时可能实现的性能优化。
- “创建和执行显示列表”:详细讨论创建、执行和删除显示列表的命令。
- “执行多个显示列表”:展示如何连续执行多个显示列表,以一个小字符集为例。
- “使用显示列表管理状态变量”:说明如何使用显示列表保存和恢复设置状态变量的OpenGL命令。
#### 2. 为何使用显示列表
显示列表可以提高性能,因为你可以用它们存储OpenGL命令以供后续执行。如果你计划多次重绘相同的几何图形,或者有一组需要多次应用的状态更改,将命令缓存到显示列表中通常是个好主意。使用显示列表,你可以一次性定义几何图形和/或状态更改,并多次执行它们。
例如,绘制三轮车时,后面的两个轮子尺寸相同但相互偏移,前轮比后轮大且位置不同。一种高效的渲染方法是将一个轮子的几何图形存储在显示列表中,然后执行该列表三次。每次执行列表之前,你需要适当地设置模型视图矩阵,以计算每个轮子的正确大小和位置。
当在网络上远程运行OpenGL程序到另一台机器时,将命令缓存到显示列表中尤为重要。因为显示列表是服务器状态的一部分,驻留在服务器机器上,所以如果你将重复使用的命令存储在显示列表中,可以减少通过网络重复传输数据的成本。
在本地运行时,将常用命令存储在显示列表中通常也可以提高性能。一些图形硬件可能会将显示列表存储在专用内存中,或者以与图形硬件或软件更兼容的优化形式存储数据。
#### 3. 使用显示列表的示例
显示列表是一种方便且高效的方式来命名和组织一组OpenGL命令。例如,假设你想绘制一个圆环并从不同角度查看它。最有效的方法是将圆环存储在显示列表中。然后,每当你想更改视图时,只需更改模型视图矩阵并执行显示列表来绘制圆环。以下是一个示例代码:
```c
GLuint theTorus;
/* Draw a torus */
static void torus(int numc, int numt)
{
int i, j, k;
double s, t, x, y, z, twopi;
twopi = 2 * (double)M_PI;
for (i = 0; i < numc; i++) {
glBegin(GL_QUAD_STRIP);
for (j = 0; j <= numt; j++) {
for (k = 1; k >= 0; k--) {
s = (i + k) % numc + 0.5;
t = j % numt;
x = (1+.1*cos(s*twopi/numc))*cos(t*twopi/numt);
y = (1+.1*cos(s*twopi/numc))*sin(t*twopi/numt);
z = .1 * sin(s * twopi / numc);
glVertex3f(x, y, z);
}
}
glEnd();
}
}
/* Create display list with Torus and initialize state */
static void init(void)
{
theTorus = glGenLists(1);
glNewList(theTorus, GL_COMPILE);
torus(8, 25);
glEndList();
glShadeModel(GL_FLAT);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glCallList(theTorus);
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
}
/* Rotate about x-axis when “x” typed; rotate about y-axis
when “y” typed; “i” returns torus to original view */
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'x':
case 'X':
glRotatef(30., 1.0, 0.0, 0.0);
glutPostRedisplay();
break;
case 'y':
case 'Y':
glRotatef(30., 0.0, 1.0, 0.0);
glutPostRedisplay();
break;
case 'i':
case 'I':
glLoadIdentity();
gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
glutPostRedisplay();
break;
case 27:
exit(0);
break;
}
}
int main(int argc, char **argv)
{
glutInitWindowSize(200, 200);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
```
在这个示例中,`init()` 函数创建了一个圆环的显示列表并初始化OpenGL渲染状态。`torus()` 函数用于绘制圆环,它被 `glNewList()` 和 `glEndList()` 括起来,从而定义了一个显示列表。`glNewList()` 的 `listName` 参数是一个由 `glGenLists()` 生成的整数索引,用于唯一标识这个显示列表。
用户可以在窗口获得焦点时按下 `x` 或 `y` 键,使圆环绕x轴或y轴旋转。每当发生这种情况时,回调函数 `keyboard()` 会被调用,它将一个30度的旋转矩阵(绕x轴或y轴)
0
0
相关推荐










