前言
VBO和VAO是OpenGL中非常重要的概念,这里先解释一下是什么意思:
顶点数组对象:Vertex Array Object,VAO
顶点缓冲对象:Vertex Buffer Object,VBO
初学者很容易弄错两者的关系 刚开始我也弄错了QAQ,这里就来详细解释一下:
VBO
全称Vertex Buffer Object,是用来储存顶点数据的,我们知道:将数据从CPU发送到显卡是非常慢的,所以,就需要这样一个东西,将顶点数据一次性发送到显卡,提高渲染的效率,创建VBO的流程大概是这样的:
glGenBuffers(1, &VBO); // 创建一个VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定顶点数据缓存空间
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 发送数据
这里简单说一下:GL_ARRAY_BUFFER 指的是OpenGL提供的几种缓冲区中的一种,类似比较常用的还有:GL_ELEMENT_ARRAY_BUFFER ,这些缓冲区是用来缓存待发送的数据的,当数据全部复制到缓冲区GL_ARRAY_BUFFER ~(即 glBindBuffer(GL_ARRAY_BUFFER, VBO); )~ 之后,再通过 glBufferData 发送数据到显卡上,这样就完成了一次高效的数据传输。
VAO
接着就是 Vertex Array Object ,我们用VBO向显卡发送了数据,但是显卡并不知道这些数据是干嘛的,以及怎么使用这些数据,这时候就需要VAO来描述这些数据了,VAO还有一个好处,一个VAO可以对应多个VBO,这样绘制起来就很方便。
注意:OpenGL的核心模式要求我们使用VAO,所以它知道该如何处理我们的顶点输入。如果我们绑定VAO失败,OpenGL会拒绝绘制任何东西。
同样,创建一个VAO也很简单:
glGenVertexArrays(1, &VAO); // 创建一个VAO
glBindVertexArray(VAO); // 绑定VAO
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // 利用VAO描述顶点属性
glEnableVertexAttribArray(0); // 启用着色器中的顶点属性
整合
将上面所说的整合成一个类就是这样的:
注:BasicShader是用来编译着色器的。
class BasicDraw
{
public:
~BasicDraw() {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO_Vertex);
glDeleteBuffers(1, &VBO_color);
}
// 初始化绘图==>创建VAO
unsigned int Get_STATIC_VAO(float vertices[],int size_vertices, float color[], int size_color) {
// 创建VBO和VAO
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO_Vertex); // 创建顶点和颜色的VBO
glGenBuffers(1, &VBO_color);
// 绑定VAO,这代表解绑这钱所有数据都会存到这个VAO中
glBindVertexArray(VAO);
// 提交数据
/* 顶点VBO */
glBindBuffer(GL_ARRAY_BUFFER, VBO_Vertex); // 绑定顶点数据缓存空间
glBufferData(GL_ARRAY_BUFFER, size_vertices, vertices, GL_STATIC_DRAW);
// 解析VBO中的数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// 启用顶点属性==>即着色器中(location=0)的顶点属性
glEnableVertexAttribArray(0);
/* 颜色VBO */
glBindBuffer(GL_ARRAY_BUFFER, VBO_color);
glBufferData(GL_ARRAY_BUFFER, size_color, color, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
// 解绑VBO==>因为已经将数据发送到显卡了,所以可以安全的解绑
glBindBuffer(GL_ARRAY_BUFFER, 0);
// 解绑VAO
glBindVertexArray(0);
return VAO;
}
private:
unsigned int VBO_Vertex, VBO_color, VAO;
};
顶点数据
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
GLfloat colors[] = {
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
特别注意!
如果是通过类来实现绘制功能,需要在参数里加上数组的大小,不然就会找俩小时错误都不知道错在哪QAQ,因为sizeof(ptr)一定是8字节,所以一定会出错!!!学的教训啊QAQ