OpenGL基本图元的连接方式及练习

OpenGL图元

图元即基本图形元素,是任何一个图形表达都是由若干不同的点、线、面图案或相同的图案循环组合而成的。这些点、线、面图案即为基本图形元素,简称图元。OpenGL中通过不过的图元来呈现不同的图像。


图元

GL_POINTS   每个顶点在屏幕上都是独立的点

GL_LINES        每两个顶点定义一条线段,两两连接

GL_LINES_STRIP    将每一个顶点依次连接的线

GL_LINE_LOOP    将每一个顶点依次连接的闭合线段

GL_POLYGON    绘制多边形使用

GL_QUADS    每4个顶点连接并内部填充

GL_QUAD_STRIP    形成四边形后2个顶点复用

GL_TRIANGLES    每3个顶点定义一个三角形

GL_TRIANGLE_STRIP    共用一个边上的顶点的一组三角形

GL_TRIANGLE_FAN    以一个顶点作为原点设为中心呈扇形排列,共用相邻顶点的一组三角形

矩阵

modelViewMatrix:模型视图矩阵

projectionMatrix:投影矩阵

transformPipeline:变换管道

矩阵的作用:让一个数据集做批量处理的方式。比如我们的例子中让顶点数据通过一个矩阵做一些批量的修改;比如一个YUV * 矩阵 = RGBA。

声明的全局变量

// 各种需要的类

GLShaderManager    shaderManager;//着色器管理类

GLMatrixStack      modelViewMatrix;//模型视图矩阵栈 管理模型和观察者的矩阵

GLMatrixStack      projectionMatrix;//投影矩阵栈,管理投影矩阵

GLFrame            cameraFrame;//记录观察者变化的对象

GLFrame            objectFrame;//记录模型变化的对象

//投影矩阵

GLFrustum          viewFrustum;//配置投影的对象

//容器类(7种不同的图元对应7种容器对象)

GLBatch            pointBatch;

GLBatch            lineBatch;

GLBatch            lineStripBatch;

GLBatch            lineLoopBatch;

GLBatch            triangleBatch;

GLBatch            triangleStripBatch;

GLBatch            triangleFanBatch;

//几何变换的管道

GLGeometryTransform transformPipeline;

GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };

GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };

// 跟踪效果步骤

int nStep = 0;

main函数

int main(int argc, char* argv[])

{

    gltSetWorkingDirectory(argv[0]);

    glutInit(&argc, argv);

    //申请一个颜色缓存区、深度缓存区、双缓存区、模板缓存区

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);

    //设置window 的尺寸

    glutInitWindowSize(800, 600);

    //创建window的名称

    glutCreateWindow("GL_POINTS");

    //注册回调函数(改变尺寸)

    glutReshapeFunc(ChangeSize);

    //点击空格时,调用的函数

    glutKeyboardFunc(KeyPressFunc);

    //特殊键位函数(上下左右)

    glutSpecialFunc(SpecialKeys);

    //显示函数

    glutDisplayFunc(RenderScene);


    //判断一下是否能初始化glew库,确保项目能正常使用OpenGL 框架

    GLenum err= glewInit();

    if (GLEW_OK != err) {

        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));

        return 1;

    }


    //绘制

    SetupRC();


    //runloop运行循环

    glutMainLoop();

    return 0;

}

SetupRC函数

