UnityShader精要筆記十九 Unity中的渲染優(yōu)化技術(shù)

本文繼續(xù)對(duì)《UnityShader入門精要》——馮樂(lè)樂(lè) 第十六章 Unity中的渲染優(yōu)化技術(shù) 進(jìn)行學(xué)習(xí)

程序優(yōu)化的第一條準(zhǔn)則: 不要優(yōu)化。程序優(yōu)化的第二條準(zhǔn)則(僅針對(duì)專家猿推! 〉: 不要優(yōu)化垮兑。一一Michael A. Jackson

在進(jìn)行程序優(yōu)化的時(shí)候盯漂,人們經(jīng)常會(huì)引用英國(guó)的計(jì)算機(jī)科學(xué)家Michael A. Jackson 在1988 年的優(yōu)化準(zhǔn)則。Jackson 是想借此強(qiáng)調(diào),對(duì)問(wèn)題認(rèn)識(shí)不清以及過(guò)度優(yōu)化往往會(huì)讓事情變得更加復(fù)雜饼记,產(chǎn)生更多的程序錯(cuò)誤新荤。

然而凡橱, 如果我們?cè)谟螒蜷_(kāi)發(fā)過(guò)程中從來(lái)都沒(méi)有考慮優(yōu)化小作,那么結(jié)果往往是慘不忍睹的。一個(gè)正確的做法是稼钩, 從一開(kāi)始就把優(yōu)化當(dāng)成是游戲設(shè)計(jì)中的一部分顾稀。正在閱讀本書的讀者,有可能是移動(dòng)游戲的開(kāi)發(fā)者坝撑。和PC 相比静秆,移動(dòng)設(shè)備上的GPU 有著完全不同的架構(gòu)設(shè)計(jì),它能使用的帶寬巡李、功能和其他資源都非常有限抚笔。這要求我們需要時(shí)刻把優(yōu)化謹(jǐn)記在心,才可以避免等到項(xiàng)目完成時(shí)才發(fā)現(xiàn)游戲根本無(wú)法在移動(dòng)設(shè)備上流暢運(yùn)行的結(jié)果击儡。

在本章塔沃,我們將會(huì)闡述一些Unity 中常見(jiàn)的優(yōu)化技術(shù)蝠引。這些優(yōu)化技術(shù)都是和渲染相關(guān)的阳谍,例如蛀柴, 使用批處理、LOD (Level of Detail )技術(shù)等矫夯。在本章最后的擴(kuò)展閱讀部分鸽疾, 我們給出一些非常有價(jià)值的參考資料, 在那里讀者可以學(xué)習(xí)到更多真實(shí)項(xiàng)目中的優(yōu)化技術(shù)训貌。

在開(kāi)始學(xué)習(xí)之前制肮, 我們希望讀者能夠理解, 游戲優(yōu)化不僅是程序員的工作递沪,更需要美工人員在游戲的美術(shù)上進(jìn)行一定的權(quán)衡豺鼻,例如, 避免使用全屏的屏幕特效款慨, 避免使用計(jì)算復(fù)雜的shader, 減少透明混合造成的overdraw 等儒飒。也就是說(shuō),這是由程序員和美工人員等各個(gè)部分人員共同參與的工作檩奠。

一桩了、移動(dòng)平臺(tái)的特點(diǎn)

和PC 平臺(tái)相比,移動(dòng)平臺(tái)上的GPU 架構(gòu)有很大的不同埠戳。由于處理資源等條件的限制井誉, 移動(dòng)設(shè)備上的GPU 架構(gòu)專注于盡可能使用更小的帶寬和功能,也由此帶來(lái)了許多和PC 平臺(tái)完全不同的現(xiàn)象整胃。

