OpenGL公转与自转的绘制

2020-07-20  本文已影响0人  ZAREMYDREAM

公转和自转是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();
}
上一篇下一篇

猜你喜欢

热点阅读