unity-shader-SamplerState採樣器


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

unity-shader-SamplerState採樣器


前篇


說明

之前對在玩 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/[email protected]/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
            }
        }
    }
    
  • 效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章