3.1、什么是纹理

纹理是一个用来保存图像的颜色元素值的OpenGLES缓存。图3-1显示的是本章例子中的一个纹理使用的一个图像。纹理可以使用任何图像,包括树木、面孔、砖块、云彩,或者机器。当把纹理;应用到几何图形中后,会使渲染的场景显得更自然,会使三角形的复杂组合像是真实的物体而不只是有颜色的面。

图 3-1

在纹理的缓存中保存的颜色值可能要耗费很多的内存。所有的嵌人式系统都为纹理设定了内存的最大尺寸限制。所有的iPhone和iPadTouch版本都可以支持由1024X1024像素的图像生成的纹理。iPad和最新一代iPhone、iPod Touch所支持的尺寸甚至更大。但是,由于嵌人式系统的可用内存相对较小,应尽量使用最小的图像来产生可以接受的渲染结果。

当用一个图像初始化一个纹理缓存之后,在这个图像中的每个像素变成了纹理中的一个纹素(texel)。 与像素类似,纹素保存颜色数据。像素和纹素之间的差别很微妙:像素通常表示计算机屏幕上的一个实际的颜色点,因此,像素通常被用来作为一个测量单位。说一个图像有256像素宽,256 像素高是正确的。与此相反,纹素存在于一个虚拟的没有尺寸的数学坐标系中。图3-2显示了OpenGL ES纹理坐标系中的一个纹理。

图 3-2

纹理坐标系有一个命名为S和T的2D轴。在一个纹理中无论有多少个纹素,纹理的尺寸永远是在S轴上从0.0到1.0,在T轴上从0.0到1.0。 从一个1像素高64像素宽的图像初始化来的纹 理会沿着整个T轴有1纹素,沿着S轴有64纹素。


注意

本书中的例子使用的是2D纹理,但是一些OpenGL实现还会支持ID和3D纹理。一个1D的纹理就相当于沿着T轴只有1纹素的2D纹理,因此一个64纹素的ID纹理与从尺寸为64X1的图像初始化来的2D纹理是相同的。3D纹理就像一个层饼,一个在拥有R、S和T轴的坐标系中沿着R轴堆叠的多个2D纹理的层饼。1D和3D纹理对于某些特定的应用来说是非常方便的,但是2D纹理是迄今为止最常见的。


3.1.1 对齐纹理和几何图形

我们需要告诉OpenGL ES如何使用一个纹理来给几何图形对象着色。图3-3显示的是第2章例子中的简单三角形,但是这次它是用一个纹理绘制的。在图3-3中需要注意的第一件事是绘制的三角形的高度要比宽度大。这个三角形是用{-0.5f,-0.5f,0.0}、 {0.5f,-0.5f,0.0}、 {-0.5f,0.5f,0.0}这三个顶点定义的,这使得三角形的高度和宽度在纯数学的OpenGLES坐标系中是相等的。但是这个例子的帧缓存是按像素来匹配屏幕尺寸的。在渲染时,GPU会转换纯数学OpenGL ES坐标系中的每个顶点的X、Y、Z坐标为帧缓存中所对应的真实像素位置。帧缓存中的像素位置叫做视口(viewport) 坐标。第2章曾简短地提到过视口。转换为视口坐标的结果是所有绘制的几何图形都被拉伸以适合屏幕大小,也就是说高比宽大了。第5章会讲解怎么控制GPU的这个转换。

图 3-3

注意

一个场景中的每个几何坐标的转换都要耗费一打的矢量数学运算,但是GPU经常会在每秒执行10亿次矢量运算。与内存读取相比这个转换是如此之快,以至于这个转换在实际的应用中几乎不会产生性能影响。


在每个顶点的X、Y、Z坐标被转换成视口坐标后,GPU会设置转换生成的三角形内的每个像素的颜色。转换几何形状数据为帧缓存中的颜色像素的渲染步骤叫做点阵化(rasterizing), 每个颜色像素叫做片元( fragment)。当OpenGL ES没有使用纹理时,GPU会根据包含该片元的对象的顶点的颜色来计算每个片元的颜色。当设置了使用纹理后,GPU会根据在当前绑定的纹理缓存中的纹素来计算每个片元的颜色。

程序需要指定怎么对齐纹理和顶点,以便让GPU知道每个片元的颜色由哪些纹素决定。这个对齐又叫做映射(mapping),是通过扩展为每个顶点保存的数据来实现的:除了X、Y、Z坐标,每个顶点还给出了U和V坐标值。每个U坐标会映射顶点在视口中的最终位置到纹理中的沿着S轴的一个位置。V坐标映射到T轴。图3-4形象化了3.2节将介绍的OpenGLES_Ch3_1例子中演示的纹理映射。

图 3-4

3.1.2纹理的取样模式

