OpenGL ES---纹理

纹理是什么

 纹理(TEXTURE),即物体表面的样子。在计算机的世界中,我们能够绘制的仅仅是一些非常基础的形状,比如点、线、三角形,这些基础显然是无法将一个现实世界中的物体很好的描述在屏幕上的。通常我们通过纹理映射将物体表面图片贴到物体的几何图形上面,完成贴图的过程,将物体从现实世界中模拟到虚拟世界中。
 纹理的基础单元是纹素(Texel,即texture element或texture pixel的合成字),亦如屏幕的基础单元是像素。屏幕上有自己的坐标系,纹理也有,即纹理坐标,一个维度称为 s,另一个维度称为 t,其范围都在 [0,1]之间。纹理坐标上,是纹素。

纹理坐标

 如上图所示,在 OpenGL的二维世界中,本质上,纹理就是一个二维数组(图像数据),而纹素就是这个二维数组中的值。

纹理映射到屏幕

 接下来,首先我们讨论下图像数据是如何从纹理坐标下被投射到屏幕上的。

坐标映射

 上面我们就讲过纹理坐标系。两个维度,范围都在[0,1]之间。无论是使用纯色渲染,还是图片渲染,实际上都是在进行颜色渲染,最终,都需要将那块颜色映射到归一化坐标系中。而归一化坐标系中两个维度都是在[-1,1]之间。
 由于这种坐标系的不一致,就需要将纹理坐标系中的图片映射到归一化坐标系中。这里,首先我们会遇到两个问题:

  • 将纹理坐标系中的哪个区域块取出来进行映射。
  • 取出来的区域块又该如何如何对应到归一化坐标系中通过顶点定义的外形中。


    纹理坐标和归一化坐标的对应关系

 如上图所示,我们可以得到以下几点:

  • 要选取图片中的哪个区域是由我们通过纹理顶点坐标定义的。上图中,我们通过定义(0,0),(0,1),(1,1),(1,0),实际上选取了整个图片部分作为贴片。
  • 要进行贴图的部分定义好了,它所要贴到的地方,实际上和我们定义的顶点坐标按照定义顺序一一对应(映射)。即,我们定义的第一个纹理顶点坐标,对应我们定义的第一个顶点坐标。

 最终,我们可以得到:

屏幕上显示的图形

 为了明显起见,这里再给出一张图(改变顶点定义的顺序):

改变映射顺序后的结果
纹理过滤(Texture Filtering)

 纹理坐标和归一化坐标通常并不能实现一比一的映射关系,纹理可能会比归一化坐标系中的几何图形大,也可能更小。这样就带来了这样的问题:在不能实现一比一映射的时候,该如何在纹理坐标中采样显示到归一化坐标中。这就是纹理过滤,实际上是在处理放大和缩小纹理的操作。
 常见的过滤方式有两种:最邻近过滤和双线性过滤。
 对于最邻近过滤,顾名思义,是为每个片段选择最近的纹素;而双线性过滤,使用双线性插值平滑像素之间的过滤。如下图所示,显然线性过滤会有更好的效果,但是也会消耗更多的计算能力:

最邻近过滤和双线性过滤

 我们可以看到,对于双线性过滤这种方式,特别是在进行缩小采样的时候,当缩小比例过大,会丢掉很多的细节,因为不管这个比例如何,它只会选取周围的四个点(即四个纹理元素)。为了解决这样的问题,可以使用 MIP 贴图的方式解决。关于 MIP 更多信息可以参考这里

纹理环绕(Texture Wrapping)

 上面坐标中,我们指定的纹理坐标范围均是在 [0,1]之间,但是如果超出了这个范围, 此时刻,我们选择的纹理区域大于了实际图片大小,纹理区域空白部分该如何处理,就是纹理环绕问题。下图参考

纹理环绕模式

 综上,我们了解了纹理坐标及其映射。下面,我们可以进行实际地编码工作了。

在程序中使用纹理

 通常,我们在程序中使用纹理的步骤是这样的:

  1. 定义顶点以及渲染程序。其中,在 glsl 程序中使用的 attribute 、uniform、varying 区别可参考
    private static final String VERTEX_SHADER =
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "attribute vec2 a_texCoord;" +
                    "varying vec2 v_texCoord;" +
                    "void main() {" +
                    " gl_Position = uMVPMatrix * vPosition;" +
                    " v_texCoord = a_texCoord;" +
                    "}";
    private static final String FRAGMENT_SHADER =
            "precision mediump float;" +
                    "varying vec2 v_texCoord;" +
                    "uniform sampler2D s_texture;" +
                    "void main() {" +
                    " gl_FragColor = texture2D(s_texture, v_texCoord);" +
                    "}";

private static final float[] TEX_VERTEX = {   // in clockwise order:
            0, 1f,  // top left
            1f, 0,  // bottom right
            0, 0,  // bottom left
    };

private static final float[] VERTEX = {   // in counterclockwise order:
            -1, -1f, 0, // bottom left
            1, 1, 0,   // top right
            -1, 1, 0,  // top left
    };
  1. 加载图片,创建 texture 纹理,然后将图片指定在纹理上。
GLES20.glGenTextures(1, texNames, 0);
mTexName = texNames[0];
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),
                R.drawable.cat);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexName);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
  1. 指定纹理参数,主要包括纹理过滤和纹理环绕方式。
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
                GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
                GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
                GLES20.GL_MIRRORED_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
                GLES20.GL_MIRRORED_REPEAT);
  1. 为几何顶点指定相应的纹理坐标中的顶点
mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_texCoord");
GLES20.glEnableVertexAttribArray(mTexCoordHandle);
GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false, 0,
                mTexVertexBuffer);
  1. 绘制
 GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);

 完整代码MyRender.java
需要注意的一点,上述代码中我们定义的顺序。实际上,在计算机中图片都是原点在左上角,x轴向右延伸,y轴向下延伸,如下图所示。

小结

 本节中,我们对 OpenGL 中的纹理进行了解和应用。在现实世界中物体有太多的细节,纹理给我们提供了一种方式将这些细节通过图片的方式贴在屏幕上的几何物体上。这对于二维平面来说,从效果上来说可能不具有太多吸引力,因为我们的图片本来就是二维的,但是 OpenGL 也能对其进行一些变换(剪切、翻转、平移等等),而且这些变换是运行在 GPU 上。下面,我们将进入三维的世界。

参考链接
Texture Mapping
Texture Mapping
OPENGL ES 2.0:纹理
Mipmap
Textures objects and parameters

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

推荐阅读更多精彩内容

  • 前言 本文是关于OpenGL ES的系统性学习过程,记录了自己在学习OpenGL ES时的收获。这篇文章的目标是学...
    秦明Qinmin阅读 10,389评论 7 22
  • 1,纹理【1】什么是纹理:定义:在计算机图形学中,纹理既包括通常意义上物体表面的纹理。也就是我们土话所讲的使物体表...
    simple_0955阅读 631评论 0 1
  • 1 纹理基础 纹理是一种结构化的存储形式(Textures are a structured form of st...
    RichardJieChen阅读 15,669评论 0 9
  • 概述:纹理是一个用来保存图像的颜色元素值的OpenGL ES缓存。当把纹理应用到几何图形中后,会使渲染的场景显得更...
    HoFie阅读 928评论 0 1
  • 版本记录 前言 OpenGL 图形库项目中一直也没用过,最近也想学着使用这个图形库,感觉还是很有意思,也就自然想着...
    刀客传奇阅读 8,779评论 0 8