例如颗圣,為了盡可能移除那些隱藏的表面,減少overdraw (即一個(gè)像素被繪制多次)爪模, PowerVR芯片(通常用于iOS 設(shè)備和某些Android 設(shè)備〉使用了基于瓦片的延遲渲染(Tiled-based Deferred Rendering, TBDR)架構(gòu)欠啤, 把所有的渲染圖像裝入一個(gè)個(gè)瓦片(tile )中,再由硬件找到可見(jiàn)的片元屋灌,而只有這些可見(jiàn)片元才會(huì)執(zhí)行片元著色器洁段。另一些基于瓦片的GPU 架構(gòu),如Adreno (高通的芯片)和Mali ( ARM 的芯片〉則會(huì)使用Early-Z 或相似的技術(shù)進(jìn)行一個(gè)低精度的的深度檢測(cè)共郭,來(lái)剔除那些不需要渲染的片元祠丝。還有一些GPU,如Tegra (英偉達(dá)的芯片〉除嘹,則使用了傳統(tǒng)的架構(gòu)設(shè)計(jì)写半, 因此在這些設(shè)備上,overdraw 更可能造成性能的瓶頸尉咕。

由于這些芯片架構(gòu)造成的不同叠蝇, 一些游戲往往需要針對(duì)不同的芯片發(fā)布不同的版本,以便對(duì)每個(gè)芯片進(jìn)行更有針對(duì)性的優(yōu)化年缎。尤其是在Android 平臺(tái)上悔捶,不同設(shè)備使用的硬件铃慷,如圖形芯片、屏幕分辨率等蜕该,大相徑庭犁柜,這對(duì)圖形優(yōu)化提出了更高的挑戰(zhàn)。相比與Android 平臺(tái)堂淡, iOS 平臺(tái)的硬件條件則相對(duì)統(tǒng)一馋缅。讀者可以在Unity 手冊(cè)的iOS 硬件指南( http://docs.unity3d.corn/Manual/iphone-Hardware.html )中找到相關(guān)的資料。

二绢淀、影響性能的因素

首先萤悴,在學(xué)習(xí)如何優(yōu)化之前,我們得了解影響游戲性能的因素有哪些皆的,才能對(duì)癥下藥稚疹。對(duì)于一個(gè)游戲來(lái)說(shuō),它主要需要使用兩種方式計(jì)算資源: CPU 和GPU祭务。它們會(huì)互相合作内狗,來(lái)讓我們的游戲可以在預(yù)期的幀率和分辨率下工作。其中义锥, CPU 主要負(fù)責(zé)保證幀率柳沙, GPU 主要負(fù)責(zé)分辨率相關(guān)的一些處理。據(jù)此拌倍,我們可以把造成游戲性能瓶頸的主要原因分成以下幾個(gè)方面赂鲤。

1.CPU
  • 過(guò)多的draw call 。
  • 復(fù)雜的腳本或者物理模擬柱恤。
2.GPU
  • 頂點(diǎn)處理数初。
    • 過(guò)多的頂點(diǎn)。
    • 過(guò)多的逐頂點(diǎn)計(jì)算梗顺。
  • 片元處理泡孩。
    • 過(guò)多的片元〈既可能是由于分辨率造成的,也可能是由于overdraw 造成的〉寺谤。
    • 過(guò)多的逐片元計(jì)算仑鸥。
3.帶寬
  • 使用了尺寸很大且未壓縮的紋理。
  • 分辨率過(guò)高的幀緩存变屁。

對(duì)于CPU 來(lái)說(shuō)眼俊,限制它的主要是每一幀中draw call 的數(shù)目。我們?cè)?.2 節(jié)和2.4.3 節(jié)中介紹過(guò)draw call 的相關(guān)概念和原理粟关。簡(jiǎn)單來(lái)說(shuō)疮胖,就是CPU 在每次通知GPU 進(jìn)行渲染之前,都需要提前準(zhǔn)備好頂點(diǎn)數(shù)據(jù)(如位置、法線澎灸、顏色谷市、紋理坐標(biāo)等〉,然后調(diào)用一系列API 把它們放到GPU 可以訪問(wèn)到的指定位置击孩,最后,調(diào)用一個(gè)繪制命令鹏漆,來(lái)告訴GPU 巩梢,“嘿,我把東西都準(zhǔn)備好了艺玲,你趕緊出來(lái)干活(渲染〉吧括蝠!”。而調(diào)用繪制命令的時(shí)候饭聚,就會(huì)產(chǎn)生一個(gè) draw call忌警。過(guò)多的draw call 會(huì)造成CPU 的性能瓶頸,這是因?yàn)槊看握{(diào)用draw call 時(shí)秒梳, CPU 往往都需要改變很多渲染狀態(tài)的設(shè)置法绵,而這些操作是非常耗時(shí)的。如果一幀中需要的draw call 數(shù)目過(guò)多的話酪碘,就會(huì)導(dǎo)致CPU 把大部分時(shí)間都花費(fèi)在提交draw call 的工作上面了朋譬。當(dāng)然,其他原因也可能造成CPU 瓶頸兴垦,例如物理徙赢、布料模擬、蒙皮探越、粒子模擬等狡赐,這些都是計(jì)算量很大的操作,但由于本書主要討論Shader 方面的相關(guān)技術(shù)钦幔,因此枕屉,這些內(nèi)容不在本書的討論范圍內(nèi)。

而對(duì)于GPU 來(lái)說(shuō)鲤氢,它負(fù)責(zé)整個(gè)渲染流水線搀庶。它從處理CPU 傳遞過(guò)來(lái)的模型數(shù)據(jù)開(kāi)始,進(jìn)行頂點(diǎn)著色器铜异、片元著色器等一系列工作哥倔,最后輸出屏幕上的每個(gè)像素。因此揍庄, GPU 的性能瓶頸和需要處理的頂點(diǎn)數(shù)目咆蒿、屏幕分辨率、顯存等因素有關(guān)。而相關(guān)的優(yōu)化策略可以從減少處理的數(shù)據(jù)規(guī)模(包括頂點(diǎn)數(shù)目和片元數(shù)目〉沃测、減少運(yùn)算復(fù)雜度等方面入手缭黔。

在了解了上面基本的內(nèi)容后,本章后續(xù)章節(jié)會(huì)涉及的優(yōu)化技術(shù)有:

  • CPU 優(yōu)化蒂破。
    • 使用批處理技術(shù)減少draw call 數(shù)目馏谨。
  • GPU 優(yōu)化。
    • 減少需要處理的頂點(diǎn)數(shù)目附迷。
      • 優(yōu)化幾何體惧互。
      • 使用模型的LOD (Level ofDetail )技術(shù)。
      • 使用遮擋剔除( Occlusion Culling )技術(shù)喇伯。
    • 減少需要處理的片元數(shù)目喊儡。
      • 控制繪制順序。
      • 警惕透明物體稻据。
      • 減少實(shí)時(shí)光照艾猜。
    • 減少計(jì)算復(fù)雜度。
      • 使用Shader 的LOD (Level of Detail) 技術(shù)捻悯。
      • 代碼方面的優(yōu)化匆赃。
  • 節(jié)省內(nèi)存帶寬。
    • 減少紋理大小今缚。
    • 利用分辨率縮放炸庞。
三、Unity 中的渲染分析工具

在開(kāi)始優(yōu)化之前荚斯,我們首先需要知道是哪個(gè)步驟造成了性能瓶頸埠居。而這可以利用Unity 提供的一些渲染分析工具來(lái)實(shí)現(xiàn)。Unity 內(nèi)置了一些工具事期,來(lái)幫助我們方便地查看和渲染相關(guān)的各個(gè)統(tǒng)計(jì)數(shù)據(jù)滥壕。這些數(shù)據(jù)可以幫助我們分析游戲渲染性能,從而更有針對(duì)性地進(jìn)行優(yōu)化兽泣。在Unity 5 中绎橘,這些工具包括了渲染統(tǒng)計(jì)窗口( Rendering Statistics Window )、性能分析器( Profiler ) 唠倦,以及幀調(diào)試器( Frame Debugger )称鳞。需要注意的是,在不同的目標(biāo)平臺(tái)上稠鼻,這些工具中顯示的數(shù)據(jù)也會(huì)發(fā)生變化冈止。

1.認(rèn)識(shí)Unity 5 的渲染統(tǒng)計(jì)窗口

Unity 5 提供了一個(gè)全新的窗口,即渲染統(tǒng)計(jì)窗口(Rendering Statistics Window )來(lái)顯示當(dāng)前游戲的各個(gè)渲染統(tǒng)計(jì)變量候齿,我們可以通過(guò)在Game 視圖右上方的菜單中單擊Stats 按鈕來(lái)打開(kāi)它熙暴,如圖16.1 所示闺属。從圖16.1 中可以看出, 渲染統(tǒng)計(jì)窗口主要包含了3 個(gè)方面的信息: 音頻(Audio )周霉、圖像( Graphics )和網(wǎng)絡(luò)(Network)掂器。我們這里只關(guān)注第二個(gè)方面,即圖像相關(guān)的渲染統(tǒng)計(jì)結(jié)果俱箱。


圖16.1 Unity 5的渲染統(tǒng)計(jì)窗口

渲染統(tǒng)計(jì)窗口中顯示了很多重要的渲染數(shù)據(jù)国瓮,例如FPS 、批處理數(shù)目狞谱、頂點(diǎn)和三角網(wǎng)格的數(shù)目等乃摹。表16.1 列出了渲染統(tǒng)計(jì)窗口中顯示的各個(gè)信息。

image.png

image.png

Unity 5 的渲染統(tǒng)計(jì)窗口相較于之前版本中的有了一些變化芋簿,最明顯的區(qū)別之一就是去掉了draw call 數(shù)目的顯示,而添加了批處理數(shù)目的顯示璃饱。Batches 和Saved by batching 更容易讓開(kāi)發(fā)者理解批處理的優(yōu)化結(jié)果与斤。當(dāng)然,如果我們想要查看draw call 的數(shù)目等其他更加詳細(xì)的數(shù)據(jù)猪狈,可以通過(guò)Unity 編輯器的性能分析器來(lái)查看冯吓。

2.性能分析器的渲染區(qū)域

我們可以通過(guò)單擊Window -> Profiler 來(lái)打開(kāi)Unity 的性能分析器(Profiler) 霍弹。 性能分析器中的渲染區(qū)域(Rendering Area )提供了更多關(guān)于渲染的統(tǒng)計(jì)信息,圖16.2 給出了對(duì)圖16.1 中場(chǎng)景的渲染分析結(jié)果食寡。


圖16.2 使用Unity的性能分析器中的渲染區(qū)域來(lái)查看更多關(guān)于渲染的統(tǒng)計(jì)信息

性能分析器顯示了絕大部分在渲染統(tǒng)計(jì)窗口中提供的信息,例如廓潜,綠線顯示了批處理數(shù)目抵皱、藍(lán)線顯示了Pass 數(shù)目等,同時(shí)還給出了許多其他非常有用的信息辩蛋,例如呻畸, draw call 數(shù)目、動(dòng)態(tài)批處理/靜態(tài)批處理的數(shù)目悼院、渲染紋理的數(shù)目和內(nèi)存占用等伤为。

結(jié)合渲染統(tǒng)計(jì)窗口和性能分析器,我們可以查看與渲染相關(guān)的絕大多數(shù)重要的數(shù)據(jù)据途。一個(gè)值得注意的現(xiàn)象是绞愚,性能分析器給出的draw call 數(shù)目和批處理數(shù)目、Pass 數(shù)目并不相等颖医,并且看起來(lái)好像要大于我們估算的數(shù)目位衩,這是因?yàn)閁nity 在背后需要進(jìn)行很多工作,例如熔萧,初始化各個(gè)緩存蚂四、為陰影更新深度紋理和陰影映射紋理等光戈,因此需要花費(fèi)比“預(yù)期”更多的draw call。一個(gè)好消息是遂赠,Unity 5 引入了一個(gè)新的工具來(lái)幫助我們查看每一個(gè)draw call 的工作久妆,這個(gè)工具就是幀調(diào)試器。

3.再談幀調(diào)試器

我們已經(jīng)在之前的章節(jié)中多次看到幀調(diào)試器(Frame Debugger) 的應(yīng)用跷睦,例如5.5.3 節(jié)中解釋了如何使用幀調(diào)試器來(lái)對(duì)Shader 進(jìn)行調(diào)試筷弦。我們可以通過(guò)Window -> Frame Debugger 來(lái)打開(kāi)它。在這個(gè)窗口中抑诸,我們可以清楚地看到每一個(gè)draw call 的工作和結(jié)果烂琴,如圖16.3 所示。


圖16.3 使用幀調(diào)試器來(lái)查看單獨(dú)的draw call的繪制結(jié)果

幀調(diào)試器的調(diào)試面板上顯示了渲染這一幀所需要的所有的渲染事件蜕乡,在本例中奸绷,事件數(shù)目為14,而其中包含了10 個(gè)draw call 事件〈其他渲染事件多為清空緩存等〉层玲。通過(guò)單擊面板上的每個(gè)事件号醉,我們可以在Game 視圖查看該事件的繪制結(jié)果,同時(shí)渲染統(tǒng)計(jì)面板上的數(shù)據(jù)也會(huì)顯示成截止到當(dāng)前事件為止的各個(gè)渲染統(tǒng)計(jì)數(shù)據(jù)辛块。以本例為例〈場(chǎng)景如圖16.1 所示〉畔派,要渲染一幀共需要花費(fèi)10 個(gè)draw call,其中4 個(gè)draw call 用于更新深度紋理(對(duì)應(yīng)UpdateDepthTexture), 4 個(gè)draw call 用于渲染平行光的陰影映射紋理润绵,1 個(gè)draw call 用于繪制動(dòng)態(tài)批處理后的3 個(gè)立方體模型线椰, 1 個(gè)draw call 用于繪制球體。

在Unity 的渲染統(tǒng)計(jì)窗口尘盼、分析器和幀調(diào)試器這3 個(gè)利器的幫助下憨愉,我們可以獲得很多有用的優(yōu)化信息。但是卿捎,很多諸如渲染時(shí)間這樣的數(shù)據(jù)是基于當(dāng)前的開(kāi)發(fā)平臺(tái)得到的莱衩,而非真機(jī)上的結(jié)果。事實(shí)上娇澎, Unity 正在和硬件生產(chǎn)商合作笨蚁,來(lái)首先讓使用英偉達(dá)圖睿( Tegra)的設(shè)備可以出現(xiàn)在Unity 的性能分析器中。我們有理由相信趟庄,在后續(xù)的Unity 版本中括细,直接在Unity 中對(duì)移動(dòng)設(shè)備進(jìn)行性能分析不再是夢(mèng)想。然而戚啥,在這個(gè)夢(mèng)想實(shí)現(xiàn)之前奋单,我們?nèi)匀恍枰恍┩獠康男阅芊治龉ぞ叩膸椭?/p>

4.其他性能分析工具

對(duì)于移動(dòng)平臺(tái)上的游戲來(lái)說(shuō),我們更希望得到在真機(jī)上運(yùn)行游戲時(shí)的性能數(shù)據(jù)猫十。這時(shí)览濒,Unity 目前提供的各個(gè)工具可能就不再能滿足我們的需求了呆盖。

對(duì)于Android 平臺(tái)來(lái)說(shuō),高通的Adreno 分析工具可以對(duì)不同的測(cè)試機(jī)進(jìn)行詳細(xì)的性能分析贷笛。英偉達(dá)提供了NVPerfHUD 工具來(lái)幫助我們得到幾乎所有需要的性能分析數(shù)據(jù)应又,例如,每個(gè)draw call 的GPU 時(shí)間乏苦,每個(gè)shader 花費(fèi)的cycle 數(shù)目等株扛。

對(duì)于iOS 平臺(tái)來(lái)說(shuō), Unity 內(nèi)置的分析器可以得到整個(gè)場(chǎng)景花費(fèi)的GPU 時(shí)間汇荐。PowerVRAM的 PVRUniSCo shader 分析器也可以給出一個(gè)大致的性能評(píng)估洞就。Xcode 中的OpenGL ES Driver Instruments 可以給出一些宏觀上的性能信息,例如掀淘,設(shè)備利用率旬蟋、渲染器利用率等。但相對(duì)于Android 平臺(tái)革娄,對(duì)iOS 的性能分析更加困難(工具較少)倾贰。而且PowerVR 芯片采用了基于瓦片的延遲渲染器,因此稠腊,想要得到每個(gè)draw call 花費(fèi)的GPU 時(shí)間是幾乎不可能的躁染。這時(shí)鸣哀,一些宏觀上的統(tǒng)計(jì)數(shù)據(jù)可能更有參考價(jià)值架忌。

一些其他的性能分析工具可以在Unity 的官方手冊(cè)( http://docs.unity3d.com/Manual/MobileProfiling.html )中找到。當(dāng)找到了性能瓶頸后我衬,我們就可以針對(duì)這些方面進(jìn)行特定的優(yōu)化叹放。

四、減少draw call 數(shù)目

讀者最衬痈幔看到的優(yōu)化技術(shù)大概就是批處理( batching )了井仰。批處理的實(shí)現(xiàn)原理就是為了減少每一幀需要的draw call 數(shù)目。為了把一個(gè)對(duì)象渲染到屏幕上破加, CPU 需要檢查哪些光源影響了該物體俱恶,綁定shader 并設(shè)置它的參數(shù),再把渲染命令發(fā)送給GPU范舀。當(dāng)場(chǎng)景中包含了大量對(duì)象時(shí)合是,這些操作就會(huì)非常耗時(shí)。一個(gè)極端的例子是锭环,如果我們需要渲染一千個(gè)三角形聪全,把它們按一千個(gè)單獨(dú)的網(wǎng)格進(jìn)行渲染所花費(fèi)的時(shí)間要遠(yuǎn)遠(yuǎn)大于渲染一個(gè)包含了一千個(gè)三角形的網(wǎng)格。在這兩種情況下辅辩,GPU 的性能消耗其實(shí)并沒(méi)有多大的區(qū)別难礼,但CPU 的draw call 數(shù)目就會(huì)成為性能瓶頸娃圆。因此,批處理的思想很簡(jiǎn)單蛾茉,就是在每次面對(duì)draw call 時(shí)盡可能多地處理多個(gè)物體讼呢。我們已經(jīng)在2.2 節(jié)和 2.4.3 節(jié)中詳細(xì)地講述了draw call 和批處理之間的聯(lián)系,本節(jié)旨在介紹如何在Unity 中利用批處理技術(shù)來(lái)優(yōu)化渲染臀稚。

那么吝岭,什么樣的物體可以一起處理呢?答案就是使用同一個(gè)材質(zhì)的物體吧寺。這是因?yàn)榇芄埽瑢?duì)于使用同一個(gè)材質(zhì)的物體,它們之間的不同僅僅在于頂點(diǎn)數(shù)據(jù)的差別稚机。我們可以把這些頂點(diǎn)數(shù)據(jù)合并在一起幕帆,再一起發(fā)送給GPU,就可以完成一次批處理赖条。

Unity 中支持兩種批處理方式:

  • 一種是動(dòng)態(tài)批處理失乾,另一種是靜態(tài)批處理。對(duì)于動(dòng)態(tài)批處理來(lái)說(shuō)纬乍,優(yōu)點(diǎn)是一切處理都是Unity 自動(dòng)完成的碱茁,不需要我們自己做任何操作,而且物體是可以移動(dòng)的仿贬,但缺點(diǎn)是纽竣,限制很多,可能一不小心就會(huì)破壞了這種機(jī)制茧泪,導(dǎo)致Unity 無(wú)法動(dòng)態(tài)批處理一些使用了相同材質(zhì)的物體蜓氨。
  • 而對(duì)于靜態(tài)批處理來(lái)說(shuō),它的優(yōu)點(diǎn)是自由度很高队伟,限制很少穴吹;但缺點(diǎn)是可能會(huì)占用更多的內(nèi)存,而且經(jīng)過(guò)靜態(tài)批處理后的所有物體都不可以再移動(dòng)了(即便在腳本中嘗試改變物體的位置也是無(wú)效的〉嗜侮。
1.動(dòng)態(tài)批處理

如果場(chǎng)景中有一些模型共享了同一個(gè)材質(zhì)并滿足一些條件港令, Unity 就可以自動(dòng)把它們進(jìn)行批處理,從而只需要花費(fèi)一個(gè)draw call 就可以渲染所有的模型锈颗。動(dòng)態(tài)批處理的基本原理是顷霹,每一幀把可以進(jìn)行批處理的模型網(wǎng)格進(jìn)行合并,再把合并后模型數(shù)據(jù)傳遞給GPU然后使用同一個(gè)材質(zhì)對(duì)其渲染宜猜。除了實(shí)現(xiàn)方便泼返,動(dòng)態(tài)批處理的另一個(gè)好處是,經(jīng)過(guò)批處理的物體仍然可以移動(dòng)姨拥,這是由于在處理每幀時(shí)Unity 都會(huì)重新合并一次網(wǎng)格绅喉。

雖然Unity 的動(dòng)態(tài)批處理不需要我們進(jìn)行任何額外工作渠鸽,但只有滿足條件的模型和材質(zhì)才可以被動(dòng)態(tài)批處理。需要注意的是柴罐,隨著Unity 版本的變化徽缚,這些條件也有一些改變。在本節(jié)中革屠,我們給出一些主要的條件限制凿试。

  • 能夠進(jìn)行動(dòng)態(tài)批處理的網(wǎng)格的頂點(diǎn)屬性規(guī)模要小于900 。例如似芝,如果shader 中需要使用頂點(diǎn)位置那婉、法線和紋理坐標(biāo)這3 個(gè)頂點(diǎn)屬性,那么要想讓模型能夠被動(dòng)態(tài)批處理党瓮,它的頂點(diǎn)數(shù)目不能超過(guò)300详炬。需要注意的是,這個(gè)數(shù)字在未來(lái)有可能會(huì)發(fā)生變化寞奸,因此不要依賴這個(gè)數(shù)據(jù)呛谜。
  • 一般來(lái)說(shuō),所有對(duì)象都需要使用同一個(gè)縮放尺度(可以是(1, 1, 1 )枪萄、( 1, 2, 3)隐岛、(1.5, 1.4,1.3)等瓷翻,但必須都一樣〉聚凹。一個(gè)例外情況是,如果所有的物體都使用了不同的非統(tǒng)一縮放逻悠,那么它們也是可以被動(dòng)態(tài)批處理的元践。但在Unity 5 中韭脊,這種對(duì)模型縮放的限制已經(jīng)不存在了童谒。
  • 使用光照紋理(lightmap )的物體需要小心處理。這些物體需要額外的渲染參數(shù)沪羔,例如饥伊,在光照紋理上的索引、偏移量和縮放信息等蔫饰。因此琅豆,為了讓這些物體可以被動(dòng)態(tài)批處理,我們需要保證它們指向光照紋理中的同一個(gè)位置篓吁。
  • 多Pass 的shader 會(huì)中斷批處理茫因。在前向渲染中,我們有時(shí)需要使用額外的Pass 來(lái)為模型添加更多的光照效果杖剪,但這樣一來(lái)模型就不會(huì)被動(dòng)態(tài)批處理了冻押。

在本書資源的Scene_16_3_1 場(chǎng)景中驰贷,我們給出了這樣一個(gè)場(chǎng)景。場(chǎng)景中包含了3 個(gè)立方體洛巢,它們使用同一個(gè)材質(zhì)括袒,同時(shí)還包含了一個(gè)使用其他材質(zhì)的球體。場(chǎng)景中還包含了一個(gè)平行光稿茉,但我們關(guān)閉了它的陰影效果锹锰,以避免陰影計(jì)算對(duì)批處理數(shù)目的影響。這樣一個(gè)場(chǎng)景的渲染統(tǒng)計(jì)數(shù)據(jù)如圖16.4 所示漓库。


圖16.4 動(dòng)態(tài)批處理

從圖16.4 中可以看出恃慧,要渲染這樣一個(gè)包含了4 個(gè)物體的場(chǎng)景共需要兩個(gè)批處理。其中渺蒿, 一個(gè)批處理用于繪制經(jīng)過(guò)動(dòng)態(tài)批處理合并后的3 個(gè)立方體網(wǎng)格糕伐,另一個(gè)批處理用于繪制球體。我們可以從Save by batching看出批處理幫我們節(jié)省了兩個(gè)draw Call蘸嘶。
現(xiàn)在良瞧,我們?cè)傧驁?chǎng)景中添加一個(gè)點(diǎn)光源,并調(diào)整它的位置使它可以照亮場(chǎng)景中的4 個(gè)物體训唱。由于場(chǎng)景中的物體都使用了多個(gè)Pass 的shader褥蚯,因此,點(diǎn)光源會(huì)對(duì)它們產(chǎn)生光照影響况增。圖16.5 給出了添加點(diǎn)光源后的渲染統(tǒng)計(jì)數(shù)據(jù)赞庶。


圖16.5 多光源對(duì)動(dòng)態(tài)批處理的影響結(jié)果

從圖16.5 中可以看出,渲染一幀所需的批處理數(shù)目增大到了8 澳骤,而Save by batching的數(shù)目也變成了0歧强。這是因?yàn)椋褂昧硕鄠€(gè)Pass 的shader 在需要應(yīng)用多個(gè)光照的情況下为肮,破壞了動(dòng)態(tài)批處理的機(jī)制摊册, 導(dǎo)致Unity 不能對(duì)這些物體進(jìn)行動(dòng)態(tài)批處理。而由于平行光和點(diǎn)光源需要對(duì)4 個(gè)物體分別產(chǎn)生影響颊艳,因此茅特, 需要2×4 個(gè)批處理操作。需要注意的是棋枕,只有物體在點(diǎn)光源的影響范圍內(nèi)白修,Unity 才會(huì)調(diào)用額外的Pass 來(lái)處理它。因此重斑, 如果場(chǎng)景中點(diǎn)光源距離物體很遠(yuǎn)朵夏,那么它們?nèi)匀粫?huì)被動(dòng)態(tài)批處理的唾戚。

