GLES 顶点缓冲区对象(VBO)

可能大家经常从别人口中听到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)

相关文章:

你感兴趣的文章:

标签云: