openGL关于VAO和VBO和EBO的区分和理解

1.VBO

VBO为顶点缓冲对象,是显卡存储空间中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法向量,顶点颜色数据等。在渲染时,可以直接从VBO中取出顶点的各类属性数据。
所以可以理解为VBO就是显存中的一个存储区域,可以保持大量的顶点属性信息。并且可以开辟很多个VBO,每个VBO在OpenGL中有它的唯一标识ID,这个ID对应着具体的VBO的显存地址,通过这个ID可以对特定的VBO内的数据进行存取操作。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

如上图,定义两个vbo,我们绘制vbo数据下的三角形,但是出现的却是vbo2下的三角形,为什么呢?
因为,我们在绘制前,已经定义了显存中位置0的地方指向的是内存vbo,但是后面我们又把位置显存中位置0的地方指向给了vbo2,所以我们看到的就是最后一个三角形。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); //从layout为0开始,一个顶点包含三个数据,跨6个顶点为一组,从开头为0读取

那么怎么解决这个问题呢?
在这里插入图片描述

在这里插入图片描述
如上,只需要我们在绘制的时候指定一个临时的显存位置来绘制,就可以看到绘制的三角形为正常的了。

1.VAO

VAO中定义了顶点的属性,每一种属性有特定的读取VBO的方法,它相当于是一个VBO数据对象的集合,使用glVertexAttribPointer对顶点属性进行的设置,这样我们就知道某一个vbo应该具体的是哪一些信息。如图:

在这里插入图片描述
这里就可以解决上面vbo绘制两个三角形时,永远出现的最后一个的问题,如下代码:
在这里插入图片描述
在这里插入图片描述
这个时候,我们看到的就是,他绘制为第一个三角形。

EBO

举个例子:假设我们绘制一个矩形。我们就可以绘制两个三角形来组成一个矩形。这样我们就需要六个顶点集合,并且会有两个重合的顶点(左下角和右上角的点)。这样当顶点变多时,会产生很大的浪费。所以最好的解决办法是每个顶点只存一次,当我们需要使用这些顶点时,只调用顶点的索引。
EBO中存储的内容就是顶点位置的索引indices,EBO跟VBO类似,也是在显存中的一块内存缓冲器,只不过EBO保存的是顶点的索引。
在这里插入图片描述

当用EBO绑定顶点索引的方式绘制模型时,需要使用glDrawElements而不是glDrawArrays: glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

  • 第一个参数指定了要绘制的模式;
  • 第二个参数指定要绘制的顶点个数;
  • 第三个参数是索引的数据类型;
  • 第四个参数是可选的EBO中偏移量设定。
    如下,使用EBO绘制两个三角形组成的矩形:
//使用EBO绘制矩形(两个三角形)
#include <GL/glew.h>  
#include <GL/freeglut.h>  
 
void userInit();  //自定义初始化
void reshape(int w, int h);   //重绘
void display(void);
void keyboardAction(unsigned char key, int x, int y);   //键盘退出事件
 
GLuint eboId;//element buffer object句柄    
GLuint vboId;//vertext buffer object句柄    
GLuint vaoId;//vertext array object句柄    
 
int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(512, 512);
	glutCreateWindow("Rectangle demo");
 
	//使用glew,需要执行glewInit,不然运行过程会报错
	//glewInit要放在glut完成了基本的初始化之后执行
	glewInit();
 
	//自定义初始化,生成VAO,VBO,EBO
	userInit();
 
	//重绘函数
	glutReshapeFunc(reshape);
	glutDisplayFunc(display);
	//注册键盘按键退出事件
	glutKeyboardFunc(keyboardAction);
	glutMainLoop();
	return 0;
}
 
//自定义初始化函数    
void userInit()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
 
	//创建顶点数据    
	const GLfloat vertices[] = {
		-0.5f,-0.5f,0.0f,1.0f,
		0.5f,-0.5f,0.0f,1.0f,
		0.5f,0.5f,0.0f,1.0f,
		-0.5f,0.5f,0.0f,1.0f,
	};
	// 索引数据
	GLshort indices[] = {
		0, 1, 3,  // 第一个三角形
		1, 2, 3   // 第二个三角形
	};
 
	//创建VAO对象
	glGenVertexArrays(1, &vaoId);
	glBindVertexArray(vaoId);
 
	//创建VBO对象,把顶点数组复制到一个顶点缓冲中,供OpenGL使用
	glGenBuffers(1, &vboId);
	glBindBuffer(GL_ARRAY_BUFFER, vboId);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
 
	//创建EBO对象	
	glGenBuffers(1, &eboId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
	//传入EBO数据
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
 
	//解释顶点数据方式
	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);
 
	//解绑VAO
	glBindVertexArray(0);
	//解绑EBO
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	//解绑VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}
 
//调整窗口大小回调函数    
void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}
 
//绘制回调函数    
void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	//绑定VAO
	glBindVertexArray(vaoId);
	//绘制模型
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
	glutSwapBuffers();
}
 
//键盘按键回调函数    
void keyboardAction(unsigned char key, int x, int y)
{
	switch (key)
	{
	case 033:  // Escape key    
		exit(EXIT_SUCCESS);
		break;
	}
}

把一个矩形拆分在六个顶点的三角形,分别为0,1,2,1,2,3再绘制
在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值