美文网首页
OpenGL公转与自转的绘制

OpenGL公转与自转的绘制

作者: ZAREMYDREAM | 来源:发表于2020-07-20 17:38 被阅读0次

    公转和自转是OpenGL中的一个经典案例,先来看看效果:


    效果图

    方法分析

    1、对图形数据初始化,需要调用setupRC()方法
    2、窗口大小变动时,需要调用changeSize(int,int)方法
    3、每次绘制时,需要调用RenderScene()方法
    4、按键盘移动,需要调用SpecialKey(int,int,int)方法

    变量分析

    1、地面容器 GLBatch floorBatch
    2、红色球体 GLTriangleBatch redBatch
    3、蓝色球体 GLTriangleBatch blueBatch
    4、 观察者 GLFrame camera
    5、远处球体坐标 GLFrame spheres[NUM_SPHERES]

    运行流程:

    1、main函数中先进行初始化设置
    2、在SetupRC中初始化图形参数
    3、设置视图尺寸触发changSize()
    4、每次渲染时执行RenderScene()
    5、键盘输入执行SpecialKey()后,会调用RenderSecene()
    6、自转公转需要定时器,定时器每秒钟会触发重新渲染调用RenderSecene()


    执行顺序

    具体个方法实现

    1、main函数

    int main(int argc,char *argv[]) {
    
        //初始化GLUT库
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL)
     
        //设置GLUT窗口大小与标题
        glutInitWindowSize(1920, 1080);
        glutCreateWindow("Floor");
       
        //指定窗口改变时调用的方法
        glutReshapeFunc(changeSize);
        //指定渲染时调用的方法
        glutDisplayFunc(RenderScene);
        //指定键盘输入时调用的方法
        glutSpecialFunc(SpecialKey);
        //判断驱动器有没有问题
        GLenum status = glewInit();
        if (GLEW_OK != status)  {
                    return 0;
        }
        
        //初始化渲染环境
        setupRC();
        //执行loop循环
        glutMainLoop();
        return  0;
    }
    

    2、changsize函数

    void changeSize(int w,int h) {
        //设置窗口
        glViewport(0, 0, w, h);
        
        //设置投影矩阵,因为投影矩阵需要窗口长宽比,所以在changsize中设置
        viewFrustum.SetPerspective(35, float(w)/float(h), 1, 100);
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
       //模型矩阵,视图矩阵加入管道,便于取用
        transform.SetMatrixStacks(modelMatrix, projectionMatrix);
    }
    

    3、setupRC函数

    void setupRC() {
        //清除遗留背景色并设置背景色
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        //初始化着色器
        shaderManager.InitializeStockShaders();
        //开启深度测试
        glEnable(GL_DEPTH_TEST);
        camera.RotateWorld(float(m3dDegToRad(180.0f)), 0, 1, 0);
        
        //地面的坐标
        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(redBatch, 0.5f, 100, 100);
        //蓝球
        gltMakeSphere(blueBatch, 0.1f, 20, 20);
        
        //随机位置放置蓝球
        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);
        }
    }
    

    4、SpecialKey函数

    void SpecialKey(int keys, int x, int y) {
        //每次移动的距离
        GLfloat line = 1;
        //每次旋转的弧度
        float angular = float(m3dDegToRad(5.0f));
    
        if (keys == GLUT_KEY_UP) {
            camera.MoveForward(line);
        }
        if (keys == GLUT_KEY_DOWN) {
            camera.MoveForward(-line);
        }
        if (keys == GLUT_KEY_LEFT) {
            camera.RotateWorld(angular, 0, 1, 0);
        }
        if (keys == GLUT_KEY_RIGHT) {
            camera.RotateWorld(-angular, 0, 1, 0);
        }
    }
    

    5、RenderScene函数

    void RenderScene(void) {
        //清空颜色缓存区和深度缓存区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        //地板颜色
        static GLfloat floorC[] = {0,1,0,1};
        //红球颜色
        static GLfloat redC[] = {1,0,0,1};
        //篮球颜色
        static GLfloat blueC[] = {0,0,1,1};
        //定时器
        static CStopWatch timer;
        float yRot = timer.GetElapsedSeconds()*60;
        //光源位置
        M3DVector4f light = {0.0f,10.0f,5.0f,1.0f};
        //拷贝一份栈顶的状态并放入栈顶
        modelMatrix.PushMatrix();
        //观察者移动
        M3DMatrix44f mCamera;
        camera.GetMatrix(mCamera);
        modelMatrix.PushMatrix(mCamera);
        //绘制地面
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transform.GetModelViewProjectionMatrix(),floorC);
        floorBatch.Draw();
        
        //红球
        //红球向屏幕内移动
        modelMatrix.Translate(0, 0, -3);
        //红球自转需要保存自转前的状态,先进行拷贝入栈
        modelMatrix.PushMatrix();
       //红球自转
        modelMatrix.Rotate(yRot, 0, 1, 0);
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transform.GetModelViewMatrix(), transform.GetProjectionMatrix(), light, redC);
        redBatch.Draw();
        modelMatrix.PopMatrix();
    
        //蓝色小球
        for (int i = 0; i < NUM_SPHERES; i++) {
            modelMatrix.PushMatrix();
            modelMatrix.MultMatrix(spheres[i]);
            shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transform.GetModelViewMatrix(), transform.GetProjectionMatrix(), light, blueC);        blueBatch.Draw();
            modelMatrix.PopMatrix();
        }
        
        //公转
        modelMatrix.Rotate(yRot*-3.0, 0, 1, 0);
        modelMatrix.Translate(0.8f, 0, 0);
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transform.GetModelViewMatrix(), transform.GetProjectionMatrix(), light, blueC);
        blueBatch.Draw();
        modelMatrix.PopMatrix();
        modelMatrix.PopMatrix();
        glutSwapBuffers();
        glutPostRedisplay();
    }
    

    相关文章

      网友评论

          本文标题:OpenGL公转与自转的绘制

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