動(dòng)態(tài)批處理的限制條件比較多丐箩,例如很多時(shí)候惩妇,我們的模型數(shù)據(jù)往往會(huì)超過(guò)900 的頂點(diǎn)屬性限制。這種時(shí)候依賴動(dòng)態(tài)批處理來(lái)減少draw call 顯然已經(jīng)不能夠滿足我們的需求了。這時(shí),我們可以使用Unity 的靜態(tài)批處理技術(shù)。

2.靜態(tài)批處理

Unity 提供了另一種批處理方式若债, 即靜態(tài)批處理。相比于動(dòng)態(tài)批處理來(lái)說(shuō)拆融,靜態(tài)批處理適用任何大小的幾何模型蠢琳。它的實(shí)現(xiàn)原理是, 只在運(yùn)行開(kāi)始階段镜豹, 把需要進(jìn)行靜態(tài)批處理的模型合并到一個(gè)新的網(wǎng)格結(jié)構(gòu)中傲须, 注意味著這些模型不可以在運(yùn)行時(shí)刻被移動(dòng)。但由于它只需要進(jìn)行一次合并操作趟脂, 因此泰讽, 比動(dòng)態(tài)批處理更加高效。

靜態(tài)批處理的另一個(gè)缺點(diǎn)在于昔期,它往往需要占用更多的內(nèi)存來(lái)存儲(chǔ)合并后的幾何結(jié)構(gòu)已卸。這是因?yàn)椋绻陟o態(tài)批處理前一些物體共享了相同的網(wǎng)格硼一,那么在內(nèi)存中每一個(gè)物體都會(huì)對(duì)應(yīng)一個(gè)該網(wǎng)格的復(fù)制品累澡,即一個(gè)網(wǎng)格會(huì)變成多個(gè)網(wǎng)格再發(fā)送給GPU 。如果這類使用同一網(wǎng)格的對(duì)象很多般贼, 那么這就會(huì)成為一個(gè)性能瓶頸了愧哟。

