在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...