• 【OpenGL 学习笔记04】顶点数组


    通过之前的学习,我们知道,如果要绘制一个几何图形,那就要不断的调用绘制函数,比如绘制一个20条边的多边形,起码要调用22条函数(包含glBegin和glEnd)。
    所以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);
    }

    一目了然啊有木有...


  • 相关阅读:
    Android Studio打包过程和应用安装过程
    MVP模式和Clean模式
    Gradle入门学习---认识buildeTypes和dependencies
    微信小程序官方DEMO解读
    从ListView逐步演变到RecyclerView
    Mac下如何配置环境变量
    Android上滑手势触发和不增加布局层级扩大点击区域
    寻找Fragment的替代品的尝试
    高效的策略模式设计方法
    利用ListView的基本方法实现效果
  • 原文地址:https://www.cnblogs.com/fzll/p/3954573.html
Copyright © 2020-2023  润新知