目录:Unity Shader - 知识点目录(先占位,后续持续更新)
原文:Using sampler states
版本:2019.1
Using sampler states
使用采样器的状态
Coupled textures and samplers
成对耦合的纹理与采样器
多数时候当在shader中采样纹理时,纹理的采样状态都将来自texture settings 纹理设置,本质上,纹理与采样器都是成对使用的。这些在使用DX9风格的语法都是默认的行为。
sampler2D _MainTex;
// ...
half4 color = tex2D(_MainTex, uv);
使用了sampler2D,sampler3D,samplerCUBE HLSL的关键字来定义纹理与采样器。
多数时候这都是你想要的结果,并且这在老旧的图形API(OpenGL ES)都是唯一支持的选项。
Separate textures and samplers
将纹理与采样器分离
许多图形API和GPU允许使用比纹理更少的采样器,而耦合的纹理+采样器语法可能不允许编写更复杂的着色器。例如Direct3D 11允许你在一个单独的shader中使用最多128个纹理,但采样器最多只有16个。
Unity允许定义纹理和采样器,使用DX11风格的HLSL语法,和使用一个特殊的命名规则来匹配使用:采样器的名字以"sampler" + 纹理名称的形式规则,将会从纹理得到采样状态。
上面的shader代码都可以使用DX11风格的HLSL语法来重写,它们的效果是一样的:
Texture2D _MainTex;
SamplerState sampler_MainTex; // "sampler" + “_MainTex”
// ...
half4 color = _MainTex.Sample(sampler_MainTex, uv);
然而,这种方式的shader,当需要采样的纹理不止一个的时候,可以写成从其他纹理中复用的采样器。下面的例子中,有三个纹理需要采样,但仅仅只有一个采样器使用就可以了:
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 ES 2.0),查看 shading language了解详情。你可以使用 #pragma target 3.5(查看 shader compilation targets 了解pragma target详情)来让该shader跳过老旧平台的支持。
Unity提供一些shader宏来帮助定义采样纹理,使用这种"separate samplers"(纹理与采样器分离)方法,查看 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这样的老平台上将会回退到使用三个采样器的方式。
Inline sampler state
内联的采样器状态
除了将HLSL SamplerState对象命名为“sampler”+TextureName之外,Unity还可以识别采样器名称中的其他一些模式。这对于直接在着色器中声明定义简单的硬编码采样状态来说是非常有用。例如:
Texture2D _MainTex;
SamplerState my_point_clamp_sampler;
// ...
half4 color = _MainTex.Sample(my_point_clamp_sampler, uv);
名为"my_point_clamp_sampler"将会被识别为一个使用纹理点(最近的点)filter(滤波),与纹理wrap模型为Clamp的采样器。
采样器的名称被识别为"inline"(内联)的采样器状态(大小写不敏感的):
- “Point”, “Linear” 或 “Trilinear”(必要项)设置纹理的filter过滤模型。
- “Clamp”, “Repeat”, “Mirror” 或 “MirrorOnce”(必要项)设置纹理的wrap模型。
- Wrap模式可以指定没轴向的模式(UVW),例如:“ClampU_RepeatV”,将指定U坐标使用Clamp,V坐标使用Repeat。
- “Compare” (可选项)设置采样的深度比较;使用HLSL SamplerComparisonState 类型和 SampleCmp 或 SampleCmpLevelZero 函数。
这儿有个采样纹理的例子:分别使用 sampler_linear_repeat 和 sampler_point_repeat,下面的图片,就是对应名称如何控制过滤模式:
这儿还有一个例子,分别使用 SmpClampPoint,SmpRepeatPoint,SmpMirrorPoint,SmpMirrorOncePoint,Smp_ClampU_RepeatV_Point 的采样器状态,下面展示如何控制wrap模式的。在最后的那个例子中,使用了水平u,和垂直v轴向都不一样的wrap模式。在这些例子中纹理坐标都是使用-2.0到+2.0。
就像分开 texture + sampler(纹理 + 采样器)的语法一样,内联的采样器状态在某些平台不支持。当前它们在Direct3D 11/12,PS4,XboxOne 和 Metal都支持。
注意 “MirrorOnce” 纹理的Wrap模式在多数的移动设备的GPU/API都不知道,当它不支持的时候将会回退使用Mirror模式。