你已經(jīng)決定使用Unity開發(fā)一款VR游戲脾猛,并且以Samsung GearVR作為你的目標(biāo)平臺嗤朴。想要在這個設(shè)備上運行起來其實很容易须肆,但是問題是,幀率實在是太低了合敦。你的十字準(zhǔn)星像粘住了一樣初橘,在視野的邊上還會閃爍黑邊,相機(jī)的移動看起來好像攝影師被踢了一樣糟糕充岛。你已經(jīng)知道維持一個穩(wěn)定的幀率有多重要保檐,現(xiàn)在終于知道為什么了——在移動VR應(yīng)用中,低于60FPS的時候不僅僅是看起來糟糕崔梗,更重要的是體驗超爛夜只。你的高端PC動輒跑到1000FPS,聽起來好像搭載了個噴氣機(jī)引擎蒜魄,但實際上但風(fēng)扇轉(zhuǎn)起來的時候沒有明顯提升(不太理解原作者這句話的意思)扔亥。你所需要的是一個優(yōu)化方法场躯,以便讓你的作品跑在移動芯片上。
GearVR環(huán)境與高效VR游戲的特點這并不是關(guān)于GearVR的一個包羅萬象的性能優(yōu)化介紹旅挤,這僅僅是個快速開始踢关。在這一篇博客中,我們將討論GearVR硬件粘茄,以及一個設(shè)計良好的移動VR程序的特點签舞。接下來的一篇博客將介紹你已經(jīng)構(gòu)建好的程序怎樣做性能優(yōu)化。這篇博客基于Unity做優(yōu)化柒瓣,因為它看起來在GearVR開發(fā)者中間比較流行儒搭。但是,這里提到的概念可以應(yīng)用于任何游戲引擎嘹朗。
了解你的硬件在你動手找到性能瓶頸以前师妙,應(yīng)該先思考一下手機(jī)的性能特點。一般來說屹培,移動圖形管線基于一個非衬ǎ快的CPU,一個非惩市悖快的GPU蓄诽,它們通過一個非常慢的總線或者內(nèi)存控制器連接,以及具有諸多限制的OpenGL ES驅(qū)動媒吗。GearVR運行在Samsung Note 4和Samsung Galaxy S6(估計這篇博客寫的時候是這樣的)仑氛。這兩個產(chǎn)品先實際上代表了許多不同的硬件配置:
Note4有兩種不同的芯片組。在南美和歐洲出售的設(shè)備基于高通驍龍Snapdragon處理器(驍龍805)闸英,而在韓國和亞洲其他地方出售的則是三星Exynos獵戶座處理器(獵戶座5433)锯岖。驍龍?zhí)幚砥饔兴膫€核心,而獵戶座有八個核心甫何。這些設(shè)備分別搭載了兩種不同的GPU:高通Adreno420圖形處理器和Mali-T760出吹。
Note4可以進(jìn)一步按操作系統(tǒng)劃分。大多數(shù)設(shè)備多運行這Android 4.4.4 (KitKat)辙喂,但是Android 5 (Lollipop) 已經(jīng)可以獲取更新了捶牢。使用Exynos獵戶座處理器的Note4設(shè)備全都運行在Android 5上面。
Galaxy S6設(shè)備都基于同樣的芯片組:三星獵戶座處理器Exynos 7420 (搭載Mali-T760M8 GPU)巍耗。S6還存在另一個版本秋麸,Galaxy S6 Edge,但是從內(nèi)部來說炬太,它和S6是一樣的灸蟆。
所有的Galaxy S6都是Android 5系統(tǒng)。
如果這看起來比較亂的話亲族,不要著急:盡管設(shè)備之間的硬件配置各部相同次乓,這些設(shè)備的性能測試方法非常類似(只有一個例外吓歇,參見下面“陷阱”一節(jié))。如果你能夠使他們在一臺設(shè)備上運行加快票腰,那么在其他設(shè)備上也會加快城看。
對大多數(shù)移動芯片組來說,3D圖形性能在這些設(shè)備有相當(dāng)可靠的特點测柠。下面列舉一些使得GearVR工程變慢的原因(按嚴(yán)重程度排序):
場景必須依賴渲染器(例如陰影和反射)(消耗CPU/GPU)
綁定VBOs來發(fā)射draw call(消耗CPU/驅(qū)動)
透明,多通道shader缘滥,逐像素光照轰胁,其他填充大量像素的效果(消耗GPU/IO)
大型紋理加載,傳送以及其他形式的內(nèi)存拷貝(消耗IO/內(nèi)存控制)
蒙皮動畫(消耗CPU)
Unity垃圾回收限制(消耗CPU)
另一方面朝扼,這些設(shè)備具有相對較大的內(nèi)存赃阀,可以塞進(jìn)去大量的多邊形。注意擎颖,Note4和S6都是2560x1440的顯示屏榛斯,默認(rèn)情況下,為了節(jié)省填充率我們渲染兩個1024x1024的紋理搂捧。
了解VR環(huán)境由于VR渲染每幀都要渲染兩次驮俗,每次渲染一只眼睛的圖像,非常消耗硬件性能允跑。在Unity 4.6.4p3和5.0.1p1版本中王凑,這意味著每個draw call都要發(fā)送兩次,每個mesh繪制兩次聋丝,每個紋理綁定兩次索烹。還有一個比較小的開銷,就是把最終的幀圖像輸出弱睦,包括扭曲和TimeWarp(大約2毫秒)百姓。將來肯定還會有進(jìn)一步優(yōu)化的,但是目前我們卡在整個幀渲染兩次每篷。這意味著瓣戚,渲染管線中一些開銷最大部分的消耗是一般的游戲的兩倍端圈。
考慮到這些焦读,下面是GearVR應(yīng)用的一些合理目標(biāo):
每幀50-100次draw call
每幀50k-10k個多邊形
紋理越少越好(可以使用大紋理)
腳本執(zhí)行時間1-3毫秒(Unity Update())
請記住,這些并不是死限制舱权,而是一些經(jīng)驗法則矗晃。
這幀畫面中有3萬個多邊形和40個draw call
還要注意,Oclus Mobile SDK引入了一個API宴倍,可以調(diào)節(jié)CPU和GPU的使用來控制手機(jī)發(fā)熱和電池消耗(示例用法查看OVRModeParams.cs)张症。這些方法允許你選擇CPU或者GPU哪個對你的場景更重要仓技。舉例來說,如果你需要更多的draw call提交俗他,把CPU調(diào)高(GPU調(diào)低)可能改進(jìn)整體幀率脖捻。如果你忽略了設(shè)置這些值,你的程序會被嚴(yán)重的限制住兆衅,所以花點時間來實驗是值得的地沮。
最后,GearVR具有Oculus的異步TimeWarp技術(shù)羡亩。當(dāng)你的游戲開始減慢的時候摩疑,TimeWarp基于最近的頭部位置信息,提供了中間幀畏铆。它通過扭曲前一幀來匹配最近的頭部位置雷袋,在掉幀的時候可以幫助你平穩(wěn)過度,所以沒有借口跑不到60幀辞居。當(dāng)你搖頭的時候楷怒,如果你在視場邊緣看到了黑色閃爍的條塊,這意味著你的游戲運行的太慢了速侈,就算TimeWarp也沒有足夠的幀圖像來填充空白了率寡。
面向性能的設(shè)計開發(fā)一個高性能程序的最佳方法就是預(yù)先設(shè)計好。對于GearVR應(yīng)用來說倚搬,這通常意味著圍繞移動設(shè)備GPU的特點來設(shè)計冶共。
設(shè)置在開始之前,確保你的Unity工程設(shè)置為最佳性能每界。特別的捅僵,一定要確保設(shè)置下面的選項:
Static batching
Dynamic batching
GPU skinning
Multithreaded Rendering
Default Orientation to Landscape Left
Batching既然知道了draw call通常是GearVR程序最耗費性能的部分,那么第一步就是要把場景所需draw call盡可能少眨层。一個draw call是一條發(fā)送給GPU使其繪制一個mesh或者一部分mesh的指令庙楚。這個操作代價最高的部分實際上是mesh本身的選擇。每次游戲決定繪制一個新mesh時趴樱,這個mesh在被發(fā)送到GPU之前必須被驅(qū)動處理過馒闷。Shader必須要綁定,可能發(fā)生格式轉(zhuǎn)換等等叁征;每次一個新mesh選定之后纳账,驅(qū)動都要使用CPU進(jìn)行工作。所以當(dāng)draw call發(fā)送時捺疼,最嚴(yán)重的開銷是這個選擇的過程疏虫。
然而,這也意味著,一旦一個mesh(或者更加具體的卧秘,頂點緩沖對象VBO)選擇之后呢袱,我們可以花費一次選擇的成本,然后對它渲染多次翅敌。只要沒有新mesh(或者shader羞福,或者紋理)被選擇,這個狀態(tài)會被驅(qū)動緩存下來蚯涮,然后draw call的發(fā)送就快多了坯临。為了利用這一點來提升性能,我們實際上可以把多個mesh打包成一個大的頂點數(shù)組恋昼,然后使用同一個VBO渲染它們看靠。我們花費了一次整體mesh的選擇成本,然后從包含在這個對象內(nèi)部的mesh中液肌,發(fā)送盡可能多的draw call挟炬。這個技巧叫做batching,比每個mesh都創(chuàng)建一個VBO的方法快的多嗦哆,這也是我們進(jìn)行draw call優(yōu)化的基礎(chǔ)谤祖。
包含在一個VBO中的所有mesh,為了能正確的batching老速,必須有相同的材質(zhì)設(shè)置:相同的紋理粥喜、相同的shader,相同的shader參數(shù)橘券。為了利用unity中的batching额湘,實際上你需要更進(jìn)一步:只有對象具有相同的材質(zhì)對象指針,他們才能給正確batching旁舰。最后锋华,下面是一些經(jīng)驗法則:
大紋理/紋理圖集:盡可能少的使用紋理,盡可能多的把模型映射到僅有的幾張大紋理上箭窜。
紋理圖集
Static標(biāo)志:在Unity Inspector中把從不移動物體標(biāo)記成Static毯焕。
材質(zhì)訪問:訪問Renderer.material的時候要小心。這將會復(fù)制一份材質(zhì)并返回磺樱,這會把該對象排除在batching之外(因為它的材質(zhì)指針不再相同了)纳猫。請使用Renderer.sharedMaterial。
確保batching打開了:在Player Settings中竹捉,確保Static Batching以及Dynamic Batching都打開了芜辕。
Unity 提供了兩種方法來把mesh打包在一起: Static Batching以及Dynamic Batching。
Static Batching當(dāng)你把一個mesh標(biāo)記為static活孩,你就是在告訴Unity這個對象不會移動物遇,動畫,或者縮放憾儒。Unity使用這個信息询兴,在構(gòu)建的時候自動的把共享材質(zhì)的mesh打包成一個大型的mesh。有些情況下起趾,這是一個非常重要的優(yōu)化诗舰;出來打包mesh減少draw call,Unity還把變換信息記錄在每個mesh的頂點位置中训裆,所以它們就不需要在運行時變換眶根。場景中標(biāo)記為static的部分越多越好。請記住為了進(jìn)行批處理該過程需要mesh具有同樣的材質(zhì)边琉。
注意属百,因為static batching在構(gòu)建時產(chǎn)生新的大型mesh,這會增加程序最終二進(jìn)制文件的大小变姨。這通常對GearVR開發(fā)者來說不是問題族扰,但是如果你的游戲有好多個獨立場景,并且每個場景有很多的靜態(tài)mesh定欧,加起來就會很大渔呵。另一個選項是使用StaticBatchingUtility.Combine在運行時來生成打包的紋理,而不會使你的程序體積膨脹(需要花費一次性的CPU使用和一些內(nèi)存)砍鸠。最后扩氢,請確保你正在使用的Unity版本支持static batching。
Dynamic BatchingUnity同樣可以打包沒有標(biāo)記為靜態(tài)的mesh爷辱,只要他們符合共享材質(zhì)的需求录豺。如果你打開了Dynamic Batching選項,這個過程幾乎可以自動生成饭弓。每幀計算要打包的mesh的時候會有一些開銷巩检,但是從性能的角度來看,通常會有一個明顯的提升示启。
其他batching問題要注意的是兢哭,有一些方法會破壞打包。渲染陰影和其他多通道shader需要一個狀態(tài)轉(zhuǎn)換夫嗓,使得對象不能正確的打包迟螺。多通道shader也會使得mesh被提交多次,在GearVR上應(yīng)該引起注意舍咖。逐像素的光照有同樣的效果:在Unity4中使用默認(rèn)的Diffuse著色器矩父,投射到mesh上的每個光源都會使得mesh提交一次。這會使得draw call很快增長并超過多邊形數(shù)量限制排霉。如果你需要逐像素的光照窍株,可以嘗試把Quality Setting窗口中同時光源的數(shù)量設(shè)置成1。最接近的光源會以逐像素方式進(jìn)行渲染,附近的光照將會使用球諧方法進(jìn)行計算球订。要更好的話后裸,刪除所有像素光照,使用光照探測器冒滩。還要注意的是微驶,batching通常對蒙皮的mesh不起作用。透明物體必須以一定的順序進(jìn)行渲染开睡,因此batch效果不太好因苹。
好消息是,你可以在編輯器中測試和調(diào)試batching篇恒。Unity Profiler和Game窗口中的Stats面板都可以告訴你發(fā)送了多少次draw call以及batching節(jié)省了多少資源扶檐。如果你的幾何體使用很少數(shù)量的紋理,那你就不用實例化材質(zhì)胁艰、標(biāo)記static對象蘸秘,你的場景也會很高效。
Transparency, Alpha Test, and Overdraw如上所述蝗茁,移動設(shè)備的芯片通常是“fill-bound”醋虏,意味著填充像素的花銷是一幀中最昂貴的部分。降低填充花銷的關(guān)鍵是每個屏幕上的像素都只渲染一次哮翘。多通道的shader颈嚼,逐像素光照效果(例如Unity默認(rèn)的specular著色器),還有透明物體都需要把它們涉及到的像素渲染多次饭寺。類似這些像素太多的話阻课,將會充滿總線。
做為一個最佳實踐艰匙,嘗試把Quality Settings中的Pixel Light Count限制到1.如果你使用了多余一個的逐像素光源限煞,確保你知道他們要作用于那個幾何體,以及渲染該幾何體多次的代價员凝。類似的署驻,讓透明物體盡量小點。因為主要的開銷是渲染像素健霹,所以物體占據(jù)的像素越小旺上,幀渲染完成的越快。注意像煙霧這樣的透明特效糖埋,可能占據(jù)比你想象中更多的像素宣吱。
還要注意的是,在移動設(shè)備上絕對不要使用alpha測試著色器瞳别,例如Unity的cutout著色器征候。Alpha測試的操作(還要clip()杭攻,或者像素著色器中顯式的discard操作)強制一些普通的移動設(shè)備GPU取消了硬件填充優(yōu)化,使得渲染非常慢疤坝。Discard像元的操作會導(dǎo)致大量難看的走樣(aliasing)兆解,盡量使用不透明物體。
Performance Throttling在你測試場景性能之前卒煞,你需要確保你設(shè)置了CPU和GPU的限制。因為VR游戲的性能達(dá)到了移動設(shè)備的界限叼架,你必須在CPU和GPU之間設(shè)置一個權(quán)重畔裕。如果你的游戲偏重CPU,為了讓CPU滿速運行乖订,你可以調(diào)低GPU扮饶。如果偏重GPU可以做相反的操作。如果你的游戲已經(jīng)很流暢了乍构,可以把兩者都調(diào)低甜无,這樣能夠節(jié)省電量,延長用戶在線時間哥遮。更多的信息請查看Mobile SDK documentation中的“Power Management”部分岂丘。
重要的是,在你開始任何類型的性能測試之前都要設(shè)置CPU和GPU限制眠饮。如果這些值初始化失敗的話奥帘,程序?qū)谀J(rèn)設(shè)置非常低的環(huán)境中運行。因為大多數(shù)GearVR應(yīng)用一般都會偏重CPU仪召,所以通常會把CPU調(diào)整的高于GPU寨蹋。OVRModeParams.cs中有一個關(guān)于怎樣初始化節(jié)流設(shè)置的例子,你可以復(fù)制粘貼到游戲啟動腳本中扔茅。
Gotchas陷阱在考慮性能優(yōu)化的時候已旧,你還應(yīng)該記住下面這些技巧:
有一個特殊的設(shè)備比其他都要慢,具體來說就是基于驍龍的Note 4運行Android 5的系統(tǒng)召娜,圖形驅(qū)動在draw call方面似乎有一個倒退运褪。對于draw call已經(jīng)達(dá)到限制的游戲,會發(fā)現(xiàn)這個問題非常嚴(yán)重(draw call時間增加了20%)玖瘸,會導(dǎo)致正常的渲染管線停滯并且整體幀率下降吐句。我們正和三星和高通努力解決這個問題。運行Android4.4系統(tǒng)的驍龍?zhí)幚砥鞯腘ote 4設(shè)備店读,還有Exynos處理器的Note 4和S6設(shè)備嗦枢,都不受此影響。
盡管對CPU和GPU進(jìn)行節(jié)流很大程度上減輕了手機(jī)的發(fā)熱屯断,對重量級的應(yīng)用來說文虏,在長時間運行的時候?qū)е略O(shè)備過熱仍然是可能的侣诺。這種情況發(fā)生時,手機(jī)會警告用戶氧秘,然后降低處理器的頻率年鸳,會導(dǎo)致VR應(yīng)用無法使用。如果你正在做性能測試和解決發(fā)熱問題丸相,請讓手機(jī)先休息五分鐘再繼續(xù)搔确。
Unity 4免費版不支持static batching和Unity Profiler。Unity 5的個人版已經(jīng)有了灭忠。
S6不支持各向異性紋理過濾膳算。
到此結(jié)束。下一篇弛作,我們將討論怎樣調(diào)試真實的性能問題涕蜂。
聯(lián)系方式:0755-81699111
課程網(wǎng)址: http://www.vrkuo.com/course/vr.html