Unity 使用 Vertex/Fragment Shader 完整實現 BumpMapping(NormalMapping)


  這幾天一直在為了研究清楚 ShadowGun 示例的 shader,但沒寫過 Unity 的 shader,於是從頭開始閱讀官方的說明,發現多出了 SurfaceShader 的概念,再加上對 Unity 的光照系統不太了解,看起來的確實有點頭暈,細心看了看后還是有點頭緒。於是就把上一篇的討論過的法線貼圖實現一下吧,其實想在 Unity 里面使用法線貼圖效果,簡直簡單的像畫一個一字,直接選一個內建的 BumpMap 就好了,甚至你使用 SurfaceShader 直接讀取出法線就好了,其它也不用管。但是要是非要使用 vertex/fragment shader 一步一步的寫完法線貼圖的所有實現過程,就只能一步步來,最重要的當然就是要自己處理 tbn 矩陣。正好趁這個機會復習下前面的內容,寫這個的過程遇到了不少細節上的不明白,不過解決后就更明白了。

  “Use Scene Light” 大於0時,使用的是場景里的 Light(你需要自己拖一個 Direction Light),如果小於等於0就是用下面的 “Light Dir”,自定義一個燈光位置,燈光的方向從世界坐標系的原點指向該位置 (LightDir = LightPos - OriginalPos)。這里面我已經加入了高光 Specular Light。

  代碼如下:  

Shader "Custom/ManuallyNormalMapping"
{
    Properties
    {
        _MainTex("Main Tex", 2D)                 = "white" {}
        _BumpTex("Bump Tex", 2D)                 = "bump" {}
        _Ambient("Ambient Color", Color)         = (0.6, 0.6, 0.6, 1.0)
        _Diffuse("Diffuse Color", Color)         = (0.7, 0.7, 0.8, 1.0)
        _Specular("Specular Color", Color)       = (1.0, 1.0, 1.0, 1.0)
        _UseSceneLight("Use Scene Light", Float) = 1.0
        _LightDir("Light Dir", Vector)           = (0.0, -1.0, 1.0, 0.0)
    }
    
    SubShader
    {
        Tags {"RenderType" = "Opaque"}
        
        Pass
        {
            CGPROGRAM
            #pragma vertex   vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            // fragma input
            struct v2f
            {
                float4 pos      : SV_POSITION;
                float2 uv       : TEXCOORD0;
                float3 viewDir  : TEXCOORD1;
                float3 lightDir : TEXCOORD2;
            };
            
            sampler2D _MainTex;
            sampler2D _BumpTex;
            float4    _Ambient;
            float4    _Diffuse;
            float4    _Specular;
            float     _UseSceneLight;
            float4    _LightDir;
            
            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv  = v.texcoord;

                float3 tangent  = normalize(v.tangent);
                float3 normal   = normalize(v.normal);
                float3 binormal = normalize(cross(normal, v.tangent.xyz) * v.tangent.w);
                
                // All vector here is col vector, matrix is left mulpitlied.
                // So TBN matrix is [T, B, N], after normalized, TBN's inverse matrix is [T, B, N]T.
                float3x3 TBN;
                TBN[0] = tangent;
                TBN[1] = binormal;
                TBN[2] = normal;
                
                // We do not need this.
                //TBN = transpose(TBN);

                // Assume from view space.
                float3 viewDir  = ObjSpaceViewDir(v.vertex);
                float3 lightDir = float3(0.0, 0.0, 0.0);
                if (_UseSceneLight > 0.0)
                {
                    lightDir = ObjSpaceLightDir(v.vertex);
                }
                else
                {
                    lightDir = -mul(_World2Object, _LightDir);
                }
                
                o.viewDir  = mul(TBN, ObjSpaceViewDir(v.vertex));
                o.lightDir = mul(TBN, lightDir);

                return o;
            }
            
            float4 frag(v2f i) : COLOR0
            {
                float3 viewDir  = normalize(i.viewDir);
                float3 lightDir = normalize(i.lightDir);
                
                float4 normalMap = tex2D(_BumpTex, i.uv);
                //float3 normalDir = normalize(normalMap * 2.0 - 1.0);
                float3 normalDir = normalize(UnpackNormal(normalMap));

                float  s    = max(0, dot(lightDir, normalDir));
                fixed3 h    = normalize(viewDir + lightDir);
                float  r    = max(0, dot(h, normalDir));
                float  spec = pow(r, 48.0);
                float4 clr  = tex2D(_MainTex, i.uv);
                
                float4 c;
                c.rgb = ((_Ambient + _Diffuse * s) * clr.rgb + spec * _Specular.rgb * clr.a * 1.5) * 1.3;
                c.a   = clr.a;
                
                return c;
            }
            
            ENDCG
        }
    }
    
    Fallback "Diffuse"
}

  Have Fun!

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM