LearnOpenGL学习笔记(三)——VBO,VAO,EBO理解
在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理解的更多相关文章
- [Firefly引擎][学习笔记三][已完结]所需模块封装
原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读: 笔记三主要就是各个模块的封装了,这里贴 ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
- VSTO学习笔记(三) 开发Office 2010 64位COM加载项
原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...
- 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记
回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...
- ES6学习笔记<三> 生成器函数与yield
为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...
- angular学习笔记(三十一)-$location(2)
之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...
- angular学习笔记(三十)-指令(7)-compile和link(2)
继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...
- angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令
在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...
- openresty 学习笔记三:连接redis和进行相关操作
openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...
随机推荐
- Android开发日常-listview滚动方法梳理
listview滚动方法梳理 1.setSelection(position); 滚动到指定条目 2.setSelectionFromTop(position,y): 距离指定条目向下偏移y(像素) ...
- c++矩阵运算库Eigen简介
C++矩阵运算库Eigen介绍 C++中的矩阵运算库常用的有Armadillo,Eigen,OpenCV,ViennaCL,PETSc等.我自己在网上搜了一下不同运算库的特点,最后选择了Eigen.主 ...
- Eclipse Golang 开发环境搭建 GoClipse 插件
Windows平台 下载完成后,直接双击安装即可 默认情况下,.msi文件会安装在 C:\Go 目录下.可以将 C:\Go\bin 目录添加到环境变量 PATH 中,方便调用命令. Go 里面有两个非 ...
- SQL 不常用的一些命令sp_OACreate,xp_cmdshell,sp_makewebtask
开启和关毕xp_cmdshell EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cm ...
- linux 基础 文件系统 用户权限
描述Linux系统的启动过程? 1.开机自检 BIOS 2.MBR引导 3.GRUB菜单 4.加载内核 5.运行init进程 6.从/etc/inittab读取运行级别 7.根据/etc/rc.sys ...
- Unity3D使用EasyMovieTexture插件播放视频
Unity3D对于视频的播放兼容个人感觉很差劲,之前写过一篇使用Unity3D自己自带的一些功能去播放视频,链接如下: http://www.cnblogs.com/xiaoyulong/p/8627 ...
- PowerShell 使用.NetFramework
我们都知道,由于PowerShell是基于.NETFramework建立的所以它能够具备访问.NET的能力,因为.NET提供了庞大的数据类库,所以我们可以很好的使用PowerShell去完成一些Pow ...
- 2.3.7synchronized代码块有volatile同步的功能
关键字synchronized可以使多个线程访问同一个资源具有同步性,而且他还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能. package com.cky.thread; /** * ...
- springMVC一个Controller处理所有用户请求的并发问题(转)
springMVC一个Controller处理所有用户请求的并发问题 有状态和无状态的对象基本概念: 有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的.一 ...
- 文件描述符fd、文件指针fp和vfork()
1. fd:在形式上是一个非负整数.实际上他是一个索引值.指向kernal为每一个进程所维护的该进程打开文件的记录表. 当程序打开一个文件或者创建一个新文件的时候kernal向进程返回一个文件描述符. ...
