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. 基于 OAuth2.0 协议的单点登录系统方案设计

    一.什么是单点登录? 单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一.SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用 ...

  2. Flutter TextField开始输入中文的时候,被打断导致错误输入字母问题

    一.Bug样例 建立一个web demo flutter run -d chrome --web-renderer html 出现问题: 输入中文的时候,比如打字 hao, 第一个字母h会先输入,变成 ...

  3. NOIP模拟53

    我在时光斑驳深处,聆听到花开的声音. 前言 这套题好像是随便拼接起来的,来自三套不同的题,最后一道还是学长出的(nb 场上为数不多的几次死磕一道题正解,大概有三个小时吧(惭愧,前两个小时看错题了,一直 ...

  4. containerd 源码分析:创建 container(三)

    文接 containerd 源码分析:创建 container(二) 1.2.2.2 启动 task 上节介绍了创建 task,task 创建之后将返回 response 给 ctr.接着,ctr 调 ...

  5. python的一些常用编码技巧(持续更新)

    语法问题 我常用的库函数 1 copy库 import copy copy.deepcopy() 2.list库 from typing import List 获取迭代对象的第一个值 方法一:使用l ...

  6. MySQL创建表的时候建立联合索引的方法

    1.MySQL创建表建立联合索引的步骤 在MySQL中,联合索引(也称为复合索引或多列索引)是基于表中的多个列创建的索引.这种索引可以提高多列查询的性能,特别是当查询条件涉及这些列时.下面是一个详细的 ...

  7. 别想宰我,怎么查看云厂商是否超卖?详解 cpu steal time

    据说有些云厂商会超卖,宿主有 96 个核心,结果卖出去 100 多个 vCPU,如果这些虚机负载都不高,大家相安无事,如果这些虚机同时运行一些高负载的任务,相互之间就会抢占 CPU,对应用程序有较大影 ...

  8. 网络诊断工具traceroute的使用

    在 Linux 系统中,traceroute 是一个网络诊断工具,用于确定数据包从你的计算机到目标主机(如一个网站或远程服务器)所经过的路由路径. 如果你的系统中没有安装 traceroute,你可以 ...

  9. undefined,null 和 undeclared 有什么区别?

    a.null表示"没有对象",即该处不应该有值,转为数值时为0.典型用法是:作为函数的参数,表示该函数的参数不是对象.作       为对象原型链的终点. b.undefined表 ...

  10. 第四届物联网与机器学习国际学术会议(IoTML 2024)

    [ACM独立出版,高录用,见刊检索快速稳定]第四届物联网与机器学习国际学术会议(IoTML 2024) [IoTML 2023会后三个半月内完成EI检索]2024 4th International ...