Unity中Shader是否可以熱更新的測試

2021-09-25 20:02:18 字數 4285 閱讀 5003

在unity的資源中,shader是比較特殊的一類。主要有下面幾個疑問

1. shader算是**,並且需要編譯。那麼是否可以熱更新?

2. ab中載入進來的shader是否可以通過shader.find(名稱)來索引?

3.在使用shader_feature關鍵字後,build時忽略的變種是否要在執行時編譯?

4.預編譯shader cache的儲存位置究竟在**?

直接補充最終結論:

1. shader可以熱更新。

2. 使用multi_compile生成shader variant時,材質可以直接熱更新。

3. 使用shader_feature生成shader variant時,可以使用shadervariantcollection來記錄所有使用到的變種,實現材質更新。(目前仍有bug,必須將shader、svc和所有材質放在乙個ab中)

4. 不要用shader.find找自己包裡的shader,使用assetbundle.loadasset()

5. shadercache隨材質儲存,材質可以熱更新。

針對以上問題我做了一系列測試,記錄如下:

測試一:

準備乙個shader ,乙個材質,乙個cube做的prefab,各自打成乙個ab。

在乙個空場景中用指令碼按如下順序載入:

shaderab->materialab->prefabab->prefab->gameobject。顯示正常。

(事實上只要保證prefabab->prefab->gameobject的順序,materialab和shaderab在同一函式的任意位置都可以。unity應該是延遲處理了資源的引用關係)

修改shader,打成新的ab,改名或者另存為備用。

發布以後,在資料夾中找到對應的shaderab,使用新的shaderab替換。

重新啟動,效果已經更新。

結論一: shader可以熱更新!

測試平台:android和pc standalone

**稍作修改可以在執行時實現熱更新。

測試二:

準備3個shader,引用同乙個標頭檔案。shader和cginc全部進入乙個ab裡。

執行時先載入shaderab,然後用乙個按鈕切換shader

結果如下表:

熱更新前

熱更新後

shader.find

正常(原shader)

錯誤(shader丟失)[1]

assetbundle.loadasset[2]

正常(原shader)

正常(新shader)

[1]    在standalone或者移動平台上會有shader丟失;在editor模式下會使用舊的shader,仔細分析後猜測是在editor模式下,shader.find的查詢順序如下:已載入的 assetbundle->shader原始檔。而在發布平台上,由於沒有散的shader原始檔,所以直接丟失。

[2]    assetbundle.loadasset的路徑要使用manifest中記載的路徑,如下形式:

assets/shaders/src/shadertest2.shader

結論二:可以在執行時手動替換上ab中的shader,但必須使用assetbundle.loadasset

·可以使用cginc標頭檔案!

·可以使用資料夾管理shader!

·最好完全不使用shader.find,除非你100%確定這個shader不會熱更新。

關於shader.find,個人猜測如下:

unity內部使用乙個字典或者hashset來支援shader.find,這裡暫且叫它shadermap。shadermap的鍵是shaderlab語法中的名字;值是shader檔案的guid。

shadermap生成於build專案時,儲存了來自三個地方的shader cache引用關係:

1.      resources中的shader或resources其中其他資源引用到的shader

2.      任意場景中引用到的shader

3.      streamingassets中asset bundle內的shader

執行時使用shaderfind,只能找到這些shader,如果對應guid的shader不存在,查詢就會失敗,即使熱更新後加入了新的asset bundle中含有同名shader(即shaderlab語法同名)。

4.      目前沒有辦法在發布以後動態更新shadermap。

測試三:

準備兩個同樣的shader,設定好#ifdef feature,其一使用multi_compile,其二使用shader_feature

準備四個材質,分別對應

·multi_compile      feature on

·multi_compile      feature off

·shader_feature   feature on

·shader_feature   feature off

所有shader打成乙個ab, 所有material打成乙個ab

在執行時切換4個材質。結果如下:

·multi_compile   feature off

正常·multi_compile   feature on

正常·shader_feature  feature off

正常·shader_feature  feature on

錯誤(和shader_feature  feature off一樣)

結論三:

·使用shader_feature的uber shader無法熱更新!

(結論已更新)

·若將shader儲存於自定義ab時,僅按照所有shader_feature都沒有定義的方式來編譯。並且不會匯報這個編譯過程中的任何錯誤!(如:在shader中定義了shader_feature a b;並且依賴於a、b二者任一必須定義的話,編譯就會出錯。)

·unity並不會在發布平台上編譯缺失的變種。(直接拿個現有的變種湊數?)

測試四放棄熱更新shader,檢查在使用shader_feature的時候,材質能否熱更新。即能否在熱更新時生成缺失的變種。

準備乙個uber shader。再來3個材質,各使用不同的變種,並分別打成m1,m2,m3三個包。發布時僅選擇m1發布,然後在執行時熱更新,使用m2,m3替換m1,顯示效果達到預期。

這時候注意到m1,m2,m3體積分別為11,9,11kb,應該不只是存有shader引用和相關引數。因此再將m1,m2,m3打為乙個ab,體積為11kb。

結論四:

·在shader進入mainassets的前提下,材質可以熱更新。

·shader cache隨material ab儲存,多個引用了同樣shader(變種)的材質會重複儲存cache。

更新測試五

使用shadervariantcollection,記錄所有用到的variant。

將svc和shader打入乙個shaderab。

將材質打成materialab

執行時載入shaderab,取svc,warmup,再載入materialab。結果丟失部分variant

更換分包方式,svc、shader和material打成乙個包。一切正常。

結論五:

·使用shadervariantcollection可以做到帶變種的材質更新。

·目前版本(5.6.0和5.5.2)依然有bug,必須將svc、shader和所有對應材質放在一起才能做到可熱更新。

備註:·為了測試,我用hfs配置了區域網http伺服器,只要在同乙個無線網端下,pc和手機都能訪問,配合不同平台的ab分資料夾管理,所有平台都能同步看到效果。

·ab.unload()會把ab設為null!

·cginc標頭檔案修改後,所有用到的shader必須手動import一次以強制重新編譯!

測試二用到的工程(ab和熱更新)

unity中shader的Cutout問題

unity中自帶的shader裡有cutout型別的shader,今天發現這種型別很詭異,先 貼幾種自帶的 shader transparent cutout diffuse cutoff alpha cutoff range 0,1 0.5 subshader lod 200 cgprogram ...

Unity中的Shader的形態

unity通過shaderlab來組織shader 作為一款號稱跨平台性最好的遊戲開發引擎,unity使用自定義使用mono這個開源的.net來實現。對於要適應不同的gpu的shader來說,unity使用自定義shaderlab來組織shader的內容,並會針對不同的平台進行編譯。1.關鍵字sha...

unity中頂點片段shader環境反射

最近具體聯絡了一下裡面shader的基本寫法,弄來個綜合版本 然後就是最難看出差異的反射計算問題,頂點裡面計算和片段裡面計算的區別 使用的模型是這個,其中右邊的是平滑法線後的模型 具體的差異可以看下面gif圖 可以看出 下面是 shader unlit shenmifangkeshader norm...