耦合的材质和取样器
大多数情况下,在shader中采样贴图时,贴图采样声明应该来自贴图设置-本质上,贴图和采样器是被绑在一起的。在用DX9风格 shader 语法时,这是一个默认行为:
sampler2D _MainTex; // ... half4 color = tex2D(_MainTex, uv);
使用 sampler2D,sampler3D,samplerCUBE HLSL关键字同时声明贴图和取样器。
大多数情况下这是你想要的,但是这只在老图形API上才支持(OpenGL ES)。
分别的材质和取样器
大部分图形API和CPU允许贴图比采样器多,并且耦合的贴图+采样器在写复杂的shader时可能是不允许的。比如在D3D 11中一个shader中可以使用128张贴图,但是最多却只有16个采样器。
unity允许声明贴图和采样器时使用DX11风格的HLSL语法,用一个特殊的命名惯例来将他们匹配起来;拥有名字为“sampler”+贴图名字 的采样器会对这个纹理进行取样。
上面描述的语法如下:
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);
但是请注意,dx11风格的HLSL语法在一些较旧的平台上不起作用(比如OpenGL ES2.0),在 shading language查看细节。你可能需要声明 #pragma target 3.5
来跳过老的平台使用shader。
unity提供几个shader宏命令来帮助声明和采样贴图使用这个“分离的采样器”方法,查看 built-in macros.上面的例子可以被重写为下面的样子:
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”会被认为是一个使用点贴图过滤和夹结构包装模式的采样器。
采样器名字被认为是“内联”采样器声明(所有不区分大小写):
- “Point”, “Linear” or “Trilinear” (必须) 设置贴图过滤模式。
- “Clamp”, “Repeat”, “Mirror” or “MirrorOnce” (必须)设置贴图覆盖模式。
- 贴图覆盖模式可以指定每个轴向(UVW),比如:“ClampU_RepeatV”。
- “比较”(可选择的)设置采样器深度比较;使用HLSL 采样器比较声明类型和 SampleCmp / SampleCmpLevelZero 函数。
这里有一个抽样纹理的例子,sampler_linear_repeat和sampler_point_repeat SamplerStates分别说明了名称控制过滤模式的方式:
这里有一个SmpClampPoint、SmpRepeatPoint、SmpMirrorPoint、SmpMirrorOncePoint、Smp_ClampU_RepeatV_Point SamplerStates的例子,说明了名称如何控制包装模式。在最后一个例子中,为水平(U)和垂直(V)轴设置不同的包装模式。在所有情况下,纹理坐标从-2.0到+2.0。
就像单独的纹理+采样器语法一样,在某些平台上不支持内联采样器状态。目前他们在Direct3D 11/12, PS4, XboxOne和Metal实现。
注意,在大多数移动gpu / api上,“MirrorOnce”纹理包装模式不受支持,当支持不存在时,它将返回镜像模式。