文档章节

OpenGL(八) 显示列表

abcijkxyz
 abcijkxyz
发布于 2016/11/14 20:10
字数 1586
阅读 17
收藏 0

OpenGL在即时模式(Immediate Mode)下绘图时,程序中每条语句产生的图形对象被直接送进绘图流水线,在显示终端立即绘制出来。当需要在程序中多次绘制同一个复杂的图像对象时,这种即时模式会消耗大量的系统资源,降低程序的运行效率,为此,OpenGL提供了一种更有效组织OpenGL语句的形式——显示列表

OpenGL使用显示列表方式绘图一般要比瞬时方式快,尤其是显示列表方式可以大量地提高网络性能,即当通过网络发出绘图命令时,由于显示列表驻留在服务器中,因而使网络的负担减轻到最小。另外,在单用户的机器上,显示列表同样可以提高效率。例如旋转矩阵函数glRotate*(),若将它置于显示列表中,则可大大提高性能,因为旋转矩阵的计算并不简单,包含有平方、三角函数等复杂运算,而在显示列表中,它只被存储为最终的旋转矩阵,于是执行起来如同硬件执行函数glMultMatrix()一样快。


显示列表的使用流程:建立显示列表、调用显示列表、删除显示列表


建立显示列表


分配显示列表编号

OpenGL中用正整数来区分不同的显示列表,为防止重复定义已经存在的显示列表号,使用glGenLists函数来自动分配一个没有被使用过的显示列表编号。

glGenLists函数原型:


GLuint   glGenLists (GLsizei range);


参数range指定要分配几个显示列表。

返回值是被分配的显示列表中的最小编号,若返回0表示分配失败。


创建显示列表

创建显示列表声明了把哪些OpenGL语句装入到当前显示列表中。使用glNewList开始装入,使用glEndList结束装入。

glNewList的函数原型如下:


void   glNewList (GLuint list, GLenum mode);


第一个参数标示当前正在操作的显示列表号

第二个参数有两种取值--GL COMPILE和GL COMPILE AND EXECUTE,前者声明当前显示列表只是装入相应OpenGL语句,不执行;后者表示在装入的同时,执行一遍当前显示列表。

并不是所有的OpenGL函数都可以装入到显示列表中,一般来说,用于传递参数或具有返回数值的函数语句不能存入显示列表。


调用显示表 


调用显示列表只需要在需要调用的地方插入glCallList(id)即可,入参id表示了要调用的显示列表的编号。另外也可以使用glCallLists一次性调用一组显示列表。


删除显示表


在退出程序前要将所建立的显示表删除,释放显示列表占用的资源。

glDeleteLists(GLuint list,GLsizei range)用来删除用户建立的显示列表。

参数list表示要删除的第一个显示列表的数字编号;参数range表示从指定的第一个显示表开始要删除的连续的显示表个数。


下边是一个使用显示列表的例子,创建了两个显示列表,第一个显示列表里定义了模型视图矩阵,第二个显示列表里定义了一个矩形立方体模型,包含顶点颜色等。


调用了1次List 1,调用了3次List 2,生成了3个立体模型,运行效果:



完整代码:

#include <glut.h> 
#include <Windows.h>

GLfloat angle = 0.0f; 

void CreateDisplayLists()
{
	//List 1 定义模型视图矩阵
	if(!glIsList((GLuint)1))
	{
		glNewList(1,GL_COMPILE);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(75,1,2,50);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(0,25,25,0,0,0,0,1,0);
		glEndList();
	}

	//List 2 定义实体矩形
	if(!glIsList((GLuint)2))
	{
		glNewList(2,GL_COMPILE);
		glBegin(GL_QUADS);

		//底面
		glColor3f(1,0,0);
		glVertex3f(-5,-5,-5);
		glVertex3f(5,-5,-5);
		glColor3f(0,0,1);
		glVertex3f(5,5,-5);
		glVertex3f(-5,5,-5);
		//侧面A
		glColor3f(0,0,1);
		glVertex3f(-5,-5,-5);
		glVertex3f(5,-5,-5);
		glColor3f(0,1,0);
		glVertex3f(5,-5,5);
		glVertex3f(-5,-5,5);
		//侧面B
		glColor3f(0,1,0);
		glVertex3f(5,-5,-5);
		glVertex3f(5,5,-5);
		glColor3f(0,1,1);
		glVertex3f(5,5,5);
		glVertex3f(5,-5,5);
		//侧面C
		glColor3f(1,1,0);
		glVertex3f(5,5,-5);
		glVertex3f(-5,5,-5);
		glColor3f(1,0,1);
		glVertex3f(-5,5,5);
		glVertex3f(5,5,5);
		//侧面D
		glColor3f(1,0,1);
		glVertex3f(-5,5,-5);
		glVertex3f(-5,-5,-5);
		glColor3f(0,1,0);
		glVertex3f(-5,-5,5);
		glVertex3f(-5,5,5);
		//顶面
		glColor3f(1,1,0);
		glVertex3f(-5,-5,5);
		glVertex3f(5,-5,5);
		glColor3f(0,0,1);
		glVertex3f(5,5,5);
		glVertex3f(-5,5,5);
		glEnd();
		glEndList();
	}
}

