Opengl是大家常用的一个API,我们用它绘制数据的时候需要使用vao,vbo,ebo等对象,绘制方式分为 vao绘制,ebo绘制等。使用不同api还能分为普通调用以及Instance绘制。

首先申请vao,vbo和以及他们两者的绑定:

 这里注意的是,百度百科上说的最多支持四个位置,我测试了一下,7到8个顶点属性都没问题,比如Position,Texcoord,Color,Normal等等,需要排列好。

其实他们的绑定有两种方式,第一种是vao搭配多个vbo,每一个vbo代表顶点的一种属性,比如vbo[0] 代表位置,vbo[1]代表纹理坐标。。代码如下:

//位置
glGenBuffers(1, &vbo0);
glBindBuffer(GL_ARRAY_BUFFER, vbo0);
glBufferData(GL_ARRAY_BUFFER, 3 * 4 * sizeof(GLfloat), posCube, GL_STATIC_DRAW); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
//纹理
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), texCube, GL_STATIC_DRAW); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr); //法线
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, 3 * 4 * sizeof(GLfloat), normalCube, GL_STATIC_DRAW); glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(GLfloat), nullptr); //法线
glGenBuffers(1, &vbo3);
glBindBuffer(GL_ARRAY_BUFFER, vbo3);
glBufferData(GL_ARRAY_BUFFER, 3 * 4 * sizeof(GLfloat), normalCube2, GL_STATIC_DRAW); glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(GLfloat), nullptr); //法线
glGenBuffers(1, &vbo4);
glBindBuffer(GL_ARRAY_BUFFER, vbo4);
glBufferData(GL_ARRAY_BUFFER, 3 * 4 * sizeof(GLfloat), normalCube3, GL_STATIC_DRAW); glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(GLfloat), nullptr); //法线
glGenBuffers(1, &vbo5);
glBindBuffer(GL_ARRAY_BUFFER, vbo5);
glBufferData(GL_ARRAY_BUFFER, 3 * 4 * sizeof(GLfloat), normalCube4, GL_STATIC_DRAW); glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(GLfloat), nullptr);

第二种关联方式:则一个vao搭配一个vbo,这种传递方式类似于把结构体数组或者内存的数据传递给vbo。 内存排布 是这样的:位置纹理法线位置纹理法线  。位置是float x3,纹理floatx2,法线float x3,

解析的时候就是 顶点1: 位置纹理法线 顶点2位置纹理法线,他们会有间隔

struct MyVertex
{
vec3 pos;
vec2 tex;
vec3 normal;
}; //顶点定义
for (int i = 0; i < 4; i++)
{
MyVertex v;
v.pos.x = posCube[i * 3 + 0];
v.pos.y = posCube[i * 3 + 1];
v.pos.z = posCube[i * 3 + 2]; v.tex.s = texCube[i * 2 + 0];
v.tex.t = texCube[i * 2 + 1]; v.normal.x = normalCube2[i * 3 + 0];
v.normal.y = normalCube2[i * 3 + 1];
v.normal.z = normalCube2[i * 3 + 2];
eboBuffers.push_back(v);
} glGenVertexArrays(1, &vao);
glBindVertexArray(vao); glGenBuffers(1, &vbo0);
glBindBuffer(GL_ARRAY_BUFFER, vbo0); glBufferData(GL_ARRAY_BUFFER, eboBuffers.size()* sizeof(MyVertex), eboBuffers.data(), GL_STATIC_DRAW);
int stride = sizeof(MyVertex);
glEnableVertexAttribArray(0); //根据属性数量来顶,这里开启三个 0 1 2
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)offsetof(MyVertex, pos));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)offsetof(MyVertex, tex));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, stride, (GLvoid*)offsetof(MyVertex, normal));

VAO绘制:

glBindVertexArray(vao);
glDrawArrays(GL_QUADS, first, count); //第一个是起始位置,第二个是顶点数量

EBO的绘制:

  ebo的好处是可以省大量的内存,只需要调用顶点所在的索引(id)即可完成绘制,因为

  在有了vao,vbo的申请以及他们的内存关联之后,ebo开始工作。

  ebo绘制有两种方式

1)先申请在绘制

  

//申请:
glGenBuffers(1, &eboId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLubyte), vIdx, GL_STATIC_DRAW); //vidx 即绘制索引数组 GLubyte vIdx[] = { 0,1,2,1,2,3 }; //绘制:
glBindVertexArray(vao);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0); //最后一个参数是0,因为已经绑定了vao,ebo

2. 直接使用数组

    //清除已绑定的ebo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, vIdx); //传入索引数组内存以及顶点数量

最后绘制在Shader中的展示(ebo,vbo调用均一样): Normal2,Normal3,Normal4 是用来测试顶点属性数量用的,支持6个属性没问题

uniform mat4 proj;
uniform mat4 view;
uniform mat4 model; layout (location = 0) in vec3 Position; //layout (locatiopn=0)一定要写,否则识别会出问题
layout (location = 1) in vec2 Texcoord;
layout (location = 2) in vec3 Normal;
layout (location = 3) in vec3 Normal2;
layout (location = 4) in vec3 Normal3;
layout (location = 5) in vec3 Normal4; out vec3 Color; void main()
{ Color = Normal4;
gl_Position = proj * view *model* vec4(Position,1);
}

