unity-shader-SamplerState采样器

    xiaoxiao2025-07-12  5


    title: unity-shader-SamplerState采样器 categories: Unity3d-Shader tags: [unity, shader, SamplerState, 采样器] date: 2019-05-23 01:35:28 comments: false

    unity-shader-SamplerState采样器


    前篇

    官方文档: Using sampler states - https://docs.unity3d.com/Manual/SL-SamplerStates.html 别人的翻译: https://www.cnblogs.com/leiGameDesigner/p/8462956.html

    说明

    之前对在玩 ue4-shader-自定义shader代码hlsl 就时里面的 SamplerState 不了解, 现在查看 shader graph 内置节点 Normal From Texture 的源码时又遇到了才去查了下.

    官方 Normal From Texture 节点的源码

    void Unity_NormalFromTexture_float(Texture texture, SamplerState Sampler, float2 UV, float Offset, float Strength, out float3 Out) { Offset = pow(Offset, 3) * 0.1; float2 offsetU = float2(UV.x + Offset, UV.y); float2 offsetV = float2(UV.x, UV.y + Offset); float normalSample = Texture.Sample(Sampler, UV); float uSample = Texture.Sample(Sampler, offsetU); float vSample = Texture.Sample(Sampler, offsetV); float3 va = float3(1, 0, (uSample - normalSample) * Strength); float3 vb = float3(0, 1, (vSample - normalSample) * Strength); Out = normalize(cross(va, vb)); }

    我翻译后实现: [Normal From Texture 的实现](#Normal From Texture 的实现)


    现在一般采用纹理是都用这样的语法, 使用 sampler2D,sampler3D,samplerCUBE HLSL关键字同时声明贴图和取样器。

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

    大部分图形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);

    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);`

    实例代码

    用 unlit shader 为模板改一下

    代码

    Shader "test/SamplerState_unlit" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; // sampler2D _MainTex; float4 _MainTex_ST; // Texture2D _MainTex; // SamplerState sampler_MainTex; UNITY_DECLARE_TEX2D(_MainTex); v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { // fixed4 col = tex2D(_MainTex, i.uv); // fixed4 col = _MainTex.Sample(sampler_MainTex, i.uv); fixed4 col = UNITY_SAMPLE_TEX2D(_MainTex, i.uv); return col; } ENDCG } } }

    效果 (tiling 不起作用, 暂时没去找解决方案)


    Normal From Texture 的实现

    参考官方 shader graph 的实现: Normal From Texture - https://docs.unity3d.com/Packages/com.unity.shadergraph@6.5/manual/Normal-From-Texture-Node.html

    shader

    Shader "test/Bump2Normal" { Properties { _MainTex ("Texture", 2D) = "white" {} _Offset ("Offset", Float) = 0.5 _Strength ("Strength", Float) = 10 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; float _Offset; float _Strength; // sampler2D _MainTex; float4 _MainTex_ST; UNITY_DECLARE_TEX2D(_MainTex); v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { float offset = _Offset; float Strength = _Strength; float3 Out = float3(0, 0, 0); float2 offsetUV = i.uv; offset = pow(offset, 3) * 0.1; float2 offsetU = float2(offsetUV.x + offset, offsetUV.y); float2 offsetV = float2(offsetUV.x, offsetUV.y + offset); float normalSample = UNITY_SAMPLE_TEX2D(_MainTex, offsetUV); float uSample = UNITY_SAMPLE_TEX2D(_MainTex, offsetU); float vSample = UNITY_SAMPLE_TEX2D(_MainTex, offsetV); float3 va = float3(1, 0, (uSample - normalSample) * Strength); float3 vb = float3(0, 1, (vSample - normalSample) * Strength); Out = normalize(cross(va, vb)); return fixed4(Out, 1); } ENDCG } } }

    效果

    最新回复(0)