本节书摘来自华章出版社《Unity着色器和屏幕特效开发秘笈(原书第2版)》一书中的第2章,第2.4节,作者 [英]艾伦朱科尼(Alan Zucconi) [美]肯尼斯拉默斯(Kenneth Lammers),更多章节内容可以访问“华章计算机”公众号查看
2.4 给着色器添加纹理
在模拟现实效果方面,纹理可以让着色器迅速生动起来。为了高效使用纹理,我们需要理解二维图像是如何映射成三维模型的。这个映射过程称为纹理映射。为了进行纹理映射,我们需要在着色器和想要应用纹理的三维模型上下点工夫。模型事实上是由三角形组成的,三角形的每一个顶点可以存储着色器可以访问的数据。UV数据是顶点中存储的诸多重要信息之一。UV数据由两个坐标组成,也就是U和V,取值范围为0到1,它们表示了二维图像中像素映射到顶点时的XY坐标。UV数据只是给顶点用的,三角形内部其他位置上的值则是GPU根据差值算法按照一定的间隔比例去纹理上取的值。下图展示了二维纹理是如何映射到一个三维模型的基础三角形上去的。
UV数据保存在三维模型中,并需要用专门的建模软件才可编辑。某些模型没有UV组件,也就不能支持纹理映射了。比如之前举例的那个斯坦福兔子最开始就没有UV组件。
2.4.1 准备工作
在这一节中,需要一个有UV数据的三维模型及其纹理。在开始之前需要将这二者导入Unity中。你可以直接将其拖曳到Unity编辑器中。标准着色器默认支持纹理映射,所以我们会用这个标准着色器来解释纹理映射是怎么工作的。
2.4.2 操作步骤
使用标准着色器给模型添加纹理非常简单,步骤是:
1. 创建一个新的名为TexturedShader的标准着色器。
2. 创建一个新的名为TexturedMaterial的材质。
3. 通过拖曳将着色器指定给材质。
4. 选中材质后,将纹理拖曳到名为Albedo(RGB)的空长方形中。如果你按照这个步骤进行的话,材质的Inspector标签页应该看起来像这样:
标准着色器知道如何通过UV数据将二维图像映射到三维模型上。
2.4.3 工作原理
当标准着色器在材质的审查器(inspector)中被使用时,纹理映射背后的过程对于开发人员是完全透明的。如果我们想理解它是如何工作的,需要深入看一看TexturedShader。从Properties部分来看,可以发现Albedo(RGB)纹理实际引用的代码是_MainTex:
在CGPROGRAM部分,该纹理被定义为sampler2D—二维纹理的标准类型:
下一行代码是一个名为Input的结构体。这是表面函数的输入参数,这个输入参数包含一个名为uv_MainTex的包装数组:
每次surf()函数被调用时,Input结构会包含三维模型需要渲染的某一个特殊点的_MainTex的UV值。标准着色器会识别出uv_MainTex引用的是_MainTex的值,并且会自动对其进行初始化。如果你对于UV值是如何从三维模型映射到二维纹理上的比较感兴趣,可以看看第3章的内容。
最后,表面函数的第一行中, UV数据被用来对纹理进行采样:
这个过程是通过Cg的tex2D()函数来实现的。该函数接受一个纹理和UV,并返回像素在该位置的颜色值。
UV坐标都是从0到1,其中(0,0)和(1,1)表示的是两个对顶角。不同的实现方式会把UV和不同的角联系起来。如果你的纹理看起来有点翻转了,试着颠倒一下V的值。
2.4.4 更多内容
当你向Unity导入一个纹理的时候,其实是在给sampler2D准备一些它需要用到的属性。最重要的是Filter(过滤)模式,过滤模式会决定纹理采样时颜色是如何插值的。一般而言,UV数据不会准确指向像素的中心,而其他一些时候你可能需要在最接近的像素间进行插值来让颜色看起来匀称。下图是一个样例纹理的Inspector标签页截图:
对于大部分应用程序,Bilinear(双线性)过滤是一种廉价而又有效的平滑纹理的方式。但是如果你创建的是二维游戏,那么双线性可能产生一些模糊的地方,这时你可以使用Point(点)过滤来移除纹理采样过程的插值。
当我们从一个大倾角观察纹理时,纹理采样通常会产生一些不友好的瑕疵。你可以通过增加Aniso Level的值来减少这些瑕疵,这个改动对于地板和天花板这种类型的纹理非常有效,因为这些纹理中的一些毛刺会破坏视觉的连续性。
2.4.5 参考
如果你想深入了解纹理映射的更多内容,可以查阅下面的网址:
http://http.developer.nvidia. com/CgTutorial/cg_tutorial_chapter03.html。
也可以在下面这个网址找到所有导入二维纹理时的可用选项:
。