Mip贴图

作者: 君幸食j | 来源:发表于2020-08-28 13:41 被阅读0次

    什么是Mip贴图?

    Mip贴图是一种功能强大的纹理技巧,它可以提高渲染性能同时可以改善场景的显示质量。

    想象一下,假设我们有一个包含着上千物体的大房间,每个物体上都有纹理。有些物体会很远,但其纹理与近处的物体同样高的分辨率。由于远处的物体可能只产生很少的片段,OpenGL从高分辨率纹理中为这些片段获取正确的颜色值就很困难,因为它需要对一个跨过纹理很大部分的片段只拾取一个纹理颜色。在小物体上这会产生不真实的感觉,更不用说它们使用高分辨率纹理浪费内存的问题了。

    OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题,它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。同时,多级渐远纹理的性能非常好,如下图: 1.png

    手工为每个纹理图像创建一系列多级渐远纹理很麻烦,幸好OpenGL有一个glGenerateMipmaps函数,在创建完一个纹理后调用它,就会承担接下来的所有工作。

    常见问题

    • 闪烁问题,当屏幕上被渲染物体的表面与它所应用的纹理图像相比显得非常小时,就会出现闪烁效果。类似闪光,当纹理图像采样区域的移动幅度与它在屏幕大小相比显得不成比例时,也会发生这种现象。处于运动状态时,会比较容易看到闪烁的负面效果。
    • 性能问题,加载大的纹理内存并对它们进行过滤处理,但屏幕上实际只是显示很少的一部分片段。纹理越大,这个问题所造成的性能影响也就越明显。

    这两种问题,可以用很简单的方法解决,就是使用更小的纹理图像。但是这种方法又产生一个新的问题,就是当一个物体更靠近观察者时,它必须渲染的比原来更大一些,这样纹理就会被拉伸,形成模糊的视觉效果或斑驳状的纹理化效果。从根本上解决问题,就是使用Mip贴图。不是单纯的把单个图像加载到纹理状态中,而是把一系列从最大到最小的图像加载到单个“Mip贴图”纹理状态。然后,OpenGL使用一组新的过滤模式,为一个特定的几何图形选择具有最佳过滤效果的纹理。

    Mip纹理由一系列纹理图像组成,每个图像的大小在每个轴的方向上都缩小一半,或者是原来图像像素的四分之一。Mip贴图的每个图像大小都依次减半,直到最后一个图像大小为 1*1的纹理单元为止。


    2.png

    使用glTexParameteri()函数时,用到level参数,它指定图像数据用于哪个mip层。第一层是0,后面依次类推。如果未使用Mip贴图,就只加载第0层。默认情况下,为了使用Mip贴图,mip层都要被加载,可以设置GL_TEXTURE_BASE_LEVELGL_TEXTURE_MAX_LEVEL纹理参数使用基层和最大层。

    //设置mip贴图基层
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVEL,0);
    
    //设置mip贴图最大层
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,0);
    

    虽然可以通过设置GL_TEXTURE_BASE_LEVELGL_TEXTURE_MAX_LEVEL纹理参数控制哪些mip层被加载。但仍然可以使用GL_TEXTURE_MIN_LODGL_TEXTURE_MAX_LOD参数限制已加载的mip层使用范围。

    什么时候生成Mip贴图

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

    • GL_NEAREST_MIPMAP_NEAREST具有非常好的性能,并且闪烁现象很弱。
    • GL_LINEAR_MIPMAP_NEAREST常用于对游戏加速,它使用高质量的线性过滤器。
    • GL_NEAREST_MIPMAP_LINEAR过滤器在Mip层之间执行了一些额外的插值,以消除它们之间的过滤痕迹。
    • GL_LINEAR_MIPMAP_LINEAR三线性Mip贴图。纹理过滤的黄金准则,具有最高的精度。
    if(minFilter == GL_NEAREST_MIPMAP_NEAREST ||
    minFilter == GL_LINEAR_MIPMAP_NEAREST ||
    minFilter == GL_NEAREST_MIPMAP_LINEAR ||
    minFilter == GL_LINEAR_MIPMAP_LINEAR)
    
    //纹理生成所有Mip层
    //参数:GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D
    glGenerateMipmap(GL_TEXTURE_2D); 
    

    glGenerateMipmap 函数解析

    目的:为纹理对象生成一组完整的mipmap 
    void glGenerateMipmap (GLenum target);
    
    参数:将生成mipmap的纹理对象绑定到纹理目标。GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
    
    描述:glGenerateMipmap计算从零级数组派生的一组完整的mipmap数组。无论先前的内容如何,最多包括1x1维度纹理图像的数组级别都将替换为派生数组。零级纹理图像保持不变(原图)。
    
    派生的mipmap数组的内部格式都与零级纹理图像的内部格式相匹配。通过将零级纹理图像的宽度和高度减半来计算派生数组的尺寸,然后将每个阵列级别的尺寸减半,直到达到1x1尺寸纹理图像。
    

    Mip贴图过滤

    3.png

    一个常见的错误是将放大过滤的选项设置为多级渐远纹理过滤选项之一,这样是没有任何效果的,因为多级渐远纹理主要是使用在纹理被缩小的情况下的:纹理放大不会使用多级渐远纹理,为放大过滤设置多级渐远纹理的选项会产生一个 GL_INVALID_ENUM 错误代码。

    //GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST (最邻近 
    过滤)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
    //GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR (线性过滤
    )
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    //GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_NEAREST (选择最邻近的Mip层,k执行最邻近过滤)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
    
    
    //GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR (在Mip层之间执行线性插补,并执行最邻近过滤)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GGL_NEAREST_MIPMAP_LINEAR);
    
    //GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR (选择最邻近Mip层,并执行线过滤)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
    
    //GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR_MIPMAP_LINEAR (在MipM之间执行线性插补,并执行线性过滤,又称为三线性过滤) 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    

    各向异性过滤

    各向异性纹理过滤(Anisotropic texture filtering) 并不是OpenGL核心规范中的一部分,但它是一种得到广泛使用的扩展,可以极大提高纹理过滤操作的质量。

    2种基本过滤,最邻近过滤(GL_NEAREST) 和 线性过滤 (GL_LINEAR)。当一个纹理贴图被过滤时,OpenGL使用纹理坐标来判断一个特定的几何片段将落在纹理的什么地方。然后,紧邻这个位置的纹理使用GL_NEAREST和GL_LINEAR过滤操作进行采样。

    当几何图形进行纹理贴图时,如果它的观察方向和观察点怡好垂直,那么这个过程是相当完的。如下图:


    4.png

    当我们从一个角度倾斜地观察这个几何图形时,对周围纹理单元进行常规采样,会导致一些纹理信息丟失(看上去显得模糊)。为了更加逼真和准确的采样应该沿著包含纹理的平面方向进行延伸。如果我们进行处理纹理过滤时,考虑了观察角度,那么这个过滤方法就叫“各向异性过滤”。在Mip贴图纹理过滤模型中,或者其它所有的基本纹理过滤我们都可以应用各向异性过滤。

    应用各向异性过滤,需要2个步骠

    • 第一,查询得到支持的各向异性过滤的最大数量,可以使用 glGetFloatv 函数,GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 参数。
    GLfloat flargest;
    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISCTROPY_EXT, &fLargest);
    
    • 第二,我们可以使用 glTexParameter 函数以及GL_TEXTURE_MAX_ANISOTROPY_EXT,设置各向异性过滤数据。
    //设置纹理参数(各向异性采样)
    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,flargest);
    
    //设置各向同性过滤,数量为1.0表示(各向同性采样)
    glTexParameterf(glTexParameterf, GL_TEXTURE_MAX_ANISOTROPY_EXT,1.0f); 
    

    注意:
    各向异性过滤所应用的数量越大,沿著最大变化方向(沿最强的观察点)所采样的纹理单元就越多。值1.0表示常规的纹理过滤(各向同性过滤)。各向异性过滤,是会增加额外的工作,包括其他纹理单元,很可能对性能造成影响。但是,在现代硬件上,应用这个特性对速度造成影响不大。最重要的是,目前它已经成为流行游戏、动画和模拟程序的一个标准特性。

    相关文章

      网友评论

          本文标题:Mip贴图

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