如何有效提升Unity Gear VR游戲性能

?? 由 文心大模型 生成的文章摘要

好的,所以你決定用 Unity 來做一個 VR 游戲,并選定了三星 Gear vr 為你的目標平臺。做好之后,打開應用,在設備上執(zhí)行文件再容易不過 – 但有個問題,幀率實在太低。視野邊上有閃爍的黑邊出現(xiàn),感覺好像有誰往攝像機操作員的肚子上踢了幾腳。你聽說過保持穩(wěn)定的幀率有多重要,現(xiàn)在你明白為什么了 – 在虛擬現(xiàn)實中,任何低于每秒60幀的東西不僅看起來不好,讓人難受才是最糟糕的。你的高端上檔臺式機能把這個游戲運行到每秒1000幀,但機箱發(fā)出的聲音像飛機引擎一樣,而且……風扇發(fā)動時機箱好像真的升起來一點了!現(xiàn)在你要做的就是把你的大作針對移動芯片好好地優(yōu)化一下。這個系列的文章針對的就是這個問題。

第一部分: 運行環(huán)境以及高效率VR應用的一些特征

這并不是關(guān)于 Gear vr 的一個優(yōu)化大全,更像是一個快速入門吧。在這第一貼中我們將先討論下 Gear vr的硬件以及設計良好的移動 VR 應用的一些特點。之后將會著重講述如何針對你的應用來提升表現(xiàn)。這篇文章主要針對 Unity,因為這是目前 Gear VR 開發(fā)中的主流引擎。但是,這些概念對于其它引擎來說也是可以適用的。

了解你的硬件

在把你的項目大卸八塊尋找其低效之處之前,最好先花點時間思考下當下移動手機的一些表現(xiàn)特征??偟膩碚f,移動圖形管線基于一個很快的 CPU ,通過一個很慢的總線和/或內(nèi)容控制器來和一個很快的 GPU 連接,還需要一個造成很多開銷的 OpenGL ES 驅(qū)動。Gear VR 在三星 Note4 和 S6 上運行。這兩個產(chǎn)品線代表了幾種不同的硬件規(guī)格:

  • Note 4 的核心有兩種。在北美和歐洲售賣的版本基于高通的驍龍芯片(SnapDragon 805),而在韓國和亞洲一些其它地區(qū)的基本都是三星自己的獵戶座芯片(Exynos 5433)。驍龍芯片是四核 CPU 規(guī)格,而獵戶座有八核,這兩個核心分別對應兩種 GPU: Adreno 420 以及 Mali-T760。
  • Note 4 又被最近的谷歌分成兩種系統(tǒng)。分別是安卓 4.4.4 (KitKat) 和 Android 5 (Lollipop)。目前基本上世界上的獵戶座的 Note4 都運行安卓5.0了(看來我給世界拖后腿了)。
  • S6 則都只有一種核心:Exynos 7420 (圖形芯片是 Mali-T760M8)。還有另一個版本的 S6,S6Edge,但它們除了外形不一樣以外里面都是一樣的。
  • 所有的 S6 都是安卓5.0棒棒糖系統(tǒng)。

看起來好復雜是吧!沒事,它們所有的性能和表現(xiàn)其實都很接近(除了一種狀況,最下面的注意事項里會說),如果你能在某個設備上跑得不錯,在其它上面應該也不會有生命問題。

和多數(shù)移動芯片一樣,它們的 3D 圖形表現(xiàn)方面的屬性都比較穩(wěn)定可靠。因此,這里有一些普遍的可能讓你的項目跑得不好的原因(按嚴重順序排列):

  • 場景需要獨立的渲染器(比如陰影和反射)(CPU/GPU開銷)
  • 綁定 VBO 來進行繪制調(diào)用(CPU/驅(qū)動開銷)
  • 透明,多通道渲染,每像素照明以及其它的像素效果(GPU/IO 開銷)
  • 大型紋理加載,blits,以及各種類型的內(nèi)存開銷(IO/內(nèi)存控制開銷)
  • 蒙皮動畫(CPU開銷)
  • Unity 垃圾回收開銷(CPU開銷)

另一方面來說,這些設備有著比較大的內(nèi)存,可以描畫比較多的多邊形。Note4 和 S6 都有著 2560×1440 的分辨率,但默認情況下我們一般只渲染 1024×1024 的紋理分辨率來節(jié)約填充率。

了解你的VR環(huán)境

