VAO,VBO 概念整理总结

现在的OpenGL,如果想绘制一个基本图元,必须有 VAO 和 VBO,否则无法完成基础绘制。但是直接摆在眼前两个英文简称,让人不明所以。今天重新看了一下VAO,VBO 的概念,在此做一个整理总结。

OpenGL 已经抛弃了固定管线,想要 绘制一个 三角形图元,必须使用自定义着色器.至少要有一个顶点着色器,告诉gl每个顶点如何处理;一个像素着色器,告诉gl每个像素的颜色值。

简单的 vertex shader 写法如下:

#version 330 core
layout(location=0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}

简单的 fragment shader 写法如下:

#version 330 core
out vec3 color;
void main(){
  color = vec3(1,0,0);
}


写好了这个shader,程序就具备了绘制顶点的能力。




但是光有着色器,光具备绘制顶点的能力还不够,因为gl并不知道具体要绘制什么内容。要想画一个正经的三角形,必须告诉gl三角形3个顶点的位置。




可以简单的定义一个一维数组,当做描述三角形3个顶点位置的数据,分别代表3个坐标点(-1,-1,0),(1,-1,0),(0,1,0)


static const GLfloat testVerticePosData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};


由于 gl 的视口里,只能绘制 [-1,1] 之间的内容,所以我们的默认顶点位置数据里 ,没有超出这个取值范围的数据。




有了这样的数据描述三角形3个顶点的位置已经够了,但是电脑只认为他是一个一维数组,要想把这些数据绘制出来,就需要把这些数据,按照我们所理解的格式,传到 对应的 shader 中。这时,就需要一个把 内存中的数组数据,传递到 shader中的 桥梁。


这时,终于轮到主角出场了:
这个把内存数据,传递到 shader 中的桥梁,就是 VAO;
存储 数据的场所 ,就是 VBO.




VBO 是 Vertex Buffer Object ,顶点缓存对象 的简称。
它的作用是,用于存储内存里的数据。比如上面描述三角形位置的一维数组 testVerticePosData,可以把它存到一个 VBO 里。




VAO 全称, Vertex Array OBject,顶点数组对象。
它负责把 VBO 里的数据,传递到 shader 里。




创建VBO,设置VBO 数据的 代码一般是这样:


GLuint _vboPos;
glGenBuffers(1, &_vboPos);
glBindBuffer(GL_ARRAY_BUFFER, _vboPos);
glBufferData(GL_ARRAY_BUFFER, sizeof(testVerticePosData), testVerticePosData,GL_STATIC_DRAW);




创建 VAO 的 代码是样:
GLuint _vao;
glGenVertexArrays(1, &_vao);




有了 VAO 和 VBO 可以这样把他们联系起来:


glGenVertexArrays(1, &_vao); // 创建 VAO
glBindVertexArray(_vao); // bind 函数,告诉GL 我现在要操作 _vao 这个 VAO 对象了




glGenBuffers(1, &_vboPos); // 创建用于描述位置信息的vbo
glBindBuffer(GL_ARRAY_BUFFER, _vboPos); // 注意这里参数是 GL_ARRAY_BUFFER,告诉 GL 这个 vbo 要装载 顶点数组信息(与之对应的是 顶点索引信息,这里先不讨论)
glBufferData(GL_ARRAY_BUFFER, sizeof(testVerticePosData), testVerticePosData,GL_STATIC_DRAW); // 这里要真正让 vbo 真正承载数据了.GL_ARRAY_BUFFER 表示它所描述的是 顶点数组信息,内存大小有 sizeof(testVerticePosData) 那么大 ,内存数据起始位置 是 testVerticePosData ,GL_STATIC_DRAW 这个位置的参数表示 这段数据是否会 频繁改变




上面的代码,在给 vbo 设置数据时,由于已经 glBindVertexArray(_vao); 做了 bind _vao 的操作,所以 GL 明确知道 下面操作 vbo 的数据,是给 _vao 这个 VAO 对象所准备的。


此时, 数据有了--存储在 _vbo 这个 VBO 对象里,桥梁有了 -- 是 _vao 这个 VAO 对象.接下来,要把 vbo 里的数据,通过 vao ,映射到 我们 上面自定义的 vertex shader 里。




这里再贴一遍 vertex shader 的代码:


#version 330 core
layout(location=0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}

in 代表 shader 里的这个数据是要由 cpp 代码里的 VAO 传进来的。
location = 0 表示,这个 shader 变量的位置index 是 0.

由此,可以用下面glVertexAttribPointer() 函数,来把 vbo 的数据,通过 vao 传递到 shader 里面去:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);


//typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
第1个参数 index,表示 我们 接下来的 vbo 里面的数据,要传递给 vertex shader 里 location = 0 的 in 的 变量里面去;
第2个参数 size ,表示 shader 里面对应变量得纬度。比如 position 是3 (x,y,z),颜色是 4 (r,g,b,a)
第3个参数 type GL_FLOAT 表示 我们用的每个数据 都是浮点数
第4个参数 GLboolean normalized 表示是否 应该被归一化(这里我还不是很明白 这里 GL_TRUE/GL_FALSE 的区别),我的理解是,这个如果是 TRUE 的话,无论你传什么样的数据,有多少维度,到 shader 里 会被 当做向量 normalize 一次。
第5个参数 stride 和 第6个参数 pointer ,分别表示 vbo 里的数组数据 之间的间隔,和 起始偏移。正因为有了这样两个参数,可以让一个 一维数组,同时可以包含很多种类型的数据。


比如 1维数组数据 如果只包含 位置信息

[pt1.x,pt1.y,pt1.z,pt2.x,pt2.y,pt2.z ... ] 则 stride 间隔为 0,起始偏移 pointer 也是0

比如 1微数据 ,假设同时包含 位置,颜色两种信息
[pt1.x,pt1.y,pt1.z,pt1.r,pt1.g,pt1.b,pt1.a,pt2.x,pt2.y,pt2.z,pt2.r,pt2.g,pt2.b,pt2.a,....]


这样一来, 一个 VBO 里面存储的数据,就能够给 shader 提供包括位置,颜色等 多种 数据了.


同时,多个 VBO 也可以同时对应一个 VAO.
例如,vbopos 只存储位置信息,stride,pointer 都是 0
另一个 vbocolor 只存储颜色信息,stride,pointer 都是0


只要是 在  glBindVertexArray(_vao); 后, 连续给多个 vbo 赋值,即可实现 多个 vbo 对应一个 vao 的效果。


在 c++数组 ---> VBO ---> VAO ---> shader 这个流程完成以后,需要 依赖 VAO 来开启 shader 里面的 参数

glEnableVertexAttribArray(0); // 参数是 shader 参数里的 location

最后再用  glDrawArrays(),配合 对应的 shader , 即可进行最后的图元绘制。


glDrawArrays(GL_TRIANGLES, 0, 3);


断断续续总结了很久,一直在加班,中间还修改了 bug,现在已经凌晨 4:20了。。语无伦次。
下次思路清晰一些,并且把一些 不明白的再摸得透彻一些,再做 补充和 更改吧。


VAO VBO 的概念非常重要,必须有清晰的认识,才能把 OpenGL 的学习进行下去。
今天的 VAO VBO 笔记先到此为止。

猜你喜欢

转载自blog.csdn.net/korekara88730/article/details/79314252