Version: Unity 6.0 (6000.0)
语言 : 中文
将顶点数据输入至着色器
为不同的图形 API 编写着色器

纹理采样器

大多数情况下,在着色器中对纹理进行采样时,纹理采样状态应以纹理设置为准——即在本质上将纹理和采样器耦合在一起。使用 DX9 风格的着色器语法时,这是默认行为:

sampler2D _MainTex;
// ...
half4 color = tex2D(_MainTex, uv);

使用 HLSL 关键字 sampler2D、sampler3D 和 samplerCUBE 可声明纹理和采样器。

这在大部分情况下都会是您想要的结果,而且在较旧的图形 API (OpenGL ES) 中,这是唯一支持的选项。

单独的纹理和采样器

许多图形 API 和 GPU 都允许使用的采样器数量少于纹理,而耦合的纹理+采样器语法可能不允许编写更复杂的着色器。例如,Direct3D 11 允许在单个着色器中最多使用 128 个纹理,但最多仅允许使用 16 个采样器。

Unity 允许使用 DX11 风格的 HLSL 语法来声明纹理和采样器,但需要通过特殊的命名规范匹配双方:名称为“sampler”+TextureName 格式的采样器将从纹理中获取采样状态。

上文小节中的着色器代码片段可以用 DX11 风格的 HLSL 语法重写,并且也会执行相同的操作:

Texture2D _MainTex;
SamplerState sampler_MainTex; // "sampler" + “_MainTex”
// ...
half4 color = _MainTex.Sample(sampler_MainTex, uv);

但这样一来,着色器就可以被编写为重复使用其他纹理中的采样器,同时采样多个纹理。下方示例采样了三个纹理,但仅一个采样器用于所有纹理:

Texture2D _MainTex;
Texture2D _SecondTex;
Texture2D _ThirdTex;
SamplerState sampler_MainTex; // "sampler" + “_MainTex”
// ...
half4 color = _MainTex.Sample(sampler_MainTex, uv);
color += _SecondTex.Sample(sampler_MainTex, uv);
color += _ThirdTex.Sample(sampler_MainTex, uv);

Unity 提供了一些着色器宏帮助您使用这种“单独采样器”方法来声明和采样纹理,详情请参阅内置宏。以上示例可以用所述的宏重写为下列形式:

UNITY_DECLARE_TEX2D(_MainTex);
UNITY_DECLARE_TEX2D_NOSAMPLER(_SecondTex);
UNITY_DECLARE_TEX2D_NOSAMPLER(_ThirdTex);
// ...
half4 color = UNITY_SAMPLE_TEX2D(_MainTex, uv);
color += UNITY_SAMPLE_TEX2D_SAMPLER(_SecondTex, _MainTex, uv);
color += UNITY_SAMPLE_TEX2D_SAMPLER(_ThirdTex, _MainTex, uv);

以上代码会在 Unity 支持的所有平台上进行编译,但会在 DX9 等旧平台上回退为使用三个采样器。

内联采样器状态

除了能识别名为“sampler”+TextureName 的 HLSL SamplerState 对象外,Unity 还能识别某些其他模式的采样器名称。这非常适合用于直接在着色器中声明简单硬编码采样状态。例如:

Texture2D _MainTex;
SamplerState my_point_clamp_sampler;
// ...
half4 color = _MainTex.Sample(my_point_clamp_sampler, uv);

名称 “my_point_clamp_sampler”将被识别为应使用点(最近距离的)纹理过滤和限制 (Clamp) 纹理包裹模式的采样器。

被识别为“内联”采样器状态的采样器名称(全都不区分大小写):

  • “Point”、“Linear”或“Trilinear”(必需)设置纹理过滤模式。

  • “Clamp”、“Repeat”、“Mirror”或“MirrorOnce”(必需)设置纹理包裹模式。

    • 可根据轴 (UVW) 逐个指定包裹模式,例如“ClampU_RepeatV”。
  • “Compare”(可选)设置用于深度比较的采样器;与 HLSL SamplerComparisonState 类型和 SampleCmp/SampleCmpLevelZero 函数配合使用。

  • 可以添加“AnisoX”(其中 X 可以是 2/4/8 或 16,例如 Aniso8)来请求各向异性过滤。

以下是分别使用 sampler_linear_repeatsampler_point_repeat 采样器状态进行纹理采样的示例,展示了如何通过名称控制过滤模式:

以下是分别使用 SmpClampPointSmpRepeatPointSmpMirrorPointSmpMirrorOncePointSmp_ClampU_RepeatV_Point 采样器状态的示例,展示了如何通过名称控制包裹模式。在上一个示例中,水平轴 (U) 和垂直轴 (V) 被设置了不同的包裹模式。在任何情况下,纹理坐标的范围都是 –2.0 到 +2.0。

就像单独的纹理+采样器语法一样,某些平台不支持内联采样器状态。目前只在 Direct3D 11/12 和 Metal 上实现了内联采样器状态。

请注意,大部分移动端 GPU/API 都不支持“MirrorOnce”纹理包裹模式,并将在不支持的情况下回退到 Mirror 模式。

请注意,“AnisoX”过滤模式是基于平台功能和所选 API 的最佳方案。实际值将根据所支持的最大各向异性级别进行钳制(在不支持各向异性过滤的情况下,包括将其设为禁用状态的情况)。

纹理/采样器声明宏

宏: 用途:
UNITY_DECLARE_TEX2D(name) 声明纹理和采样器对。
UNITY_DECLARE_TEX2D_NOSAMPLER(name) 声明不含采样器的纹理。
UNITY_DECLARE_TEX2DARRAY(name) 声明纹理数组采样器变量。
UNITY_SAMPLE_TEX2D(name,uv) 使用给定的纹理坐标从纹理和采样器对中采样。
UNITY_SAMPLE_TEX2D_SAMPLER( name,samplername,uv) 使用另一个纹理中的采样器 (samplername),从纹理 (name) 中采样。
UNITY_SAMPLE_TEX2DARRAY(name,uv) 从具有 float3 UV 的纹理数组中采样;坐标的 z 分量为数组元素索引。
UNITY_SAMPLE_TEX2DARRAY_LOD(name,uv,lod) 从具有明确 Mipmap 级别的纹理数组中采样。
将顶点数据输入至着色器
为不同的图形 API 编写着色器