在opengl中所有的数据都要放在显存中,我们通过一定的手段去管理它,既要提供地方存放它,还要提供方法去正确地提取它们,去使用它们,opengl通过VAO,VBO,EBO这些手段来解决这些问题。 (一)VBO(Vertex Buffer Objects,顶点缓冲对象)介绍: 首先我们要明白VBO是一种管理手段,它的中文名中“缓冲”,就决定了它是管理存储的一种手段(methon),总的来 说,为什么要设置这个VBO,是应该从着色器程序说起。 着色器的第一个顶点着色器接受到我们数据流传入的顶点数据后,它会把这些数据放到GPU的显存上面(等同内存) 接下来向OpenGL中配置如何去解释这些内存,未来如何发给显卡处理。接下来着色器才会按照我们编的代码做我们想做 事情。 我们设立VBO的原因就是要管理这些内存,这样做有很多好处比如:1.我们可以往一个VBO管理的内存中放很多顶点 的数据,这样我们就可以一下子把这些数据都从cpu的数据流上送到GPU(显卡)的显存上,这样节省时间,因为从CPU往 GPU的过程中,要经过很多“关卡”,送一“筐”和送一“卡车”是没有区别的。 (二)声明一个VBO如下:

unsigned int VBO;//声明一个句柄
glGenBuffers(1, &VBO);//1是一个缓冲ID,用Gen生成一个缓冲区。

glBindBuffer(GL_ARRAY_BUFFER, VBO); //用这个函数将这个缓冲区变成一个GL_ARRAY_BUFFER,这是顶点缓冲类型的意思。
//注意这是一个绑定函数,现在所有输入GL_ARRAY_BUFFER的数据,都会直接被送入现在这个VBO,而不是其他的VBO2,VBO3之类的什么,如果
我们不要用这个VBO,想换一个VBO2,我们必须先解绑这个VBO。
//注意我们不会去直接用VBO,因为我们的数据必须全部输入到目标缓冲GL_ARRAY_BUFFER里,这样表明我们输入的是顶点属性,而不是别的
什么。
//这就相当于我们可以输入的缓冲对象类型,已经被设定好了,我们只能往这些地方输入数据,位于它们后面缓冲区,可以不断更换用来实现
不同目的。

(三)往VBO里面放入数据:

     接下来这个函数是很重要的,它是将数据从cpu的流中提取出来,放入显存中的VBO管理的区域里。
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//首先是缓冲类型声明,GL_ARRAY_BUFFER表明数据将被传入刚才绑定这个类型的缓冲区里,第二个是数据流的大小,第三个是数据流名字,
第四个是希望显卡如何管理给定的数据,要告诉显卡这些数据未来会不会被改变。要是希望经常改变的话,显卡会把数据放在能够高速写入
的内存部分,这样节省资源。
GL_STATIC_DRAW :数据不会或几乎不会改变。
GL_DYNAMIC_DRAW:数据会被改变很多。
GL_STREAM_DRAW :数据每次绘制时都会改变。 //到这一步,我们的数据流已经没有用了,放在内存上的缓冲区的坐标数据,将被传入显卡上的着色器,被用来使用。
接下来就是着色器的任务了。如何去解释数据流,将一条连续的float流数据解读为三维的顶点数据(就是将数字变成具有几何意义的坐标点)
这都是着色器的任务了。

在解释什么是VAO之前,我们先要解释一下着色器的一个任务,正是着色器的这个任务,导致我们必须使用VAO这种方式来设置。

复制顶点数组到缓冲中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 1. 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 2. 当我们渲染一个物体时要使用着色器程序
glUseProgram(shaderProgram);
// 3. 绘制物体
someOpenGLFunctionThatDrawsOurTriangle();
//这就是我们渲染一个物体的步骤,其中最重要的就是1.将数据从cpu数据流传入CPU的VBO缓冲区管理的显存里2.将数据流正确的解释成三维
坐标。
//这里使用了一个属于叫做顶点属性指针,他就是用来解释该如何去解释数据流的,使用不同的属性指针可以得到不同的解释。

(四)设立VAO,顶点数组对象(Vertex Array Object):

   一个VAO中包含两个关键东西,glVertexAttribPointer函数绑定的VBO和顶点属性配置(也就是数据放在哪里
,和如何读取数据)。此外还有glEnableVertexAttribArray和glDisableVertexAttribArray这两个函数用来启
用顶点属性,和取消顶点属性链接。
这样就造成了一个你绑定一个VAO就可以知道,去哪里读,用什么方式去解读。
这样你在绑定一个VAO的情况下,便可以绘制这个物体,只要它们的读取方式(顶点属性配置)一样。
注意把顶点数组复制到缓冲中供OpenGL使用,是在VBO里面布置的,
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//举个例子,你想绘制一个边长3cm的立方体,就绑定这个VAO,OPENGL这个状态机下一刻就会绘制出来这个
//如果你想绘制一个长方体,就解绑之前哪个VAO,绑定VAO1,就下一刻绘制出长方体了。

