美文网首页
OpenGL 综合案例

OpenGL 综合案例

作者: 君幸食j | 来源:发表于2020-08-22 20:19 被阅读0次

    结合前面学到的知识,做一个球公转自转的综合程序,代码如下:

    #include "GLTools.h"
    #include "GLShaderManager.h"
    #include "GLMatrixStack.h"
    #include "GLFrustum.h"
    #include "GLGeometryTransform.h"
    #include "StopWatch.h"
    
    //在Mac 系统下,`#include<glut/glut.h>` 在Windows 和 Linux上,我们使⽤freeglut的静态库版本并且需要添加⼀个宏
    #ifdef __APPLE__
    #include <glut/glut.h>
    #else
    #define FREEGLUT_STATIC
    #include <GL/glut.h>
    #endif
    
    
    GLShaderManager shaderManager; //着色器管理器
    GLMatrixStack modelViewMatrix; //模型视图矩阵
    GLMatrixStack projectionMatrix; //投影矩阵
    GLFrustum viewFrustum; //视景体
    GLGeometryTransform transformPipeline; //几何图形变换管道
    
    GLBatch floorBatch; //地板
    GLTriangleBatch torusBatch; //大球
    GLTriangleBatch sphereBatch; //小球
    
    GLFrame cameraFrame; //照相机角色帧
    
    //球随机数
    #define NUM_SPHERES 50
    GLFrame spheres[NUM_SPHERES];
    
    
    
    
    
    //ChangeSize 函数:⾃定义函数.通过glutReshaperFunc(函数名)注册为重塑函数.当屏幕⼤⼩发⽣变化/或者第⼀次创建窗⼝时,会调⽤该函数调整窗⼝⼤⼩/视⼝⼤⼩.
    void ChangeSize(int w ,int h)
    {
        //设置视口窗口尺寸
        glViewport(0, 0, w, h);
        
        //创建投影矩阵,
        viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
        //加载到投影矩阵堆栈上
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        
        //设置变换管道以使用两个矩阵堆栈
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    }
    
    
    void SetupRC()
    {
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
        shaderManager.InitializeStockShaders();
        
        //开启深度测试
        glEnable(GL_DEPTH_TEST);
        
        //设置地板顶点数据
        floorBatch.Begin(GL_LINES, 324);
        for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5) {
            floorBatch.Vertex3f(x, -0.55f, 20.0f);
            floorBatch.Vertex3f(x, -0.55f, -20.0f);
            
            floorBatch.Vertex3f(20.0f, -0.55f, x);
            floorBatch.Vertex3f(-20.0f, -0.55f, x);
        }
        floorBatch.End();
        
        //设置大球模型
        gltMakeSphere(torusBatch, 0.4f, 40, 80);
        
        //设置小球模型
        gltMakeSphere(sphereBatch, 0.1f, 26, 13);
    
        //随机位置放置小球
        for (int i = 0; i < NUM_SPHERES; i++)
        {
            //y轴不变,X,Z产生随机值
            GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
            GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
    
            //在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度
            //对spheres数组中的每一个顶点,设置顶点数据
            spheres[i].SetOrigin(x, 0.0f, z);
        }
        
        
    }
    
    //上下左右键位控制移动
    void SpecialKeys(int key, int x, int y)
    {
        //移动步长
        float linear = 0.1f;
        //旋转度数
        float angular = float(m3dDegToRad(5.0f));
        
    
        if (key == GLUT_KEY_UP)
        {
            cameraFrame.MoveForward(linear);
        }
        
        if (key == GLUT_KEY_DOWN)
        {
            cameraFrame.MoveForward(-linear);
        }
        
        if (key == GLUT_KEY_LEFT)
        {
            cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
        }
        
        if (key == GLUT_KEY_RIGHT)
         {
             cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
         }
    }
    
    //RenderScene 函数:⾃定义函数.通过glutDisplayFunc(函数名)注册为显示渲染函数.当屏幕发⽣变化/或者开发者主动渲染会调⽤此函数,⽤来实现数据->渲染过程
    void RenderScene(void)
    {
        
        //清理缓存区(颜⾊,深度,模板缓存区等)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        //颜色值(地板,大球,小球颜色)
        static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
        static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f};
        static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f};
        
        //基于时间动画
        static CStopWatch rotTimer;
        float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
        
        //加入观察者
        M3DMatrix44f mCamera;
        cameraFrame.GetCameraMatrix(mCamera);
        modelViewMatrix.PushMatrix(mCamera);
        
        //获取光源位置
        M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
        
        //绘制地板
        shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
        floorBatch.Draw();
        
        //大球默认位置(0,0,0)Z深度(3.0) 正负指的是方向, 数字指的移动距离
        //使得大球位置平移(3.0)向屏幕里面  只移动1次
        modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
    
        //压栈(复制栈顶)
        modelViewMatrix.PushMatrix();
        //大球自转
        modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    
        //指定合适的着色器(点光源着色器)
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vTorusColor);
        torusBatch.Draw();
        modelViewMatrix.PopMatrix();
        
        //画小球
        for (int i = 0; i < NUM_SPHERES; i++)
        {
            modelViewMatrix.PushMatrix();
            modelViewMatrix.MultMatrix(spheres[i]);
            shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSphereColor);
            sphereBatch.Draw();
            modelViewMatrix.PopMatrix();
        }
    
    
        modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
        modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
        shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
        sphereBatch.Draw();
    
        modelViewMatrix.PopMatrix();
        
        
        //同步绘制命令
        glutSwapBuffers();
        
        glutPostRedisplay();
        
        
        
    }
    
    
    //main 函数: 程序⼊⼝.OpenGL 是⾯向过程编程.所以你会发现利⽤OpenGL处理图形/图像都是链式形式.以及基于OpenGL封装的图像处理框架也是链式编程
    int main(int argc, char* argv[])
    {
        gltSetWorkingDirectory(argv[0]);
        glutInit(&argc, argv);
        //申请一个颜色缓存区、双缓存区、深度缓存区
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
        //设置窗口的尺寸
        glutInitWindowSize(800, 800);
        //设置窗口的名称
        glutCreateWindow("球的公转自转");
        //注册回调函数(改变尺寸)
        glutReshapeFunc(ChangeSize);
        //注册显示函数
        glutDisplayFunc(RenderScene);
        
        glutSpecialFunc(SpecialKeys);
        
        GLenum err = glewInit();
        if (GLEW_OK != err)
        {
            fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
            return 1;
        }
        
        SetupRC();
       
        //runloop运行循环
        glutMainLoop();
        
        return 0;
    }
    
    运行后效果图 1.png

    相关文章

      网友评论

          本文标题:OpenGL 综合案例

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