端游戲發(fā)熱優(yōu)化:光照烘焙如何讓GPU負(fù)載減半、溫度直降4℃)
這個(gè)系列前面聊過(guò)不少給手機(jī)降負(fù)載的手段但真正讓我覺(jué)得一勞永逸、性?xún)r(jià)比極高的還得是光照烘焙這張牌。光照烘焙解決的是移動(dòng)端發(fā)燙優(yōu)化里最核心的一塊把每一幀都要做的光照計(jì)算提前換成一次貼圖采樣。很多團(tuán)隊(duì)對(duì)發(fā)熱的直覺(jué)是“手機(jī)散熱不行”“芯片太激進(jìn)”但從項(xiàng)目可控度來(lái)看真正能改的是渲染成本。光照烘焙就是那個(gè)能在不犧牲觀感的前提下把GPU負(fù)載實(shí)打?qū)嵖车粢淮蠼氐牟僮?。這篇我結(jié)合自己做過(guò)的一個(gè)移動(dòng)端場(chǎng)景改造把光照烘焙為什么能降溫、接入時(shí)要注意什么、實(shí)測(cè)數(shù)據(jù)能到什么水平以及烘焙過(guò)程中容易踩的坑全部捋一遍。適合正在做發(fā)燙治理的客戶(hù)端開(kāi)發(fā)、技術(shù)美術(shù)也適合第一次接觸烘焙的新人。1. 發(fā)熱的賬本實(shí)時(shí)光照是GPU負(fù)載里的重頭開(kāi)銷(xiāo)1.1 移動(dòng)端發(fā)熱的本質(zhì)是芯片持續(xù)高負(fù)載手機(jī)發(fā)燙表面上是外殼熱本質(zhì)上是SoC里的GPU長(zhǎng)時(shí)間處于高功耗狀態(tài)。移動(dòng)端設(shè)備散熱面積小沒(méi)有主動(dòng)風(fēng)扇熱量一旦積累起來(lái)芯片就會(huì)觸發(fā)降頻然后表現(xiàn)為幀率波動(dòng)、畫(huà)面變卡玩家體感就是“又燙又卡”。這個(gè)循環(huán)一旦形成體驗(yàn)基本很難救回來(lái)。所以做發(fā)燙優(yōu)化思路不應(yīng)該是“想辦法給手機(jī)降溫”而是“想辦法讓芯片不需要做那么多事”。只要每一幀的渲染負(fù)載降下來(lái)功耗就會(huì)降溫度自然跟著降。這也是為什么所有發(fā)熱治理方案最后都會(huì)落到渲染開(kāi)銷(xiāo)上——要么減少繪制量要么減少單個(gè)像素的計(jì)算量要么減少帶寬占用。光照烘焙屬于第三種思路里最典型的代表把本來(lái)逐幀動(dòng)態(tài)計(jì)算的光照信息提前離線(xiàn)算好運(yùn)行時(shí)只需要讀數(shù)據(jù)。它跟LOD、合批這類(lèi)優(yōu)化還不一樣LOD是在砍幾何復(fù)雜度合批是在砍Draw Call光照烘焙直接砍的是著色器里最貴的那部分?jǐn)?shù)學(xué)運(yùn)算。1.2 一幀畫(huà)面里實(shí)時(shí)光照到底在算些什么要理解烘焙為什么省電得先看清實(shí)時(shí)光照在一幀里做了多少事。假設(shè)一個(gè)室內(nèi)場(chǎng)景有一個(gè)平行光當(dāng)太陽(yáng)兩盞點(diǎn)光當(dāng)裝飾燈再有個(gè)動(dòng)態(tài)角色在走動(dòng)平行光會(huì)對(duì)所有接收光照的物體產(chǎn)生漫反射和高光計(jì)算每個(gè)像素都要跑一遍光照模型。兩盞點(diǎn)光意味著每個(gè)像素還要額外疊加兩次光源貢獻(xiàn)Shader里就要多算兩遍漫反射高光衰減。平行光要投射陰影就必須以光源視角額外渲染一張Shadow Map這本身就是一次全場(chǎng)景深度渲染。動(dòng)態(tài)角色要跟地面有接觸陰影角色身上通常還要單獨(dú)開(kāi)實(shí)時(shí)陰影再疊加一層陰影貼圖采樣。如果場(chǎng)景里有間接光純實(shí)時(shí)渲染基本算不動(dòng)通常只能靠環(huán)境光或者各種近似方案湊合。這些運(yùn)算疊加在一起GPU的時(shí)鐘周期和帶寬都在瘋狂消耗。我在低端機(jī)上測(cè)過(guò)一個(gè)不算復(fù)雜的中型場(chǎng)景光平行光和兩盞實(shí)時(shí)點(diǎn)光光柵化加陰影采樣就能吃掉8到12毫秒的GPU時(shí)間。對(duì)移動(dòng)端來(lái)說(shuō)這個(gè)數(shù)字已經(jīng)意味著幀率頂不上60幀發(fā)熱也很明顯。1.3 為什么優(yōu)先動(dòng)光照而不是先調(diào)Shader有人會(huì)問(wèn)Shader里加一些分支優(yōu)化、減少Overdraw不也能省電嗎能但收益量級(jí)完全不同。Shader微調(diào)通常是在5%到15%的范圍內(nèi)摳而光照烘焙是無(wú)縫切換到另一條成本曲線(xiàn)把逐像素光照計(jì)算變成一次紋理采樣省掉的是80%以上的光源相關(guān)開(kāi)銷(xiāo)。尤其是場(chǎng)景里靜態(tài)物體占比高的情況下烘焙的收益最大。一個(gè)典型的游戲關(guān)卡地板、墻體、道具、建筑這些靜態(tài)元素通常占到90%以上的畫(huà)面面積這些物體如果都走實(shí)時(shí)計(jì)算GPU大部分時(shí)間都在做無(wú)用功。把它們轉(zhuǎn)換成烘焙光照等于讓GPU退掉大部分重復(fù)性的加班只保留少數(shù)真正需要?jiǎng)討B(tài)計(jì)算的部分。2. 光照烘焙的省錢(qián)原理把“逐幀現(xiàn)做”變成“查表拿結(jié)果”2.1 Lightmap的本質(zhì)是提前算好的光照結(jié)果烘焙之后生成的Lightmap光照貼圖說(shuō)白了就是一套紋理紋理里每個(gè)像素存的是對(duì)應(yīng)物體表面接收到的光照結(jié)果包括直接光和間接光。運(yùn)行時(shí)Shader不需要再計(jì)算光源方向、衰減、遮擋只需要采樣這張貼圖把顏色疊加到材質(zhì)上。舉個(gè)生活化的例子實(shí)時(shí)渲染就像每天中午去廚房現(xiàn)切菜、現(xiàn)炒菜一道菜要忙活半小時(shí)烘焙相當(dāng)于提前把菜做好打包放進(jìn)冰箱吃飯的時(shí)候微波爐加熱三分鐘就端上桌。觀感上還是那份飯但后廚的工作量完全不是一個(gè)量級(jí)。具體到引擎實(shí)現(xiàn)里Unity和Unreal都提供了完整的光照烘焙管線(xiàn)。開(kāi)發(fā)者把物體標(biāo)記為靜態(tài)、把光源設(shè)置為烘焙模式、設(shè)置好分辨率然后就交給引擎離線(xiàn)計(jì)算。引擎會(huì)算出每個(gè)物體表面的光照結(jié)果并排成一張或者多張Atlas貼圖。運(yùn)行期間引擎會(huì)把這張貼圖自動(dòng)綁定到材質(zhì)上原本幾十上百條GPU指令的運(yùn)算變成幾次UV采樣和一次插值。2.2 不只是漫反射Light Probe、Shadowmask、Reflection Probe一起配合如果只是靜態(tài)物體表面有烘焙光動(dòng)態(tài)角色站在場(chǎng)景里會(huì)顯得“浮起來(lái)”——因?yàn)榻巧砩蠜](méi)有正確的環(huán)境光反饋。所以完整的烘焙方案不是一個(gè)Lightmap單打獨(dú)斗而是一套組合Lightmap負(fù)責(zé)靜態(tài)物體表面的直接光和間接光。Light Probe光照探針在場(chǎng)景里布一些采樣點(diǎn)記錄該位置的入射光信息。動(dòng)態(tài)物體運(yùn)行時(shí)通過(guò)周?chē)结槻逯档玫焦庹兆尳巧谌牒姹簣?chǎng)景。Reflection Probe反射探針用來(lái)給金屬、玻璃這類(lèi)高光物體提供環(huán)境反射信息彌補(bǔ)烘焙貼圖不包含高光反射的問(wèn)題。Shadowmask模式把靜態(tài)物體的陰影烘焙到貼圖里的同時(shí)預(yù)留一些實(shí)時(shí)陰影能力讓動(dòng)態(tài)物體也能在場(chǎng)景里投射正確的影子。這套組合的重要性在于光照烘焙不是把整個(gè)場(chǎng)景打回“沒(méi)有陰影的貼圖感”而是把靜態(tài)信息用貼圖保存動(dòng)態(tài)信息用探針和實(shí)時(shí)陰影補(bǔ)足。畫(huà)面層次和動(dòng)態(tài)交互都能保留但計(jì)算的絕對(duì)量大幅下降。2.3 移動(dòng)端尤其劃算的另一個(gè)原因分辨率感知不高在PC大屏上烘焙貼圖的細(xì)節(jié)差距可能通過(guò)走近看還是能發(fā)現(xiàn)但在手機(jī)上屏幕尺寸和PPI決定了玩家不會(huì)貼著一個(gè)物體去看光照過(guò)渡。中等分辨率的Lightmap在手機(jī)上已經(jīng)足夠平滑勞動(dòng)成本卻比高精度烘焙低一個(gè)數(shù)量級(jí)。這個(gè)特性讓移動(dòng)端成了光照烘焙收益最大的平臺(tái)你付出離線(xiàn)計(jì)算的成本換來(lái)的是運(yùn)行時(shí)幾乎為零的光照開(kāi)銷(xiāo)同時(shí)畫(huà)質(zhì)觀感損失很小。3. 實(shí)戰(zhàn)接入U(xiǎn)nity和Unreal里把光照“烤”熟的標(biāo)準(zhǔn)動(dòng)作3.1 Unity側(cè)從標(biāo)記Static到出圖在Unity里做烘焙第一步是把需要烘焙的物體標(biāo)記為靜態(tài)。選中場(chǎng)景里的模型在Inspector面板右上角點(diǎn)開(kāi)Static下拉菜單選擇Lightmap Static或者直接在Mesh Renderer組件里勾選Contribute GI。這里要注意物體必須是靜態(tài)的烘焙結(jié)果才能被正確生成如果物體沒(méi)有標(biāo)記即使你再怎么調(diào)光源烘焙出來(lái)它也都是黑的或者實(shí)時(shí)計(jì)算。光源的設(shè)置同樣關(guān)鍵。需要全局定向光就選平行光組件的Light Mode有三種選擇Realtime繼續(xù)實(shí)時(shí)計(jì)算適合玩家交互產(chǎn)生的動(dòng)態(tài)光。Baked完全烘焙運(yùn)行時(shí)沒(méi)有任何光照計(jì)算代價(jià)適合裝飾燈、氛圍燈。Mixed混合模式靜態(tài)物體的陰影烘焙但Shadowmask和Light Probe還能對(duì)動(dòng)態(tài)物體產(chǎn)生投影適合主光源。移動(dòng)端我個(gè)人的習(xí)慣是主平行光用Mixed普通裝飾光全部Baked只有真的跟隨角色或者表現(xiàn)特效動(dòng)態(tài)變化的光源才保留Realtime。這樣既保留了動(dòng)態(tài)物體最基本的影子反饋又不會(huì)把實(shí)時(shí)光源數(shù)量拖起來(lái)。設(shè)置完成后打開(kāi)Window Rendering Lighting面板在Scene標(biāo)簽里把Lighting Mode選好然后點(diǎn)擊Generate Lighting。Unity默認(rèn)的Progressive GPU Lightmapper會(huì)逐步顯示烘焙進(jìn)度方便你邊烤邊看效果。3.2 Unreal側(cè)Static光源與Build LightsUnreal的流程思路一樣但入口不太一樣。UE中網(wǎng)格體要標(biāo)記為Static光源則設(shè)置為Static或Stationary。對(duì)于移動(dòng)端項(xiàng)目我的做法是主平行光用Stationary因?yàn)镾tationary光源保留了動(dòng)態(tài)物體投射陰影的能力但靜態(tài)物體依然走烘焙結(jié)果點(diǎn)光源除非是關(guān)鍵交互對(duì)象否則一律Static完全烘焙。在World Settings里有一個(gè)經(jīng)常被人忽略的參數(shù)Static Lighting Level Scale它控制間接光照的體積分辨率。默認(rèn)值是1烘焙細(xì)節(jié)高但內(nèi)存和時(shí)長(zhǎng)也跟著高。移動(dòng)端我一般調(diào)到0.3~0.5畫(huà)面觀感下降不多Lightmap和VLM體積占用卻會(huì)明顯減少烘焙時(shí)間也快不少。設(shè)置完成之后點(diǎn)擊Build菜單下的Build Lighting Only或者直接按快捷鍵引擎就會(huì)調(diào)用Lightmass開(kāi)始烘焙。Unreal的好處是烘焙結(jié)果會(huì)直接在視口里反饋光影質(zhì)量很直觀。3.3 移動(dòng)端專(zhuān)項(xiàng)參數(shù)建議很多項(xiàng)目第一次烘焙直接沿用PC的配置結(jié)果烘焙完一看包體和內(nèi)存爆了低端機(jī)也扛不住。移動(dòng)端烘焙參數(shù)要單獨(dú)調(diào)我的常用基線(xiàn)是這樣Lightmap Resolution每單位世界距離的像素密度移動(dòng)端建議10~20中小型房間15左右足夠大型野外場(chǎng)景可以降到8~10。Directional Mode優(yōu)先選Non-Directional能省一半內(nèi)存。只有場(chǎng)景里明顯需要法線(xiàn)方向光影變化時(shí)才考慮Directional。CompressionUnity里開(kāi)啟Lightmap壓縮Android選ETC2或ASTCiOS選ASTC。壓縮能顯著減小包體和運(yùn)行時(shí)內(nèi)存但注意壓縮程度太高會(huì)產(chǎn)生漏光或顏色斷層要平衡。Lightmap Padding單一圖集內(nèi)不同UV島之間的間距太小時(shí)相鄰物件容易互相滲色移動(dòng)端建議保持在4~8像素左右。Bounces間接光反彈次數(shù)Unity和Unreal默認(rèn)2~3次足夠再高畫(huà)面已經(jīng)看不出差異純純?cè)黾雍姹簳r(shí)間。這幾個(gè)參數(shù)如果場(chǎng)景不是特別復(fù)雜基本能讓烘焙結(jié)果在容量和畫(huà)質(zhì)之間達(dá)到一個(gè)比較穩(wěn)的平衡點(diǎn)。調(diào)試階段可以先調(diào)低分辨率快速出圖看構(gòu)圖確定燈位和氛圍沒(méi)問(wèn)題再回到高分辨率做最終烘焙。4. 實(shí)測(cè)數(shù)據(jù)一個(gè)中等場(chǎng)景烘焙前后的性能與溫度對(duì)比4.1 測(cè)試場(chǎng)景和方法這部分的數(shù)據(jù)來(lái)自我之前做的一個(gè)移動(dòng)端室外街區(qū)加室內(nèi)小場(chǎng)景的改造。場(chǎng)景里有街道、房屋、綠化、室內(nèi)家具等靜態(tài)物體實(shí)行動(dòng)線(xiàn)固定角色在街道和房間里穿行。手機(jī)測(cè)試機(jī)選用一臺(tái)驍龍8系中端機(jī)系統(tǒng)亮度固定50%開(kāi)啟飛行模式關(guān)掉后臺(tái)進(jìn)程每人同一視角路線(xiàn)跑3次取平均。記錄工具上Unity側(cè)用Profiler里的GPU模塊看單幀GPU耗時(shí)整機(jī)功耗和溫度用PerfDog配合第三方腳本讀取。溫度測(cè)量放在30分鐘連續(xù)跑圖之后記錄機(jī)身最熱位置的紅外溫度。4.2 關(guān)鍵數(shù)字對(duì)比改造前場(chǎng)景里有一個(gè)Realtime平行光外加三盞Realtime點(diǎn)光所有靜態(tài)物體都有實(shí)時(shí)陰影。改造后平行光切成Mixed點(diǎn)光全部Baked靜態(tài)物體全部成為L(zhǎng)ightmap對(duì)象動(dòng)態(tài)角色保留Light Probe和Shadowmask。指標(biāo)烘焙前烘焙后變化GPU單幀耗時(shí)低負(fù)載場(chǎng)景12.3 ms5.8 ms下降約53%GPU單幀耗時(shí)復(fù)雜街區(qū)19.6 ms9.2 ms下降約53%平均FPS4259穩(wěn)定提升整機(jī)功耗4.8 W3.3 W下降約31%30分鐘后機(jī)身最高溫度43.1 ℃38.9 ℃下降4.2 ℃Lightmap內(nèi)存占用無(wú)約5 MB換取大幅運(yùn)算下降這個(gè)數(shù)據(jù)不是絕對(duì)的但它能反映出光照烘焙的真實(shí)量級(jí)GPU耗時(shí)直接腰斬整機(jī)功耗下降約三成30分鐘后機(jī)身溫度從“明顯燙手”回到“溫溫的”狀態(tài)。對(duì)玩家而言這種溫度差異已經(jīng)能從握持手感上明顯感知出來(lái)。4.3 數(shù)據(jù)要這么讀先看瓶頸再看指標(biāo)同類(lèi)項(xiàng)目如果想復(fù)現(xiàn)這個(gè)流程我建議先把測(cè)試目標(biāo)拆開(kāi)。第一優(yōu)先級(jí)是看GPU耗時(shí)是否成為瓶頸如果項(xiàng)目瓶頸在CPU端烘焙效果會(huì)被其他因素蓋住。第二步看GPU耗時(shí)下降后整機(jī)功耗是否跟著下降很多時(shí)候Shader省了但CPU還在忙幀率沒(méi)變溫度也沒(méi)變需要配合其他優(yōu)化一起做。另外要控制變量環(huán)境溫度差幾度、手機(jī)亮度差10%、后臺(tái)多跑一個(gè)App甚至手機(jī)殼的導(dǎo)熱性能都會(huì)影響溫度讀數(shù)。最好是同一天測(cè)試同一臺(tái)設(shè)備跑同一個(gè)場(chǎng)景路徑才能得到有說(shuō)服力的對(duì)比數(shù)據(jù)。5. 烘焙實(shí)戰(zhàn)中最容易踩的坑從“烤不熟”到“烤糊了”的排查鏈路5.1 場(chǎng)景里總有物體是黑的或?qū)崟r(shí)計(jì)算的最常見(jiàn)的現(xiàn)象是烘焙完某面墻黑得離譜或者某個(gè)裝飾物看起來(lái)跟周?chē)h(huán)境格格不入。究其原因基本就是物體沒(méi)有被正確標(biāo)記為Static或者光源里還殘留Realtime模式。排查鏈路我一般是這么走的先選中那個(gè)物體看Inspector里的Static標(biāo)記是否勾上。然后在Lighting窗口刷新后直接Generate Lighting烘焙完看一眼Lightmap列表里有沒(méi)有生成該物體的圖集。如果是物體本身UV2不對(duì)Unity會(huì)把它單獨(dú)放進(jìn)一個(gè)很小的圖集表現(xiàn)為烘焙結(jié)果特別糊。一個(gè)很容易被忽略的細(xì)節(jié)是模型導(dǎo)入時(shí)如果沒(méi)勾選Generate Lightmap UVsUnity會(huì)提示需要第二套UV。對(duì)有高級(jí)UV技巧的建模師來(lái)說(shuō)這是基本功但很多時(shí)候從美術(shù)手里拿到的模型只有一套UV這時(shí)可以勾選引擎自帶的自動(dòng)展UV功能并把Pack Margin調(diào)到0.05左右避免UV島之間相互滲色。5.2 接縫、漏光和顏色斷層烘焙完最常見(jiàn)的視覺(jué)瑕疵就是接縫——在兩個(gè)相鄰物體的交界處看到一條明顯的亮線(xiàn)或暗線(xiàn)。原因通常是光照貼圖的UV島之間沒(méi)有足夠Padding或者不同物體用了不同分辨率導(dǎo)致采樣跳變。漏光的根源大多是Lightmap分辨率不夠或者各向異性壓縮太狠。ASTC 6x6壓完之后顏色過(guò)渡變粗糙燈光在模型邊角處的漸變就會(huì)出現(xiàn)斷裂。解決辦法是先看看是不是分辨率問(wèn)題調(diào)到更高分辨率再試如果分辨率已經(jīng)夠高還漏則多半是壓縮格式問(wèn)題改成ASTC 4x4或者ETC2會(huì)好很多。還有一類(lèi)發(fā)黑的問(wèn)題跟Lightmap無(wú)關(guān)是后處理里的AO疊加太猛。烘焙自帶AO通常已經(jīng)很柔和再疊加屏幕空間AO會(huì)把墻角、邊緣壓得太黑。移動(dòng)端我建議烘焙時(shí)把AO信息放在Lightmap里后處理關(guān)掉或降強(qiáng)度畫(huà)面反而更干凈。5.3 動(dòng)態(tài)角色到了烘焙場(chǎng)景里發(fā)灰烘焙場(chǎng)景里角色顯得跟環(huán)境脫節(jié)通常是Light Probe沒(méi)布好。烘焙之后動(dòng)態(tài)物體的實(shí)時(shí)光照不能直接用需要通過(guò)探針插值。如果場(chǎng)景里探針數(shù)量不足、位置放得太密或太疏角色走到一些區(qū)域就采不到有效光照整體發(fā)灰發(fā)悶。正確布法是沿著玩家動(dòng)線(xiàn)、門(mén)前、轉(zhuǎn)角、房間中心這些關(guān)鍵位置放置探針密度以“兩米左右一個(gè)”為基準(zhǔn)再根據(jù)場(chǎng)景明暗變化加密。探針千萬(wàn)不要塞進(jìn)墻體或大型物體內(nèi)部測(cè)出來(lái)的一幀光照會(huì)污染整片插值結(jié)果。布完探針之后在Game視圖里讓角色走一圈動(dòng)線(xiàn)檢查明暗過(guò)渡是否順滑。5.4 烘焙時(shí)間太長(zhǎng)、Lightmap圖集過(guò)大烘焙時(shí)間會(huì)隨著GI雙反彈、Lightmap分辨率和場(chǎng)景面積飛速膨脹。美術(shù)這邊調(diào)一版燈光跑去烤一次兩小時(shí)這基本沒(méi)法迭代。我的做法是迭代階段用低分辨率加僅直接光模式只看光影構(gòu)圖確定最終燈光氛圍后再開(kāi)完整烘焙一次出最終結(jié)果。圖集過(guò)大的問(wèn)題則要從“圖集復(fù)用”的角度解決。把場(chǎng)景分成多個(gè)區(qū)域用Lighting窗口里的Lightmap Parameters分別控制不同區(qū)域的烘焙分辨率。比如核心戰(zhàn)斗區(qū)用20 texels/m邊角堆放區(qū)用10 texels/m能有效控制最終貼圖總量。同時(shí)圖集盡量控制在2048或1024以?xún)?nèi)移動(dòng)端超過(guò)4096不僅內(nèi)存高GPU采樣帶寬也會(huì)成為新的瓶頸。5.5 一個(gè)容易忽略的坑動(dòng)態(tài)光源沒(méi)清干凈烘焙完靜態(tài)物體很完美但只要角色進(jìn)入場(chǎng)景某個(gè)地方就會(huì)突然出現(xiàn)一道黑影或高亮的色斑。排查到最后往往是場(chǎng)景里還殘留著某個(gè)并非需求必選的實(shí)時(shí)點(diǎn)光。這種光在運(yùn)行時(shí)一進(jìn)入照射范圍就會(huì)實(shí)時(shí)計(jì)算不僅成本高還容易跟烘焙結(jié)果產(chǎn)生雙重照明。處理方式非常粗暴把不需要?jiǎng)討B(tài)的光源全部切成Baked保留的最少兩盞交互光設(shè)置為Mixed并控制照射半徑。開(kāi)Frame Debugger看一下每個(gè)像素的光照貢獻(xiàn)來(lái)源能清清楚楚看到哪個(gè)光源在干活。6. 別把烘焙當(dāng)萬(wàn)能藥適用邊界與組合拳6.1 哪些玩法不能只靠靜態(tài)烘焙光照烘焙的前提是場(chǎng)景光照基本不變。如果游戲有實(shí)時(shí)晝夜循環(huán)、動(dòng)態(tài)天氣、可破壞墻體、玩家可制造光源等玩法純烘焙方案就沒(méi)辦法滿(mǎn)足——Lightmap是離線(xiàn)算好的運(yùn)行時(shí)不會(huì)跟著晝夜變化。這種項(xiàng)目我建議采用“分層烘焙微量實(shí)時(shí)”的混合思路把結(jié)構(gòu)場(chǎng)景整體烘焙為基調(diào)晝夜變化用環(huán)境光和Directional Light的旋轉(zhuǎn)、顏色、強(qiáng)度來(lái)模擬配合后處理調(diào)色。動(dòng)態(tài)光源嚴(yán)格控制在個(gè)位數(shù)其余全部靠烘焙和探針提供基礎(chǔ)光照。這樣既保留了核心玩法需要的動(dòng)態(tài)光照反饋又不會(huì)讓實(shí)時(shí)光照成本失控。6.2 跟其他移動(dòng)端優(yōu)化手段怎么銜接光照烘焙應(yīng)該排在渲染優(yōu)化的第一梯隊(duì)但它不能替代所有工作。它跟LOD、遮擋剔除、紋理壓縮是互補(bǔ)關(guān)系烘焙負(fù)責(zé)砍逐像素光照計(jì)算LOD負(fù)責(zé)減少頂點(diǎn)數(shù)遮擋剔除負(fù)責(zé)減少可見(jiàn)物體數(shù)量紋理壓縮負(fù)責(zé)降低帶寬。四者疊加起來(lái)才能把一個(gè)場(chǎng)景的渲染成本壓到很低的水平。一個(gè)比較成熟的移動(dòng)端組合是靜態(tài)物體全量Lightmap 角色/特效少量實(shí)時(shí)光 陰影貼圖僅作用于近處 反射探針預(yù)烘焙。這樣場(chǎng)景在任何角度看都有穩(wěn)定光影動(dòng)態(tài)交互點(diǎn)也不至于干癟。再疊加上Streaming Mipmap和Lightmap的紋理流送內(nèi)存也能控制在可接受范圍內(nèi)。6.3 我落地時(shí)的幾條經(jīng)驗(yàn)項(xiàng)目做發(fā)燙治理時(shí)我把“GPU耗時(shí)、整機(jī)功耗、峰值溫度”三個(gè)指標(biāo)固化成每次構(gòu)建的必測(cè)項(xiàng)每次改動(dòng)光照配置后都跑一次這三項(xiàng)數(shù)據(jù)而不是只看幀率。幀率快被垂直同步卡住時(shí)根本看不出性能變化功耗和溫度才是真正反映發(fā)熱的鏡子。另外烘焙迭代的流程養(yǎng)成習(xí)慣后效率會(huì)高很多。前期先用最低分辨率快速出圖定調(diào)中期開(kāi)中等分辨率檢查美術(shù)細(xì)節(jié)最后只保留高分辨率出包。不要每一次都在高分辨率下反復(fù)重烤那會(huì)把團(tuán)隊(duì)的心態(tài)和迭代節(jié)奏全拖垮。最后分享一個(gè)小技巧只要條件允許把Lightmap的最終結(jié)果單獨(dú)用一個(gè)目錄管理版本變動(dòng)時(shí)通過(guò)Asset Bundle只更新貼圖資源。這樣美術(shù)調(diào)整燈光后程序不需要重新構(gòu)建整個(gè)場(chǎng)景移動(dòng)端補(bǔ)丁體積也能控制在很小的范圍內(nèi)。這套流程跑順了光照烘焙不只是一次性能優(yōu)化更是整個(gè)項(xiàng)目提效的一部分。