OpenGL编程指南6:顶点数组

来源:互联网 发布:淘宝买水果拒收 编辑:程序博客网 时间:2024/06/01 18:36

1.前言

前面的例子中,我们可以看到,OpenGL需要进行大量的函数调用才能完成对几何图元的渲染。绘制一个20条边的多边形至少需要22个函数调用。首先调用一个glBegin(),然后为每个顶点调用一次函数,最后调用1次glEnd().如果我们还要添加其他的额外信息(如多边形边界标志或表面法线),在每个顶点上还要增加函数调用。这可能会成倍地增加渲染几何物体所需要的函数调用数量。在很多系统中,函数调用具有相当大的开销,可能会影响应用程序的性能。

另一个问题是,相邻多边形的共享定点的冗余处理。如上图所示的立方体具有六个面和8个共享顶点。遗憾的是,如果按照标准方法描述这个物体,每个顶点必须被指定3次,因为每个顶点都在三个面上。这样就造成了大量的冗余。
幸运的是,OpenGL提供了一些顶点数组函数,允许只用少数几个数组指定大量的与顶点相关的数据,并用少量函数调用(与顶点数组的数量相仿)访问这些数据。使用顶点数组函数,一个拥有20条边的多边形的顶点可以放在一个数组中,并且只通过1个函数进行调用。其实有其他如文理、法向量等,也可以只通过1个函数进行调用。
把数据放在顶点数组中可以提高应用程序的性能。使用顶点数组可以减少函数的调用次数,从而提高性能,也可以避免共享顶点的冗余处理。

2.顶点数组对几何图形渲染步骤

1.激活/启用最多可达8个数组

每个数组用于存储不同类型的数据:顶点坐标、表面法线、RGBA颜色、辅助颜色、颜色索引、雾坐标、纹理坐标以及多边形的边界标志。
该步骤是调用void glEnableClientState(GLenum array)函数实现。
array指定了需要启用的数组。其参数可以是下面常量:GL_VERTEX_ARRAY / GL_COLOR_ARRAY / GL_SECONDARY_COLOR_ARRRAY / GL_INDEX_ARRAY / GL_NORMAL_ARRAY / GL_FOG_COORDINATE_ARRAY / GL_TEXTURE_COORD_ARRAY / GL_EDGE_FLAG_ARRAY.
例如,如果我们需要光照,就可以为每一个顶点定义一条发现向量。这种情况下使用顶点数组时,需要同时激活表面法向数组和顶点坐标数组。
glEnableClientState(GL_NORMAL_ARRAY);glEnableClientState(GL_VERTEX_ARRAY);
void display(void)  {      glClear(GL_COLOR_BUFFER_BIT);      GLfloat vertices[]={0.25,0.25,                        0.75,0.25,                        0.75,0.75,                        0.25,0.75};    GLfloat colors[]={1.0, 0.0, 0.0,                      1.0, 1.0, 0.0,                      0.0, 1.0, 0.0,                      0.0, 0.0, 1.0};    glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_COLOR_ARRAY);    glVertexPointer(2,GL_FLOAT,0,vertices);    glColorPointer (3,GL_FLOAT,0,colors);    glBegin(GL_POLYGON);  glArrayElement(0);glArrayElement(1);glArrayElement(2);glArrayElement(3);    glEnd();        glFlush();  }  
输出结果如下:

2.把数据放入数组中

这些数据是通过指针进行访问的。

3.绘制几何图形

绘制图形关键点在于“解引用”,而解引用关键在于glArrayElement()函数。该函数通常在glBegin()和glEnd()之间调用。否则,glArrayElement()函数就会设置所有启用数组的当前状态(顶点除外,因为它不存在当前状态)。
下面例子展示的是,使用取自启用的顶点数组的0,3,4号顶点绘制三角形。
 glBegin(GL_POLYGON);  glArrayElement(0);glArrayElement(2);glArrayElement(3);    glEnd(); 
输出结果:
由于glArrayElemrnt()函数对于每个顶点只调用一次,因此它可能减少对函数的调用数量,从而提高程序的整体性能。

3.重启图元

