【Unity Shaders】Mobile Shader Adjustment —— 為手機定製Shader
阿新 • • 發佈:2019-02-13
這裡是本書所有的插圖。這裡是本書所需的程式碼和資源(當然你也可以從官網下載)。
========================================== 分割線 ==========================================
寫在前面
在上一篇裡,我們學習了一些技巧來初步優化Shader。這次,我們學習更多的技術來實現一個更復雜的Shader:Normal-Mapped Specular Shader。這些技術包括:使用光照函式的兩個新變數halfasview或者approxview,減少使用的貼圖數量,以及對貼圖進行更好的壓縮。
準備工作
- 建立一個新的場景和一個球體,新增一個平行光。
- 建立一個新的Shader和Material,可以命名為MobileShader。
- 把Shader賦給Material,把Material賦給球體。
實現
- 首先,還是修改Properties塊。本節我們需要一張diffuse貼圖,它的alpha通道值對應畫素的光滑度(Gloss);以及一張法線貼圖,和高光指數的滑動條。
Properties { _Diffuse ("Base (RGB) Specular Amount (A)", 2D) = "white" {} _NormalMap ("Normal Map", 2D) = "bump"{} _SpecIntensity ("Specular Width", Range(0.01, 1)) = 0.5 }
解釋:一直沒有徹底搞懂Unity SurfaceOutput裡面各變數的計算細節。這裡再詳細解釋下。SurfaceOutput裡面的內建變數可以見這篇,如下:struct SurfaceOutput { half3 Albedo; // 該畫素的反射率,反應了畫素的基色 half3 Normal; // 該畫素的法線方向 half3 Emission; // 該畫素的自發光顏色,使得即便沒有光照也可以物體本身也可以發出光 half Specular; // 該畫素的高光指數 half Gloss; // 該畫素的高光光滑度,值越大高光反射越清晰,反之越模糊 half Alpha; // 該畫素的不透明度 };
- 下面是建立#pragma宣告。這可以控制Surface Shader各屬性的開關,使得Shader更高效或者更低效:
CGPROGRAM #pragma surface surf MobileBlinnPhong exclude_path:prepass nolightmap noforwardadd halfasview
解釋:忽略延遲光照,不支援光照貼圖,只接受一個單一的平行光光源作為逐畫素光源。最後,使用halfasview宣告告訴Unity,我們使用一個介於光照方向和觀察方向之間的half vector來代替真正的觀察方向viewDir來計算光照函式。這將加速Shader的處理時間,因為這是基於逐頂點而非逐畫素計算而得的。雖然這樣得到的結果是近似值,但對於移動平臺來說足夠了。 - 建立和Properties塊中各變數的聯絡。和之前不同,我們這次使用fixed來得到高光指數滑條的值:
sampler2D _Diffuse; sampler2D _NormalMap; fixed _SpecIntensity;
- 得到貼圖的UV座標。在上一篇就提過,為了節省變數空間,我們僅使用一個UV值:
struct Input { half2 uv_Diffuse; };
- 由於我們在宣告中添加了新的變數,我們可以在光照函式中使用新的引數:
inline fixed4 LightingMobileBlinnPhong (SurfaceOutput s, fixed3 lightDir, fixed3 halfDir, fixed atten) { fixed diff = max (0, dot (s.Normal, lightDir)); fixed nh = max (0, dot (s.Normal, halfDir)); fixed spec = pow (nh, s.Specular * 128) * s.Gloss; fixed4 c; c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2); c.a = 0.0; return c; }
- 最後,我們在surf函式中完成對畫素顏色的計算:
void surf (Input IN, inout SurfaceOutput o) { fixed4 diffuseTex = tex2D (_Diffuse, IN.uv_Diffuse); o.Albedo = diffuseTex.rgb; o.Gloss = diffuseTex.a; o.Alpha = 0.0; o.Specular = _SpecIntensity; o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_Diffuse)); }