【風宇沖】Unity3D教程寶典之Shader篇:第二十講法線貼圖

來源:互聯網
上載者:User

【風宇沖】Unity3D教程寶典之Shader篇:第二十講法線貼圖(2012-12-26 10:42:55)

轉載
標籤:

unity3d教程unity3dunityit遊戲開發
分類:
Unity3d之Shader篇
原創文章如需轉載請註明:轉載自風宇沖Unity3D教程學院

                                
第二十講 法線貼圖



上一講我們講了凹凸貼圖以及產生法線貼圖。這一講來談談怎麼使用法線貼圖。一:法線貼圖的原理二:法線貼圖的實現三:法線貼圖的使用四:法線貼圖的格式一:法線貼圖的原理    光照效果很大程度上是由垂直於物體表面的法線決定的,因為法線影響反射光的方向。均勻垂直的法線是鏡面貼圖。但是有時候我們會給一個平面使用磚牆貼圖,磚牆應該是凹凸不平的,而如果讓磚牆使用該平面的法線的話,畫面就會很假,神馬?一面牆像鏡子一樣反光=。=而如果按真實磚牆去做模型的話,即做高精度模型,一方面製作麻煩,另一方面運行時對效能損耗大。法線貼圖就是來解決這個問題的。法線貼圖就是把法線資訊儲存在一張圖裡。使用法線貼圖時,通常頂點數和三角形面數只有高精度模型的十分之一不到。二:法線貼圖的實現    將材質貼圖對應的法線 繪製在一張貼圖上。將貼圖對應點的單位法線向量資訊float3(x,y,z) 儲存在圖對應的顏色裡color(r,g,b)裡,其中x,y,z分別對應r,g,b。單位法線向量 float3(x,y,z),x,y,z的取值範圍是 [-1,1]。在法線貼圖中被壓縮在顏色的範圍[0,1]中,所以需要轉換:顏色 = 0.5 * 法線 + 0.5;線 = 2 * (顏色 - 0.5);  
 
三:法線貼圖的使用主要步驟(1)對法線貼圖進行採樣,取得壓縮在色彩空間[0,1]裡的法線float4 packedNormal = tex2D(_NormalMap, IN.uv_MainTex);(2)將壓縮在[0,1]裡的法線轉換至3D空間[-1,1]  (因為是單位向量)float3 expand(float3 v) { return (v -
0.5) * 2; }   之後使用該法線即可,方法與16講裡一樣。
   具體實現詳見本文末的指令碼。
四:法線貼圖的格式法線貼圖主要分為2個類別:(1)RGB法線貼圖,即上面使用的。通常呈藍色。(尾碼可以是常見的.png  .jpg等)(2)壓縮格式的法線貼圖。例如DXT5nm(尾碼名為.dds)

 dds是DirectDraw Surface的縮寫,實際上,它是DirectX紋理壓縮(DirectX Texture Compression,簡稱DXTC)的產物。DXTC減少了紋理記憶體消耗的50%甚至更多,有3種DXTC的格式可供使用,它們分別是DXT1,DXT3和DXT5。
有關DDS的延伸閱讀 壓縮法線貼圖的原理:法線(x,y,z)是一條單位向量。故X2 + Y2 +Z2 
=1。所以知道了x,y,z裡的任意兩個,剩下的那個就可以通過計算得出。所以我們就可以使用2個通道的圖儲存x,y,z裡的兩個值,將xyz裡剩餘的值省略,通過計算得出。 壓縮法線貼圖的好處:壓縮後的法線貼圖,大小隻有原來的1/4左右,故可以使用更大或者更多的貼圖來提升畫面品質。
Unity3d的法線貼圖:Unity3d使用的壓縮法線貼圖是DXT5nm格式的。有A和G兩個通道。對於法線(x,y,z) A對應x,G對應y。對壓縮法線貼圖的採樣依然是如下函數:

float4 packedNormal = tex2D(_NormalMap, IN.uv_MainTex);

packedNormal.w對應A通道,即法線的x。

packedNormal.y對應G通道,即法線的y。


範圍依然是[0,1], 依然需要轉換至[-1,1]。對DXT5nm法線貼圖進行轉換的函數如下,其中v傳入packedNormal
  1. float3 expand(float3 v)
  2.  { 
  3. fixed3 normal;
  4. normal.xy = v.wy * 2 - 1;
  5. normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
  6. return normal;
  7. }

Unity3d的標準法線解壓函數是fixed3 UnpackNormal(fixed4 packednormal)。開啟UnityCG.cginc找到對應函數:
  1. inline fixed3 UnpackNormal(fixed4 packednormal)
  2. {
  3. #if defined(SHADER_API_GLES) && defined(SHADER_API_MOBILE)
  4. return packednormal.xyz * 2 - 1;
  5. #else
  6. fixed3 normal;
  7. normal.xy = packednormal.wy * 2 - 1;
  8. normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
  9. return normal;
  10. #endif
  11. }
該函數定義的如果是移動平台或者OpenGL ES,那麼斷定使用的是RGB法線貼圖,否則則為DXT5nm貼圖。但實際上移動平台也可以用壓縮格式的法線貼圖,而Windows也能使用RGB法線貼圖。故不建議使用UnpackNormal函數,建議根據法線貼圖的具體格式來使用自己寫的對應函數。
================================================================================================================================================================================================================================================================================================
指令碼:
  1. //  Shader: 帶法線貼圖的Surface Shader
  2. //  Author: 風宇沖
  3. Shader "Custom/3_NormalMap" {
  4.   Properties
  5.   {
  6.     _MainTex ("Texture", 2D) = "white" {}
  7.     _NormalMap ("NormalMap", 2D) = "white" {}
  8.   }
  9.  
  10.   Subshader
  11.   {
  12.   CGPROGRAM
  13.   #pragma surface surf BlinnPhong 
  14.   struct Input
  15.   {
  16.   float2 uv_MainTex;
  17.   };
  18.  
  19.   //法線範圍轉換:單位法線 float3(x,y,z),x,y,z的取值範圍是 [-1,1]。在法線貼圖中被壓縮在顏色的範圍[0,1]中,所以需要轉換
  20.   //(1)RGB法線貼圖
  21.   float3 expand(float3 v) { return (v - 0.5) * 2; }
  22.   //(2)DXT5nm法線貼圖
  23.   float3 expand2(float4 v)
  24. fixed3 normal;
  25. normal.xy = v.wy * 2 - 1;
  26. normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
  27. return normal;
  28. }
  29.  
  30.   sampler2D _MainTex;
  31.   sampler2D _NormalMap;
  32.  
  33.   void surf(Input IN,inout SurfaceOutput o)
  34.   {
  35.   half4 c = tex2D(_MainTex, IN.uv_MainTex);
  36.   o.Albedo = c.rgb;
  37.   o.Alpha = c.a;
  38.  
  39. //對法線貼圖進行採樣,取得壓縮在色彩空間裡的法線([0,1])
  40.  float4 packedNormal = tex2D(_NormalMap, IN.uv_MainTex);
  41.  
  42.   //要將色彩空間裡的法線[0,1],轉換至真正3D空間裡的法線範圍[-1,1]
  43.   //注意:範圍基本都是從[0,1]轉換至[-1,1].主要是圖的通道與法線xyz的對應關係要根據法線貼圖格式而定
  44.   //UnpackNormal, UnityCG.cginc裡的函數
  45.   //o.Normal = UnpackNormal(packedNormal);
  46.  
  47.   //expand,標準法線解壓函數
  48.  o.Normal = expand(packedNormal.xyz);
  49.   }
  50.   ENDCG
  51.   }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.