美文网首页opengl
OpenGL纹理MipMap和隧道案例

OpenGL纹理MipMap和隧道案例

作者: 过气的程序员DZ | 来源:发表于2020-07-22 13:50 被阅读0次

开场白

本文介绍一下纹理的mip映射以及用一个隧道案例来展示不同mip过滤模式的效果。

MipMap简介一下

MipMap是一个纹理渲染技术。它能够提高渲染性能并且提升场景的视觉质量。
纹理贴图会有以下两个常见问题:

  • 闪烁:当纹理size远大于被渲染物体表面时,会出现闪烁现象。尤其是移动观察者远离物体的时候,负面效果更明显
  • 性能影响:当加载大量纹理时,并且对这些纹理进行缩小操作(观察者远离物体)时,会对性能要求比较高。

MipMap可以很好的解决上述的两个问题。使用此技术,OpenGL会生成大小不等的多个纹理并且OpenGL会自动根据不同状态选择不同的纹理进行渲染。多个纹理也就会增加存储空间,也就是用空间换时间的一种方案。

设置方法

调用纹理参数函数,例如:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

  • 参数1:指定纹理模式
  • 参数2:告诉OpenGL要设定的什么,这里设定的是纹理缩小过滤方式。
  • 参数3:mip之间使用线性过滤,整体使用邻近过滤。

mip的纹理过滤方式

过滤方式如图:


纹理过滤方式
  • 前两个GL_NEAREST和GL_LINEAR方式,只会加载基础mip层。
  • 后四个是GL_X1_MIPMAP_X2形式。X2指定的是mip之间的过滤方式,X1指定的是整体的过滤方式。可以理解为是纹理的内部(X2)和外部(X1)分别使用什么样的过滤方式。

隧道案例

先看看效果:


案例效果

案例简述

使用纹理渲染地面、天花板和左右两面的墙壁。用键盘控制前进、后退以及观察视角的旋转。

核心代码

核心代码就是纹理的渲染,键盘控制可以参考本人往期的OpenGL的相关文章。

初始化设置SetupRC
void SetupRC() {
    glClearColor(0.0f,0.0f,0.0f,1.0f);
    shaderManager.InitializeStockShaders();
    
    //1.定义纹理需要的相关变量
    GLbyte *pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;
    GLint iLoop;
    
    //2.申请TEXTURE_COUNT个纹理对象
    glGenTextures(TEXTURE_COUNT, textures);
    
    //3.设置纹理属性
    for (iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
        //3.1绑定纹理
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        //3.2加载纹理
        pBytes = gltReadTGABits(szTextureFiles[iLoop], &iWidth, &iHeight, &iComponents, &eFormat);
        
        //3.3放大缩小过滤方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        
        //3.4环绕方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        
        //3.5设定纹理
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        //3.6设置mipmap
        glGenerateMipmap(GL_TEXTURE_2D);
        free(pBytes);
    }
    
    GLfloat z;
    //4.地板批次类设置
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 60; z >= 0; z-=10) {
        
        floorBatch.MultiTexCoord2f(0, 0, 0);
        floorBatch.Vertex3f(-10, -10, z);

        floorBatch.MultiTexCoord2f(0, 1, 0);
        floorBatch.Vertex3f(10, -10, z);

        floorBatch.MultiTexCoord2f(0, 0, 1);
        floorBatch.Vertex3f(-10, -10, z-10);

        floorBatch.MultiTexCoord2f(0, 1, 1);
        floorBatch.Vertex3f(10, -10, z-10);
    }
    floorBatch.End();
    
    //5.天花板批次类设置
    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 60; z >= 0; z-=10) {
        ceilingBatch.MultiTexCoord2f(0, 0, 0);
        ceilingBatch.Vertex3f(-10, 10, z);
        
        ceilingBatch.MultiTexCoord2f(0, 0, 1);
        ceilingBatch.Vertex3f(-10, 10, z - 10);
        
        ceilingBatch.MultiTexCoord2f(0, 1, 0);
        ceilingBatch.Vertex3f(10, 10, z);
        
        ceilingBatch.MultiTexCoord2f(0, 1, 1);
        ceilingBatch.Vertex3f(10, 10, z - 10);
    }
    ceilingBatch.End();
    
    //6.左侧墙壁批次类设置
    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 60; z >= 0; z-=10) {
        leftWallBatch.MultiTexCoord2f(0, 0, 0);
        leftWallBatch.Vertex3f(-10, -10, z);
        
        leftWallBatch.MultiTexCoord2f(0, 0, 1);
        leftWallBatch.Vertex3f(-10, 10, z);
        
        leftWallBatch.MultiTexCoord2f(0, 1, 0);
        leftWallBatch.Vertex3f(-10, -10, z - 10);
        
        leftWallBatch.MultiTexCoord2f(0, 1, 1);
        leftWallBatch.Vertex3f(-10, 10, z - 10);
    }
    leftWallBatch.End();
    
    //7.右侧墙壁批次类设置
    rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 60; z >= 0; z-=10) {
        rightWallBatch.MultiTexCoord2f(0, 0, 0);
        rightWallBatch.Vertex3f(10, -10, z);
        
        rightWallBatch.MultiTexCoord2f(0, 0, 1);
        rightWallBatch.Vertex3f(10, 10, z);
        
        rightWallBatch.MultiTexCoord2f(0, 1, 0);
        rightWallBatch.Vertex3f(10, -10, z - 10);
        
        rightWallBatch.MultiTexCoord2f(0, 1, 1);
        rightWallBatch.Vertex3f(10, 10, z - 10);
    }
    rightWallBatch.End();
    
}
  1. 定义纹理需要的一些变量,这些的值都会在加载纹理gltReadTGABits函数中进行返回,并且在设定纹理glTexImage2D函数中会使用到,传入即可。

  2. 申请纹理对象,本案例中会用到3个纹理(地面、天花板、墙壁)。

  3. 设置纹理属性,用一个for循环,for内部统一处理3个纹理。

    1. 绑定纹理,使用2D的方式
    2. 加载纹理,获取纹理的相关信息到定义的变量上
    3. 设置放大缩小过滤方式
    4. 设置环绕方式,绕S和T环绕
    5. 设定纹理
    6. 设置mip
  4. 设置地板,使用三角形带GL_TRIANGLE_STRIP的方式设置批次类。将纹理的四个顶点设置到如图的位置上: 地板
  5. 设置天花板,与设置地板类似: 天花板
  1. 设置左右墙壁: 左右墙壁
