【Unity Shaders】Mobile Shader Adjustment—— 什麼是高效的Shader
版權宣告:本文為博主原創文章,未經博主允許不得轉載。
本系列主要參考《Unity Shaders and Effects Cookbook》一書(感謝原書作者),同時會加上一點個人理解或擴充。
這裡是本書所有的插圖。這裡是本書所需的程式碼和資源(當然你也可以從官網下載)。
========================================== 分割線 ==========================================
寫在前面
之前學習的各種Shader時,我們從沒有考慮在所有平臺下的可用性。Unity是一個強大的跨平臺遊戲引擎,但這也決定了在編寫程式碼時我們需要考慮更多的平臺因素。對於Shader而言,如果沒有進行相應的優化,很有可能無法執行在移動平臺等對效能限制較高的平臺上。我們需要理解一些關鍵的因素來優化我們的Shader,以提高遊戲效能而又能儘可能保持取得同樣的視覺效果。
尤其是如果你的目標平臺包括Android系統,那麼就一定要小心中國各種山寨機的大浪一下把你拍在沙灘上的後果。。。所以,如果你從來沒有為你的Shader考慮過這些情況,那麼,且用且小心吧。。。
這一章中,我們會學習三節內容:什麼是一個高效的Shader,怎樣對Shader進行效能分析,為移動平臺優化我們的Shader。
那麼,什麼是一個高效的Shader呢?這是個有點複雜的問題,它涉及到了很多因素。例如,和你使用的變數個數及其所佔記憶體,Shader使用的紋理個數有關等等。還有可能,你的Shade雖然工作良好,但我們實際商可以使用一半數目的變數就可以取得相同的效果。我們將在本節中發掘這樣的一些技巧,並向你說明它們是如何組合起來讓我們的Shader更快更高效的,而又可以各種平臺上取得同樣高質量的視覺效果。
準備工作
我們將首先使用一個最常見的Shader之一:Bumped Diffuse Shader。也就是應用了法線貼圖的Shader。
- 建立一個新的場景和一個球體,新增一個平行光。
- 建立一個新的Shader和Material,可以命名為OptimizedShader001。
- 把Shader賦給Material,把Material賦給球體。
- 最後,使用下列程式碼修改Shader。
簡單的光照函式裡面進行了簡單的漫反射處理,surf函式裡則改變了模型的法線。
最後,你得到的效果大概是這樣的:
實現
下面,我們來一步步優化這個Shader。
首先,我們需要優化變數型別,以便它們儘可能少地佔用記憶體:
- 修改Input結構。之前,我們的UV座標都是儲存在了float2型別的變數中,現在我們將它們改為half2:
- 接下來是光照函式。同樣,將其中float家族的變數改成對應的fixed型別變數:
- 最後,修改surf函式中的變數型別。同樣使用fixed型別變數:
現在,我們可以使用共享UV座標來繼續優化Shader。為此,我們使用_MainTex的UV座標代替_NormalMap的UV在UnpackNormal()中的查詢作用,並移除Input結構中的uv_NormalMap:
最後,我們告訴Unity,這個Shader只工作在特定的渲染器上:
最後優化前後效果如下(左前右後):
可以看出,我們肉眼幾乎看不出任何差別,但是我們已經減少了這個Shader被繪製到螢幕上所花費的時間。我們將在下一節中利用Unity的視覺化工具來分析這種減少程度的大小。但在這裡,我們關注的是,使用了更少的資料來得到相同的渲染效果。在建立我們自己的Shader的時候,也要一直記住這個思想!
解釋
上面一共提到了4種優化方式:優化變數型別,共享UV座標,減少處理的光源個數,讓Shader只工作在特定的渲染器上。下面,我們來更深入地理解這些技術是如何工作的,最後再學習其他一些技巧。
優化變數型別
首先,我們來看一下在我們宣告變數時每個變數儲存的資料大小。由於在宣告變數時,我們往往有多個選擇(float,half,fixed),我們需要來看一下這些型別的特點:
- float:高精度浮點值,通常是32位,也是三者中最慢的一個。它對應的還有float2,float3和float4。
- half:中精度浮點值。通常是16位,範圍是-60000至+60000,它適合儲存UV座標,顏色值等,比float型別快很多。它對應的還有half2,half3,和half4。
- fixed:低精度浮點值。通常是11位,範圍是-2.0至+2.0,精度為1/256。這是三者中最小的一個,可以用於光照計算、顏色等。它對應的值有fixed2,fixed3和fixed4。
- 儘可能使用低精度變數。
- 對於顏色值和單位長度的向量,使用fixed。
- 對於其他型別,如果範圍和精度合適的話,使用half;其他情況使用float。
減少處理的光源個數
這樣做當然很好,但是如果我們需要不止一個平行光,而且想要控制哪一個是用於該逐畫素計算的主光源,又該怎麼辦呢?這就需要Unity皮膚中的一個設定啦!如果你仔細觀察,就會法線每一個光源都有一個Render Mode下拉選單。當你點選它時,會出現Auto, Important, 和Not Important三種選項。通過選擇Important,你可以告訴Unity這個光源更需要被當成一個逐畫素光源,而非一個逐頂點光源。如果設定為Auto,那麼就由Unity自己做決定啦!
懵了是不是。。。為了說明上述意思,我們來做個試驗!在場景裡放置另一個點光源,然後移除Shader中的Main Texture。第一次,開啟平行光,關閉點光源(左圖);第二次關閉平行光,開啟點光源(右圖)。你可以發現第二個點光源並不會影響我們的法線貼圖(只是照亮了模型,也就是它只是逐頂點處理),只有第一個平行光才會影響。
這裡的優化,是由於我們把其他所有光源當成了頂點光源,而在計算畫素顏色時只計算一個主平行光作為畫素光源。
共享UV座標
這步優化很簡單,僅僅使用了Main Texture的UV座標來代替法線貼圖的UV座標,這樣實際上減少了內部提取法線貼圖UV座標的程式碼。這種方法可以很好地簡化我們的程式碼。
只工作在特定渲染器上
最後,我們在語句中宣告瞭,以便告訴Unity,這個Shader不會再接受來自延遲渲染中的其他任何自定義的光照。這意味著,我們僅可以在正向渲染(forward render)中有效地使用這個Shader,這是在主攝像機的設定中設定的。
寫在最後
其他的優化策略還有很多。我們之前學過如何把多個灰度圖打包到一個RGBA貼圖中,以及如何使用一張貼圖來模擬光照效果。由於這些眾多的技術,因此問如何優化Shader是一個很模糊的問題。但是,瞭解這些技術使得我們可以根據不同的Shader和平臺採用合適的技術,來得到一個具有穩定幀率的Shader。
相關文章
- Unity Shader 00 - 梳理 Unity Shader 的基本結構Unity
- unity 統一替換shaderUnity
- Unity 的 Surface Shader有關記錄Unity
- unity shader 溶解,上下左右,cutoffUnity
- Unity3D Shader官方教程翻譯(三)----Shader語法:屬性Unity3D
- Unity3D Shader官方教程翻譯(四)----Shader語法:SubShaderUnity3D
- Unity Shader 入門精要 筆記(1)Unity筆記
- Unity3D 透明物體ShaderUnity3D
- 【Unity Shader入門精要】— 高階篇Unity
- Unity Shader 實現雨天的水面漣漪效果Unity
- Unity&Shader常用函式的使用方法Unity函式
- Unity開發--(三)Shader程式設計:寫一個shader讓圖片的背面不被剔除Unity程式設計
- Unity3D學習筆記3——Unity Shader的初步使用Unity3D筆記
- Unity Shader基於視差對映的雲海效果Unity
- Unity3D中的shader基礎知識Unity3D
- Unity Shader-後處理:Bloom全屏泛光UnityOOM
- Unity3D Shader官方教程翻譯(一)Unity3D
- Unity3D Shader官方教程翻譯(二)Unity3D
- 【Unity3D Shader程式設計】之二 雪山飛狐篇:Unity的基本Shader框架寫法&顏色、光照與材質Unity3D程式設計框架
- Unity Shader之磨砂玻璃與水霧玻璃效果Unity
- Unity Shader- UV動畫原理及簡易實現Unity動畫
- Unity Shader之雙面材質和多Pass渲染Unity
- Shader中的shader_feature與multi_compileCompile
- Unity Shader 基於光照圖的簡易晝夜變化Unity
- Compute Shader
- 【Shader】ComputeScreenPos 的使用
- threejs - src - WebGLProgram是如何組建Shader的?JSWeb
- godot shader 升級Go
- threejs - src - material和shader是如何對應的?JS
- Compute Shader 簡介
- WebGL Shader 環境搭建Web
- OpenGL shader 程式基礎
- Cesium渲染模組之Shader
- Shader:常用結構體結構體
- Android著色器——ShaderAndroid
- 寫一個Geometry Shader
- Godot 字型邊框shaderGo
- Shader 中的顏色計算