• OpenGL代码学习(15)--理解透视投影矩阵


    注意:需要在配置好OpenGL的编程环境中运行下列代码,环境配置文章可参考:

    OpenGL在Mac项目上的配置

    下面的代码,直接放置在main.cpp文件中即可:

    #include "GLTools.h"
    #include "GLMatrixStack.h"
    #include "GLFrame.h"
    #include "GLFrustum.h"
    #include "GLGeometryTransform.h"
    #include "GLBatch.h"
    #include "math.h"
    #include <GLUT/GLUT.h>
    
    
    GLFrame viewFrame;
    GLFrustum viewFrustum;
    GLBatch tubeBatch;
    GLBatch innerBatch;
    GLMatrixStack modelViewMatix;
    GLMatrixStack projectionMatrix;
    GLGeometryTransform transformPipeline;
    GLShaderManager shaderManager;
    float fZ = 100.0f;
    float bZ = -100.0f;
    
    // 窗口渲染调用
    void RenderScene(void) {
        // 清除缓存区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        // 压栈,物体矩阵
        modelViewMatix.PushMatrix(viewFrame);
        
        // 默认红色光源着色
        GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
        shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);
        tubeBatch.Draw();
        
        // 默认灰色光源着色
        GLfloat vGray[] = { 0.75f, 0.75f, 0.75f, 1.0f };
        shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vGray);
        innerBatch.Draw();
        
        // 出栈,还原为单位矩阵
        modelViewMatix.PopMatrix();
        
        // 双缓存模式,后台缓存切换到前台进行显示
        glutSwapBuffers();
    }
    
    void SetupTubeBatch() {
        tubeBatch.Begin(GL_QUADS, 200);
        tubeBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);
        // 后面
        GLfloat vBack[] = {
            // Left Pannel
            -50.0f, 50.0f, fZ,
            -50.0f, -50.0f, fZ,
            -35.0f, -50.0f, fZ,
            -35.0f, 50.0f, fZ,
            // Right Panel
            50.0f, 50.0f, fZ,
            35.0f, 50.0f, fZ,
            35.0f, -50.0f, fZ,
            50.0f,-50.0f, fZ,
            // Top Panel
            -35.0f, 50.0f, fZ,
            -35.0f, 35.0f, fZ,
            35.0f, 35.0f, fZ,
            35.0f, 50.0f, fZ,
            // Bottom Panel
            -35.0f, -35.0f, fZ,
            -35.0f, -50.0f, fZ,
            35.0f, -50.0f, fZ,
            35.0f, -35.0f, fZ
        };
        for(int i = 0; i < 16; i++) {
            int index = i * 3;
            tubeBatch.Normal3f(0.0f, 0.0f, 1.0f);
            tubeBatch.Vertex3f(vBack[index], vBack[index+1], vBack[index+2]);
        }
        
        // 前面
        GLfloat vFront[] = {
            // Left Pannel
            -35.0f, 50.0f, bZ,
            -35.0f, -50.0f, bZ,
            -50.0f, -50.0f, bZ,
            -50.0f, 50.0f, bZ,
            // Right Panel
            50.0f, -50.0f, bZ,
            35.0f, -50.0f, bZ,
            35.0f, 50.0f, bZ,
            50.0f, 50.0f, bZ,
            // Top Panel
            35.0f, 50.0f, bZ,
            35.0f, 35.0f, bZ,
            -35.0f, 35.0f, bZ,
            -35.0f, 50.0f, bZ,
            // Bottom Panel
            35.0f, -35.0f, bZ,
            35.0f, -50.0f, bZ,
            -35.0f, -50.0f, bZ,
            -35.0f, -35.0f, bZ
        };
        for(int i = 0; i < 16; i++) {
            int index = i * 3;
            tubeBatch.Normal3f(0.0f, 0.0f, -1.0f);
            tubeBatch.Vertex3f(vFront[index], vFront[index+1], vFront[index+2]);
        }
        
        // 上面
        GLfloat vTop[] = {
            -50.0f, 50.0f, fZ,
            50.0f, 50.0f, fZ,
            50.0f, 50.0f, bZ,
            -50.0f, 50.0f, bZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            tubeBatch.Normal3f(0.0f, 1.0f, 0.0f);
            tubeBatch.Vertex3f(vTop[index], vTop[index+1], vTop[index+2]);
        }
        
        // 下面
        GLfloat vBottom[] = {
            -50.0f, -50.0f, fZ,
            -50.0f, -50.0f, bZ,
            50.0f, -50.0f, bZ,
            50.0f, -50.0f, fZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            tubeBatch.Normal3f(0.0f, -1.0f, 0.0f);
            tubeBatch.Vertex3f(vBottom[index], vBottom[index+1], vBottom[index+2]);
        }
        
        // 左面
        GLfloat vLeft[] = {
            50.0f, 50.0f, fZ,
            50.0f, -50.0f, fZ,
            50.0f, -50.0f, bZ,
            50.0f, 50.0f, bZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            tubeBatch.Normal3f(1.0f, 0.0f, 0.0f);
            tubeBatch.Vertex3f(vLeft[index], vLeft[index+1], vLeft[index+2]);
        }
        
        // 右面
        GLfloat vRight[] = {
            -50.0f, 50.0f, fZ,
            -50.0f, 50.0f, bZ,
            -50.0f, -50.0f, bZ,
            -50.0f, -50.0f, fZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            tubeBatch.Normal3f(-1.0f, 0.0f, 0.0f);
            tubeBatch.Vertex3f(vRight[index], vRight[index+1], vRight[index+2]);
        }
        tubeBatch.End();
    }
    
    void SetupInnerBatch() {
        innerBatch.Begin(GL_QUADS, 40);
        innerBatch.Color4f(0.75f, 0.75f, 0.75f, 1.0f);
        // 上面
        GLfloat innerTop[] = {
            -35.0f, 35.0f, fZ,
            35.0f, 35.0f, fZ,
            35.0f, 35.0f, bZ,
            -35.0f, 35.0f, bZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            innerBatch.Normal3f(0.0f, -1.0f, 0.0f);
            innerBatch.Vertex3f(innerTop[index], innerTop[index+1], innerTop[index+2]);
        }
        
        // 下面
        GLfloat innerBottom[] = {
            -35.0f, -35.0f, fZ,
            -35.0f, -35.0f, bZ,
            35.0f, -35.0f, bZ,
            35.0f, -35.0f, fZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            innerBatch.Normal3f(0.0f, 1.0f, 0.0f);
            innerBatch.Vertex3f(innerBottom[index], innerBottom[index+1], innerBottom[index+2]);
        }
        
        // 左面
        GLfloat innerLeft[] = {
            35.0f, 35.0f, fZ,
            35.0f, -35.0f, fZ,
            35.0f, -35.0f, bZ,
            35.0f, 35.0f, bZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            innerBatch.Normal3f(-1.0f, 0.0f, 0.0f);
            innerBatch.Vertex3f(innerLeft[index], innerLeft[index+1], innerLeft[index+2]);
        }
        
        // 右面
        GLfloat innerRight[] = {
            -35.0f, 35.0f, fZ,
            -35.0f, 35.0f, bZ,
            -35.0f, -35.0f, bZ,
            -35.0f, -35.0f, fZ
        };
        for(int i = 0; i < 4; i++) {
            int index = i * 3;
            innerBatch.Normal3f(1.0f, 0.0f, 0.0f);
            innerBatch.Vertex3f(innerRight[index], innerRight[index+1], innerRight[index+2]);
        }
        
        innerBatch.End();
    }
    
    // 程序初始化环境
    void SetupRC() {
        // 设置背景颜色为淡蓝色
        glClearColor(0.0f, 0.0f, 0.75f, 1.0f);
        
        // 开启深度测试
        glEnable(GL_DEPTH_TEST);
        
        // 着色器初始化
        shaderManager.InitializeStockShaders();
        
        // 物体向里面移动 450 距离
        viewFrame.MoveForward(450.0f);
        
        // 创建长方体暴露在外面的红色面
        SetupTubeBatch();
        
        // 创建长方体里面的灰色面
        SetupInnerBatch();
    }
    
    void SpecialKeys(int key, int x, int y) {
        // 按下上、下、左、右方向键,对物体进行旋转,m3dDegToRad = 角度 -> 弧度
        switch(key) {
            case GLUT_KEY_UP:
                // angle=-5, x=1, y=0, z=0 表示绕x轴正方向顺时针旋转(从x轴正方向看去)
                viewFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
                break;
            case GLUT_KEY_DOWN:
                // angle=5, x=1, y=0, z=0 表示绕x轴正方向逆时针旋转(从x轴正方向看去)
                viewFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
                break;
            case GLUT_KEY_LEFT:
                // angle=-5, x=0, y=1, z=0 表示绕y轴正方向顺时针旋转(从y轴正方向看去)
                viewFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
                break;
            case GLUT_KEY_RIGHT:
                // angle=5, x=0, y=1, z=0 表示绕y轴正方向逆时针旋转(从y轴正方向看去)
                viewFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
                break;
        }
        
        // 重写渲染窗口
        glutPostRedisplay();
    }
    
    // 窗口变换回调
    void ChangeSize(int width, int height) {
        // 防止除数为0
        if(height == 0)
            height = 1;
        
        // 设置视口
        glViewport(0, 0, width, height);
        
        // 设置透视投影矩阵,参数分别为:透视角,宽高比,近距,远距
        viewFrustum.SetPerspective(35.0f, float(width)/float(height), 1.0f, 1000.0f);
        
        // 保持透视投影矩阵
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        
        // 利用变换管线,管理2个堆栈
        transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
    }
    
    // 程序入口
    int main(int argc, char* argv[]) {
        // 针对 Mac OS 设置工作目录路径
        gltSetWorkingDirectory(argv[0]);
        
        // 初始化 GLUT
        glutInit(&argc, argv);
        
        // 初始化渲染模式
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
        
        // 初始化窗口大小
        glutInitWindowSize(800, 720);
        
        // 创建窗口并命名
        glutCreateWindow("Perspective Projection Example");
        
        // 检测驱动程序是否初始化成功
        GLenum err = glewInit();
        if (GLEW_OK != err) {
            fprintf(stderr, "GLEW Error: %s
    ", glewGetErrorString(err));
            return 1;
        }
        
        // 窗口大小改变回调函数设置
        glutReshapeFunc(ChangeSize);
        
        // 特殊按键点击回调函数设置
        glutSpecialFunc(SpecialKeys);
        
        // 窗口渲染回调函数设置
        glutDisplayFunc(RenderScene);
        
        // 程序初始化环境
        SetupRC();
        
        // 主消息循环
        glutMainLoop();
        
        return 0;
    }

    效果图如下所示:

     

     

  • 相关阅读:
    微信小程序 视频广告展示异常(“表情、壁纸”等页面,当视频广告与顶部区域重叠时,视频广告呈现透明状态,需重新设置视频广告的层级即可)
    Vue:The template root requires exactly one element.的解决办法
    Angular之ES6语法实现数组去重
    Java程序中的代理作用和应用场景及实现
    Hadoop hdfs副本存储和纠删码(Erasure Coding)存储优缺点
    Hadoop源码:namenode格式化和启动过程实现
    ssh免密登录设置后不生效
    递归查询子级元素,返回树形菜单数据
    mysql设置密码
    PX4飞行模式简单对比梳理
  • 原文地址:https://www.cnblogs.com/cchHers/p/14726477.html
Copyright © 2020-2023  润新知