Mip贴图

什么是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表示常规的纹理过滤(各向同性过滤)。各向异性过滤,是会增加额外的工作,包括其他纹理单元,很可能对性能造成影响。但是,在现代硬件上,应用这个特性对速度造成影响不大。最重要的是,目前它已经成为流行游戏、动画和模拟程序的一个标准特性。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352