當前位置:
首頁 > 最新 > 必讀!使用ILRuntime來實現熱更新的優與劣!

必讀!使用ILRuntime來實現熱更新的優與劣!

這是第103篇UWA技術知識分享的推送。今天我們繼續為大家精選了若干和開發、優化相關的問題,建議閱讀時間15分鐘,認真讀完必有收穫。文末,我們的互動話題是,NGUI和UGUI這兩個UI系統,你用過/ 正在/ 將來會選擇哪個呢?期待你的灼見!

熱更新

Q:使用ILRuntime來實現熱更新的可行度有多高,大家有沒有使用經驗分享?

A:一般熱更新分兩塊,代碼+資源,資源熱更幾乎都是通過AssetBundle來搞,代碼熱更可以用某種解釋器+解釋執行的語言來搞,可供選擇的有Lua、as3、python、js、C#等,據我所知,主流是Lua,次主流是C#。

熱更新的選擇上,我們項目最初所有代碼都是C#寫,不考慮熱更新。因為團隊沒人會Unity3D,全是邊學邊做,」做出來」是第一要務。上線後自然頂不住運營的壓力:在中國很多Android渠道的情況下,運營的這個需求是合理的,否則每次版本更新,各個渠道審核和上線的時間同步是非常困難的。

然後我們首先用XLua打補丁修Bug:成本最低,後來運營要求能通過熱更加功能,而不僅僅是改Bug,那麼要麼用Lua寫所有可能會被熱更新的代碼,這需要把現有的大量C#代碼翻譯過來;要麼想辦法讓C#能熱更新。於是很自然的就選擇了後者+ILRuntime.

最後的技術方案是這樣:

1. 基本限制

熱更部分的代碼都不繼承MonoBehaviour,也就是都不掛腳本,非熱更部分隨意:熱更對MonoBehaviour這種比較特殊東西的支持都挺麻煩,要麼不用,要麼只是做個不可熱更的消息轉發層;要麼開發時掛腳本,打包時用某種特殊的方式把它變成代碼里動態AddComponent。

2. Android

不用任何第三方的熱更方案,用C#反射執行DLL,性能和代碼寫法和純C#基本一樣。

Google Pay強制要求在2019年8月之前App都支持64位,Unity的應對方案是Android IL2cpp,暫時沒有支持mono backend 64位的打算。所以到時候只能是IL2CPP+ ILRuntime的方式,性能會差一大截,主要慢在ILRuntime上。

3. iOS

ILRuntime + DLL 解釋執行,當然是在IL2CPP下。

4.優點

