可能大家经常从别人口中听到VBO,不知道是什么意思,觉得高大上的样子,但是如果知道中文名称,应该能明白一二。

VBO,即顶点缓冲区对象。

使用顶点数组时,指定的顶点数据保存在系统内存中,在进行glDrawArrays 或者glDrawElements 的时候,需要把这些顶点数据复制到显卡内存。

很麻烦。其实我们想想,直接把顶点数据保存在显卡内存中,这样不是就免去了复制这一步操作。这种方法可以改进渲染性能,而且降低了内存带宽消耗。

在使用VBO之前,我们需要申请分配缓冲区对象,并且将顶点数据和元素索引上传到对应的缓冲区对象。

下面的例子来说明使用方式:

//创建和绑定顶点缓冲区对象(VBO);
void InitVertexBufferObjects(float* vertexBuffer,GLushort* indices,GLuint numVertices,GLuint numIndices,GLuint* vboIds)
{glGenBuffers(2,vboIds);        //申请两块缓冲区,一个用于保存实际顶点数据,一个用于保存组成图元的元素索引;glBindBuffer(GL_ARRAY_BUFFER,vboIds[0]); //指定当前缓冲区对象;glBufferData(GL_ARRAY_BUFFER,numVertices*sizeof(float),vertexBuffer,GL_STATIC_DRAW);//创建和初始化数据存储;glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vboIds[1]);glBufferData(GL_ELEMENT_ARRAY_BUFFER,numIndices*sizeof(float),indices,GL_STATIC_DRAW);}

下面来看看,不使用VBO和使用VBO 进行图元绘制的不同操作:

//不使用VBO来绘制图元,使用顶点数组-结构数组;
void DrawPrimitiveWithoutVBOs(GLfloat* vertices,GLint vtxStride,GLint numIndices,GLushort* indices)
{GLfloat *vertexBuffer=vertices;glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);glEnableVertexAttribArray(VERTEX_POS_INDX);            //允许顶点数组;glEnableVertexAttribArray(VERTEX_COLOR_INDX);glVertexAttribPointer(VERTEX_POS_INDX,VERTEX_POS_SIZE,GL_FLOAT,GL_FALSE,vtxStride,vertexBuffer);//顶点数组;vertexBuffer=vertexBuffer+VERTEX_POS_SIZE; //偏移;glVertexAttribPointer(VERTEX_COLOR_INDX,VERTEX_COLOR_SIZE,GL_FLOAT,GL_FALSE,vtxStride,vertexBuffer);glDrawElements(GL_TRIANGLES,numIndices,GL_UNSIGNED_SHORT,indices);glDisableVertexAttribArray(VERTEX_POS_INDX);glDisableVertexAttribArray(VERTEX_COLOR_INDX);
}//使用VBO来绘制图元;
void DrawPrimitiveWithVBOs(ESContext* esContext,GLint numVertices,GLfloat* vertexBuffer,GLint vtxStride,GLint numIndices,GLushort* indices)
{UserData* userData=(UserData*)esContext->userData;GLuint offset=0;if(userData->vboIds[0]==0 && userData->vboIds[1]==0){glGenBuffers(2,userData->vboIds);glBindBuffer(GL_ARRAY_BUFFER,userData->vboIds[0]);glBufferData(GL_ARRAY_BUFFER,vtxStride*numVertices,vertexBuffer,GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,userData->vboIds[1]);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*numIndices,vertexBuffer,GL_STATIC_DRAW);}glBindBuffer(GL_ARRAY_BUFFER,userData->vboIds[0]);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,userData->vboIds[1]);glEnableVertexAttribArray(VERTEX_POS_INDX);glEnableVertexAttribArray(VERTEX_COLOR_INDX);//注意开始使用VBO,最后的参数不再是vertexBuffer,而是VBO中的数据;glVertexAttribPointer(VERTEX_POS_INDX,VERTEX_POS_SIZE,GL_FLOAT,GL_FALSE,vtxStride,(const void*)offset);offset =offset+VERTEX_POS_SIZE*sizeof(float); //偏移;glVertexAttribPointer(VERTEX_COLOR_INDX,VERTEX_COLOR_SIZE,GL_FLOAT,GL_FALSE,vtxStride,(const void*)offset);glDisableVertexAttribArray(VERTEX_POS_INDX);glDisableVertexAttribArray(VERTEX_COLOR_INDX);//恢复默认绑定VBO;glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);}void Draw(ESContext* esContext)
{UserData *userData=(UserData*)esContext->userData;GLfloat vertices[3*(VERTEX_POS_SIZE+VERTEX_COLOR_SIZE)]={-0.5f,0.5f,0.0f,              //v01.0f,0.0f,0.0f,1.0f,            //c0-1.0f,-0.5f,0.0f,               //v10.0f,1.0f,0.0f,1.0f,            //c10.0f,-0.5f,0.0f,                //v20.0f,0.0f,1.0f,1.0f,            //c2};GLushort indices[3]={0,1,2};glViewport(0,0,esContext->width,esContext->height);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(userData->programObject);glUniform1f(userData->offsetLoc,0.0f);DrawPrimitiveWithoutVBOs(vertices,sizeof(GLfloat)*(VERTEX_POS_SIZE+VERTEX_COLOR_SIZE),3,indices);glUniform1f(userData->offsetLoc,1.0f);DrawPrimitiveWithVBOs(esContext,3,vertices,sizeof(GLfloat)*(VERTEX_POS_SIZE+VERTEX_COLOR_SIZE),3,indices);
}

整个代码

#include "esUtil.h"#define VERTEX_POS_SIZE 3
#define VERTEX_COLOR_SIZE 4
#define VERTEX_POS_INDX 0
#define VERTEX_COLOR_INDX 1typedef struct
{GLuint programObject; //保存GLProgram;GLuint vboIds[2];//vbo对象;GLuint offsetLoc;
} UserData;//加载Shader;
GLuint LoadShader(GLenum type,const char    *shaderSrc)
{GLuint shader;GLint compiled;shader=glCreateShader(type);if (shader==0){return 0;}glShaderSource(shader,1,&shaderSrc,NULL);glCompileShader(shader);glGetShaderiv(shader,GL_COMPILE_STATUS,&compiled);if (!compiled){GLint infoLen=0;glGetShaderiv(shader,GL_INFO_LOG_LENGTH,&infoLen);if (infoLen>1){char* infoLog=(char*)malloc(sizeof(char) * infoLen);glGetShaderInfoLog(shader,infoLen,NULL,infoLog);esLogMessage("Error Compiling Shader : %s",infoLog);free(infoLog);}glDeleteShader(shader);return 0;}return shader;
}//初始化Shader和GLProgram;
int Init(ESContext *esContext)
{UserData *userData=(UserData*)esContext->userData;char vShaderStr[]="#version 300 es\n""layout(location = 0) in vec4 a_Position;"//指定顶点属性的索引,可选,如果没有设置程序将自动分配;"layout(location = 1) in vec4 a_Color;""uniform float u_offset;""out vec4 v_Color;" //输出值到Fragment Shader;平面着色;"void main()""{""    v_Color=a_Color;""   gl_Position=a_Position;""    gl_Position.x += u_offset;""}";char fShaderStr[]="#version 300 es\n""precision mediump float;"//默认精度限定符;还有highp,lowp,mediump;"in vec4 v_Color;" //来自Vertex Shader的值;"out vec4 o_fragColor;""void main()""{""     o_fragColor=vec4(v_Color);""}";GLuint vertexShader;GLuint fragmentShader;GLuint programObject;GLint linked;vertexShader=LoadShader(GL_VERTEX_SHADER,vShaderStr);fragmentShader=LoadShader(GL_FRAGMENT_SHADER,fShaderStr);programObject=glCreateProgram();if(programObject==0){return 0;}glAttachShader(programObject,vertexShader);glAttachShader(programObject,fragmentShader);glLinkProgram(programObject);glGetProgramiv(programObject,GL_LINK_STATUS,&linked);if(!linked){GLint infoLen=0;glGetProgramiv(programObject,GL_INFO_LOG_LENGTH,&infoLen);if(infoLen>1){char* infoLog=(char*)malloc(sizeof(char)*infoLen);glGetProgramInfoLog(programObject,infoLen,NULL,infoLog);esLogMessage("Error linking program : %s \n",infoLog);free(infoLog);}glDeleteProgram(programObject);return 0;}userData->programObject=programObject;userData->offsetLoc=glGetUniformLocation(programObject,"u_offset");userData->vboIds[0]=0;userData->vboIds[1]=0;glClearColor(1.0f,1.0f,1.0f,1.0f);return 1;
}//创建和绑定顶点缓冲区对象(VBO);
void InitVertexBufferObjects(float* vertexBuffer,GLushort* indices,GLuint numVertices,GLuint numIndices,GLuint* vboIds)
{glGenBuffers(2,vboIds);        //申请两块缓冲区,一个用于保存实际顶点数据,一个用于保存组成图元的元素索引;glBindBuffer(GL_ARRAY_BUFFER,vboIds[0]); //指定当前缓冲区对象;glBufferData(GL_ARRAY_BUFFER,numVertices*sizeof(float),vertexBuffer,GL_STATIC_DRAW);//创建和初始化数据存储;glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vboIds[1]);glBufferData(GL_ELEMENT_ARRAY_BUFFER,numIndices*sizeof(float),indices,GL_STATIC_DRAW);}//不使用VBO来绘制图元,使用顶点数组-结构数组;
void DrawPrimitiveWithoutVBOs(GLfloat* vertices,GLint vtxStride,GLint numIndices,GLushort* indices)
{GLfloat *vertexBuffer=vertices;glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);glEnableVertexAttribArray(VERTEX_POS_INDX);            //允许顶点数组;glEnableVertexAttribArray(VERTEX_COLOR_INDX);glVertexAttribPointer(VERTEX_POS_INDX,VERTEX_POS_SIZE,GL_FLOAT,GL_FALSE,vtxStride,vertexBuffer);//顶点数组;vertexBuffer=vertexBuffer+VERTEX_POS_SIZE; //偏移;glVertexAttribPointer(VERTEX_COLOR_INDX,VERTEX_COLOR_SIZE,GL_FLOAT,GL_FALSE,vtxStride,vertexBuffer);glDrawElements(GL_TRIANGLES,numIndices,GL_UNSIGNED_SHORT,indices);glDisableVertexAttribArray(VERTEX_POS_INDX);glDisableVertexAttribArray(VERTEX_COLOR_INDX);
}//使用VBO来绘制图元;
void DrawPrimitiveWithVBOs(ESContext* esContext,GLint numVertices,GLfloat* vertexBuffer,GLint vtxStride,GLint numIndices,GLushort* indices)
{UserData* userData=(UserData*)esContext->userData;GLuint offset=0;if(userData->vboIds[0]==0 && userData->vboIds[1]==0){glGenBuffers(2,userData->vboIds);glBindBuffer(GL_ARRAY_BUFFER,userData->vboIds[0]);glBufferData(GL_ARRAY_BUFFER,vtxStride*numVertices,vertexBuffer,GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,userData->vboIds[1]);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*numIndices,indices,GL_STATIC_DRAW);}glBindBuffer(GL_ARRAY_BUFFER,userData->vboIds[0]);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,userData->vboIds[1]);glEnableVertexAttribArray(VERTEX_POS_INDX);glEnableVertexAttribArray(VERTEX_COLOR_INDX);//注意开始使用VBO,最后的参数不再是vertexBuffer,而是VBO中的数据;glVertexAttribPointer(VERTEX_POS_INDX,VERTEX_POS_SIZE,GL_FLOAT,GL_FALSE,vtxStride,(const void*)offset);offset =offset+VERTEX_POS_SIZE*sizeof(float); //偏移;glVertexAttribPointer(VERTEX_COLOR_INDX,VERTEX_COLOR_SIZE,GL_FLOAT,GL_FALSE,vtxStride,(const void*)offset);glDrawElements(GL_TRIANGLES,numIndices,GL_UNSIGNED_SHORT,0);glDisableVertexAttribArray(VERTEX_POS_INDX);glDisableVertexAttribArray(VERTEX_COLOR_INDX);//恢复默认绑定VBO;glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);}void Draw(ESContext* esContext)
{UserData *userData=(UserData*)esContext->userData;GLfloat vertices[3*(VERTEX_POS_SIZE+VERTEX_COLOR_SIZE)]={-0.5f,0.5f,0.0f,              //v01.0f,0.0f,0.0f,1.0f,            //c0-1.0f,-0.5f,0.0f,               //v10.0f,1.0f,0.0f,1.0f,            //c10.0f,-0.5f,0.0f,                //v20.0f,0.0f,1.0f,1.0f,            //c2};GLushort indices[3]={0,1,2};glViewport(0,0,esContext->width,esContext->height);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(userData->programObject);glUniform1f(userData->offsetLoc,0.0f);DrawPrimitiveWithoutVBOs(vertices,sizeof(GLfloat)*(VERTEX_POS_SIZE+VERTEX_COLOR_SIZE),3,indices);glUniform1f(userData->offsetLoc,1.0f);DrawPrimitiveWithVBOs(esContext,3,vertices,sizeof(GLfloat)*(VERTEX_POS_SIZE+VERTEX_COLOR_SIZE),3,indices);
}void Draw1(ESContext* esContext)
{UserData *userData=(UserData*)esContext->userData;GLfloat vVertices[]={0.0f,0.5f,0.0f,-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f};glViewport(0,0,esContext->width,esContext->height);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(userData->programObject);glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,vVertices); //顶点缓冲区0;glEnableVertexAttribArray(0);//生效顶点缓冲区0;glDrawArrays(GL_TRIANGLES,0,3);
}void ShutDown(ESContext* esContext)
{UserData *userData=(UserData*)esContext->userData;glDeleteProgram(userData->programObject);
}int esMain(ESContext* esContext)
{EGLint majorVersion;//主版本;EGLint minorVersion;//小版本;EGLDisplay display=eglGetDisplay(EGL_DEFAULT_DISPLAY);if(display==EGL_NO_DISPLAY){esLogMessage("no display");return 0;}if(!eglInitialize(display,&majorVersion,&minorVersion)){esLogMessage("eglInitialize error");return 0;}esContext->userData=malloc(sizeof(UserData));esCreateWindow(esContext,"Hello Triangle",960,640,ES_WINDOW_RGB);if(!Init(esContext)){return GL_FALSE;}esRegisterShutdownFunc(esContext,ShutDown);esRegisterDrawFunc(esContext,Draw);return GL_TRUE;
}

