您的位置:首页 > 运维架构

OpenGL缓冲区对象之VAO

2016-12-07 09:52 483 查看

简介

VAO ( Vertex Array Object )是OpenGL用来处理顶点数据的一个缓冲区对象,它不能单独使用,都是结合VBO来一起使用的。VAO是OpenGL CoreProfile 引入的一个特性。事实上在CoreProfile中做顶点数据传入时,必须使用VAO方式。当我们使用VBO传入顶点数据时,一般的处理如下:
// 绑定VBO,设置VBO中的数据
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 1. 设置顶点属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 2. 使用Shader程序
glUseProgram(shaderProgram);
// 3. 绘制
someOpenGLFunctionThatDrawsOurTriangle();
每当我们绘制一个几何体时,我们需要重复同样的工作(首先绑定缓冲区、然后设置顶点属性)。当需要绘制的物体很多时,这个过程就显得有些耗时。那么我们有没有一种方式来简化这一过程呢?这就是VAO做的事情,它将所有顶点绘制过程中的这些设置和绑定过程集中存储在一起,当我们需要时,只需要使用相应的VAO即可。VAO的这种方式有点像一个中介,把所有繁琐的绑定和顶点设置工作都集中起来处理,我们需要绘制时,直接找这个中介就好了。

VAO包含的内容

VAO对象中存储的内容包括:1. VAO开启或者关闭的状态(
glEnableVertexAttribArray
glDisableVertexAttribArray
)2. 使用
glVertexAttribPointer
对顶点属性进行的设置3. 存储顶点数据的VBO对象

VAO的使用

1.创建VAO

创建VAO使用
glGenVertexArrays
参数与创建其他缓冲区对象的glGenBuffers类似
void glGenVertexArrays( GLsizei n,
GLuint *arrays);

2.绑定并设置VAO

在创建VAO之后,需要使用
glBindVertexArray
设置它为当前操作的VAO,之后我们所有关于顶点数据的设置(包括数据使用的VBO对象,顶点的属性设置的信息都会被存储在VAO之中),在设置完成之后一般会解绑VAO,然后在需要绘制的时候启用相应的VAO对象。具体的代码如下所示:
//创建VAO
GLuint VAO;
glGenVertexArrays(1, &VAO);
//设置当前VAO,之后所有操作(注意:这些操作必须是上文VAO中包含的内容所注明的调用,其他非VAO中存储的内容即使调用了也不会影响VAO)存储在该VAO中
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO); //设置了VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//设置VBO中的数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); //设置顶点属性(索引为0的属性,与shader中的内容有交互)
glEnableVertexAttribArray(0); //设置开启顶点属性(索引为0的属性,与shader中的内容有交互)
glBindVertexArray(0); //解绑VAO(解绑主要是为了不影响后续VAO的设置,有点类似于C++中指针delete后置空,是个好习惯
通过上面的代码就完成了对VAO的设置,当我们需要绘制的时候,使用的代码类似于:
glUseProgram(shaderProgram);glBindVertexArray(VAO); //绑定我们需要的VAO,会导致上面所有VAO保存的设置自动设置完成someOpenGLFunctionThatDrawsOurTriangle();glBindVertexArray(0);   //解绑VAO
另外需要注意的是,当我们使用EBO的时候,VAO中也会记录索引信息,因此完整的VAO所包含的内容图如下所示(添加了EBO):

示例程序

#pragma comment(lib, "glew32.lib")#pragma comment(lib, "freeglut.lib")#include <stdio.h>#include <iostream>#include <gl/glew.h>#include <gl/glut.h>GLuint eboID;GLuint vboID;GLuint vaoID;GLuint shaderProgram;const GLchar* vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 position;\n""void main()\n""{\n""gl_Position = vec4(position.x, position.y, position.z, 1.0);\n""}\0";const GLchar* fragmentShaderSource = "#version 330 core\n""out vec4 color;\n""void main()\n""{\n""color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""}\n\0";GLfloat vertices[] = {0.5f, 0.5f, -1.0f,   // 右上角0.5f, -0.5f, -1.0f,  // 右下角-0.5f, -0.5f, -1.0f, // 左下角-0.5f, 0.5f, -1.0f   // 左上角};GLuint indices[] = {// 起始于0!0, 1, 3, // 第一个三角形1, 2, 3  // 第二个三角形};void ChangeSize(int w, int h){if (h == 0)h = 1;glViewport(0, 0, w, h);}void initShaders(){// Build and compile our shader program// Vertex shaderGLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// Check for compile time errorsGLint success;GLchar infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// Fragment shaderGLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// Check for compile time errorsglGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// Link shadersGLuint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// Check for linking errorsglGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);}void SetupRC(){glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glGenBuffers(1, &eboID);glGenBuffers(1, &vboID);glGenVertexArrays(1, &vaoID);//首先绑定vaoID,之后所有设置都存储在vaoID中glBindVertexArray(vaoID);glBindBuffer(GL_ARRAY_BUFFER, vboID);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);//注意:这里是可以的,因为glVertexAttribPointer将注册eboID作为它的VBO,因此这里可以安全的解绑glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);initShaders();}void RenderScene(void){glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();glUseProgram(shaderProgram);glBindVertexArray(vaoID);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glBindVertexArray(0);glutSwapBuffers();}int main(int argc, char* argv[]){glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);glutInitWindowSize(800, 600);glutCreateWindow("OpenGL");glutReshapeFunc(ChangeSize);glutDisplayFunc(RenderScene);GLenum err = glewInit();if (GLEW_OK != err) {fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));return 1;}SetupRC();glutMainLoop();glDeleteVertexArrays(1, &vaoID);glDeleteBuffers(1, &vboID);glDeleteBuffers(1, &eboID);return 0;}

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: