最近对程序中绘制卡顿的问题忍无可忍,终于决定下手处理了。程序涉及的绘制比较多,除了点、线、三角形、多边形、圆柱体之外,还有自组格式模型。开始想全部采用显示列表优化,毕竟效率最高,虽然显示列表存在编译之后不能更改的缺点,但是程序中更改模型的情况不多,更改每个类别的模型后重新加载该类别的显示列表就行了。

1.显示列表+顶点数组

显示列表的使用就不赘述了。主要想说一下配合顶点数组使用显示列表,可以带来更大的性能提升。对于三角网格和基于顶点的自组格式模型来说,摒弃一个个三角形画吧,效果绝对令你满意!当然,这么做的前提应该是顶点vertex在不同三角形中的属性相同(法线、颜色……)

list = glGenLists(1);
glNewList(list);

……
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);

glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);//纹理

glTexCoordPointer(2,GL_FLOAT,0,textures);

glColorPointer(3,GL_FLOAT,0,colors);//颜色 nTri*3

glNormalPointer(GL_FLOAT,0,normals);//法线 nTri*3
glVertexPointer(3,GL_FLOAT,0,vertexs);//顶点 nVer
glDrawElements(GL_TRIANGLES,nTri*3,GL_UNSIGNED_INT,iIndex);//索引 nTri*3

glEndList();

2.VBO(vertex buffer object)+VAO(vertex array object)

  另一个选择是采用VBO进行绘制。VBO的好处是采用将数据提交到高速缓存的同时还保留数据的存取入口,可以直接获取并更新数据。VBO有两种方式,一种是使用glEnableClientState进行绘制,另一种就是组合VAO进行使用,也就是将对应不同属性的多组VBO存储到同一个VAO中(在渲染的时候可以少写很多代码)。

关于两种方式的取舍在这篇文章里面有介绍(http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html),这里我使用了第二种方式,也就是VBO+VAO进行使用。

GLuint vao;
GLuint vbo;

……

//初始化代码
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);//当前VAO 到glBindVertexArray(NULL)之间的vbo等都成为该vao的属性  
//
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER,12 * 3 * sizeof(float),vertexs,GL_STATIC_DRAW);//此处点坐标按照每个四边形四个点进行存入
glEnableVertexAttribArray(0); //坐标
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER,NULL);
//
glBindVertexArray(NULL);
glBindBuffer(GL_ARRAY_BUFFER,NULL);

……

//渲染代码

glBindVertexArray(vbo);
glDrawArrays(GL_QUADS,0,4);

glBindVertexArray(vbo);

之后突然想到,VA的使用中,共用顶点的索引方式index会比直接每个多边形顶点暴力存储效率高很多。所以查了下,果然有关于索引的用法:

---IBO(http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/)

其实就是VBO的方式运用索引而已,GL_ELEMENT_ARRAY_BUFFER。经过修改,代码就变成了下面的样式:

GLuint vao;

……

