在以前旧版DX9的HLSL是纹理与采样器成对耦合的定义的
如:
sampler2D _Tex;
在DX9中上面就定义了一个纹理,一个采样器
但我们现代的比较多的GPU都是在一个shader可以支持128个纹理,而采样器,可能就16个
如果沿用DX9就这方式来定义就无法超过16个纹理了,因为采样器会一并定义。
在DX10后,就有优化了,可以将纹理,采样器分开了定义了
这样我们就可以在多张纹理采样时使用指定的采样器
在我们下面的例子:三个纹理采样时使用同一个采样器
具体,可看看之前翻译的Using sampler states 使用采样器的状态
// jave.lin 2019.07.03
Shader "Test/TestMultiSampler"
{
Properties
{
[KeywordEnum(SamplerMacro, DIY)] _SMP ("Sampler Snippet type", Float) = 0
_tex1 ("tex1", 2D) = "white" {}
[NoScaleOffset] _tex2 ("tex2", 2D) = "white" {}
[NoScaleOffset] _tex3 ("tex3", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma multi_compile _SMP_SAMPLERMACRO _SMP_DIY
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
#if _SMP_SAMPLERMACRO
UNITY_DECLARE_TEX2D(_tex1);
UNITY_DECLARE_TEX2D_NOSAMPLER(_tex2);
UNITY_DECLARE_TEX2D_NOSAMPLER(_tex3);
#else
Texture2D _tex1;
Texture2D _tex2;
Texture2D _tex3;
//#define smp sampler_tex1 // 使用unity的texture setting的sampler
//#define smp sampler_linear_clampu // filter:linear, wrap: clamp u
//#define smp sampler_linear_clampv // filter:linear, wrap: clamp v
//#define smp sampler_point_clamp // filter:point, wrap: clamp u & v
//#define smp sampler_linear_clamp // filter:linear, wrap: clamp u & v
//#define smp sampler_trilinear_clamp // filter:trilinear, wrap: clamp u & v
//#define smp sampler_trilinear_mirroru // filter:trilinear, wrap: mirror u
//#define smp sampler_trilinear_mirrorv // filter:trilinear, wrap: mirror v
//#define smp sampler_trilinear_mirror // filter:trilinear, wrap: mirror v & v
//#define smp sampler_trilinear_mirroronceu // filter:trilinear, wrap: mirror once u, 这个亲测法线mirror v也生成,不知道是否解析的BUG
//#define smp sampler_trilinear_mirroroncev // filter:trilinear, wrap: mirror once v, 这个亲测法线mirror u也生成,不知道是否解析的BUG
//#define smp sampler_trilinear_mirroroncev_mirroru // filter:trilinear, wrap: mirror once v & mirror u, 亲测两个一起设置,就没有BUG
//#define smp sampler_trilinear_mirroru_repeat // filter:trilinear, wrap: mirror u & repeat v
#define smp sampler_trilinear_mirroru_clamp // filter:trilinear, wrap: mirror u & repeat v
SamplerState smp;
#endif
float4 _tex1_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _tex1);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
#if _SMP_SAMPLERMACRO
half3 tc1 = UNITY_SAMPLE_TEX2D(_tex1, i.uv);
half3 tc2 = UNITY_SAMPLE_TEX2D_SAMPLER(_tex2, _tex1, i.uv);
half3 tc3 = UNITY_SAMPLE_TEX2D_SAMPLER(_tex3, _tex1, i.uv);
#else
half3 tc1 = _tex1.Sample(smp, i.uv);
half3 tc2 = _tex2.Sample(smp, i.uv);
half3 tc3 = _tex3.Sample(smp, i.uv);
#endif
half4 combined = fixed4(tc1 * tc2 + tc3, 1);
return combined;
}
ENDCG
}
}
}
我们使用#pragma multi_compile区别了两种方式
#pragma multi_compile _SMP_SAMPLERMACRO _SMP_DIY
第一种是使用UNITY内置的方式,这种方式是使用Unity编辑器中对纹理设置的配置来定义采样器状态的,如,在Project视图,选择中一个纹理,设置了它的Filter为Point,那么这个宏定义默认就会使用你刚刚定义的纹理配置:Filter:Point。
第二种是手动编写的方式,这种方式在之前翻译的Using sampler states 使用采样器的状态,有提到,叫Inline Sampler States,内联方式,Unity会对名称进行识别,对linear,point,trilinear,clamp,mirror,mirroronce,repeat等,都可以识别,然后自动给你这个按名称定义的采样器,自动设置上对应的采样状态属性。
上面的名称的识别的字,大小写不敏感的,按你喜欢方式来写即可。
也可以看到手动写的第一行注释掉的方式:
Texture2D _tex1;
...
#define smp sampler_tex1 // 使用unity的texture setting的sampler
这个方式和第一种使用的方式是一样的
注释的代码中,可以看到有好多种配置组合定义的方式,按你需要的来即可