VR 渲染讓硬件的表現(xiàn)受到最嚴苛的考驗,因為每一幀都必須給雙眼繪制共兩次。在 Unity 4.6.4p3 和 5.0.1p1 里,意味著每個繪制調(diào)用都被執(zhí)行了兩次,每個網(wǎng)格被繪制了兩次,每個紋理被裝訂了兩次。此外還有少量的開銷被分配給了最終的畸變和時間穿越(2ms的預算)上。雖然我們期待未來硬件的表現(xiàn)以及程序的流程會越來越好,但目前就是得每幀畫兩次。這意味著相較于普通的游戲,VR 游戲的開銷要多幾乎一倍。

而基于這些特性,以下是一些比較靠譜的 Gear VR 應用渲染目標。


這一幀大概有30000個多邊形和40個繪制調(diào)用

 

  • 每幀 50 – 100 個繪制調(diào)用
  • 每幀 50k – 100k 個多邊形
  • 紋理貼圖越少越好(但每個可以很大)
  • 腳本執(zhí)行時間在 1 ~ 3 毫秒以內(nèi) (Unity Update())

注意這些不是硬性規(guī)范,只是我們的經(jīng)驗之談。

另外注意 Oculus Mobile SDK 還引進了一個給 CPU 和 GPU 節(jié)流降頻的 API 來控制熱量和電池消耗(查閱使用樣例 OVRModeParams.cs)這些方式讓你可以選擇對于在某個場景下,控制 CPU 和 GPU 的開銷。比方說,如果在繪制調(diào)用的提交上出了問題,你讓 CPU 升頻(同時讓 GPU 降頻)可能能提升整體的幀率。如果你忽視這些做法,你的應用可能會被迫運行在降頻的環(huán)境下,因此你最好多花點時間在這上面。

最后,Gear VR 也擁有 Oculus 的異步時間穿越(Asynchronous TimeWarp)技術(shù)。TimeWarp 能在程序變慢時基于最近的頭部姿態(tài)信息來得到接下來的幀畫面。它通過頭部信息來扭曲上一幀的畫面,能幫助你即便在偶爾丟失幾幀時也能有流暢的體驗,但絕對不是一個讓你把應用隨意運行在60幀每秒以下的借口。如果你左右搖擺腦袋時能看到眼角黑色的色塊,就說明你的游戲已經(jīng)慢到 TimeWarp 沒有足夠的幀畫面來填補這些黑色空白了。

為性能表現(xiàn)而設計

做出表現(xiàn)良好的應用就是為了表現(xiàn)良好而去設計,而這意味著圍繞移動 GPU 的一些特性來設計你的美術(shù)資源。

準備事項

在開始之前,先確保你的 Unity 項目的設定都已經(jīng)為最高表現(xiàn)設定好了。特別的,是確定如下值的設定:

  • 靜態(tài)批處理(Static batching)
  • 動態(tài)批處理(Dynamic batching)
  • GPU 蒙皮(GPU skinning)
  • 多線程渲染(Multithreaded Rendering)
  • 默認方向到地平左邊(Default Orientation to Landscape Left)

批處理

現(xiàn)在我們知道的是,一般來說繪制調(diào)用數(shù)量是 Gear VR 應用中最占用資源的方面,那么優(yōu)化的第一步就是在藝術(shù)層面上做出一些設計,讓程序在最終實現(xiàn)時調(diào)用越少的繪制命令越好。一個繪制調(diào)用就是對 GPU 的一個命令,讓它繪制一個網(wǎng)格或者網(wǎng)格的一部分。而這個命令最占用資源的部分其實是網(wǎng)格的選擇本身。每一次當程序決定繪制一個新網(wǎng)格時,網(wǎng)格在被提交給 GPU 之前必須先被驅(qū)動進行處理。著色器必須被彈回,可能會發(fā)生一些格式的轉(zhuǎn)化等等;而這些過程在每次一個新的網(wǎng)格被選中后都會發(fā)生,并占用了最大的開銷。

但這也同樣意味著,每次一個網(wǎng)格(或者更具體一點,一個頂點緩沖區(qū)對象VBO)被選中后,只需要占用這一次開銷,就能使用多次。只要沒有新的網(wǎng)格(或者紋理、著色器)被選中,當前狀態(tài)會一直存在于驅(qū)動緩存中并可以進行反復使用。為了利用這個特性,我們可以將多個網(wǎng)格整合進一個大的頂點陣列中,并通過 VBO 進行單獨繪制。我們付出一次選擇的代價后,就可以從這個對象內(nèi)包含的多個網(wǎng)格進行調(diào)用而不會提高系統(tǒng)開銷。這個方式被稱作為批處理(Batching),比起為每一個不同的網(wǎng)格創(chuàng)建 VBO 要快得多,也是針對繪制調(diào)用進行優(yōu)化的基礎。