// 灰色的背景

   glClearColor(0.7f, 0.7f, 0.7f, 1.0f );

   shaderManager.InitializeStockShaders();

   glEnable(GL_DEPTH_TEST);

   //设置变换管线以使用两个矩阵堆栈

   transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

   cameraFrame.MoveForward(-15.0f);


   /*

    常见函数:

    void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);

     参数1:表示使用的图元

     参数2:顶点数

     参数3:纹理坐标(可选)


    //负责顶点坐标

    void GLBatch::CopyVertexData3f(GLFloat *vNorms);


    //结束,表示已经完成数据复制工作

    void GLBatch::End(void);



    */

   //定义一些点,三角形形状。


   GLfloat vCoast[9] = {

       3,3,0,0,3,0,3,0,0


   };


   //用点的形式

   pointBatch.Begin(GL_POINTS, 3);

   pointBatch.CopyVertexData3f(vCoast);

   pointBatch.End();


   //通过线的形式

   lineBatch.Begin(GL_LINES, 3);

   lineBatch.CopyVertexData3f(vCoast);

   lineBatch.End();


   //通过线段的形式

   lineStripBatch.Begin(GL_LINE_STRIP, 3);

   lineStripBatch.CopyVertexData3f(vCoast);

   lineStripBatch.End();


   //通过线环的形式

   lineLoopBatch.Begin(GL_LINE_LOOP, 3);

   lineLoopBatch.CopyVertexData3f(vCoast);

   lineLoopBatch.End();


//    通过三角形创建金字塔

   GLfloat vPyramid[12][3] = {

       -2.0f, 0.0f, -2.0f,

       2.0f, 0.0f, -2.0f,

       0.0f, 4.0f, 0.0f,

       2.0f, 0.0f, -2.0f,

       2.0f, 0.0f, 2.0f,

       0.0f, 4.0f, 0.0f,

       2.0f, 0.0f, 2.0f,

       -2.0f, 0.0f, 2.0f,

       0.0f, 4.0f, 0.0f,

       -2.0f, 0.0f, 2.0f,

       -2.0f, 0.0f, -2.0f,

       0.0f, 4.0f, 0.0f


   };

   //GL_TRIANGLES 每3个顶点定义一个新的三角形

   triangleBatch.Begin(GL_TRIANGLES, 12);

   triangleBatch.CopyVertexData3f(vPyramid);

   triangleBatch.End();



   // 三角形扇形--六边形

   GLfloat vPoints[100][3];   

   int nVerts = 0;

   //半径

   GLfloat r= 3.0f;

   //原点(x,y,z) = (0,0,0);

   vPoints[nVerts][0] = 0.0f;

   vPoints[nVerts][1] = 0.0f;

   vPoints[nVerts][2] = 0.0f;



   //M3D_2PI 就是2Pi 的意思,就一个圆的意思。 绘制圆形

   for(GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {


       //数组下标自增(每自增1次就表示一个顶点)

       nVerts++;

       /*

        弧长=半径*角度,这里的角度是弧度制,不是平时的角度制

        既然知道了cos值,那么角度=arccos,求一个反三角函数就行了

        */

       //x点坐标 cos(angle) * 半径

       vPoints[nVerts][0] = float(cos(angle)) * r;

       //y点坐标 sin(angle) * 半径

       vPoints[nVerts][1] = float(sin(angle)) * r;

       //z点的坐标

       vPoints[nVerts][2] = -0.5f;

   }


   // 结束扇形 前面一共绘制7个顶点(包括圆心)

   //添加闭合的终点

   //课程添加演示:屏蔽177-180行代码,并把绘制节点改为7.则三角形扇形是无法闭合的。

   nVerts++;

   vPoints[nVerts][0] = r;

   vPoints[nVerts][1] = 0;

   vPoints[nVerts][2] = 0.0f;


   // 加载!

   //GL_TRIANGLE_FAN 以一个圆心为中心呈扇形排列,共用相邻顶点的一组三角形

   triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);

   triangleFanBatch.CopyVertexData3f(vPoints);

   triangleFanBatch.End();


   //三角形条带,一个小环或圆柱段

   //顶点下标

   int iCounter = 0;

   //半径

   GLfloat radius= 3.0f;

   //从0度~360度,以0.3弧度为步长

   for(GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)

   {

       //或许圆形的顶点的X,Y

       GLfloat x= radius * sin(angle);

       GLfloat y= radius * cos(angle);


       //绘制2个三角形(他们的x,y顶点一样,只是z点不一样)

       vPoints[iCounter][0] = x;

       vPoints[iCounter][1] = y;

       vPoints[iCounter][2] = -0.5;

       iCounter++;


       vPoints[iCounter][0] = x;

       vPoints[iCounter][1] = y;

       vPoints[iCounter][2] = 0.5;

       iCounter++;

   }


   // 关闭循环

   printf("三角形带的顶点数:%d\n",iCounter);

   //结束循环,在循环位置生成2个三角形

   vPoints[iCounter][0] = vPoints[0][0];

   vPoints[iCounter][1] = vPoints[0][1];

   vPoints[iCounter][2] = -0.5;

   iCounter++;


   vPoints[iCounter][0] = vPoints[1][0];

   vPoints[iCounter][1] = vPoints[1][1];

   vPoints[iCounter][2] = 0.5;

   iCounter++;


   // GL_TRIANGLE_STRIP 共用一个条带(strip)上的顶点的一组三角形

   triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);

   triangleStripBatch.CopyVertexData3f(vPoints);

   triangleStripBatch.End();

