OpenGL系列教程之七:OpenGL显示列表

相关主题:顶点缓冲区对象(VBO)

下载:displayList.zip


显示列表是一组被存储或编译的用来以后执行的OpenGL命令的集合。当一个显示列表被创建以后,所有的顶点数据和像素数据被复制到位于服务器端的显示列表内存中。这个过程只进行一次。当显示列表准备好(被编译完成)后,你可以重复使用它而不需要在每帧中重复地传输这些数据。显示列表是最快的一种绘制静态数据的方式,因为顶点数据和OpenGL命令被缓冲在服务器端的显示列表中,这样减少了从客户端到服务器段的数据传输。这意味着减少了执行实际的数据传输的CPU周期。

显示列表另一个重要的功能是显示列表可以被多个客户端所共享,因为它是服务器端的状态。

为了最佳的性能,将矩阵变换,光照,材质计算尽可能地放在显示列表中,这样OpenGL将只会在显示列表创建时执行一次这些高昂开销的计算,并将最终的结果存储在显示列表中。

然而,显示列表有一个缺点。当一个显示列表被编译后,它不能被改变。如果你需要频繁地改变数据或需要动态的数据,使用顶点数组顶点缓冲区对象。顶点缓冲区对象可以同时处理静态和动态的数据。

注意并不是所有的OpenGL命令都可以存储在显示列表中。由于显示列表是服务器端的状态,所有与客户端状态相关的命令不能被放置在显示列表中。例如:glFlush(),glFinish(),glRenderMode(),glEnableClientState(),glVertexPointer()等这些函数不能放在显示列表中。并且有返回值的OpenGL命令也不能放在显示列表中,因为这些返回值需要被返回到客户端,而不是显示列表中,例如:glIsEnabled(),geGet*(),glReadPixels(),glFeedbackBuffer()等。如果这些命令存储在显示列表中,它们将会被立即执行。





使用显示列表非常简单。首先是使用glGenLists()函数创建一个或多个显示列表对象,它的参数是需要创建的显示列表的数目,它返回连续的显示列表块中的第一个元素的索引。例如,glGenLists()函数如果返回1并且你创建的显示列表的数目为3的话,那么索引1,2,3是可用的。如果OpenGL创建显示列表失败,它将会返回0。如果你不再使用显示列表,可以使用glDeleteLists()删除它们。

第二步,你需要在glNewList()和glEndList()块之间存储OpenGL命令到显示列表中来优先渲染。这个过程叫做编译。glNewList()需要两个参数,第一个参数是glGenLists()函数返回的索引值,第二个参数是指定模式:是只编译还是编译并执行,GL_COMPLILE,GL_COMPLILE_AND_EXECUTE。

到现在为止,准备工作已经做好了。只需要在每帧中使用glCallList()函数或glCallLists()函数来执行显示列表就可以了。

看一下下面这个简单的显示列表的例子:

// 创建一个显示列表对象
GLuint index = glGenLists(1);

// 编译显示列表, 存储一个三角形
glNewList(index, GL_COMPILE);
    glBegin(GL_TRIANGLES);
    glVertex3fv(v0);
    glVertex3fv(v1);
    glVertex3fv(v2);
    glEnd();
glEndList();
...

// 绘制显示列表
glCallList(index);
...

// 如果不再需要这个显示列表,删除它
glDeleteLists(index, 1);

注意只有在glNewLists()和glEndLists()之间的OpenGL命令才会被记录到显示列表中一次,并在每次调用glCallList()时缓存一次。

为了使用glCallLists()执行多个显示列表,你需要做一个额外的工作。你需要使用一个数组来存放那些需要被渲染的显示列表的索引。换句话说,你可以选择渲染所有显示列表中的部分显示列表。glCallLists()需要3个参数:需要绘制的显示列表的个数,索引数组的数据类型,指向索引数组的指针。

注意你可以不需要指定显示列表的准确索引到数组中,你可以指定它们的偏移量,然后使用glListBase()设置基准的显示列表的位置。当glCallLists()被调用时,实际的索引值会通过将基准的位置与偏移量想加得到。下面的例子显示了如何使用glCallLists()以及一些说明:

GLuint index = glGenLists(10);  // 创建10个显示列表
GLubyte lists[10];              // 最多允许渲染10个显示列表

glNewList(index, GL_COMPILE);   // 编译第一个显示列表
...
glEndList();

...// 编译中间的显示列表

glNewList(index+9, GL_COMPILE); // 编译最后一个显示列表
...
glEndList();
...

// 只绘制部分显示列表 (第1个,第3个,第5个,第7个,第9个)
lists[0]=0; lists[1]=2; lists[2]=4; lists[3]=6; lists[4]=8;
glListBase(index);              // 设置基准的位置
glCallLists(5, GL_UNSIGNED_BYTE, lists);

OpenGL为了方便起见提供了glListBase()函数指定当glCallLists()函数执行时添加到显示列表索引的基准。

在上面的例子中,只有5个显示列表会被渲染:第1个,第3个,第5个,第7个,第9个。因此实际的偏移是index+0,index+2,index+4,index+6,index+8,这些偏移会被存储在索引数组中方便后面的渲染。如果glGenLists()函数的返回值是3,那么背渲染的显示列表的实际的索引是:3+0,3+2,3+4,3+6,和3+8。

glCallLists()显示使用字体中相对应的ASCII值做偏移的文字时非常有用。







这个例子使用了显示列表绘制了一个茶壶(6320个多边形)。最开始它使用顶点数组,glDrwaElements(0来渲染茶壶,但是所有的glDrawElements()调用都是放置在显示列表中。你可以看到使用显示列表和顶点数组在性能上的差异。

注意不能放置所有与客户端状态相关的OpenGL命令在显示列表中,glEnableClientState(),glVertexPointer(),和glNormalPointer()不应该被仿制在显示列表中。

下载源文件和可执行文件:displayList.zip

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值