您的位置:首页 > 运维架构

OpenGL加速渲染:显示列表glGenLists

2018-02-09 15:26 681 查看
在OpenGL中,可能要用非常多的点、线、面来构成一幅图。若进行实时渲染,无疑对显示效率有非常大的影响。比如要画几百万个三角形,那么很可能旋转一下图片需要响应很久。
为了加速渲染,可以将需要绘制的部分放在显示列表glGenLists中。每一个绘制的部分都是一个显示列表成员。然后将该列表进行预编译,编译完后并不显示。当需要显示的时候,直接调用显示列表,由于已经经过了预编译,所以此时会不经编译直接显示,从而提升效率。
以一个有盖杯子为例。设杯子需要绘制的有两部分:杯盖与杯身。
使用显示列表的步骤如下:
①  定义显示列表变量作为显示列表标示符。也就是说每个绘制的部分都需要用一个标示符来标识。杯子有2个绘制部分,也就是2个标识符。GLuint coverList, bodyList;注意GLuint是个int型变量。
②  申请2个显示列表名,并赋值给刚才创建的现实列表变量:coverList = glGenLists(2);
bodyList = coverList + 1;申请的显示列表标示符是从1开始的。也就是说,coverList==1,bodyList==2。若glGenLists返回0,则表示没有调用成功。glGenLists就相当于C++的new操作。不要在未删除上次赋值的情况下对同一个标示符进行再次赋值。
③  为每个显示列表进行绘制操作:glNewList(coverList, GL_COMPILE);
DrawCover();
glEndList();
glNewList(bodyList, GL_COMPILE);
DrawBody();
glEndList();这样,就使得int型标示符与绘制函数建立了关系。调用时,只用通过int型标识     符即可调用绘制函数。
类似glBegin/glEnd,glNewList/ glEndList之间可以放置任意绘制函数。
④  在场景绘制函数中,通过直接调用int型标识符直接绘制即可:glCallList(coverList);
glCallList(bodyList);注意显示列表调用的位置。显示列表的glNewList/ glEndList必须在窗口创建后调用;一定不可以在显示函数(渲染函数/场景绘制函数)中调用;只有glCallList才在场景绘制函数中调用。显示列表的glNewList/ glEndList一般会在SteupRC中调用。因为glNewList/ glEndList负责预编译工作,会对之间的函数进行编译,而该编译只需要进行一次
注意,由于使用的是预编译,所以显示列表中的部分在glNewList/ glEndList时就已经确定并编译完成了。比如在显示过程中希望更改杯体的颜色,于是直接修改了杯体的绘制函数中所使用的杯体数据,但是运行却发现杯子并没有任何变化,依然保持在glNewList/ glEndList时的状态。这是预编译造成的,预编译时是什么样子,显示时就是什么样子。即便之后更改了显示数据,但由于该数据已经编译完成,不会对新的修改再做编译了,所以修改了也没有变化。
 如果要实时反映修改的情况,那么就需要每修改一次,就重新对显示列表进行编译。一个显示列表允许多次编译。若要再次编译,重新调用glNewList/ glEndList即可。
调用GLboolean glIsList(GLuint list);函数来判断索引值是否存在。
调用glDeleteLists(GLuint list, GLsizei range);函数来删除多个显示列表。其中list为第一个显示列表的标示符,range 为从该标示符开始的范围。比如glDeleteLists (5,3),将从标示符5开始,删除3个显示列表,也就是删除5、6、7这三个显示列表。
当范围中的某些值非法时,会被自动忽略。if (glIsList(m_showListGround))
{
glDeleteLists(m_showListGround, 1);
}
在glNewList/ glEndList之间是可以调用已经创建的显示列表的:glNewList(AllList, GL_COMPILE);
glCallList(coverList);
glCallList(bodyList);
glEndList();但不可以创建新的显示列表:// 错误写法
glNewList(AllList, GL_COMPILE);
glNewList(coverList, GL_COMPILE);
DrawCover();
glEndList();
glEndList();
上面写法是错误的。

 关于glGenLists,其创建结果类似一个UINT数组。理论上最多创建2147483647(2^31-1)个显示列表。且一次性创建的显示列表必定是连续的。
删除时,显示列表仅仅把当前位置元素删掉,并不会将后面的元素前移。比如把显示列表1、2、3中的2删除,那么1后面的2将会是个无效显示列表,但3依然保持有效。
若此时要创建新的显示列表,那么会从前向后选择合适区域创建。比如要创建2个显示列表,由于一次性创建的显示列表必连续,所以要选择有2个空区域的位置来进行创建。于是会成功创建标示符为4、5的显示列表。
此时要再次创建1个显示列表,由于2号位为空,且其大小满足1个显示列表,故而会在2号位创建新的显示列表,该列表的标示符将是2。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: