VAO、VBO介绍
随着OpenGL状态和固定管线模式的移除,我们不在用任何glEnable函数调用,而且也不会有glVertex、glColor等函数调用。这就意味着我们需要一种新的方式来将数据传输到图形卡以渲染图形。我们可以采用VBO,或者是在OpenGL3以上版本引入的新的特性,叫做VAO。通过它,我们可以把顶点数据和颜色存储在不同的VBO中,但是在同一个VAO中。对于法线数据或者其他的顶点信息也是一样。
VAO,是这样一种方式:把对象信息直接存储在图形卡中,而不是在当我们需要的时候传输到图形卡。这就是Direct3D所采用得方式,而在OpenGL中只有OpenGL3.X以上的版本中采用。这就意味着我们的应用程序不用将数据传输到图形卡或者是从图形卡输出,这样也就获得了额外的性能提升。
使用VAO并不难。我们不需要大量的glVertex调用,而是把顶点数据存储在数组中,然后放进VBO,最后在VAO中存储相关的状态。记住:VAO中并没有存储顶点的相关属性数据。OpenGL会在后台为我们完成其他的功能。
主要代码
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint NumVertices = 6;
void init()
{
glGenVertexArrays(NumVAOs, VAOs);
glBindVertexArray(VAOs[Triangles]);
GLfloat vertices[NumVertices][2] = {
{ -0.90f, -0.90f },
{ 0.85f, -0.90f },
{ -0.90f, 0.85f },
{ 0.90f, -0.85f },
{ 0.90f, 0.90f },
{ -0.85f, 0.90f },
};
glGenBuffers(NumBuffers, Buffers);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "triangles.vert" },
{ GL_FRAGMENT_SHADER, "triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders(shaders);
glUseProgram(program);
#define BUFFER_OFFSET(offset) ((void *)(offset))
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(vPosition);
}
主要API介绍
void glGenVertexArrays(GLSize n, GLuint *arrays);
返回n个当前未使用的名字,用作数组arrays中的顶点数组对象,
创建了VAO以后,需要初始化新的对象,并且把要使用的顶点数组数据的对象的集合与单个已分配的对象关联起来,
GLvoid glBingVertexArray(GLuint array);
glBingVertexArray做了三件事:
1. 当使用的值array不是零并且是从glGenVertexArrays()返回的值时,创建一个新的VAO,并且分配该名字;
2. 当绑定到之前创建的一个VAO的时候,该VAO就是当前活动的;
3. 当绑定到一个为0的数组时,就停止使用VAO,并且返回顶点数组的默认状态。
如果array不是之前从glGenVertexArray返回的值,如果是glDeleteVertexArray()已经释放的值,如果调用任何一个gl*Pointer()函数来指定一个顶点数组,而在绑定一个非0VAO的时候,它没有和缓冲区对象关联起来,将会返回GL_INVALID_OPERATION错误。
这个函数是绑定VAO到上下文,并没有像glBindBuffer那样take a target。
void glVertexAttribPointer()
首先要清楚关联a buffer object和 a vertex attribute的操作:
并不发生在函数glBindBuffer(GL_ARRAY_BUFFER),而是发生在glVertexAttribPointer();
当你调用glVertexAttribPointer() ,OpenGL 获取缓冲区绑定到GL_ARRAY_BUFFER并且关联顶点属性,想象一下GL_ARRAY_BUFFER就像一个全局指针
绘制代码
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
//绑定到上下文,告诉OPENGL要使用这个VAO
glBindVertexArray(VAOs[Triangles]);
glDrawArrays(GL_TRIANGLES, 0, NumVertices);
glFlush();
}