美文网首页
四、OpenGL案例分析

四、OpenGL案例分析

作者: 随意昵称你能懂得 | 来源:发表于2020-07-10 21:02 被阅读0次

    本文将以金字塔为例,对使用OpenGL绘制图形的代码做一些简单分析。


    金字塔.png

    金字塔实现

    必要属性

    //着色管理器
    GLShaderManager shaderManager;
    //模型矩阵
    GLMatrixStack modelViewMatrix;
    //投影矩阵
    GLMatrixStack projectionMatrix;
    //相机位置
    GLFrame cameraFrame;
    //模型位置
    GLFrame objectFrame;
    
    //投影矩阵
    GLFrustum viewFrustum;
    
    //金色塔容器
    GLBatch triangleBatch;
    
    //几何变换的管道
    GLGeometryTransform transformPipeline;
    
    //红色表面
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    //黑色比酷昂
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    

    main函数

    需要初始化一些功能,再绑定一些按键和方法,然后初始化显示数据,最后开启循环。

    int main(int argc, char* argv[])
    {
        //设置当前目录
        gltSetWorkingDirectory(argv[0]);
        //初始化glut
        glutInit(&argc, argv);
        //申请一个颜色缓存区、深度缓存区、双缓存区、模板缓存区
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
        //设置视图窗口的尺寸
        glutInitWindowSize(800, 600);
        //创建视图窗口的名称
        glutCreateWindow("GL_TRIANGLES");
        //监听视图窗口改变大小
        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;
    }
    

    自定义绘制方法

    设置改场景下的部分设置,并且初始化金字塔数据

    void SetupRC()
    {
        //设置背景色
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f );
        //初始化着色管理器
        shaderManager.InitializeStockShaders();
        //打开深度测试
        glEnable(GL_DEPTH_TEST);
        //设置变换管线以使用两个矩阵堆栈
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
        //设置相机位置
        cameraFrame.MoveForward(-15.0f);
        
        //通过三角形创建金字塔
        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();
    }
    

    显示函数

    进行矩阵变换,中间留出正在渲染金字塔的方法

    void RenderScene(void) {
        // 清理缓存区
        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);
        
        //渲染金字塔方法
        DrawWireFramedBatch(&triangleBatch);
    
        //还原到以前的模型视图矩阵(单位矩阵)
        modelViewMatrix.PopMatrix();
        
        // 进行缓冲区交换
        glutSwapBuffers();
    }
    

    渲染金字塔

    先画表面,然后画边框,设置一些优化属性,需要还原回来。

    void DrawWireFramedBatch(GLBatch* pBatch)
    {
        //金字塔表面
        //提供着色器的Uniform值-平面着色器
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
        pBatch->Draw();
        
        //黑色边框
        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(GL_FRONT_AND_BACK, GL_LINE);
        
        //设置线条宽度
        glLineWidth(2.5f);
        
        //提供着色器的Uniform值-平面着色器
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
        pBatch->Draw();
    
        // 复原原本的设置
        //这个必须设置回来,不然可能会导致移动后表面颜色消失
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glDisable(GL_POLYGON_OFFSET_LINE);
        glLineWidth(1.0f);
        glDisable(GL_BLEND);
        glDisable(GL_LINE_SMOOTH);
        
    }
    

    上下左右按键

    在屏幕中做旋转

    void SpecialKeys(int key, int x, int y) {
        
        if(key == GLUT_KEY_UP)
            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();
    }
    

    窗口大小改变

    该方法必须设置绑定,不然会导致显示不出东西

    void ChangeSize(int w, int h)
    {
        glViewport(0, 0, w, h);
        //创建投影矩阵,并将它载入投影矩阵堆栈中
        viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        
        //调用顶部载入单元矩阵
        modelViewMatrix.LoadIdentity();
    }
    

    相关文章

      网友评论

          本文标题:四、OpenGL案例分析

          本文链接:https://www.haomeiwen.com/subject/ydkpcktx.html