US3S2L1——纹理颜色采样

知识回顾

内置函数 —— 二维纹理采样函数,详见:US2S3L12——CG内置函数

1
fixed tex2D(sampler2D tex, float2 s)

传入纹理图片和UV坐标,返回纹理图片中对应位置的颜色值

单张纹理颜色采样的Shader

关键步骤:

  1. 纹理属性和CG成员变量声明

    CG中映射ShaderLab中的纹理属性,需要有两个成员变量:
    一个用于映射纹理颜色数据,一个用于映射纹理缩放平移数据

    ShaderLab中的属性:图片属性(2D​),用于利用UV坐标提取这个图片中的颜色

    1
    2
    3
    4
    Properties
    {
    _MainTex("MainTex", 2D) = ""{}
    }

    image

    在Inspector窗口上,可以看到ShaderLab的图片属性除了关联贴图,还可以修改贴图的缩放和偏移量,
    如果CG代码内需要获取贴图的缩放和偏移量这些数据,还需要额外的声明对应的 float4​ 变量去获取这些值

    因此,CG中用于映射属性的成员变量有:

    1. sampler2D 纹理属性名​:用于映射纹理图片

    2. float4 纹理属性名_ST​: 用于映射纹理图片的缩放和平移

      固定命名方式为:纹理名_ST​(S代表Scale缩放,T代表Translation平移)

    假设要获取 _MainTex​ 属性设置的纹理贴图以及缩放与偏移量,则在CG语句中声明如下变量:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    sampler2D _MainTex;
    float4 _MainTex_ST;

    v2f_img vert (appdata_base v) { /*...*/ }
    fixed4 frag (v2f_img i) : SV_Target { /*...*/ }
    ENDCG
  2. 在顶点着色器中用缩放平移参数参与UV值计算

    这里使用 UnityCG.cginc​ 提供的 v2f_img​ 作为顶点着色器返回值,
    其中就包括了表示纹理UV坐标的成员 uv​,计算出来的uv坐标值需要赋值给该成员

    1. 如何获取模型中携带的uv信息?

      在顶点着色器中,我们可以利用 TEXCOORD​ 语义获取到模型中的纹理坐标信息,它是一个 float4​ 类型的,其中:

      • xy​ 获取到的是纹理坐标的水平和垂直坐标
      • zw​ 获取到的是纹理携带的一些额外信息,例如深度值等,目前暂时不用。

      例如:UnityCG.cginc​ 提供的 appdata_base​ 就包含 TEXCOORD0​ 语义的成员 texcoord​,它就用于获取模型的UV信息。

    2. 如何计算

      固定算法为:先缩放,后平(偏)移,缩放用乘法,平(偏)移用加法

      语法类似于:纹理坐标.xy * 纹理名_ST.xy + 纹理名_ST.zw

      1
      2
      3
      4
      5
      6
      7
      8
      v2f_img vert (appdata_base v)
      {
      v2f_img data;
      data.pos = UnityObjectToClipPos(v.vertex); //将顶点转换到裁剪空间下
      //根据属性设置的缩放和偏移量,修正顶点UV坐标,确保缩放偏移后也能正确映射
      data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
      return data;
      }

      或者直接用内置宏:TRANSFORM_TEX(纹理坐标变量, 纹理变量)​,该宏在内部会进行相同的计算

      1
      2
      3
      4
      5
      6
      7
      v2f_img vert (appdata_base v)
      {
      v2f_img data;
      data.pos = UnityObjectToClipPos(v.vertex); //将顶点转换到裁剪空间下
      data.uv = TRANSFORM_TEX(v.texcoord.xy, _MainTex); //根据属性设置的缩放和偏移量,修正顶点UV坐标,确保缩放偏移后也能正确映射
      return data;
      }

      如果没有进行缩放和平移,那么计算后,值是不会变化的,因为缩放默认值是1和1,平移默认值是0和0

  3. 在片元着色器中进行纹理颜色采样

    这里使用 tex2D()​ ,传入UV坐标和贴图,将纹理中对应的UV坐标的颜色映射到模型的某个片元

    要注意,这里传入的 v2f_img​ 的 uv​ 是插值计算后的,每一个片元自己的UV坐标,这样才可以精准的从贴图中取出颜色

    1
    2
    3
    4
    5
    fixed4 frag (v2f_img i) : SV_Target
    {
    fixed4 color = tex2D(_MainTex, i.uv); //根据UV坐标,将纹理上颜色映射到模型上
    return color;
    }

完整Shader代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Shader "TeachShader/Lesson48"
{
Properties
{
_MainTex("MainTex", 2D) = ""{}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

sampler2D _MainTex;
float4 _MainTex_ST;

v2f_img vert (appdata_base v)
{
v2f_img data;
data.pos = UnityObjectToClipPos(v.vertex); //将顶点转换到裁剪空间下
data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; //根据属性设置的缩放和偏移量,修正顶点UV坐标,确保缩放偏移后也能正确映射
return data;
}

fixed4 frag (v2f_img i) : SV_Target
{
fixed4 color = tex2D(_MainTex, i.uv); //根据UV坐标,将纹理上颜色映射到模型上
return color;
}
ENDCG
}
}
}

显示效果(左图为不关联纹理的模型的显示效果(固定为白色),右图为关联的纹理的模型的显示效果):

image

修改纹理的缩放和偏移量,会影响到模型的显示效果(偏移量修改为0.5,0):

image