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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342