OpenGL纹理详解(上)

写在前面的话

现实生活中,纹理最通常的作用是装饰我们的物体模型,它就像是贴纸一样贴在物体表面,使得物体表面拥有图案。但实际上在OpenGL中,纹理的作用不仅限于此,它可以用来存储大量的数据,一个典型的例子就是利用纹理存储地形信息。

纹理对象和参数

         现代OpenGL中,纹理对象和顶点数组对象(VAO)及缓存对象(VBO)一样,需要调用glGenTextures函数生成。

生成纹理对象

        同样的,纹理对象需要进行绑定。OpenGL中纹理可以分为1D,2D和3D纹理,我们在绑定纹理对象的时候需要指定纹理的种类。由于本文将以一张图片为例,因此我们为我们的纹理对象绑定一个GL_TEXTURE_2D的纹理。

2D纹理绑定

纹理坐标

         在OpenGL中,我们通常将纹理中的像素将按照纹理坐标进行编址,纹理坐标系是一个空间直角坐标系,横轴为S轴,纵轴为T轴,垂直于屏幕的坐标轴为R轴。在我们的2D纹理中,由于没有R轴,我们也可以将横轴称为U 纵轴称为V轴,也就是我们所说的UV坐标系。但和OpenGL坐标系所不同的是:纹理坐标系的(0,0)点位于纹理的左下角,而(1,1)点位于纹理的右上角。

 2D纹理坐标系

采样

        通过纹理坐标获取像素颜色信息的过程称为采样,而采样的结果会根据纹理参数设置的不同而千差万别。OpenGL中设置纹理参数的API接口为glTextureParameter,我们所有的纹理参数都由这个接口设置,下面我们介绍几种常用的纹理参数的配置。

Wrapping

        纹理坐标的范围与OpenGL的屏幕坐标范围一样,是0-1。超出这一范围的坐标将被OpenGL根据GL_TEXTURE_WRAP参数的值进行处理:

GL_REPEAT: 超出纹理范围的坐标整数部分被忽略,形成重复效果。

GL_MIRRORED_REPEAT: 超出纹理范围的坐标整数部分被忽略,但当整数部分为奇数时进行取反,形成镜像效果。

GL_CLAMP_TO_EDGE:超出纹理范围的坐标被截取成0和1,形成纹理边缘延伸的效果。

GL_CLAMP_TO_BORDER: 超出纹理范围的部分被设置为边缘色。

       这四种模式所产生的纹理效果如下:

2D纹理的4种wrapping模式

      我们可以为纹理坐标系中每条坐标轴设定不同的wrapping模式,例如这里我们将S和T轴的wrapping模式设定为GL_REPEAT:

wrapping模式的设置

         需要注意的是,如果我们将wrapping模式设置为GL_CLAMP_TO_BORDER,我们需要单独设置另一属性----边界颜色,具体方法也是利用glTextureParameter方法,只不过将属性名称替换为GL_TEXTURE_BORDER_COLOR:

纹理边界颜色的设置

这两行代码执行后,纹理的边界颜色将被设置为红色。

过滤

        由于纹理坐标和我们当前的屏幕分辨率是无关的,所以当我们为一个模型贴纹理时,往往会遇到纹理尺寸与模型尺寸不符的情况,这时,纹理会因为缩放而失真。处理这一失真的过程我们称为过滤,在OpenGL中我们有如下几种常用的过滤手段:

GL_NEAREST: 最临近过滤,获得最靠近纹理坐标点的像素。

GL_LINEAR: 线性插值过滤,获取坐标点附近4个像素的加权平均值。

GL_NEAREST_MIPMAP_NEAREST:用于mipmap,下节将详细介绍。

GL_LINEAR_MIPMAP_NEAREST:

GL_NEAREST_MIPMAP_LINEAR:

GL_LINEAR_MIPMAP_LINEAR:

         在我们讨论mipmap之前,我们来看看前两种过滤算法在纹理图像面前会产生怎样的过滤效果(原始图片大小和模型大小相差16倍):

