案例-通過積雪效果更深入的了解shader

之前的預(yù)備知識能讓我們掌握shader的基本用法,并且寫出一些簡單的shader。這次我們通過積雪效果來更進一步的了解shader是如何結(jié)合數(shù)學(xué),實現(xiàn)效果。
另外注意,關(guān)注有強烈光照需求的shader才使用surface shader,否則使用VF shader就可。

Shader "Custom/SnowEffect" {   //定義shader的路徑
    Properties{
    
       _MainTex("Albedo (RGB)", 2D) = "white" {}       //要使用的紋理

    //定義了默認值為“bump”的2D類型的紋理_Bump,初始值為空。
      _Bump("Bump",2D) = "bump"{}

      _Snow("Snow Level",Range(0,1)) = 0            
      _SnowColor("Snow Color",Color) = (1,1,1,1)
      _SnowDirection("Snow Direction",Vector) = (0,1,0)  //默認水平方向,值為1,而不是-1
      _SnowDepth("Snow Depth",Range(0,0.3)) = 0.1        //積雪厚度
    }
        SubShader{
            //在腳本中可以通過判斷rendertype來做一些處理,比如shader替換、shader關(guān)閉
            //參考:  https://blog.csdn.net/nnsword/article/details/17840439   類型
            //        https://blog.csdn.net/zmafly/article/details/51141011    作用
            //       http://lib.csdn.net/article/unity3d/44793                解析
            Tags { "RenderType" = "Opaque" }

            CGPROGRAM        //shader的正文

            //聲明surface shader 函數(shù)名,光照類型,使用的頂點函數(shù)(自定頂點函數(shù)名為vert)
            #pragma surface surf Lambert vertex:vert  

          //添加對PROPERTIES的引用
          sampler2D _MainTex;
          sampler2D _Bump;
          float _Snow;
          float4 _SnowColor;
          float4 _SnowDirection;
          float _SnowDepth;

          struct Input {
              float2 uv_MainTex;

              //添加一個變量float2 uv_Bump來獲得_Bump紋理的uv坐標(biāo)。
              float2 uv_Bump;
              //獲取世界坐標(biāo)下的法向值
              float3 worldNormal;
              INTERNAL_DATA
          };

          void surf(Input IN, inout SurfaceOutput o) {
              //tex2D對紋理進行采樣
              half4 c = tex2D(_MainTex, IN.uv_MainTex);
              o.Albedo = c.rgb;
              o.Alpha = c.a;

              //tex2D根據(jù)輸入?yún)?shù)的類型,獲取對應(yīng)含義的值,此處從_Bump紋理中提取法向信息
              //UnpackNormal函數(shù)的作用就是將tex2D函數(shù)獲取到的fixed4類型值轉(zhuǎn)換成fixed3類型的值
              o.Normal = UnpackNormal(tex2D(_Bump, IN.uv_Bump));

              //得到世界坐標(biāo)系下的真正法向量(而非凹凸貼圖產(chǎn)生的法向量,要做一個凹凸貼圖法向值到世界坐標(biāo)系法向值的轉(zhuǎn)化)和雪落
              //下相反方向的點乘結(jié)果,即兩者余弦值,并和_Snow(積雪程度)比較
              if (dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz) > lerp(1, -1, _Snow))
              {
                  /*
                  我們知道,余弦值是-1和1之間的一個數(shù),越接近于1,說明該點法向與雪落下相反方向越一致,當(dāng)為-1時,說明兩者方向相反。
                 此處我們可以看出_Snow參數(shù)只是一個插值項,當(dāng)上述夾角余弦值大于
                  lerp(1,-1,_Snow)=1-2*_Snow時,即表示此處積雪覆蓋,所以此值越大

                  多講一點,lerp的第三個參數(shù)是一個(0,1)之間的比例因子,代表所處前兩個參數(shù)范圍的位置
                  注意為了符合正常的自然現(xiàn)象,我們_Snow一般只取0~0.5,因為大于0.5時,插值的結(jié)果將小于0,會造成雪好像穿過了巖石,落到了巖石的后面。這個道理和光照的道理一樣,物體背面是見不到陽光的。
                  */

                  //積雪程度程度越大。此時給覆蓋積雪的區(qū)域填充雪的顏色
                  o.Albedo = _SnowColor.rgb;
              }

              else      //否則表示未覆蓋
              {
                  o.Albedo = c.rgb;
              }

              o.Alpha = 1;

          }
          //自定義頂點函數(shù)
          /*
             參數(shù)appdata_full v,參數(shù)的類型為appdata_full(Unity內(nèi)置類型),該類型包含了紋理坐標(biāo),法向量,頂點位置,以及切線信息
          */
          void vert(inout appdata_full v)
          {
              //將_SnowDirection從世界坐標(biāo)系轉(zhuǎn)換到模型的局部坐標(biāo)系下
              /*
                  將_SnowDirection乘以Unity內(nèi)置矩陣 – UNITY_MATRIX_IT_MV
                  (IT表示Inverse Transpose逆轉(zhuǎn)置矩陣,MV表示 ModelView矩陣,該矩陣表示是ModelView的逆轉(zhuǎn)置矩陣)。
                現(xiàn)在我們得到了該頂點的法向量。
                _Snow*2/3,這表示只有那些更接近雪落下方向的區(qū)域才會增加雪的厚度,更符合自然現(xiàn)象。
                而這些通過測試的區(qū)域,沿著(sn.xyz+v.normal)方向進行加厚,也就是將其頂點沿此方向伸展一定距離。
                注意到增厚的程度取決于_SnowDepth和_Snow,而增厚的方向是由物體法向和雪落的方向綜合作用的,這也符合自然現(xiàn)象。
              */
               float4 sn = mul(UNITY_MATRIX_IT_MV, _SnowDirection);

               if (dot(v.normal, sn.xyz) >= lerp(1, -1, (_Snow * 2) / 3))
                   v.vertex.xyz += (sn.xyz + v.normal) * _SnowDepth * _Snow;
           }
               ENDCG
      }
          FallBack "Diffuse"      //shader失敗時回滾
}

調(diào)節(jié)箭頭所指落雪方向可以改變落雪效果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容