單個 VBO 中的所有網(wǎng)格必須享有同樣的材質(zhì),才能進行批處理的整合:同樣的紋理、著色器以及著色器參數(shù)。為了更高效地在 Unity 中利用批處理,我們還得更進一步:對象必須有同樣的材質(zhì)對象指針。為此,這里有一些參考規(guī)則:

提升unity gear vr游戲性能3
紋理集合/圖譜

 

  • 紋理集合(Macrotexture / Texture Atlases):通過將盡可能多的模型映射到少數(shù)幾個大的紋理集合中來達到盡可能少的紋理數(shù)量。
  • 靜態(tài)旗幟(Static Flag): 將所有不會移動的對象在 Unity 的 Inspector 中標記為靜態(tài)。
  • 材質(zhì)訪問:小心訪問 Renderer.material。這個操作會復制材質(zhì)并返回給你復件,導致對象被排除在批處理之外(因為材質(zhì)指針變成獨特的了)。請使用 Renderer.sharedMaterial。
  • 確保批處理是開啟的:在玩家設定(看下面)中確保靜態(tài)批處理和動態(tài)批處理都被開啟了。

Unity 提供兩種將網(wǎng)格批處理的方式:靜態(tài)批處理和動態(tài)批處理。

靜態(tài)批處理

一旦你把某個網(wǎng)格標記成靜態(tài),這意味著你告訴 Unity 這個對象永遠不會移動、變形或者縮放等。Unity 會基于這一點來自動將所有享用同樣材質(zhì)的網(wǎng)格整合成一個大的。在某些情況下,這將是很好的優(yōu)化;不僅減少了繪制調(diào)用數(shù)量,Unity 也把變形操作變成了頂點的位置選擇,這樣在運行時就不需要變形了。在一個場景內(nèi),越多的部分能被標記成靜態(tài)越好。要記得只有同樣材質(zhì)的才能被整合在一起哦!

但需要注意的是,靜態(tài)批處理生成了新的一個大網(wǎng)格,有可能導致最終的應用容量變得很大。一般來說對于 Gear VR 開發(fā)者問題不大,但如果你的應用里有很多不同場景,每個場景都有很多靜態(tài)網(wǎng)格,那么最終占用可能就會比較大。所以另一個選項就是在運行時使用StaticBatchingUtility.Combine來生成批處理網(wǎng)格,而不會讓你的應用變得太大(但你得付出一個一次性的 CPU 大量開銷以及一定的內(nèi)存占用的代價)。

最終,小心你的 Unity 版本,確認是否支持靜態(tài)批處理(看最后的注意事項)。

動態(tài)批處理

只要共享同樣的材料,Unity 也能把那些并沒有標記為靜態(tài)的網(wǎng)格進行批處理。只要你把動態(tài)批處理選項打開,剩下的基本就不太用管了。對每幀都進行批處理會對計算性能造成一些開銷,但一般來說對于整體性能表現(xiàn)總是會有提升。

批處理的其它問題

當然,還有其它一些情況也要小心。比如給物體繪制陰影啦,其它需要給物體轉(zhuǎn)換狀態(tài)的多通道著色器(Multi-pass shader)啦,都會讓批處理出現(xiàn)問題。多通道著色會讓網(wǎng)格被提交多次,針對 Gear VR 時務必要小心處理。逐像素光照(Per-pixel lighting)也有著類似的效果:使用 Unity4 里默認的擴散著色器(Diffuse Shader),網(wǎng)格會在每次被光線接觸時重新提交一次,很快會把你的繪制調(diào)用數(shù)和多邊形數(shù)耗光。如果你需要逐像素光照,可以試著在質(zhì)量設置窗口中的并發(fā)光照總數(shù)設置為一。最近的光線會被逐像素渲染,而周遭的光線會通過球面調(diào)和函數(shù)(Spherical Harmonics)來計算得出。更好的方式是放棄逐像素光照,采用光照探針。另外要注意的是批處理不支持蒙皮網(wǎng)格。透明對象必須要按某種順序來進行繪制所以很難被進行恰當?shù)呐幚怼?/span>

不過,你還是可以在編輯器中測試、調(diào)校批處理的。無論是在 Unity Profiler (Unity Pro 才有) 還是游戲窗口的統(tǒng)計欄中,都能顯示當前有多少繪制調(diào)用被下達了,多少被通過批處理節(jié)省了。如果你圍繞著很小數(shù)量的紋理來組織你的幾何圖形,那么確保不要實例化你的材質(zhì),并把靜態(tài)物體都標記上靜態(tài)的旗幟,這樣整個場景一般來說就比較節(jié)能環(huán)保綠色高效了。

