Unity中的渲染優(yōu)化技術(shù)
移動(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 Deffered 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)化片效。尤其是在安卓平臺(tái)上,不同設(shè)備使用的硬件英古,如圖形芯片淀衣、屏幕分辨率等,大相徑庭召调,這對(duì)圖形優(yōu)化提出了更高的挑戰(zhàn)膨桥。相比于Android平臺(tái)蛮浑,ios平臺(tái)的硬件條件則相對(duì)統(tǒng)一。
影響性能的因素
我們可以把造成游戲性能的瓶頸的主要原因分成以下幾個(gè)方面:
- CPU:
- 過(guò)多的draw call
- 復(fù)雜的腳本或物理模擬
- GPU:
- 頂點(diǎn)處理
- 過(guò)多的頂點(diǎn)
- 過(guò)多的逐頂點(diǎn)計(jì)算
- 片元處理
- 過(guò)多的片元(即有可能是由于分辨率造成的国撵,也有可能是由于overdraw造成的)
- 過(guò)多的逐片元計(jì)算
- 頂點(diǎn)處理
- 帶寬:
- 使用了尺寸很大且未壓縮的紋理
- 分辨率過(guò)高的幀緩存
draw call:過(guò)多的draw call會(huì)造成GPU的性能瓶頸陵吸,這是因?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的工作上面了环础。
本章后續(xù)涉及的優(yōu)化技術(shù)有:
- CPU優(yōu)化
- 批處理技術(shù)
- 共享材質(zhì)
- GPU優(yōu)化
- 減少需要處理的頂點(diǎn)數(shù)目
- 優(yōu)化幾何體
- 使用模型的LOD(Level of Detail)技術(shù)。
- 使用遮擋剔除(Occluision Culling)技術(shù)剩拢。
- 減少需要處理的片元數(shù)目
- 控制繪制順序
- 警惕透明物體
- 減少實(shí)時(shí)光照
- 場(chǎng)景烘焙
- 體積光
- 查找紋理
- 實(shí)時(shí)陰影
- 減少計(jì)算復(fù)雜度
- 使用Shader的LOD(Level of Detail)技術(shù)线得。
- 代碼方面的優(yōu)化
- 運(yùn)算對(duì)象選擇
- 精度值選擇
- 插值寄存器處理
- 其他
- 減少需要處理的頂點(diǎn)數(shù)目
- 節(jié)省內(nèi)存帶寬
- 減小紋理大小
- 多級(jí)漸遠(yuǎn)技術(shù)
- 紋理壓縮
- 利用分辨率縮放
- 減小紋理大小
Unity中的渲染分析工具
在開(kāi)始優(yōu)化之前,我們首先需要知道是哪個(gè)步驟造成了性能瓶頸徐伐。而這可以利用Unity提供的一些渲染分析工具來(lái)實(shí)現(xiàn)贯钩。這些工具包含了渲染統(tǒng)計(jì)窗口(Rendering Statistics Window)、性能分析器(Profiler)办素,以及幀調(diào)試器(Frame Debugger)角雷。需要注意的是,在不同的目標(biāo)平臺(tái)上性穿,這些工具中顯示的數(shù)據(jù)也會(huì)發(fā)生變化勺三。
渲染統(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)它需曾,如下圖所示:
渲染窗口主要包含了3個(gè)方面的信息:音頻(Audio)吗坚、圖像(Graphics)和網(wǎng)絡(luò)(Network)。我們?cè)谶@里只關(guān)注第二個(gè)方面呆万,即圖像相關(guān)的渲染統(tǒng)計(jì)結(jié)果商源。
信息名稱 | 描述 |
---|---|
每幀的時(shí)間和FPS | 在Graphic的右側(cè)顯示,給出了處理和渲染一幀所需的時(shí)間谋减,以及FPS數(shù)目 |
Batches | 一幀中需要進(jìn)行的批處理數(shù)目 |
Saved by batching | 合并的批處理數(shù)目牡彻,這個(gè)數(shù)字表明了批處理為我們節(jié)省了多少draw call |
Tris和Verts | 需要繪制的三角面片和頂點(diǎn)數(shù)目 |
Screen | 屏幕的大小,以及它占用的內(nèi)存的大小 |
SetPass | 渲染使用的Pass的數(shù)目逃顶,每個(gè)Pass都需要Unity的runtime來(lái)綁定一個(gè)新的Shader讨便,這可能造成CPU的瓶頸 |
Visible Skinned Meshes | 渲染的蒙皮網(wǎng)格的數(shù)目 |
Animations | 播放的動(dòng)畫(huà)數(shù)目 |
性能分析器的渲染區(qū)域
如果我們想要查看draw call的數(shù)目等其它更加詳細(xì)的數(shù)據(jù),可以通過(guò)Unity編輯器的性能分析器來(lái)查看以政。
們可以通過(guò)單擊Window->Analysis->Profiler來(lái)打開(kāi)Unity的性能分析器(Profiler)霸褒。性能分析器中的渲染區(qū)域(Rendering Area)提供了更多關(guān)于渲染的統(tǒng)計(jì)信息,下圖給出了對(duì)上圖場(chǎng)景的渲染分析結(jié)果:
一個(gè)值得注意的現(xiàn)象是盈蛮,性能分析器給出的draw call數(shù)目和批處理數(shù)目废菱、Pass數(shù)目并不相等,并且看起來(lái)好像要大于我們估算的數(shù)目,這是因?yàn)閁nity在背后需要進(jìn)行很多工作殊轴,例如初始化各個(gè)緩存衰倦、為陰影更新深度紋理和陰影映射紋理等,因此需要花費(fèi)比預(yù)期更多的draw call旁理。一個(gè)好消息是樊零,Unity5引入了一個(gè)新的工具來(lái)幫助我們查看每一個(gè)draw call的工作,這個(gè)工具就是幀調(diào)試器孽文。
幀調(diào)試器
們?cè)谇懊嬉呀?jīng)多次看到幀調(diào)試器(Frame Debugger)的作用驻襟。我們可以通過(guò)Window->Analysis->Frame Debugger來(lái)打開(kāi)它。在這個(gè)窗口中芋哭,我們可以清楚的看到每一個(gè)draw call的工作和結(jié)果沉衣,如下圖所示。
幀調(diào)試器的調(diào)試面板上顯示了渲染這一幀所需要的所有渲染事件减牺,在本例中豌习,事件數(shù)目為5,而其中包含了3個(gè)draw call事件(其它渲染事件多為清空緩沖等)拔疚。通過(guò)單擊面板上的每個(gè)事件肥隆,我們可以在Game視圖查看該事件的繪制結(jié)果,同時(shí)渲染統(tǒng)計(jì)面板上的數(shù)據(jù)也會(huì)顯示成截止到當(dāng)前事件為止的各個(gè)渲染統(tǒng)計(jì)數(shù)據(jù)草雕。
以本例為例巷屿,要渲染一幀共需要花費(fèi)3個(gè)draw call,其中1個(gè)draw call用于更新深度紋理(對(duì)應(yīng)UpdateDepthTexture)和用于渲染平行光的陰影映射紋理墩虹,1個(gè)draw call用于繪制球體嘱巾,1個(gè)draw call用于繪制動(dòng)態(tài)批處理后的3個(gè)立方體模型。
在Unity的渲染統(tǒng)計(jì)窗口诫钓、分析器和幀調(diào)試器這3個(gè)利器的幫助下旬昭,我們可以獲得很多有用的優(yōu)化信息。但是菌湃,很多諸如渲染時(shí)間這樣的數(shù)據(jù)是基于當(dāng)前的開(kāi)發(fā)平臺(tái)得到的问拘,而非真機(jī)上的結(jié)果。
減少draw call數(shù)目
批處理的實(shí)現(xiàn)原理就是為了減少每一幀需要的draw call數(shù)目惧所。為了把一個(gè)對(duì)象渲染到屏幕上骤坐,CPU需要檢查哪些光源影響了該物體,綁定Shader并設(shè)置它的參數(shù)下愈,再把渲染命令發(fā)給GPU纽绍。當(dāng)場(chǎng)景中包含了大量的對(duì)象時(shí),這些操作就會(huì)非常耗時(shí)势似。
一個(gè)極端的例子是拌夏,如果我們需要渲染1000個(gè)三角形僧著,把它們按1000個(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)單皆怕,就是在每次調(diào)用draw call時(shí)盡可能多的處理物體。
那么世蔗,什么樣的物體可以一起處理呢端逼?答案就是使用一個(gè)材質(zhì)的物體。這是因?yàn)槲哿埽瑢?duì)于使用同一個(gè)材質(zhì)的物體,它們之間的不同僅僅在于頂點(diǎn)數(shù)據(jù)的差別余掖。我們可以把這些頂點(diǎn)數(shù)據(jù)合并在一起寸爆,在一起發(fā)送給GPU,就可以完成一次批處理盐欺。
兩種批處理優(yōu)缺點(diǎn)
Unity中支持兩種批處理方式:一種是動(dòng)態(tài)批處理赁豆,另一種是靜態(tài)批處理。
- 對(duì)于動(dòng)態(tài)批處理來(lái)說(shuō)冗美,優(yōu)點(diǎn)是一切處理都是Unity自動(dòng)完成的魔种,不需要我們自己進(jìn)行任何操作,而且物體是可以移動(dòng)的粉洼,但缺點(diǎn)是节预,限制很多,可能一不小心就破壞了這種機(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ú)效的)锅棕。
動(dòng)態(tài)批處理
動(dòng)態(tài)批處理的基本原理是拙泽,每一幀把可以進(jìn)行批處理的模型網(wǎng)格進(jìn)行合并,再把合并后模型數(shù)據(jù)傳遞給GPU裸燎,然后使用同一個(gè)材質(zhì)對(duì)其渲染顾瞻。
條件限制
雖然Unity的動(dòng)態(tài)批處理不需要我們進(jìn)行任何額外工作,但只有滿足條件的模型和材質(zhì)才可以被動(dòng)態(tài)批處理顺少。
- 使用光照紋理(lightmap)的物體需要小心處理朋其。這些物體需要額外的渲染參數(shù)王浴,例如在光照紋理上的索引、偏移量和縮放信息等梅猿。因此氓辣,為了讓這些物體可以被動(dòng)態(tài)批處理,我們需要保證他們指向光照紋理中的同一位置袱蚓。
- 多Pass的Shader會(huì)中斷批處理钞啸,在前向渲染中,我們有時(shí)需要額外的Pass來(lái)為模型添加更多的光照效果喇潘,但這樣一來(lái)模型就不會(huì)被動(dòng)態(tài)批處理了体斩。
從上圖可以看出,要渲染這樣一個(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)生光照影響。下圖給很出了添加點(diǎn)光源后的渲染統(tǒng)計(jì)數(shù)據(jù):
從上圖可以看出从铲,渲染一幀所需要的批處理數(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)批處理的。
靜態(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ì)稱為1個(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ù)目)恩掷,或者自己編寫(xiě)批處理的方法倡鲸。
操作
在本節(jié)的場(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ù)如下圖所示:
從上圖我們可以看出,盡管3個(gè)Teapot模型使用了相同的材質(zhì)杂伟,但它們?nèi)匀粵](méi)有被動(dòng)態(tài)批處理移层。這是因?yàn)椋琓eapot模型包含的頂點(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即可)晦溪,如下圖所示瀑粥。
這時(shí),我們?cè)儆^察渲染統(tǒng)計(jì)窗口中的批處理數(shù)目尼变,還是沒(méi)有變化利凑,但是不要著急,運(yùn)行程序后嫌术,變化就出現(xiàn)了哀澈,如下圖所示:
合并后的網(wǎng)格
從上圖可以看出,現(xiàn)在的批處理數(shù)目變成了2度气,而Save by batching數(shù)目也顯示2割按。此時(shí),如果我們?cè)谶\(yùn)行時(shí)查看每個(gè)模型使用的網(wǎng)格磷籍,會(huì)發(fā)現(xiàn)它們都變成了一個(gè)名為Combined Mesh(roo:scene)的東西适荣,如下圖所示。
這個(gè)網(wǎng)格是Unity合并了所有被標(biāo)識(shí)為“Static”的物體的結(jié)果院领,在我們的例子里弛矛,就是3個(gè)Teapot和一個(gè)立方體。讀者可能會(huì)有一個(gè)疑問(wèn)比然,這4個(gè)對(duì)象明明都不是使用的同一種材質(zhì)丈氓,為什么可以合并成一個(gè)呢?如果仔細(xì)觀察上圖的結(jié)果强法,會(huì)發(fā)現(xiàn)在圖的右下方標(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)絡(luò)結(jié)構(gòu)中我們還可以發(fā)現(xiàn),盡管3個(gè)Teapot對(duì)象使用了同一個(gè)網(wǎng)格杰扫,但合并后卻變成了3個(gè)獨(dú)立網(wǎng)格队寇。而且,我們可以從Unity的分析器中觀察到在應(yīng)用靜態(tài)批處理前后VBO total的變化章姓。從下圖所示中我們可以看出:
更多的內(nèi)存
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ì)被批處理的风宁。下圖顯示了在場(chǎng)景中添加了一個(gè)會(huì)影響4個(gè)物體的點(diǎn)光源之后,渲染統(tǒng)計(jì)窗口的數(shù)據(jù)變化蛹疯。
但是戒财,處理平行光的Base Pass部分仍然會(huì)被靜態(tài)批處理,因此我們讓然可以節(jié)省兩個(gè)draw call捺弦。
共享材質(zhì)
從之前的內(nèi)容可以看出固翰,無(wú)論是動(dòng)態(tài)批處理還是靜態(tài)批處理,都要求模型之間需要共享同一個(gè)材質(zhì)羹呵。
紋理不同
如果兩個(gè)材質(zhì)之間只有使用紋理的不同,我們可以把這些紋理合并到一張更大的紋理中疗琉,這張更大的紋理被稱為是一張圖集(atlas)冈欢。一旦使用了同一張紋理,我們就可以使用同一個(gè)材質(zhì)盈简,再使用不同的采樣坐標(biāo)對(duì)紋理采樣即可凑耻。
材質(zhì)參數(shù)不同
但有時(shí),除了紋理不同外柠贤,不同的物質(zhì)在材質(zhì)上還有一些微小的參數(shù)變化香浩,例如顏色不同、某些浮點(diǎn)屬性不同臼勉。但是不管是動(dòng)態(tài)批處理還是靜態(tài)批處理邻吭,它們的前提都是要使用同一個(gè)材質(zhì)。是同一個(gè)宴霸,而不是使用了同一個(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ì)意味著修改會(huì)應(yīng)用到所有使用該材質(zhì)的物體上烛占。另一個(gè)類似的API是Render.material
胎挎,如果使用Render.material
來(lái)修改材質(zhì),Unity會(huì)創(chuàng)建一個(gè)該材質(zhì)的復(fù)制品忆家,從而破壞批處理在該物體上的應(yīng)用犹菇,這可能并不是我們希望看到的。
批處理的注意事項(xiàng)
在選擇使用動(dòng)態(tài)批處理還是靜態(tài)批處理芽卿,我們有一些小小的建議揭芍。
- 盡可能選擇靜態(tài)批處理,但得時(shí)刻小心對(duì)內(nèi)存的消耗卸例,并且記住經(jīng)過(guò)靜態(tài)批處理的物體不可以再被移動(dòng)
- 如果無(wú)法進(jìn)行靜態(tài)批處理称杨,而要使用動(dòng)態(tài)批處理的話,那么請(qǐng)小心上面提到的各種條件限制筷转。
- 對(duì)于游戲中的小道具姑原,例如可以撿拾的金幣等,可以使用動(dòng)態(tài)批處理呜舒。
- 對(duì)于包含動(dòng)畫(huà)的這類物體锭汛,我們無(wú)法全部使用靜態(tài)批處理,但其中如果有不動(dòng)的部分,可以把這部分標(biāo)識(shí)成“Static”店乐。
- 由于批處理需要把多個(gè)模型變換到世界空間下再合并它們艰躺,因此,如果Shader中存在一些基于模型空間下的坐標(biāo)的運(yùn)算眨八,那么往往會(huì)得到錯(cuò)誤的結(jié)果腺兴。一個(gè)解決方法是,在Shader中使用DisableBatching標(biāo)簽來(lái)強(qiáng)制使用該Shader的材質(zhì)不會(huì)被批處理廉侧。
- 使用半透明材質(zhì)的物體通常需要使用嚴(yán)格的從后往前的繪制順序來(lái)保證透明混合的正確性漆枚。對(duì)于這些物體姓惑,Unity會(huì)首先保證它們的繪制順序鸭限,再嘗試對(duì)它們進(jìn)行批處理排抬。這意味著,當(dāng)繪制順序無(wú)法滿足時(shí)连舍,批處理無(wú)法在這些物體上被成功應(yīng)用没陡。
減少需要處理的頂點(diǎn)數(shù)目
優(yōu)化幾何體
在建模時(shí),有一條規(guī)則我們需要記姿魃汀:盡可能減少模型中三角面片的數(shù)目盼玄,一些對(duì)于模型沒(méi)有影響、或是肉眼非常難察覺(jué)到區(qū)別的頂點(diǎn)都要盡可能的去掉潜腻。 在很多三維建模軟件中埃儿,都有相應(yīng)的優(yōu)化選項(xiàng),可以自動(dòng)優(yōu)化網(wǎng)格結(jié)構(gòu)融涣。
軟件頂點(diǎn)數(shù)不同
Unity中顯示的數(shù)目往往要多于建模軟件里顯示的頂點(diǎn)數(shù)童番,通常Unity中顯示的數(shù)目要大很多。誰(shuí)才是對(duì)的呢威鹿?其實(shí)剃斧,這是因?yàn)樵诓煌慕嵌壬嫌?jì)算的,都有各自的道理忽你,但我們真正應(yīng)該關(guān)心的是Unity里顯示的數(shù)目悯衬。
- 三維軟件更多的是站在我們?nèi)祟惖慕嵌热ダ斫忭旤c(diǎn)的,即組成幾何體的每一個(gè)點(diǎn)就是一個(gè)單獨(dú)的點(diǎn)檀夹。
- Unity是站在GPU的角度去理解頂點(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)化建議就是:移除不必要的硬邊以及紋理銜接酒甸,避免邊界平滑和紋理分離魄健。
模型的LOD技術(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í)的模型。
遮擋剔除技術(shù)
我們最后要介紹的頂點(diǎn)優(yōu)化策略就是遮擋剔除(Occlusion culling)技術(shù)滓技。遮擋剔除可以用來(lái)消除那些在其他物件后面看不到的物體哩牍,這意味著資源不會(huì)浪費(fèi)在計(jì)算那些看不見(jiàn)的頂點(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谒麦,提高游戲性能。
減少需要處理的片元數(shù)目
另一個(gè)造成GPU瓶頸的是需要處理過(guò)多的片元哆致。這部分優(yōu)化的重點(diǎn)在于減少overdraw绕德。簡(jiǎn)單來(lái)說(shuō),overdraw指的就是同一個(gè)像素被繪制了多次摊阀。
overdraw視圖查看
Unity還提供了查看overdraw的視圖耻蛇,我們可以在Scene視圖左上方的下拉菜單中選中Overdraw即可。
實(shí)際上胞此,這里的視圖只是提供了查看物體相互遮擋的層數(shù)臣咖,并不是真正的最終屏幕繪制overdraw。也就是說(shuō)漱牵,可以理解為他顯示的是夺蛇,如果沒(méi)有使用任何深度測(cè)試和其它優(yōu)化策略時(shí)的overdraw。這種視圖是通過(guò)把所有對(duì)象都渲染成一個(gè)透明的輪廓酣胀,通過(guò)查看透明顏色的累積程度刁赦,來(lái)判斷物體之間的遮擋。當(dāng)然闻镶,我們可以使用一些措施來(lái)防止這種最壞的情況出現(xiàn)甚脉。
控制繪制順序
為了最大限度的表面overdraw,一個(gè)重要的優(yōu)化策略就是控制繪制順序铆农。由于深度測(cè)試的存在牺氨,如果我們可以保證物體都是從前往后繪制的,那么可以很大程度上減少overdraw墩剖。這是因?yàn)楹锇迹诤竺胬L制的物體無(wú)法通過(guò)深度測(cè)試,因此就無(wú)法再進(jìn)行后面的渲染處理岭皂。
在Unity中郊霎,那些渲染隊(duì)列數(shù)目小于2500(如:Background、Geometry和AlphaTest)的對(duì)象都被認(rèn)為是不透明(opaque)的物體蒲障,這些物體總體上是從前往后繪制的,而使用其他的隊(duì)列(如Transparent、Overlay等)的物體揉阎,則是從后往前繪制的庄撮。這意味著,我們可以盡可能的把物體的隊(duì)列設(shè)置為不透明物體的渲染隊(duì)列毙籽,而盡量避免使用半透明隊(duì)列洞斯。
案例
在第一人稱射擊游戲中,對(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í)間助被。
時(shí)刻警惕透明物體
對(duì)于半透明對(duì)象來(lái)說(shuō)剖张,由于它們沒(méi)有開(kāi)啟深度寫(xiě)入,因此恰起,如果要得到正確的渲染結(jié)果修械,就必須從后往前渲染检盼。這意味著肯污,半透明物體幾乎一定會(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)該避免的灰伟。
GUI處理
對(duì)于上述GUI的這種情況拆又,我們可以盡量減少窗口中GUI所占的面積。
如果實(shí)在無(wú)能無(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)啟一些特效功能。
透明度測(cè)試
在移動(dòng)平臺(tái)上前计,透明度測(cè)試也會(huì)影響游戲性能胞谭。雖然透明度測(cè)試沒(méi)有關(guān)閉深度寫(xiě)入,但由于它的實(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è)試更好业岁。
減少實(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ì)中斷批處理看成。
烘焙技術(shù)
一個(gè)模擬光源的方法是使用場(chǎng)景烘焙君编。把光照提前烘焙到一張光照紋理(lightmap)中,然后在運(yùn)行時(shí)刻只需要根據(jù)紋理采樣得到光照結(jié)果即可川慌。
體積光
另一個(gè)模擬光源的方法是使用體積光God Ray吃嘿。場(chǎng)景中很多小型光源的效果都是靠這種方法模擬的。它們一般不是真正的光源梦重,很多情況是通過(guò)透明紋理模擬得到的兑燥。
在移動(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這款游戲中云石,有很多取巧的渲染優(yōu)化技術(shù)唉工,可以去百度看看。
實(shí)時(shí)陰影
實(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ā)的性能瓶頸继谚。
減少紋理大小
之前提到過(guò),使用紋理圖集可以幫助我們減少draw call的數(shù)目阵幸,而這些紋理的大小同樣是一個(gè)需要考慮的問(wèn)題花履。
需要注意的是,所有紋理的長(zhǎng)寬比最好是一個(gè)正方形挚赊,而且長(zhǎng)寬值最好是2的整數(shù)冪诡壁。這是因?yàn)橛泻芏鄡?yōu)化策略只有在這種時(shí)候才可以發(fā)揮最大作用。在Unity 5中荠割,即便我們導(dǎo)入的紋理長(zhǎng)寬值不是2的整數(shù)冪欢峰,Unity也會(huì)自動(dòng)把長(zhǎng)寬轉(zhuǎn)換到離它最近的2的整數(shù)冪值。
除此之外涨共,我們還應(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)室囊,如下圖所示:
<img src="E:\Git\SiKi\文檔\Shader入門(mén)精要參考\Unity中的渲染優(yōu)化技術(shù).assets\image-20201202135938249.png" alt="image-20201202135938249" />
多級(jí)漸遠(yuǎn)技術(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í)漸元紋理往往會(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ì)畫(huà)質(zhì)的要求,我們不希望對(duì)這些紋理進(jìn)行壓縮兼雄。
利用分辨率縮放
過(guò)高的屏幕分辨率也是造成性能下降的原因之一吟逝,尤其是對(duì)于很多低端的手機(jī),除了分辨率高其它硬件條件并不盡如人意赦肋,而這恰恰是游戲性能的兩大瓶頸:過(guò)大的屏幕分辨率和糟糕的GPU块攒。
因此,我們需要對(duì)于特定機(jī)器進(jìn)行分標(biāo)率的放縮佃乘。當(dāng)然囱井,這樣可能會(huì)造成游戲效果的下降,但性能和畫(huà)面之間永遠(yuǎn)是個(gè)需要權(quán)衡的話題趣避。在Unity中設(shè)置屏幕分標(biāo)率可以直接使用Screen.SetResolution庞呕。
減少計(jì)算復(fù)雜度
Shader的LOD技術(shù)
和前面提到的模型的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
}
我們也可以在UnityShader的導(dǎo)入面板上看到該Shader使用的LOD值髓绽。在默認(rèn)情況下,允許的LOD等級(jí)是無(wú)限大的妆绞。這意味著顺呕,任何被當(dāng)前顯卡支持的Shader都可以被調(diào)用。
但是括饶,在某些情況下我們可能去掉一些使用了復(fù)雜計(jì)算的Shader渲染株茶。這時(shí)我們可以使用Shader.maximumLOD
或Shader.globalMaximumLOD
來(lái)設(shè)置允許的最大LOD值。
Unity內(nèi)置的Shader使用了不同的LOD值图焰,例如启盛,Diffuse
的LOD為200,而Bumped Specular
的LOD為100
代碼方面的優(yōu)化
運(yùn)算對(duì)象
在實(shí)現(xiàn)游戲效果時(shí)技羔,我們可以選擇在哪里進(jìn)行特定的運(yùn)算僵闯。通常來(lái)講,游戲需要計(jì)算的對(duì)象藤滥、頂點(diǎn)和像素?cái)?shù)目的排序是對(duì)象數(shù)<頂點(diǎn)數(shù)<像素?cái)?shù)鳖粟。因此,我們應(yīng)該盡可能的把計(jì)算放在每個(gè)對(duì)象或逐頂點(diǎn)上拙绊。
精度值
首先向图,第一點(diǎn)是,盡可能使用低精度的浮點(diǎn)值進(jìn)行計(jì)算标沪。
- 最高精度的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)行處理。
Shader合并
除此之外迂尝,盡量把多個(gè)特效合并到一個(gè)Shader中脱茉。例如,我們可以把顏色校正和添加噪聲等屏幕特效在Bloom特效的最后一個(gè)Pass中進(jìn)行合成垄开。還有一個(gè)方法就是使用前面介紹的縮放思想琴许,來(lái)選擇性的開(kāi)啟特效。
其他
- 盡可能不要使用分支語(yǔ)句和循環(huán)語(yǔ)句
- 盡可能避免使用類似sin溉躲、tan榜田、pow、log等較為復(fù)雜的數(shù)學(xué)運(yùn)算锻梳。我們可以使用查找表來(lái)作為替代箭券。
- 盡可能不要使用discard操作,因?yàn)檫@會(huì)影響某些硬件的優(yōu)化疑枯。
根據(jù)硬件條件進(jì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)啟粒子效果等。