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!

 
 
posted @ 2013-06-16 00:01  yaukey  阅读(4382)  评论(1编辑  收藏  举报