新年伊始,隨著大家緊鑼密鼓地開始了工作,UWA每周推送的知識型欄目《厚積薄發 | 技術分享》在節後的首個工作日迎來了第100篇!今天,我們繼續為大家精選了5個和開發、優化相關的問題,建議閱讀時間15分鐘,認真讀完必有收穫。如果您有任何獨到的見解或者發現也歡迎聯繫我們,一起探討。
UWA QQ
UWA 問答社區:answer.uwa4d.com
粒子系統
Q:請問粒子系統的消耗如何區分呢?哪部分是在CPU哪部分在GPU呢?一個空粒子(禁用所有模塊,包括Render)會有消耗嗎?如果有消耗,會體現在哪部分呢?
A:就目前的Unity引擎的原生功能而言,粒子系統中的狀態更新(粒子的位置、朝向、觸發事件等)均為CPU端開銷,具體表現在ParticleSystem.Update和ParticleSystem.EndUpdateAll等函數中。具體可以查看UWA性能報告中的這兩張圖:
同時,粒子系統在渲染時也需要在CPU端進行準備,比如粒子系統的Culling和Draw Call操作等等,這些也都屬於CPU端開銷,如下圖所示。
而GPU端的耗時則與其他Mesh渲染無差,主要和ALU、Bandwidth和Overdraw相關。但與其他一般場景渲染不同的是,粒子系統在GPU端的壓力往往在Overdraw中進行體現,如下圖所示:
上圖來自《極無雙》的性能詳細報告,大家可以參考完整數據來加深這部分的理解:https://www.uwa4d.com/demo/pa.html?v=5x&platform=android&name=jws&device=Mi5S#overdraw
一個空粒子其自身開銷理論上很小,但UWA這邊暫時沒有做過測試,題主可自行做一些測試,絕知此事要躬行。
此問答來自於UWA 問答社區,如您對該問題仍有疑問,可以轉至社區進行進一步交流。
https://answer.uwa4d.com/question/5a865162d35eb22c10a0a202
資源管理
Q:我用的是Unity 5.5 版本,由於項目採用LZ4格式的AssetBundle,如果直接放進StreamingAssets下,包就太大了。現在想把所有的AssetBundle打成一個壓縮包,再放進StreamingAssets,讓玩家在第一次安裝時,拷貝到PersistentDataPath目錄下再解壓。但目前不知道怎麼讀取Android平臺下的StreamingAssets目錄下的壓縮包,希望能得到指導,感謝!
A1:我們是直接使用的C實現的unzip庫,啟動遊戲的時候就常駐打開Apk,後面都直接通過unzip庫解需要的文件到緩存目錄來讀取,讀完了,不用就定期做一些清理。
感謝Lujian提供了以上回答
A2:在Unity的API裡應該就只有WWW(新版本裡對應UnityWebRequest)能訪問非Bundle文件了,但這個接口是異步的,另外.bytes操作會產生較高的堆內存分配,容易撐高堆內存峰值。
所以,有的做法是通過Android的Java API來讀取,可以參考下雨松MOMO的這篇文章裡用的Java接口:https://www.tuicool.com/articles/fAnYJ3I
此問答來自於UWA 問答社區,如您對該問題仍有疑問,可以轉至社區進行進一步交流。
https://answer.uwa4d.com/question/5a8105ab2174bd258ff90fc8
資源管理
Q:我用的是Unity 2017.2f版本,我們Prefab裡Image元素直接引用的是Sprite Atlas文件夾裡的圖片,現在把Prefab和Sprite Atlas分別打到兩個不同的AssetBundle裡,並且去掉了Sprite Atlas的include build的選項。拿工具查看Prefab和Sprite Atlas的Bundle發現,Prefab所在的Bundle會把Image元素引用的那張Sprite圖也打進來,而Sprite Atlas所在的Bundle裡不但包括了這個Atlas圖,並且原圖都在這個Bundle裡。這是為什麼呢?
A:UWA測試發現Unity 2017.2和2017.3都存在題主說的問題,不過也都能通過一些操作繞過這個問題。先說一下個人認為正常的現象:
include in build不應該影響Bundle的打包行為,且Prefab的Bundle中始終不應該有SpriteAtlas存在。但是如果不開啟include in build,正常加載完兩個Bundle,且實例化Prefab後,Sprite不會顯示,因為需要做一下late binding。
接下來說一下碰到的這個Bug:1)如果在第一次(打之前清空Bundle目錄)打Bundle時,include in build開啟了,那麼atlas會被打包進prefab的bundle中(即題主的問題);
2)但如果在第一次打Bundle時,include in build沒開啟,那麼就是正常現象(Atlas不在prefab的Bundle中);
有意思的是,在第二次打Bundle時,不論include in build有沒有開,結果都和上一次打包一樣。所以,繞過去的方法是:
先清空Bundle目錄,關閉include in build打一次Bundle;再開啟include in build打第二次。得到的結果就是Atlas不在Prefab的Bundle裡,同時Atlas的include in build是開啟狀態的。題主可以按這個步驟做個嘗試。
此問答來自於UWA 問答社區,如您對該問題仍有疑問,可以轉至社區進行進一步交流。
https://answer.uwa4d.com/question/5a822325847802258a06509e
渲染
Q:我從文檔(https://docs.unity3d.com/Manual/SL-TextureArrays.html)上來看,GLES3 Metal 已經可以支持了。最容易想到的就是地形的splat層,如果是四層splat,那麼就可以用一個Texture2DArray來代替,好處是減少了bind消耗。相關的知乎連結https://www.zhihu.com/question/56015505,其中根據龔大的意思來看,似乎還可以減少splat採樣次數,但根據自己的測試和理解來看並不行,因為Texture2DArray 的slice之間並不會 blending,不知是不是我理解問題。
我使用一個Texture2DArray來代替4層的Splat地形,從XCode上看開銷,並沒有任何的減小,那目前來看這麼做地形的意義就不是很大了。AssetStore上有一個插件叫MegaSplat就是使用Texture2DArray來達到很多層混合。目前想到的Texture2DArray還有一個可以利用的地方是場景貼圖。比如場景用到了多張1024的貼圖,或者多張lightmap,原來由於貼圖不同導致StaticBatching無法合併,現在就可以使用Texture2DArray來做了。還有比如UI上的icon之類的,可以合併到一個Texture2DArray來達到DrawCall的合併。
目前Texture2DArray最不利的地方是:只能通過代碼來創建,沒有編輯器的支持。如果要離線製作Texture2DArray,就需要為不同的平臺準備多份資源了。請問大家有沒有Texture2DArray的經驗可以分享呢?
A:UWA研究了Texture2DArray,看起來它是將多個2D的Texture組合起來變成一個對象,所以在使用的時候只需要綁定一次,就可以採樣多個2D Texture。的確如題主所說,採樣的時候還是一次只能採樣一個指定的slice,blend也需要另外的Shader代碼來完成。題主說了:
其中根據龔大的意思來看,似乎還可以減少splat採樣次數,但根據自己的測試和理解來看並不行
我感覺他的意思可能是:並不是每次採樣必須把所有的slice都採了,而是可以只採其中一部分。估計原本想表達的是一次採樣只採一個slice。
我使用一個Texture2DArray來代替4層的Splat地形,從xcode上看開銷,並沒有任何的減小,那目前來看這麼做地形的意義就不是很大了。
如果單從性能上看,Texture2DArray比Texture2D的確只是減少紋理綁定的開銷,然後在遊戲引擎中可能會對合批產生影響。其他的做法跟普通Texture2D是一樣的。Texture2DArray比Texture3D在LOD處理上不同,Texture3D會減少slice,這並不是渲染Terrain時想要的。然後Texture2DArray在filter的時候只會在U,V上做,而Texture3D還會在d上做,所以這部分Texture2DArray也比Texture3D性能更好。綜合這些因素可能是推薦渲染Terrain使用Texture2DArray的原因吧。題主通過實驗說明Texture2DArray渲染地形沒有減少開銷,也有可能是因為一般一個場景就一個地形,從綁4張紋理變成綁1張就少了幾毫秒,而且也不是每幀都綁,所以從整體效果上看不大出來。
UWA做了個簡單實驗驗證了一下,下圖分別是用Texture2D和Texture2DArray渲染地形結果和GLES API調用。實驗設備為三星S6。
Texture2D:
Texture2DArray:
其中,GLES API調用圖中紅色框表示紋理綁定的API調用,綠色框表示渲染API調用。WT表示了該API調用的耗時,單位為納秒。從Texture2D圖中可知一共有5次紋理綁定,分別對應於材質中的5張紋理綁定,而Texture2DArray圖中只有兩次調用,分別是splat紋理和四層混合紋理的綁定。從圖中可知一次glBindTexture的耗時大約為1000~10000ns,即最多0.01ms。因此,三次glBindTexture加上三次glActiveTexture也最多0.06ms。所以看不出來。
此問答來自於UWA 問答社區,如您對該問題仍有疑問,可以轉至社區進行進一步交流。
https://answer.uwa4d.com/question/5a7e9f79847802258a065084
物理
Q:我們正在開發一款超大地形的MMO遊戲,場景中的角色或者怪物較多,請問Unity引擎是否會對遠處(500m或1km外)的GameObject進行物理模擬?是否有設置可以降低這部分GameObject的物理模擬開銷?
A:Unity引擎確實會對遠處的GameObject進行物理計算,只要該物體是Active、掛載Rigidbody(Character Controller)組件並且沒有Sleeping的。Unity引擎並沒有原生功能可以根據距離的遠近來調整物理系統的計算,不過題主可以自行來進行控制,比如通過Culling Group或者自行計算GameObject的遠近來控制Rigidbody組件的Active和Deactive,從而降低整體的物理系統耗時。
此問答來自於UWA 問答社區,如您對該問題仍有疑問,可以轉至社區進行進一步交流。
https://answer.uwa4d.com/question/5a8e6c1bd35eb22c10a0a215
今天的分享就到這裡。當然,生有涯而知無涯。在漫漫的開發周期中,您看到的這些問題也許都只是冰山一角,我們早已在UWA問答網站(answer.uwa4d.com)上準備了更多的技術話題等你一起來探索和分享。歡迎熱愛進步的你加入,也許你的方法恰能解別人的燃眉之急;而他山之「石」,也能攻你之「玉」。
官網:www.uwa4d.com官方技術博客:blog.uwa4d.com官方問答社區:answer.uwa4d.com官方技術QQ(僅限技術交流) 活動!UWA DAY 2018 開啟報名!
近期精彩回顧【虛幻引擎學習之路】渲染模塊之光照系統【萬象更新】看完性能簡報,想不優化好都難!【厚積薄發】50次遊戲性能的深度優化,得出了這五條「毒雞湯」UWA問答:用心解決「你」的每一個問題!