OpenGL学习日记之VBO、VAO、EBO

在这里要先了解一下OpenGL的一个幕后大致运作流程,可以直接阅读OPENGL CN

我自己大概总结了一下就是,OpenGL本身就是一个巨大的状态机,我们通过更改状态变量(上下文)来告诉OpenGL如何去绘制图像。一般通过设置选项,修改缓冲来更改OpenGL状态。OpenGL的库是C语言写的,为了方便,OPenGL为我们抽象了一个层,这个层就是把一个状态或者选项包装为一个“对象”,一个对象就是一些选项或者数据的集合,它代表OpenGL状态的一个子集。

VBO
英文全名是Vertex Buffer Object,中文翻译过来是顶点缓冲对象
VBO就是OpenGL的一个“对象”,我们把大批顶点数据封装成一个VBO对象,然后通过CPU将这个VBO对象发送到显存上,方便后期GPU的读取。
例如buffer1数组和buffer2就分别为一个VBO对象
buffer1里面就是最普通的封装的顶点的三个坐标值
buffer2里面就包含顶点坐标的坐标值以及顶点颜色

float buffer1= {
       //顶点坐标(3个一组)              
    0.5f,  0.5f, 0.0f,               
    0.5f, -0.5f, 0.0f,               
   -0.5f, -0.5f, 0.0f,             
   -0.5f,  0.5f, 0.0f, };
   
float buffer2 = {
       //顶点坐标(3个一组)              //顶点颜色(3个一组)          
    0.5f,  0.5f, 0.0f,                1.0f, 0.0f, 0.0f,              
    0.5f, -0.5f, 0.0f,                0.0f, 1.0f, 0.0f,               
   -0.5f, -0.5f, 0.0f,                0.0f, 0.0f, 1.0f,               
   -0.5f,  0.5f, 0.0f,                1.0f, 1.0f, 0.0f,               
};

*VAO
英文全名 Vertex Array Object ,中文翻译过来是顶点数组对象,存储着设置的顶点属性指针。
VAO就像是为了向GPU解释顶点数据,指定VBO数据中的各个属性字段用途,我们把顶点相关数据打包成一个VBO传入显存,供GPU读取,GPU读取到这个数组数据以后,顶点着色器并不知道要如何去使用这些数据,这个时候就需要VAO来解释这些数据,通过指针告诉顶点着色器,数据去哪里取,取来是做什么的。

在这里插入图片描述
链接顶点属性buffer1示列

    //顶点着色器代码开始
    #version 330 core
    layout (location = 0) in vec3 position; // 位置变量的属性位置值为 0 
   out vec3 ourColor; // 向片段着色器输出一个颜色

    void main()
    {
    gl_Position = vec4(position, 1.0);
    }
    //顶点着色器代码结束
    
   //链接顶点属性代码开始
    GLuint VBO,VAO;
    glGenVertexArrays(1, &VAO); //生成数组对象
    glGenBuffers(1, &VBO);//生成缓冲区对象
    
    //绑定VAO
    glBindVertexArray(VAO);
    // 把顶点数组复制到缓冲中供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    //链接顶点属性代码结束

链接顶点属性buffer2示例,我们在定义顶点着色器代码的时候不仅会用layout定义position位置属性为0,还会定义位置属性为1的color。

    //顶点着色器代码开始
    #version 330 core
    layout (location = 0) in vec3 position; // 位置变量的属性位置值为 0 
    layout (location = 1) in vec3 color;    // 颜色变量的属性位置值为 1

   out vec3 ourColor; // 向片段着色器输出一个颜色

    void main()
    {
    gl_Position = vec4(position, 1.0);
    ourColor = color; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
    }
    //顶点着色器代码结束

    //链接顶点属性代码开始
   GLuint VBO,VAO;
    glGenVertexArrays(1, &VAO); //生成数组对象
    glGenBuffers(1, &VBO);//生成缓冲区对象
    
    //绑定VAO
    glBindVertexArray(VAO);
    // 把顶点数组复制到缓冲中供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
   // 颜色属性
   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));
   glEnableVertexAttribArray(1);
    //链接顶点属性代码结束

glVertexAttribPointer函数的参数非常多,所以我会逐一介绍它们:

第一个参数指定我们要配置的顶点属性。我们会在顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值(Location),它可以把顶点属性的位置值设置为0。因为我们希望把数据传递到这一个顶点属性中,所以这里我们传入0。

第二个参数指定顶点属性的大小。顶点属性是一个vec3,它由3个值组成,所以大小是3。

第三个参数指定数据的类型,这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)。

第四个参数定义我们是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。我们把它设置为GL_FALSE。

第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在6个GLfloat之后,我们把步长设置为6* sizeof(GLfloat)。

最后一个参数的类型是GLvoid*,所以需要我们进行这个奇怪的强制类型转换。它表示位置数据在缓冲中起始位置的偏移量(Offset)。

*EBO
英文Element Buffer Object ,中文翻译为索引缓冲对象
当我们绘制一个矩形,由两个三角形组成,分别为顶点ABC,BCD构成的三角形组成,如果我们按照将组成每个三角形的单个顶点都存入到数组中,那BC这两个顶点就被存储了2次,就会产生额外的开销。当顶点的数量特别多时,开销就会特别巨大。因此为了优化这个问题,就有一个方案,全部的顶点只存储一次,但是额外存储这些顶点的绘制顺序。也就是我们这里存储ABCD四个顶点到VBO中,在EBO中存储绘制顺序,012,123。

耗费资源方式
GLfloat vertices[] = {
    // 第一个三角形
    0.5f, 0.5f, 0.0f,   // 右上角
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, 0.5f, 0.0f,  // 左上角
    // 第二个三角形
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, -0.5f, 0.0f, // 左下角
    -0.5f, 0.5f, 0.0f   // 左上角
};
索引绘制方式
GLfloat vertices[] = {
    0.5f, 0.5f, 0.0f,   // 右上角
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, -0.5f, 0.0f, // 左下角
    -0.5f, 0.5f, 0.0f   // 左上角
};

GLuint indices[] = { // 注意索引从0开始! 
    0, 1, 3, // 第一个三角形
    1, 2, 3  // 第二个三角形
};

绘制过程如下
1、使用各自唯一的ID生成VAO,VBO,EBO对象
2、新创建的VBO缓冲绑定到GL_ARRAY_BUFFER类型目标上,从绑定这一刻起,我们使用的任何(在GL_ARRAY_BUFFER类型目标上的)缓冲调用都会用来配置当前绑定的缓冲(VBO)。并把定义的顶点数据复制到缓冲的内存中
3、新创建的EBO缓冲绑定到GL_ELEMENT_ARRAY_BUFFER类型目标上,并把索引数据复制到缓冲内存中
4、设定顶点属性指针

GLuint VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    // Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
    glBindVertexArray(VAO);

    //新创建的VBO缓冲绑定到GL_ARRAY_BUFFER目标上
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //把之前定义的顶点数据复制到缓冲的内存中
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    // 新创建的EBO缓冲绑定到GL_ELEMENT_ARRAY_BUFFER目标上
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    //并把索引数据复制到缓冲内存中
    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);

    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glBindVertexArray(0);

参考链接:https://www.cnblogs.com/zhoug2020/p/16465692.html
参考链接:https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/04%20Hello%20Triangle/
参考链接:https://zhuanlan.zhihu.com/p/150906665

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值