glEnable(GL_DEPTH_TEST);

开启深度测试功能,启用之后OpenGL在绘制的时候就会检查,当前像素前面是否有别的像素,如果别的像素挡道了它,那它就不会绘制,也就是说,OpenGL就只绘制最前面的一层。

ChangeSize函数

glViewport(0, 0, w, h);

    //创建投影矩阵,并将它载入投影矩阵堆栈中

    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);

    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

    //调用顶部载入单元矩阵

    modelViewMatrix.LoadIdentity();

KeyPressFunc点击空格键调用的方法

  if(key == 32) //空格键的ASCII码是32

    {

        nStep++; //通过nStep来区分绘制不能的视图


        if(nStep > 6)

            nStep= 0;

    }

    //根据nStep 来给窗口设定特定的窗口名

    switch(nStep)

    {

        case 0:

            glutSetWindowTitle("GL_POINTS");

            break;

        case 1:

            glutSetWindowTitle("GL_LINES");

            break;

        case 2:

            glutSetWindowTitle("GL_LINE_STRIP");

            break;

        case 3:

            glutSetWindowTitle("GL_LINE_LOOP");

            break;

        case 4:

            glutSetWindowTitle("GL_TRIANGLES");

            break;

        case 5:

            glutSetWindowTitle("GL_TRIANGLE_STRIP");

            break;

        case 6:

            glutSetWindowTitle("GL_TRIANGLE_FAN");

            break;

    }


    glutPostRedisplay();//重新渲染

SpecialKeys函数

if(key == GLUT_KEY_UP)

        //围绕一个指定的X,Y,Z轴旋转。

        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);


    if(key == GLUT_KEY_DOWN)

        objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);


    if(key == GLUT_KEY_LEFT)

        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);


    if(key == GLUT_KEY_RIGHT)

        objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);


    glutPostRedisplay();

RenderScene

  // Clear the window with current clearing color

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);


    //压栈

    modelViewMatrix.PushMatrix();

    M3DMatrix44f mCamera;

    cameraFrame.GetCameraMatrix(mCamera);


    //矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部

    modelViewMatrix.MultMatrix(mCamera);


    M3DMatrix44f mObjectFrame;

    //只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。用来使用GLShaderManager 的使用。或者是获取顶部矩阵的顶点副本数据

    objectFrame.GetMatrix(mObjectFrame);


    //矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部

    modelViewMatrix.MultMatrix(mObjectFrame);


    /* GLShaderManager 中的Uniform 值——平面着色器

     参数1:平面着色器

     参数2:运行为几何图形变换指定一个 4 * 4变换矩阵

     --transformPipeline.GetModelViewProjectionMatrix()获取的

     GetMatrix函数就可以获得矩阵堆栈顶部的值

     参数3:颜色值(黑色)

     */

    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);


    switch(nStep) {

        case 0:

            //设置点的大小

            glPointSize(4.0f);

            pointBatch.Draw();

            glPointSize(1.0f);

            break;

        case 1:

            //设置线的宽度

            glLineWidth(2.0f);

            lineBatch.Draw();

            glLineWidth(1.0f);

            break;

        case 2:

            glLineWidth(2.0f);

            lineStripBatch.Draw();

            glLineWidth(1.0f);

            break;

        case 3:

            glLineWidth(2.0f);

            lineLoopBatch.Draw();

            glLineWidth(1.0f);

            break;

        case 4:

            DrawWireFramedBatch(&triangleBatch);

            break;

        case 5:

            DrawWireFramedBatch(&triangleStripBatch);

            break;

        case 6:

            DrawWireFramedBatch(&triangleFanBatch);

            break;

    }


    //还原到以前的模型视图矩阵(单位矩阵)

    modelViewMatrix.PopMatrix();


    // 进行缓冲区交换

    glutSwapBuffers();

