顶点数组
根据前面的介绍,OpenGL需要进行大量的函数调用才能完成对几何图元的渲染。如绘制一个20条边的多边形至少需要22个函数调用。首先调用1次glBegine(),然后为每个顶点调用1次函数,最后调用1次glEnd()。有时还需要额外的信息,也增加函数的调用。这样就成倍地增加渲染几何物体所需要的函数调用数量,直接影响到了应用程序的性能。
OpenGL提供了一些顶点数组函数,允许只用少数几个数组指定大量的与顶点相关的数据,并用少量函数调用访问这些数据。使用顶点数组,一个拥有20条边的多边形的20个顶点可以放在1个数组中,并且只通过1个函数进行调用。
使用顶点数组对几何图形进行渲染步骤:
1) 激活(启用)最多可达8个数组,每个数组用于存储不同类型的数据:顶点坐标、表面法线、RGBA颜色、辅助颜色、颜色索引、雾坐标、纹理坐标以及多边形的边界标志。
2) 把数据放入数组中。
3) 用这些数据绘制几何图形。
步骤1.启用数组
void glEnableClientState(GLenum array);
指定了需要启用的数组。array参数列表如下:
GL_VERTEX_ARRAY 顶点数组
GL_COLOR_ARRAY 颜色数组
GL_SECONDARY_COLOR_ARRAY 辅助色数组
GL_INDEX_ARRAY 索引数组
GL_NORMAL_ARRAY 法向量数组
GL_FOG_COORDINATE_ARRAY 雾坐标数组
GL_TEXTURE_COORD_ARRAY 纹理坐标数组
GL_EDGE_FLAG_ARRAY 边界标志数组
理论上说,最多可调用该函数8次,激活8个可用的数组。但在实践中,可以激活的数组最多只有6个,因为有些数组不能同时激活。
相应地,有启用函数就有禁用函数:
void glDisableClientState(GLenum array);
指定了需要禁用的数组,接受的参数与glEnableClientState()函数相同。
步骤2.指定数组的数据
共有8个不同的函数用来指定数组,每个函数用于指定一个不同类型的数组。
void glVertextPointer(Glint size,GLenum type,GLsizei stride,const void *pointer);
void glColorPointer(Glint size,GLenum type,GLsizei stride,const void *pointer);
void glTexCoordPointer(Glint size,GLenum type,GLsizei stride,const void *pointer);
void glSecondaryColorPointer(Glint size,GLenum type,GLsizei stride,const void *pointer);
void glIndexPointer(GLenum type,GLsizei stride,const void *pointer);
void glNormalPointer(GLenum type,GLsizei stride,const void *pData);
void glFlgCoordPointer(GLenum type,GLsizei stride,const void *pointer);
void glEdgeFlagPointer(GLenum type,GLsizei stride,const void *pointer);
参数size-是每个顶点的坐标数量,一般来说表示二维空间(x,y)则顶点的坐标数量为2
参数type-指定了数组中每个坐标的数据类型(GL_SHORT、GL_INT、GL_FLOAT或GL_DOUBLE)
参数stride-指定了每个数组元素之间以字节为单位的空隙。一般情况下,该值为0,也就是数组元素之间没有空隙。
参数pointer/pData-是指向数据数组的指针
步骤3.用数据绘图
在顶点数组的内容被解引用(即提取指针指向的数据)之前,数组一直保存在客户端,它们的内容很容易进行修改。在此步骤中,数组中的数据被提取,接着发送到服务器,然后发送到图形处理管线进行渲染。
解引用单个数组元素
void glArrayElement(Glint ith);
获取当前所有已启用数组的第ith个顶点的数据。使用glArrayElement的优点就是只要用一个函数调用就可以替代为一个特定顶点所有数据所需要的几个函数调用(glNormal、glColor、glVertex等)。
示例:一个具有颜色的三角形
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(3,GL_FLOAT,0,colors); //colors是三角形顶点rgb颜色数组
glVertexPointer(2,GL_INT,0,vertices); //vertices是三角形二维坐标数组
//绘制三角形
glBegin(GL_TRIANGLES);
glArrayElement(0); //解引用第一个元素
glArrayElement(1); //解引用第二个元素
glArrayElement(2); //解引用第三个元素
glEnd();
上面代码最后5行与下面代码段具有相同的效果
glBegin(GL_TRIANGLES);
glColor3fv(colors);
glVertex2iv(vertices);
glColor3fv(colors + (1 * 3));
glVertex2iv(vertices + (1 * 2));
glColor3fv(colors + (2 * 3));
glVertex2iv(vertices + (2 * 2));
glEnd();
由于glArrayElement()对于每个顶点只调用1次,因此减少函数调用的数量,从而提高程序的总体性能。
解引用数组元素的一个列表
void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid *indices);
使用count个元素定义一个几何图元序列,这些元素的索引值保存在indices数组中。Type必须是GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT或GL_UNSIGNED_INT,表示indices数组的数据类型。mode参数指定了被创建的是哪种类型的图元,它的值和glBegin()函数所接受的参数值相同。
glDrawElements(mode, count, type, indices)的效果几乎相当于下面代码:
glBegin(mode);
for(i=0;i<count;i++)
glArrayElement(indices[i]);
glEnd();
解引用一个数组元素序列
void glDrawArrays(GLenum mode,Glint first,GLsizei count);
创建一个几何图元序列,使用每个被启用的数组中从first开始,到first+count-1结束的数组元素。
glDrawArrays(mode,first,count)的效果几乎相当于下面代码:
glBegin(mode);
for(i=0;i<count;i++)
glArrayElement(first + i);
glEnd();