glGenVertexArrays(1,&vao);
glBindVertexArray(vao);//当前VAO 到glBindVertexArray(NULL)之间的vbo等都成为该vao的属性  
//
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER,nVert * 3 * sizeof(float),vertexs,GL_STATIC_DRAW);
glEnableVertexAttribArray(0); //坐标
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER,NULL);
//
GLuint colorVbo;//
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER,nVert * 3 * sizeof(float),colors,GL_STATIC_DRAW);
glEnableVertexAttribArray(1); //颜色
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER,NULL);
//
GLuint normalVbo;//
glGenBuffers(1, &normalVbo);
glBindBuffer(GL_ARRAY_BUFFER, normalVbo);
glBufferData(GL_ARRAY_BUFFER,nVert * 3 * sizeof(float),normals,GL_STATIC_DRAW);
glEnableVertexAttribArray(2); //法线
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER,NULL);
//
GLuint ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,nElem * 4 * sizeof(short), index,GL_STATIC_DRAW);//由于是绘制六棱柱侧面,nElem = nVert/2
//
glBindVertexArray(NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
glBindBuffer(GL_ARRAY_BUFFER,NULL);

渲染部分代码稍作改变

glBindVertexArray(vao);
glDrawElements(GL_QUADS,24, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(NULL);

3.目前存在的问题

  (1)由于我的程序仍在opengl 2.0下写的,并没有采用shader和GLSL,要做的事情实在太多,明知道需要学习,但还是无法在技术上投入太多时间。

  (2)在上面VAO+VBO+IBO版的代码中遇到了一个问题:颜色没有设置成功(法线没问题),不知为何,仍在寻找中。如果有高手看到烦请赐教。

  (3)关于VBO的更新:目前还没测试更新的效率。GL_STATIC_DRAW之后两种更新方式(复制和直接给出内存映射地址)貌似都需要重新设置/更新数据,还未测试GL_DYNAMIC_DRAW的使用效率。

  (4)对其后台机制还是模棱两可。还是那句话,烦请高手赐教!也欢迎新手讨论!

VAO VBO IBO大乱炖的更多相关文章

  1. opengl中VAO,VBO,IBO用法小结(zz) 【转】

    http://cowboy.1988.blog.163.com/blog/static/751057982014380251300/ opengl中VAO,VBO,IBO用法小结 这三个玩意全面取代旧 ...

  2. opengl中VAO,VBO,IBO用法小结【转】

    http://cowboy.1988.blog.163.com/blog/static/751057982014380251300/ opengl中VAO,VBO,IBO用法小结 这三个玩意全面取代旧 ...

  3. HTM CSS 笔记乱炖

    一.常用实体(字符转义) '<' == '<' '©' == '©' '>' == '>' '"' == '"' ' ' == ' ' '®' == '®' ...

  4. OpenGL ES 2: debugging, and improvements to VAO, VBO

    OpenGL ES 2: debugging, and improvements to VAO, VBO http://www.altdevblogaday.com/2013/10/12/opengl ...

  5. GridView的 PreRender事件与 RowCreated、RowDataBound事件大乱斗

    GridView的 PreRender事件与 RowCreated.RowDataBound事件大乱斗 之前写了几个范例,做了GridView的 PreRender事件与 RowCreated.Row ...

  6. python红蓝英雄大乱斗(面向对象实现)

    红蓝英雄大乱斗 游戏规则 ''' 有红蓝两方英雄(可自定义个数) 随机一方英雄使用随机攻击方式攻击另一方英雄,任意一方英雄全部阵亡则游戏结束 每个英雄有 名字.生命值.普通攻击.Q技能攻击.W技能攻击 ...

  7. OpenGL渲染管道,Shader,VAO&VBO&EBO

    OpenGL渲染管线 (也就是)OpenGL渲染一帧图形的流程 以下列举最简单的,渲染一个三角形的流程,你可以将它视为 精简版OpenGL渲染管线 更复杂的流程也仅仅就是:在此基础上的各个流程中 添加 ...

  8. openGL 提升渲染性能 之 顶点数组 VBO IBO VAO

    使用openGL图形库绘制,都需要通过openGL接口向图像显卡提交顶点数据,显卡根据提交的数据绘制出相应的图形. openGL绘制方式有:直接模式,显示列表,顶点数组,顶点索引. 直接模式:最简单, ...

  9. OpenGL中VA,VAO,VBO和EBO的区别

    1,顶点数组(Vertex Array) VA,顶点数组也是收集好所有的顶点,一次性发送给GPU.不过数据不是存储于GPU中的,绘制速度上没有显示列表快,优点是可以修改数据. 4.VBO(Vertex ...

随机推荐

  1. WinForm DataGridView增删改查

    DataGridView连接数据库对表进行增删改查 一.绑定数据源 //做一个变量控制页面刷新 ; public Form1() { InitializeComponent(); } private ...

  2. TimSort算法分析

    Timsort是一种混合稳定的排序算法,采用归并排序混合插入排序的设计,在多种真实数据上表现良好. 它基于一个简单的事实,实际中大部分数据都是部分有序(升序或降序)的. 它于2002年由Tim Pet ...

  3. Jenkins的插件

    Jenkins不仅自己为大家提供了很多功能,而且还支持插件.用户可以根据自己的需要安装插件,或者是自己开发插件. 这里说一下Jenkins的插件的安装方法: 首先,打开Jenkins首页,选择Jenk ...

  4. pom.xml配置详解

    <!--可以免费转载,转载时请注明出处  http://pengqb.iteye.com .--><project xmlns="http://maven.apache.o ...

  5. .NET Core在WindowsServer服务器部署及发布

    VS使用WEB DEPLOY发布.NET Core程序   背景是这样的,公司有两台服务器,平时一台备用,另一台做为主生产机器.当有大量补丁或者安装什么东西需要重启的时候,交其中一台直接关掉IIS,然 ...

  6. 内网穿透+VS2015自带IIS express实现本地调试(微信等需要将开发环境暴漏到外网的情况使用)

    今天一个兼职结束了,又要开始寻找新的兼职公司了 ,为了贴补家用啊,为了给儿子更好的生活加油! 抒情完毕进入正题,本篇文章要解决的问题是其实在开发微信支付,微信公众号等回调地址必须是外网可访问的80端口 ...

  7. setTimeout()和setInterval()的用法

    JS里设定延时: 使用SetInterval和设定延时函数setTimeout 很类似.setTimeout 运用在延迟一段时间,再进行某项操作. setTimeout("function& ...

  8. 一次MySQL死锁问题解决

    一次MySQL死锁问题解决 一.环境 CentOS, MySQL 5.6.21-70, JPA 问题场景:系统有定时批量更新数据状态操作,每次更新上千条记录,表中总记录数约为500W左右. 二.错误日 ...

  9. 杭电OJ2005——第几天

    /*第几天?Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  10. 每天一个linux命令(37)--iostat命令

    Linux 系统中的iostat是I/O statistics (输入/输出统计)的缩写,iostat工具将对系统的磁盘操作活动进行监视.它的特点是汇报磁盘活动统计情况,同时也会汇报出CPU使用情况. ...