例如,如果在一個(gè)使用了1000 個(gè)相同樹(shù)模型的森林中使用靜態(tài)批處理哼蛆,那么蕊梧,就會(huì)多使用1000 倍的內(nèi)存, 這會(huì)造成嚴(yán)重的內(nèi)存影響腮介。這種時(shí)候肥矢, 解決方法要么忍受這種犧牲內(nèi)存換取性能的方法,要么不要使用靜態(tài)批處理萤厅,而使用動(dòng)態(tài)批處理技術(shù)(但要小心控制模型的頂點(diǎn)屬性數(shù)目)橄抹,或者自己編寫批處理的方法靴迫。

在本書資源的Scene_16_3_2 場(chǎng)景中惕味,我們給出了一個(gè)測(cè)試靜態(tài)批處理的場(chǎng)景。場(chǎng)景中包含了3 個(gè)Teapot 模型玉锌, 它們使用同一個(gè)材質(zhì)名挥,同時(shí)還包含了一個(gè)使用不同材質(zhì)的立方體。場(chǎng)景中還包含了一個(gè)平行光主守,但我們關(guān)閉了它的陰影效果禀倔,以避免陰影計(jì)算對(duì)批處理數(shù)目的影響榄融。在運(yùn)行前,這樣一個(gè)場(chǎng)景的渲染統(tǒng)計(jì)數(shù)據(jù)如圖16.6 所示救湖。


圖16.6 靜態(tài)批處理前的渲染統(tǒng)計(jì)數(shù)據(jù)

從圖16.6 中可以看出愧杯, 盡管3 個(gè)Teapot 模型使用了相同的材質(zhì), 但它們?nèi)匀粵](méi)有被動(dòng)態(tài)批處理鞋既。這是因?yàn)椋?Teapot 模型包含的頂點(diǎn)數(shù)目是393 力九, 而它們使用的shader 中需要使用4 個(gè)頂點(diǎn)屬性(頂點(diǎn)位置、法線方向邑闺、切線方向和紋理坐標(biāo)〉跌前,超過(guò)了動(dòng)態(tài)批處理中限定的900 限制。此時(shí)陡舅,要想減少draw call 就需要使用靜態(tài)批處理抵乓。
靜態(tài)批處理的實(shí)現(xiàn)非常簡(jiǎn)單, 只需要把物體面板上的Static 復(fù)選框句選上即可(實(shí)際上我們只需要勾選Batching Static 即可)靶衍,如圖16.7 所示灾炭。


圖16.7 把物體標(biāo)志為Static

這時(shí),我們?cè)儆^察渲染統(tǒng)計(jì)窗口中的批處理數(shù)目颅眶,還是沒(méi)有變化咆贬。但是不要急,運(yùn)行程序后帚呼,變化就出現(xiàn)了掏缎,如圖16.8 所示。
image.png

從圖16.8 中可以看出煤杀,現(xiàn)在的批處理數(shù)目變成了2眷蜈,而Save by batching 數(shù)目也顯示為2。此時(shí)沈自,如果我們?cè)谶\(yùn)行時(shí)查看每個(gè)模型使用的網(wǎng)格酌儒,會(huì)發(fā)現(xiàn)它們都變成了一個(gè)名為Combined Mesh (root: scene)的東西,如圖16.9 所示枯途。


圖16.9 靜態(tài)批處理中Unity會(huì)合并所有被標(biāo)識(shí)為“Static”的物體

這個(gè)網(wǎng)格是Unity 合并了所有被標(biāo)識(shí)為“Static”的物體的結(jié)果忌怎,在我們的例子里,就是3 個(gè)Teapot 和一個(gè)立方體酪夷。讀者可能會(huì)有一個(gè)疑問(wèn)榴啸,這4 個(gè)對(duì)象明明不是都使用了一個(gè)材質(zhì),為什么可以合并成一個(gè)呢晚岭?如果你仔細(xì)觀看圖16.9 的結(jié)果鸥印,會(huì)發(fā)現(xiàn)在圖16.9 的右下方標(biāo)明了“4 submeshes”,也就是說(shuō),這個(gè)合并后的網(wǎng)格其實(shí)包含了4 個(gè)子網(wǎng)格库说,即場(chǎng)景中的4 個(gè)對(duì)象狂鞋。對(duì)于合并后的網(wǎng)格, Unity 會(huì)判斷其中使用同一個(gè)材質(zhì)的子網(wǎng)格潜的,然后對(duì)它們進(jìn)行批處理骚揍。

在內(nèi)部實(shí)現(xiàn)上,Unity 首先把這些靜態(tài)物體變換到世界空間下啰挪,然后為它們構(gòu)建一個(gè)更大的頂點(diǎn)和索引緩存疏咐。對(duì)于使用了同一材質(zhì)的物體,Unity 只需要調(diào)用一個(gè)draw call 就可以繪制全部物體脐供。而對(duì)于使用了不同材質(zhì)的物體浑塞,靜態(tài)批處理同樣可以提升渲染性能。盡管這些物體仍然需要調(diào)用多個(gè)draw call 政己,但靜態(tài)批處理可以減少這些draw call 之間的狀態(tài)切換酌壕,而這些切換往往是費(fèi)時(shí)的操作。從合并后的網(wǎng)格結(jié)構(gòu)中我們還可以發(fā)現(xiàn)歇由,盡管3 個(gè)Teapot 對(duì)象使用了同一個(gè)網(wǎng)格卵牍,但合并后卻變成了3 個(gè)獨(dú)立網(wǎng)格。

圖16.10 靜態(tài)批處理會(huì)占用更多的內(nèi)存沦泌。左圖:靜態(tài)批處理前的渲染統(tǒng)計(jì)數(shù)據(jù)糊昙。右圖:靜態(tài)批處理后的渲染統(tǒng)計(jì)數(shù)據(jù)

而且,我們可以從Unity 的分析器中觀察到在應(yīng)用靜態(tài)批處理前后VBO total的變化谢谦,從圖16.10 所示中可以看出释牺,VBO ( Vertex Buffer Object,頂點(diǎn)緩沖對(duì)象〉的數(shù)目變大了回挽。這正是因?yàn)殪o態(tài)批處理會(huì)占用更多內(nèi)存的緣故没咙,正如本節(jié)一開(kāi)頭所講,靜態(tài)批處理需要占用更多的內(nèi)存來(lái)存儲(chǔ)合并后的幾何結(jié)構(gòu)千劈,如果一些物體共享了相同的網(wǎng)格祭刚,那么在內(nèi)存中每一個(gè)物體都會(huì)對(duì)應(yīng)一個(gè)該網(wǎng)格的復(fù)制品。

如果場(chǎng)景中包含了除了平行光以外的其他光源墙牌,并且在shader 中定義了額外的Pass 來(lái)處理它們涡驮,這些額外的Pass 部分是不會(huì)被批處理的。圖16.11 顯示了在場(chǎng)景中添加了一個(gè)會(huì)影響4 個(gè)物體的點(diǎn)光源之后喜滨,渲染統(tǒng)計(jì)窗口的數(shù)據(jù)變化捉捅。


圖16.11 處理其他逐像素光的Pass不會(huì)被靜態(tài)批處理

但是,處理平行光的Base Pass 部分仍然會(huì)被靜態(tài)批處理鸿市,因此锯梁,我們?nèi)匀豢梢怨?jié)省兩個(gè)draw call.

五即碗、共享材質(zhì)

從之前的內(nèi)容可以看出焰情,無(wú)論是動(dòng)態(tài)批處理還是靜態(tài)批處理陌凳,都要求模型之間需要共享同一個(gè)材質(zhì)。但不同的模型之間總會(huì)需要有不同的渲染屬性内舟,例如合敦,使用不同的紋理、顏色等验游。這時(shí)充岛,我們需要一些策略來(lái)盡可能地合并材質(zhì)。

如果兩個(gè)材質(zhì)之間只有使用的紋理不同耕蝉,我們可以把這些紋理合并到一張更大的紋理中崔梗,這張更大的紋理被稱為是一張圖集( atlas )。一旦使用了同一張紋理垒在,我們就可以使用同一個(gè)材質(zhì)蒜魄,再使用不同的采樣坐標(biāo)對(duì)紋理采樣即可。

