向着色器添加纹理

通过纹理,可以很容易让着色器变得生动起来,获得非常真实的效果。为了更有效的使用纹理,我们需要了解一张2D图片是如何映射到3D模型中去的。 这个映射的过程称之为纹理贴图texture mapping,为了完成映射,我们在使用的模型和着色器上还有额外的工作。模型实际上是由很多的三角形拼接而成的;而三角形的每个顶点都保存有着色器可以访问的各种数据。 其中很重要的一个信息就是UV信息 (UV data)。 它包含两个坐标,UV,其取值范围是0到1。这两者表示2D图片的像素点坐标的XY位置信息,而这些信息将会映射到顶点中去。 UV数据只为顶点表示[意思可能也等价于:UV数据只存在顶点中]; 当三角内的点需要被纹理贴图时,GPU会插值最接近的UV值,从而从相应的纹理中找到正确的像素点。下面的图片展示了一张2D纹理贴图到3D模型中的三角形中的情况:

UV数据保存在3D模型中并且需要3D模型工具去编辑它们。有些模型缺少UV组件,因而它们不支持纹理贴图。比如3D模型软件中的默认的那个兔子模型,就没有提供这么一个组件。

  • 始前准备

    学习这个知识点的时候,你需要一个有UV数据和纹理的3D模型。然后把它们都导入到Unity中。也可以直接拖拽到Unity编辑器中,会自动导入。因为标准着色器支持默认的纹理贴图。我们会用到这一点,而后会详细的介绍它是如何工作的。


  • 操作步骤

    用标准着色器给你的模型添加一张纹理异常的简单,按照下面步骤:

    1. 创建一个叫TexturedShader标准着色器。

    2. 创建一个名为TexturedMaterial的材质球。

    3. 通过拖拽的方式,把着色器赋值给材质,把着色器拖到材质上即可。

    4. 选择刚才的材质,然后拖拽模型对应的纹理到一个叫**Albedo(RGB)的矩形区域中的空白部分。如果你正确的执行了上述步骤,你的材质检查器面板(Inspector )**会如下图所示:

  • 原理介绍

    当通过材质的检查器面板使用标准材质的时候,纹理贴图背后的处理过程对于开发者来说是透明的。如果我们想了解它是如何工作的,那我们需要更加详细的了解我们刚才创建的TexturedShader着色器。在着色器的属性Properties部分,我们可以看到**Albedo (RGB)**的纹理跟代码的关联如下代码所示:

    MainTex:
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    

    在我们着色器代码中的CGPROGRAM代码块部分,纹理被定义为sampler2D类型,这是一种标准的2D纹理类型:

    sampler2D _MainTex;
    

    紧接着下一行给我们展示了Input这个结构。这个结构就是surface 函数中得输入参数并且这个结构包含了一个叫做uv_MainTex的包组数组:

    struct Input 
    {
    	float2 uv_MainTex;
    };
    

    每一次调用**surf()函数的时候,对应3D模型中的包含_MainTex 这个UV的Input 结构都需要被渲染。标准着色器会知道uv_MainTex _MainTex **是关联的,并且会自动初始化它。如果你真的很想了解到底UV是怎么从3D模型映射到2D纹理的话,你可以看看第三章, 理解光照模型

    终于,UV数据被用来在**surface **函数中展示成一张纹理:

    fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    

    注意

    UV的取值范围都是从0到1,**(0,0)(1,1)**相当于两个相对的角[可以想象成一个是左下角,一个是右上角]。如果你的纹理出现了颠倒的情况,试着把V的值也颠倒就能解决了。


    • 额外内容

      当你把纹理导入到Unity的时候,你就会默认设置一些sampler2D类型将要使用的一些属性。 最重要的就是筛选模式Filter mode,它决定了一张纹理显示的时候颜色是如何插值的。跟UV数据会准确的指向像素的正中心非常不同;在一些其他的情况中,你也许想对最近的像素之间进行颜色插值从而获得更一致的颜色。下图是示例纹理在检查器面板Inspector tab的截屏:

      当以一个很大的倾斜角去观看一张纹理时,纹理采样似乎会呈现一种看起来不舒服的人工制品。你可以通过设置更高的**Aniso Level **的值来减少这种感觉。这一点对地板纹理和天花板纹理特别有用,可以解决一些小瑕疵导致的纹理观感不连续性的问题。