两种插值过滤算法过滤效果

        从这里我们可以看出,线性插值算法的过滤效果似乎更加平滑,但并不表示这种算法适合所有的场合,如果我们需要对图像进行马赛克处理或模拟一个8位游戏机的游戏画面时,最临近过滤算法是最好的选择。

        我们可以单独为纹理缩放指定不同的过滤算法,这两种情况下纹理参数设置分别对应为:GL_TEXTURE_MIN_FILTER和GL_TEXTURE_MAG_FILTER.

分别为纹理缩放指定线性过滤算法 

Mipmaps

          正如前面所提到的,还有一种过滤纹理的方法---mipmaps。如下图所示: Mipmaps 将纹理按照1/2的比例缩小并生成副本,以此类推直到纹理只有1x1大小(这里是纹理坐标,不是真实像素大小)。采样时我们根据当前缩小比率来选择合适大小的纹理,按照线性过滤或最邻近过滤来采样。比如,我们要用做贴图的纹理大小为 64x32,对它做下采样生成32x16,16x8,8x4,4x2,2x1,1x1的纹理,如果要渲染的区域大小为14x6,那么我们要么选16x8的纹理,要么选16x8与8x4的两块纹理做加权平均。

Mipmaps实例

         Mipmaps是一个功能强大的纹理技术,它可以提高渲染的性能以及提升场景的视觉质量。它可以用来解决使用一般的纹理贴图会出现的两个常见的问题:

1.  闪烁,当屏幕上被渲染区域与它所应用的纹理图像相比显得非常小时,就会出现闪烁。尤其当视口和物体在移动的时候,这种负面效果更容易被看到。

2. 性能问题。如果我们的贴纹理的区域离我们非常远,远到在屏幕中只有一个像素那么大小时,纹理的所有纹素都集中在这一像素中。这时,我们无论做邻近过滤还是做线性过滤时都不得不将纹理的所有纹素计算在内,这种计算效率将大大影响我们的采样效率,而纹理的数据量越大,对效率的影响就会更大。

         使用Mipmaps技术就可以解决上面那两个问题。当加载纹理的同时预处理生成一系列从大到小的纹理,使用时只需选择合适大小的纹理加载就行了。这样虽然会增加一些额外的内存(一个正方形纹理将额外占用约30%的内存),但将大大提高了我们的采样效率和采样质量。

        生成mipmaps的过程很简单,只需要在加载纹理后执行下面一行代码:

 生成mipmaps

       使用mipmaps也很简单,只需设置过滤参数为以下4种中的任意一种:

GL_NEAREST_MIPMAP_NEAREST:选择最邻近的mip层,并使用最邻近过滤。

GL_NEAREST_MIPMAP_LINEAR:对两个mip层使用最邻近过滤后的采样结果进行加权平均。

GL_LINEAR_MIPMAP_NEAREST:选择最邻近的mip层,使用线性插值算法进行过滤。

GL_LINEAR_MIPMAP_LINEAR:对两个mip层使用线性插值过滤后的采样结果进行加权平均,又称三线性mipmap。

        在选择这几种过滤方法时,我们需要考虑的是效率和质量,线性过滤往往更加平滑,但随之而来的是更多的采样次数;而临近过滤减少了采样次数,但最终视觉效果会比较差。

         到这里,我们的纹理单元已生成完毕,纹理参数也已配置就绪,在下一篇中,我们将继续讨论如何加载和使用纹理的问题。

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

推荐阅读更多精彩内容

  • 版本记录 前言 OpenGL 图形库项目中一直也没用过,最近也想学着使用这个图形库,感觉还是很有意思,也就自然想着...
    刀客传奇阅读 8,768评论 0 8
  • http://blog.csdn.net/wangdingqiaoit/article/details/51457...
    jerryhigh阅读 5,291评论 0 8
  • 纹理(Textures) 我们已经了解到,我们可以为每个顶点使用颜色来增加图形的细节,从而创建出有趣的图像。但是通...
    IceMJ阅读 5,616评论 2 13
  • 纹理的基础知识 2D 纹理 2d纹理是OpenGlES中最基础和普遍的一种纹理结构。一个2d纹理,就是图片的数据的...
    Zsj_Sky阅读 5,361评论 0 8
  • 现在生活又开始有些混乱,很多事情不知道怎么解,不知道自己做的是对是错,好希望能有一个类似解忧杂货店的地方,帮我解决烦恼
    猫头鹰TWO阅读 217评论 0 0