但有時(shí)场躯,除了紋理不同外谈为,不同的物體在材質(zhì)上還有一些微小的參數(shù)變化,例如踢关,顏色不同伞鲫、某些浮點(diǎn)屬性不同。但是签舞,不管是動(dòng)態(tài)批處理還是靜態(tài)批處理秕脓,它們的前提都是要使用同一個(gè)材質(zhì)。是同一個(gè)儒搭,而不是使用了同一種Shader 的材質(zhì)撒会,也就是說(shuō)它們指向的材質(zhì)必須是同一個(gè)實(shí)體。這意味著师妙,只要我們調(diào)整了參數(shù)诵肛,就會(huì)影響到所有使用這個(gè)材質(zhì)的對(duì)象。那么想要微小的調(diào)整怎么辦呢默穴?一種常用的方法就是使用網(wǎng)格的頂點(diǎn)數(shù)據(jù)(最常見(jiàn)的就是頂點(diǎn)顏色數(shù)據(jù)〉來(lái)存儲(chǔ)這些參數(shù)怔檩。

前面說(shuō)過(guò),經(jīng)過(guò)批處理后的物體會(huì)被處理成更大的VBO 發(fā)送給GPU, VBO 中的數(shù)據(jù)可以作為輸入傳遞給頂點(diǎn)著色器蓄诽,因此薛训,我們可以巧妙地對(duì)VBO 中的數(shù)據(jù)進(jìn)行控制,從而達(dá)到不同效果的目的仑氛。一個(gè)例子是乙埃,森林場(chǎng)景中所有的樹(shù)使用了同一種材質(zhì)闸英,我們希望它們可以通過(guò)批處理來(lái)減少draw call ,但不同樹(shù)的顏色可能不同介袜。這時(shí)甫何,我們可以利用網(wǎng)格的頂點(diǎn)的顏色數(shù)據(jù)來(lái)調(diào)整。

需要注意的是遇伞,如果我們需要在腳本中訪問(wèn)共享材質(zhì)辙喂,應(yīng)該使用Renderer.sharedMaterial 來(lái)保證修改的是和其他物體共享的材質(zhì),但這意味著修改會(huì)應(yīng)用到所有使用該材質(zhì)的物體上鸠珠。另一個(gè)類似的API 是Renderer.material 巍耗,如果使用Renderer.material 來(lái)修改材質(zhì), Unity 會(huì)創(chuàng)建一個(gè)該材質(zhì)的復(fù)制品渐排,從而破壞批處理在該物體上的應(yīng)用炬太,這可能并不是我們希望看到的。

六驯耻、批處理的注意事項(xiàng)

在選擇使用動(dòng)態(tài)批處理還是靜態(tài)批處理時(shí)亲族,我們有一些小小的建議。

  • 盡可能選擇靜態(tài)批處理吓歇,但得時(shí)刻小心對(duì)內(nèi)存的消耗孽水,并且記住經(jīng)過(guò)靜態(tài)批處理的物體不可以再被移動(dòng)。
  • 如果無(wú)法進(jìn)行靜態(tài)批處理城看,而要使用動(dòng)態(tài)批處理的話女气,那么請(qǐng)小心上面提到的各種條件限制。例如测柠,盡可能讓這樣的物體少并且盡可能讓這些物體包含少量的頂點(diǎn)屬性和頂點(diǎn)數(shù)目炼鞠。
  • 對(duì)于游戲中的小道具,例如可以撿拾的金幣等轰胁,可以使用動(dòng)態(tài)批處理谒主。
  • 對(duì)于包含動(dòng)畫的這類物體,我們無(wú)法全部使用靜態(tài)批處理赃阀,但其中如果有不動(dòng)的部分霎肯,可以把這部分標(biāo)識(shí)成“Static”。

除了上述提示外榛斯,在使用批處理時(shí)還有一些需要注意的地方观游。

  • 由于批處理需要把多個(gè)模型變換到世界空間下再合并它們,因此驮俗,如果shader 中存在一些基于模型空間下的坐標(biāo)的運(yùn)算懂缕,那么往往會(huì)得到錯(cuò)誤的結(jié)果。一個(gè)解決方法是王凑,在shader 中使用DisableBatching 標(biāo)簽來(lái)強(qiáng)制使用該Shader 的材質(zhì)不會(huì)被批處理搪柑。
  • 另一個(gè)注意事項(xiàng)是聋丝,使用半透明材質(zhì)的物體通常需要使用嚴(yán)格的從后往前的繪制順序來(lái)保證透明混合的正確性。對(duì)于這些物體工碾,Unity 會(huì)首先保證它們的繪制順序弱睦,再嘗試對(duì)它們進(jìn)行批處理。這意味著倚喂,當(dāng)繪制順序無(wú)法滿足時(shí)每篷,批處理無(wú)法在這些物體上被成功應(yīng)用瓣戚。

盡管在Unity 5.2 中端圈,只實(shí)現(xiàn)了對(duì)一些渲染部分的批處理。而諸如渲染攝像機(jī)的深度紋理等部分子库,還沒(méi)有實(shí)現(xiàn)批處理舱权。但我們相信,在后續(xù)的Unity 版本中仑嗅,批處理會(huì)應(yīng)用到越來(lái)越多的渲染部分中宴倍。

七、減少需要處理的頂點(diǎn)數(shù)目

盡管draw call 是一個(gè)重要的性能指標(biāo)仓技,但頂點(diǎn)數(shù)目同樣有可能成為GPU 的性能瓶頸鸵贬。在本節(jié)中,我們將給出3 個(gè)常用的頂點(diǎn)優(yōu)化策略脖捻。

1.優(yōu)化幾何體

3D 游戲制作通常都是由模型制作開(kāi)始的阔逼。而在建模時(shí),有一條規(guī)則我們需要記椎鼐凇:盡可能減少模型中三角面片的數(shù)目嗜浮, 一些對(duì)于模型沒(méi)有影響、或是肉眼非常難察覺(jué)到區(qū)別的頂點(diǎn)都要盡可能去掉摩疑。為了盡可能減少模型中的頂點(diǎn)數(shù)目危融,美工人員往往需要優(yōu)化網(wǎng)格結(jié)構(gòu)。在很多三維建模軟件中雷袋,都有相應(yīng)的優(yōu)化選項(xiàng)吉殃,可以自動(dòng)優(yōu)化網(wǎng)格結(jié)構(gòu)。

在Unity 的渲染統(tǒng)計(jì)窗口中楷怒,我們可以查看到渲染當(dāng)前幀需要的三角面片數(shù)目和頂點(diǎn)數(shù)目蛋勺。需要注意的是, Unity 中顯示的數(shù)目往往要多于建模軟件里顯示的頂點(diǎn)數(shù)率寡,通常Unity 中顯示的數(shù)目要大很多迫卢。誰(shuí)才是對(duì)的呢?其實(shí),這是因?yàn)樵诓煌慕嵌壬嫌?jì)算的漂洋,都有各自的道理,但我們真正應(yīng)該關(guān)心的是Unity 里顯示的數(shù)目钱反。

我們?cè)谶@里簡(jiǎn)單解釋一下造成這種不同的原因家卖。三維軟件更多地是站在我們?nèi)祟惖慕嵌壤斫忭旤c(diǎn)的眨层,即組成幾何體的每一個(gè)點(diǎn)就是一個(gè)單獨(dú)的點(diǎn)。而Unity 是站在GPU 的角度上去計(jì)算頂點(diǎn)數(shù)的上荡。在GPU 看來(lái)趴樱,有時(shí)需要把一個(gè)頂點(diǎn)拆分成兩個(gè)或更多的頂點(diǎn)。這種將頂點(diǎn)一分為多的原因主要有兩個(gè):一個(gè)是為了分離紋理坐標(biāo)(uv splits)酪捡, 另一個(gè)是為了產(chǎn)生平滑的邊界(smoothing splits).

它們的本質(zhì)叁征,其實(shí)都是因?yàn)閷?duì)于GPU 來(lái)說(shuō),頂點(diǎn)的每一個(gè)屬性和頂點(diǎn)之間必須是一對(duì)一的關(guān)系逛薇。而分離紋理坐標(biāo)捺疼,是因?yàn)榻r(shí)一個(gè)頂點(diǎn)的紋理坐標(biāo)有多個(gè)。例如永罚,對(duì)于一個(gè)立方體啤呼,它的6 個(gè)面之間雖然使用了一些相同的頂點(diǎn),但在不同面上呢袱,同一個(gè)頂點(diǎn)的紋理坐標(biāo)可能并不相同官扣。對(duì)于GPU 來(lái)說(shuō),這是不可理解的羞福,因此惕蹄,它必須把這個(gè)頂點(diǎn)拆分成多個(gè)具有不同紋理坐標(biāo)的頂點(diǎn)。而平滑邊界也是類似的坯临,不同的是焊唬,此時(shí)一個(gè)頂點(diǎn)可能會(huì)對(duì)應(yīng)多個(gè)法線信息或切線信息。這通常是因?yàn)槲覀円獩Q定一個(gè)邊是一條硬邊( hard edge )還是一條平滑邊(smooth edge )看靠。

對(duì)于GPU 來(lái)說(shuō)赶促,它本質(zhì)上只關(guān)心有多少個(gè)頂點(diǎn)。因此挟炬,盡可能減少頂點(diǎn)的數(shù)目其實(shí)才是我們真正需要關(guān)心的事情鸥滨。因此,最后一條幾何體優(yōu)化建議就是:移除不必要的硬邊以及紋理銜接谤祖,避免邊界平滑和紋理分離婿滓。

2.模型的LOO 技術(shù)

另一個(gè)減少頂點(diǎn)數(shù)目的方法是使用LOD (Level of Detail) 技術(shù)。這種技術(shù)的原理是粥喜,當(dāng)一個(gè)物體離攝像機(jī)很遠(yuǎn)時(shí)凸主,模型上的很多細(xì)節(jié)是無(wú)法被察覺(jué)到的。因此额湘,LOD 允許當(dāng)對(duì)象逐漸遠(yuǎn)離攝像機(jī)時(shí)卿吐,減少模型上的面片數(shù)量旁舰,從而提高性能。

在Unity 中嗡官,我們可以使用LOD Group 組件來(lái)為一個(gè)物體構(gòu)建一個(gè)LOD箭窜。我們需要為同一個(gè)對(duì)象準(zhǔn)備多個(gè)包含不同細(xì)節(jié)程序的模型,然后把它們賦給LOD Group 組件中的不同等級(jí)衍腥, Unity就會(huì)自動(dòng)判斷當(dāng)前位置上需要使用哪個(gè)等級(jí)的模型磺樱。

3.遮擋剔除技術(shù)

我們最后要介紹的頂點(diǎn)優(yōu)化策略就是遮擋剔除( Occlusion culling)技術(shù)。遮擋剔除可以用來(lái)消除那些在其他物件后面看不到的物件婆咸,這意味著資源不會(huì)浪費(fèi)在計(jì)算那些看不到的頂點(diǎn)上竹捉,進(jìn)而提升性能。

我們需要把遮擋剔除和攝像機(jī)的視錐體剔除( Frustum Culling )區(qū)分開(kāi)來(lái)擅耽。視錐體剔除只會(huì)剔除掉那些不在攝像機(jī)的視野范圍內(nèi)的對(duì)象活孩,但不會(huì)判斷視野中是否有物體被其他物體擋住物遇。而遮擋剔除會(huì)使用一個(gè)虛擬的攝像機(jī)來(lái)遍歷場(chǎng)景乖仇,從而構(gòu)建一個(gè)潛在可見(jiàn)的對(duì)象集合的層級(jí)結(jié)構(gòu)。