透明,Alpha Test 以及重復繪制(Overdraw)

如上所提及,移動芯片一般都是“填充率瓶頸”,意味著像素填充可能是一幀中占用開銷最大的地方。減少填充開銷的關(guān)鍵就在于盡量讓每一個像素只被繪制一次。多通道著色器,逐像素光照效果(比如 Unity 的默認高光著色器)還有透明對象等都需要對像素進行多次渲染。太多的話,就會影響總線。

作為最佳實踐的標準之一,你可以在質(zhì)量設置(Quality Settings)中試著限制像素光照數(shù)(Pixel Light Count)為一。如果超過了一,你也要確保自己知道是哪部分的問題以及其造成的開銷。同樣,盡量讓透明的物體小。這里的開銷由碰到的像素決定,因此你接觸到的像素越少,這幀渲染的速度就越快。小心那些透明的粒子效果,比如煙霧等,其涉及到的像素數(shù)量可能會超過你的預期。

此外還要注意你不應該在移動設備上去使用 alpha test 著色器,比如 Unity 的鏤空著色器(Cutout Shader)。那些 Alpha Test 的操作(以及 clip(),或者片段著色器里的顯式丟棄), 會強制目前多數(shù)移動 GPU 撤銷那些硬件優(yōu)化,讓其運行變得極慢。在管線中丟棄片段也經(jīng)常會導致各種丑陋的反鋸齒,因此還是請用不透明幾何或者 Alpha to coverage 來做鏤空。

性能節(jié)流

在你能可靠測試你的場景之前,你需要確保 CPU 和 GPU 的節(jié)流設置已經(jīng)設定好了。因為 VR 游戲已經(jīng)把手機的性能壓榨到了極致,因此你需要好好掌握 CPU 和 GPU 之間的平衡。如果你的游戲瓶頸在 CPU,那么你可以為 GPU 降頻來讓 CPU 全速運轉(zhuǎn)。如果你的應用瓶頸在于 GPU 那你就反過來。如果你的應用效率非常高,那么你可以把 CPU 和 GPU 都降頻來降低耗電和溫度??梢栽?CPU 和 GPU 移動 SDK 文檔講述電源管理的章節(jié)“Power Management” 來查看更多關(guān)于 CPU 和 GPU 的節(jié)流設置方面的信息。

比較重要的一個地方是在做這類性能測試前必須先選定一個 CPU 和 GPU 的節(jié)流配置。如果這些具體的數(shù)值沒有被成功初始化,你的應用會被默認運行在降頻的環(huán)境下。由于多數(shù) Gear VR 的應用都會被 CPU 那邊的驅(qū)動開銷(比如繪制調(diào)用提交數(shù)目)所限制,因此一般來說對于頻率的設定會更有利 CPU 一些。你可以在 OVRModeParams.cs 中找到一個關(guān)于如何初始化節(jié)流目標的例子,也可以直接復制粘貼到一個在游戲開始時執(zhí)行的腳本里來檢驗效果。

注意事項

這幾天是你在考量自己應用性能表現(xiàn)時應當注意的:

  • 運行在 Lolipop 下驍龍805核心的 Note4 比起其它所有版本的 Note4 都要慢;貌似圖形驅(qū)動關(guān)于提交繪制調(diào)用這一塊有了退步。如果某些游戲在繪制調(diào)用這一塊已經(jīng)到底了那么有可能會發(fā)現(xiàn)新的瓶頸(最多可能達增加20%的響應時間),足夠讓常規(guī)的管線停頓并導致幀率下降。我們正努力和三星以及高通共通解決這個問題。運行安卓 4.4 的驍龍805 Note4 以及獵戶座 Note4 和 S6 設備皆不受此影響。
  • 盡管為 CPU 和 GPU 進行降頻節(jié)流能極大降低手機的熱量,那些開銷大的應用在長時間的使用過程中依然可能讓手機過熱。在這種情況發(fā)生時,手機會發(fā)出警告,然后動態(tài)降低處理器的頻率,一般都會導致應用幀率低到不可用的地步。如果你在做性能測試時碰到了這種情況,請關(guān)閉應用并讓手機休息個至少五分鐘再繼續(xù)測試。
  • Unity 4 免費版不支持靜態(tài)批處理以及 Unity Profiler。但是 Unity 5 個人版支持這些。
  • S6 不支持各向異性紋理過濾 。