本篇主要介绍vao对象的创建及其使用,通过本篇学习,希望大家能熟悉怎么为vertex shader提供各种输入。vao(vertex array object)是OpenGL中的一个非常基本的数据类型,代表vertex shader 的输入,可以把van对象当成一个媒介,一方面,该对象内部提供很多的binding point可以绑定自定义的vbo对象,另一方面,该对象提供了很多attribute index对应 vertex shader的输入变量,openGL提供接口可以将一个shader的输入和一个vbo对象连接起来。具体来说,使用分以下几个步骤:
1 vao对象的创建,方法如下:
GLuint vao
glCreateVertexArrays(1,&vao)
glBindVertexArray(vao)
2 属性和buffer绑定,创建对象后,可以将内部某一个属性和一个binding point绑定到一起,并将该binding point 和一个vbo对象绑定到一起,具体定义如下:
//vaobj代表操作的vai对象,attribindex代表属性index,binding index代表binding point,也是一个index,buffer代表vbo对象,offset代表缓冲区的偏移量,stride代表从一个顶点数据跳转到下一个顶点数据需要跳转的size大小
void glVertexArrayAttribBinding(GLuint vaobj,GLuint attribindex,GLuint bindingindex)
void glVertexArrayVertexBuffer(GLuint vaobj,GLuint bindingindex,GLuint buffer,GLintptr offset,GLsizei stride)
3 指定缓冲区数据格式,定义如下:
//第一个参数是vao对象,第二个参数是属性index,第三个参数是component个数,比如1,2,3,4,第四个是数据类型,详细见上篇文章,第五个参数代表数据传给shader的时候是否需要归一化,第六个参数是vbo对象中的偏移量
void glVertexArrayAttribFormat(GLuint vaobj,GLuint attribindex,GLint size,GLenum type,GLboolean normalized,GLuint relativeoffset)
4 启用功能,调用一个方法启用自动为vertex shader填充数据的功能,使用完再调用对应方法关掉此功能,定义如下:
void glEnableVertexAttribArray(GLuint index)
void glDisableAttribArray(GLuint index)
5 在shader中进行绑定。以上都是在客户端来实现的功能,在vertex shader 中还需要将输入变量和attribute index绑定到一起,非常简单,如下:
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
上述代码定义了两个输入变量,分别从vao对象的attribute index 为0和1对应的vbo对象中获取数据。
以上就是vao对象的基本使用步骤,但这只设计一个属性,实际使用中,每一个顶点都对应很多属性,例如位置,颜色,法向量,纹理坐标等等,每一个属性的数据类型和数据大小都可能不一样,怎样为顶点填充多个属性,系统提供了两种机制,一种称为seprate attributes,一种称为interleaved attributes,顾名思义,前一种是将各个属性分开存放,可以放到不同的vbo缓冲区中,也可以放到同一个缓冲区的不同位置,后一种方法是放在一起,只有一个缓冲区,而且所有的属性构成一个结构体,缓冲区是中是一个一个按序排列的结构体。从效率上来说,OpenGL更推荐后一种方法。
下面代码片段是第一种实现:
GLuint buffer[2];
GLuint vao;
static const GLfloat positions[] = {…};//位置信息
static const GLfloat colors[] = {…}; //颜色信息
glCreateVertexArrays(1,&vao);
glCreateBuffers(2,&buffer[0]);
//设置第一个属性
glNamedBufferStorage(buffer[0],sizeof(positons),positions,0);
glVertexArrayVertexBuffer(vao,0,buffer[0],0,sizeof(vmtah::vec3));
glVertexArrayAttribFormat(vao,0,3,GL_FLOAT,GL_FALSE,0);
glVertexArrayAttribBinding(vao,0,0);
glEnableVertexArrayAttrib(0);
//设置第二个属性
glNamedBufferStorage(buffer[1],sizeof(colors),colors,0);
glVertexArrayVertexBuffer(vao,1,buffer[1],0,sizeof(vmtah::vec3));
glVertexArrayAttribFormat(vao,1,3,GL_FLOAT,GL_FALSE,0);
glVertexArrayAttribBinding(vao,1,1);
glEnableVertexArrayAttrib(vao,1);
以下代码实现是第二种方法:
struct vertex
{
//position
float x;
float y;
float z;
//color
float r;
float g;
float b;
};
GLuint vao;
GLuint buffer;
static const vertex vertices[] = {…};
glCreateVertexArrays(1,&vao);
glCreateBuffers(1,&buffer);
glNamedBufferStorage(buffer,sizeof(vertices),vertices,0);
glVertexArrayAttribBinding(vao,0,0);
glVertexArrayAttribFormat(vao,0,3,GL_FLOAT,GL_FALSE,offsetof(vertex,x));
glEnableVertexArrayAttrib(0);
glVertexArrayAttribBinding(vao,1,0);
glVertexArrayAttribFormat(vao,1,3,GL_FLOAT,GL_FALSE,offsetof(vertex,r));
glEnableVertexArrayAttrib(1);
glVertexArrayVertexBuffer(vao,0,buffer)
以上就是vao的基本使用方法,不管多么复杂的数据模型或者shader,都不外乎以上几种提供数据的方法,接下来准备钻研一下uniform变量。