OpenGL加速渲染:顶点数组

         加速渲染主要有两种方法:显示列表顶点数组

         其中,显示列表是通过预编译方式加速,而顶点数组是通过优化实时编译方式加速。但是,不需要同时使用两种加速方式。如果把顶点数组放在预编译中,然后通过显示列表来显示,这样做所耗时间与直接使用顶点数组所耗时间基本相同。

         使用顶点数组,也就是把所有点存储在一个数组中,然后将该数组的地址属性通知给OpenGL,然后使用顶点调用函数来调用所有的顶点。OpenGL会对调用进行优化。

         其具体步骤如下:

1.  建立一个GLfloat型一位数组。比如要以三维方式显示一张6×7的图片上的每个点,那么就共有42个点,每个点含(x,y,z)共3个分量。所以该数组共有6×7×3=126个元素。

GLfloat	vPoints[126];

然后为每个元素赋值。按照x0,y0,z0,x1,y1,z1……的方式进行顺序赋值。

2.  在场景绘制函数中,启用顶点数组:

glEnableClientState(GL_VERTEX_ARRAY);

3.  设置顶点数组的地址及属性

glVertexPointer(3, GL_FLOAT, 0, vPoints);

①  3表示顶点数组由3个成分组成(x,y,z);

②  GL_FLOAT表示每个成分的数据类型都是GLfloat型;

③  0表示每个数组元素间以字节为单位的空隙,一般为0;vPoints指定了数组的首地址。

4.  访问顶点数组

glBegin(GL_POINTS);
for (int i = 0; i < 42; i++)
	glArrayElement(i);
glEnd();

这样,就会将顶点以点的形式绘制出来。

glArrayElement(i);即可访问第i个元素的(x,y,z)坐标值。该函数用于单个元素的访问。

伪代码如下:

GLfloat	vPoints[126];

对每个元素进行赋值

glEnableClientState(GL_VERTEX_ARRAY); //启用顶点数组
glVertexPointer(3, GL_FLOAT, 0, vPoints); //设置顶点数组属性
glBegin(GL_POINTS);
for (int i = 0; i < 42; i++)
	glArrayElement(i);	//访问顶点数组
glEnd();
glDisableClientState(GL_VERTEX_ARRAY); //禁用顶点数组

关于涉及到的几个函数:

1.      glEnableClientState

         在OpenGL使用客户/服务器模型。在个人电脑上,服务器指的是图形硬件,比如显卡等,而客户端指CPU和内存。也就是说,CPU和内存需要显卡为其提供服务。

         OpenGL的绝大部分函数是使用客户/服务器模型,比如glEnable/glDisable。但是也有部分函数只针对客户端使用。

void glEnableClientState(GLenum array);	//启用客户端功能
void glDisableClientState(GLenum array);	//禁用客户端功能

         以上两个函数仅针对客户端,用于启用/禁用指定功能。当

         其中GLenum的取值为:

         GL_VERTEX_ARRAY                                                         //顶点数组

         GL_COLOR_ARRAY                                                 //颜色数组

         GL_SECONDARY_COLOR_ARRAY

         GL_NORMAL_ARRAY

         GL_FOG_COORDINATE_ARRAY

         GL_TEXURE_COORD_ARRAY

         GL_EDGE_FLAG_ARRAY

         在相关绘制结束后一定要调用glDisableClientState来禁用客户端功能,否则会影响到接下来的绘制。比如在GL_COLOR_ARRAY生效时,glColor3f是无效的。

         客户端功能允许在一次绘制中打开/关闭多次。但不允许多次打开而不关闭。且一旦客户端功能打开,其相应的数组必须调用glVertexPointer来设置,否则会出错。

2.      glVertexPointer

void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);

         该函数仅用于设置顶点数组的地址及属性。

         GLint size:指定每个顶点的坐标分量个数,只可以为2、3、4中的一个,默认为4

         GLenum type:指定顶点的数据类型,取值为:GL_BYTE, GL_SHORT,GL_FIXED,GL_FLOAT

         GLsizei stride:指定每个数组元素的总大小,以字节为单位。默认为0,OpenGL会按照已设的size自行计算。但若使用混合数据,比如3个坐标分量后面跟着3个坐标颜色分量,那么该值就需要设置为6*sizeof(GLfloat),也就是元素1偏移6*sizeof(GLfloat)即为元素2

         在该例中,设为0或者设为3*sizeof(GLfloat)结果是相同的。因为若设为0,系统会按照size自行计算出3*sizeof(GLfloat)

         const GLvoid *pointer:指定顶点数组首地址

         glVertexPointer对应于glEnableClientState(GL_VERTEX_ARRAY );用于启用顶点数组。同理地:

①  glEnableClientState(GL_ COLOR _ARRAY         )对应于:

void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);

②  glEnableClientState(GL_SECONDARY_COLOR_ARRAY)对应于:

void glSecondaryColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);

③  glEnableClientState(GL_NORMAL_ARRAY)对应于:

void glNormalPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);

④  glEnableClientState(GL_TEXURE_COORD_ARRAY)对应于:

void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);


3.      glArrayElement

void glArrayElement(GLint index);

         该函数用于访问所有已启用顶点数组,且只能访问单个元素。注意此时访问的是整个元素,不是元素的某一部分。比如元素是点,那么glArrayElement (k)就是访问序号为k的点,而不是序号为k的GLfloat组成部分。这是由顶点设置所造成的。

         注意,可以同时启用多种顶点数组,且使用glArrayElement进行同时访问,来达到将不同顶点数组中的数据进行组合的效果。

         例如:

glEnableClientState(GL_VERTEX_ARRAY); / 启用顶点数组
glEnableClientState(GL_COLOR_ARRAY); / 启用颜色数组
glVertexPointer(3, GL_FLOAT, 0, vertices); //设置顶点数组
glColorPointer(3, GL_FLOAT, 0, colors); //设置颜色数组
glBegin(GL_LINES);
glArrayElement(0); //同时访问所有启用数组的0号元素
glArrayElement(1); //同时访问所有启用数组的1号元素
glEnd();

         在上面例子中,同时启用了两个数组:顶点数组与颜色数组。当调用glArrayElement(0)时,会对两个启用的数组同时访问,从而既获取了顶点信息又获取了颜色信息。

         也可以使用混合数组:

GLfloat data[] = {	1.0, 0.0, 0.0,	25.0,25.0,
					1.0, 0.0, 0.0,	100.0,100.0,
					0.0, 1.0, 0.0,	120.0,120.0,
					0.0, 1.0, 0.0,	200.0,200.0 };
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), &data[0]);
glVertexPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), &data[3]);
glArrayElement(0);

  在上面的data[]中,每一行都按(3个颜色分量,2个坐标分量)构成。所以:

glColorPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), &data[0]);

        表示每个颜色元素含3个GLfloat分量,每两个元素首地址之间偏移量为5*sizeof(GLfloat)。第0个颜色元素的首地址为&data[0]。

glVertexPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), &data[3]);

   表示个坐标元素含2个GLfloat分量,每两个元素首地址之间偏移量为5*sizeof(GLfloat)。第0个坐标元素的首地址为&data[3]。

glArrayElement(0);

   表示调用第0个元素。也就是(1.0,0.0, 0.0,        25.0,25.0)。并且会按照颜色为(1.0,0.0, 0.0),坐标为(25.0,25.0)来解析。

4.       glDrawArrays

void glDrawArrays(GLenum mode, GLint first, GLsizei count);

         glArrayElement一次只能访问一个元素。有时候需要对一片数据区进行访问,那么可以使用glDrawArrays。这是一个绘制函数,且不需要在glBegin/glEnd之间调用。

GLenum mode:绘制方式,有以下参数:GL_POINTSGL_LINESGL_LINE_LOOPGL_LINE_STRIPGL_TRIANGLESGL_TRIANGLE_STRIPGL_TRIANGLE_FAN

GLint first:从数组缓存中的哪一个元素开始绘制,也就是第一个绘制顶点的序号,一般为0

GLsizei count:数组中需绘制顶点的数量。注意是顶点数量,而非GLfloat元素个数,也不是最后绘制顶点的序号

例:

points中共存储了0-98个GLfloat元素,每个顶点占用3个GLfloat元素,所以共有33个顶点。

glDrawArrays(GL_POINTS, 5, 20);//以点的形式将数组中5-20号元素(共计16个)绘制出来。绘制时使用的GLfloat为15-60号GLfloat元素
glDrawArrays(GL_POINTS, 0, 33);//全部绘制。注意后面两个参数

OpenGL会对数据块的传输进行优化,从而使其性能明显优于多次调用单独的顶点函数。

glDrawArrays会从glEnableClientState所启用的所有数组中查找对应的数据。因此,若调用glEnableClientState来启用了一个数组,那么就必须为该数组调用glVertexPointer等函数来指定数组属性。否则会出现非法访问内存。

猜你喜欢

转载自blog.csdn.net/fyyyr/article/details/79298740
今日推荐