modelViewMatrix的压栈和出栈

 M3DMatrix44f mCamera;

   cameraFrame.GetCameraMatrix(mCamera);

transformPipeline.GetModelViewProjectionMatrix()

transformPipeline管理者两个矩阵栈,一个是投影矩阵栈,一个是模型视图矩阵栈。模型视图矩阵栈管理者模型矩阵和视图矩阵。坐标转化过程,投影矩阵栈管理者投影矩阵。

DrawWireFramedBatch

 /*------------画绿色部分----------------*/

    /* GLShaderManager 中的Uniform 值——平面着色器

     参数1:平面着色器

     参数2:运行为几何图形变换指定一个 4 * 4变换矩阵

          --transformPipeline变换管线(指定了2个矩阵堆栈)

     参数3:颜色值

    */

    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);

    pBatch->Draw();


    /*-----------边框部分-------------------*/

    /*

        glEnable(GLenum mode);用于启用各种功能。功能由参数决定

        参数列表:http://blog.csdn.net/augusdi/article/details/23747081

        注意:glEnable() 不能写在glBegin() 和 glEnd()中间

        GL_POLYGON_OFFSET_LINE  根据函数glPolygonOffset的设置,启用线的深度偏移

        GL_LINE_SMOOTH          执行后,过虑线点的锯齿

        GL_BLEND                启用颜色混合。例如实现半透明效果

        GL_DEPTH_TEST          启用深度测试 根据坐标的远近自动隐藏被遮住的图形(材料



        glDisable(GLenum mode);用于关闭指定的功能 功能由参数决定


     */


    //画黑色边框

    glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移

    glEnable(GL_POLYGON_OFFSET_LINE);


    // 画反锯齿,让黑边好看些

    glEnable(GL_LINE_SMOOTH);

    glEnable(GL_BLEND);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


    //绘制线框几何黑色版 三种模式,实心,边框,点,可以作用在正面,背面,或者两面

    //通过调用glPolygonMode将多边形正面或者背面设为线框模式,实现线框渲染

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    //设置线条宽度

    glLineWidth(2.5f);


    /* GLShaderManager 中的Uniform 值——平面着色器

     参数1:平面着色器

     参数2:运行为几何图形变换指定一个 4 * 4变换矩阵

         --transformPipeline.GetModelViewProjectionMatrix()获取的

          GetMatrix函数就可以获得矩阵堆栈顶部的值

     参数3:颜色值(黑色)

     */


    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);

    pBatch->Draw();

    // 复原原本的设置

    //通过调用glPolygonMode将多边形正面或者背面设为全部填充模式

    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    glDisable(GL_POLYGON_OFFSET_LINE);

    glLineWidth(1.0f);

    glDisable(GL_BLEND);

    glDisable(GL_LINE_SMOOTH);

modelViewMatrix的大致执行过程



引用文章:

https://www.jianshu.com/p/aac693650a80

https://www.jianshu.com/p/6167604c9cfa

https://www.jianshu.com/p/147028461043

https://www.jianshu.com/p/2aa2145aae94

你可能感兴趣的:(OpenGL基本图元的连接方式及练习)