赞
踩
知识回顾:
二维三角形的数据可以表示为如下所示
- float vertices[] = {
- -0.5f,-0.5f, 0.5f,
- 0.5f,-0.5f, 0.0f,
- 0.0f, 0.5f, 0.0f
- };
图形渲染本质上,就是CPU端的C++程序控制GPU行为的过程,控制过程包括数据传输和指令发送 在内存中,以上数据以vertices数组存储,那么在显存中呢?则需要VBO
VBO(Vertex Buffer Object):表示在GPU显存上的一段存储空间对象
VBO在C++中表现为一个 unsigned int 类型变量,理解成为GPU内存对象的一个ID编号
VBO的创建: void glGenBuffers(GLsizei n , GLuint *buffers)
n: 创建多少个VBO buffers:创建出来的vbo编号们,都放到buffer指向的数组中
VBO的销毁: void glDeleteBuffers(GLsizei n, GLuint *buffers)
n:删除多少个VBO ,buffers:要删除的vbo编号数组
示例如下:
- // 学会创建销毁vbo
- void prepare() {
- GLuint vbo = 0;
- glGenBuffers(1, &vbo); // 创建一个vbo 编号放到后者指向的数组
- glDeleteBuffers(1, &vbo);// 销毁一个vbo
-
- GLuint vboArr[] = { 0,0,0 };
- glGenBuffers(3, vboArr); //创建n个vbo
- glDeleteBuffers(3, vboArr); //销毁n个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模型数据会频繁改变
注意:此函数调用的时候,会重新开辟存储空间!尽可能谨慎使用
示例代码 如下
- void prepareVBO() {
- float vertices[] = {
- -0.5f,-0.5f, 0.5f,
- 0.5f,-0.5f, 0.0f,
- 0.0f, 0.5f, 0.0f
- };
-
- GLuint vbo = 0;
- glGenBuffers(1, &vbo);//生成一个vbo
-
- // 绑定当前vbo 到opengl状态机当前vbo 插槽
- // GL_ARRAY_BUFFER:表示当前vbo这个插槽
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
-
- //向当前vbo传输数据,也是在开辟显存
- glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
- }

下面给出两种方案,首先是SingleBuffer 每个属性放在一个单独的vbo当中
- void prepareSingleBuffer() {
- //准备顶点颜色与数据
- float positions[] = {
- -0.5f, -0.5f ,0.0f,
- 0.5f, -0.5f ,0.0f,
- 0.0f, 0.5f ,0.0f
- };
- float colors[] = {
- 1.0f ,0.0f,0.0f,
- 0.0f,1.0f,0.0f,
- 0.0f,0.0f,1.0f
- };
- // 为位置和颜色各自生成一个vbo
- GLuint posVbo = 0, colorVbo = 0;
- glGenBuffers(1, &posVbo);
- glGenBuffers(1, &colorVbo);
-
- //给两个分开的vbo各自填充数据
- //position
- glBindBuffer(GL_ARRAY_BUFFER, posVbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof positions, positions, GL_STATIC_DRAW);
-
- // color 填充数据
- glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof colors, colors, GL_STATIC_DRAW);
- }

第二种是InterleavedBuffer 所有属性都存储在一个vbo当中
- void prepareInterleavedBuffer() {
- float vertices[] = {
- -0.5f,-0.5f,-0.5f, 0.0f, 1.0f, 0.0f,
- 0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
- };
-
- GLuint vbo = 0;
- glGenBuffers(1, &vbo);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
- }
在图形学编程中,对于一组纯粹的数据,我们往往给出一段描述结构
每个顶点三个数字 - size
每个数字都是float类型 -type
每个顶点的数据,步长为12byte -stride(步长属性并不多余,每个顶点中不一定只包含位置信息,还可能有其他信息)
多个VBO情况
铺垫完这些,接下来就可以介绍介绍什么是VAO了
VAO(Vertex Array Object):顶点数组对象,用于存储一个Mesh网络所有的顶点属性描述信息
三角形的位置与颜色可以交叉放到同一个vbo当中,如何描述呢?
对于位置数据,它的信息放在每个顶点的前头,与前面相差不大
而对于颜色数据,我们则需要知道它在每个顶点的哪个位置,但是使用步长移动指针,只能以每个顶点为单位移动!所以我们需要知道:顶点数据内部,每个属性相对开头的偏移量(offset)
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存放数组
- void prepareVAO() {
- //准备顶点颜色与数据
- float positions[] = {
- -0.5f, -0.5f ,0.0f,
- 0.5f, -0.5f ,0.0f,
- 0.0f, 0.5f ,0.0f
- };
- float colors[] = {
- 1.0f ,0.0f,0.0f,
- 0.0f,1.0f,0.0f,
- 0.0f,0.0f,1.0f
- };
- // 为位置和颜色各自生成一个vbo
- GLuint posVbo = 0, colorVbo = 0;
- glGenBuffers(1, &posVbo);
- glGenBuffers(1, &colorVbo);
- //position
- glBindBuffer(GL_ARRAY_BUFFER, posVbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof positions, positions, GL_STATIC_DRAW);
- // color 填充数据
- glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof colors, colors, GL_STATIC_DRAW);
-
- //生成vao 并且绑定
- GLuint vao = 0;
- glGenVertexArrays(1, &vao);
- glBindVertexArray(vao);
-
- //4 分别将位置 / 颜色属性的描述信息加入到vao当中
- glBindBuffer(GL_ARRAY_BUFFER, posVbo); // 只有绑定了posVbo 下面的描述属性才会与此vbo相关
- glEnableVertexAttribArray(0); // 激活vao的第一个位置
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
-
- glBindBuffer(GL_ARRAY_BUFFER,colorVbo);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);
-
- glBindVertexArray(0); //解绑vao
-
- }

一个VAO是否就能够代表整个三角形?答案是可以的。
通过这个VAO,我们是不是可以了解到这个三角形的一切?这个三角形的位置信息,我们通过vao,通过0号属性,跟posVbo挂钩,就能找到它的位置信息。同理颜色信息描述。
- void prepareInterleavedBuffer() {
- //准备好 interleaved数据 位置+颜色
- float vertices[] = {
- -0.5f,-0.5f,-0.5f, 0.0f, 1.0f, 0.0f,
- 0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
- };
-
- //创建唯一的vbo
- GLuint vbo = 0;
- glGenBuffers(1, &vbo);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
-
- //创建并绑定vao
- GLuint vao = 0;
- glGenVertexArrays(1, &vao);
- glBindVertexArray(vao);
-
- //为 vao加入位置和颜色的描述信息
- //4.1 位置描述信息
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
- //放到0号位置,每个顶点3个数据,类型,一个顶点的数据共多少(步长),偏移量
-
- glEnableVertexAttribArray(1); //激活
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)3);
-
- glBindVertexArray(0);
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。