在運(yùn)行時(shí)刻询兴,每個(gè)攝像機(jī)將會(huì)使用這個(gè)數(shù)據(jù)來(lái)識(shí)別哪些物體是可見(jiàn)的乃沙,而哪些被其他物體擋住不可見(jiàn)。使用遮擋剔除技術(shù)诗舰,不僅可以減少處理的頂點(diǎn)數(shù)目警儒,還可以減少overdraw,提高游戲性能眶根。

要在Unity 中使用遮擋剔除技術(shù)蜀铲,我們需要進(jìn)行一系列額外的處理工作。具體步驟可以參見(jiàn)Unity 手冊(cè)的相關(guān)內(nèi)容(http://docs.unity3d.com/Manual/OcclusionCulling.html )属百,本書不再贅述记劝。

模型的LOD 技術(shù)和遮擋剔除技術(shù)可以同時(shí)減少CPU 和GPU 的負(fù)荷。CPU 可以提交更少的draw call 族扰,而GPU 需要處理的頂點(diǎn)和片元數(shù)目也減少了厌丑。

八、減少需要處理的片元數(shù)目

另一個(gè)造成GPU 瓶頸的是需要處理過(guò)多的片元渔呵。這部分優(yōu)化的重點(diǎn)在于減少overdraw 怒竿。簡(jiǎn)單來(lái)說(shuō), overdraw 指的就是同一個(gè)像素被繪制了多次扩氢。

Unity 還提供了查看overdraw 的視圖耕驰,我們可以在Scene 視圖左上方的下拉菜單中選中Overdraw 即可。實(shí)際上录豺,這里的視圖只是提供了查看物體相互遮擋的層數(shù)朦肘,并不是真正的最終屏幕繪制的overdraw 托嚣。也就是說(shuō),可以理解為它顯示的是厚骗,如果沒(méi)有使用任何深度測(cè)試和其他優(yōu)化策略時(shí)的overdraw 示启。這種視圖是通過(guò)把所有對(duì)象都渲染成一個(gè)透明的輪廓,通過(guò)查看透明顏色的累計(jì)程度领舰,來(lái)判斷物體之間的遮擋夫嗓。當(dāng)然,我們可以使用一些措施來(lái)防止這種最壞情況的出現(xiàn)冲秽。

1.控制繪制順序

為了最大限度地避免overdraw舍咖, 一個(gè)重要的優(yōu)化策略就是控制繪制順序。由于深度測(cè)試的存在锉桑,如果我們可以保證物體都是從前往后繪制的排霉,那么就可以很大程度上減少overdraw。這是因?yàn)槊裰幔诤竺胬L制的物體由于無(wú)法通過(guò)深度測(cè)試攻柠,因此,就不會(huì)再進(jìn)行后面的渲染處理后裸。

在Unity 中瑰钮,那些渲染隊(duì)列數(shù)目小于2 500 (如“Background" "Geometry ”和“Alpha Test")的對(duì)象都被認(rèn)為是不透明( opaque )的物體,這些物體總體上是從前往后繪制的微驶,而使用其他的隊(duì)列(如“ Transparent "“ Overlay"等)的物體浪谴,則是從后往前繪制的。這意味著因苹,我們可以盡可能地把物體的隊(duì)列設(shè)置為不透明物體的渲染隊(duì)列苟耻,而盡量避免使用半透明隊(duì)列。

而且扶檐,我們還可以充分利用Unity 的渲染隊(duì)列來(lái)控制繪制順序凶杖。例如,在第一人稱射擊游戲中蘸秘,對(duì)于游戲中的主要人物角色來(lái)說(shuō)官卡,他們使用的shader 往往比較復(fù)雜,但是醋虏,由于他們通常會(huì)擋住屏幕的很大一部分區(qū)域寻咒,因此我們可以先繪制它們(使用更小的渲染隊(duì)列〉。而對(duì)于一些敵方角色颈嚼,它們通常會(huì)出現(xiàn)在各種掩體后面毛秘,因此,我們可以在所有常規(guī)的不透明物體后面渲染它們(使用更大的渲染隊(duì)列〉。而對(duì)于天空盒子來(lái)說(shuō)叫挟, 它幾乎覆蓋了所有的像素艰匙,而且我們知道它本遠(yuǎn)會(huì)出現(xiàn)在所有物體的后面,因此抹恳, 它的隊(duì)列可以設(shè)置為“ Geometry+ 1 ”员凝。這樣,就可以保證不會(huì)因?yàn)樗斐蒾verdraw 奋献。

這些排序的思想往往可以節(jié)省掉很多渲染時(shí)間健霹。

2.時(shí)刻警惕透明物體

對(duì)于半透明對(duì)象來(lái)說(shuō),由于它們沒(méi)有開(kāi)啟深度寫入瓶蚂,因此糖埋,如果要得到正確的渲染效果,就必須從后往前渲染窃这。這意味著瞳别,半透明物體幾乎一定會(huì)造成overdraw。如果我們不注意這一點(diǎn)杭攻,在一些機(jī)器上可能會(huì)造成嚴(yán)重的性能下降祟敛。例如,對(duì)于GUI 對(duì)象來(lái)說(shuō)朴上,它們大多被設(shè)置成了半透明垒棋,如果屏幕中GUI 占據(jù)的比例太多,而主攝像機(jī)又沒(méi)有進(jìn)行調(diào)整而是投影整個(gè)屏幕痪宰,那么GUI就會(huì)造成大量overdraw 。

因此畔裕,如果場(chǎng)景中包含了大面積的半透明對(duì)象衣撬,或者有很多層相互覆蓋的半透明對(duì)象(即使它們每個(gè)的面積可能都不大〉,或者是透明的粒子效果扮饶, 在移動(dòng)設(shè)備上也會(huì)造成大量的overdraw 具练。這是應(yīng)該盡量避免的。

對(duì)于上述GUI 的這種情況甜无,我們可以盡量減少窗口中GUI 所占的面積扛点。如果實(shí)在無(wú)能為力,我們可以把GUI的繪制和三維場(chǎng)景的繪制交給不同的攝像機(jī)岂丘, 而其中負(fù)責(zé)三維場(chǎng)景的攝像機(jī)的視角范圍盡量不要和GUI的相互重疊陵究。當(dāng)然,這樣會(huì)對(duì)游戲的美觀度產(chǎn)生一定影響奥帘,因此铜邮,我們可以在代碼中對(duì)機(jī)器的性能進(jìn)行判斷,例如,首先關(guān)閉一些耗費(fèi)性能的功能松蒜,如果發(fā)現(xiàn)這個(gè)機(jī)器表現(xiàn)非常良好扔茅,再嘗試開(kāi)啟一些特效功能。

在移動(dòng)平臺(tái)上秸苗, 透明度測(cè)試也會(huì)影響游戲性能召娜。雖然透明度測(cè)試沒(méi)有關(guān)閉深度測(cè)試, 但由于它的實(shí)現(xiàn)使用了discard 或clip 操作惊楼, 而這些操作會(huì)導(dǎo)致一些硬件的優(yōu)化策略失效萤晴。例如, 我們之前講過(guò)PowerVR 使用的基于瓦片的延遲渲染技術(shù)胁后, 為了減少overdraw 它會(huì)在調(diào)用片元著色器前就判斷哪些瓦片被真正渲染的店读。但是,由于透明度測(cè)試在片元著色器中使用了discard 函數(shù)改變了片元是否會(huì)被渲染的結(jié)果攀芯,因此屯断, GPU 就無(wú)法使用上述的優(yōu)化策略了。也就是說(shuō)侣诺,只要在執(zhí)行了所有的片元著色器后殖演, GPU 才知道哪些片元會(huì)被真正渲染到屏幕上, 這樣年鸳, 原先那些可以減少overdraw 的優(yōu)化就都無(wú)效了趴久。這種時(shí)候, 使用透明度混合的性能往往比使用透明度測(cè)試更好搔确。

3.減少實(shí)時(shí)光照和陰影

實(shí)時(shí)光照對(duì)于移動(dòng)平臺(tái)是一種非常昂貴的操作彼棍。如果場(chǎng)景中包含了過(guò)多的點(diǎn)光源,并且使用了多個(gè)Pass 的Shader膳算,那么很有可能會(huì)造成性能下降座硕。例如,一個(gè)場(chǎng)景里如果包含了3 個(gè)逐像素的點(diǎn)光源涕蜂,而且使用了逐像素的Shader华匾,那么很有可能將draw call 數(shù)目( CPU 的瓶頸〉提高3倍,同時(shí)也會(huì)增加overdraw ( GPU 的瓶頸)机隙。這是因?yàn)椋?對(duì)于逐像素的光源來(lái)說(shuō)蜘拉, 被這些光源照亮的物體需要被再渲染一次。更糟糕的是有鹿,無(wú)論是靜態(tài)批處理還是動(dòng)態(tài)批處理旭旭,對(duì)于這種額外的處理逐像素光源的Pass 都無(wú)法進(jìn)行批處理,也就是說(shuō)印颤,它們會(huì)中斷批處理您机。

當(dāng)然,游戲場(chǎng)景還是需要光照才能得到出色的畫面效果。我們看到很多成功的移動(dòng)平臺(tái)的游戲际看,它們的畫面效果看起來(lái)好像包含了很多光源咸产,但其實(shí)這都是騙人的。這些游戲往往使用了烘焙技術(shù)仲闽,把光照提前烘焙到一張光照紋理(lightmap )中脑溢, 然后在運(yùn)行時(shí)刻只需要根據(jù)紋理采樣得到光照結(jié)果即可。另一個(gè)模擬光源的方法是使用God Ray 赖欣。場(chǎng)景中很多小型光源的效果都是靠這種方法模擬的屑彻。它們一般并不是真的光源, 很多情況是通過(guò)透明紋理模擬得到的顶吮。更多信息可以參見(jiàn)本章的擴(kuò)展閱讀部分社牲。在移動(dòng)平臺(tái)上, 一個(gè)物體使用的逐像素光源數(shù)目應(yīng)該小于1(不包括平行光) 悴了。如果一定要使用更多的實(shí)時(shí)光搏恤,可以選擇用逐頂點(diǎn)光照來(lái)代替。

在游戲《ShadowGun》中湃交,游戲角色看起來(lái)使用了非常復(fù)雜高級(jí)的光照計(jì)算熟空, 但這實(shí)際上是優(yōu)化后的結(jié)果。開(kāi)發(fā)者們把復(fù)雜的光照計(jì)算存儲(chǔ)到一張查找紋理(lookup texture搞莺,也被稱為查找表息罗, lookup table, LUT )中。然后在運(yùn)行時(shí)刻才沧,我們只需要使用光源方向迈喉、視角方向、法線方向等參數(shù)糜工,對(duì)LUT 采樣得到光照結(jié)果即可弊添。使用這樣的查找紋理,不僅可以讓我們使用更出色的光照模型捌木,例如,更加復(fù)雜的BRDF 模型嫉戚,還可以利用查找紋理的大小來(lái)進(jìn)一步優(yōu)化性能刨裆,例如,主要角色可以使用更大分辨率的LUT彬檀,而一些NPC 就使用較小的LUT 帆啃。《ShadowGun》的開(kāi)發(fā)者開(kāi)發(fā)了一個(gè)LUT 烘倍工具窍帝,來(lái)幫助美工人員快速調(diào)整光照模型努潘,并把結(jié)果存儲(chǔ)到LUT 中。

實(shí)時(shí)陰影同樣是一個(gè)非常消耗性能的效果。不僅是CPU 需要提交更多的draw call, GPU 也需要進(jìn)行更多的處理疯坤。因此报慕,我們應(yīng)該盡量減少實(shí)時(shí)陰影,例如压怠,使用烘焙把靜態(tài)物體的陰影信息存儲(chǔ)到光照紋理中眠冈,而只對(duì)場(chǎng)景中的動(dòng)態(tài)物體使用適當(dāng)?shù)膶?shí)時(shí)陰影。

九菌瘫、節(jié)省帶寬

大量使用未經(jīng)壓縮的紋理以及使用過(guò)大的分辨率都會(huì)造成由于帶寬而引發(fā)的性能瓶頸蜗顽。

1.減少紋理大小

之前提到過(guò),使用紋理圖集可以幫助我們減少draw call 的數(shù)目雨让,而這些紋理的大小同樣是一個(gè)需要考慮的問(wèn)題雇盖。需要注意的是,所有紋理的長(zhǎng)寬比最好是正方形栖忠,而且長(zhǎng)寬值最好是2 的整數(shù)幕崔挖。這是因?yàn)橛泻芏鄡?yōu)化策略只有在這種時(shí)候才可以發(fā)揮最大效用。

