案例2、 OpenGL隧道

2020-07-22  本文已影响0人  ChenL

main:初始化入口
SetupRC:初始化背景色、着色器,生成纹理,并设置顶点及纹理坐标
ChangeSize:改变视景体和视口,在改变窗口大小或初始化窗口调用
RenderScene:清理缓存、绑定纹理并绘制隧道
ShutdownRC:关闭渲染环境
SpecialKeys:根据上下键位,记录前后移动的深度值,并重新渲染
ProcessMenu:根据选择的菜单选项,for循环更换所有纹理的过滤方式,并重新渲染

main函数
  gltSetWorkingDirectory(argv[0]);
   // 标准初始化
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize(800, 600);
   glutCreateWindow("Tunnel");
   glutReshapeFunc(ChangeSize);
   glutSpecialFunc(SpecialKeys);
   glutDisplayFunc(RenderScene);
   
   // 添加菜单入口,改变过滤器
   glutCreateMenu(ProcessMenu);
   glutAddMenuEntry("GL_NEAREST",0);
   glutAddMenuEntry("GL_LINEAR",1);
   glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
   glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
   glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
   glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
   glutAddMenuEntry("Anisotropic Filter", 6);
   glutAddMenuEntry("Anisotropic Off", 7);
   
   glutAttachMenu(GLUT_RIGHT_BUTTON);
   
   GLenum err = glewInit();
   if (GLEW_OK != err) {
       fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
       return 1;
   }
   // 启动循环,关闭纹理
   SetupRC();
   glutMainLoop();
   ShutdownRC();
SetupRC函数

.初始化
.生成纹理
.设置隧道数据


1.png

生成纹理标记

    参数1:纹理对象的数量
    参数2:纹理对象标识数组
    glGenTextures(TEXTURE_COUNT, textures);

设置纹理参数

由于使用了多个纹理,每个纹理都需要设置参数,使用for循环
bind --> readTGA --> texParameter --> texImage --> generateMip --> free
1、绑定纹理对象
2、读取TGA纹理文件
3、设置纹理环绕方式和过滤方式
4、载入纹理
5、生成Mip贴图(当过滤方式与Mip无关时,可以设置,也可以不设置,如果使用与Mip相关的过滤方式,就必须设置)
参数1:纹理维度,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_2D
-- glGenerateMipmap
6、释放纹理对象空间的指针

for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
    {
        /**绑定纹理对象 glBindTexture
         参数1:纹理模式,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D
         参数2:需要绑定的纹理对象
         */
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        /**加载tga文件
         参数1:纹理文件名称
         参数2:文件宽度变量地址
         参数3:文件高度变量地址
         参数4:文件组件变量地址
         参数5:文件格式变量地址
         返回值:pBytes,指向图像数据的指针
         */
        
        pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight,
                                &iComponents, &eFormat);
        
        //加载纹理、设置过滤器和包装模式
        //GL_TEXTURE_MAG_FILTER(放大过滤器,GL_NEAREST(最邻近过滤)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        //GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST(最邻近过滤)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        //GL_TEXTURE_WRAP_S(s轴环绕),GL_CLAMP_TO_EDGE(环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后一行或一列进行采样)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        //GL_TEXTURE_WRAP_T(t轴环绕),GL_CLAMP_TO_EDGE(环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后一行或一列进行采样)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        /**载入纹理 glTexImage2D
         参数1:纹理维度,GL_TEXTURE_2D
         参数2:mip贴图层次
         参数3:纹理单元存储的颜色成分(从读取像素图中获得)
         参数4:加载纹理宽度
         参数5:加载纹理的高度
         参数6:加载纹理的深度
         参数7:像素数据的数据类型,GL_UNSIGNED_BYTE无符号整型
         参数8:指向纹理图像数据的指针
         */
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        
        /**为纹理对象生成一组完整的mipmap glGenerateMipmap
         参数1:纹理维度,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_2D
         */
        glGenerateMipmap(GL_TEXTURE_2D);
        
        //释放原始纹理数据,不在需要纹理原始数据了
        free(pBytes);
    }

设置隧道数据

参数1:图元枚举值
参数2:顶点数
参数3:1组或者2组纹理坐标
void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);

6-10.png
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    //参考6-10图
    //Z表示深度,隧道的深度
    for(z = 60.0f; z >= 0.0f; z -=10.0f)
    {
        floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z);
        
        floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z);
        
        floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
        
        floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
    }
    floorBatch.End();
RenderScene函数
2.png

1、清除颜色缓存

    glClear(GL_COLOR_BUFFER_BIT);

2、push压栈:为了不影响矩阵的初始状态,方便后续恢复矩阵

modelViewMatrix.PushMatrix();

3、视图模型矩阵平移:因为初始化是是在原点,需要往-z轴平移一定的矩阵,方便观察,且与矩阵栈顶相乘,将其结果覆盖栈顶矩阵

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

4、使用纹理替换矩阵着色器:最后一个参数是指纹理的level,默认为0

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

5、绑定纹理:由于地面、天花板、左右墙分别使用不同的纹理,所以需要分别绑定并绘制

/*
     参数1:纹理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
     参数2:需要绑定的纹理
     */
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
    floorBatch.Draw();
    
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
    ceilingBatch.Draw();
    
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
    leftWallBatch.Draw();
    rightWallBatch.Draw();

6、pop出栈:恢复矩阵的初始状态

modelViewMatrix.PopMatrix();

7、交换缓冲区

glutSwapBuffers();
SpecialKeys函数

函数功能比较简单,主要就是根据上下键位,记录移动的深度值,并重新渲染

ProcessMenu函数
3.png
上一篇 下一篇

猜你喜欢

热点阅读