射器優(yōu)化實(shí)戰(zhàn):從粒子模塊減法到渲染性能提升)
Niagara的Lightweight Emitters這件事我最初是從一次移動(dòng)端掉幀事故開始的。當(dāng)時(shí)接到一個(gè)模擬項(xiàng)目X的優(yōu)化任務(wù)場(chǎng)景里有一批體積煙霧、火花和揚(yáng)塵效果總共十幾個(gè)Niagara發(fā)射器在某中端手機(jī)上幀耗時(shí)直接飆到11ms以上Profiler里滿屏都是半透明Overdraw和粒子Tick的耗時(shí)。后來我花了兩個(gè)星期把所有效果逐個(gè)改造成輕量級(jí)發(fā)射器幀耗時(shí)壓到2ms以內(nèi)畫面觀感幾乎沒損失。那次之后我才認(rèn)真把Niagara的“輕量化工”當(dāng)成一個(gè)專門方向來研究而不是簡(jiǎn)單把粒子數(shù)減半就完事。這篇內(nèi)容適合正在用Niagara做實(shí)時(shí)特效的開發(fā)者、技術(shù)美術(shù)和性能優(yōu)化崗的同行。我會(huì)從“粒子發(fā)射器為什么重”開始拆解輕量發(fā)射器的設(shè)計(jì)原則和具體搭建步驟再把我在實(shí)際項(xiàng)目中踩過的坑、排查問題的思路和一套實(shí)測(cè)對(duì)比數(shù)據(jù)寫出來。無論你是剛接觸Niagara的新人還是被性能優(yōu)化折磨很久的熟手里面的操作細(xì)節(jié)和取舍邏輯都可以直接拿到自己的項(xiàng)目里復(fù)現(xiàn)。1. 輕量發(fā)射器擺上臺(tái)面的原因1.1 傳統(tǒng)發(fā)射器的“重量”從哪來很多開發(fā)者對(duì)Niagara的第一印象是“功能強(qiáng)大但非常容易做重”。一個(gè)默認(rèn)創(chuàng)建出來的發(fā)射器模板自帶Spawn Rate、Lifetime、Gravity Force、Drag、Collision、Noise Force、Scale Sprite Size、Color Over Life等模塊。你什么都還沒干每粒子的每幀計(jì)算量就已經(jīng)堆得相當(dāng)可觀。在CPU粒子場(chǎng)景里這些模塊會(huì)逐幀遍歷粒子。假設(shè)你有2000個(gè)粒子每個(gè)粒子要執(zhí)行幾十次浮點(diǎn)運(yùn)算再加上渲染端的Vertex Shader和Pixel Shader單發(fā)射器每幀消耗就這么上去了。更隱蔽的開銷來自于數(shù)據(jù)邊界計(jì)算、組件同步、排序、裁剪和半透明混合這些固定開銷不隨粒子數(shù)等比下降反而是小數(shù)量粒子發(fā)射器里的主要成本。另一個(gè)重量來源是材質(zhì)。Niagara的Sprite渲染器只是把粒子坐標(biāo)傳給材質(zhì)真正的成本大頭在Pixel Shader上。一個(gè)包含復(fù)雜噪聲擾動(dòng)、三張以上的貼圖采樣、Custom Expression節(jié)點(diǎn)和不透明度的材質(zhì)會(huì)讓一小塊煙霧區(qū)域的GPU耗時(shí)瞬間超過一整個(gè)場(chǎng)景的模型渲染。很多“發(fā)射器不重”的錯(cuò)覺就來自這里粒子只有幾百個(gè)幀率卻被一個(gè)半透明材質(zhì)壓垮。所以輕量發(fā)射器的核心思路不是“少用粒子”而是從數(shù)據(jù)流、模塊樹、渲染材質(zhì)、狀態(tài)管理四個(gè)層面同時(shí)做減法。1.2 輕量發(fā)射器的價(jià)值邊界輕量發(fā)射器并不是所有場(chǎng)合的萬能解。它適合用在大量重復(fù)、低關(guān)注度的效果上比如遠(yuǎn)處環(huán)境的塵埃、奔跑揚(yáng)塵、瀑布濺射水花、火焰余燼、小型命中特效。這類效果有共同點(diǎn)不承擔(dān)近距離視覺核心數(shù)量卻不少同屏出現(xiàn)很多套。而主角技能、過場(chǎng)動(dòng)畫里的關(guān)鍵特效、需要精確物理反饋的交互效果就不應(yīng)該硬凹輕量化。它們值得用更多粒子、更多模塊和更復(fù)雜的渲染邏輯去堆視覺表現(xiàn)。把輕量方案強(qiáng)套在關(guān)鍵特效上只會(huì)讓畫面質(zhì)感明顯縮水最后還得返工。我一般這樣劃定邊界如果效果在屏幕上占據(jù)的面積小于總畫幅的八分之一且持續(xù)時(shí)間不超過2秒就默認(rèn)走輕量發(fā)射器方案如果單次存在時(shí)間超過5秒或者被攝像機(jī)拉到很近的距離再適當(dāng)放寬粒子預(yù)算和材質(zhì)復(fù)雜度。2. 輕量粒子的設(shè)計(jì)原則2.1 粒子數(shù)量要交給“視覺密度”決定降低粒子數(shù)量是輕量化最直覺的操作但怎么降、降到多少合適很多人是拍腦袋定的。我的判斷維度是視覺密度也就是單位屏幕面積內(nèi)粒子覆蓋的數(shù)量它比絕對(duì)粒子數(shù)更接近真實(shí)觀感。舉個(gè)例子一個(gè)全屏范圍的爆炸特效2000個(gè)粒子看起來可能還是稀疏但一個(gè)只有屏幕十分之一大小的火花特效300個(gè)粒子就已經(jīng)顯得非常密實(shí)了。直接把大范圍特效的粒子數(shù)遷移到小型特效上會(huì)白白消耗性能。實(shí)操中我會(huì)在編輯器里把視角拉到特效最常出現(xiàn)的距離先以粒子數(shù)量1024起步觀察然后逐步減少到512、256、128。每減一次截一張圖對(duì)比直到出現(xiàn)肉眼可感知的“變空”為止再往回上調(diào)一個(gè)檔位。這種做法的好處是數(shù)字不是拍腦袋出來的而是根據(jù)實(shí)際畫面面積和視覺需求推導(dǎo)的。2.2 模塊樹的減法藝術(shù)Niagara發(fā)射器的模塊樹就像一頓自助餐問題是自助餐里絕大部分菜品都不該拿。我搭建輕量發(fā)射器時(shí)默認(rèn)只保留四類模塊第一類是生成控制Spawn Rate和Spawn Burst Instantaneous按效果節(jié)奏選擇一個(gè)第二類是生命周期Lifetime和Kill Particles控制粒子存活時(shí)長(zhǎng)和回收第三類是基礎(chǔ)動(dòng)態(tài)Scale Sprite Size、Color Over Life、Velocity From Point這三樣可以覆蓋大多數(shù)效果第四類是簡(jiǎn)單噪聲比如Curl Noise Force用于做煙霧的擾動(dòng)感但要控制強(qiáng)度參數(shù)避免過度計(jì)算。其他模塊比如Collision、Drag、Gravity Force、Radial Force、Point Attractor、Fluid Simulation默認(rèn)全部移除。需要的時(shí)候再加但加之前必須想清楚這項(xiàng)計(jì)算帶來的視覺收益是否值得每一幀的額外開銷。以Collision為例在500個(gè)粒子的火花效果中開啟場(chǎng)景碰撞單幀物理查詢開銷可以輕易超過粒子本身渲染的耗時(shí)而便宜的做法是把火花落地后直接滅掉或者用一個(gè)簡(jiǎn)單的反射平面模擬視覺差異很小。2.3 數(shù)據(jù)流少算永遠(yuǎn)比快算更劃算Niagara有兩個(gè)執(zhí)行模型CPU和GPU。CPU粒子靈活可以在每個(gè)粒子級(jí)別跑各種邏輯GPU粒子則把每粒子的更新全部放到渲染線程的Compute階段。大方向上GPU更適合大量粒子CPU適合邏輯復(fù)雜但數(shù)量少的場(chǎng)景。但輕量發(fā)射器有個(gè)容易被忽視的點(diǎn)數(shù)據(jù)流的復(fù)雜度比執(zhí)行端的選擇更關(guān)鍵。無論CPU還是GPU粒子更新時(shí)訪問的內(nèi)存、執(zhí)行的指令、寄存器的占用都直接影響吞吐。Niagara里有一個(gè)概念叫Particle Attribute的“活躍集”你用到的屬性越少單粒子更新的開銷越低。所以我在做輕量發(fā)射器時(shí)會(huì)刻意避免往粒子上掛一堆自定義屬性。比如做火花時(shí)某個(gè)版本里掛了SparkSeed、BranchDir、TwinkleSpeed、TrailLength等六個(gè)自定義屬性實(shí)際有用的只有BranchDir一個(gè)。刪掉其他五個(gè)之后粒子更新代碼的寄存器占用和內(nèi)存帶寬立刻降了一個(gè)檔次幀耗時(shí)減少了大概兩成。這件事在很多教程里都不會(huì)提但卻是輕量化最立竿見影的操作之一。3. 手把手搭一個(gè)輕量級(jí)發(fā)射器3.1 創(chuàng)建發(fā)射器與基礎(chǔ)屬性設(shè)置打開Niagara系統(tǒng)編輯器新建一個(gè)空的Niagara Emitter然后從資產(chǎn)層面先做兩個(gè)基礎(chǔ)設(shè)置。第一個(gè)是Local Space。默認(rèn)發(fā)射器的粒子位置是世界空間效果跟隨場(chǎng)景移動(dòng)。對(duì)一個(gè)獨(dú)立的一次性效果這沒問題但如果是長(zhǎng)時(shí)間存活、掛在某個(gè)移動(dòng)物體上的余燼效果世界空間的粒子會(huì)出現(xiàn)在相機(jī)相對(duì)運(yùn)動(dòng)時(shí)的“拖尾”感。輕量發(fā)射器我大多數(shù)時(shí)候開啟Local Space讓粒子的坐標(biāo)空間跟隨組件減少世界坐標(biāo)變換和判斷的開銷。需要注意開啟Local Space之后粒子受世界場(chǎng)景中靜態(tài)物體遮擋裁剪的準(zhǔn)確性會(huì)下降這需要根據(jù)效果實(shí)際放置位置去權(quán)衡。第二個(gè)是Fixed Bounds。給發(fā)射器手動(dòng)指定一個(gè)包圍盒而不是讓引擎自動(dòng)計(jì)算動(dòng)態(tài)邊界。動(dòng)態(tài)邊界意味著每幀都要重新評(píng)估所有粒子的范圍這會(huì)帶來額外的CPU開銷。尤其對(duì)粒子壽命較長(zhǎng)、飄動(dòng)范圍不確定的效果Fixed Bounds能穩(wěn)定裁剪效率。代價(jià)是如果包圍盒設(shè)置太小粒子會(huì)提前被裁剪掉出現(xiàn)“憑空消失”的情況所以盒子稍微放大一點(diǎn)寧可多繪一兩個(gè)空范圍幀。3.2 CPU還是GPU輕量發(fā)射器的分水嶺我自己的經(jīng)驗(yàn)法則是粒子數(shù)少于512且需要復(fù)雜物理交互時(shí)用CPU粒子數(shù)在512到4096之間且效果是大范圍連續(xù)煙霧、水花、星塵時(shí)用GPU。但GPU粒子有幾個(gè)輕量化陷阱。最典型的是Global Sim Stage與場(chǎng)景交互會(huì)產(chǎn)生大量中間緩沖比如把粒子位置寫入紋理再讀回來做碰撞檢測(cè)這套數(shù)據(jù)流比普通的位置更新貴得多。輕量發(fā)射器不要開場(chǎng)景交互寧可損失一點(diǎn)點(diǎn)“真實(shí)感”用旋轉(zhuǎn)擾動(dòng)和透明度遮罩去模擬互動(dòng)。其次是GPU粒子在移動(dòng)端的兼容性部分早期GPU或驅(qū)動(dòng)不完整的設(shè)備上Compute Shader的運(yùn)行效率遠(yuǎn)低于桌面端這時(shí)候一個(gè)場(chǎng)景里同屏3個(gè)GPU發(fā)射器甚至?xí)峡逭麄€(gè)渲染管線。遇到底層設(shè)備我會(huì)把GPU發(fā)射器降級(jí)為CPU版本或者直接合并成一個(gè)發(fā)射器的多個(gè)Spawn段。如果是CPU粒子另一個(gè)需要留意的點(diǎn)是不規(guī)則批次。Niagara的CPU粒子不是一次性生成全部而是按Spawn Rate逐步生成這可能導(dǎo)致不同生命周期粒子的屬性不一致從而破壞批次一致性。輕量發(fā)射器可以用Spawn Burst Instantaneous來一次性生成全部粒子雖然瞬時(shí)開銷大但整體批次更穩(wěn)定總幀成本反而更低。3.3 渲染通道與半透明排序的優(yōu)化發(fā)射器的另一個(gè)隱形開銷來自半透明排序。輕量發(fā)射器往往在場(chǎng)景里和角色、場(chǎng)景模型穿插半透明物體需要從后往前排粒子的排序結(jié)果每幀都在變。當(dāng)一個(gè)場(chǎng)景里掛著十來個(gè)半透明發(fā)射器時(shí)排序本身的CPU成本會(huì)上來還容易因?yàn)榕判蝈e(cuò)誤出現(xiàn)閃爍。我的處理方式分兩步。第一步把相互之間不會(huì)遮擋的粒子效果盡量合并到一個(gè)發(fā)射器里用不同的Emitter Section或Attribute取值來差異化顏色和大小這樣可以減少排序元素的個(gè)數(shù)。第二步對(duì)不需要逐粒子深度排序的發(fā)射器比如屏幕上的小光點(diǎn)、遠(yuǎn)處的塵埃關(guān)閉透明排序的逐粒子深度測(cè)試或者使用Distance Field渲染器讓遮擋關(guān)系由深度緩沖近似決定。實(shí)測(cè)下來單個(gè)發(fā)射器內(nèi)逐粒子深度測(cè)試的開銷能省掉一大截。材質(zhì)方面我做輕量發(fā)射器時(shí)會(huì)把混合模式從Translucent換成Additive。Additive混合本身不會(huì)增加透明度計(jì)算和排序復(fù)雜度視覺上對(duì)亮度型特效火花、光粒、火焰內(nèi)芯也天然合適。如果是灰黑的煙霧類效果Additive會(huì)顯得發(fā)灰這時(shí)候我會(huì)保持Translucent但會(huì)把材質(zhì)里的不透明度計(jì)算簡(jiǎn)化成單張紋理采樣乘以一個(gè)恒定Alpha去掉所有動(dòng)態(tài)亮度映射和漸變計(jì)算。3.4 LOD與距離裁剪輕量發(fā)射器必須在引擎層面加上距離級(jí)別的降級(jí)策略。Niagara系統(tǒng)支持在細(xì)節(jié)面板設(shè)置LOD條件可以根據(jù)距離切換不同的粒子生成策略。我的習(xí)慣是設(shè)置三個(gè)距離檔位最近距離10米內(nèi)完整粒子數(shù)量帶噪聲擾動(dòng)和復(fù)雜材質(zhì)中等距離10到30米粒子數(shù)降低到40%關(guān)閉噪聲模塊材質(zhì)切換為簡(jiǎn)化版本遠(yuǎn)距離30米以上只保留發(fā)射器本身粒子數(shù)降低到20%渲染器指向一個(gè)全屏四邊形貼花式方案或者干脆禁用渲染器只保留場(chǎng)景中的定向光模擬光效。一個(gè)技巧是LOD的切換條件不要只看距離還要結(jié)合縮放值。Niagara系統(tǒng)的LOD條件是支持組合規(guī)則的比如“距離大于30米或縮放小于0.3”就切換到最簡(jiǎn)檔。因?yàn)楹芏嗵匦歉郊釉谛⌒臀矬w上的物體本身縮小的時(shí)候粒子再精細(xì)也看不見不如提前省下開銷。4. 常見瓶頸與排查實(shí)錄4.1 低端機(jī)掉幀的排查清單我排查Niagara性能問題時(shí)不會(huì)直接去看耗時(shí)的數(shù)字而是按影響面從大到小逐層篩選。第一步看的就是材質(zhì)。用引擎自帶的性能分析器把渲染線程耗時(shí)里的Shader耗時(shí)單獨(dú)拉出來如果某個(gè)發(fā)射器材質(zhì)的像素耗費(fèi)排名靠前優(yōu)先替換材質(zhì)哪怕只是把一張法線貼圖去掉可能就解決了大半問題。第二步看半透明數(shù)量。統(tǒng)計(jì)場(chǎng)景里同屏的半透明發(fā)射器個(gè)數(shù)如果超過15個(gè)先合并再談別的。第三步看粒子Sim耗時(shí)如果CPU粒子Sim很高檢查是否開啟了Collision和Drag這兩個(gè)是CPU粒子最常見的“重量源”。最后才看粒子絕對(duì)數(shù)量因?yàn)楹芏嗳艘话l(fā)現(xiàn)卡就狂減粒子數(shù)減到畫面空得沒法看實(shí)際問題出在別處。真實(shí)項(xiàng)目里我遇到過這樣一種情況某個(gè)火花效果只有256個(gè)粒子但幀耗時(shí)將近3ms。查下來既不是材質(zhì)也不是排序而是這個(gè)發(fā)射器開啟了“持續(xù)重新初始化粒子”選項(xiàng)導(dǎo)致每幀都對(duì)全部粒子重新執(zhí)行初始化邏輯和重新生成一遍幾乎沒有差別。關(guān)閉這個(gè)隱藏選項(xiàng)后耗時(shí)直接降到0.2ms。這類問題在排查順序里是最容易被忽略的遇到莫名其妙的高耗時(shí)一定要把發(fā)射器每個(gè)屬性面板都翻一遍。4.2 峰值內(nèi)存與Pool陷阱Niagara系統(tǒng)默認(rèn)有Pool機(jī)制發(fā)射器結(jié)束時(shí)粒子會(huì)被回收進(jìn)內(nèi)存池而不是立即銷毀。這本意是減少頻繁分配的開銷但實(shí)際項(xiàng)目中很容易踩坑如果發(fā)射器配置里勾選了“Persistent ID”之類的ID保留選項(xiàng)回收池里的粒子ID不會(huì)釋放長(zhǎng)時(shí)間運(yùn)行會(huì)持續(xù)占內(nèi)存另外池子里的粒子如果攜帶大量自定義屬性內(nèi)存占用也會(huì)成倍上漲。排查時(shí)我會(huì)先看內(nèi)存預(yù)算。打開分析器的內(nèi)存分部找到Niagara Pool的占用值如果它比場(chǎng)景里所有可見發(fā)射器的粒子內(nèi)存總和還高好幾倍就說明池子里堆積了大量不活躍的粒子資產(chǎn)。解決方式也很簡(jiǎn)單在發(fā)射器的“Memory Pool”選項(xiàng)里指定Pool資源給不同的效果分池對(duì)一次性特效關(guān)閉Pooling用完即棄。分池的另一個(gè)好處是同類效果復(fù)用同一個(gè)Pool的分配策略不會(huì)頻繁和操作系統(tǒng)要內(nèi)存卡頓感會(huì)明顯降低。血淚教訓(xùn)來自一個(gè)里程碑版本某正式演示場(chǎng)景開場(chǎng)連續(xù)觸發(fā)三十多次爆炸特效每個(gè)特效都在自己的發(fā)射器里新建Pool內(nèi)存峰值比預(yù)期高了三倍直接觸發(fā)手機(jī)端內(nèi)存回收。后來統(tǒng)一用一個(gè)“ExplosionPool”資源承接所有爆炸發(fā)射器才把內(nèi)存壓回正常區(qū)間。4.3 材質(zhì)Shader復(fù)雜度過高材質(zhì)這塊我要單獨(dú)強(qiáng)調(diào)因?yàn)樗禽p量發(fā)射器最容易翻車的地方。一次特效優(yōu)化項(xiàng)目里粒子數(shù)從1500砍到300幀率反而更低了。分析下來那些粒子的材質(zhì)Pixel Shader里有五層噪聲計(jì)算和三種貼圖的多次采樣GPU的單位像素計(jì)算開銷極高粒子減到300以后屏幕上每個(gè)像素的覆蓋還是那么高開銷大頭一點(diǎn)沒變。輕量發(fā)射器我推薦一個(gè)“三采樣”上限材質(zhì)最多包含一張主貼圖的采樣、一張可選遮罩貼圖的采樣、以及最多一次數(shù)學(xué)運(yùn)算比如Lerp或者Saturate。如果需要更復(fù)雜的漸變效果寧可預(yù)烘焙到貼圖里也不要在Shader里動(dòng)態(tài)算。還有一個(gè)容易被忽視的點(diǎn)是Sprite渲染器的Facing Mode。默認(rèn)是面向攝像機(jī)這對(duì)小粒子沒什么問題。但對(duì)于薄片型煙霧改成Velocity Facing或者Custom Facing能讓粒子在運(yùn)動(dòng)方向上拉出更自然的形態(tài)同時(shí)減少一張法線貼圖的依賴。視覺收益和性能收益是雙份的。4.4 半透明重疊與Overdraw隱患輕量發(fā)射器做到中后期剩下的最大開銷往往是Overdraw。大量粒子堆疊在同一屏幕區(qū)域時(shí)每個(gè)像素會(huì)被半透明混合多次GPU的幀緩沖寫入帶寬成為瓶頸。這個(gè)問題不是簡(jiǎn)化材質(zhì)能解決的因?yàn)榛旌洗螖?shù)沒有變化。應(yīng)對(duì)方式主要有三種。第一種是主動(dòng)減少粒子間的空間重疊。用Niagara的Initial Location和Velocity方向設(shè)計(jì)把粒子的分布做得更散避免所有粒子在出生幀就擠成一團(tuán)。第二種是為半透明材質(zhì)開啟“渲染距離限制”超過一定距離后轉(zhuǎn)為純不透明渲染減少遠(yuǎn)距離重疊次數(shù)。第三種是對(duì)移動(dòng)平臺(tái)特供版本做特殊處理把半透明粒子的最大重疊層數(shù)鎖死在4層以內(nèi)超過的粒子直接靜態(tài)化或降透明度為零。我做過一個(gè)瀑布飛沫效果初始方案里飛沫粒子全部集中在垂直水柱下方Overdraw爆表。后來我把粒子出生Y軸的隨機(jī)范圍拉寬同時(shí)讓偏外側(cè)的粒子速度略快、透明度略低視覺上水花更自然Overdraw直接減少了一半。5. 實(shí)測(cè)對(duì)比與個(gè)人經(jīng)驗(yàn)5.1 一套完整的優(yōu)化前后數(shù)據(jù)這里放一組我在某個(gè)模擬項(xiàng)目X中實(shí)際得到的對(duì)比數(shù)據(jù)環(huán)境是某中端移動(dòng)設(shè)備場(chǎng)景內(nèi)容三個(gè)同屏發(fā)射器分別模擬火花、煙霧尾跡和遠(yuǎn)處塵埃。優(yōu)化前版本全部采用默認(rèn)發(fā)射器模板粒子總數(shù)約4096材質(zhì)含噪聲紋理。測(cè)量維度優(yōu)化前優(yōu)化后優(yōu)化項(xiàng)粒子總數(shù)40961024削減數(shù)量并分散分布發(fā)射器數(shù)量3個(gè)獨(dú)立系統(tǒng)1個(gè)系統(tǒng)3個(gè)發(fā)射器合并共享Pool合并排序和Pool分配半透明材質(zhì)采樣數(shù)5次2次預(yù)烘焙噪聲貼圖替代動(dòng)態(tài)計(jì)算碰撞模塊3個(gè)發(fā)射器全開全部關(guān)閉用速度衰減透明度滅活模擬落地幀耗時(shí)中位3.8ms0.6ms幀耗時(shí)最差7.2ms1.1ms80秒持續(xù)運(yùn)行內(nèi)存峰值不足但存在Pool堆積分池后穩(wěn)定內(nèi)存增長(zhǎng)趨勢(shì)消除這些數(shù)據(jù)不一定適用于所有項(xiàng)目但它能反映一個(gè)趨勢(shì)輕量化發(fā)射器的收益不是單點(diǎn)削減而是模塊、渲染、內(nèi)存、排序幾個(gè)維度疊加后的結(jié)果。單獨(dú)把粒子數(shù)減少一半幀耗時(shí)可能只下降20%但配合其他策略組合操作收益就非常明顯。5.2 輕量化過程中的幾個(gè)“反直覺”經(jīng)驗(yàn)第一粒子數(shù)越少材質(zhì)越重要。輕量方案的觀感上限不由粒子數(shù)量決定而由材質(zhì)和漸變?cè)O(shè)計(jì)的精細(xì)度決定。同樣500個(gè)粒子一張漸變?nèi)岷?、帶有?dòng)態(tài)微噪的貼圖效果可以超過2000個(gè)粒子加復(fù)雜數(shù)值運(yùn)算的版本。第二合成發(fā)射器比拆分發(fā)射器更省。很多人習(xí)慣一個(gè)特效一個(gè)發(fā)射器結(jié)果同屏出現(xiàn)很多半透明物體排序和DrawCall都在膨脹。在Niagara里一個(gè)System里可以塞多個(gè)Emitter把同場(chǎng)景、同材質(zhì)族的粒子效果合并進(jìn)去DrawCall和排序成本都會(huì)下降。第三關(guān)于“開關(guān)”的學(xué)問。如果發(fā)射器不用了直接禁用渲染器而不是把Spawn Rate設(shè)為0。禁用渲染器可以徹底跳過渲染管線的相關(guān)節(jié)點(diǎn)而Spawn Rate設(shè)為0時(shí)發(fā)射器還會(huì)繼續(xù)Tick很多模塊仍會(huì)在后臺(tái)空轉(zhuǎn)??此剖切〖?xì)節(jié)在數(shù)量眾多的后臺(tái)特效里能省掉不少固定開銷。第四移動(dòng)端Vulkan和部分圖形API下半透明粒子的混合順序和桌面端不同爆發(fā)特效的視覺表現(xiàn)會(huì)有差異。在優(yōu)化時(shí)要注意別只盯著桌面端調(diào)參數(shù)每隔一段時(shí)間切到移動(dòng)設(shè)備實(shí)際看一眼不然你“優(yōu)化完美”的效果在目標(biāo)設(shè)備上可能會(huì)變得一團(tuán)暗或偏色。5.3 后續(xù)擴(kuò)展方向輕量發(fā)射器這套方法論后續(xù)可以往兩個(gè)方向延伸。一個(gè)方向是數(shù)據(jù)化驅(qū)動(dòng)把粒子參數(shù)配置導(dǎo)成表格或數(shù)據(jù)資產(chǎn)由策劃或外部工具統(tǒng)一調(diào)整減少每次手調(diào)發(fā)射器的工作量。另一個(gè)方向是GPU輕量管線的深度調(diào)優(yōu)比如用紋理烘焙方式預(yù)計(jì)算粒子軌跡在運(yùn)行時(shí)只做插值讀取這樣可以把粒子更新的CPU開銷進(jìn)一步降低。這兩個(gè)方向我都已經(jīng)在新的模擬項(xiàng)目X里做過驗(yàn)證。數(shù)據(jù)化驅(qū)動(dòng)對(duì)迭代效率的提升非常明顯而GPU預(yù)計(jì)算軌跡則適合一些固定形態(tài)的火焰和能量類效果。如果你也在優(yōu)化Niagara粒子可以先從本文的模塊減法開始一步步壓掉不必要的計(jì)算再逐步搭建起自己的輕量發(fā)射器模板庫后面再遇到新效果基本就是套模板的活了。說到底輕量發(fā)射器不是把一個(gè)效果變得“簡(jiǎn)陋”而是讓每一分性能預(yù)算都花在視覺價(jià)值最高的地方。