开始opengl第八版-1.VAO与VBO

来源:互联网 发布:最好的公交查询软件 编辑:程序博客网 时间:2024/05/17 00:08

http://www.cnblogs.com/MyGameAndYOU/p/4678657.html 

http://blog.csdn.net/candycat1992/article/details/39676669    理解VAO与VBO

传递顶点数据

那么,现在的问题是,如果是你,你会怎么把顶点和它相关的信息,例如纹理坐标、法线等,传递给GLSL呢?一般人都会想到多维数组。我们下面把它称为顶点流(Vertex Stream)。(什么?!你不是这么想的?!没关系,OpenGL是这么想的就好。。。)

我们负责创建这个顶点流,然后只需要告诉OpenGL怎样解读它就可以了。
为了渲染一个对象,我们必须使用一个shader program。而这个program会定义一系列顶点属性,例如上述Vertex Shader中的vPosition一行。这些属性决定了我们需要传递哪些顶点数据。每一个属性对应了一个数组,并且这些数据的维度都必须相等,即是一一对应的关系。
比如我们想要渲染3个顶点,我们会定义下面的数据:
[plain] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. { {1, 1, 1}, {0, 0, 0}, {0, 0, 1} }  
这些顶点的顺序是非常重要的,OpenGL将会根据这些顺序渲染网格。我们可以直接使用上述这种数据来直接渲染,也可以使用索引(indices)来指定顺序,这样可以重复使用同一个顶点。
例如,我们使用下面的索引列表:
[plain] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. {2, 1, 0, 2, 1, 2}  
那么OpenGL将会渲染6个顶点:
[plain] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. { {0, 0, 1}, {0, 0, 0}, {1, 1, 1}, {0, 0, 1}, {0, 0, 0}, {0, 0, 1} }  
现在,我们还想传递一个新的顶点属性,即每个顶点的纹理坐标,那么新的纹理数组可能长这样:
[plain] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. { {0, 0}, {0.5, 0}, {0, 1} }  
注意,纹理数据的维度大小一定要和上面的坐标数组大小一致,而其他顶点属性数组的维度也要满足这个条件。这是非常容易理解的。
那么,合并后的顶点属性列表就是:
[plain] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. [{0, 0, 1}, {0, 1}], [{0, 0, 0}, {0.5, 0}], [{1, 1, 1}, {0, 0}], [{0, 0, 1}, {0, 1}], [{0, 0, 0}, {0.5, 0}], [{0, 0, 1}, {0, 1}] }  

OpenGL的做法:VAO和VBO


OpenGL使用了VAO来实现上述管理顶点数据的数据作用,以及VBO来存放真正的顶点属性数据。

VAO(Vertex Array Object)


我们这里遇到了第一种OpenGL对象——VAO(Vertex Array Object)。前面说到OpenGL对象是状态的集合,那么VAO就是所有顶点数据的状态集合。它存储了顶点数据的格式以及顶点数据数据所需的缓存对象的引用。前面提过,OpenGL对象都有三个非常重要的函数,而VAO对应的就是glGenVertexArrays、glDeleteVertexArrays和glBindVertexArray​。

VAO负责管理顶点属性,而这些顶点属性从0到GL_MAX_VERTEX_ATTRIBS​ - 1被编号。这些属性在Vertex Shader里的表现就是类似下面的语句:
[plain] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. layout(location = 0) in vec4 vPosition;  

上述顶点属性vPosition被编号为0。
每个属性可以被enable或者disable,被disable的属性是不会传递给shader的,即便在shader里定义了这些属性,它们读出的值也会是一个常量,而非真正的数据。一个新建的VAO的所有属性访问都是disable的。而开启一个属性是通过下面的函数:
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. void glEnableVertexAttribArray​(GLuint index​);  
与其对应的是glDisableVertexAttribArray​ 函数。
而为了使用上述函数来改变VAO的状态,我们首先需要把VAO绑定到当前的context上。

VBO(Vertex Buffer Object)

VBO是一种Buffer Object,即它也是一个OpenGl对象。VBO是顶点数组数据真正所在的地方。
为了指定一个属性数据的格式和来源,我们需要告诉OpenGL,编号为0的属性使用哪个VBO,编号为1的属性使用哪个VBO等等。为了实现它,我们可以这么做。
首先,我们要知道,任何VBO都需要先绑定到GL_ARRAY_BUFFER​才可以对它进行操作。绑定后,我们可以调用下面的函数之一:
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. void glVertexAttribPointer​( GLuint index​, GLint size​, GLenum type​,  
  2.    GLboolean normalized​, GLsizei stride​, const void *offset​);  
  3.  void glVertexAttribIPointer​( GLuint index​, GLint size​, GLenum type​,  
  4.    GLsizei stride​, const void *offset​ );  
  5.  void glVertexAttribLPointer​( GLuint index​, GLint size​, GLenum type​,  
  6.    GLsizei stride​, const void *offset​ );  
