【Unity Shaders】Reflecting Your World —— Unity3D中的法線貼圖和反射

來源:互聯網
上載者:User

標籤:ase   平行光   surf   一個   idt   資訊   doc   沒有   images   

http://blog.csdn.net/candycat1992/article/details/24541623

 

本系列主要參考《Unity Shaders and Effects Cookbook》一書(感謝原書作者),同時會加上一點個人理解或拓展。

 

這裡是本書所有的插圖。這裡是本書所需的代碼和資源(當然你也可以從官網下載)。

========================================== 分割線 ==========================================

 

寫在前面 有很多情況你可能想要使用法線去影響反射效果。比如,你想要類比一個被霜雪覆蓋的玻璃材質的表面,或者一個冰塊。如果你根據物理知識真實的類比這個平面的每一個細節部分,那麼你就不要希望你遊戲的FPS還可以達到60幀了。相反的,我們可以使用法線貼圖來偽造一個視覺體驗,因此我們需要學習如何將法線貼圖的資訊傳遞給反射效果。 為了完成這個任務,我們將要學習Input結構體的另一個內建參數,它可以將由法線貼圖技術產生的修改後的平面法線資訊傳遞進來。下面,讓我們來具體看一下如何修改Input結構體來達到這個效果吧!   準備 
  1. 首先,我們需要一個Cubemap來產生反射效果。所以你可以使用前一節中的Cubemap,或者產生一個新的。這一節中,我們使用的如下所示(你可以在本書資源中找到它):
  2. 我們還需要一張法線貼圖來產生基於法線的反射效果。
  3. 最後,建立一個新的情境、一個球體、一個平面以及一個平行光。同時,還需要建立一個新的Shader和Material,命名為NormalMappedReflection。
  實現 
  1. 首先讓我們添加新的properties,使得我們能夠添加自己的Cubemap和法線貼圖。這個步驟你應該非常熟悉了。向Properties塊添加下列代碼:
    [plain] view plain copy  print?
    1. Properties {  
    2.     _MainTint ("Diffuse Tint", Color) = (1,1,1,1)  
    3.     _MainTex ("Base (RGB)", 2D) = "white" {}  
    4.     _NormalMap ("Normal Map", 2D) = "bump" {}  
    5.     _Cubemap ("Cubemap", CUBE) = ""{}  
    6.     _ReflAmount ("Reflection Amount", Range(0,1)) = 0.5  
    7. }  
  2. 然後,我們需要在SubShader塊聲明這些properties,使得我們能夠訪問Properties塊中的這些資料:
    [plain] view plain copy  print?
    1. CGPROGRAM  
    2. #pragma surface surf Lambert  
    3.   
    4. samplerCUBE _Cubemap;  
    5. sampler2D _MainTex;  
    6. sampler2D _NormalMap;  
    7. float4 _MainTint;  
    8. float _ReflAmount;  
  3. 然後,修改Input結構體。這是基於法線貼圖的反射的精華所在。通過使用INTERNAL_DATA聲明,我們可以訪問經過法線貼圖修改後的平面的法線資訊:
    [plain] view plain copy  print?
    1. struct Input {  
    2.     float2 uv_MainTex;  
    3.     float2 uv_NormalMap;  
    4.     float3 worldRefl;  
    5.     INTERNAL_DATA  
    6. };  
  4. 最後,我們需要修改surf函數,來得到最後的基於法線貼圖的反射效果:
    [plain] view plain copy  print?
    1. void surf (Input IN, inout SurfaceOutput o) {  
    2.     half4 c = tex2D (_MainTex, IN.uv_MainTex);  
    3.       
    4.     float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;  
    5.     o.Normal = normals;  
    6.       
    7.     o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;  
    8.     o.Albedo = c.rgb * _MainTint;  
    9.     o.Alpha = c.a;  
    10. }  
 最後,整體代碼如下:[plain] view plain copy  print?
  1. Shader "Custom/NormalMappedReflection" {  
  2.     Properties {  
  3.         _MainTint ("Diffuse Tint", Color) = (1,1,1,1)  
  4.         _MainTex ("Base (RGB)", 2D) = "white" {}  
  5.         _NormalMap ("Normal Map", 2D) = "bump" {}  
  6.         _Cubemap ("Cubemap", CUBE) = ""{}  
  7.         _ReflAmount ("Reflection Amount", Range(0,1)) = 0.5  
  8.     }  
  9.     SubShader {  
  10.         Tags { "RenderType"="Opaque" }  
  11.         LOD 200  
  12.           
  13.         CGPROGRAM  
  14.         #pragma surface surf Lambert  
  15.   
  16.         samplerCUBE _Cubemap;  
  17.         sampler2D _MainTex;  
  18.         sampler2D _NormalMap;  
  19.         float4 _MainTint;  
  20.         float _ReflAmount;  
  21.   
  22.         struct Input {  
  23.             float2 uv_MainTex;  
  24.             float2 uv_NormalMap;  
  25.             float3 worldRefl;  
  26.             INTERNAL_DATA  
  27.         };  
  28.   
  29.         void surf (Input IN, inout SurfaceOutput o) {  
  30.             half4 c = tex2D (_MainTex, IN.uv_MainTex);  
  31.               
  32.             float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;  
  33.             o.Normal = normals;  
  34.               
  35.             o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;  
  36.             o.Albedo = c.rgb * _MainTint;  
  37.             o.Alpha = c.a;  
  38.         }  
  39.         ENDCG  
  40.     }   
  41.     FallBack "Diffuse"  
  42. }  