void myDisplay(void) 
{
	glEnable(GL_DEPTH_TEST);   //深度缓存
	glClearColor(0.1,0.1,0.3,0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glCallList(1);
	glRotatef(angle,1,0,0);
	glRotatef(angle,0,1,0);
	glRotatef(angle,1,0,1);
	glCallList(2);  //绘制模型
	glTranslatef(-10,0,-10);
	glCallList(2);
	glTranslatef(20,0,20);
	glCallList(2);
	glutSwapBuffers();
}  

void myIdle(void) 
{    
	angle+=0.05f; 
	if( angle >= 360.0f )    
		angle = 0.0f;    
	myDisplay();
} 

int main(int argc, char* argv[]) 
{   
	glutInit(&argc, argv); 
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowPosition(200, 200);  
	glutInitWindowSize(400, 400);   
	glutCreateWindow("OpenGL"); 
	CreateDisplayLists();  //创建显示列表
	glutDisplayFunc(&myDisplay);   
	glutIdleFunc(&myIdle);     
	glutMainLoop();   
	return 0; 
}



显示列表的适用场合


并不是所有场合下显示列表都可以优化程序性能,这是因为调用显示列表本身时程序也会产生一些开销,若一个显示列表太小,这个开销将超过显示列表的所带来的效率提升。以下是一些非常适合使用显示列表的场景:

  • 矩阵操作大部分矩阵操作需要OpenGL计算逆矩阵,矩阵及其逆矩阵都可以保存在显示列表中。
  • 光栅位图和图像程序定义的光栅数据不一定是适合硬件处理的理想格式。当编译组织一个显示列表时,OpenGL可能把数据转换成硬件能够接受的数据,这可能有效地提高画位的速度。
  • 光、材质和光照模型当用一个比较复杂的光照环境绘制场景时,可以为场景中的每个物体改变材质。但是材质计算较多,因此设置材质可能比较慢。若把材质定义放在显示列表中,则每次改换材质时就不必重新计算了。因为计算结果存储在表中,因此能更快地绘制光照场景。
  • 纹理因为硬件的纹理格式可能与OpenGL格式不一致,若把纹理定义放在显示列表中,则在编译显示列表时就能对格式进行转换,而不是执行中进行,这样就能大大提高效率。
  • 多边形的图案填充模式可将定义的图案放在显示列表中。


本文转载自:http://blog.csdn.net/dcrmg/article/details/53133112

共有 人打赏支持
abcijkxyz
粉丝 63
博文 6196
码字总数 1876
作品 0
深圳
项目经理
私信 提问
Android图形---OpenGL(五)

本文译自:http://developer.android.com/guide/topics/graphics/opengl.html 形状的外观和折点 在OpenGL中,形状的外观是由三个或三维空间中更多的点来定义的一个表面。一个三个或更多的三维...

长平狐
2012/10/16
66
0
OpenGL超级宝典笔记——显示列表

前言 在先前的章节中,我们已经讨论OpenGL基本的一些渲染技术。这些基本的技巧足够渲染简单的图像,然而在渲染精细的画面逼真的画面的时候(非常多的顶点和纹理),如果使用之前的方式渲染(...

Mario_Q
2013/12/15
0
2
Metal入门教程(八)Metal与OpenGL ES交互

前言 Metal入门教程(一)图片绘制 Metal入门教程(二)三维变换 Metal入门教程(三)摄像头采集渲染 Metal入门教程(四)灰度计算 Metal入门教程(五)视频渲染 Metal入门教程(六)边界检测...

落影loyinglin
2018/08/10
0
0
Android 自定义相机开发(三) —— 了解下EGL

胡说八道 如果要使用OpenGl来自定义相机,这个还是要了解下的。可能大多数开发者使用过OpengGL但是不知道EGL是什么?EGL的作用是什么?这其实一点都不奇怪,因为Android中的GlSurfaceView已经...

aserbao
2018/05/10
0
0
OpenGL ES Programming Guide for iOS 第一章

关于OpenGL ES Open Graphics Library(OpenGL)用于二维及三维数据的可视化。它是一种多用途的开放标准图形库,支持二维和三维数位内容创作,机械和建筑设计,虚拟样,飞行模拟,游戏,以及更...

长平狐
2012/10/08
459
0

没有更多内容

加载失败,请刷新页面

加载更多

python实现下载网络图片

项目需求: 有时候我们做爬虫的时候,需要把爬取到的图片资源保存到我们本地,以防爬取的图片链接被原来资源主人变更,所以就需要把好不容易拿到的资源永久变为自己的,就需要把图片链接下载到我们...

银装素裹
33分钟前
1
0
米利型和摩尔型状态机

1. 经典状态机 x(t)为当前输入 z(t)为当前输出 组合逻辑电路输出s(t+1)为次态 状态寄存器(也就是一组触发器)输出s(t)为现态 2. 米利状态机(Mealy) 组合逻辑C1模块有两个输入端:当前输入x(t...

易冥天
34分钟前
4
0
Kafka是如何解决常见的微服务通信问题的

微服务自成立以来就以不同的方式相互沟通。有些人更喜欢使用HTTP REST API,但这些API有自己的排队问题,而有些则更喜欢较旧的消息队列,比如RabbitMQ,它们带有扩展和操作方面的问题。 以K...

java菜分享
38分钟前
1
0
关于php的xdebug配置(编辑器vscode)

虽然说echo和print_r是公认的最实用的调试工具,但是效率真的没有可视化的直接断点那么高。这里简单介绍如果安装及配置xdebug for vscode 一、PHP环境处的配置 1、编译安装 下载及编译php,因...

元谷
52分钟前
8
0
heartbeat

http://www.linux-ha.org/doc/users-guide/_building_and_installing_heartbeat_from_source.html kaer@linux-sqlf:~/Reusable-Cluster-Components-glue--0a7add1d9996> ./configure --enabl......

李有常
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部