OpenGL 4.0中数据缓冲VBO,VAO,EBO的使用总结的更多相关文章

  1. OpenGL 4.0 GLSL 基础教程概览——VAO和VBO常用操作接口

    (一) OpenGL  4.3 最新渲染管线图 从OpenGL 2.0 到 OpenGL 3.0变化非常大,但从OpenGL 3.0 到OpenGL 4.0 变化不是太大. 着色器程序直接运行在GPU ...

  2. LearnOpenGL学习笔记(三)——VBO,VAO,EBO理解

    在opengl中所有的数据都要放在显存中,我们通过一定的手段去管理它,既要提供地方存放它,还要提供方法去正确地提取它们,去使用它们,opengl通过VAO,VBO,EBO这些手段来解决这些问题. (一 ...

  3. yii2.0中数据缓存之增删改查

    public function actionSss(){ /* * 获取到缓存 * 这里是获取的是根目录下 的common/main.php中的缓存类组件 * */ $cache=\Yii::$app ...

  4. 解决EF 4.0 中数据缓存机制

    EF4.0默认开启缓存机制,如果想要禁用缓存机制的话,则须加上一句话:_db.CreateObjectSet().MergeOption = MergeOption.OverwriteChanges; ...

  5. yii2.0 中数据查询中 or、in、between 及session的使用

    1 HTML: 2 3 <div> 4 <form class="form-inline " method="get" action=&quo ...

  6. libevent中数据缓冲区buffer分析

    很多时候为了应对数据IO的"慢"或者其他原因都需要使用数据缓冲区.对于数据缓冲,我们不陌生,但是对于如何实现这个缓冲区,相信很多时候大家都没有考虑过.今天就通过分析libevent ...

  7. OpenGL中VA,VAO,VBO和EBO的区别

    1,顶点数组(Vertex Array) VA,顶点数组也是收集好所有的顶点,一次性发送给GPU.不过数据不是存储于GPU中的,绘制速度上没有显示列表快,优点是可以修改数据. 4.VBO(Vertex ...

  8. Cocos2d-x中使用OpenGL ES2.0编写shader

    这几天在看子龙山人的关于OpenGL的文章,先依葫芦画瓢,能看到些东西,才能慢慢深入了解,当入门文章不错,但是其中遇到的一些问题,折腾了一些时间,为了方便和我一样的小白们,在这篇文章中进行写补充. O ...

  9. OpenGL ES 2: debugging, and improvements to VAO, VBO

    OpenGL ES 2: debugging, and improvements to VAO, VBO http://www.altdevblogaday.com/2013/10/12/opengl ...

  10. unix中数据缓冲区高速缓冲的设计

    目录 1. 概述 2. 缓冲区的设计 2.1 缓冲区头部 2.2 缓冲区的结构 2.3 缓冲区的检索算法 2.3. 申请一个缓冲区算法 getblk 2.3.2 释放一个缓冲区算法 brelse 2. ...

随机推荐

  1. Jenkins获取gitlab源代码

    Jenkins获取gitlab源代码 Jenkins权限获取 在日常工作做由于Jenkins启动用户是Jenkins,在执行脚本时系统命令是无法让Jenkins执行的,如果需要Jenkins权限有两种 ...

  2. uniapp 返回顶部

    <template> <view> <view class="btn" @tap="toTop" :style="{'d ...

  3. vue3 函数式组件

    今天看vue3中文文档 看到函数式组件不太理解上面写的 然后自己写了一下才理解上面的自己记录一下 先在子组件里面写上 <script> // dynameic 组件 import { h ...

  4. Oracle使用序列和触发器设置自增字段

    一.创建一张工作表 例: create table tv(ID NUMBER primary key,TVNAME VARCHAR(16),ISPASS NUMBER);   二.先创建一个序列 cr ...

  5. Vue学习:2.V标签综合2

    接上一篇... V标签综合使用:书架案例 功能: 实现列表的渲染和删除 思路: 使用 v-for 渲染数据列表,并在每个列表项内放置一个绑定了 del方法的"删除"按钮,点击按钮时 ...

  6. 以 ZGC 为例,谈一谈 JVM 是如何实现 Reference 语义的

    本文基于 OpenJDK17 进行讨论 1. Reference 相关概念及其应用场景总览 Reference(引用)是 JVM 中非常核心且重要的一个概念,垃圾回收器判断一个对象存活与否都是围绕着这 ...

  7. BC6-牛牛的第二个整数

    题目描述 牛牛从键盘上输入三个整数,并尝试在屏幕上显示第二个整数. 输入描述 一行输入 3 个整数,用空格隔开. 输出描述 请输出第二个整数的值. 示例 1 输入:1 2 3 输出:2 解题思路 方案 ...

  8. 用ESP8266-NodeMCU开发板显示一下我的QQ头像

    诶,说好的自己写esp8266的开发板固件的我回来了. 20年说好的,今天回来还愿了 ESP8266串口WiFi模块 - WiFi杀手 今天我们把OLED显示屏也接上,我此次买的是4脚的OLED(12 ...

  9. Java常用的十大开源工具类库总结

    以下是个人总结的Java常用的十大开源工具类库,根据具体需求和项目,可以选择合适的工具类库来提高开发效率.1. Apache Commons:Apache Commons是一个开源的工具类库,提供了大 ...

  10. Windows10在WSL中运行GUI应用

    0. 首先在WSL装X11相关环境 需要安装x11和桌面环境, 在这里装的是xfce4   sudo apt install x11-apps sudo apt install xfce4 有两种显示 ...