Unity5.x shader打包AssetBundle總結


最近比較忙,好久沒有更新博客了,新項目切換到unity5.x后使用了新的打包機制,在打包shader的時候遇到了一些問題,這里來記錄一下吧。

 

在上一個項目中,我們使用unity4.7,對於shader並沒有進行依賴打包,而是由unity打包到了每個用到的AssetBundle中去,其實這樣是“很不科學的”。這樣不僅增加了ab的總體積,而且還會在運行時產生很多的shader實例,增加很多的顯存占用。所以我們決定把自定義的shader打包成一個AssetBundle。

 

用到的工具:

1、UnityStudio:https://github.com/Perfare/UnityStudio/releases

這是一個解包AssetBundle的工具,可以查看和導出ab中的資源。

2、Unity自帶的profiler

 

下面是一些嘗試和結果分析:

 

一、不進行依賴打包(不需要設置GraphicsSetting,不給自定義shader設置AssetBundle Name)

這種情況unity5.x還是與unity4.x一樣,把shader打包到每一個使用它的AssetBundle 中去,這樣就會同時存在多個一樣的shader,並在運行時產生多個shader實例。

如下圖:

這個Character是我們自定義的一個shader,在運行時產生了多個實例:

 

使用UnityStudio解包一個ab可以看到,我們自定義的shader ParticlesAlphaTintColor被打包到ab中:

 

 

 

打包后的運行測試結果如下:

1、編輯器是pc平台的時候,打出來的包在編輯器里運行是正常的。

2、編輯器是安卓時,打出來的包在編輯器里運行顯示粉紅(查看材質可以發現並不是丟失材質和shader),但在手機正常。

這是為什么呢?這是因為以安卓為平台打包的時候被打包的shader被編譯成安卓平台的版本,在unity編輯器中運行會發生異常。這是從4.x到5.x一直有的問題。

解包后我們可以看到不同平台編譯出來的shader subProgram不同。

Pc:

 

安卓:

 

 

二、依賴打包(將shader設置AssetBundle Name打包)

使用這種方式,需要將shader添加到GraphicsSetting-> always included shader設置中,否則shader也會顯示粉紅。注意要在設置Graphics之后把shader重新打包,在能生效。

文檔中也有說到:https://docs.unity3d.com/Manual/class-GraphicsSettings.html

 

 

測試結果如下:

1、編輯器是pc平台的時候,打出來的包在編輯器里運行是正常的。

2、編輯器是安卓時,打出來的包在編輯器里運行顯示粉紅(查看材質可以發現並不是丟失材質和shader),但在手機正常,原因同上。

 

再使用profiler查看,可以發現shader可以被物體共用了,隨着物體數量的增加也不會產生多個shader實例。(下圖有兩個Character是因為編輯器中ShaderVariantCollection跟蹤到了這個shader,也算一個引用)

 

這時解包模型的ab,也不會看到shader被打進ab中了,它們只存在與自己的ab包中。

 

三、注意事項

1、細心的朋友會發現,一中我們profiler中看到的Character是45.7k,而二中是334k,這是因為Character是一個多變體的shader,而加入了GraphicsSetting-> always included shader后,會將它所有的變體打包到游戲中。

 

2、在測試打包的過程中我發現一個有趣的現象--- unity5.4和4.x打包后的shader解包(非依賴打包)出來看起來不一樣:

 

5.4沒有看到代碼,而是看到GPUProgramID

 

而4.7是直接看到代碼

 

 

結合最新更新的unity5.5的更新日志,似乎可以看出點端倪:

https://unity3d.com/cn/unity/whats-new/unity-5.5.0

---Shaders: Shaders are now exported to the Unity player completely in binary. There is no Shader text string and parsing in run time.

 

3、關於untiy內置shader

如果沒有設置到GraphicsSetting-> always included shader中,那么會打包到依賴它的ab中,如果設置了就不會打包進去。而是再構建的時候,就導入到你的游戲。

 

4、手動設置shader 加入GraphicsSetting-> always included shader很麻煩,怎么辦?

其實是可以使用代碼設置的:

來自:http://www.hiwrz.com/2016/04/18/unity/175/

 

[csharp]  view plain  copy
 
  1. [MenuItem("Test/測試設置included shader", false, 11)]  
  2.  public static void TestIncludedShader()  
  3.  {  
  4.      string[] myShaders = new string[1]{  
  5.          "Legacy Shaders/Diffuse"  
  6.      };  
  7.    
  8.      SerializedObject graphicsSettings = new SerializedObject (AssetDatabase.LoadAllAssetsAtPath ("ProjectSettings/GraphicsSettings.asset") [0]);  
  9.      SerializedProperty it = graphicsSettings.GetIterator ();  
  10.      SerializedProperty dataPoint;  
  11.      while (it.NextVisible(true)) {  
  12.          if (it.name == "m_AlwaysIncludedShaders") {  
  13.              it.ClearArray();  
  14.    
  15.              for (int i = 0; i < myShaders.Length; i++) {   
  16.                  it.InsertArrayElementAtIndex(i);  
  17.                  dataPoint = it.GetArrayElementAtIndex (i);  
  18.                  dataPoint.objectReferenceValue = Shader.Find(myShaders[i]);  
  19.              }  
  20.    
  21.              graphicsSettings.ApplyModifiedProperties ();  
  22.          }  
  23.      }  
  24.  }  



 

5、加入AlwaysIncludedShaders的shader是開始游戲的時候就全部編譯了嗎?

答案是不會,加到always include 的shader,會將shader的所有變體打包到游戲,用到的時候才會加載用到的變體到內存!需要預加載變體可以使用:ShaderVariantCollection

相關文檔:https://docs.unity3d.com/Manual/OptimizingShaderLoadTime.html

 

值得注意的是unity5.x內置的  Standard shader是一個有成千上萬變體的shader,要謹慎的把它加入到GraphicsSetting-> always included shader,因為1中的原因,會使得你的包體非常大,打包也非常耗時。至少在我測試下是一直卡在這個界面到下班都沒有響應。。

文檔里面也有提到:

 

6、關於shader加載和預熱的一些資料:

Unity - Manual: Optimizing Shader Load Time

https://docs.unity3d.com/ScriptReference/ShaderVariantCollection.html

http://www.seven-fire.cn/archives/174

https://www.zhihu.com/question/30087487

https://zhuanlan.zhihu.com/p/21949663


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM