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,				//v0
		1.0f,0.0f,0.0f,1.0f,			//c0

		-1.0f,-0.5f,0.0f,				//v1
		0.0f,1.0f,0.0f,1.0f,			//c1

		0.0f,-0.5f,0.0f,				//v2
		0.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 1

typedef 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,				//v0
		1.0f,0.0f,0.0f,1.0f,			//c0

		-1.0f,-0.5f,0.0f,				//v1
		0.0f,1.0f,0.0f,1.0f,			//c1

		0.0f,-0.5f,0.0f,				//v2
		0.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的


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenGL ES(GLES)中,深度缓冲区和模板缓冲区是两种不同的缓冲区,通常需要分开创建。 深度缓冲区用于存储每个像素的深度值,以便进行深度测试。它在绘制过程中记录了每个像素离相机的距离。深度缓冲区需要使用特定的格式和精度,以确保正确的深度测试结果,例如GL_DEPTH_COMPONENT和GL_DEPTH_COMPONENT16。创建深度缓冲区时,可以使用glRenderbufferStorage或glTexImage2D函数分配存储空间。 模板缓冲区用于存储每个像素的模板值,通常用于实现诸如遮罩(masking)和抠图(stenciling)等技术。它记录了每个像素的特定标识,可以用于后续的渲染操作。模板缓冲区同样需要使用特定的格式和精度,例如GL_STENCIL_INDEX和GL_STENCIL_INDEX8。创建模板缓冲区时,可以使用glRenderbufferStorage或glTexImage2D函数分配存储空间。 虽然深度缓冲区和模板缓冲区可以分别创建,但它们也可以共享同一个缓冲区。这意味着可以使用同一个缓冲区来记录像素的深度值和模板值,以减少内存占用和渲染操作的开销。在这种情况下,创建缓冲区时需要使用包括GL_DEPTH_STENCIL或GL_DEPTH24_STENCIL8在内的特殊格式。 总而言之,GLES中的深度缓冲区和模板缓冲区通常需要分开创建,但也可以共享同一个缓冲区来实现更高效的渲染。具体使用哪种方式取决于特定的应用需求和硬件支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值