語言(C#)開發環境工具鏈統一,隨時可以變成不支持熱更形式,如果蘋果未來不允許任何解釋執行的方式。

框架搭好後,滿足一些限制條件(非硬性限制,主要是避免麻煩,限制主要是1個,可熱更部分的代碼不要繼承不可熱更的代碼, 不繼承MonoBehaviour是這個限制的子集),寫邏輯的同學開發方式和原生C#開發完全一樣,包括調試。

第三方插件直接可用(大部分插件都是基於C#寫的).

5.缺點

穩定性的坑還是有一些:通常發生於一些相對高級的語言特性組合,特別是各種反射代碼。另外.net4.6的asyncwait所支持的現在版本應該也還不夠穩定,純計算的性能弱於Lua,計算密集型的代碼還是想辦法放在不可熱更新的部分吧。

歷史短,Git貢獻者少,項目考驗少(據我的了解,上線的商業項目在x - 1x之間,具體的項目有MMO,SLG,休閑,也有棋牌),原理上大的優化空間沒有,小的優化空間還是有一些;另外整合了各種常用Feature的框架也少 。

感謝UWA問答社區 @GX提供了回答,歡迎大家轉至社區進行進一步交流:

https://answer.uwa4d.com/question/5a9fc420d35eb22c10a0a365

製作

Q:我們知道Unity自建的Cube是24個頂點,而不是8個。我們在Max中自建一個Cube轉換成Polygon,不加任何的UV處理,我們希望導出的頂點數量可控(可為8),但我們發現默認導出的FBX頂點數量一定是24個。為何? 如何精確控制其數量?

UWA:這個問題主要是看模型中「相鄰面的頂點是否可以共用法線」。如果可以,那麼只需要一個頂點來表示;如果不可以,則需要分為兩個頂點(位置相同,法線不同)。而「是否可以共用法線」,在Max里可以通過光滑組來控制,而在Unity里可以通過Smoothing Angle來控制(類似於相鄰面夾角小於多少的時候可以共用法線)。

所以,題主可以嘗試在Max里添加光滑組並導出;也可以在導入Unity後,把Normal一項設為Calculate,通過Smoothing Angle來控制。為了更好地說明是否合併法線對光照效果的影響,左圖是Smoothing Angle為0(基本不合併法線,頂點數最多,為7676),右圖為1(最大程度合併法線,頂點數最少,為3260)。

該回答由UWA提供,歡迎大家轉至社區進行進一步交流:

https://answer.uwa4d.com/question/5aa786ad0b827e2c0bfdd13b

製作

Q:請問在手游中如何實現晝夜交替的方法呢?我考慮了動態載入Lightmap,但是漸變的過渡,會顯得比較突兀。如果是實時光的話,性能壓力又比較大。請問移動端晝夜交替的實現方法,大家有什麼思路呢?萬分感謝!

A:美術烘焙兩套或者更多的Lightmap,然後遊戲運行時通過RenderToTexture的方式來動態blend兩張Lightmap,然後把結果拿去使用,混合過度完成後,切換正式的Lightmap,過渡Lightmap就可以丟了。

可能需要注意下Lightmap的編碼格式需要在混合前解碼一下,混合好了之後編碼回去。總之,移動平台下壓縮格式混合後有一些誤差,不過能接受。

感謝UWA問答社區 @Lujian提供了回答

A:有一種山寨的做法,就是美術要烘出白天和黑夜的兩套(如果有多種自然環境的可以烘多套)。

1)動態載入下一自然環境所要用到光照貼圖當成全局貼圖;

2)用時間做一個係數,光照貼圖解碼時,對當前的光照貼圖和第1部載入的光照貼圖進行插值就好了。(白天向黑夜轉換),解碼的地方在UnityGlobalIllumination這個函數里;

3)用時間做一個係數,適當再去調一下環境光。

這樣做的前提是,你們的場景的光照貼圖張數比較少,否則會比較尷尬。

感謝UWA問答社區 @kent提供了回答

A:我們項目也做了晝夜系統,不是我做的,邀請了對應的同事來回答,不知道有沒有時間,我先說兩句思路上的東西。

我們沒有採用兩套光照貼圖的思路,利弊比較明顯:好處就是多套光照貼圖可以做較好的效果,點光源啊,GI啊,AO啊都可以有,壞處就是包體佔用會大些,過度漸變有些麻煩。如果是ARPG那樣的切換場景的比較合適,大世界的玩家如果一直在一個場景里的可能稍微麻煩些。

我們最初設計的場景里大都是野外場景,點光源之類的變動需求很小,因此晝夜系統的思路沒有選擇多套Lightmap的方案,而是使用修改材質參數的方案來做。

1)第一個版本用了lut,漸變就用兩張lut貼圖的過渡差值來做,消耗基本可以,但是因為是全屏的後處理,也沒有HDR,特效的部分會導致也被壓暗了,美術試用一段時間後不滿意;

2)第二個版本基於材質參數的思路來做,美術烘焙的是白天的效果,晚上在PS里得出的結果里乘以一個調色值,場景和角色的Shader都要處理,特效的材質不處理,就可以實現整體變暗的效果,基本效果不算出彩,但是可以滿足基本的移動設備上的需求,性能也可以接受。

3)天空盒、方向光亮度、環境光、角色反射Cube跟隨晝夜做切換,主要對角色產生影響。

4)夜晚的時候,建築窗戶、燈籠自發光的部分調整強度,可以表現出更好的夜晚百家燈火的效果。

思路和切換光照貼圖的思路不同,供參考,運行時消耗比切換光照貼圖的思路要大一點,好處也就是節省美術的工足量,節省一些包體,過度也好做一些,方便做黃昏、早晨這樣的效果,但是效果不是最好的,手游上基本夠用。可能還有很多細節我不了解,回頭看同事有時間再來補充吧。

感謝UWA問答社區 @賈偉昊提供了回答

