戰(zhàn):從粒子系統(tǒng)到屏幕氛圍的全流程解析)
做天氣系統(tǒng)是我在游戲開發(fā)里最喜歡碰的一類需求尤其是下雨天。它不像戰(zhàn)斗系統(tǒng)那樣邏輯復(fù)雜也不像UI那樣瑣碎但一個(gè)高質(zhì)量的下雨效果能讓整個(gè)場景的質(zhì)感瞬間上一個(gè)臺(tái)階。這篇文章就完整記錄一下我在Laya引擎里落地“下雨環(huán)境效果”的全過程從方案選型、粒子參數(shù)調(diào)試、地面交互表現(xiàn)到真機(jī)性能優(yōu)化以及我踩過的那些文檔里絕對(duì)不會(huì)寫的坑。先說我做這個(gè)需求的初衷那是一個(gè)俯視角2.5D項(xiàng)目場景本身偏寫實(shí)需要一個(gè)讓玩家一眼就能感受到“天氣變了”的氛圍層。最開始我的第一反應(yīng)是偷懶直接找兩張雨絲貼圖做UV滾動(dòng)疊加效果出來之后被美術(shù)一頓吐槽——雨是“貼在屏幕上”的跟場景完全沒有交互感人物走過去褲腿都不帶濕的地面濺不起來水花整個(gè)畫面像是放了一段加了濾鏡的視頻。所以老老實(shí)實(shí)重新做用粒子系統(tǒng)配合屏幕Shader和場景聯(lián)動(dòng)才拿到了最終這版效果。這篇文章不是教你復(fù)制一個(gè)萬能下雨腳本而是把我在Laya里做這套效果時(shí)所有關(guān)鍵節(jié)點(diǎn)怎么想、怎么選、怎么調(diào)、怎么救回來的全過程寫出來。內(nèi)容比較適合已經(jīng)會(huì)用Laya做基礎(chǔ)場景、準(zhǔn)備往更高一級(jí)的技術(shù)美術(shù)方向走的開發(fā)者閱讀新手也可以跳著看參數(shù)表和排查清單那兩節(jié)可以直接抄作業(yè)。1. 整體設(shè)計(jì)思路雨不是“畫”上去的是“演”出來的首先要想清楚一個(gè)問題生活中真實(shí)的雨幕到底由哪幾層視覺信息構(gòu)成的很多人做下雨效果失敗就是只抓住了“雨絲”這個(gè)單一元素剩下的全丟掉了。我的拆解方式是四層疊加遠(yuǎn)景雨幕層、近景動(dòng)態(tài)粒子層、地面交互層、屏幕氛圍層。遠(yuǎn)景雨幕是那種半透明的斜線幕布負(fù)責(zé)在視覺上鋪開“整個(gè)場景都在下雨”的空間感近景粒子是玩家視野內(nèi)能看清的雨滴軌跡負(fù)責(zé)運(yùn)動(dòng)和速度感地面交互層是雨落地后的水花濺射、漣漪擴(kuò)散負(fù)責(zé)讓場景“活”起來屏幕氛圍層是鏡頭上的雨滴劃痕和整體偏冷的色調(diào)混合負(fù)責(zé)情緒的收口。這四層缺一不可。只做雨絲沒有地面反應(yīng)雨就像鬼魂在下只做地面反應(yīng)沒有天空幕布場景就會(huì)顯得干癟。這個(gè)分層思路是后面所有技術(shù)實(shí)現(xiàn)的總綱。再補(bǔ)一個(gè)比較重要的原則這套效果全部跑在客戶端本地不需要服務(wù)器同步因?yàn)樘鞖鈱?duì)所有玩家是一致的是純表現(xiàn)層的東西。所以開發(fā)時(shí)自由度很大但也意味著性能壓力全在自己這邊粒子數(shù)量、紋理尺寸、Shader復(fù)雜度都要自己扛。1.1 為什么用Laya自帶粒子系統(tǒng)而不是純Shader這是我被問得最多的問題。確實(shí)網(wǎng)上有大把用Shader做全屏雨效的教程思路也很清晰屏幕空間射線計(jì)算雨滴的透視軌跡、按深度夾取場景遮擋關(guān)系效果上限很高。但我的項(xiàng)目是一個(gè)大型多人在線游戲角色、場景、特效同屏壓力本來就大全屏后處理Shader需要逐像素計(jì)算在高端機(jī)上是毛毛雨但在中低端安卓機(jī)上會(huì)直接拖進(jìn)fps泥潭。所以我選了“粒子為主、Shader為輔”的混合方案所有雨滴的移動(dòng)、分布、生命周期交給粒子系統(tǒng)這是Laya最成熟的模塊異步加載、合批、碰撞都有現(xiàn)成能力和坑可踩Shader只做兩件輕量的事——屏幕邊緣的雨滴拖尾劃痕和地面的漫反射濕潤增強(qiáng)而且都用極簡實(shí)現(xiàn)。對(duì)比下來這套方案的上限也許沒有純GPU方案那么“電影級(jí)”但勝在可控、穩(wěn)定、跨設(shè)備一致性好。尤其當(dāng)你面對(duì)的是安卓千元機(jī)這種下限很低的平臺(tái)時(shí)穩(wěn)定比上限重要得多。1.2 場景聯(lián)動(dòng)不只是視覺還有聽感和交互雨的效果除了眼睛能看到耳朵也應(yīng)該收到信息。這一步是很多團(tuán)隊(duì)容易忽略的配了雨聲卻只做了一段循環(huán)音頻下大雨和毛毛雨的音量、音色完全沒區(qū)分場景里的物件和角色也不做任何反應(yīng)。我的做法是做了三檔天氣強(qiáng)度小雨、中雨、暴雨。每檔對(duì)應(yīng)不同的粒子發(fā)射速率、雨聲循環(huán)切換、音量Lerp過渡時(shí)間。在代碼里維護(hù)一個(gè)WeatherState的枚舉Notify給粒子控制器和音頻管理器用3秒的淡入淡出做切換避免瞬切導(dǎo)致的聽覺突兀。同時(shí)場景里的非角色元素也要給反應(yīng)火把加一個(gè)受潮概率熄火、水面加一個(gè)漣漪粒子發(fā)射器、角色身上的武器加一個(gè)濕反光參數(shù)。這些工作量不大但玩家體驗(yàn)到的“真實(shí)感”是靠這些細(xì)節(jié)堆起來的。1.3 雙實(shí)現(xiàn)路徑2D粒子還是3D粒子Laya引擎里粒子系統(tǒng)分2D和3D兩套。2D粒子適合做純屏幕空間的平面效果比如UI特效、技能拖尾3D粒子是真正的世界空間粒子可以掛在場景節(jié)點(diǎn)上隨攝像機(jī)移動(dòng)、有真實(shí)的深度關(guān)系、能和場景模型發(fā)生遮擋。我這個(gè)項(xiàng)目是俯視角2.5D物理空間是3D的視角是2D化的。所以雨滴必須用3D粒子系統(tǒng)這樣才能保證遠(yuǎn)處的雨和近處的雨透視關(guān)系正確。如果強(qiáng)行用2D粒子貼在屏幕上一旦攝像機(jī)開始推進(jìn)或橫移雨絲就會(huì)像貼紙一樣暴露穿幫。補(bǔ)充一個(gè)小知識(shí)Laya的3D粒子和2D粒子在編輯器里的操作邏輯差別非常大3D粒子的Transform是骨骼動(dòng)畫驅(qū)動(dòng)所有發(fā)射器參數(shù)都在LayaParticle3D組件里。如果你之前只碰過2D粒子第一次打開3D粒子面板會(huì)有勸退感參數(shù)多出一個(gè)數(shù)量級(jí)。但別怕真正核心的參數(shù)就那么幾個(gè)后面我會(huì)挨個(gè)拆。2. 雨絲粒子系統(tǒng)的核心參數(shù)解讀粒子系統(tǒng)是這個(gè)效果的絕對(duì)主力參數(shù)多如牛毛但真正決定“像不像下雨”的只有幾組。我按重要性排了個(gè)序新手從第一條開始改就行不要一上來就滿面板亂調(diào)。2.1 發(fā)射器形態(tài)為什么用矩形發(fā)射器而不是錐形Laya的3D粒子發(fā)射器支持球形、錐形、矩形等形狀。做雨的時(shí)候最自然的直覺是選錐形發(fā)射器從天空的一個(gè)區(qū)域往下噴。但實(shí)際跑起來你會(huì)發(fā)現(xiàn)錐形發(fā)射器的初始速度方向是從錐尖向外發(fā)散的降落到地面時(shí)雨滴的落點(diǎn)會(huì)散成一個(gè)圓形雨絲之間互相穿插、密度不均勻看起來像下“冒煙”而不是下雨。正確的做法是矩形發(fā)射器發(fā)射器的長寬覆蓋住玩家的視野范圍發(fā)射方向垂直朝下粒子初速度只在Y軸給一個(gè)固定負(fù)值X和Z的初速度給一個(gè)很小的隨機(jī)抖動(dòng)。這樣所有雨滴都是平行下落的密度均勻、方向統(tǒng)一視覺上才干凈。我踩過一次大坑用錐形發(fā)射器做了個(gè)看起來還行的小區(qū)域雨效但把攝像機(jī)拉遠(yuǎn)后發(fā)現(xiàn)雨的范圍遠(yuǎn)不夠鋪滿視野臨時(shí)改了發(fā)射器尺寸結(jié)果粒子的世界坐標(biāo)錯(cuò)亂雨滴從地面往天上飛。最后是把整個(gè)發(fā)射器參數(shù)重置重調(diào)的花了一個(gè)晚上。2.2 發(fā)射速率、生命周期和初速度的黃金組合這三個(gè)參數(shù)決定了雨的“密度”和“速度感”它們是聯(lián)動(dòng)關(guān)系的。發(fā)射速率決定單位時(shí)間生成多少粒子生命周期決定粒子從出生到消失存活多久初速度決定雨滴下落多快。實(shí)際操作上我是這樣定參數(shù)的先定生命周期因?yàn)橛甑螐陌l(fā)射到落地的時(shí)間決定了可見的雨絲長度。攝像機(jī)俯視角下視野高度大概20米雨滴下落速度我取35米/秒那么生命周期就是 20 ÷ 35 ≈ 0.57秒。這個(gè)值太小雨絲會(huì)短成雨點(diǎn)太大會(huì)讓雨絲穿越地面。初速度設(shè)成Y -30到-40的區(qū)間X和Z給±1.5的抖動(dòng)。發(fā)射速率調(diào)起來更像調(diào)音臺(tái)密度不夠畫面空密度過頭全是糊掉的線。我做的時(shí)候是錄屏慢放看每一幀的雨絲數(shù)量中雨檔我調(diào)到每秒900個(gè)粒子。這個(gè)數(shù)字看著大但3D粒子單粒子成本很低而且可以依賴粒子系統(tǒng)的合批能力900個(gè)粒子并不會(huì)壓垮CPU前提是你別同時(shí)開一大堆別的粒子特效。2.3 紋理制作雨滴貼圖的自繪與資源避坑雨絲貼圖看起來簡單實(shí)際翻車率特別高。從網(wǎng)上下載的免費(fèi)雨滴貼圖大多帶著黑色背景或者壓縮紋理的白色噪點(diǎn)直接導(dǎo)入Laya后粒子周圍全是黑色方塊效果慘不忍睹。我強(qiáng)烈建議自己畫一張雨滴貼圖真的只需要一分鐘新建一個(gè)64×256的畫布用漸變工具拉一條白色斜線中間亮度高、邊緣完全透明保存為TGA或PNG帶透明通道導(dǎo)入時(shí)把紋理類型設(shè)成Alpha貼圖Wrap Mode設(shè)Clamp。把粒子渲染的混合模式設(shè)成Additive加色混合雨絲就會(huì)有一種發(fā)光的通透感比Normal混合和背景生硬疊加自然得多。如果實(shí)在要用下載的資源那必須確認(rèn)三件事圖片帶不帶走Alpha通道JPG直接pass、尺寸是不是2的N次冪、壓縮格式在目標(biāo)機(jī)型的兼容性。很多“l(fā)aya模型下載”類的資源包是直接從Unity或U3D項(xiàng)目里扒出來的紋理格式不一定能在Laya Runtime里正常解壓這問題查起來非常隱蔽不是畫面問題是資源加載時(shí)直接報(bào)內(nèi)存錯(cuò)誤。3. 地面交互雨滴落地的“最后一厘米”如果說雨絲粒子是畫面的骨架地面交互就是讓效果從“不錯(cuò)”到“驚艷”的分水嶺。玩家根本不會(huì)盯著空中的雨看太久他們的視線焦點(diǎn)永遠(yuǎn)是角色周圍一米的位置而那里最搶眼的就是地面濺射。3.1 濺射粒子的實(shí)現(xiàn)與生命周期策略地面濺射等于第二套粒子系統(tǒng)而且參數(shù)邏輯和雨絲完全不同。濺射粒子的發(fā)射點(diǎn)應(yīng)該落在雨絲粒子死亡的位置附近但粒子系統(tǒng)之間沒法直接傳遞事件坐標(biāo)所以我用了一個(gè)比較樸素的方案在主雨粒子的腳本Update里做碰撞檢測一旦檢測到地面接觸就在接觸點(diǎn)生成一個(gè)濺射粒子的Play操作。濺射粒子的參數(shù)組初速度向上給5~8水平方向隨機(jī)生命周期0.2~0.4秒粒子Size從0.3衰減到0.05顏色從半透明白漸變成完全透明。數(shù)量上不需要和雨絲一一對(duì)應(yīng)每3~5根雨絲觸發(fā)一次濺射就夠既能保持密度又不至于讓粒子數(shù)翻倍。這里有個(gè)小心得濺射粒子不要只做垂直向上的小水珠我疊加了一層貼地的環(huán)形漣漪貼圖粒子速度更慢、生命周期更長模擬雨水在地面擴(kuò)散的濕潤痕跡。兩層疊加之后地面才真的像被雨浸透了。3.2 場景物體的受體反饋怎么讓濺射出現(xiàn)在正確的地方濺射粒子最容易出的問題就是穿模和下穿粒子發(fā)射出來直接嵌進(jìn)地面模型里或者在樓梯、臺(tái)階這種高低落差位置從側(cè)面穿出去。Laya的粒子系統(tǒng)支持Collision模塊但全場景物理碰撞開銷太大不能真打物理引擎。我的折中做法場景中所有能落雨交互的地面統(tǒng)一掛一個(gè)帶Collider的透明體積節(jié)點(diǎn)Collider類型用盒體或網(wǎng)格碰撞體Trigger檢測打開。粒子檢測到碰撞后只做視覺觸發(fā)不移除粒子而是將粒子速度重置一個(gè)向上分量。階梯和坡道這種特殊位置額外放幾個(gè)小體積碰撞節(jié)點(diǎn)微調(diào)效果。這一套跑下來的效果雨滴落在石板路和落在草地上的反應(yīng)其實(shí)是一樣的說實(shí)話和現(xiàn)實(shí)差異挺大。更好的方案是給地面材質(zhì)設(shè)置一個(gè)“濕潤度”全局Shader參數(shù)不同材質(zhì)對(duì)濕潤度的響應(yīng)曲線不同石板更反光、草地更啞光。這個(gè)屬于后期打磨如果你的主力Shader可控強(qiáng)烈建議加上視覺收益非常大。3.3 一套參數(shù)打天下的幻想破滅不同地形各調(diào)各的我最初天真地以為濺射粒子一套參數(shù)通吃所有地形。后來發(fā)現(xiàn)雨滴落在水面上的漣漪效果和落在地面上的濺射效果完全是兩個(gè)物種。水面要求粒子有擴(kuò)散波紋感和一定的反射度地面要求粒子有反彈跳躍感。所以我把濺射單獨(dú)拆成兩套WaterSplashEffect掛在所有水面節(jié)點(diǎn)的中心用同心圓擴(kuò)散紋理GroundSplashEffect掛在地面主節(jié)點(diǎn)上用隨機(jī)方向的短促線形粒子。兩套共用一個(gè)強(qiáng)度控制接口下雨強(qiáng)度變化時(shí)統(tǒng)一調(diào)節(jié)發(fā)射速率。4. 屏幕氛圍與Shader增強(qiáng)雨絲和地面都有了畫面還是差最后一口氣差在鏡頭上。真實(shí)雨天你透過窗戶或鏡頭看出去玻璃上會(huì)有雨滴痕遠(yuǎn)處的景物會(huì)因?yàn)樗幸稽c(diǎn)模糊發(fā)灰。這些氛圍感靠粒子是表現(xiàn)不出來的必須動(dòng)用Shader。4.1 屏幕雨痕Shader輕量實(shí)現(xiàn)與性能取舍玻璃雨痕的常規(guī)范式是屏幕空間UV加雨滴法線紋理擾動(dòng)。聽起來很嚇人其實(shí)實(shí)現(xiàn)很輕取一張帶多個(gè)圓形雨滴的法線貼圖在片元著色器里用時(shí)間偏移做UV滾動(dòng)再疊一層噪聲作為水滴滑落的路徑擾動(dòng)最后用雨滴法線擾動(dòng)屏幕UV采樣主場景即可。在Laya里這個(gè)效果寫成一個(gè)后處理Shader掛到Camera上。Shader整體就十幾行核心代碼G-Buffer都不需要只要采樣原始屏幕顏色加一個(gè)法線貼圖。我實(shí)測在1080P下跑在驍龍660級(jí)別的機(jī)器上幀率影響在3幀以內(nèi)屬于可以接受的范圍。Shader的具體實(shí)現(xiàn)里最容易坑人的是UV滾動(dòng)速度。雨滴在玻璃上滑落是重力驅(qū)動(dòng)的速度應(yīng)該是越往下越快是個(gè)加速過程而不是勻速滾動(dòng)。我剛開始圖省事用勻速結(jié)果雨滴像被勻速拖動(dòng)的抹布非常假。最后用一個(gè)二次函數(shù)做高度對(duì)應(yīng)速度的映射效果一下就自然了。4.2 畫面調(diào)色冷色調(diào)和對(duì)比度的微調(diào)技巧雨天的氛圍除了物理表現(xiàn)很大程度靠調(diào)色。做雨效時(shí)我會(huì)給Camera掛一個(gè)極簡的ColorAdjust組件把色溫往冷藍(lán)方向偏移飽和度降低10~15%對(duì)比度略微降低讓畫面有一種“濕度感”。調(diào)色的數(shù)值不要用固定的要跟著雨強(qiáng)走。暴雨時(shí)色溫偏得更冷、對(duì)比度更低小雨時(shí)只做輕微偏移。這塊建議在代碼里寫一個(gè)基于WeatherState的插值過渡切換時(shí)用Tween補(bǔ)間避免突然跳變讓玩家不適。順帶提一個(gè)細(xì)節(jié)雨天場景的霧效也是氛圍層的一部分。Laya的3D場景支持指數(shù)霧把霧的密度調(diào)高、顏色往灰色偏遠(yuǎn)處場景會(huì)被一層水汽籠罩空間深度感立刻拉出來。但注意別把霧開過猛否則性能扛不住畫面也會(huì)像蒙了一層毛玻璃。4.3 全屏后處理的疊層順序問題后處理類效果之間是有優(yōu)先級(jí)順序的。我項(xiàng)目里順帶還掛了Bloom和色差效果曾經(jīng)把雨痕Shader排到了Bloom之前結(jié)果雨痕被Bloom一糊玻璃上全是光斑完全看不到雨滴形態(tài)了。最后調(diào)整的順序是場景渲染 - 雨痕擾動(dòng) - 霧效混合 - 調(diào)色 - Bloom。這個(gè)順序本身并沒有絕對(duì)標(biāo)準(zhǔn)但建議你把雨痕放在所有“模糊類”效果之前讓雨滴邊緣保持銳利。5. 實(shí)操過程記錄從一個(gè)空?qǐng)鼍暗酵暾掠晷Ч@一節(jié)是復(fù)現(xiàn)向的。如果你跟著我上面的設(shè)計(jì)文檔走下面是我實(shí)測從零搭到能玩的全流程按步驟操作基本能還原我的效果。5.1 環(huán)境準(zhǔn)備與Laya版本說明我用的LayaAir 3.0的穩(wěn)定版本3D模塊和粒子系統(tǒng)都是相對(duì)成熟的。如果你還在用2.x版本粒子參數(shù)面板的命名不太一樣需要對(duì)照著稍微調(diào)整。編輯器導(dǎo)出項(xiàng)目后運(yùn)行在Chrome做預(yù)覽真機(jī)測試用Android端做性能基線。開始前需要準(zhǔn)備資源雨絲紋理一張、濺射水滴紋理一張、漣漪紋理一張、雨滴法線貼圖一張。全部64到256量級(jí)的小圖丟進(jìn)項(xiàng)目的assets/textures/weather目錄。不做圖集因?yàn)檫@些貼圖只被粒子系統(tǒng)和Shader各自引用一次圖集會(huì)增加額外的加載和引用復(fù)雜性。5.2 創(chuàng)建3D粒子雨絲系統(tǒng)的步驟清單在場景中新建一個(gè)3D節(jié)點(diǎn)命名為RainRoot掛上LayaParticle3D組件。發(fā)射器Shape選Rectangle尺寸設(shè)(80, 40, 0)X軸覆蓋視野寬度Y軸作為厚度。StartColor的漸變曲線設(shè)從純白到淺白帶一點(diǎn)透明模擬遠(yuǎn)近距離的雨滴亮度差異。StartSize設(shè)0.03到0.06雨絲細(xì)一點(diǎn)才像雨粗了就是下鐵絲。GravityModifier設(shè)(-2, -9.8, -2)額外施加一點(diǎn)水平風(fēng)力和垂直重力讓雨有自然的斜飄感。Duration設(shè)為InfinityLooping打開。這段配置做完先別急著往下走跑一下看看雨絲密度和方向是不是符合直覺。我第一次就是跳步了結(jié)果后面調(diào)濺射時(shí)才發(fā)現(xiàn)雨壓根不是垂直下的又重新改了發(fā)射器角度。5.3 濺射粒子和腳本控制代碼骨架濺射粒子系統(tǒng)建好后需要掛一個(gè)自定義腳本控制粒子發(fā)射事件。核心代碼是檢測雨絲粒子位置的地面碰撞并觸發(fā)濺射示意如下class RainSplashController extends Script { property({type: Particle3D}) splashParticle: Particle3D; private hitPoints: Vector3[] []; onUpdate(): void { // 遍歷活動(dòng)雨粒子檢測與GroundCollider的碰撞 let activeParticles this.rainSystem.getActiveParticles(); for (let p of activeParticles) { if (p.position.y groundY) { // 觸發(fā)濺射 this.splashParticle.transform.position p.position; this.splashParticle.particleSystem.play(); p.reset(); // 回收雨粒子 } } } }注意你看到的這段是簡化骨架實(shí)際Laya粒子系統(tǒng)的粒子遍歷要基于內(nèi)部的ParticleData數(shù)組做遍歷不能直接for of否則GC壓力會(huì)大。建議用一個(gè)固定上限的粒子池做復(fù)用超過上限時(shí)丟掉最老的粒子而不是繼續(xù)創(chuàng)建。5.4 參數(shù)調(diào)試的實(shí)測經(jīng)驗(yàn)表調(diào)試粒子參數(shù)是個(gè)痛苦且反直覺的過程。我把最終跑通的一組參數(shù)和調(diào)試時(shí)的觀察結(jié)果整理成了一個(gè)速查表方便你對(duì)照著調(diào)參數(shù)我的最終值調(diào)大后果調(diào)小后果發(fā)射速率900/s畫面糊成線團(tuán)雨稀稀疏疏生命周期0.55s雨絲落地穿透雨絲變短初速度Y-35雨像子彈雨在半空漂浮初速度X/Z抖動(dòng)±1.5雨像亂刮風(fēng)雨變成直線粒子Size0.04鐵絲雨灰塵雨段數(shù)/粒子紋理分割3段雨絲割裂看不出是雨這張表不是玄學(xué)每一項(xiàng)背后都有視覺原理。加速度、生命周期和Size共同決定了雨絲在視覺上的“長度”發(fā)射速率和視角范圍共同決定“密度”抖動(dòng)參數(shù)決定“自然度”。你把數(shù)值調(diào)成我的終值效果是穩(wěn)的但不同場景的視野高度和攝像機(jī)距離是需要微調(diào)的。6. 常見問題與排查實(shí)錄這篇特意把排查放在最后因?yàn)橄掠晷Ч{(diào)試時(shí)出的問題千奇百怪每個(gè)都能讓人卡半天。我用最典型的幾個(gè)問題做個(gè)速查表并說說背后的排查思路。6.1 粒子穿透地面和穿墻問題問題描述雨絲和濺射粒子在接近地面或墻體時(shí)直接穿過或者嵌進(jìn)模型一半。排查邏輯先看碰撞是否開啟。Laya粒子碰撞檢測需要CollisionShape有實(shí)際碰撞體參與只掛Trigger不行。再看碰撞體的層級(jí)粒子節(jié)點(diǎn)的Local坐標(biāo)和場景節(jié)點(diǎn)的世界坐標(biāo)不一致時(shí)碰撞檢測的坐標(biāo)轉(zhuǎn)換容易出錯(cuò)。解決方式給地面統(tǒng)一掛碰撞體積粒子碰撞用Shape Query模式而不是物理模擬模式。穿透特別嚴(yán)重的斜坡考慮直接把雨絲粒子生命周期截短到落地點(diǎn)而不是依賴碰撞體攔截。6.2 雨絲閃爍或呈點(diǎn)狀斷續(xù)問題描述雨絲在移動(dòng)的鏡頭下閃爍不定或者明明設(shè)置了長條紋理卻顯示成一個(gè)個(gè)光點(diǎn)。排查邏輯這是貼圖過濾和粒子UV動(dòng)畫設(shè)置的問題。紋理的MinFilter/MagFilter如果設(shè)成了Nearest每幀采樣都會(huì)跳像素雨絲就閃。粒子組的UV Animation如果開了但貼圖沒有按幀分割就會(huì)采樣到空白區(qū)域顯示成點(diǎn)狀。解決方式紋理過濾設(shè)成Bilinear關(guān)掉粒子的UV Animation讓整條紋理始終作為完整雨絲被拉伸。順帶檢查一下粒子系統(tǒng)的RenderMode是不是設(shè)成了StretchedBillboard如果不是粒子永遠(yuǎn)顯示為貼圖原始形狀而不是被拉伸的雨絲。6.3 真機(jī)性能驟降或發(fā)熱明顯問題描述編輯器里跑得飛起一到真機(jī)上就發(fā)熱、掉幀。排查邏輯編輯器預(yù)覽用的是PC性能和真機(jī)差距巨大。先用Laya Profiler看真機(jī)上的粒子Active數(shù)量和DrawCall。粒子數(shù)量超過2000或者DrawCall超過30基本就是性能瓶頸所在。解決方式把粒子發(fā)射速率降下來真機(jī)版本我通常會(huì)降到編輯器的70%濺射粒子和雨絲粒子合并到同一個(gè)紋理圖集以減少DrawCall屏幕雨痕Shader在低端機(jī)上關(guān)閉用一個(gè)靜態(tài)貼圖代替。最后給設(shè)置面板加一個(gè)“極致/標(biāo)準(zhǔn)/流暢”三檔畫質(zhì)選項(xiàng)不同檔位對(duì)應(yīng)不同粒子密度和Shader開關(guān)。6.4 雨聲循環(huán)切換時(shí)的爆音問題描述從小雨切到暴雨音頻切換瞬間有一聲“啪”的爆音。排查邏輯音頻淡入淡出沒有做逐幀漸變直接用AudioSource.Stop()再Play()新的clip波形在相位不連續(xù)處會(huì)生成爆音。解決方式配合WeatherState切換寫一個(gè)音量管理協(xié)程3秒內(nèi)從當(dāng)前音量線性Lerp到目標(biāo)音量期間不切換clip只切換clip前先降低音量到0。或者干脆只用一個(gè)雨聲循環(huán)通過調(diào)整音量和EQ模擬不同強(qiáng)度省去切換clip的麻煩。6.5 粒子系統(tǒng)在場景切換時(shí)的內(nèi)存泄漏問題描述切場景后內(nèi)存不釋放連續(xù)切幾次之后開始卡頓。排查邏輯粒子系統(tǒng)在場景銷毀時(shí)如果沒有主動(dòng)Stop和Clear粒子數(shù)據(jù)數(shù)組會(huì)滯留在內(nèi)存里等待GC而Unity和Laya的GC策略對(duì)托管堆的釋放都不及時(shí)。解決方式在場景卸載事件里手動(dòng)調(diào)用粒子系統(tǒng)的Stop()并設(shè)置Emitter.emit false再把粒子池引用置空。如果項(xiàng)目里經(jīng)常切場景建議做一個(gè)PoolManager統(tǒng)一管理粒子系統(tǒng)的創(chuàng)建和回收而不是每次new一個(gè)新的。7. 我個(gè)人的一個(gè)習(xí)慣性收尾小技巧整篇寫到這里最后分享一個(gè)讓下雨效果更容易出彩的小習(xí)慣給你的雨效加一個(gè)可控的“時(shí)間縮放”參數(shù)。具體做法是把粒子的SimulationSpeed暴露到運(yùn)維后臺(tái)的熱更配置里策劃可以隨時(shí)在后臺(tái)調(diào)快調(diào)慢雨絲下落速度實(shí)時(shí)預(yù)覽效果。我當(dāng)初是為什么加這個(gè)呢因?yàn)橛写蚊佬g(shù)提了個(gè)需求說要雨“更暴躁一點(diǎn)”我只能火速改代碼改參數(shù)重新出包。但加了SimulationSpeed之后美術(shù)自己拖一下滑桿就能找到合適的“暴躁度”完全不用等程序發(fā)版。這個(gè)看似不起眼的自由度實(shí)際上挽救了好幾次本來要通宵改包沖刺的版本。做環(huán)境和天氣效果技術(shù)上真的沒有多少高深的東西比的是誰愿意多花時(shí)間觀察真實(shí)世界誰愿意在參數(shù)堆里多試幾輪誰踩完坑之后愿意把它記下來。希望這篇文章能幫你把已經(jīng)踩過或者即將踩的坑提前填平讓你能把更多時(shí)間花在真正讓畫面變好看的事上。