OpenGL编程指南6:顶点数组
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:顶点数组相关推荐
- 《OpenGL编程指南(原书第8版)》——计算着色器
原文 http://www.csdn.net/article/2014-11-21/2822754 主题 OpenGL 数学 概述 由于图形处理器每秒能够进行数以亿计次的计算,它已成为一种性能十分惊 ...
- 《OpenGL编程指南》一3.2 OpenGL缓存数据
本节书摘来自华章出版社<OpenGL编程指南>一书中的第3章,第3.2节,作者 Bill Licea-Kane ,更多章节内容可以访问云栖社区"华章计算机"公众号查看 ...
- OpenGL深入探索——《OpenGL编程指南(原书第8版)》——计算着色器
转载自 <OpenGL编程指南(原书第8版)>--计算着色器 概述 由于图形处理器每秒能够进行数以亿计次的计算,它已成为一种性能十分惊人的器件.过去,这种处理器主要被设计用于承担实时图形渲 ...
- OpenGl编程指南例2.4大白话分析
OpenGl编程指南例2.4分析 即上一篇文章搭建了opengl的环境后,继续学习Opengl,被第二章的各种gen,bind,buffer搞得晕头转向,在还没有消化完全的时候,又被一计重击打到--为 ...
- OpenGL编程指南7:视图-
1.前言 计算机图形学的要点就是创建三维物体的二维图像(图像必须是二维的,因为他是在平面的屏幕上显示的).但是,当我们决定怎样在屏幕上绘图时,必须使用三维坐标的方式考虑. 为了把一个物体的三维坐标变成 ...
- OpenGL编程指南4:双缓冲实现运行
1.前言 绘制一个旋转的方块,主要为了说明glutSwapBuffers()函数的用法. 同时也为了学习如何使用GLUT控制输入设备,并打开或关闭空闲处理函数. 2.OpenGL编程及程序剖析 /** ...
- 《OpenGL编程指南》一第3章 OpenGL绘制方式
本节书摘来自华章出版社<OpenGL编程指南>一书中的第3章,作者 Bill Licea-Kane ,更多章节内容可以访问云栖社区"华章计算机"公众号查看 第3章 Op ...
- OpenGL编程指南8-Transform Feedback例子理解
transform feedback 是,OpenGL管线中,的,顶点处理阶段结束之后,图元装配和光栅化之前的一个步骤.transform feedback,可以重新捕获即将装配为图元(点.线段.三角 ...
- 《OpenGL编程指南》一第2章 着色器基础
本节书摘来自华章出版社<OpenGL编程指南>一书中的第2章,作者 Bill Licea-Kane ,更多章节内容可以访问云栖社区"华章计算机"公众号查看 第2章 着色 ...
最新文章
- 亚马逊:从零售商向科技公司的质变
- 关于手风琴效果延迟执行解决方式
- 文巾解题 180. 连续出现的数字
- 【视频课】深度学习必备基础,如何使用好数据?
- [LeetCode] Two Sum
- 几个重要库函数的实现
- 考教育统计与测量可以带哪种计算机,《教育统计与测量》练习题库及答案
- U-Net++粗略解释
- Linux设置ssh免密码登录
- 【转】格雷斯特(Glest)Glest(开源RTS游戏)编译备忘
- AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中?
- C语言实现成语接龙完整版
- 中职学校计算机专业课程设置,中职学校计算机专业课程设置的几点思考
- struts中ActionForm有什么作用?
- BLE service, characteristic
- acm竞赛java很少,Java多线程在ACM竞赛中的应用
- 解决Windows开机后无启动项的问题
- gateway和openfeign依赖冲突
- 自动阅读是骗人的吗?新手一定要看,避免入坑
- 作文未来的计算机医生300字,未来医生的好帮手作文300字