当前位置:   article > 正文

OpenGL学习笔记——VBO与VAO

vbo

VBO

什么是VBO

知识回顾:

二维三角形的数据可以表示为如下所示

  1. float vertices[] = {
  2. -0.5f,-0.5f, 0.5f,
  3. 0.5f,-0.5f, 0.0f,
  4. 0.0f, 0.5f, 0.0f
  5. };

图形渲染本质上,就是CPU端的C++程序控制GPU行为的过程,控制过程包括数据传输指令发送 在内存中,以上数据以vertices数组存储,那么在显存中呢?则需要VBO

VBO(Vertex Buffer Object):表示在GPU显存上的一段存储空间对象

VBO在C++中表现为一个 unsigned int 类型变量,理解成为GPU内存对象的一个ID编号

VBO创建与销毁

VBO的创建: void glGenBuffers(GLsizei n , GLuint *buffers)

n: 创建多少个VBO  buffers:创建出来的vbo编号们,都放到buffer指向的数组中

VBO的销毁: void glDeleteBuffers(GLsizei n, GLuint *buffers)

n:删除多少个VBO ,buffers:要删除的vbo编号数组

示例如下:

  1. // 学会创建销毁vbo
  2. void prepare() {
  3. GLuint vbo = 0;
  4. glGenBuffers(1, &vbo); // 创建一个vbo 编号放到后者指向的数组
  5. glDeleteBuffers(1, &vbo);// 销毁一个vbo
  6. GLuint vboArr[] = { 0,0,0 };
  7. glGenBuffers(3, vboArr); //创建n个vbo
  8. glDeleteBuffers(3, vboArr); //销毁n个vbo
  9. }

VBO的绑定与数据

绑定: 将某个资源,与OpenGL状态机中的某个状态插槽进行关联

VBO的绑定:

void glBindBuffer(GLenum target,GLuint buffer)

target: 把当前的vbo绑定到状态机的哪个状态插槽

buffer:绑定的vbo编号;0表示不绑定任何buffer

VBO填入数据:

void glBufferData(GLenum target,GLsizeiptr size,const void* data,GLenum usage)

target:针对状态机哪个状态插槽的buffer(绑定在某个插槽上的不一定是vbo,也可能是别的)

size:装入当前buffer的数据大小

data:装有数据的数组指针

usage:当前buffer的用法:1、GL_STATIC_DRAW vbo模型数据不会频繁改变 2、GL_DYNAMIC_DRAW: vbo模型数据会频繁改变

注意:此函数调用的时候,会重新开辟存储空间!尽可能谨慎使用

示例代码 如下

  1. void prepareVBO() {
  2. float vertices[] = {
  3. -0.5f,-0.5f, 0.5f,
  4. 0.5f,-0.5f, 0.0f,
  5. 0.0f, 0.5f, 0.0f
  6. };
  7. GLuint vbo = 0;
  8. glGenBuffers(1, &vbo);//生成一个vbo
  9. // 绑定当前vbo 到opengl状态机当前vbo 插槽
  10. // GL_ARRAY_BUFFER:表示当前vbo这个插槽
  11. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  12. //向当前vbo传输数据,也是在开辟显存
  13. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  14. }

VBO多属性数据存储

下面给出两种方案,首先是SingleBuffer 每个属性放在一个单独的vbo当中

  1. void prepareSingleBuffer() {
  2. //准备顶点颜色与数据
  3. float positions[] = {
  4. -0.5f, -0.5f ,0.0f,
  5. 0.5f, -0.5f ,0.0f,
  6. 0.0f, 0.5f ,0.0f
  7. };
  8. float colors[] = {
  9. 1.0f ,0.0f,0.0f,
  10. 0.0f,1.0f,0.0f,
  11. 0.0f,0.0f,1.0f
  12. };
  13. // 为位置和颜色各自生成一个vbo
  14. GLuint posVbo = 0, colorVbo = 0;
  15. glGenBuffers(1, &posVbo);
  16. glGenBuffers(1, &colorVbo);
  17. //给两个分开的vbo各自填充数据
  18. //position
  19. glBindBuffer(GL_ARRAY_BUFFER, posVbo);
  20. glBufferData(GL_ARRAY_BUFFER, sizeof positions, positions, GL_STATIC_DRAW);
  21. // color 填充数据
  22. glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
  23. glBufferData(GL_ARRAY_BUFFER, sizeof colors, colors, GL_STATIC_DRAW);
  24. }

第二种是InterleavedBuffer 所有属性都存储在一个vbo当中

  1. void prepareInterleavedBuffer() {
  2. float vertices[] = {
  3. -0.5f,-0.5f,-0.5f, 0.0f, 1.0f, 0.0f,
  4. 0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
  5. 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
  6. };
  7. GLuint vbo = 0;
  8. glGenBuffers(1, &vbo);
  9. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  10. glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
  11. }

VAO

什么是VAO

  1. GPU如何知道这些数据的用处?(位置,颜色,法线,ID)
  2. GPU如何知道每个顶点有几个FLOAT?
  3. GPU如何知道这组数据包含几种属性? (位置?颜色?uv)

