0.ShaderVariant和multi_compile編譯Shader的多個版本

 
一ShaderVarian的使用
1. 首先在CGPROGRAM 下 申明 須要多版本編譯的 幾個版本的key,Material同一時刻只能對應它所使用的Shader的一個variant。
            #pragma multi_compile A B
若是C#代碼沒指定,Unity會默認使用 A這個編譯版本。
           當B打開,Unity使用 B這個編譯版本。 當B關閉,即便咱們沒有在C#中顯式的打開A,也會使用A版本。
2. 在CGPROGRAM裏的cg代碼中 ,控制邏輯,
  不能用在外面,而且不能使用 elseif
#ifdef A
XXXX
#endif
 
#ifdef B
XXXX
#endif
 
 
3.在C#代碼裏使用Material.EnableKeyword("A")和Material.DisableKeyword("A")來開關對應的宏
  Material.EnableKeyword(keyword: string)/DisableKeyword(keyword: string)  //是全局設置
     someMaterial.EnableKeyword(keyword: string)/DisableKeyword(keyword: string)  //也能夠對某個材質單獨設置
 
  Shader.EnableKeyword(keyword: string)/DisableKeyword(keyword: string)//是全局設置
  XXXXShader.EnableKeyword(keyword: string)/DisableKeyword(keyword: string)//也能夠對XXXXShader單獨設置
 
二,注意事項
 multi_compile和shader_feature的區別
1.若是你在shader中添加了
1 #pragma multi_compile  _A _B
2 #pragma multi_compile  _C _D
  那麼不管這些宏是否真的被用到,你的shader都會被Unity編譯成四個variant,分別包含了_A _C,_A _D, _B _C,_B _D四種keyword組合的代碼
2.若是是
1 #pragma shader_feature _A _B
2 #pragma shader_feature _C _D
  那麼你的shader只會保留生成被用到的keyword組合的variant,至於如何斷定哪些組合被用到了,等後面提到Assetbundle時候再說。
 
 
4. 不要頻繁用此命令,由於關鍵字的個數是有上限的,而多條multi_complie會交叉匹配產生不少種結果。
 
5. 在屬性列表 能夠給出選項
    Properties {
 
[KeywordEnum(None, Ice)] _Overlay ("Overlay mode", Float) = 0
}
 
 
三,一些BUG。。。
可是這裏有個BUG,當你在編輯器面板手動選擇一個KEY後,mat的key也只有一個了, 在PC上好用,打包Assetbundle後也只有這個版本。
 

 

6.嘗試用NotePad++打開.mat文件(須要在編輯器設置裏把AssetSerializationMode設置爲Force Text):
若是多版本編譯成功,會看到紅圈裏的幾個版本
 
若是

 

不成功,或者沒有多版本,則 後面爲空
7. 注意事項:
   在編輯器上, 即便打開mat上的m_ShaderKeywords爲空,多版本編譯也是沒問題的, 由於是動態編譯。在代碼裏切換表現正常。
   當打包AssetBundle到手機或者PC版本,則沒法切換了。
    若是你手頭有built-in Shader的源碼能夠打開裏面的StandardShaderGUI.cs看一下Unity本身事怎麼處理對於StandardShader的keyword設置的。
  
   因此,若是出現m_ShaderKeywords爲空,則把材質切換爲另外一個材質,先保存,再切換回來,在保存
 
 
 

 

四:解決方案
解決方法1:把Shader放到在ProjectSetting->Graphics->Always Include Shaders列表裏,
把該shader加入項目設置,
 

 

同事在項目的設置裏默認爲 strip Unused,打包會跳過Unused的變量。 設置爲keep,則能夠打包出全部shader。
 
解決方法: 使用ShaderVariantCollection
         ShaderVariantCollection可讓我指定某個shader要編譯都要編譯帶有哪些keyword的變種。
        而且在ProjectSetting->Graphics界面新加了一個Preloaded Shaders列表。
 

 

若是不放這裏,也可使用代碼加載
 
ShaderVariantCollection shaderVariantCollection = Resources.Load <ShaderVariantCollection>( "MainShaderVariant");
if (shaderVariantCollection )
      shaderVariantCollection.WarmUp ();
 