它们的作用大同小异,就是告诉OpenGl,编号为index的属性使用当前绑定在GL_ARRAY_BUFFER​的VBO。为了更好理解,我们举例:
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. glBindBuffer(GL_ARRAY_BUFFER, buf1);  
  2. glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);  
  3. glBindBuffer(GL_ARRAY_BUFFER, 0);  
上面第一行代码将buf1绑定到了GL_ARRAY_BUFFER​上。第二行意味着,编号为0的属性将使用buf1的数据,因为当前绑定到GL_ARRAY_BUFFER​上的是buf1。第三行将缓存对象0绑定到了GL_ARRAY_BUFFER​上,这不会对顶点属性有任何影响,只有glVertexAttribPointer​函数可以影响它们!
这个过程就像一个中介人的作用,而中介人就是GL_ARRAY_BUFFER​。我们可以这么想,glBindBuffer​ 设置了一个全局变量,然后glVertexAttribPointer读取了这个全局变量并把它存储在VAO中,这个全局变量就是GL_ARRAY_BUFFER。当调用完glVertexAttribPointer后,顶点属性已经知道了数据来源就是buf1,它们之间就会直接联系,而不需要在通过GL_ARRAY_BUFFER


使用VAO与VBO,将其关联,并将数据传递到shader,用法
 /**
        函数原型:void glVertexAttribPointer(GLuint index, GLint size, GLenum type,
        GLboolean normalized, GLsizei stride, const GLvoid* pointer);
        之前我们调用了glBindData所传递给缓存的只是数据,之后我们要使用它,还必须指定数据类型。
        所以该函数完成的主要任务是:
        1、告诉OpenGL,该存储数据的格式
        2、因为我们使用着色器来编程,因此在顶点着色器阶段,我们会使用该函数来给着色器中的in类型的属性变量传递数据。
           那么它们是怎么联系起来的呢?
           便是通过第一个参数index,指明了着色器程序中变量的下标的作用。
           例如:layout( location=index ) in vec4 position;
           如果这个index和glVertexAttribPointer的第一个参数一样,那么相关缓存区的数据就会传递到这个position变量中去。
        3、该函数执行之后,会影响改变VAO的状态,VBO会被复制保存到VAO中。之后如果改变了当前所绑定的缓存对象,也不会改变到VAO里的对象。
    */
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    /**
        因为默认情况下,顶点属性数组是不可访问的,所以我们需要调用以下函数激活它。
        范围为0到GL_MAX_VERTEX_ATTRIBS-1
    */
    glEnableVertexAttribArray(vPosition);

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 oracle数据库密码忘了怎么办 电脑开机时不显示用户名怎么办? xp系统忘记开机密码怎么办 电脑开机密码忘了怎么办 c盘满了怎么办win10 win10电脑开机密码忘了怎么办 win10的开机密码忘了怎么办 u盘中了exe病毒怎么办 眼睛长个麦粒豆怎么办 苹果手机sdk授权失败怎么办 小米5王者荣耀卡怎么办 华为p9手机电池不耐用怎么办 华为g9青春版耗电快怎么办 华为手机摄像头坏了怎么办 华为p10摄像头玻璃划痕怎么办? 华为g9手机音量小怎么办 华为7pius太卡怎么办 华为畅享7plus卡怎么办 华为p9屏幕进水变颜色怎么办? 玩王者荣耀卡退怎么办 华为手机忘记开机密码怎么办 华为p9密码忘了怎么办 华为p9解锁密码忘了怎么办 华为手机不支持联通4g怎么办 酷派手机自动下载软件怎么办 小米5a不能开机怎么办 华为手机的视频找不到了怎么办 华为p8内存文件打不开怎么办 华为荣耀9网速慢怎么办 荣耀9手机网速慢怎么办 联想台式机不支持xp驱动怎么办 一体机尾插坏了怎么办 华为手机触屏失灵怎么办 华为p8max手机老是卡怎么办 手机屏碎了数据怎么办 华为p9屏碎了怎么办 华为p7一l09卡顿怎么办 华为p7打不开机怎么办 华为8主板坏了怎么办 华为手机主板坏了怎么办 华为p9文字变英文了怎么办