在Unity5 中娃闲,即便我們導(dǎo)入的紋理長(zhǎng)寬值并不是2 的整數(shù)幕虚汛, Unity 也會(huì)自動(dòng)把長(zhǎng)寬轉(zhuǎn)換到離它最近的2 的整數(shù)幕值。但我們?nèi)匀粦?yīng)該在制作美術(shù)資源時(shí)就把這條規(guī)則謹(jǐn)記在心皇帮,防止由于放縮而造成不好的影響卷哩。

除此之外,我們還應(yīng)該盡可能使用多級(jí)漸遠(yuǎn)紋理技術(shù)( mipmapping )和紋理壓縮属拾。在Unity 中将谊,我們可以通過(guò)紋理導(dǎo)入面板來(lái)查看紋理的各個(gè)導(dǎo)入屬性。通過(guò)把紋理類型設(shè)置為Advanced,就可以自定義許多選項(xiàng)彪置,例如电抚,是否生成多級(jí)漸遠(yuǎn)紋理( mipmaps ),如圖16.12 所示栋齿。


圖16.12 Unity的高級(jí)紋理設(shè)置面板

當(dāng)勾選了Generate Mip Maps選項(xiàng)后, Unity 就會(huì)為同一張紋理創(chuàng)建出很多不同大小的小紋理襟诸,構(gòu)成一個(gè)紋理金字塔瓦堵。而在游戲運(yùn)行中就可以根據(jù)距離物體的遠(yuǎn)近,來(lái)動(dòng)態(tài)選擇使用哪一個(gè)紋理歌亲。這是因?yàn)楣接茫诰嚯x物體很遠(yuǎn)的時(shí)候,就算我們使用了非常精細(xì)的紋理陷揪,但肉眼也是分辨不出來(lái)的惋鸥。這種時(shí)候杂穷,我們完全可以使用更小、更模糊的紋理來(lái)代替卦绣,這可以讓GPU 使用分辨率更小的紋理耐量,大量節(jié)省訪問(wèn)的像素?cái)?shù)目。在某些設(shè)備上迎卤,關(guān)閉多級(jí)漸遠(yuǎn)紋理往往會(huì)造成嚴(yán)重的性能問(wèn)題拴鸵。因此,除非我們確定該紋理不會(huì)發(fā)生縮放蜗搔, 例如GUI 和2D 游戲中使用的紋理等劲藐,都應(yīng)該為紋理生成相應(yīng)的多級(jí)漸遠(yuǎn)紋理。

紋理壓縮同樣可以節(jié)省帶寬樟凄。但對(duì)于像Android 這樣的平臺(tái)聘芜,有很多不同架構(gòu)的GPU,紋理壓縮就變得有點(diǎn)復(fù)雜缝龄,因?yàn)椴煌腉PU 架構(gòu)有它自己的紋理壓縮格式汰现,例如, PowerVRAM 的PVRTC 格式叔壤、Tegra 的DXT 格式瞎饲、Adreno 的ATC 格式。所幸的是炼绘, Unity 可以根據(jù)不同的設(shè)備選擇不同的壓縮格式嗅战,而我們只需要把紋理壓縮格式設(shè)置為自動(dòng)壓縮即可。但是俺亮, GUI 類型的紋理同樣是個(gè)例外驮捍,一些時(shí)候由于對(duì)畫質(zhì)的要求,我們不希望對(duì)這些紋理進(jìn)行壓縮脚曾。

2.利用分辨率縮放

過(guò)高的屏幕分辨率也是造成性能下降的原因之一东且,尤其是對(duì)于很多低端手機(jī),除了分辨率高其他硬件條件并不盡如人意本讥,而這恰恰是游戲性能的兩個(gè)瓶頸: 過(guò)大的屏幕分辨率和糟糕的GPU珊泳。因此,我們可能需要對(duì)于特定機(jī)器進(jìn)行分辨率的放縮拷沸。當(dāng)然旨椒,這樣可能會(huì)造成游戲效果的下降,但性能和畫面之間永遠(yuǎn)是個(gè)需要權(quán)衡的話題堵漱。

在Unity 中設(shè)置屏幕分辨率可以直接調(diào)用Screen.SetResolution。實(shí)際使用中可能會(huì)遇到一些情況涣仿,雨松MOMO 有一篇文章
( http://www.xuanyusong.com/archives/3205 )詳細(xì)講解了如何使用這種技術(shù)勤庐,讀者可參考示惊。

十、減少計(jì)算復(fù)雜度

計(jì)算復(fù)雜度同樣會(huì)影響游戲的渲染性能愉镰。在本節(jié)中米罚, 我們會(huì)介紹兩個(gè)方面的技術(shù)來(lái)減少計(jì)算復(fù)雜度。

1.Shader 的LOD 技術(shù)

和16.5.2 節(jié)提到的模型的 LOD 技術(shù)類似丈探, Shader 的 LOD 技術(shù)可以控制使用的Shader 等級(jí)录择。它的原理是,只有Shader 的 LOD 值小于某個(gè)設(shè)定的值碗降,這個(gè)Shader 才會(huì)被使用隘竭,而使用了那些超過(guò)設(shè)定值的Shader 的物體將不會(huì)被渲染。
我們通常會(huì)在SubShader 中使用類似下面的語(yǔ)句來(lái)指明該shader 的LOD 值:

SubShader{
   Tags{"RenderType"="Opaque"}
   LOD 200

我們也可以在Unity Shader 的導(dǎo)入面板上看到該Shader 使用的LOD 值讼渊。在默認(rèn)情況下动看,允許的LOD 等級(jí)是無(wú)限大的。這意味著爪幻,任何被當(dāng)前顯卡支持的Shader 都可以被使用菱皆。但是,在某些情況下我們可能需要去掉一些使用了復(fù)雜計(jì)算的Shader 渲染挨稿。這時(shí)仇轻,我們可以使用 Shader.maximumLOD 或 Shader.globalMaximumLOD 來(lái)設(shè)置允許的最大LOD 值。
Unity 內(nèi)置的Shader 使用了不同的LOD 值奶甘,例如篷店,Diffuse 的LOD 為200 ,而B(niǎo)umped Specular 的 LOD 為400 甩十。

2.代碼方面的優(yōu)化

在實(shí)現(xiàn)游戲效果時(shí)船庇,我們可以選擇在哪里進(jìn)行某些特定的運(yùn)算。通常來(lái)講侣监, 游戲需要計(jì)算的對(duì)象鸭轮、頂點(diǎn)和像素的數(shù)目排序是對(duì)象數(shù) < 頂點(diǎn)數(shù)<像素?cái)?shù)。因此橄霉, 我們應(yīng)該盡可能地把計(jì)算放在每個(gè)對(duì)象或逐頂點(diǎn)上窃爷。例如,在第13 章實(shí)現(xiàn)高斯模糊和邊緣檢測(cè)時(shí)姓蜂,我們把采樣坐標(biāo)的計(jì)算放在了頂點(diǎn)著色器中按厘,這樣的做法遠(yuǎn)好于把它們放在片元著色器中。

而在具體的代碼編寫上钱慢,不同的硬件甚至需要不同的處理逮京。因此,一些普遍的規(guī)則在某些硬件上可能并不成立束莫。更不幸的是懒棉,通常Shader 代碼的優(yōu)化并不那么直觀草描,尤其是一些平臺(tái)上缺少相關(guān)的分析器, 例如iOS 平臺(tái)策严。盡管如此穗慕,在本節(jié)我們還是會(huì)給出一些被認(rèn)為是普遍成立的優(yōu)化策略,但讀者如果發(fā)現(xiàn)在某些設(shè)備上性能反而有所下降的話妻导,這并不奇怪逛绵。

