opengl

OpenGL纹理MipMap和隧道案例

2020-07-22  本文已影响0人  过气的程序员DZ

开场白

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

MipMap简介一下

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

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

设置方法

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

mip的纹理过滤方式

过滤方式如图:


纹理过滤方式

隧道案例

先看看效果:


案例效果

案例简述

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

核心代码

核心代码就是纹理的渲染,键盘控制可以参考本人往期的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

示例代码地址

上一篇下一篇

猜你喜欢

热点阅读