這種好處:不會像Always Include Shaders列表中的那樣所有變種都生成。
 
 
 
 
      放到AB包就又涉及到shader_feature的處理,爲了在運行時動態切換材質的shadervariant,能夠在工程裏新建一堆材質,而後把每一個材質設置成一種想要的keyword組合,把他們和shader放到一塊兒打到一個AB中去,這樣雖然能讓shadervariant正確生成,可是這些Material是徹底多餘的。
  爲了解決這種問題,Unity5.0之後引入了ShaderVariantCollection(下面簡稱SVC),這裏不講用法,只說問題,這個SVC文件可讓我指定某個shader要編譯都要編譯帶有哪些keyword的變種。而且在ProjectSetting->Graphics界面新加了一個Preloaded Shaders列表,可讓你把SVC文件放進去,編譯時指定的Shader就會按照SVC中的設置進行正確的variant生成,而不會像Always Include Shaders列表中的那樣所有變種都生成。
  可是它在AB中的表現可就不盡如人意了,要讓它起做用,就必須把它和對應的shader放在一個AB中,並且除了5.6之外版本,我試了幾個都不能正確使用,不是一個variant都沒生成,就是隻生成一個shadervariant(和放一個沒有設置keyword的材質效果同樣).你能夠本身用UnityStudio打開查看一下生成的AB內容。
 
 
解決方法3:把Shader放到Resources文件夾下,也會正確處理,我猜也應該是所有keyword組合都編譯,有知道的同窗,麻煩留言告訴我。
 
 
解決方法4:用工具生成與該shader對應的 ShaderVariantCollection,與這個shader打到同一個bundle裏。
 
 
解決方法5: 放到AB包就又涉及到shader_feature的處理,爲了在運行時動態切換材質的shadervariant,能夠在工程裏新建一堆材質,而後把每一個材質設置成一種想要的keyword組合,把他們和shader放到一塊兒打到一個AB中去,這樣雖然能讓shadervariant正確生成,可是這些Material是徹底多餘的。
 
 
4、建立ShaderVariantCollection
       4.一、全手工建立
       這是最笨的一種方法,須要本身在Project視圖下建立ShaderVariantCollection資源,而後使用上面介紹的兩個窗口本身添加着色器變體
 
 
       4.二、使用Unity收集當前使用到的着色器變體
       爲了最快速、最方便的幫助咱們建立和收集那些真正被用到的着色器和他們的變體,Unity已經在編輯器中內置了能夠追蹤那些已經被使用到的着色器和他們的變體,並能夠直接生成相應的ShaderVariantCollection資源。
       打開圖形設置面板(Edit->Project Settings->Graphics)
 
 
 
 
       這時候只須要依次打開咱們的全部場景,把須要的物體都顯示一遍,Unity就會自動記錄下來哪些着色器的哪些着色器變體已經被使用到。統計完後只需點擊下面的保存按鈕就能夠生成咱們所須要的ShaderVariantCollection資源。固然你也能夠爲你的每個場景或者按需生成足夠多的ShaderVariantCollection資源。
 
 
 

 ShaderVariant與Assetbundle的關係

  我所遇到的問題正是和Assetbundle有關,緣由是打成AB包以後shader_feature所定義的宏沒有被正確包含進去。
  上面說了multi_compile定義的keyword是必定能正確的生成對應的多種組合的shaderVariant,但shader_feature不盡然,Unity引入shader_feature就是爲了不multi_compile那種完整編譯所致使組合爆炸,不少根本不會被使用的shader_variant也會被生成。Unity在處理shader_feature時會判斷相應的keyword組合是否被使用
  1.若是shader沒有與使用它的材質打在一個AB中,那麼shader_feature的全部宏相關的代碼都不會被包含進AB包中(有一種例外,就是當shader_feature _A這種形式的時候是能夠的),這個shader最終被程序從AB包中拿出來使用也會是錯誤的(粉紅色).
  2.把shader和使用它的材質放到一個AB包中,可是材質中沒有保存任何的keyword信息(你在編輯器中也是這種狀況),shader_feature會默認的把第一個keyword也就是上面的_A和_C(即每一個shader_feature的第一個)做爲你的選擇。而不會把_A _D,_B _C,_B _D這三種組合的代碼編譯到AB包中。
  3.把shader和使用它的材質放到一個AB包中,而且材質保存了keyword信息(_A _C)爲例,那麼這個AB包就只包含_A _C的shaderVariant.
  能夠看到shader_feature所定義的keyword產生的ShaderVariant並非所有被打包到AB中,特別是你想在遊戲運行時動態的經過EnableKeyWorld函數來進行動態修改材質使用的shaderVariant,若是一開始就沒有把對於variant放進AB包,天然也就找不到。
相關文章
相關標籤/搜索