每个顶点的U和V坐标会附加到每个顶点在视口坐标中的最终位置。然后GPU会根据计算出来的每个片元的U、V位置从绑定的纹理中选择纹素。这个选择过程叫做取样(Sampling)。取样会把纹理的S和T坐标系与每个渲染的三角形的顶点的U、V坐 标匹配起来。如图3-4所示,在S和T坐标系中与{0,0}位置最近的纹素会被映射到拥有{0, 0}的U、v坐标的顶点所对应的片元上。每个随后的片元位置对应于一个沿着S和T轴的与该片元在U、V坐标中的位置等比例的位置。例如,一个U、V坐标为 {0.5,0,5}的片元会被当前绑定的纹理中最接近中间位置的纹素所着色。


注意 {S,T}坐标和{U,V}坐标通常是由程序员和3D设计师设定的。两者之间只有一个实际的差异: {U,V} 坐标可能会超出0.0到1.0的这个范围。栅格化会基于一个本节后面要介绍的可配置的“循环模式”映射{s, T}坐标为超出0.0到1.0范 围的{U,V}坐标。


渲染过程中的取样可能会导致纹理被拉伸、压缩,甚至翻转。例子OpenGLES_Ch3_3会演示一些可能会产生的纹理变形。

OpenGL ES支持多个不同的取样模式:考虑一下当一个三角形产生的片元少于绑定的纹理内的可用纹素的数量时会发生什么。一个拥有大量纹素的纹理被映射到帧缓存内的一个只覆盖几个像素的三角形中,这种情况会在任何时间发生。相反的情况也会发生。一个包含少量纹素的纹理可能会被映射到一个在帧缓存中产生很多个片元的三角形。程序会使用如下的glTexParameteri()函数来配置每个绑定的纹理,以便使OpenGLES知道怎么处理可用纹素的数量与需要被着色的片元的数量之间的不匹配。


g1TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN _FILTER, GL_NEAREST);
g1TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

g1TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

使用值GL_LINEAR来指定参数GL_TEXTURE_MIN_FILTER 会告诉OpenGL ES无论何时出现多个纹素对应-一个片元时,从相配的多个纹素中取样颜色,然后使用线性内插法来混合这些颜色以得到片元的颜色。产生的片元颜色可能最终是一一个纹理中不存在的颜色。例如,一个纹理是由交替的黑色和白色纹素组成的,线性取样会混合纹素的颜色,因此片元最终会是灰色的。使用GL NEAREST值来指定GL_TEXTURE_MIN_FILTER参数会产生一个不同的结果。与片元的U、V坐标最接近的纹素的颜色会被取样。如果一个纹理是由交替的黑色和白色纹素组成的,GLNEAREST取样模式会拾取其中的一个纹素或者另一个,并且最终的片元要么是白色的,要么是黑色的。下一节(包括图3-5)会展示线性插值和最邻近差值取样模式之间的效果对比。

glTexParameteri()的GL_TEXTURE_MAG_FILTER 参数用于在没有足够的可用纹素来唯一性地映射-一个或者多个纹素到每个片元上时配置取样。在这种情况下,GL_LINEAR值会告诉OpenGLES混合附近纹素的颜色来计算片元的颜色。GL_LINEAR值会有一个放大纹理的效果,并会让它模糊地出现在渲染的三角形上。GL_TEXTURE_MAGFILTER的GL_NEAREST值仅仅会拾取与片元的U、V位置接近的纹素的颜色,并放大纹理,这会使它有点像素化地出现在渲染的三角形上。

除了减小和放大过滤选项,当U、V坐标的值小于0或者大于1时,程序会指定要发生什么。有两个选择,要么尽可能多地重复纹理以填满映射到几何图形的整个U、V区域,要么每当片元的U、V坐标的值超出纹理的S、T坐标系的范围时,取样纹理边 缘的纹素。纹理的循环模式是为S和T轴分别设置的,参考下面的代码:


glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_ S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_ s, GL_REPEAT);

glTexParameteri(GL_TEXTURB_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
g1TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

本章的例子OpenGLESCh3_3会演示一些由这些纹理参数值产生的效果。

3.1.3

MIP贴图MIP贴图是与取样密切相关的。根据维基百科, MIP代表拉丁短语Multum In Parvo,意思是“ 放置很多东西的小空间”。回忆一下,内存存取是现代图形处理的薄弱环节。当有多个纹素对应一个片元时,线性取样会导致GPU仅仅为了计算一个片元的最终颜色而读取多个纹素的颜色值。MIP贴图是一个为纹理存储多个细节级别的技术。高细节的纹理会沿着S轴和T轴存储很多的纹素。低细节的纹理沿着每个轴存储很少的纹素。最低细节的纹理只保存- -个纹素。多个细节级别增加了在S、T轴上的纹素和每个片元的U、V坐标之间有紧密的对应关系的可能性。当存在一个紧密的对应关系时,GPU会减少取样纹素的数量,进而会减少内存访问的次数。

使用MIP贴图通常会通过减少GPU取样的数量来提高渲染的性能,但是MIP贴图使每个纹理所需要的内存增加了1/3, 在网页http://en.wikipedia.org/wiki/Mipmap上做了解释。在iOS设备上,内存限制可能优先于渲染性能。通常最好的策略是逐个在使用和不使用MIP贴图的情况下测试你的应用,以决定哪种方式的效果最好。

results matching ""

    No results matching ""