美文网首页
OpenGL 综合案例(地球自转与公转)

OpenGL 综合案例(地球自转与公转)

作者: iOS_沧海一笑 | 来源:发表于2020-07-18 17:31 被阅读0次
    • 我们首先来看一下效果,大红球自转,小蓝球围绕着大红球转

    QQ20200718-171301-HD.gif
    • 接下来我们用OpenGL来实现这个效果:

    1. 首先我们要定义一些需要用到的全局属性:
    GLShaderManager   shaderManager;     //着色器管理器
    GLMatrixStack     modelViewMatrix;   //模型视图矩阵
    GLMatrixStack     projectionMatrix;  //投影矩阵
    GLFrustum         viewFrustum;       //视景体
    GLGeometryTransform transformPipeline; //几何图形变换管道
    
    GLTriangleBatch   torusBatch;        //打球
    GLTriangleBatch   sphereBatch;       //小球
    GLBatch           floorBatch;        //地板
    
    //角色帧 照相机角色帧
    GLFrame           cameraFrame;
    
    //添加附加随机球数量
    #define NUM_SPHERES  50
    GLFrame spheres[NUM_SPHERES];
    
    1. main函数是程序的入口出:
    int main(int argc, char* argv[]) {
        gltSetWorkingDirectory(argv[0]);
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
        glutInitWindowSize(800, 800);
        glutCreateWindow("OpenGL SphereWorld");
        glutReshapeFunc(ChangeSize);
        glutDisplayFunc(RenderScene);
        glutSpecialFunc(SpeacialKeys);
        GLenum err = glewInit();
        if (GLEW_OK != err) {
            fprintf(stderr, "GLEW error: %s\n", glewGetErrorString(err));
            return 1;
        }
        SetupRC();
        glutMainLoop();
        return 0;
    } 
    
    1. SetupRC()函数中初始化一些数据
    void SetupRC() {
        //1.初始化
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        shaderManager.InitializeStockShaders();
    
        //2.开启深度测试
        glEnable(GL_DEPTH_TEST);
    
        //3.设置地板顶点数据
        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();
    
        //4.设置大球模型
        gltMakeSphere(torusBatch, 0.4f, 40, 80);
    
        //5.设置小球模型
        gltMakeSphere(sphereBatch, 0.2f, 30, 60);
        //6.随机位置放置小球
        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, 这使得他们看起来是飘浮在眼镜的高度
            //对spheres数组中的每一个顶点,设置顶点数据
            spheres[i].SetOrigin(x, 0.0f, z);
        }
    }
    
    1. 调用ChangeSize函数初始化屏幕大小和创建投影矩阵
    //屏幕更改大小或已初始化
    void ChangeSize(int nWidth, int nHeight) {
        //1.设置视口
        glViewport(0, 0, nWidth, nHeight);
    
        //2.创建投影矩阵
        viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.f);
        //viewFrustum.GetProjectionMatrix() 获取viewFrustum投影矩阵
        //将其加载到投影矩阵堆栈上
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
        //3.设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix, 投影矩阵projectionMatrix)
        //初始化GLGeometryTransform的实例transformPipeline,通过将它的内部指针设置为模型视图矩阵堆栈和投影矩阵堆栈实例,来完成初始化
        //这个操作也可以在SetupRC函数中完成,但是在窗口大小改变时或者窗口创建时设置他们并没有坏处,而且这样可以一次性完成矩阵和管线的设置。
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    }
    
    1. 调用RenderScene函数进行绘制场景和球转动的动画效果
    //进行调用以绘制场景
    void RenderScene(void) {
        //1.颜色值(地板,打球,小球颜色)
        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};
    
        //2 基于时间动画
        static CStopWatch rotTimer;
        float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    
        //3.清除颜色缓冲区和深度缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    
        //压栈 有push就有pop 要一一对应
        modelViewMatrix.PushMatrix();
    
        //3.5 加入观察者,平移10步
        M3DMatrix44f mCamara;
        cameraFrame.GetCameraMatrix(mCamara);
        modelViewMatrix.PushMatrix(mCamara);
    
        //4.绘制地面
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vFloorColor);
        floorBatch.Draw();
    
        //5. 获取光源位置
        M3DVector4f vLightPos = {0.0f, 10.0f, 5.0f, 1.0f};
    
        //6.使得大球位置平移 3.0 向屏幕里面
        modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
    
        //7.压栈(复制栈顶)
        modelViewMatrix.PushMatrix();
    
        //8.大球自转
        modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    
        //9.指定合适的着色器(点光源着色器)
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
        torusBatch.Draw();
    
        //10.绘制完毕还要pop
        modelViewMatrix.PopMatrix();
    
        //11.画小球
        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();
        }
    
        //12.让一个小蓝球围绕大球公转自转
        modelViewMatrix.Rotate(yRot * -2.0f, 0.0, 1.0f, 0.0f);
        modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
        sphereBatch.Draw();
    
        //有几个push就有几个pop
        modelViewMatrix.PopMatrix();
    
        modelViewMatrix.PopMatrix();
        //12.执行缓冲区交换
        glutSwapBuffers();
    
        //重新绘制
        glutPostRedisplay();
    }
    
    1. 我们通过调用SpeacialKeys函数可以通过控制键盘的上下左右键来控制视图的方向和移动距离
    void SpeacialKeys(int key, int x, int y) {
        //移动步长
        float linear = 0.1f;
        //旋转度数
        float angular = float(m3dDegToRad(5.0f));
    
        if (key == GLUT_KEY_UP) {
            //MoveForward 平移
            cameraFrame.MoveForward(linear);
        }
        if (key == GLUT_KEY_DOWN) {
            cameraFrame.MoveForward(-linear);
        }
        if (key == GLUT_KEY_LEFT) {
            //RotateWorld旋转
            cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
        }
        if (key == GLUT_KEY_RIGHT) {
            cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
        }
    }
    
    1. 至此,我们就完成了这个动画的小案例,如果想看代码实现,请点击这里OpenGL_Ball_Demo

    相关文章

      网友评论

          本文标题:OpenGL 综合案例(地球自转与公转)

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