首先第一點(diǎn)是,盡可能使用低精度的浮點(diǎn)值進(jìn)行運(yùn)算倔韭。最高精度的float/highp 適用于存儲(chǔ)諸如頂點(diǎn)坐標(biāo)等變量术浪, 但它的計(jì)算速度是最慢的,我們應(yīng)該盡量避免在片元著色器中使用這種精度進(jìn)行計(jì)算狐肢。而half/mediump 適用于一些標(biāo)量添吗、紋理坐標(biāo)等變量,它的計(jì)算速度大約是float 的兩倍份名。而 fixed/lowp 適用于絕大多數(shù)顏色變量和歸一化后的方向矢量碟联,在進(jìn)行一些對(duì)精度要求不高的計(jì)算時(shí),我們應(yīng)該盡量使用這種精度的變量僵腺。它的計(jì)算速度大約是float 的4 倍鲤孵,但要避免對(duì)這些低精度變量進(jìn)行頻繁的swizzle 操作(如color.xwxw )。還需要注意的是辰如,我們應(yīng)當(dāng)盡量避免在不同精度之間的轉(zhuǎn)換普监,這有可能會(huì)造成一定的性能下降。

對(duì)于絕大多數(shù)GPU 來(lái)說(shuō)琉兜,在使用插值寄存器把數(shù)據(jù)從頂點(diǎn)著色器傳遞給下一個(gè)階段時(shí)凯正,我們應(yīng)該使用盡可能少的插值變量。例如豌蟋,如果需要對(duì)兩個(gè)紋理坐標(biāo)進(jìn)行插值廊散,我們通常會(huì)把它們打包在同一個(gè)float4 類型的變量中,兩個(gè)紋理坐標(biāo)分別對(duì)應(yīng)了xy 分量和 zw 分量梧疲。然而允睹,對(duì)于PowerVR平臺(tái)來(lái)說(shuō),這種插值變量是非常廉價(jià)的幌氮,直接把不同的紋理坐標(biāo)存儲(chǔ)在不同的插值變量中缭受,有時(shí)反而性能更好。尤其是该互, 如果在PowerVR 上使用類似 tex2D(_MainTex, uv.zw)這樣的語(yǔ)句來(lái)進(jìn)行紋理采樣米者, GPU 就無(wú)法進(jìn)行一些紋理的預(yù)讀取, 因?yàn)樗鼤?huì)認(rèn)為這些紋理采樣是需要依賴其他數(shù)據(jù)的宇智。因此塘雳,如果我們特別關(guān)心游戲在PowerVR 上的性能陆盘, 就不應(yīng)該把兩個(gè)紋理坐標(biāo)打包在同一個(gè)四維變量中。

盡可能不要使用全屏的屏幕后處理效果败明。如果美術(shù)風(fēng)格實(shí)在是需要使用類似Bloom、熱擾動(dòng)這樣的屏幕特效太防,我們應(yīng)該盡量使用 fixed/lowp 進(jìn)行低精度運(yùn)算(紋理坐標(biāo)除外妻顶,可以使用 half/mediump )。那些高精度的運(yùn)算可以使用查找表(LUT)或者轉(zhuǎn)移到頂點(diǎn)著色器中進(jìn)行處理蜒车。除此之外讳嘱, 盡量把多個(gè)特效合并到一個(gè)Shader 中。例如酿愧,我們可以把顏色校正和添加噪聲等屏幕特效在Bloom 特效的最后一個(gè)Pass 中進(jìn)行合成沥潭。還有一個(gè)方法就是使用16.8.3 節(jié)中介紹的縮放思想, 來(lái)選擇性地開(kāi)啟特效嬉挡。

還有一些讀者經(jīng)常會(huì)聽(tīng)到的代碼優(yōu)化規(guī)則钝鸽。

  • 盡可能不要使用分支語(yǔ)句和循環(huán)語(yǔ)句。
  • 盡可能避免使用類似sin 庞钢、tan拔恰、pow、log 等較為復(fù)雜的數(shù)學(xué)運(yùn)算基括。我們可以使用查找表來(lái)作為替代颜懊。
  • 盡可能不要使用discard 操作,因?yàn)檫@會(huì)影響硬件的某些優(yōu)化风皿。
3.根據(jù)硬件條件進(jìn)行縮放

諸如iOS 和 Android 這樣的移動(dòng)平臺(tái)河爹,不同設(shè)備之間的性能千差萬(wàn)別。我們很容易可以找到一臺(tái)手機(jī)的渲染性能是另一臺(tái)手機(jī)的10 倍桐款。那么咸这,如何確保游戲可以同時(shí)流暢地運(yùn)行在不同性能的移動(dòng)設(shè)備上呢? 一個(gè)非常簡(jiǎn)單且實(shí)用的方式是使用所謂的放縮(scaling)思想鲁僚。我們首先保證游戲最基本的配置可以在所有的平臺(tái)上運(yùn)行良好炊苫,而對(duì)于一些具有更高表現(xiàn)能力的設(shè)備,我們可以開(kāi)啟一些更“養(yǎng)眼”的效果冰沙,比如使用更高的分辨率侨艾,開(kāi)啟屏幕后處理特效,開(kāi)啟粒子效果等拓挥。

十一唠梨、擴(kuò)展閱讀

Unity 官方手冊(cè)的移動(dòng)平臺(tái)優(yōu)化實(shí)踐指南 (http://docs.unity3d.com/Manual/MobileOptimizationPracticalGuide.html )一文給出了一些針對(duì)移動(dòng)平臺(tái)的優(yōu)化技術(shù),包括渲染和圖形方面的優(yōu)化侥啤,以及腳本優(yōu)化等当叭。手冊(cè)中另一個(gè)針對(duì)圖像性能優(yōu)化的文檔是優(yōu)化圖像性(http://docs.unity3d.com/Manual/OptimizingGraphicsPerformance.html)一文茬故,在這個(gè)文檔中,Unity 給出了常見(jiàn)的性能瓶頸以及一些相應(yīng)的優(yōu)化技術(shù)蚁鳖。除此之外磺芭, 文檔列出了一個(gè)清單,包含了優(yōu)化游戲性能的常見(jiàn)做法和約束醉箕。

在SIGGRAPH 2011 上钾腺, Unity 進(jìn)行了一個(gè)關(guān)于移動(dòng)平臺(tái)上 Shader 優(yōu)化的演講 (http://blogs.unity3d.com/2011/08/18/fast-mobile-shaders-talk-at-siggraph/)。在這個(gè)演講中讥裤,作者給出了各個(gè)主流移動(dòng)GPU 的架構(gòu)特點(diǎn)放棒,并給出了相應(yīng)的shader 優(yōu)化細(xì)節(jié), 還結(jié)合了真實(shí)的Unity 游戲項(xiàng)目來(lái)進(jìn)行實(shí)例學(xué)習(xí)己英。

在Unite 2013 會(huì)議上间螟, Unity 呈現(xiàn)了一個(gè)名為針對(duì)移動(dòng)平臺(tái)優(yōu)化Unity 游戲的演講,在這個(gè)簡(jiǎn)短的演講中损肛,作者對(duì)造成性能瓶頸的原因進(jìn)行了分類厢破,并給出了一些常見(jiàn)的優(yōu)化技術(shù)。

在GDC 2014 上荧关, Unity 展示了如何使用內(nèi)置的分析器分析移動(dòng)平臺(tái)的游戲性能溉奕,讀者可以在Youtube上找到相應(yīng)的視頻。

在最近的SIGGRAPH 2015 會(huì)議上忍啤, Unity 進(jìn)行了一系列演講和課程加勤。在Unity和來(lái)自高通、ARM 等公司的開(kāi)發(fā)人員共同呈現(xiàn)的名為Moving Mobile Graphics 的課程中同波,來(lái)自Unity 的Renaldas Zioma 講解了移動(dòng)平臺(tái)上PBR 的優(yōu)化技術(shù)鳄梅。更多Unity 在SIGGRAPH 2015 上的演講,讀者可以參見(jiàn)Unity 的博客未檩。

除了手冊(cè)和演講資料外戴尸,成功的移動(dòng)平臺(tái)中的游戲同樣是非常好的學(xué)習(xí)資料≡┙疲《ShadowGun》是由MadFinger 在2011 年發(fā)布的一款移動(dòng)平臺(tái)的第三人稱射擊游戲孙蒙, 使用的開(kāi)發(fā)工具正是Unity 。在Unity 2011 上悲雳,該游戲的開(kāi)發(fā)者給出了《ShadowGun》中使用的渲染和優(yōu)化技術(shù)挎峦,讀者可以在Youtube 上面找到這個(gè)視頻。更難能可貴的是合瓢,在2012 年坦胶, 《ShadowGun》的開(kāi)發(fā)者放出了示例場(chǎng)景,來(lái)讓更多的開(kāi)發(fā)者學(xué)習(xí)如何優(yōu)化移動(dòng)平臺(tái)上的shader。另一個(gè)非常好的游戲優(yōu)化實(shí)例是Unity 自帶的項(xiàng)目《Angry Bots》顿苇, 讀者可以直接在Unity 資源商店下載到完整的項(xiàng)目源代碼峭咒。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纪岁,隨后出現(xiàn)的幾起案子凑队,更是在濱河造成了極大的恐慌,老刑警劉巖蜂科,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顽决,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡导匣,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門茸时,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贡定,“玉大人,你說(shuō)我怎么就攤上這事可都』捍” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵渠牲,是天一觀的道長(zhǎng)旋炒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)签杈,這世上最難降的妖魔是什么瘫镇? 我笑而不...
    開(kāi)封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮答姥,結(jié)果婚禮上铣除,老公的妹妹穿的比我還像新娘。我一直安慰自己鹦付,他們只是感情好尚粘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著敲长,像睡著了一般郎嫁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祈噪,一...
    開(kāi)封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天泽铛,我揣著相機(jī)與錄音,去河邊找鬼钳降。 笑死厚宰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铲觉,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼澈蝙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了撵幽?” 一聲冷哼從身側(cè)響起灯荧,我...
    開(kāi)封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盐杂,沒(méi)想到半個(gè)月后逗载,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡链烈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年厉斟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片强衡。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡擦秽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出漩勤,到底是詐尸還是另有隱情感挥,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布越败,位于F島的核電站触幼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏究飞。R本人自食惡果不足惜置谦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望噪猾。 院中可真熱鬧霉祸,春花似錦、人聲如沸袱蜡。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坪蚁。三九已至奔穿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間敏晤,已是汗流浹背贱田。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嘴脾,地道東北人男摧。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓异吻,卻偏偏與公主長(zhǎng)得像徽龟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容