内容引自《Real Time Rendering 3rd》
在计算机图形学中,纹理贴图是使用图像、函数或其他数据源来改变物体表面外观的技术。例如,可以将一幅砖墙的彩色图像应用到一个多边形上,而不用对砖墙的几何形状进行精确表示。当观察这个多边形的时候,这张彩色图像就出现在多边形所在位置上。只要观察者不接近这面墙,就不会注意到其中几何细节的不足(比如其实砖块和砂浆的图像是显示在光滑的表面上的事实)。通过这种方式将图像和物体表面结合起来,可以在建模、存储空间和速度方面节省很多资源。
纹理(Texturing)是一种针对物体表面属性进行“建模”的高效技术。图像纹理中的像素通常被称为纹素(Texels),区别于屏幕上的像素。通过将投影方程(projector function)运用于空间中的点 ,从而得到一组称为参数空间值(parameter-spacevalues)的关于纹理的数值,再使用一个或者多个映射函数(corresponder function)将参数空间值(parameter-space values )转换到纹理空间。这个过程就称为贴图(Mapping,也称映射 ),也就是纹理贴图(Texture Mapping,也称纹理映射 )。
将2D图像上的每一点精确对应到3D模型物体表面,在点与点之间的间隙位置进行图像光滑插值处理,这就是UV mapping。
下面是对上图中描述的纹理管线的分步概述:
具体的例子:找到物体空间中的位置(x,y,z),比如点(-2.3,7.1,88.2),然后对该位置运用投影函数。这个投影函数通常将向量(x,y,z)转换为一个二元向量(u,v)。在此示例中使用的投影函数是一个正交投影,类似一个投影仪,将具有光泽的砖墙图像投影到多边形表面上。再考虑砖墙这边,其实这个投影过程就是将砖墙平面上的点变换为值域为0到1之间的一对(u,v)值,如图,(0.32,0.29)就是这个我们通过投影函数得到的uv值。而我们图像的分辨率是256 x 256,所以,将256分别乘以(0.32,0.29),去掉小数点,得到纹理坐标(81, 74)。通过这个纹理坐标,可以在纹理贴图上查找到坐标对应的颜色值,所以,我们接着找到砖块图像上像素位置为(81,74)处的点,得到颜色(0.9,0.8,0.7)。而由于原始砖墙的颜色太暗,因此可以使用一个值变换函数,给每个向量乘以1.1,就可以得到我们纹理管线过程的结果——颜色值(0.99,0.88,0.77)。
投影函数(projector function)的功能就是将空间中的三维点转化为纹理坐标,也就是获取表面的位置并将其投影到参数空间中。
在常规情况下,在美术建模过程中,已经投影结果把存储在模型顶点数据中。
各种常见投影的不同要点:
映射函数(The Corresponder Function)的作用是将参数空间坐标(parameter-space coordinates)转换为纹理空间位置(texture space locations)。
我们知道图像会出现在物体表面的(u,v)位置上,且uv值的正常范围在[0,1)范围内。超出这个值域的纹理,其显示方式便可以由映射函数(The Corresponder Function)来决定。
贴图间的拼接模式
在OpenGL中,这类映射函数称为“封装模式(Warapping Mode)”,在Direct3D中,这类函数叫做“寻址模式(Texture Addressing Mode)”。最常见的映射函数有以下几种:
重复寻址模式(wrap):
假设我们要创建一个正方形图元,并将纹理坐标声明为(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。这时,如果我们设置了重复寻址模式,就可以使纹理在U、V方向都重复三次。
镜像寻址模式(mirror):
在我们创建一个正方形图元,为坐标为(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。我们设置镜像纹理寻址模式,纹理在U、V方向都重复了三次,并且每一行、每一列都与相邻的行和列成镜像关系。
夹取寻址模式(clamp to edge):
创建一个正方形图元,纹理地址分配为(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。这时,设置夹取纹理寻址模式,纹理将只使用一次,并且最顶一行和最后一列上的像素颜色会一直延伸到图元的最顶端和最右段。
边框颜色寻址模式(clamp to border):
创建一个正方形图元,纹理地址分配为(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。这时,设置夹取纹理寻址模式,纹理将只使用一次,并且在纹理坐标超过范围的地方使用一个任意的颜色,也就是边界颜色。
纹理的采样方式
当一个比较小的贴图,贴到一个比较大的3D模型上,就会存在一个问题,3D模型上的点,不会正好对应贴图上的像素,3D模型上的点可能就会落在贴图上像素点与像素点之间。
如果选择Point模式,就会选择贴图对应3D模型上的点,距离最近的一个贴图像素点,来插值采样,纹理像素看起来就会一块块的,形似马赛克。
如果选择Bilinear模式,就会选择贴图对应3D模型上的点,周围的四个贴图像素点,来插值采样,纹理像素看起来就会过渡的更加自然。
如果选择Trilinear模式,还会在Mip map(多级渐远纹理)之间进行混合,如果纹理没有采用Mip map技术,那么Trilinear得到结果跟Bilinear是一样的。
Point:点过滤 - 纹理像素变得块状紧密,
Bilinear:双线性插值
Trilinear:三线插值 - 用于Mip map,对不同的Mip层进行插值,使其过渡的更自然
将2D图像上的每一点精确对应到3D模型物体表面,在点与点之间的间隙位置进行图像光滑插值处理,这就是UV mapping。UV坐标是以左下角为(0,0),右上角为(1,1)
Mip maps是一个逐渐缩小的图像列表,用于优化实时3D引擎的性能。远离相机的物体使用较小的Texture版本。使用Mip maps需要使用33%以上的内存,但不使用它会导致巨大的性能损失。
缺点:运行时占用更多内存,且增加包的容量。因为Mip maps会根据摄像机远近不同而生成对应的八个贴图,运行会加载到内存中。
优点:优化显存带宽,用来减少渲染。因为可以根据距离摄像机远近,选择适合的贴图来渲染。
一般不需要距离摄像机靠近清晰,否则模糊的这种效果,取消勾选Generate Mip Maps选项。
勾选Mip maps,对处理锯齿和闪烁的很有用。
Cubemap是六个方形纹理表示对环境的反射集合。六个方形形成围绕物体的假想立方体的面。通常用于捕捉物体的反射和周围环境。例如,天空盒(Skybox)和环境反射(Reflection Probe),可用于模拟不同光滑度平面的反射。
Unity两种创建方式:
最好,采用从纹理导入创建Cubemap,这样可以压缩立方体贴图纹理数据,进行边缘修正和光照反射计算,同时还支持HDR。
直接解决内存、带宽问题和缓存问题的一个解决方案是固定速率纹理压缩(Fixed-rateTexture Compression)。通过硬件解码压缩纹理,纹理可以需要更少的纹理内存,从而增加有效的高速缓存大小。至少这样的纹理使用起来更高效,因为他们在访问时消耗更少的内存带宽。
有多种图像压缩方法用于图像文件格式,如JPEG和PNG,但在硬件上对其实现解码会非常昂贵。
ETC
对于OpenGL ES,选择了一种称为ETC(Ericsson texture compression,ETC)的压缩算法。即快速解码,随机访问,无间接查找,速率固定。ETC算法将4×4纹素的块编码为64位,即每个纹理元素4位。
基本思想如下图所示。
ETC算法对像素块的颜色(color)进行编码,然后修改每像素的亮度(luminance)以创建最终的纹理颜色。
当前移动平台主流压缩格式的总结:
格式 | GPU支持 | 描述 | 图片要求 |
---|---|---|---|
PVRTC RGBA/RGB | PowerVR | IOS平台都支持,支持每个像素2位或者4位的纹理,包含或者不包含alpha通道都可以;PVRTC 2-bpp把一个8×4的像素单元组压成一个64位的数据块,压缩效果比较差;PVRTC 4-bpp把一个4×4的像素单元组压成一个64位的数据块。游戏中使用4位压缩更多。 | 尺寸为2的N次幂,并且宽高相同。 |
ETC1 RGB 4Bit | 支持Opnegl ES2.0的GPU | OpenGL ES2.0版本支持,移动GPU均支持的一个格式,遗憾的是不支持Alpha通道。ETC1把一个4x4的像素单元组压成一个64位的数据块。游戏开发中采用最多的格式,不过麻烦的是需要对Alpha通道进行单独存储。 | 尺寸为2的N次幂,长宽可不同 |
ETC2 ARGB/RGB 4bit | 支持Opnegl ES3.0的GPU | OpenGL ES 3.0以上才支持,补全了ETC1不支持Alpha通道,支持更高质量的压缩。 | 尺寸为4的倍数 |
ASTC RGBA/RGB |
iOS(A8以上) | 从IOS9(A8架构)Apple 手机开始支持ASTC压缩格式 ,相对于PVRTC2/4而言,ASTC(4X4)的压缩比会增加到0.25,不过显示效果也会好很多,而且不需要把图片设置为正方形。 | 长宽可不同 |
在不同移动GPU平台下选择GPU支持的压缩纹理,就可以在不需要CPU解压的情况下直接被GPU采样,节省CPU内存和带宽,也可以节省存储的体积。如果目标平台不支持设置的压缩格式,纹理将解压为RGBA32或者RGB24,浪费CPU时间和内存。
在实际开发中,一般iOS选择RGBA ASTC 4* 4 block,Android选择RGBA ETC 2 8bits。
凹凸贴图是指计算机图形学中在三维环境中通过纹理方法来产生表面凹凸不平的视觉效果。后来的Normal Mapping,Parallax Mapping,Parallax Occulision Mapping,Relief Mapping等等,均是基于同样的思想,只是考虑得越来越全面,效果也越来越逼真。
关键思想是访问纹理来修改表面的法线,而不是改变光照方程中的颜色分量。物体表面的几何法线保持不变,我们修改的只是照明方程中使用的法线值。
凹凸贴图是指计算机图形学中在三维环境中通过纹理方法来产生表面凹凸不平的视觉效果。它主要的原理是通过改变表面光照方程的法线,而不是表面的几何法线,或对每个待渲染的像素在计算照明之前都要加上一个从高度图中找到的扰动,来模拟凹凸不平的视觉特征,如褶皱、波浪等等。
Blinn于1978年提出了凹凸贴图方法。使用凹凸贴图,是为了给光滑的平面,在不增加顶点的情况下,增加一些凹凸的变化。他的原理是通过法向量的变化,来产生光影的变化,从而产生凹凸感。实际上并没有顶点(即Geometry)的变化。
表示凹凸效果的另一种方法是使用高度图来修改表面法线的方向。每个单色纹理值代表一个高度,所以在纹理中,白色表示高高度区域,黑色是低高度的区域(反之亦然)。
法线贴图(Normal mapping)是凸凹贴图(Bump mapping)技术的一种应用,法线贴图有时也称为“Dot3(仿立体)凸凹纹理贴图”。凸凹与纹理贴图通常是在现有的模型法线添加扰动不同,法线贴图要完全更新法线。与凸凹贴图类似的是,它也是用来在不增加多边形的情况下在浓淡效果中添加细节。但是凸凹贴图通常根据一个单独的灰度图像通道进行计算,而法线贴图的数据源图像通常是从更加细致版本的物体得到的多通道图像,即红、绿、蓝通道都是作为一个单独的颜色对待。
简单来说,Normal Map直接将正确的Normal值保存到一张纹理中去,那么在使用的时候直接从贴图中取即可。
视差贴图Parallax Mapping,又称为 Offset Mapping,以及virtual displacement mapping,于2001年由Kaneko引入,由Welsh进行了改进和推广。视差贴图是一种改进的Bump Mapping技术,相较于普通的凹凸贴图,视差贴图技术得到凹凸效果得会更具真实感(如石墙的纹理将有更明显的深度)。视差贴图是通过替换渲染多边形上的顶点处的纹理坐标来实现的,而这个替换依赖于一个关于切线空间中的视角(相对于表面法线的角度)和在该点上的高度图的方程。简单来说,Parallax Mapping利用Height Map进行了近似的Texture Offset。
我们知道,Parallax Mapping是针对Normal Mapping的改进,利用HeightMap进行了近似的Texture Offset。而Relief Mapping是精确的Texture Offset,所以表现力上应该是比较完美的。相较于视差贴图(左),浮雕贴图(右)可以实现更深的凹凸深度。
相较于Parallax Mapping,浮雕贴图(Relief Mapping)可以实现更深的凹凸深度。浮雕贴图方法不仅更容易提供更深的深度,还可以做出自阴影和闭塞效果,当然算法也稍稍有点复杂,具体细节可以参考这篇中文文献:http://www.ixueshu.com/document/3dc4369a761ca0d6318947a18e7f9386.html,而如果要用一句话概括Relief Mapping,将会是:“在Shader里做光线追踪”。