美文网首页
九、OpenGL综合练习-球体世界

九、OpenGL综合练习-球体世界

作者: 含笑州 | 来源:发表于2020-08-31 06:51 被阅读0次

    最终效果

    代码

    #include "GLTools.h"

    #include "GLShaderManager.h"

    #include "GLFrustum.h"

    #include "GLBatch.h"

    #include "GLMatrixStack.h"

    #include "GLGeometryTransform.h"

    #include "StopWatch.h"

    #include <math.h>

    #include <stdio.h>

    #ifdef __APPLE__

    #include <glut/glut.h>

    #else

    #define FREEGLUT_STATIC

    #include <GL/glut.h>

    #endif

    //添加附加随机球

    #define NUM_SPHERES 50

    GLFrame spheres[NUM_SPHERES];

    GLShaderManager shaderManager; // 着色器管理器

    GLMatrixStack modelViewMatrix; // 模型视图矩阵

    GLMatrixStack projectionMatrix; // 投影矩阵

    GLFrustum viewFrustum; // 视景体

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

    GLTriangleBatch torusBatch; // 花托批处理

    GLBatch floorBatch; // 地板批处理

    //**2、定义公转球的批处理(公转自转)**

    GLTriangleBatch  sphereBatch; //球批处理

    //**3、角色帧 照相机角色帧(全局照相机实例)

    GLFrame  cameraFrame;

    //**5、添加纹理

    //纹理标记数组

    GLuint uiTextures[3];

    bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)

    {

     GLbyte *pBits;

     int nWidth, nHeight, nComponents;

     GLenum eFormat;

     //1.读取纹理数据

    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);

     if(pBits == NULL)

     return false;

     //2、设置纹理参数

     //参数1:纹理维度

     //参数2:为S/T坐标设置模式

     //参数3:wrapMode,环绕模式

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);

     //参数1:纹理维度

     //参数2:线性过滤

     //参数3:wrapMode,环绕模式

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);

     //3.载入纹理

     //参数1:纹理维度

     //参数2:mip贴图层次

     //参数3:纹理单元存储的颜色成分(从读取像素图是获得)-将内部参数nComponents改为了通用压缩纹理格式GL_COMPRESSED_RGB

     //参数4:加载纹理宽

     //参数5:加载纹理高

     //参数6:加载纹理的深度

     //参数7:像素数据的数据类型(GL_UNSIGNED_BYTE,每个颜色分量都是一个8位无符号整数)

     //参数8:指向纹理图像数据的指针

     glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0,

    eFormat, GL_UNSIGNED_BYTE, pBits);

     //使用完毕释放pBits

     free(pBits);

     //只有minFilter 等于以下四种模式,才可以生成Mip贴图

     //GL_NEAREST_MIPMAP_NEAREST具有非常好的性能,并且闪烁现象非常弱

     //GL_LINEAR_MIPMAP_NEAREST常常用于对游戏进行加速,它使用了高质量的线性过滤器

     //GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹。

     //GL_LINEAR_MIPMAP_LINEAR 三线性Mip贴图。纹理过滤的黄金准则,具有最高的精度。

     if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||

    minFilter == GL_LINEAR_MIPMAP_NEAREST ||

    minFilter == GL_NEAREST_MIPMAP_LINEAR ||

    minFilter == GL_NEAREST_MIPMAP_NEAREST)

     //4.加载Mip,纹理生成所有的Mip层

     //参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D

     glGenerateMipmap(GL_TEXTURE_2D);

     return true;

    }

    void SetupRC(){

     //1.设置清屏颜色到颜色缓存区

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

     //2.初始化着色器管理器

     shaderManager.InitializeStockShaders();

     //3.开启深度测试/背面剔除

     glEnable(GL_DEPTH_TEST);

     glEnable(GL_CULL_FACE);

     //4.设置大球球

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

     //5.设置小球(公转自转)

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

     //6.设置地板顶点数据&地板纹理

     GLfloat texSize = 10.0f;

     floorBatch.Begin(GL_TRIANGLE_FAN, 4,1);

     floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);

     floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);

     floorBatch.MultiTexCoord2f(0, texSize, 0.0f);

     floorBatch.Vertex3f(20.0f, -0.41f, 20.f);

     floorBatch.MultiTexCoord2f(0, texSize, texSize);

     floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);

     floorBatch.MultiTexCoord2f(0, 0.0f, texSize);

     floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);

     floorBatch.End();

     //7.随机小球球顶点坐标数据

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

        }

     //8.命名纹理对象

     glGenTextures(3, uiTextures);

     //9.将TGA文件加载为2D纹理。

     //参数1:纹理文件名称

     //参数2&参数3:需要缩小&放大的过滤器

     //参数4:纹理坐标环绕模式

     glBindTexture(GL_TEXTURE_2D, uiTextures[0]);

     LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);

     glBindTexture(GL_TEXTURE_2D, uiTextures[1]);

     LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR,

     GL_LINEAR, GL_CLAMP_TO_EDGE);

     glBindTexture(GL_TEXTURE_2D, uiTextures[2]);

     LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,

     GL_LINEAR, GL_CLAMP_TO_EDGE);

    }

    //删除纹理

    void ShutdownRC(void)

    {

     glDeleteTextures(3, uiTextures);

    }

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

    void ChangeSize(int nWidth, int nHeight)

    {

     //1.设置视口

     glViewport(0, 0, nWidth, nHeight);

     //2.设置投影方式

     viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);

     //3.将投影矩阵加载到投影矩阵堆栈,

     projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

     modelViewMatrix.LoadIdentity();

     //4.将投影矩阵堆栈和模型视图矩阵对象设置到管道中

     transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    }

    void drawSomething(GLfloat yRot)

    {

     //1.定义光源位置&漫反射颜色

     static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };

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

     //2.绘制悬浮小球球

     glBindTexture(GL_TEXTURE_2D, uiTextures[2]);

     for(int i = 0; i < NUM_SPHERES; i++) {

     modelViewMatrix.PushMatrix();

     modelViewMatrix.MultMatrix(spheres[i]);

     shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,

     modelViewMatrix.GetMatrix(),

     transformPipeline.GetProjectionMatrix(),

                                         vLightPos,

                                         vWhite,

     0);

     sphereBatch.Draw();

     modelViewMatrix.PopMatrix();

        }

     //3.绘制大球球

     modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);

     modelViewMatrix.PushMatrix();

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

     glBindTexture(GL_TEXTURE_2D, uiTextures[1]);

     shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,

     modelViewMatrix.GetMatrix(),

     transformPipeline.GetProjectionMatrix(),

                                     vLightPos,

                                     vWhite,

     0);

     torusBatch.Draw();

     modelViewMatrix.PopMatrix();

     //4.绘制公转小球球(公转自转)

     modelViewMatrix.PushMatrix();

     modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);

     modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);

     glBindTexture(GL_TEXTURE_2D, uiTextures[2]);

     shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,

     modelViewMatrix.GetMatrix(),

     transformPipeline.GetProjectionMatrix(),

                                     vLightPos,

                                     vWhite,

     0);

     sphereBatch.Draw();

     modelViewMatrix.PopMatrix();

    }

    //进行调用以绘制场景

    void RenderScene(void)

    {

     //1.地板颜色值

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

     //2.基于时间动画

     static CStopWatch    rotTimer;

     float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

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

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

     //4.压入栈(栈顶)

     modelViewMatrix.PushMatrix();

     //5.设置观察者矩阵

     M3DMatrix44f mCamera;

     cameraFrame.GetCameraMatrix(mCamera);

     modelViewMatrix.MultMatrix(mCamera);

     //6.压栈(镜面)

     modelViewMatrix.PushMatrix();

     //7.---添加反光效果---

     //翻转Y轴

     modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);

     //镜面世界围绕Y轴平移一定间距

     modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);

     //8.指定顺时针为正面

     glFrontFace(GL_CW);

     //9.绘制地面以外其他部分(镜面)

     drawSomething(yRot);

     //10.恢复为逆时针为正面

     glFrontFace(GL_CCW);

     //11.绘制镜面,恢复矩阵

     modelViewMatrix.PopMatrix();

     //12.开启混合功能(绘制地板)

     glEnable(GL_BLEND);

     //13. 指定glBlendFunc 颜色混合方程式

     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

     //14.绑定地面纹理

     glBindTexture(GL_TEXTURE_2D, uiTextures[0]);

     /*15.

         纹理调整着色器(将一个基本色乘以一个取自纹理的单元nTextureUnit的纹理)

         参数1:GLT_SHADER_TEXTURE_MODULATE

         参数2:模型视图投影矩阵

         参数3:颜色

         参数4:纹理单元(第0层的纹理单元)

         */

     shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,

     transformPipeline.GetModelViewProjectionMatrix(),

                                     vFloorColor,

     0);

     //shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);

     //开始绘制

     floorBatch.Draw();

     //取消混合

     glDisable(GL_BLEND);

     //16.绘制地面以外其他部分

     drawSomething(yRot);

     //17.绘制完,恢复矩阵

     modelViewMatrix.PopMatrix();

     //18.交换缓存区

     glutSwapBuffers();

     //19.提交重新渲染

     glutPostRedisplay();

    }

    //**3.移动照相机参考帧,来对方向键作出响应

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

        }

    }

    部分讲解

    地板

    相比于原来demo的324个小地板拼成一个大地板,这里采用了一整块大地板。由于纹理贴图较小,这里使用了10倍的纹理坐标大小,以获得更细腻的地板效果。

    //5.设置地板顶点数据&地板纹理

    GLfloat texSize = 10.0f;

    floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);

    floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);

    floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);

    floorBatch.MultiTexCoord2f(0, texSize, 0.0f);

    floorBatch.Vertex3f(20.0f, -0.41f, 20.f);

    floorBatch.MultiTexCoord2f(0, texSize, texSize);

    floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);

    floorBatch.MultiTexCoord2f(0, 0.0f, texSize);

    floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);

    floorBatch.End();

    纹理

    依次读取3个纹理,并使用了mipmap技术。

    //7.创建3个纹理对象

    glGenTextures(3, uiTextures);

    //8.将TGA文件加载为2D纹理。

    //参数1:纹理文件名称

    //参数2&参数3:需要缩小&放大的过滤器

    //参数4:纹理坐标环绕模式

    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);

    LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);

    glBindTexture(GL_TEXTURE_2D, uiTextures[1]);

    LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);

    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);

    LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);

    球的贴图

    不管是大球还是小球,绘制方式基本和原来一样。只是多了纹理的绑定,同时使用的shader从GLT_SHADER_POINT_LIGHT_DIFF变为了GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF。

    //2.绘制悬浮小球

    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);

    for(int i = 0; i < NUM_SPHERES; i++) {

       modelViewMatrix.PushMatrix();

       modelViewMatrix.MultMatrix(spheres[i]);

       shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,

                                    modelViewMatrix.GetMatrix(),

                                    transformPipeline.GetProjectionMatrix(),

                                    vLightPos,

                                    vWhite,

                                    0);

       sphereBatch.Draw();

       modelViewMatrix.PopMatrix();

    }

    镜面效果

    镜面效果通过镜像绘制小球,并和地板进行混合达到镜面效果。

    镜面之后,y轴的前后移动会反向;原来正面为逆时针,现在为顺时针。

    //7.---添加反光效果---

       //翻转Y轴

       modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);

       //镜面世界围绕Y轴平移一定间距,因为镜面了,所以是向下移动0.8

       modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);

       // 镜面后,原来逆时针为正面,现在顺时针为正面

       //8.指定顺时针为正面

       glFrontFace(GL_CW);

       //9.绘制地面以外其他部分(镜面)

       drawSomething(yRot);

       //10.恢复为逆时针为正面

       glFrontFace(GL_CCW);

       //11.绘制镜面完毕,恢复矩阵

       modelViewMatrix.PopMatrix();

       //12.开启混合功能(绘制地板)

       glEnable(GL_BLEND);

       //13. 指定 glBlendFunc 颜色混合方程式

       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

       //14.绑定地面纹理

       glBindTexture(GL_TEXTURE_2D, uiTextures[0]);

       /*15.

        纹理调整着色器(将一个基本色乘以一个取自纹理的单元nTextureUnit的纹理)

        参数1:GLT_SHADER_TEXTURE_MODULATE

        参数2:模型视图投影矩阵

        参数3:颜色

        参数4:纹理单元(第0层的纹理单元)

        */

       shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,

                                    transformPipeline.GetModelViewProjectionMatrix(),

                                    vFloorColor,

                                    0);

       //开始绘制

       floorBatch.Draw();

       //绘制完毕,取消混合

       glDisable(GL_BLEND);

    相关文章

      网友评论

          本文标题:九、OpenGL综合练习-球体世界

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