OpenGL--多级纹理

来源:互联网 发布:微软最牛程序员 编辑:程序博客网 时间:2024/06/01 10:05
  • 理论基础
    多级纹理(Mipmap):就是分辨率递减的同一纹理,根据距离观察点的距离选着最适合的分辨率纹理。
    它主要解决两方面问题:一,闪烁,当屏幕上被渲染物体的表面与它所应用的纹理图像相比显得非常小时,就会出现闪烁。尤其当相机和物体在移动的时候,这种负面效果更容易被看到。二,性能问题,加载了大量的纹理数据之后,还要对其进行过滤处理(缩小),在屏幕上显示的只是一小部分。纹理越大,所造成的性能影响就越大。但同时它也会增加额外的内存,大约比原先多出1/3内存空间。

注:多级纹理使用步骤:1,使用glGenerateMipmap生成一组mipmap 2,设置好相应的过滤方式。


  • 代码示例
#include <GLTools.h>#include <GLShaderManager.h>#include <GLFrustum.h>#include <GLBatch.h>#include <GLFrame.h>#include <GLMatrixStack.h>#include <GLGeometryTransform.h>#ifdef __APPLE__#include <glut/glut.h>#else#define FREEGLUT_STATIC#include <GL/glut.h>#endif/*注释:如果gltReadTGABits读取失败,可以自己定义这个接口,具体的定义前面章节有*/GLShaderManager     shaderManager;          // Shader ManagerGLMatrixStack       modelViewMatrix;        // Modelview MatrixGLMatrixStack       projectionMatrix;       // Projection MatrixGLFrustum           viewFrustum;            // View FrustumGLGeometryTransform transformPipeline;      // Geometry Transform PipelineGLBatch             floorBatch;GLBatch             ceilingBatch;GLBatch             leftWallBatch;GLBatch             rightWallBatch;GLfloat             viewZ = -65.0f;// Texture objects#define TEXTURE_BRICK   0#define TEXTURE_FLOOR   1#define TEXTURE_CEILING 2#define TEXTURE_COUNT   3GLuint  textures[TEXTURE_COUNT];const char *szTextureFiles[TEXTURE_COUNT] = {    "/Users/app05/Desktop/opengl/brick.tga",    "/Users/app05/Desktop/opengl/floor.tga",    "/Users/app05/Desktop/opengl/ceiling.tga" };// 设置纹理过滤方式void ProcessMenu(int value){    GLfloat fLargest;    GLint iLoop;    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)    {        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);        switch(value)        {            //单纹理,远近调节时有明显闪烁不自然情况            case 0:                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);                break;            case 1:                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);                break;             //设置多级纹理的过滤方式(远模糊近清晰,有效避免闪烁情况)            case 2:                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);                break;            case 3:                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);                break;            case 4:                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);                break;            case 5:                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);                break;             //开启各向异性过滤(过滤时还考虑了观察的角度,效果最好方式,但也是最耗性能的)            case 6:                glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);                break;            //恢复为各向同性过滤(过滤时不考虑观察角度,默认垂直方向采样,如果是倾斜观察,这种模式下会丢失一些纹理信息)            case 7:                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);                break;        }    }    glutPostRedisplay();}void init(){    GLbyte *pBytes;    GLint iWidth, iHeight, iComponents;    GLenum eFormat;    GLint iLoop;    glClearColor(0.0f, 0.0f, 0.0f,1.0f);    shaderManager.InitializeStockShaders();    glGenTextures(TEXTURE_COUNT, textures);    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)    {        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);        pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight,                                &iComponents, &eFormat);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);        glGenerateMipmap(GL_TEXTURE_2D);//为纹理生成一组完整的mipmap,即多级纹理(分辨率递减的同一纹理)        free(pBytes);    }    //绘制地板几何图形    GLfloat z;    floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);    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();    //绘制天花板几何图形    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);    for(z = 60.0f; z >= 0.0f; z -=10.0f)    {        ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f);        ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);        ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f);        ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);        ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f);        ceilingBatch.Vertex3f(-10.0f, 10.0f, z);        ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);        ceilingBatch.Vertex3f(10.0f, 10.0f, z);    }    ceilingBatch.End();    //绘制左面墙几何图形    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);    for(z = 60.0f; z >= 0.0f; z -=10.0f)    {        leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);        leftWallBatch.Vertex3f(-10.0f, -10.0f, z);        leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);        leftWallBatch.Vertex3f(-10.0f, 10.0f, z);        leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);        leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);        leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);        leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);    }    leftWallBatch.End();    //绘制右面墙几何图形    rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);    for(z = 60.0f; z >= 0.0f; z -=10.0f)    {        rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);        rightWallBatch.Vertex3f(10.0f, -10.0f, z);        rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);        rightWallBatch.Vertex3f(10.0f, 10.0f, z);        rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);        rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);        rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);        rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);    }    rightWallBatch.End();}//退出,删除纹理对象void ShutdownRC(void){    glDeleteTextures(TEXTURE_COUNT, textures);}//前后移动视口void SpecialKeys(int key, int x, int y){    if(key == GLUT_KEY_UP)        viewZ += 0.5f;    if(key == GLUT_KEY_DOWN)        viewZ -= 0.5f;    glutPostRedisplay();}void ChangeSize(int w, int h){    GLfloat fAspect;    if(h == 0)        h = 1;    glViewport(0, 0, w, h);    fAspect = (GLfloat)w/(GLfloat)h;    viewFrustum.SetPerspective(80.0f,fAspect,1.0,120.0);    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);}//绘制场景void RenderScene(void){    glClear(GL_COLOR_BUFFER_BIT);    modelViewMatrix.PushMatrix();    modelViewMatrix.Translate(0.0f, 0.0f, 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();}int main(int argc, char *argv[]){    gltSetWorkingDirectory(argv[0]);    glutInit(&argc, argv);    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);    glutInitWindowSize(800, 600);    glutCreateWindow("Anisotropic 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;    }    init();    glutMainLoop();    ShutdownRC();    return 0;}

这里写图片描述

0 0
原创粉丝点击