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;}
相关文章推荐
- OpenGL缓冲区对象之VAO
- OpenGL缓冲区对象之VAO
- OpenGL系列教程之八:OpenGL顶点缓冲区对象(VBO)
- opengl缓冲区对象,glBufferSubData,glMapBuffer
- OpenGL缓冲区对象之VBO
- [OpenGL] 高级着色器应用之 统一缓冲区对象(Uniform Buffer Object)
- OpenGL系列教程之九:OpenGL像素缓冲区对象(PBO)
- OPenGL中的缓冲区对象
- OpenGL顶点缓冲区对象(VBO)
- opengl缓冲区对象
- OpenGL深入探索——像素缓冲区对象 (PBO)
- OpenGL缓冲区对象
- OpenGL缓冲区对象之UBO
- OPenGL中的缓冲区对象
- OpenGL像素缓冲区对象
- OpenGL缓冲区对象之EBO
- OpenGL顶点缓冲区对象(VBO)
- OpenGL缓冲区对象之UBO
- OpenGL离线渲染和缓冲区对象
- OpenGL像素缓冲区对象