所以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);
}
一目了然啊有木有...