运行结果,左边是不使用VBO的,右边是使用VBO的

GLES 顶点缓冲区对象(VBO)相关推荐

  1. opengles 顶点数组 android,OpenGLES顶点属性、顶点数组和缓冲区对象

    顶点属性数据可以用一个顶点数组对每个顶点指定,也可以将一个常量值用于一个图元的所有顶点 OpenGLES支持最少16个顶点属性.准确查询顶点数量方法如下: GLint maxVertexAttribs ...

  2. Android OpenGL ES 3.0 PBO像素缓冲区对象

    1.什么是PBO OpenGL PBO(Pixel Buffer Object),被称为像素缓冲区对象,主要被用于异步像素传输操作.PBO 仅用于执行像素传输,不连接到纹理,且与 FBO (帧缓冲区对 ...

  3. 深入理解:顶点缓存对象(VBO)

    深入理解:顶点缓存对象(VBO) 顶点缓存对象(VBO) 深入理解:顶点缓存对象(VBO) 前言 一.创建VBO 二.绘制VBO 更新VBO 实例 源码下载 引用 前言 GL_ARB_vertex_b ...

  4. Opengl ES系列学习--顶点属性、顶点数组和缓冲区对象

    本节我们继续来看一下<OPENGL ES 3.0编程指南 原书第2版(中文版)>书中第6章的内容,PDF下载地址:OPENGL ES 3.0编程指南 原书第2版(中文版),代码下载地址:O ...

  5. 顶点缓冲区与着色器 (The Cherno + LeranOpenGL)笔记

    目录 图形渲染管线介绍 (一)顶点缓冲区 (二)VAO/VBO/IBO (三)着色器 (四)索引缓冲区 绘制矩形完整代码 : 图形渲染管线介绍 1.图形渲染管线主要被划分成两个主要部分,第一部分是把物 ...

  6. OpenGL深入探索——像素缓冲区对象 (PBO)

    英文原文地址 wiki解释 概述 OpenGL ARB_pixel_buffer_object 扩展与ARB_vertex_buffer_object.很相似.为了缓冲区对象不仅能存储顶点数据,还能存 ...

  7. OpenGL缓冲区对象之EBO

    简介 EBO(Element Buffer Object,也叫IBO:Index Buffer Object)索引缓冲区对象,这个缓冲区主要用来存储顶点的索引信息. 考虑这样一种情况,我们需要绘制一个 ...

  8. openGL 入门 2--顶点数组对象 VAO 和 缓存对象 VBO

    用户输入的数据 以 顶点数组对象表示 Vertex Array Object,VAO void glGenVertexArrays(GLsizei n, GLuint *arrays); 返回 n个 ...

  9. 红宝书阅读笔记——缓冲区对象

    前面的顶点数组使得几何图元的显示方便了很多,但是如果每次都要向OPENGL发送一大块数据,而这数据其实并没有修改过,那么这传输就是冗余的.所以这里添加了缓冲区对象,将顶点数组存储在服务器端的缓冲区对象 ...

最新文章

  1. 今日 Paper | 高效骨干搜索;学习扩充;最小人脸检测器;​DEPARA等
  2. eax ax ah al
  3. 算法基础数学知识篇(1)之----- 排列数组
  4. 页面浏览事件之 $AppViewScreen 全埋点
  5. oracle11g 01031,Oracle11g Data Guard -- ORA-16047 , ORA-16057 ,ORA-01031
  6. android 9.0的模拟器,Exagear模拟器最新版
  7. JavaBean 与 EJB 的区别
  8. 计算机组成原理——指令格式设计
  9. echarts如何画地图
  10. 基本共射放大电路的动态分析
  11. 使用 requireJS 的shim参数 解决插件jequery 插件问题
  12. 物联网NB-IoT技术商用正全面铺开 竞争日趋激烈
  13. OC语言学习——继承和多态的一些随笔记
  14. 区块链治理:用编程迎接未来
  15. 超乎认知 认知智能十大黑科技 我国首次对外公布 道翰天琼认知智能
  16. ssh远程连接发送命令行
  17. 毕业三年,初心你忘记了吗?
  18. matplotlib画多个子图
  19. office365邮箱批量添加到指定组
  20. namp扫描网络中IP、端口信息

热门文章

  1. ads-b无源定位,伪装目标检测笔记
  2. 功能繁多的一个木函, 到底什么来头?
  3. HTML超文本(一)
  4. 物联网技术实地测试:ZETA完胜LoRa,助力石油勘探
  5. 一键压缩word文档的办法,太简单了
  6. (亚马逊云)10分钟-快速启动基于 Odoo 的电商网站
  7. windows 宋体 与 vista 雅黑
  8. 柏格森:矛盾的非进化论者
  9. ArcGIS距离分析—规划最低成本路径
  10. 如何选择分光光度计参比溶液,有技巧可寻