zoukankan      html  css  js  c++  java
  • 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!

     
     
  • 相关阅读:
    &和&&的区别
    AOP和IOC的实现原理(用到的设计模式)
    字符串里有数字和字符,如何只获取一种(以数字为例)
    maven的搭建
    java中递归的方法的实例
    从零开始学习oracle
    各个浏览器的webdriver
    “equals”有值 与 “==”存在 “equals”只是比较值是否相同,值传递,==地址传递,null==a,避免引发空指针异常,STRING是一个对象==null,对象不存在,str.equals("")对象存在但是包含字符‘''
    Oracle基础入门
    orcale => 含义
  • 原文地址:https://www.cnblogs.com/yaukey/p/unity_bump_mapping_shader.html
Copyright © 2011-2022 走看看