【OpenGL 学习笔记04】顶点数组
通过之前的学习,我们知道,如果要绘制一个几何图形,那就要不断的调用绘制函数,比如绘制一个20条边的多边形,起码要调用22条函数(包含glBegin和glEnd)。
所以OpenGL提供了一系列的顶点数组函数减少函数调用的次数来提高性能。而且使用顶点还可以避免顶点共享的冗余处理。
对于上面的示例,我们使用顶点数组如下:
现在我们合并成一个数组,stride参数指定如何跨距数据(由于跨距需要计算数据类型,所以数组的数据类型需要相同),具体如下:
一目了然啊有木有...
所以OpenGL提供了一系列的顶点数组函数减少函数调用的次数来提高性能。而且使用顶点还可以避免顶点共享的冗余处理。
1.简单示例
先来回顾一下之前我们是怎么画直线的:
void drawOneLine(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2) { glBegin(GL_LINES); glVertex2f (x1,y1); glVertex2f (x2,y2); glEnd(); }
对于上面的示例,我们使用顶点数组如下:
void drawLineWithArray() { GLint vertices[]={25,25, 100,100 }; glEnableClientState(GL_VERTEX_ARRAY);//启用顶点数组 glVertexPointer(2,GL_INT,0,vertices);//指定数组数据 glBegin(GL_LINES); glArrayElement(0); //解引用和渲染 glArrayElement(1); glEnd(); }
2.使用顶点数组的三个步骤
(1)先启用顶点数组
//指定需要启动的数组(GL_VERTEX_ARRAY,GL_COLOR_ARRAY,GL_INDEX_ARRAY等8个可用数组) void glEnableClientState(GLenum array);
(2)指定数组数据
//size表示顶点坐标数量(2,3,4),type表示数据类型,stride表示连续顶点之间字节偏移(0表示紧密相邻),pointer表示数组首地址 void glVertexPointer(GLint size,GLenum type,GLsizei stride,const GLvoid* pointer); //其它几个数组等 void glColorPointer(GLint size,GLenum type,GLsizei stride,const GLvoid* pointer); void glColorPointer(GLenum type,GLsizei stride,const GLvoid* pointer); ...
(3)解引用和渲染
解引用单个//获取当前所哟启用的数组第ith个顶点数据(从0开始算) void glArrayElement(GLint ith);解引用多个
//mode指定要创建图元的类型(和glBegin参数相同),count为顶点数量,type为顶点数据类型,indices表示索引数组首地址 //glDrawElements的作用相当于多条glArrayElement(indices[i]) void glDrawElements(GLenum mode,GLsize count,GLenum type,const GLvoid* indices); //相当于primcount条glDrawElements(mode,count[i],type,indices[i])语句 void glMultiDrawElements(GLenum mode,GLsize* count,GLenum type,const GLvoid** indices,GLsizei primcount); //相当于有范围的glDrawElements,范围为[start,end] void glDrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsize count,GLenum type,const GLvoid* indices); //创建一个图元序列,从每个被启用的数组,范围为[first,first + count - 1] void glDrawArrays(GLenum mode,GLint first,GLsizei count); //相当于primcount条glDrawArrays(mode,first[i],count[i]) void glMultiDrawArrays(GLenum mode,GLint* first,GLsizei* count,GLsizei primcount);
3.使用顶点数组的一个示例
我们现在有一个顶点数组和一个颜色数组,我们使用它们来两条画线:#include <GL/glut.h> void display(void) { glClear (GL_COLOR_BUFFER_BIT); //清除颜色缓冲区 static GLint vertices[]={25,25, 100,100, 120,120, 200,200}; static GLfloat colors[]={1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0}; GLubyte index[]= {0,1,2,3} ; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2,GL_INT,0,vertices); glColorPointer(3,GL_FLOAT,0,colors); glDrawElements(GL_LINES,4,GL_UNSIGNED_BYTE,index);//这条语句等价于如下注释的语句 // glBegin(GL_LINES); // glArrayElement(0); // glArrayElement(1); // glArrayElement(2); // glArrayElement(3); // glEnd(); glFlush (); } void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h);//调整绘图的像素矩阵大小 glMatrixMode (GL_PROJECTION); //将当前矩阵指定为投影矩阵 glLoadIdentity (); //把当前矩阵设为单位矩阵 gluOrtho2D (0.0, (GLdouble) w, 0.0, (GLdouble) h); } void init (void) { glClearColor (0.0, 0.0, 0.0, 0.0); //设置窗口将被清除成黑色 glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影矩阵 glLoadIdentity(); //把当前矩阵设为单位矩阵 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);//指定绘制图像时使用的坐标系统 glOrtho(Xmin,Xmax,Ymin,Ymax,Zmin,Zmax); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (250, 250); glutInitWindowPosition (100, 100); glutCreateWindow ("hello"); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }效果图:
4.顶点数组跨距
来简单回顾一下上面那个例子:
void display() { GLint vertices[]={25,25, 100,100, 120,120, 200,200}; GLfloat colors[]={1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0}; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2,GL_INT,0,vertices); //从vertices[0]开始获取,每次获取2个,下一次从vertices[2]开始获取 glColorPointer(3,GL_FLOAT,0,colors); glBegin(GL_LINES); glArrayElement(0); glArrayElement(1); glArrayElement(2); glArrayElement(3); glEnd(); }
现在我们合并成一个数组,stride参数指定如何跨距数据(由于跨距需要计算数据类型,所以数组的数据类型需要相同),具体如下:
void display() { 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]);//从data[0]开始获取,每次获取3个,下一次从data[0+5]获取3个... glVertexPointer(2,GL_FLOAT,5*sizeof(GLfloat),&data[3]);// glBegin(GL_LINES); glArrayElement(0); glArrayElement(1); glArrayElement(2); glArrayElement(3); glEnd(); }
5.混合数组
glInterleavedArrays的作用相当于:步骤1启用数组 + 步骤2指定数组数据。
//初始化全部的8个数组,并禁用format没有指定的数组。stride为连续顶点之间字节偏移,pointer为数组首地址 void glInterleavedArrays(GLenum format,GLsizei stride,const GLvoid* pointer);
void display() { GLfloat data[]= {1.0, 0.0, 0.0,25.0,25.0,0.0, 1.0, 0.0, 0.0,100.0,100.0,0.0, 0.0, 1.0, 0.0,120.0,120.0,0.0, 0.0, 1.0, 0.0,200.0,200.0,0.0}; glInterleavedArrays(GL_C3F_V3F,0,data); //启用颜色数组和顶点数组 并指定数据 glDrawArrays(GL_LINES,0,4); //相当于循环调用4次glArrayElement(i),i为0到3 }现在去掉颜色的数组的话,代码如下:
void drawTwoLineWithArray2() { GLfloat data[]= {25.0,25.0, 100.0,100.0, 120.0,120.0, 200.0,200.0}; glInterleavedArrays(GL_V2F,0,data); glDrawArrays(GL_LINES,0,4); }
一目了然啊有木有...