一、Texture 存在的原因。
我们绘制物体是通过顶点组成图元然后转换成像素片段然后着色绘制而成的。如果我们由顶点上指定的颜色来绘制物体,那么一个颜色丰富的物体需要大量的顶点才能表达。这时候Texture就出来了。Texture 是一个2D的图片,通过他我们能用少量的顶点绘制更加颜色丰富的图元了。使用Texture我们需要在顶点数据中同时指定顶点对应的纹理坐标(x,y 的2D坐标值)。在OpenGL绘制时在片段着色器中通过对Texture采样赋予片段颜色。
在实际应用中,Texture 除了用于做物体贴图的上色上。还可以承载图元片段很多其它信息,比如每个片段的法向量,每个片段的光照属性等。所以我们常常也听到 法向量贴图,光照贴图,金属贴图等。
二、纹理绘制
2.1 纹理坐标,纹理坐标是 0 - 1 的范围。原点在左下角。如下图所示。
当遇到一个大的区域需要用小的纹理去填充时,一般有两种方案,
1、纹理平铺填充。
当平铺的时候纹理坐标就会超出0-1 的范围,超出的坐标最终会最终映射回0-1的坐标范围(方法就是直接忽略纹理坐标的整数部分)。而超出的坐标如何映射回0-1的纹理坐标我们称之为环绕。OpenGL为我们提供了几种超出的环绕方式如下图:
效果如下
2、纹理缩放填充。
由于纹理坐标独立于屏幕坐标。所以我们能将大分辨率的片段用小分辨率的纹理去填充,那么就存在一个问题如何用小的纹理填充到大分辨率的片段上呢?由于我们显示器显示是通过一个一个很小的像素格子显示不同颜色来表达的。如果像素片段的格子数量和纹理的格子数量不同的的情况下就存在一个采样如何抉择的问题了。这个采样的方式我们称之为纹理过滤方案。
我们常见的方案有两种
1、GL_NEAREST 邻近过滤,取像素最近的颜色值
2、GL_LINEAR线性过滤,取像素邻近的几个像素颜色值的平均值。
这两种方案在同一个图片使用的效果如下图:
通过上图我们可以看出来两个方案的优缺点。
1、GL_NEAREST 邻近取色的方案保证了原图的原色输出。 但是存在像素跳格的问题,导致存在相邻的像素衔接不平滑而存在锯齿效果。
2、GL_LINEAR 线性方案,我们保证了颜色的衔接是平滑的。但是由于一直对颜色做均值处理。所以图片整体颜色值被均值冲淡了。上图的黄色和蓝色黑色都比原图浅了。而且也感觉变模糊了。(其实我们后面做模糊效果的时候也有用这种线性均值颜色的方法实现图片的模糊处理)。
所以我们在项目中也需要根据实际情况选择适合我们的方案。发扬优点忍受缺点。
我们知道了过滤的方法了,那么我们就要区分两种缩放情况设置对应的过滤方案了
1、在3D空间中存在的物体分为远近两种情况,同一个分辨的纹理图片在物体远和近的情况下,纹理片段采样的大小是不同的。远处的片段只会产生很少的片段,如果我们还在一个很大分辨率的纹理上采样那我们需要跨度很大的纹理上计算采样的颜色值,这样不仅计算量大而且颜色也会不真实。。这种情况我们在OpenGL中有个方案叫做多级渐远纹理的方案,他会将纹理生成多个级别大小的纹理,每个级别纹理是之前级别的二分之一的大小。这样根据远近我们可以选择适合级别的纹理采样。下图就是一个多级渐远图片的实例:
针对多级渐远的情况下我们纹理采样有如下4种方案:
1. GL_NEAREST_MIPMAP_NEAREST 使用最接近级别的纹理图片采样,并在纹理中选择最节点纹理坐标的颜色值。
2.GL_LINEAR_MIPMAP_NEAREST 使用最接近级别的纹理图片采样,并在纹理中选择最接近的几个纹理坐标取线性插值。
3.GL_NEAREST_MIPMAP_LINEAR 取最接近两个级别的纹理图片。将两个图片的像素线性插值后,再选择其中最接近的纹理坐标的颜色。比如显示为 6x6 的片段,会选择8x8 和 4x4两个级别的纹理图片线性插值生成一个片段,然后再从生成的片段选择最接近坐标的纹理坐标的颜色值。
4.GL_LINEAR_MIPMAP_LINEAR 取最接近两个级别的纹理图片。将两个图片的像素线性均值后,再将纹理坐标邻近的几个像素值取线性均值。比如显示为 6x6 的片段,会选择8x8 和 4x4两个级别的纹理图片线性插值生成一个片段,然后再从生成的片段选择邻近的几个像素坐标的颜色值取线性插值。
在记忆这四个方案的时候可以分割成两段来记忆,GL_纹理取颜色方案_MIPMAP_渐远纹理取样方案。
2、当将小的纹理映射到一个大的像素片段上时我们用的两个方案,GL_NEAREST,GL_LINEAR 原理就是之前说的。
三、纹理的更多应用
由于纹理能用少量顶点给图形赋予更丰富的色彩,同样的我们顶点着色器,片段着色器中,对每个顶点,每个片段需要的其它非颜色信息也可以通过纹理来传递。这样能在有限顶点的情况下描述更加复杂的物体了。比如我们用法线纹理,将四个顶点描述的平面法线变得更加丰富,这样计算光照信息时候光照能在4个顶点描述的平时上计算出凹凸不平的光照效果。比如材质纹理,我们能将片段各个位置的感光细节表达得更加得丰富。等等各种各样的纹理应用就是利用了纹理采样的方法将片段上的各种细节以纹理的方式描述让OpenGL绘制出更加丰富多彩的物体。