渲染函数RenderScene
void RenderScene(void) {
    //清楚一个或一组特定的缓冲区
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);
    
    modelViewMatrix.PushMatrix(mCamera);
    modelViewMatrix.Translate(0, 0, viewZ);
    
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
    
    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();
    
    modelViewMatrix.PopMatrix();
    
    //将在后台缓冲区进行渲染,然后在结束时交换到前台
    glutSwapBuffers();
}
  1. 使用纹理替换GLT_SHADER_TEXTURE_REPLACE着色器
  2. 绘制不同纹理前需要先进行绑定后在绘制

两个核心函数中纹理设置大概流程如图:


右击菜单-修改过滤方式

通过右击可以呼出菜单,修改不同的缩小过滤方式


GL_NEARSET_MIPMAP_LINEAR 与 GL_LINEAR
  • 左图是:GL_NEARSET_MIPMAP_LINEAR方式
  • 右图是:GL_LINEAR方式
    可以看到远处墙壁模糊度是不同的,也就是缩小状态下过滤方式不同。

示例代码地址

相关文章

  • OpenGL纹理MipMap和隧道案例

    开场白 本文介绍一下纹理的mip映射以及用一个隧道案例来展示不同mip过滤模式的效果。 MipMap简介一下 Mi...

  • OpenGL 纹理隧道案例

    隧道示例程序使用了和纹理有关的内容,并在视觉上显示了不同的过滤器和贴图模式。 该示例程序在启动时加载3个纹理用于对...

  • OpenGL 纹理案例-隧道

    在学习了纹理之后,我们尝试着用纹理来实现一个类似于下图这样的隧道效果,并且让他可以通过键盘的上下键可以来进行前进和...

  • OpenGL纹理案例-隧道

    使用OpenGL常用的API,绘制一个简单的隧道模型并贴图。最终下过如下: 完成代码: #include "GLT...

  • OpenGL纹理案例-隧道

    OpenGL纹理案例-隧道 之前我写过一些关于纹理的一些基本API和API的方法参数的解释,现在我们来弄一个隧道案...

  • OpenGL纹理坐标&&隧道案例(二)

    一.隧道案例效果 二.纹理坐标 纹理坐标主要是把图形映射到OpenGL中去,图形中每个顶点关联到对应的纹理坐标下,...

  • 八:OpenGL纹理(中):隧道案例

    前言: 上节为大家介绍了一个金字塔的原型,接下来为大家来实现一个更加复杂的案例吧,本节为大家介绍一个“隧道穿行”,...

  • OpenGL:纹理隧道

    本案例主要目的多个纹理如何使用,加深对纹理的使用的理解。 整体的案例效果如图所示 下面接着说说隧道的绘制过程,整体...

  • OpenGL之纹理映射Mipmap

    一、Mipmapping 1、Mipmapping是一个功能强大的纹理技术,它可以提高渲染的性能以及提升场景的视觉...

  • OpenGL之Mipmap、压缩纹理

    Mipmap Mipmap是一个功能强大的纹理技术,它可以提高渲染的性能以及提升场景的视觉质量。为了加快渲染速度和...

网友评论

    本文标题:OpenGL纹理MipMap和隧道案例

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