(五)设立EBO,索引缓冲对象(Element Buffer Object):

      索引缓冲对象EBO,不是我们必须设置的东西,我们必须设置VAO,来告诉OpenGL如何读取,将数据放入哪里。但我们不必一定
要有EBO。我们之所以发明EBO是用来简化我们的程序的渲染步骤的,它是用来告诉我们如何去绘制的。
这要从我们3d世界说起,电脑里面的所有3d立体图形,无论是球形,还是不规则图形,它们都是由三角形构成的,也就是说
都是由三个点构成一个面,无数个面构成一个立体图形。这样在不规则立体图形里,必然由许多的点是共用的,我们为了能在输入
数据的时候少输入一些点(传输数据很花时间的),就要想办法将这些共用的点利用起来,只输入一次,这就是EBO的发明原因。
在操作时,我们先输入所有点的数据(VBO,和设置顶点属性指针),再设置将哪些点绘制成面(EBO),这就形成了正规的3d立体图形。
float 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 // 左上角
};
unsigned int indices[] = {
// 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
我们也是用数据流来表明,哪些点构成一个面。
接下来的操作似曾相识,将数据索引复制到缓冲里。
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

在渲染的时候,因为调用了EBO,所以不能用绘制VAO的函数glDrawArrays,要使用兼容glDrawElements,用法是类似的。
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//6的意思是一共绘制六个顶点。0是一个偏移量,这里填0就好了 在绘制的时候,EBO和VBO都可以看作缓存,它们都被VAO管理着,所以实际渲染中,我们只需要绑定VAO,就可以了。

,并且将一条连续的float流数据解读为三维的顶点数据 (就是将数字变成具有几何意义的坐标点)。

LearnOpenGL学习笔记(三)——VBO,VAO,EBO理解的更多相关文章

  1. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  2. java之jvm学习笔记三(Class文件检验器)

    java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...

  3. VSTO学习笔记(三) 开发Office 2010 64位COM加载项

    原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...

  4. 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记

    回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...

  5. ES6学习笔记&lt;三&gt; 生成器函数与yield

    为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...

  6. angular学习笔记(三十一)-$location(2)

    之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...

  7. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  8. angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令

    在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...

  9. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

随机推荐

  1. 给DOM生成的元素添加事件

    问题:通过js给页面添加新元素,并给该元素添加绑定事件,但新添加的元素上却没有绑定任何事件. 常见例子:在处理表格的时候,每行行末有个删除按钮,如下图.点击删除按钮的时候删除这一行. //html部分 ...

  2. Canvas 最佳实践(性能篇)

    Canvas 想必前端同学们都不陌生,它是 HTML5 新增的「画布」元素,允许我们使用 JavaScript 来绘制图形.目前,所有的主流浏览器都支持 Canvas. Canvas 最常见的用途是渲 ...

  3. linux下软件安装与升级

    待续 sudo apt-get update sudo apt-get upgrade sudo apt-get dist-upgrade

  4. Android在listview添加checkbox实现单选多选操作问题(转)

    转自:http://yangshen998.iteye.com/blog/1310183 在Android某些开发需求当中,有时候需要在listveiw中加入checkbox实现单选,多选操作.表面上 ...

  5. hdu 3887 Counting Offspring dfs序+树状数组

    Counting Offspring Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  6. C++ 中的形参与返回值

    函数调用时,形参对象和返回对象均采用引用方式进行(临时对象作为中介),当一个对象作为参数(非引用)被函数调用时,该对象会通过复制构造函数获得一个临时对象,该临时对象以引用方式传递给函数,简言之,函数会 ...

  7. python是一个解释器

    python是一个解释器 利用pip安装python插件的时候,观察到python的运作方式是逐步解释执行的 适合作为高级调度语言: 异常的处理以及效率应该是主要的问题

  8. 【CSS3】---盒模型margin、padding及border

    盒模型--边框 盒子模型的边框就是围绕着内容及补白的线,这条线你可以设置它的粗细.样式和颜色(边框三个属性). 如下面代码为 div 来设置边框粗细为 2px.样式为实心的.颜色为红色的边框: div ...

  9. kettle列转行

  10. jQuery 定时局部刷新(setInterval)方法总结

    来自:http://www.jbxue.com/article/8516.html 1.jQuery 定时局部刷新(setInterval),显示时间的代码. <head> <scr ...