vr优化
轉載自博主狂云歌 原文章鏈接http://blog.csdn.net/madcloudsong/article/details/52446813
【狂云歌之unity_vr】VR開發中的優化
前言
大概做了大半年的VR開發,HTCVive上與room scale和手柄控制器、激光相關的開發做過,gearvr使用oculus sdk開發做過,使用Cardboard做普通VR app在Android和iOS上發布也做過。
vr設備呢,HTCVive和oculus搞過,gearvr和普通Cardboard類的手機vr搞過,LG的新的glass接過,露光嚴重,idealens、還有一大票的國產一體機,pico、小米,嗯做的好的目前的確還是那幾個大廠的。
由于我參與的項目主要圍繞視頻播放的功能,所以大型3d場景接觸的倒不多,然而還是有很多需要優化的點,為什么呢,因為做的視頻播放本身就需要對大于1080p的視頻做解碼、在unity中渲染,對cpu和gpu消耗都很大,擠占了部分性能,所以對其他邏輯和渲染部分的性能要求更高。
VR開發中的優化主要圍繞兩部分吧,一部分是由于VR的特殊場景,雙眼渲染,且對幀率要求高,所以對性能要求也高,還有vr場景下一些特殊要求。另一部分是傳統unity性能優化部分,對程序和美術都有要求。unity相關的優化網上已經有很多優秀的文章了,我在這只根據VR開發與傳統unity開發的區別,分享一些優化的建議。
歡迎下載我們的app
VR優化
先從VR幀率卡說起
因為HTCVive和gearvr做的開發比較多,先說說這兩個設備卡的表現,對于HTCVive而言,如果程序執行時卡頓比如loading或者什么,一般會優雅的回到HTCVive的一個默認場景,對用戶還算比較友好,而對于gearvr而言,如果卡頓影響了渲染或者幀率低,那么用戶頭轉動的時候能明顯看到周圍來不及渲染的黑的地方,如果渲染卡死的話,只剩最后一幀渲染的畫面,周圍的空間都是黑的。
對于PC而言,我們配置的顯卡至少也會是970+吧,性能都比較好,cpu、渲染、IO等性能都比較高,但是到了移動端,相應操作性能都會變差,之前對比過一些操作,比如圖片動態加載,在editor下可能只要幾毫秒最多20幾毫秒,到了移動端可能都要幾十毫秒甚至2-500毫秒的都有,那么幀率降低的簡直不要不要的。所以對于unity而言,不光在editor下看性能指標,也要利用profiler觀察在移動設備的性能。我們在開發過程中和測試中都要不斷的進行性能優化。
VR和傳統游戲卡的區別
傳統游戲也會做很多的性能優化,但是卻可以有很多常用的解決方案,例如為了解決資源包大的問題,將資源通過異步下載并動態加載,為了減少加載的損耗,那么大不了加一個loading畫面,而loading時一般而言隨便卡,不太需要關注操作的阻塞延遲和幀率,因為loading時無需響應用戶操作。甚至有的游戲按一個按鈕也會進行阻塞,大不了出個loading嘛反正用戶也會等。
對于VR應用,用戶都是可以自由操作轉頭的,一旦卡頓,影響幀率,直接會影響用戶視野轉動,影響體驗,同時降低幀率刷新后,用戶會有眩暈感,那么就很失敗。
一般什么時候會發生卡頓呢,對于vr程序開發而言,往往出現在場景切換時資源加載、初始化腳本邏輯執行,例如monobehaviour的awake和start里包含的大量的邏輯,甚至你以為使用了協程就沒有問題,然而協程在首次執行時第一個yield前可能也包含了大量的邏輯。還有運行時動態資源加載以及常見的每幀處理事情過多導致降幀。
性能優化工具
unity提供了一些性能指標查看工具,比如profiler和frame debug。
profiler
profiler可以看cpu、render、內存等性能消耗,一般可以看出每一幀哪些操作分別消耗了多少時間,找到瓶頸進行優化。例如我之前在pc上看性能貌似都還可以,但是在gearvr移動端就明顯的看到像Resource.Load()這種操作過多的占用了時間于是優化掉。
另外注意不必要的log記得清理,否則在profiler里會占用很多時間。
profiler也可以實時查看unity程序在Android和iOS上運行時的性能表現。
framedebug
framedebug可以方便的查看一幀都進行了哪些渲染,可以用來優化drawcall,在做vr開發的時候,因為雙眼渲染,所以drawcall比普通程序也會高很多,正常表現是2倍的drawcall,具體平臺就算進行了一定的優化,看起來往往也要多50%以上的drawcall。
嗯具體優化drawcall的方式常規游戲中也有蠻多,我只說我們做的簡單且立竿見影的優化,因為ugui用的多,那么用ugui的sprite pack之后drawcall可以直接ugui中大量sprite的drawcall,再加上雙倍的渲染,drawcall的節約其實非常可觀,而不用做太多事情。
一些優化的經驗
場景異步加載
在切換場景的時候,使用異步接口進行load,還是之前說的,同步load會導致卡頓而影響渲染。通過異步加載場景,盡量減少阻塞的時間,因為場景加載完畢運行的時候,初始化相關例如awake和start還是會導致一定的卡頓,這個就要通過后面的方式來解決。
資源分散到每一幀加載
例如加載一些prefab等資源,很多想load就load,或者集中在某個函數里依次load好,但是這樣其實還是會導致卡頓。所以可以考慮使用協程等將資源加載分散到每一幀進行加載,這樣也可以很快的在幾幀內加載完畢,同時幀率也幾乎不會下降。
腳本分散到每一幀執行
做項目的時候,在通過profiler調查性能時,有發現某一幀干了很多事情,導致卡頓。例如通過for循環干什么事情再用協程加載10張圖片,那么這些操作雖然單獨一個操作只要2-3ms不影響幀率,但是多個累計起來可能就高達幾十ms甚至更高,就會影響幀率。
另外如果開了10個協程加載10張圖片,很有可能在圖片下載ok之后,在同一幀之內多張圖片同時轉為texture,這個操作很耗時,于是會累計導致卡頓,所以我也封裝了一個用來控制類似操作的協程,每一幀只會執行一次這種阻塞耗時操作。
(必殺)黑屏
如果實在沒辦法,那就在特殊阻塞操作之前給用戶一個預期吧,同時漸變黑屏掉,這樣全黑的情況下,就算渲染卡頓了,用戶也看不出來。比如切換場景后開始的時候會比較卡,可能高達幾百ms甚至1秒,那么我就給用戶預期是loading切換場景,先切到黑屏再阻塞,然后渲染ok了再恢復渲染。我看了有的app也是這樣做的。
一個圖片處理優化的例子
對于vr視頻播放app而言,顯示各種網絡上的圖片是一個比較常見的事情,在vr場景下,圖片分辨率不能太低,而恰巧我們服務器提供了一張分辨率較低的縮略圖和分辨率較高的大圖,使用小圖呢,不夠清晰,使用大圖呢,過于清晰,會造成閃的效果,同時loading大圖比較慢,不劃算,所以希望得到一個適當尺寸的圖。讓服務器去多給張合適的圖,是最快最方便的途徑,然而~好吧還是希望在客戶端處理一下。
unity實現
如果使用unity的texture相關函數,由于unity動態生成大texture比較慢,在pc上都要幾十ms,如果到了移動端差不多要幾百ms,而且是同步阻塞操作,這個完全不能接受。
如果使用unity多線程操作呢,然而unity多線程不能處理渲染相關的類例如texture。
或者使用基本c#實現,一般的處理方法是使用System.Drawing,但是也不跨平臺,理論上應該有直接對圖片數據處理的辦法,但是當時也沒有那么多精力去研究。
native實現
使用unity下載圖片并緩存到本地,寫個android的Java插件,使用android多線程處理圖片,然后回調unity(此處也可封裝為協程),這樣對unity而言就只剩下JNI的調用開銷和load適當大小圖片的開銷了。當然對于iOS平臺需要再寫一個小插件。
Unity優化
使用unity做vr開發,那么優化很多也是基于傳統unity游戲開發的優化經驗。由于unity接觸也不夠深入,所以基本也是參考其他人的優化方法,逐漸去學習使用和深入了解。
舉例參考 
 http://www.cnblogs.com/murongxiaopifu/p/4284988.html
等等,這個unity優化相關可以百度或者google到很多系統的文章,大同小異。優化之路漫漫。
結語
總之傳統unity游戲開發有很多種途徑進行優化,必要時也可以有很多種方式避免用戶輸入和感知卡頓,可以在某些情況下降幀,而VR開發由于雙眼渲染、頭部控制的存在,對性能要求更高,壓榨幀率,需要降幀的時候也需要特殊處理(例如黑屏)。
我看HTCVive上有些app在配有980的相對配置較高的機器上也很卡頓,還是希望可以在細節處優化,在用戶體驗上可以流暢。
總結
                            
                        - 上一篇: 视频教程-清华-尹成老师-java基础-
 - 下一篇: 微信二维码扫描支付