美文网首页
OpenGL综合案例

OpenGL综合案例

作者: 逃避不面对 | 来源:发表于2020-07-20 15:21 被阅读0次

    OpenGL已经学习了一段时间,现在进行一下综合整理工作。

    绘制地板

    以下是详细代码及注释,这里不再做一一解释,这里只摘录了changeSize、SetupRC、RenderScene这几个方法中的代码,其他代码及他们的执行流程,可以参照之前文章:

    GLShaderManager shaderManager; // 着色器管理器

    GLMatrixStack        modelViewMatrix;        // 模型视图矩阵

    GLMatrixStack        projectionMatrix;        // 投影矩阵

    GLFrustum            viewFrustum;            // 视景体

    GLGeometryTransform    transformPipeline;        // 几何图形变换管道

    GLTriangleBatch        torusBatch;            //大球

    GLTriangleBatch    sphereBatch;            //小球

    GLBatch                floorBatch;          //地板

    //角色帧 照相机角色帧

    GLFrame            cameraFrame;

    //**4、添加附加随机球

    #define NUM_SPHERES 50

    GLFrame spheres[NUM_SPHERES];

    //屏幕更改大小或已初始化

    void changeSize(int w,int h)

    {

        //设置视口大小

        glViewport(0, 0, w, h);

        //创建投影矩阵 并将它载入到投影矩阵堆栈中

        viewFrustum.SetPerspective(35.0f, (float)w/(float)h, 1.0f, 100.0f);

        //viewFrustum.GetProjectionMatrix()用来获取投影矩阵

        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

        //3.设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix ,投影矩阵projectionMatrix)

        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    }

    //初始化操作

    void setupRC()

    {

        //进行初始化操作

        //1.清理颜色

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        //初始化着色器

        shaderManager.InitializeStockShaders();

        //开启深度测试

        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();

    }

    //进行调用以绘制场景

    void RenderScene(void)

    {

        //设置地板颜色值

        static GLfloat vFloorColor[] = {0.0f,1.0f,0.0f,1.0f};

        //2.清除颜色缓存区和深度缓冲区

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //3.绘制地面 GLT_SHADER_FLAT平面着色器

        shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);

        //进行绘制

        floorBatch.Draw();

        //交换缓冲区

        glutSwapBuffers();

    }

    执行后结果:

    绘制大球

    代码及注释:

    //以上面的代码为基础,changeSize中不需要更改,在setupRC设置大球模型

    //设置大球模型  因为OpenGL中自带球类模型,不需要自己画顶点,直接调用gltMakeSphere方法,使用批次类,传对应的参数及可。

        gltMakeSphere(torusBatch, 0.4f, 40, 80);

    //RenderScene中改动较大,详细代码如下:

    void RenderScene(void)

    {

        //设置地板颜色值

        static GLfloat vFloorColor[] = {0.0f,1.0f,0.0f,1.0f};

        //设置大球颜色

        static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };

        //创建定时器,用于控制大球转动

        static CStopWatch rotTimer;

        //得到大球每秒转动的角度

        float yRot = rotTimer.GetElapsedSeconds() *60.0;

        //2.清除颜色缓存区和深度缓冲区

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //进行压栈,为了确保每次操作独立,不影响其他操作  每一次压栈PushMatrix都要对应一次出栈PopMatrix

        modelViewMatrix.PushMatrix();

        //3.绘制地面 GLT_SHADER_FLAT平面着色器

        shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);

        //进行绘制

        floorBatch.Draw();

        //用矩阵设置一处光源

        M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};

        //为了获得更好的观察效果,让大球想屏幕里移动3.0

        modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);

        //再次压栈,为了下面的旋转操作

        modelViewMatrix.PushMatrix();

        //大球绕y轴旋转

        modelViewMatrix.Rotate(0.0f, 1.0f, 0.0f, 1.0f);

        //设置着色器(点光源着色器) 模型视图变换矩阵  投影矩阵 点光源位置 颜色值

        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vTorusColor);

        //绘制

        torusBatch.Draw();

        //进行出栈 2次

        modelViewMatrix.PopMatrix();

        modelViewMatrix.PopMatrix();

        //交换缓冲区

        glutSwapBuffers();

        //重新提交渲染

        glutPostRedisplay();

    }

    执行结果:

    绘制多个小球

    代码如下:

    //如添加大球时的操作,同样SetupRC中添加小球模型,并随机放置50个

    //设置小球模型

        gltMakeSphere(sphereBatch, 0.2f, 13, 26);

        //随机放置 NUM_SPHERES上面定义过的宏

        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);

        }

    //同样在RenderScene中去绘制这50个小球

    //画小球,for循环画50个,单个小球画法和大球差不多,不同的是通过压栈来保持每一次小球的独立

        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();

        }

    生成小球

    小球围绕大球转动

    代码:

    //在RenderScene方法中加入

    //让一个小篮球围绕大球公众自转

        modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 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();

    键位控制

    代码:

    //mian函数中注册键位控制函数

    glutSpecialFunc(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);

        }

    }

    //然后在RenderScene中加入一个观察者 平移10步(地板,大球,小球,小小球),通过移动观察者来达到目的

        M3DMatrix44f mCamera;

        cameraFrame.GetCameraMatrix(mCamera);

        modelViewMatrix.PushMatrix(mCamera);

    这里大球自转,小球围绕大球公转的案例就完成了。

    相关文章

      网友评论

          本文标题:OpenGL综合案例

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