歡迎大家轉至社區進行進一步交流:

https://answer.uwa4d.com/question/5aa9d6f4d35eb22c10a0a3cf

資源管理

Q:請教AssetBundle Diff Patch方案是否可行嗎?我原先的更新方案是比對AssetBundle文件的hash值,直接替換整個AssetBundle和manifest來達到更新效果的,不知道有沒有其它方案類似Diff patch,可以減小更新包體,如果可以做Diff patch,資源顆粒度是不是就可以忽略了。

A:基於AssetBundle的直接Diff更新目前沒有看到成熟的方案,不過只把完整的Resources庫中的部分資源挑出來更新的項目,已經是做了2個了。思路其實很簡單:

1)出整包的時候,用ScriptableObject記錄下AssetsDataBase中所有被發布資源的MD5碼(不能用Unity自己的hash碼);

2)用工具調出哪些assets是代碼中動態Load的,分入一個Resource包中;找出這些資源的依賴資源,分入一個Share包中,並記錄每個Asset所屬的AssetBundle包;

3)出補丁時,對比當前AssetsDataBase中哪些代碼中動態Load的資源出現了增加和改動(刪除可以無視),包括他們依賴的資源。仍然把代碼中動態Load的資源放入ResPatch中,依賴放入SharePatch中。對於沒有變化的資源,仍然維持原來的AssetBundle名字;

4)記錄下此次補丁之後,更新每個Asset所屬的AssetBundle包;

5)下一次補丁時的Resource和Share可能會依賴上一次的補丁的Share;

6)運行時,對所有補丁入的Res建立一個字典索引。Load的時候,優先判斷這個Asset是否在補丁的Res包中,如果是,則讀補丁的AssetBundle包,並按套路處理依賴包。否則就用二進位版本內建的包。

這種做法的好處是:

1)分利用版本中的已經發布的資源,以減小補丁包的體積;

2)補丁包的打包規則可以幾乎無視完整包的分包規則,方便後續折騰。

當然缺點也是很明顯的:

1)完整包里的大包真的好嗎?如果所有資源打成一個AssetBundle,就和全部用Resources目錄沒有區別的,這個是Unity官方竭力阻止的。實測下來,一個300MB的Res包Open一下,iOS分配了接近40MB的內存…(其實這個問題和Diff更新不矛盾,現在我們二進位包里的資源也拆得比較小了,但補丁仍然可以使用上述規則)。

2)工具啊工具,開發維護資源MD5資料庫、補丁生成規則打包器,肝了5天5夜才搞對啊;

3)也是最致命的問題,對於被非常多資源依賴的Assets,一旦變化,更新包里就會找出一堆躺槍的Resources,例如UIAtlas相關的東西、Shader全家、字體什麼的…

對於問題3,幾乎必須要用整包的替換的思路,把這些易變的Assets挑出來,單獨打AB包。後續什麼Res什麼Shared全都依賴它們。如果它們中有一個變了,就覆蓋更新掉這整個基礎AssetBundle包,而依賴它們的Res不視為發生了變化。

其實差異更新和整包替換到底哪個更好,我也一直在糾結。當初用差異更新的最主要原因,其實是項目里的代碼非同步化處理得不好,頻繁Load小的AssetBundle包很卡,所以才打大包,被迫上Diff方案的。

另外,無論哪種打包方案,千萬要控制好AssetBundle包中的冗餘資源量【不管大包還是Diff包,都可以解決好的】,我的底線是2%實際容量以內。這一點上UWA的在線AssetBundle包檢測工具能幫大忙,謝謝!

感謝UWA問答社區 @鄭昊提供了回答

A:我是來勸退的。整包Diff的,Flashyiyi寫過一個基於bsdiff的方案

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

bsdiff我在Cocos2d年代用來做CPP的更新,縮小so的體積,確實十分有效,但是為什麼我還要勸退呢?

1. 維護難度大

Diff是精準產生兩個文件之間的差異,也就要求每一次補丁都要精準匹配上一版本和下一版本,並且在多版本時是一個嚴格線性的關係:必須逐個補丁按順序安裝合併。而這個嚴格線性關係是致命的缺點。

版本很多時,這個假如中間有一個版本丟失,或者中間一個補丁是有問題的,整個更新鏈就出問題。可靠的系統還是需要考慮出錯的情況。