在OpenGL绘制图形时,可能需要绘制多个并不相连的图形。这样的情况下这几个图形没法被当做一个图形来处理。也就需要多次调用 DrawArrays 或 DrawElements. 如果图形很多,可能会需要用一个循环来调用:
for (int i = 0; i < num_objects; i++) {    glDrawArrays(GL_TRIANGLES,                object[n]->first_vertex,                object[n]->vertex_count);}
每一次调用OpenGL 的绘制函数,都需要一定的资源开销,如果每一帧调用太多次,会对程序的性能产生较大的影响。提高性能的办法就是调用一次绘制函数,画出分散的图形。
一种方法是使用 glMultiDrawElements 函数来代替旧的绘制函数,可以减少调用次数,仅需调用此函数一次即可。但是这个函数在OpenGL ES 没有得到支持。而且使用这个函数,仍然需要将每一个分散的图形维护一组单独的顶点坐标/纹理坐标,这个是免不了的,这些数据仍然需要分开上传,还是会消耗一定的资源。针对这种情况使用图元重启会更加合适。

3.1 基本介绍

考虑通常的情况,当用户绘制 GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_LINE_STRIP, GL_LINE_LOOP 这些图元时,所有的绘制点按照特定的顺序被连起来,以形成一个最终的复杂图形,也就是说最终的复杂图形由多个相连的三角形或线段组成。像上面提到的情况,想要绘制分散的图形,应该怎么办?
图元重启(Primitive restart) 允许用户绘制不连续的、分散的图形。考虑使用glDrawElements 函数,绘制时按照indices所指定的顶点的顺序来绘制的。此时可以指定某一个值,该值表示一个重启的标志。遇到这个值的时候,OpenGL不会绘制图元,而是结束上一段绘制,然后重新启动新的绘制,也就是說用后面的索引所指定的顶点来从头绘制一个图形。
举个例子:比如指定8为重启的标志,遇到8就重启。


上面的是不启用图元重启的情况,即通常的情况。
下面的是启用图元重启的情况,我们可以看到,从9开始,又重新从头开始绘制Triangle strip了。

3.2 执行过程

指定重启位置的数值,在桌面版的OpenGL是可以自行设定的,glPrimitiveRestartIndex​ 函数指定重启的标志。在OpenGL ES 无法自行指定,只能用给定的值。
首先设置启用图元重启:
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
Fixed index就代表了使用固定的重启的标志,具体数值和indices内数据类型有关。glDrawElements 的indices参数类型必须是以下的一种:GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT. 那么分别对应的重启的标志就是 2^8 - 1;2^16 - 1;2^32 - 1;也就是說重启的标志的数值就是indices数组所能允许的最大值。这个值一般来说是不会被用到的,拿来当标志正好。
所以我们只需要在 indices 里面的合适的位置插入一个标志,然后再调用 glDrawElements 函数即可实现图元重启。
下面代码片段是一个具体的例子:


// Prepare index buffer data (not shown: vertex buffer data, loading vertex and index buffers)GLushort indexData[11] = {    0, 1, 2, 3, 4,    // triangle strip ABCDE    0xFFFF,           // primitive restart index (largest possible GLushort value)     5, 6, 7, 8, 9,    // triangle strip FGHIJ};// Draw triangle stripsglEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);glDrawElements(GL_TRIANGLE_STRIP, 11, GL_UNSIGNED_SHORT, 0);

4.参看资料

[1].Primitive Restart Makes GPGPU Tech Sparkle
[2].Combining Drawing Functions, Combining Geometry Using Primitive
[3].TechniquesforWorkingwithVertexData

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老是不想写作业怎么办 一年级孩子不爱学怎么办 一年级孩子不爱学习怎么办 我不想读书了怎么办 孩子读书读不懂怎么办 一岁多宝宝不吃奶粉怎么办 小孩不讲话怎么办 舌头 看书记不住内容怎么办 看不下去书怎么办 职高读不下去怎么办 小孩不主动说话怎么办 不喜欢自己的儿子怎么办 生了儿子不喜欢怎么办 孩子不愿意去幼儿园怎么办 内向妈妈带孩子怎么办 从小就不爱学习怎么办 孩子老爱玩不爱学习怎么办? 孩子不爱做题怎么办 看书静不下心怎么办 孩子不自觉学习怎么办 不自觉的孩子怎么办 不学习的孩子怎么办 电脑不受老师控制怎么办 儿子不尊重老师怎么办 小孩不喜欢吃蔬菜怎么办 小孩不愿练钢琴怎么办 孩子不喜欢幼儿园老师怎么办 孩子不主动思考怎么办 我初一不想读书怎么办 初中孩子不爱学习怎么办 初一就不想读书怎么办 孩子懒得写作业怎么办 初中学生讨厌学习怎么办? 小学不写作业怎么办 幼儿园小朋友不愿意上学怎么办 幼儿园孩子不愿意上学怎么办 宝宝不愿意上幼儿园怎么办 孩子不爱上幼儿园怎么办 宝宝不爱上幼儿园怎么办 宝宝不爱去幼儿园怎么办 幼儿园宝宝不爱写字怎么办