標籤:ase 平行光 surf 一個 idt 資訊 doc 沒有 images
http://blog.csdn.net/candycat1992/article/details/24541623
本系列主要參考《Unity Shaders and Effects Cookbook》一書(感謝原書作者),同時會加上一點個人理解或拓展。
這裡是本書所有的插圖。這裡是本書所需的代碼和資源(當然你也可以從官網下載)。
========================================== 分割線 ==========================================
寫在前面 有很多情況你可能想要使用法線去影響反射效果。比如,你想要類比一個被霜雪覆蓋的玻璃材質的表面,或者一個冰塊。如果你根據物理知識真實的類比這個平面的每一個細節部分,那麼你就不要希望你遊戲的FPS還可以達到60幀了。相反的,我們可以使用法線貼圖來偽造一個視覺體驗,因此我們需要學習如何將法線貼圖的資訊傳遞給反射效果。 為了完成這個任務,我們將要學習Input結構體的另一個內建參數,它可以將由法線貼圖技術產生的修改後的平面法線資訊傳遞進來。下面,讓我們來具體看一下如何修改Input結構體來達到這個效果吧! 準備
- 首先,我們需要一個Cubemap來產生反射效果。所以你可以使用前一節中的Cubemap,或者產生一個新的。這一節中,我們使用的如下所示(你可以在本書資源中找到它):
- 我們還需要一張法線貼圖來產生基於法線的反射效果。
- 最後,建立一個新的情境、一個球體、一個平面以及一個平行光。同時,還需要建立一個新的Shader和Material,命名為NormalMappedReflection。
實現
- 首先讓我們添加新的properties,使得我們能夠添加自己的Cubemap和法線貼圖。這個步驟你應該非常熟悉了。向Properties塊添加下列代碼:
[plain] view plain copy print?
- Properties {
- _MainTint ("Diffuse Tint", Color) = (1,1,1,1)
- _MainTex ("Base (RGB)", 2D) = "white" {}
- _NormalMap ("Normal Map", 2D) = "bump" {}
- _Cubemap ("Cubemap", CUBE) = ""{}
- _ReflAmount ("Reflection Amount", Range(0,1)) = 0.5
- }
- 然後,我們需要在SubShader塊聲明這些properties,使得我們能夠訪問Properties塊中的這些資料:
[plain] view plain copy print?
- CGPROGRAM
- #pragma surface surf Lambert
-
- samplerCUBE _Cubemap;
- sampler2D _MainTex;
- sampler2D _NormalMap;
- float4 _MainTint;
- float _ReflAmount;
- 然後,修改Input結構體。這是基於法線貼圖的反射的精華所在。通過使用INTERNAL_DATA聲明,我們可以訪問經過法線貼圖修改後的平面的法線資訊:
[plain] view plain copy print?
- struct Input {
- float2 uv_MainTex;
- float2 uv_NormalMap;
- float3 worldRefl;
- INTERNAL_DATA
- };
- 最後,我們需要修改surf函數,來得到最後的基於法線貼圖的反射效果:
[plain] view plain copy print?
- void surf (Input IN, inout SurfaceOutput o) {
- half4 c = tex2D (_MainTex, IN.uv_MainTex);
-
- float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
- o.Normal = normals;
-
- o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;
- o.Albedo = c.rgb * _MainTint;
- o.Alpha = c.a;
- }
最後,整體代碼如下:[plain] view plain copy print?
- Shader "Custom/NormalMappedReflection" {
- Properties {
- _MainTint ("Diffuse Tint", Color) = (1,1,1,1)
- _MainTex ("Base (RGB)", 2D) = "white" {}
- _NormalMap ("Normal Map", 2D) = "bump" {}
- _Cubemap ("Cubemap", CUBE) = ""{}
- _ReflAmount ("Reflection Amount", Range(0,1)) = 0.5
- }
- SubShader {
- Tags { "RenderType"="Opaque" }
- LOD 200
-
- CGPROGRAM
- #pragma surface surf Lambert
-
- samplerCUBE _Cubemap;
- sampler2D _MainTex;
- sampler2D _NormalMap;
- float4 _MainTint;
- float _ReflAmount;
-
- struct Input {
- float2 uv_MainTex;
- float2 uv_NormalMap;
- float3 worldRefl;
- INTERNAL_DATA
- };
-
- void surf (Input IN, inout SurfaceOutput o) {
- half4 c = tex2D (_MainTex, IN.uv_MainTex);
-
- float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
- o.Normal = normals;
-
- o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;
- o.Albedo = c.rgb * _MainTint;
- o.Alpha = c.a;
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
效果如下(一個表明凹凸不平的反射球):而是不加法線影響的效果(一個光滑的反射球): 解釋 你可能已經注意到這一節的Shader和上一節中的非常類似,而有一個非常重要的不同點(上一節直接使用IN.worldRefl來尋找Cubemap)。我們想要使用逐像素的法線貼圖來修改我們的反射貼圖。為了完成這個目的,我們需要得到在應用法線貼圖後、物體的平面法線資訊。這意味著,我們需要下列代碼:[plain] view plain copy print?
- float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
- 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中的法線貼圖和反射