在图形学编程中,对于一组纯粹的数据,我们往往给出一段描述结构

每个顶点个数字 - size

每个数字都是float类型 -type

每个顶点的数据,步长为12byte -stride(步长属性并不多余,每个顶点中不一定只包含位置信息,还可能有其他信息)

多个VBO情况

铺垫完这些,接下来就可以介绍介绍什么是VAO了

VAO(Vertex Array Object):顶点数组对象,用于存储一个Mesh网络所有的顶点属性描述信息

三角形的位置与颜色可以交叉放到同一个vbo当中,如何描述呢?

对于位置数据,它的信息放在每个顶点的前头,与前面相差不大

而对于颜色数据,我们则需要知道它在每个顶点的哪个位置,但是使用步长移动指针,只能以每个顶点为单位移动!所以我们需要知道:顶点数据内部,每个属性相对开头的偏移量(offset)

VAO完整描述

对于三角形顶点的某一个属性,我们需要知道的描述信息为:

  1. 每个顶点xxx个数字
  2. 每个数字都是xxx类型
  3. 每个顶点的数据,步长为xxx byte
  4. 此属性数据在顶点数据内的偏移量 offset
  5. 此属性存储在xxx号vbo

VAO创建与删除

VAO的创建:

void glGenVertexArrays(GLsizei n, GLuint *arrays)

n:创建多少个vao   arrays:创建出来的vao编号们,都放到arrays指向的数组中

VAO的绑定:

void glBindVertexArray(GLuint array)

array:要绑定的vao编号

VAO加入对于VBO的描述:

void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,GLsizei stride,const void* pointer)

这个函数似乎没有体现和vbo的关系,我们怎么知道我们在描述哪个vbo呢?下节见分晓

VAO的删除:

void glDeleteVertexArrays(GLsizei n, GLuint *arrays)

n:删除多少个vao  arrays:要删除的vao存放数组

VAO-SingleBuffer策略

  1. void prepareVAO() {
  2. //准备顶点颜色与数据
  3. float positions[] = {
  4. -0.5f, -0.5f ,0.0f,
  5. 0.5f, -0.5f ,0.0f,
  6. 0.0f, 0.5f ,0.0f
  7. };
  8. float colors[] = {
  9. 1.0f ,0.0f,0.0f,
  10. 0.0f,1.0f,0.0f,
  11. 0.0f,0.0f,1.0f
  12. };
  13. // 为位置和颜色各自生成一个vbo
  14. GLuint posVbo = 0, colorVbo = 0;
  15. glGenBuffers(1, &posVbo);
  16. glGenBuffers(1, &colorVbo);
  17. //position
  18. glBindBuffer(GL_ARRAY_BUFFER, posVbo);
  19. glBufferData(GL_ARRAY_BUFFER, sizeof positions, positions, GL_STATIC_DRAW);
  20. // color 填充数据
  21. glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
  22. glBufferData(GL_ARRAY_BUFFER, sizeof colors, colors, GL_STATIC_DRAW);
  23. //生成vao 并且绑定
  24. GLuint vao = 0;
  25. glGenVertexArrays(1, &vao);
  26. glBindVertexArray(vao);
  27. //4 分别将位置 / 颜色属性的描述信息加入到vao当中
  28. glBindBuffer(GL_ARRAY_BUFFER, posVbo); // 只有绑定了posVbo 下面的描述属性才会与此vbo相关
  29. glEnableVertexAttribArray(0); // 激活vao的第一个位置
  30. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
  31. glBindBuffer(GL_ARRAY_BUFFER,colorVbo);
  32. glEnableVertexAttribArray(1);
  33. glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);
  34. glBindVertexArray(0); //解绑vao
  35. }

一个VAO是否就能够代表整个三角形?答案是可以的。

通过这个VAO,我们是不是可以了解到这个三角形的一切?这个三角形的位置信息,我们通过vao,通过0号属性,跟posVbo挂钩,就能找到它的位置信息。同理颜色信息描述。

VAO-InterleavedBuffer策略

  1. void prepareInterleavedBuffer() {
  2. //准备好 interleaved数据 位置+颜色
  3. float vertices[] = {
  4. -0.5f,-0.5f,-0.5f, 0.0f, 1.0f, 0.0f,
  5. 0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
  6. 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
  7. };
  8. //创建唯一的vbo
  9. GLuint vbo = 0;
  10. glGenBuffers(1, &vbo);
  11. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  12. glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
  13. //创建并绑定vao
  14. GLuint vao = 0;
  15. glGenVertexArrays(1, &vao);
  16. glBindVertexArray(vao);
  17. //为 vao加入位置和颜色的描述信息
  18. //4.1 位置描述信息
  19. glEnableVertexAttribArray(0);
  20. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
  21. //放到0号位置,每个顶点3个数据,类型,一个顶点的数据共多少(步长),偏移量
  22. glEnableVertexAttribArray(1); //激活
  23. glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)3);
  24. glBindVertexArray(0);
  25. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/818282
推荐阅读
相关标签
  

闽ICP备14008679号