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 ABCDE0xFFFF,           // primitive restart index (largest possible GLushort value) 5, 6, 7, 8, 9,    // triangle strip FGHIJ
};
// Draw triangle strips
glEnable(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

OpenGL编程指南6:顶点数组相关推荐

  1. 《OpenGL编程指南(原书第8版)》——计算着色器

    原文  http://www.csdn.net/article/2014-11-21/2822754 主题 OpenGL 数学 概述 由于图形处理器每秒能够进行数以亿计次的计算,它已成为一种性能十分惊 ...

  2. 《OpenGL编程指南》一3.2 OpenGL缓存数据

    本节书摘来自华章出版社<OpenGL编程指南>一书中的第3章,第3.2节,作者 Bill Licea-Kane ,更多章节内容可以访问云栖社区"华章计算机"公众号查看 ...

  3. OpenGL深入探索——《OpenGL编程指南(原书第8版)》——计算着色器

    转载自 <OpenGL编程指南(原书第8版)>--计算着色器 概述 由于图形处理器每秒能够进行数以亿计次的计算,它已成为一种性能十分惊人的器件.过去,这种处理器主要被设计用于承担实时图形渲 ...

  4. OpenGl编程指南例2.4大白话分析

    OpenGl编程指南例2.4分析 即上一篇文章搭建了opengl的环境后,继续学习Opengl,被第二章的各种gen,bind,buffer搞得晕头转向,在还没有消化完全的时候,又被一计重击打到--为 ...

  5. OpenGL编程指南7:视图-

    1.前言 计算机图形学的要点就是创建三维物体的二维图像(图像必须是二维的,因为他是在平面的屏幕上显示的).但是,当我们决定怎样在屏幕上绘图时,必须使用三维坐标的方式考虑. 为了把一个物体的三维坐标变成 ...

  6. OpenGL编程指南4:双缓冲实现运行

    1.前言 绘制一个旋转的方块,主要为了说明glutSwapBuffers()函数的用法. 同时也为了学习如何使用GLUT控制输入设备,并打开或关闭空闲处理函数. 2.OpenGL编程及程序剖析 /** ...

  7. 《OpenGL编程指南》一第3章 OpenGL绘制方式

    本节书摘来自华章出版社<OpenGL编程指南>一书中的第3章,作者 Bill Licea-Kane ,更多章节内容可以访问云栖社区"华章计算机"公众号查看 第3章 Op ...

  8. OpenGL编程指南8-Transform Feedback例子理解

    transform feedback 是,OpenGL管线中,的,顶点处理阶段结束之后,图元装配和光栅化之前的一个步骤.transform feedback,可以重新捕获即将装配为图元(点.线段.三角 ...

  9. 《OpenGL编程指南》一第2章 着色器基础

    本节书摘来自华章出版社<OpenGL编程指南>一书中的第2章,作者 Bill Licea-Kane ,更多章节内容可以访问云栖社区"华章计算机"公众号查看 第2章 着色 ...

最新文章

  1. 亚马逊:从零售商向科技公司的质变
  2. 关于手风琴效果延迟执行解决方式
  3. 文巾解题 180. 连续出现的数字
  4. 【视频课】深度学习必备基础,如何使用好数据?
  5. [LeetCode] Two Sum
  6. 几个重要库函数的实现
  7. 考教育统计与测量可以带哪种计算机,《教育统计与测量》练习题库及答案
  8. U-Net++粗略解释
  9. Linux设置ssh免密码登录
  10. 【转】格雷斯特(Glest)Glest(开源RTS游戏)编译备忘
  11. AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中?
  12. C语言实现成语接龙完整版
  13. 中职学校计算机专业课程设置,中职学校计算机专业课程设置的几点思考
  14. struts中ActionForm有什么作用?
  15. BLE service, characteristic
  16. acm竞赛java很少,Java多线程在ACM竞赛中的应用
  17. 解决Windows开机后无启动项的问题
  18. gateway和openfeign依赖冲突
  19. 自动阅读是骗人的吗?新手一定要看,避免入坑
  20. 作文未来的计算机医生300字,未来医生的好帮手作文300字

热门文章

  1. 散度、旋度与 Laplacian
  2. Sencha-概念-Events(事件)(官网文档翻译10)
  3. red hat 5 和 oracle
  4. NYOJ 659 判断三角形
  5. nyoj 712 探寻宝藏
  6. JAVA 设计的七大原则
  7. 你知道CSS实现水平垂直居中的第10种方式吗?
  8. 洛谷P2158仪仗队(数学,观察找规律,欧拉函数)
  9. ubuntu下安装mysql及常用操作
  10. [luoguP1773] 符文之语_NOI导刊2010提高(02)(DP)