使用Unity開發專案的人都知道,Build Settings里切換平臺時,會根據每個紋理指定的對應平臺的壓縮格式去壓縮紋理,壓縮紋理非常慢,會占用總時間的一多半,那能不能把這個時間降下來呢?2018年秋就接到了公司的這個需求,
網上看到有人之前嘗試著解決這個問題,說白了就是把壓的作業從爛CPU(作者指的主要是Mac)轉移到強大的CPU上(主頻高、核多),見https://blog.codingnow.com/2016/12/unity3d_remote_pvrtextool.html,這個方案至少打開了一個有啟發性的思路,
但是,上面的方案理論上來說最多快上幾倍,壓縮紋理還是會占用很長時間,因為普通民用CPU的性能不會差別太大,
那怎么才能大幅提升速度呢?想起了開發引擎時經常會使用聯合編譯,從這得到靈感(UE4里的Lightmass烘焙Lightmap很慢,所以實作了個Swarm,可以分布式烘焙,也是這個做法):為什么不將紋理拆分開,用分布式的方式來壓縮呢,壓縮完畢后拼合成一張完整的紋理,我們都知道公司工位上的機器大部分時間CPU都是閑置狀態,還有公司內部也有很多淘汰下來的服務器,如果這么做,理論上來說能提高幾個數量級,很興奮,搞嘛,
幸好公司購買了Unity原始碼,很快就搞清楚了紋理壓縮的流程:Unity根據壓縮格式的不同會啟動不同的命令列工具的行程進行處理,例如PVRTexTool.exe、etccompress.exe;ASTC比較特殊一些,將一個ASTC壓縮的開源庫直接編譯進了引擎里,先不管這個,技術Demo沒有處理這種情況,壓縮工具行程完成后,Unity再繼續運行,自己寫代碼編譯出Proxy工具,這些工具命名成PVRTexTool.exe和etccompress.exe,將Unity里的替換成掉,這些Proxy工具只是個中轉站,將命令引數和未壓縮的紋理資料分別上傳到中心服務器和資料服務器,服務器分拆紋理,并將小塊的紋理交給不同的任務服務器去壓縮,壓縮完畢后合并成完整的紋理,通過網路回傳給Unity編輯器,對于ASTC這種特殊方式,可以用Hook的技術轉發命令引數和紋理資料,不過沒有時間去嘗試這個(其實強烈建議Unity官方將這個開源庫編譯成接收命令列引數的可執行程式,這樣就處理起來統一了),
分布式壓縮的圖:

其實也沒什么技術難題,也就分拆PVR格式的紋理時卡了下,因為PVR里的紋素是Z字形排列的,主要是工程化的比重比較多,所以細碎的活很多,需要支持Windows、MacOS和Linux,需要用到多種語言和IDE,但由于人手嚴重不足,只能完成了各技術Demo,技術Demo到產品化還有很長的距離要走的,需要解決各種細枝末節的問題,所以需要一個團隊,
經實測,確實有明顯的性能提升:測驗了在三臺電腦上分布式壓縮,壓縮性能基本上跟服務器數量的增加成正比,
當然,這種方式也有缺點:拆分紋理很麻煩,例如紋理有很多種格式,還分2D、3D、Cubemap,還有Mipmap,性能也有不小的損失,因為拆分、網路傳輸、合并都需要時間,
前兩天看到一篇文章,Unity官方終于出手解決這個問題了:《Unity 2021.1 beta 中的紋理優化,提速最高達 3.1 倍》,見https://mp.weixin.qq.com/s/GEC6zzNVXKySNcU5gHQAcg,采用的方式是應用 SIMD 或執行緒優化,以及采用最新壓縮庫或優化壓縮庫本身來進行紋理壓縮,
不過,經常做性能優化的人都有一個常識:針對語言層面的優化一般最多只能優化出幾倍的速度(別抬杠,寫的太爛的代碼優化出來幾百倍的速度也正常);而如果選用不同的架構或者演算法,性能的提升有可能達到幾個數量級以上,
那有沒有更好的方法呢?我覺得理論上來說,“分布式異步壓縮”是個可以考慮的方案,也就是壓縮紋理時不要同步執行,將需要壓縮的紋理直接扔出去讓聯網的作業機器去執行,Unity繼續執行其它的切換平臺的作業,當然,選擇異步的方式是需要一個前提的:沒有任何作業的執行需要依賴于紋理的壓縮完成,除了打包這種,這樣就把2/3的時間都節省了,
是不是感覺有點意思?有的話可以聯系我,一起試著玩玩,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/265375.html
標籤:其他
