• OpenGL代码学习(7)--开始接触3D效果


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

    OpenGL在Mac项目上的配置

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

    #include "GLTools.h"
    #include "GLMatrixStack.h"
    #include "GLFrame.h"
    #include "GLFrustum.h"
    #include "GLBatch.h"
    #include "GLGeometryTransform.h"
    #include <math.h>
    #include <glut/glut.h>
    
    GLShaderManager shaderManager;
    GLMatrixStack modelViewMatrix;
    GLMatrixStack projectionMatrix;
    GLFrame cameraFrame;// 摄像机的位置
    GLFrame objectFrame;// 物体的位置
    GLFrustum viewFrustum;// 投影矩阵
    
    //三角形扇的批次
    GLBatch triangleFanBatch;
    
    //变换管线
    GLGeometryTransform transformPipeline;
    
    //颜色
    GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    
    //初始化三角形扇批次
    void SetupTriangleFanBatch() {
        // 用代码生成三角形扇的顶点位置
        // x,y,z 坐标的点
        GLfloat vPoints[9][3];//??
        int nVerts = 0;
        GLfloat r = 3.0f;
        vPoints[nVerts][0] = 0.0f;
        vPoints[nVerts][1] = 0.0f;
        vPoints[nVerts][2] = 0.0f;
    
        for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
            nVerts++;
            vPoints[nVerts][0] = float(cos(angle)) * r;
            vPoints[nVerts][1] = float(sin(angle)) * r;
            vPoints[nVerts][2] = -r;
        }
        //使三角形扇闭合
        nVerts++;
        vPoints[nVerts][0] = r;
        vPoints[nVerts][1] = 0;
        vPoints[nVerts][2] = 0.0f;
        
        printf("顶点数据的个数:~%d
    ", nVerts);
    
        /*
         点 -> GL_POINTS:屏幕上单独的点
         线段 -> GL_LINES:每对顶点定义一条线段
         线条 -> GL_LINE_STRIP:从起始点依次经过所有后续点的线条
         闭合线条 -> GL_LINE_LOOP:起始点和终点相连的线条
         三角形 -> GL_TRIANGLES:每 3 个顶点定义一个三角形
         三角形条带 -> GL_TRIANGLE_STRIP:共用一个条带上顶点的一组三角形
         三角形扇 -> GL_TRIANGLE_FAN:以圆点为中心呈扇形的共用相邻顶点的一组三角形
         */
        //三角形扇批次初始化
        triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
        triangleFanBatch.CopyVertexData3f(vPoints);
        triangleFanBatch.End();
        
        glPointSize(5.f);
    }
    
    //为程序作一次性的设置
    void SetupRC() {
        //设置窗口背景颜色
        glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
    
        //初始化着色器管理器
        shaderManager.InitializeStockShaders();
    
        //开启深度测试
        glEnable(GL_DEPTH_TEST);// 如果去掉这行代码,依然能3D效果,点的颜色不再是绿色,而是黑色
    
        //设置变换管线以使用两个矩阵堆栈
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);// 这行代码去掉的话,代码出错
    
        /*
         默认情况下,透视投影中的观察者位置处于原点(0,0,0),并沿着z轴负方向看向屏幕里面,一般通过moveForward方法来调整观察者位置,moveForward默认的朝向是-z轴,所有向屏幕里面移动传正数值,向屏幕外即+z轴,需要传负数值
         */
        //移动摄像机的位置
        cameraFrame.MoveForward(-15.0f);//-25:看得更近    -10:看得更远
    
        //准备画图要用的批次
        SetupTriangleFanBatch();
    }
    
    //画三角形
    void DrawTriangleBatch(GLBatch* pBatch) {
        //画绿色面
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
        pBatch->Draw();
    
        //开启调节片段的深度值,使深度值产生偏移而不实际改变 3D 空间的物理位置
        glPolygonOffset(-1.0f, -1.0f);
        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);
        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 RenderScene(void) {
        //清除一个或一组特定的缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
        //保存当前的模型视图矩阵 (单位矩阵)
        modelViewMatrix.PushMatrix();
    
        //MultMatrix: 用一个矩阵乘以矩阵堆栈的顶部矩阵,相乘得到的结果随后将存储在堆栈的顶部
        //处理模型相对于摄像机的位置
        M3DMatrix44f mCamera;
        // GetCameraMatrix是GLFrame的一个函数,通常会用这个来进行设置,通过此函数来获取一个观察者变换后的矩阵
        cameraFrame.GetCameraMatrix(mCamera);
        modelViewMatrix.MultMatrix(mCamera);
    
        //处理模型自身的旋转
        M3DMatrix44f mObjectFrame;
        // GetCameraMatrix是GLFrame的一个函数,通常会用这个来进行设置,通过此函数来获取一个观察者变换后的矩阵
        objectFrame.GetCameraMatrix(mObjectFrame);
        modelViewMatrix.MultMatrix(mObjectFrame);
    
        //画图
        DrawTriangleBatch(&triangleFanBatch);
    
        // 还原以前的模型视图矩阵 (单位矩阵)
        modelViewMatrix.PopMatrix();
    
        //将在后台缓冲区进行渲染,然后在结束时交换到前台
        glutSwapBuffers();
    }
    
    //特殊按键(功能键或者方向键)监听
    void SpecialKeys(int key, int x, int y) {
    
        //上、下、左、右按键,3D 旋转
        /*
         * RotateWorld(float fAngle, float x, float y, float z)
         * fAngle: 旋转弧度, x/y/z:以哪个坐标轴旋转
         * m3dDegToRad:角度 -> 弧度
         */
        switch (key) {
            case GLUT_KEY_UP: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f); break;
            case GLUT_KEY_DOWN: objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f); break;
            case GLUT_KEY_LEFT: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); break;
            case GLUT_KEY_RIGHT: objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f); break;
            default:
                break;
        }
    
        //触发渲染
        glutPostRedisplay();
    }
    
    //窗口大小改变时接受新的宽度和高度
    void ChangeSize(int width, int height) {
    
        // 防止下面除法的除数为0导致的闪退
        if(height == 0) height = 1;
    
        //设置视图窗口位置
        glViewport(0, 0, width, height);
    
        // 创建投影矩阵,并将它载入到投影矩阵堆栈中
        /* 显示3D图形,有远小近大的效果
         参数1:垂直方向上的视场角度
         参数2:窗口的纵横比 = w / h
         参数3:近裁剪面距离
         参数4:远裁剪面距离
         */
        viewFrustum.SetPerspective(35.0f, float(width) / float(height), 1.0f, 500.0f);
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
        // 在模型视图矩阵顶部载入单位矩阵
        modelViewMatrix.LoadIdentity();
    }
    
    //程序入口
    int main(int argc, char* argv[]) {
        //设置当前工作目录,针对MAC OS X
        gltSetWorkingDirectory(argv[0]);
    
        //初始化GLUT库
        glutInit(&argc, argv);
    
        /*初始化渲染模式,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
         双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    
        //初始化窗口大小
        glutInitWindowSize(800, 720);
        //创建窗口
        glutCreateWindow("GL_POINTS");
    
        //注册回调函数
        glutReshapeFunc(ChangeSize);
        glutDisplayFunc(RenderScene);
        glutSpecialFunc(SpecialKeys);
    
        //确保驱动程序的初始化中没有出现任何问题
        GLenum err = glewInit();
        if(GLEW_OK != err) {
            fprintf(stderr, "glew error:%s
    ", glewGetErrorString(err));
            return 1;
        }
    
        //初始化设置
        SetupRC();
    
        //进入调用循环
        glutMainLoop();
        
        return 0;
    }
    
    #pragma mark - 代码逻辑整理
    /*
     1 UseStockShader函数肯定是关键,核心。所以先从该函数入手。
     
     2 共有两处地方使用到了该函数
     (1)shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
     (2)shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
     
     //变换管线
     GLGeometryTransform transformPipeline;
     
     //设置变换管线以使用两个矩阵堆栈
     transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
     
     
     GLMatrixStack modelViewMatrix;
     
     modelViewMatrix.PushMatrix();
     
     modelViewMatrix.MultMatrix(mCamera);
     (1)GLFrame cameraFrame;
     (2)//移动摄像机的位置
     cameraFrame.MoveForward(-15.0f);
     (3)//处理模型相对于摄像机的位置
     M3DMatrix44f mCamera;
     cameraFrame.GetCameraMatrix(mCamera);
     modelViewMatrix.MultMatrix(mCamera);
     
     modelViewMatrix.MultMatrix(mObjectFrame);
     (1)GLFrame objectFrame;
     (2)//处理模型自身的旋转
     M3DMatrix44f mObjectFrame;
     objectFrame.GetCameraMatrix(mObjectFrame);
     modelViewMatrix.MultMatrix(mObjectFrame);
     (3)switch (key) {
         case GLUT_KEY_UP: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f); break;
         case GLUT_KEY_DOWN: objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f); break;
         case GLUT_KEY_LEFT: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); break;
         case GLUT_KEY_RIGHT: objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f); break;
         default:
             break;
     }
     
     modelViewMatrix.PopMatrix();
     
     modelViewMatrix.LoadIdentity();
     
     
     GLMatrixStack projectionMatrix;
     
     projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
     (1)GLFrustum viewFrustum;
     (2)// 创建投影矩阵,并将它载入到投影矩阵堆栈中
     viewFrustum.SetPerspective(35.0f, float(width) / float(height), 1.0f, 500.0f);
     projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
     
     */

    运行上面的代码,得到的部分效果图示:

     

     

     

  • 相关阅读:
    五分钟上手Markdown
    css中居中方法小结
    事务和同步锁
    插入排序
    插入排序
    交换排序
    eclipse 常用快捷键
    交换排序
    二叉搜索树(BST)
    二叉树遍历以及根据前序遍历序列反向生成二叉树
  • 原文地址:https://www.cnblogs.com/cchHers/p/14724593.html
Copyright © 2020-2023  润新知