效果如下(一個表明凹凸不平的反射球):而是不加法線影響的效果(一個光滑的反射球):   解釋 你可能已經注意到這一節的Shader和上一節中的非常類似,而有一個非常重要的不同點(上一節直接使用IN.worldRefl來尋找Cubemap)。我們想要使用逐像素的法線貼圖來修改我們的反射貼圖。為了完成這個目的,我們需要得到在應用法線貼圖後、物體的平面法線資訊。這意味著,我們需要下列代碼:[plain] view plain copy  print?
  1. float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;  
  2. o.Normal = normals;  

一旦上述代碼在Shader中執行後,物體的平面法線將被修改;因此,我們需要使用它來影響我們的反射。我們可以通過聲明INTERNAL_DATA來訪問修改後的法線資訊,然後使用WorldReflectionVector (IN, o.Normal)去尋找Cubemap中對應的反射資訊。這是Unity提供給我們的另一個內建函數,因此我們不需要再自己寫那些冗長的代碼,而僅僅需要關注編寫Shader中產生關鍵效果的部分。   更多… 結構體中還有很多內建函數(變數),而在將來的章節中我們的確會接觸到它們。下面的表格描述了每一個內建函數的作用以及如何使用它們。你也可以訪問官網來得到更多的關於內建函數的資訊: 
float3 viewDir 包含了視角的觀察方向,主要用於計算視差效應(Parallax effects ),邊緣光照,等等。
float4 COLOR 包含了經過插入值(interpolated )的每個頂點的顏色值。
float4 screenPos 包含了用於反射效果的螢幕座標系的位置資訊。例如,在Unity專業版的WetStreet shader中使用了它。
float3 worldPos 包含了全局座標系中的位置。
float3 worldRefl 包含了全局座標系中的反射向量,如果Surface Shader沒有重寫o.Normal。參考Reflect-Diffuse shader。
float3 worldNormal 包含了全局座標系中的法線向量,如果Surface Shader沒有重寫o.Normal。
float3 worldRefl;
INTERNAL_DATA
包含了全局座標系的反射向量,如果Surface Shader重寫了o.Normal。為了得到基於逐像素的法線貼圖的反射向量,請使用WorldReflectionVector (IN,o.Normal) 。參考Reflect-Bumped shader。
float3 worldNormal;
INTERNAL_DATA
包含了全局座標系的發現向量,如果Surface Shader重寫了o.Normal。為了得到基於逐像素的法線貼圖的法線向量,請使用WorldNormalVector (IN,o.Normal) 。參考Reflect-Bumped shader。

【Unity Shaders】Reflecting Your World —— Unity3D中的法線貼圖和反射

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.