2. 合併補丁需要謹慎

替換文件的套路看起來補丁會大,但卻天然做到了多個版本的補丁的重複改動是自動合併的,所以老玩家或者裝apk更新到最新版本的時候下載總量不見得會很誇張。

但Diff方案就很麻煩,雖然可以進行Diff合併,但首先是你合併了也不能輕易刪除合併前的補丁,否則更新到中間版本的玩家就會沒有補丁可用。你得做很嚴謹的判斷來跳過合併的補丁。也需要有靠譜的製作流程來防止合併補丁搞出問題。

3. 打一個大AssetBundle會導致合併緩慢

這是因為你要一個個地按順序合併。相對地,雲風寫過一個解包Bundle,然後運行時再組裝的方案(Blog,非源碼)。祖龍的六龍爭霸也是這個方案。並且他們也不是打一個大Bundle,而是小Bundle內精準替換。這個沒有那麼依賴版本的精準一致性,也能做到更新包非常小。

但又帶來新的問題:官方格式一改,代碼也要跟著改。而官方格式不開源,而是自行破解的(可以參考Unity Extractor之類的開源方案),你跟隨的難度也就可見一斑。

所以,如果真的不是十分在意更新大小的,其實替換文件還是不錯的……反正我們是在用。現在大廠的遊戲,動輒也是幾十MB補丁。

感謝UWA問答社區 @招文勇提供了回答

歡迎大家轉至社區進行進一步交流:

https://answer.uwa4d.com/question/5aa5f267d35eb22c10a0a38e

其他

Q:我們團隊最近上線的產品用的是Unity 4.6版本,然後最新在籌劃新項目,還是一款MMO產品。想請教一下,升級到Unity 5的必要性有多大呢。因為Demo切到5之後,出了一些解決起來比較耗時的問題,我們擔心後續的坑比較多。我想大概所了解的Unity 5主要的新特性有:AssetBundle打包的優化、粒子從主線程中分離出去了、PBR渲染方式等,但是這幾個東西暫時看對我們的影響不是太大。

UWA:如果是新項目,那麼升級Unity 5很有必要。功能新特性上還是建議直接去看Unity 5的功能介紹吧,網上很多了。說說性能上提升的幾個重要方面:

1)載入效率更高。即便都是同樣的LZMA壓縮打包,Unity 5.3之前版本關於同樣內容的AssetBundle載入也一樣提速(5%~15%)。另外,對於Unity 5.3之後的新LZ4 AB,載入速度較之之前是飛一般的提升;當然Unity 2017載入ms更快,我們將會在UWA Day 2018上進行總結和分享;

2)AssetBundle載入內存佔用更小。Unity 5.3之後沒有了Webstream,一大幸事。但需要注意5.4.5、5.5.4版本之前的0.5MB SerializedFile的「坑」;

3)除題主提到的粒子系統外,動畫模塊也同樣多線程處理進行處理,效率提升明顯(雖然有時候會出現主線程等待子線程的麻煩問題,但總體來說還是利大於弊);

4)UGUI在Unity 5.2版本以後趨於完善,且加入了多線程處理。在我們的趨勢分析中,UGUI無論是性能還是使用成熟度方面趕超NGUI的趨勢非常明顯;

5)物理在Unity 5.4版本以後可根據項目的物理使用情況自行進行剝離,從而避免之前一直在不停空轉的尷尬問題。

除上述之外,性能提升點還有很多,可以說Unity 5的性能提升還是多方面的,建議升級。最後,Unity 4已經不再維護了,如果以後萬一出現了設備或系統的兼容性問題,咋辦?

該回答由UWA提供,歡迎大家轉至社區進行進一步交流:

https://answer.uwa4d.com/question/5aa686680b827e2c0bfdd117

互動話題

NGUI和UGUI這兩個UI系統,你用過/ 正在/ 將來會選擇哪個呢?你是如何看待其各自的優劣?

歡迎在文章底部和我們分享你的灼見!

本文封面圖來源:Star Citizen《星際公民》,出處:https://robertsspaceindustries.com


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 侑虎科技 的精彩文章:

支持本地管理深度測評、全新的UWA API、兼容Unity 2017.3

TAG:侑虎科技 |