OpenGL学习笔记(八)

来源:互联网 发布:淘宝如何提升流量 编辑:程序博客网 时间:2024/06/06 13:15

顶点数组对象(vao)

随着程序逐渐增大并且使用更多的模型,读者可能发现要在每个帧的多组顶点数组之间切换。根据你为每个顶点使用多少个顶点属性,像对glVetexPointer()这样的函数的调用次数可能变得很大。顶点数组对象捆绑了调用的集合,以设置顶点数组的状态。在初始化之后,可以通过单次调用在不同的顶点数组集合之间快速修改。

创建顶点数组对象标识:

void glGenVertexArrays(GLsizei n,GLuint *arrays);

返回n个当前未使用的名字,记录在数组arrays

绑定顶点数组对象:

GLvoid glBindVertexArray(GLuint array);

该函数做3件事情:

1.   当使用的值array不是零并且是从glGenVertexArrays()返回的值时,创建一个新的顶点数组对象并且分配该名字。

2.   当绑定的之前创建的一个顶点数组对象时,该顶点数组对象变成活动的,这影响到存储在该对象中的顶点数组状态

3.   当绑定到一个为零的array值时,OpenGL停止使用顶点数组对象并且返回顶点数组的默认状态

注意:如果array不是之前从glGenVertexArrays()返回的值;如果它是glDeleteVertexArrays()已经释放的值;如果调用了任何一个gl*Pointer()函数来指定一个顶点数组,而在绑定一个非零顶点数组对象的时候,它没有和一个缓冲区对象关联起来,将会产生GL_INVALID_OPERATION错误。

删除顶点数组对象:

void glDeleteVertexArrays(GLsizei n,GLuint *arrays);

删除arrays中指定的n个顶点数组对象,使这些名字随后可以作为顶点数组重用。

确定一个特定的值是否可以表示一个已分配的顶点数组对象,可调用:

GLboolean glIsVertexArray(GLuint array);

如果array是之前glGenVertexArrays()产生的一个顶点数组对象的标识,且没有删除则返回GL_TRUE;如果array0或者一个非顶点数组对象标识的非零值则返回GL_FALSE

示例:展示使用顶点数组对象在两组顶点数组之间进行切换

#define BUFFER_OFFSET(offset) ((GLvoid *)NULL + offset)

#define NumberOf(array) (sizeof(array)/sizeof(array[0]))

typedef struct{

       GLfloat x,y,z;

} vec3;

Typedef struct{

       vec3 xlate;

       GLfloat angle; //旋转角度

       vec3 axis;       //旋转轴

} XForm;

GLuint VAO[2];     //记录数组对象标识

GLenum PrimType[2];   //

GLsizei NumElements[2];     //记录索引长度

XForm xform[2]={

              {{-2.0,0.0,0.0},0.0,{0.0,1.0,0.0}},

              {{0.0,0.0,2.0},0.0,{1.0,0.0,0.0}}

};

GLfloat Angle = 0.0;

void ini{

       glGenVertexArrays(2,VAO); //创建顶点数组对象标识

GLuint buffers[3];  //[0]记录顶点标识,[1]记录颜色标识,[2]记录索引标识

       for(int n=0;n<2;n++){

              GLfloat *verts;//顶点数组

              GLfloat *colors;//颜色数组

              GLubyte *indices;//索引数组

              …

              //初始化顶点、颜色、索引数组

              …

              glBindVertexArray(VAO[n]); //绑定顶点数组对象

              glGenBuffers(3,buffers);              //创建缓冲区对象标识

              glBindBuffer(GL_ARRAY_BUFFER,buffers[0]); //绑定顶点缓冲区对象

              glBufferData(GL_ARRAY_BUFFER,sizeof(verts),verts,GL_STATIC_DRAW);//填充顶点数据

              glVertexPointer(3,GL_FLOAT,0,BUFFER_OFFSET(0));

              glEnableClientState(GL_VERTEX_ARRAY);

             

              glBindBuffer(GL_ARRAY_BUFFER,buffers[1]); //绑定颜色缓冲区对象

              glBufferData(GL_ARRAY_BUFFER,sizeof(colors),colors,GL_STATIC_DRAW);//填充颜色数据

              glColorPointer(3,GL_FLOAT,0,BUFFER_OFFSET(0));

              glEnableClientState(GL_COLOR_ARRAY);

 

              glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,buffers[2]); //绑定索引缓冲区对象

              glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices), indices,GL_STATIC_DRAW);//填充索引数据

             

              PrimType[n] = GL_QUADS; //这里使用该值只是作为示例

              NumElements[n] = NumberOf(indices);

       }

       glEnable(GL_DEPTH_TEST);      //启用深度测试

}

void display(){

       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕

       glPushMatrix(); //将当前矩阵状态入栈,进行保存

       glRotatef(Angle,0.0,1.0,0.0); //旋转

       for(int i=0;i<2;i++){

              glPushMatrix(); //矩阵入栈

              //下面进行一些矩阵变换操作

              glTranslatef(xform[i].xlate.x, xform[i].xlate.y, xform[i].xlate.z);

              glRotatef(xform[i].angle, xform[i].axis.x, xform[i].axis.y, xform[i].axis.z);

              //

              glBindVertexArray(VAO[i]); //激活指定顶点数组对象

              glDrawElements(PrimType[i], NumElements[i]); //绘制

              glPopMatrix(); //矩阵出栈

       }

       glPopMatrix(); //矩阵出栈,恢复原先状态

       …

}

 

附:VBOVAO的一些看法

VBOVertex Buffer Object(顶点缓冲区对象)VAOVertex Array Object(顶点数组对象)

VBO其实就是显卡中的显存,为了提高渲染速度,可以将要绘制的顶点数据缓存在显存中,这样就不需要将要绘制的顶点数据重复从CPU发送到GPU,浪费带宽资源。

而VAO则是一个容器,可以包含多个VBO,它类似于以前的call list,由于它进一步将VBO容于其中,所以绘制效率将在VBO的基础上更进一步。
原创粉丝点击