當(dāng)前位置:首頁 >  科技 >  IT業(yè)界 >  正文

打破開放世界魔咒,中手游《仙劍世界》跨平臺(tái)優(yōu)化技術(shù)分享

 2024-08-14 13:49  來源: 互聯(lián)網(wǎng)   我來投稿 撤稿糾錯(cuò)

  域名預(yù)訂/競價(jià),好“米”不錯(cuò)過

編者注: 近年來,游戲行業(yè)開放世界賽道火熱,但是跨平臺(tái)體驗(yàn)一直是業(yè)界的難題。最近幾款備受期待的開放世界大作移動(dòng)端接連翻車,要么出現(xiàn)跳票延期的情況,令眾多玩家感到失望。

但在前陣子的Unite Shanghai 2024上,來自中手游的仙劍IP首款開放世界RPG《仙劍世界》帶來了開放世界跨平臺(tái)優(yōu)化的技術(shù)分享,在大會(huì)上介紹了許多項(xiàng)目曾經(jīng)走過的彎路,以及對應(yīng)解決的經(jīng)驗(yàn)技巧。

以下是Untiy 中國對《仙劍世界》主創(chuàng)團(tuán)隊(duì)的采訪原文,內(nèi)容干貨十足,值得全文閱讀。

《仙劍世界》作為仙劍 IP 系列的最新?篇?作,從故事和劇情上延續(xù)了仙劍的精髓。在仙劍 33 年的世界觀下,游戲打造出了?個(gè)浪漫唯美的江南全景、磅礴恢弘的蜀?、神秘苗疆等區(qū)域,構(gòu)成?個(gè) 384 平?公?完整的?縫開放?世界。以東?題材為起點(diǎn),以江南的浪漫為開端,以巴蜀的幻想?格作為延續(xù),通過不斷的迭代和內(nèi)容更新,為秈?們奉上?款難以忘懷的仙俠?作。

Unity 中國有幸采訪到了主創(chuàng)團(tuán)隊(duì),并邀請他們參加了 Unite 上海 2024,與開發(fā)者們面對面交流。

可以為我們簡哪個(gè)單介紹下團(tuán)隊(duì)和項(xiàng)?嗎?

?家好,我們是中?游旗下的滿天星?作室,核?成員為原巨??絡(luò)巨??作室原班團(tuán)隊(duì),參與 過《征途》瑞游研發(fā),主導(dǎo)了《巨?》端游,《仙俠世界》系列端游和《?珠最強(qiáng)之戰(zhàn)》?游的研 發(fā)。?前我們正在開發(fā)的《仙劍世界》,是中?游?研?發(fā)的仙劍 IP ?款開放世界 RPG,游戲致?于 在多端平臺(tái)打造?個(gè)萬物有靈的東?浪漫幻想世界。

但在項(xiàng)?研發(fā)早期,由于場景龐?,對視野要求也很?,我們?度糾結(jié)如何能在有限的時(shí)間內(nèi)整 合各類效果好的 feature,管理開銷。所幸有 Unity HDRP 管線,得益于它的特性,最終幫助我們實(shí)現(xiàn)了對游戲世界的暢想,充分展現(xiàn)出東?浪漫幻想世界的魅?。

HDRP 相對于 URP,給《仙劍世界》帶來了什么好處?

URP確實(shí)是一個(gè)非常簡潔靈活的渲染管線,但是當(dāng)我們需要制作一款在PC體驗(yàn)的大世界游戲的時(shí)候,URP就會(huì)有一些稍顯不足的地方。特別是我們當(dāng)時(shí)使用的是Unity 2021,URP在原生支持的feature上略微少一些。反之,HDRP管線則為我們內(nèi)置了大量非常實(shí)用,且效果很好的feature,確實(shí)為我們在項(xiàng)目初期,提供了快速,穩(wěn)定,優(yōu)質(zhì)的畫面效果提升。

Unite大會(huì)上《仙劍世界》 HDRP Feature展示

例如,HDRP下內(nèi)置的SSGI,在我們自己的PRTGI 方案還未落地時(shí),為游戲提供了很好的GI畫面支持。SSS也為角色皮膚提供了非常好的質(zhì)感,讓角色變得更加真實(shí)自然,比項(xiàng)目早期使用預(yù)積分Lut的皮膚SSS方案要更加潤澤和透亮,總體來說更符合我們游戲中國風(fēng)人物的皮膚質(zhì)感。Tile/Cluster的點(diǎn)光解決方案,也讓場景燈光師可以肆意擺放燈光,為副本、夜晚提供很棒的氛圍和質(zhì)感。另外對于實(shí)時(shí)天氣和日月變化,當(dāng)時(shí)HDRP下提供的Volume體系也可以實(shí)現(xiàn)非常炫酷的效果,甚至提供管線的管理和混合效果。又比如,我們劇情導(dǎo)演希望引擎這邊能提供一個(gè)比較高質(zhì)量基于物理的DOF(景深)效果,那HDRP下的DOF就是一個(gè)很好的選擇,它基于物理相機(jī)的整套參數(shù)調(diào)整,可以讓我們的劇情導(dǎo)演非常容易的上手和理解。

HDRP SSAO遮蔽效果展示

在研發(fā)早期,人力相對比較緊張,但又正是項(xiàng)目確立游戲風(fēng)格效果、質(zhì)量體系等標(biāo)準(zhǔn)的時(shí)候,HDRP相比于URP會(huì)更加適合我們,因此我們也非常堅(jiān)定的選擇了HDRP管線作為我們的渲染管線。從最終結(jié)果上看,它也為我們節(jié)約了不少預(yù)研時(shí)間,加快了開發(fā)進(jìn)度。當(dāng)我們想要嘗試某些效果,幾乎只需要在管線設(shè)置上打開相應(yīng)開關(guān),即可看到它帶來的畫面變化,非常的方便。

HDRP PCSS軟陰影效果展示

從 PC 端移植到移動(dòng)端?概花了多久?移植過程中遇到的最?的困難是什么?

在最開始的時(shí)候,項(xiàng)?是基于 URP 管線的,但是由于 PC 端?漸新增的畫?提升需求,我們加?了 HDRP 來作為 PC 端的管線。也就是說這個(gè)時(shí)期,我們確實(shí)是 URP 和 HDRP 同時(shí)運(yùn)?的。

之所以選擇同時(shí)進(jìn)?,是因?yàn)?HDRP 原?不?持移動(dòng)平臺(tái),放眼全球?業(yè),也鮮有其他游戲?qū)?HDRP 進(jìn)?移植的案例。所以我們?開始對它報(bào)以謹(jǐn)慎的態(tài)度,對 HDRP 管線技術(shù)不斷地進(jìn)?學(xué)習(xí)和整合。但是隨著對 HDRP 使?的深?,我們了解了它的各種特性和優(yōu)點(diǎn)之后,出于對引擎維護(hù)和資產(chǎn)流程管理成本的考慮;也因 為我們團(tuán)隊(duì)相對有?較成熟的 PC 和移動(dòng)平臺(tái)的開發(fā)移植經(jīng)驗(yàn),對??的技術(shù)實(shí)?也很有信?。所以經(jīng)過評估之后,我們決定將 HDRP 向移動(dòng)平臺(tái)進(jìn)?移植。?此,我們游戲就只有 HDRP ?套渲染管線了。

Unite大會(huì)上《仙劍世界》 HDRP 跨平臺(tái)優(yōu)化技術(shù)分享

在開始移植之前,我們預(yù)留了約一個(gè)月左右的時(shí)間作為移植的緩沖時(shí)間,以防止遇到難以解決的突發(fā)問題。另外,我們提前評估了所有PC上我們正在使用的,甚至還未使用,但是很可能會(huì)用到的HDRP下所有feature,它們在移動(dòng)端上可能的性能表現(xiàn),用于確定是否能在移動(dòng)平臺(tái)保留或簡化這些feature。我們經(jīng)過多次會(huì)議和討論,確定了大體的移動(dòng)端管線結(jié)構(gòu)和流程,以及對應(yīng)的RT的格式和尺寸。然后就是通過平臺(tái)宏控制,將移動(dòng)平臺(tái)下預(yù)期不佳的功能,從管線和Shader上先進(jìn)行了屏蔽,渲染管線也進(jìn)行了重新設(shè)計(jì),以適配移動(dòng)平臺(tái)的帶寬壓力。在完成這些整理之后,我們才開始正式移植到移動(dòng)真機(jī)上的。整個(gè)移植過程非常非常順利。由于絕大部分的問題在上真機(jī)之前就已經(jīng)預(yù)料和屏蔽了,因此幾乎沒有遇到什么困難就可以在移動(dòng)平臺(tái)的高端設(shè)備上跑起來。

Opaque 的ColorBuffer 的load是不必要的

只是真正的難關(guān),是在跑起來之后。

在HDRP移植到真機(jī)之后,我們發(fā)現(xiàn)其運(yùn)行性能實(shí)在不是很好,大約可能只有10+、20+的FPS。這個(gè)離我們的預(yù)期太遠(yuǎn)了,所以我們開始Profiler真機(jī)看看問題都出在哪里。

主要的問題就是在Shader上面。HDRP的標(biāo)準(zhǔn)Lit Shander 在移動(dòng)平臺(tái)下編譯出來數(shù)千行還帶有循環(huán)的指令,實(shí)在是讓移動(dòng)平臺(tái)的GPU難以應(yīng)對。因此我們開啟了大規(guī)模的Shader的整理和簡化工作。整個(gè)優(yōu)化流程進(jìn)行了很多輪,時(shí)至今日,我們?nèi)匀贿€在持續(xù)為Shader進(jìn)行移動(dòng)端的優(yōu)化。但是在初期一兩次核心整理之后,F(xiàn)PS就有了大幅提升。主要的優(yōu)化方向有,去掉復(fù)雜的,很多次循環(huán)迭代的某些算法(如陰影,環(huán)境高光等),改用適合移動(dòng)端的輕量級算法。另外光柵化數(shù)據(jù)的結(jié)構(gòu)整理,也很有必要。去掉各種不必要的feature的分支。因?yàn)槲覀円呀?jīng)熟悉了解了自己項(xiàng)目的需求,因此不必保留這些Shader里面可能的分支流程。最后,由于HDRP原本并不是為移動(dòng)平臺(tái)設(shè)計(jì)的,因此會(huì)存在大量的動(dòng)態(tài)索引設(shè)計(jì)。動(dòng)態(tài)索引確實(shí)在設(shè)計(jì)的靈活性上非常方便,但是這會(huì)使得buffer的訪問速度,甚至大量中間變量的計(jì)算速度變得很慢。因此去除主方向光、陰影等等渲染輸入數(shù)據(jù)的List結(jié)構(gòu),使其變成可以通過靜態(tài)偏移的方式去訪問。使得Shader代碼從行數(shù),寄存器訪問速度,甚至CPU數(shù)據(jù)填充方面都有很大的性能提升。

在移動(dòng)端開發(fā)的過程中,我們也深刻地認(rèn)識(shí)到——移動(dòng)平臺(tái)的優(yōu)化是需要持續(xù)進(jìn)行的,即使到了項(xiàng)目開發(fā)的中后期,也應(yīng)該對移動(dòng)端性能的保持關(guān)注和維護(hù)。過程雖然會(huì)有困難和卡點(diǎn),但是優(yōu)化過后的效果總能讓移動(dòng)端的表現(xiàn)更上一層樓。

PC 端的資源?產(chǎn)?作流和移動(dòng)端是怎么平衡和配合的?

我們是以 PC 為基礎(chǔ)?產(chǎn)模型資源的,在技術(shù)給定的規(guī)格框架內(nèi),保證基本效果的情況下向移動(dòng)端 過渡。這個(gè)過度包括模型的?數(shù),貼圖材質(zhì)的處理,LOD 的處理和銜接,以及技術(shù) Shader 上的調(diào)整。兩者之間有共?和繼承關(guān)系,也有完全獨(dú)?的部分。?如 PC 的最后?級 LOD 是移動(dòng)端的第?級。當(dāng) 然,移動(dòng)端因?yàn)榧骖櫺阅芎托Ч麊栴},我們也會(huì)對?些模型進(jìn)?單獨(dú)制作和調(diào)整。這個(gè)調(diào)整也是在 PC 資產(chǎn)的基礎(chǔ)上去想辦法,這樣才能保證 PC 和移動(dòng)端的效果統(tǒng)?。

游戲場景及規(guī)模都很?,資源和渲染管理??做了哪些特殊的設(shè)計(jì)嗎?

仙劍世界的地圖面積高達(dá)384平方公里,涵蓋多樣化的地形地貌、人文景觀和精怪生態(tài)。其中所涉及的資源種類和數(shù)量非常龐大,我們在尋找開發(fā)效率、包體大小、更新效率、性能優(yōu)化和游戲品質(zhì)之間的平衡點(diǎn)時(shí),遇到了極大的挑戰(zhàn)。通過項(xiàng)目前期的不斷打磨和調(diào)整,我們最終探索出了一整套的涵蓋資源制作、場景編輯等上下游的規(guī)范、流程和工具鏈。

首先是為不同平臺(tái)制定不同的美術(shù)資源標(biāo)準(zhǔn),確定每個(gè)平臺(tái)的資源制作規(guī)格、命名規(guī)范和品質(zhì)標(biāo)桿。

其次我們將場景物件按“花草樹木山石湖河器物”等進(jìn)行細(xì)分,為每個(gè)類別制定專門的場景擺放規(guī)則。通過資源代理機(jī)制,地編只需制作一份場景,我們可以針對不同平臺(tái)進(jìn)行細(xì)節(jié)控制,在不影響功能性和品質(zhì)的前提下適配平臺(tái)特性。

《仙劍世界》場景地編

在打磨和調(diào)整過程中,我們逐步完善了工具鏈,以標(biāo)準(zhǔn)、自動(dòng)、可視、高效為原則,助力各個(gè)生產(chǎn)環(huán)節(jié),提供效率,保障品質(zhì)。

再次,我們引入了Unity新一代資源構(gòu)建管線SBP,其靈活、可定制、高效的特性,使我們可以從容管理數(shù)十萬且還在不斷增長的資產(chǎn),隨心控制打包粒度,縮減CICD的時(shí)長。

最后,我們通過對Unity引擎的深度定制化,讓游戲可以承載更豐富的細(xì)節(jié),容納更多的玩法,體現(xiàn)更高的畫面品質(zhì)。

在渲染方面,我們除了在近景使用了HIS系統(tǒng)進(jìn)行大規(guī)模合批(在Unite大會(huì)詳細(xì)分享過這個(gè)技術(shù),它主要針對材質(zhì)相同,mesh相同,但是數(shù)量非常龐大的組件式的model類型),還利用Unity 的 Batch Renderer Group 來針對mesh、材質(zhì)重疊度不高,數(shù)量不大,但是種類很多的靜態(tài)非組件式物件進(jìn)行合批操作。這樣我們近景對象的DrawCall問題就得到了很好的解決。

通過HIS進(jìn)行場景管理,同樣的場景FPS可以達(dá)到230以上,性能增加了15倍

未來的上線計(jì)劃能和我們透露嗎?

在前段時(shí)間結(jié)束的多端付費(fèi)刪檔測試中,?些 HDRP 在各個(gè)?機(jī)型號上的適配效果也得到了初步驗(yàn) 證。雖然?前還沒達(dá)到最佳理想的狀態(tài),但是從團(tuán)隊(duì)優(yōu)化效果的軌跡來看,對于 HDRP 移動(dòng)端的移植還 是保持著樂觀的預(yù)期。

同時(shí),?論是 PC 端還是移動(dòng)端平臺(tái),我們都希望游戲給玩家?guī)砀玫母惺堋W罱彩窃俣乳_啟 了?范圍的共研服測試,針對畫?、玩法、體驗(yàn)等不同層?進(jìn)?優(yōu)化和迭代。例如針對我們核?“萬物有靈”的玩法,新增多御靈助戰(zhàn)、注靈探索、御靈仙術(shù)、御靈派遣等豐富內(nèi)容;針對“五靈? 克”戰(zhàn)?機(jī)制,優(yōu)化戰(zhàn)?效果與玩法策略;針對游戲基礎(chǔ)體驗(yàn),優(yōu)化UI表現(xiàn)和戰(zhàn)??感等等。后續(xù)將 會(huì)有更好的效果表現(xiàn)呈現(xiàn)給?家,也可以期待?下。

采訪還附上了 U3D 引擎開發(fā)工程師何姝姝,在 Unite Shanghai 2024 上的分享《<仙劍世界>: HDRP 管線下的超大世界游戲與跨平臺(tái)優(yōu)化》演講全文。

大家好,我叫何姝姝,來自上海凡影滿天星工作室,我們最近開發(fā)了一款名叫《仙劍世界》的開放世界游戲,很高興今天有機(jī)會(huì)跟大家分享我們在《仙劍世界》這款游戲中所遇到的技術(shù)方面的經(jīng)驗(yàn)和數(shù)據(jù)。

立項(xiàng)的時(shí)候,我們計(jì)劃制作一款大世界游戲,它可以上天入地、自由飛翔,它有什么特點(diǎn)呢?它非常的大,它是一個(gè)開放性地圖,地圖直徑有 24 公里,總規(guī)模達(dá)到 384 平方公里,全場景自由探索,并且完全沒有 loading 條,我們支持 PC、iOS 和安卓,可能還會(huì)有其他平臺(tái)后續(xù)的支持計(jì)劃。在 PC 上,我們要求很高的質(zhì)量,并且移動(dòng)平臺(tái)我們要求非常流暢。

《仙劍世界》御劍飛行效果展示

我們項(xiàng)目早期是 URP 管線,優(yōu)點(diǎn)是簡潔、靈活、代碼總量小、便于維護(hù),控制它的成本比較小,但這也是它的缺點(diǎn),它實(shí)在太簡單了,缺少大項(xiàng)目需要很多 feature。當(dāng)時(shí)我們有兩個(gè)選擇,一個(gè)是自己造輪子,進(jìn)度和計(jì)劃不是很允許。另外是尋找各種 feature 的 package,把它們整合到一起,但是整合成本也很高,可能會(huì)有很多 bug??偟膩碚f,我們當(dāng)時(shí)的訴求是快速、好看、靈活、效果豐富和穩(wěn)定。

我們當(dāng)時(shí)比較重視曾經(jīng)使用了/或者還在使用的效果 feature,包括 SSS、Tile/Cluster 的精確光系統(tǒng)、volume級別的環(huán)境效果、管線管理,SSAO,基于物理的光照單位(lux、lumen等),物理的光照、大氣,更加完善的 PBR 著色,基于探針的環(huán)境 GI、SSGI 等全局光照體系,PCF 和 PCSS 的陰影體系,后處理中比較方便的如 DOF、運(yùn)動(dòng)模糊等效果體系,以及 TAA、DLSS 等抗噪體系,更完善的 ColorGrading 和 Tonemaping 等畫面風(fēng)格化處理,最后是極度便捷好用的 RenderingDebug 系統(tǒng)。

我這里給大家直接在游戲內(nèi)截的圖,比較真實(shí)的反饋了 SSS 帶來的皮膚效果。與選人或者抽卡等這種影棚燈光效果不同,大世界游戲場景的燈光會(huì)相對比較簡單,這樣更能給大家?guī)碇庇^的 SSS 效果體驗(yàn)。我們這里看到,即使是從月光照射下,甚至在陰影下, SSS 都給角色皮膚帶來了較為清透的質(zhì)感效果。

[11 SSS皮膚效果展示.mp4]

SSAO 也是游戲中比較重要的效果,左下圖是 SSAO 貼圖,左上是關(guān)閉了 SSAO 的效果,右下是開啟 SSAO 的效果。開啟 SSAO 之后,屋檐下的遮蔽更加明顯,建筑和畫面也因此變得更加立體和扎實(shí)。

在后面這組畫面中,建筑基本位于陰影之下,SSGI 沒有開啟之前,屋檐內(nèi)部光照缺乏層次細(xì)節(jié),黑糊糊一團(tuán),使用了 SSGI 之后,不僅外部柱子因?yàn)檎诒螠p少,亮度提升,夾縫中的屋檐也因?yàn)榉磸椆獗徽樟亮?,并且屋檐下每個(gè)橫梁、每個(gè)面都受到了不同 GI 的效果,畫面也豐富了很多。

得益于 HDRP 便捷的 Volume 系統(tǒng),我們可以方便快捷的實(shí)現(xiàn)日月變化和動(dòng)態(tài)天氣效果。

[14 天氣變化.mp4]

PCSS 也是 HDRP 的一個(gè)特色 feature,它可以為我們實(shí)現(xiàn)比較高質(zhì)量的軟陰影效果,大家可以看到樹葉打到柱子、樹葉、地面,墻壁上的陰影呈現(xiàn)不同程度的 soft 效果,比較柔和自然。

這里我想給大家重點(diǎn)推薦一下 DLSS,在關(guān)閉 DLSS 畫面的竹葉噪點(diǎn)很多,也比較閃爍,開啟 DLSS 的那一剎那,畫面得到了非常大的提升,沒有噪點(diǎn),更加穩(wěn)定,甚至樹葉形態(tài)都更加清晰了。DLSS 確實(shí)是非常重要的提升效果的 feature。

我們后來接入 HDRP 之后遇到了一些問題,首當(dāng)其沖的就是 Shader,HDRP 的 Shader 是基于 Uber 方式進(jìn)行管理的,它提供了非常多便捷的 feature 支持,HDRP 開發(fā)者將眾多大型游戲中或者其他工業(yè)渲染中可能會(huì)運(yùn)用到的各種功能濃縮到一套 Uber Shader 下,這樣做的好處非常明顯,它可以在早期開發(fā)時(shí)期以很低廉的學(xué)習(xí)成本,直接運(yùn)用和控制這些 feature。比如所有的 Lit shader 可以輕易切換成更適合自己的游戲算法。中后期,Uber 為我們帶來了很多問題,比如它的代碼量實(shí)在太大了,所以閱讀起來非常耗時(shí)。其次它的編譯太慢了,初期可能改一個(gè)底層的 Lightloop 文件需要編譯 20 分鐘時(shí)間,簡直難以讓人忍受。最后,代碼或者 keyword 和分支過多之后,整個(gè) shader 所占用的總內(nèi)存就會(huì)變得很龐大,達(dá)到數(shù)百 M 以上。

這三點(diǎn)每一點(diǎn)都很痛。好在后面我們都摸索出了一些解決方案。

首先,我們?nèi)匀皇墙ㄗh,在 HDRP 下,盡可能的使用 Uber 的方式進(jìn)行 shader 管理 HDRP 的 feature 過多,渲染代碼量非常大,且分支過多,因此一定要注意維持 shader 以及 keyword 的數(shù)量,keyword 的新增是申請制,去掉一切不會(huì)使用到的 feature。采用靜態(tài) keyword 去替代掉動(dòng)態(tài) keyword。

第二,減少 if 分支的使用。去掉不用的 if 分支。HDRP 因?yàn)榉种н^多,會(huì)導(dǎo)致編譯器無法合并,位于不同分支內(nèi)的相同運(yùn)算過程,這將使代碼復(fù)雜度、運(yùn)算量大大增加。

第三,盡量嚴(yán)格統(tǒng)一底層,使用相同的 Lit 和 LightLoop 等底層光照文件,便于后期統(tǒng)一優(yōu)化,因?yàn)槲覀円欢ㄐ枰獌?yōu)化。效果沒有確定下來之前,建議使用 Shader Graph 來探索渲染效果,建議花費(fèi)一些時(shí)間修改 Shader Graph的 package 中源碼,增加其 Shader Graph 轉(zhuǎn)成 Code Shader 后的代碼可讀性和維護(hù)性,否則轉(zhuǎn)出來的代碼太長了,實(shí)在沒有什么可讀性,優(yōu)化起來也不是很方便。

第二個(gè)問題是 Volume 的更新,因?yàn)橛袑?shí)時(shí)日月天氣的變化,依賴 Volume 以后,可以很輕松實(shí)現(xiàn)。從右圖可以看到,一個(gè)環(huán)境配置可能包括有數(shù)十個(gè)不同的組件,包括 Unity 自帶的組件和我們自己實(shí)現(xiàn)得功能等,但是每個(gè)組件又帶有數(shù)十個(gè)變量,會(huì)造成刷新性能不好的結(jié)果。因此,我們的優(yōu)化方向是需要嚴(yán)格控制刷新頻率,比如沒有變化的時(shí)候不刷新、不需要刷新的變量也不刷新,這部分的優(yōu)化是必不可少的大家可以根據(jù)自己的項(xiàng)目情況進(jìn)行極限壓縮,主要是為了減少刷新的計(jì)算量。

控制好 Volume 體系開銷之后,我們發(fā)現(xiàn) Render Graph 管線開銷也很大。首先 HDRP 管線,我來給大家梳理一下它的大體工作流程:

他們大部分都需 new RendererListDesc() 函數(shù),這就需要引擎層為這些所有的 pass,執(zhí)行 SRP Batcher 工作。Unity 引擎底層會(huì)將這些,通過了 Filter 裁剪器之后的 Renderer,pack 成 RenderNode,然后把他們分發(fā)到多個(gè) Job 線程,去整合他們的材質(zhì),變量,區(qū)分每一個(gè)變量是否是 Global 的,如果是,還要把變量從 Global 區(qū)域 copy 出來,填充形成自己這個(gè) Drawcall 的 cbuffer。另外還有每個(gè)需要裁剪的 Camera,還需要對所有 RenderNode 進(jìn)行裁剪,還有各種 Probe 的裁剪,Bound 計(jì)算等等。管線的工作成本是非常高的。而且這個(gè)高,是會(huì)隨著相機(jī)數(shù)量成倍數(shù)增長。即使開了 Job,并且實(shí)在多線程中完成這些計(jì)算,但是當(dāng)場景中的渲染對象多到一定程度之后,我們發(fā)現(xiàn) RenderGraph 在 PC 上的成本都是很高的,更何況并行能力更差的移動(dòng)平臺(tái)。有時(shí)候其開銷能達(dá)到 10ms 以上,基本上很難接受。因此我們的優(yōu)化策略是一定要控制住 Camera 的數(shù)量,絕不額外增加 Camera。剩下的相機(jī),一定增加多種相機(jī)類型,以便于精確控制除了主相機(jī)之外的相機(jī)的渲染流程。例如:UICamera AvatarCamera 等等特殊相機(jī)類型。

如果要?jiǎng)討B(tài)改變環(huán)境,當(dāng)發(fā)生變化的時(shí)候,每個(gè)模塊都需要刷新,這個(gè)時(shí)候就需要對每個(gè)相機(jī)的每個(gè)管線,進(jìn)行量身定制,以減少除了主相機(jī)之外的所有次要管線內(nèi)非必要計(jì)算:

例如:UpdateEnvironment()(他們包括了 SkyBox 更新,Convolution mipmap 的計(jì)算,GI 的球諧刷新等等),我們只需要計(jì)算和渲染主相機(jī)那一次,其他情況盡可能復(fù)用。另外,昂貴的 PostProcess 體系最好只有主相機(jī)有,其他相機(jī)只保留必要的 feature 即可,能去掉的盡量去掉。最后,GlobalBuffer 會(huì)在多條管線中填充多次,很多時(shí)候是可以復(fù)用的,盡量減輕管線的負(fù)擔(dān),盡量減少非必要填充。

跨過了 RenderGraph 之后,我們遇到了一個(gè)新的問題,那就是 Batch。首先,我們已經(jīng)定制修改渲染管線了,CPU 壓力就解決了嗎?但是別忘了,我們是一個(gè)大世界游戲。

這里我給大家補(bǔ)充一些信息。

第一個(gè),HDRP 和 URP 同屬于 SRP 管線,其底層都是具有 SRP Batcher 功能的。本來 SRP Batcher 是一個(gè)優(yōu)化游戲性能的東西,為什么到這里,就變成一個(gè)性能瓶頸了呢?因?yàn)榇笫澜绲?Renderer 數(shù)量太多了,能達(dá)到 30W 個(gè)以上,其 CPU 管理成本非常非常高,所以 Batch 成本也是很高。

所以我們開發(fā)了一套 HIS 系統(tǒng)。場景的 Renderer 太多,動(dòng)態(tài)計(jì)算即使使用 Job 也很難承擔(dān) SRP Batch 和底層渲染的 CPU 壓力。那么我們采取的方案是:脫離 Renderer 對象管理(Renderer 僅用于烘焙場景) —— 這樣做減少了絕大部分原本 SRP Batch 的壓力。

BVH Tree 場景靜態(tài)烘焙加速場景管理,它可以預(yù)先烘焙記錄材質(zhì)、變量等信息,直接從烘焙結(jié)果中得到 Batch 結(jié)構(gòu),不再需要?jiǎng)討B(tài)計(jì)算。適合大量的,相同材質(zhì) Shader 的場景組件,可以一次性使用 Draw Instanced 繪制成百上千的對象。徹底解決 SRP Batcher 合批之后,仍然會(huì)有多個(gè) Drawcall Set 的問題。得益于這個(gè)系統(tǒng),我們可以發(fā)現(xiàn),大量相同的場景組件,其 Drawcall 以及其他渲染狀態(tài)切換均只有一次。GPU 壓力也因此得到降低。

我們可以看到右邊圖片,HIS 合并之后,場景中的大量物體都進(jìn)行了 Instancing 合批繪制,非常高效,最高的有 1200 多次。

這是 BVH Tree 的烘焙結(jié)果,這個(gè)動(dòng)畫展示了 4 層的 BVH Tree 的烘焙結(jié)果。當(dāng)我們想要定位攝像機(jī)內(nèi)有哪些渲染對象的時(shí)候,可以根據(jù) BVH Tree 進(jìn)行加速篩選定位。

我們來看看這個(gè) HIS 系統(tǒng)加入前后的性能表現(xiàn)差異,這是以一個(gè) Renderer 對象超過 8W 的小型城市建筑群。大家可以通過右上角的統(tǒng)計(jì)面板看到,SPR Batch 之后只有 10 個(gè)左右的 set pass。但是在我的電腦 I7 的 Cpu 上,它僅僅能跑 15fps。

我們來看 Profiler,是什么消耗了 CPU 性能。通過 Unity 的 Profiler,我們可以清楚的看到,CPU 每幀總開銷超過 50ms,其中 60% 以上來自 SRP Batcher 的開銷。當(dāng)開啟了 HIS 之后,我們的 FPS 可以達(dá)到 230 以上,整體 CPU 性能增加了 15 倍。

在場景的管理解決之后,我們又發(fā)現(xiàn)大世界中的光照也很麻煩,左邊的視頻可以看到,制作人要求我們實(shí)現(xiàn)實(shí)時(shí)日月光照角度變化,同時(shí)又要支持不同的天氣效果切換。右邊的視頻可以看到角色從地面飛行到三百米的高空中,如果使用 Lightmap,可能需要加載很大范圍內(nèi)的貼圖數(shù)據(jù),并且 PC 端還被要求實(shí)現(xiàn)一根柱子不同朝向的 GI 變化,因此傳統(tǒng)的 Lightmap 很難從內(nèi)存和效果上達(dá)到我們的要求。因此我們采用 PRTGI 的方式來實(shí)現(xiàn)實(shí)時(shí) GI。

我們基本上參考了《對馬島之魂》在 2021 的 SIGGRAPH 上發(fā)表的這篇文章,來實(shí)現(xiàn)的預(yù)烘焙部分。烘焙主要采用了 DX12 的光線追蹤算法,來記錄了以 0.5 米為單位的 LightProbe 內(nèi)烘焙信息。具體做法是,烘焙時(shí)通過構(gòu)建一個(gè)單位亮度為 1 的白色天空球的反彈信息 × 實(shí)時(shí)天空盒的 0 階球諧(天光的反彈) + 模擬水平面和垂直面的反彈的實(shí)時(shí)主光的反彈球諧(主光反彈)+ 實(shí)時(shí)天空盒 SH,計(jì)算游戲的最終 GI。

我們通過這種預(yù)烘焙和實(shí)時(shí)結(jié)合的方式,獲得了低成本的實(shí)時(shí) GI 效果。由于其優(yōu)秀的性能和內(nèi)存表現(xiàn),這套方案可以完全運(yùn)行到移動(dòng)平臺(tái)上,它的性能開銷可以控制在 2ms 內(nèi)和 40m 左右。當(dāng)然便捷的操作也是必不可少了。不能讓我們場景美術(shù)手動(dòng)去布置這些探針球,畢竟我們場景很大。因此自適應(yīng)生成系統(tǒng)必不可少。另外特殊的地方可以進(jìn)行人為修正也是可以支持的。

但是我們和大部分的 PRTGI 系統(tǒng)一樣,都會(huì)遇到的類似的問題,那就是——漏光。我們可以看到,由于漏光,在墻體物件和外界交界的地方,存在大量不均勻的,不穩(wěn)定的遮蔽程度,嚴(yán)重影響效果。

我們采用的方案是借助 Dilation(Post-Bake) 和 Virtual Offset(Pre-Bake) ,我們很好的控制住了漏光現(xiàn)象,獲得了均勻可信的烘焙 GI 信息,大家可以看同一個(gè)場景,漏光解決后,是不是均勻很多?大家可以參考 Unity 在 SIGGRAPH 2022 年發(fā)布的 Enemies 論文,我在這里就不作過多的詳述了。

PC 平臺(tái)的一些問題我們介紹完了,下面著重給大家介紹一下移動(dòng)平臺(tái)。在 PC 版本逐漸穩(wěn)定了之后,我們開啟了對其進(jìn)行移動(dòng)平臺(tái)的移植。這將是一個(gè)更大的挑戰(zhàn),因?yàn)槲覀兌贾?,HDRP 原生是不支持移動(dòng)平臺(tái)的,如果我們要做一致,要選擇適合的項(xiàng)目時(shí)機(jī),我們要預(yù)留比較長的容錯(cuò)時(shí)間,安排合適的項(xiàng)目進(jìn)度。由于管線的復(fù)雜程度,可能早期 8Gen3 的手機(jī)上只有 10FP,但一定要有堅(jiān)定的信心。

移植前需要做一些什么準(zhǔn)備工作呢?

第一,HDRP 是同時(shí)支持延時(shí)和前向管線的。所以需要根據(jù)自己項(xiàng)目對渲染的需求,設(shè)計(jì)自己的移動(dòng)平臺(tái)的渲染管線,是 forward/deferred。挑選移動(dòng)平臺(tái)需要的 feature。

第二,由于 HDRP 整個(gè)管線體系內(nèi)的 Shader 都并非面向移動(dòng)平臺(tái),因此有大量 feature 是使 Compute Shader,即使可以優(yōu)化,也需要做好自己項(xiàng)目的支持的設(shè)備性能基線機(jī)型選擇。因?yàn)?Compute Shader 可能對少部分低端機(jī)不友好。部分 feature HDRP 提供了 Shader 和 CS 兩種版本??梢园葱柽x擇。如果要支持移動(dòng)平臺(tái),建議盡量使用 shader 版本。因此要評估自己的項(xiàng)目對低端機(jī)下限的容忍程度。如果沒有特別長的時(shí)間專門去做優(yōu)化,選擇 HDRP 可能不能做到面向特別低端的手機(jī)。

第三,由于是移植,多端通用的資源意味著,往往并不是為移動(dòng)平臺(tái)設(shè)計(jì)的資源。那么需要提前預(yù)備好,優(yōu)化這些資源的人力和時(shí)間。根據(jù) PC 端的面數(shù)和 Drawcall 數(shù)量,估算出多端資源的各級指標(biāo),比如角色面數(shù)上限,場景面數(shù)上限等,這些需要在制作 PC 資源的時(shí)候就要準(zhǔn)備好,可以加快移動(dòng)平臺(tái)的移植進(jìn)程。

接下來看一下我們早期遇到的問題,我們早期的 Drawcall 數(shù)量可能達(dá)到了一兩千個(gè),帶寬開銷可能是 1G 以上,巨量的三角面數(shù)有時(shí)候達(dá)到了兩千萬億左右,管線和 Shader 代碼對移動(dòng)平臺(tái)不太友好,很多機(jī)型上有崩潰現(xiàn)象。

其中一點(diǎn)就是 DrawCall,我們的解決方案就是,前面介紹過的 HIS 系統(tǒng)。游戲的場景物件,盡可能使用模塊組件化設(shè)計(jì)。目的是為了極大的提高 Mesh 的利用率,從而提高我們自己寫的 Insancing 合批程度。另外就是 HLod 系統(tǒng),HIS 系統(tǒng)合并掉了近處的物件,那么中遠(yuǎn)景的場景就交給了 HLod 系統(tǒng)。它可以將一大堆建筑合并成一個(gè) Drawcall,也極大的減輕了管線壓力,是非常值得挖掘的體系。多輪的資源優(yōu)化和面數(shù)控制,最重要的還是輸入數(shù)據(jù)就能控制到接近的數(shù)量級上,其次是多級的 LOD 體系,非常有助于減面。

最后我想講一下剔除算法,第一個(gè)是 HIZ 剔除,它用 GPU Driven 的方式,利用 PreDepthPass 的深度圖,生成 HIZ 的深度金字塔,將實(shí)際上被遮擋的水體、植被等進(jìn)行 GPU 上的剔除處理。它的特點(diǎn)是是可以以非常廉價(jià)的 GPU 開銷,一次性的剔除掉大量的 Renderer 對象。但是如果不采用 GPU 回讀的方式,由于它的剔除行為發(fā)生在 GPU 階段,因此所有渲染數(shù)據(jù)都需要向 GPU 提交。因此 CPU 壓力并沒有得到釋放。如果進(jìn)行回讀,當(dāng)視角與上一幀變化稍大一些,其回讀數(shù)據(jù)就會(huì)喪失可信任性,仍然是會(huì)產(chǎn)生 CPU 的渲染提交,以及 GPU 上最終的渲染成本。另一方面,由于它是以相同材質(zhì)和 Mesh 來作為單元管理,當(dāng)材質(zhì)和 Mesh 的多樣性非常高,實(shí)例化數(shù)量卻不大的時(shí)候,CPU 的管理壓力就相對會(huì)比較大。

最后,在 CPU 方面,我們有采取了 Intel 的 SOC 軟光柵化剔除來減少從 CPU 提交 Drawcall 的數(shù)量。CPU 剔除就沒有材質(zhì)類型的限制,但是它依賴遮擋體的設(shè)計(jì)和制作。因此也更適合用于城市中,墻體周圍的小道具和小建筑等等的剔除。

這兩個(gè)剔除算法都很重要。他們能協(xié)助我們從每一個(gè)層面,去最大可能的減少 Drawcall 的渲染數(shù)量。

Drawcall 看完了,讓我們來看看帶寬。首先,重新設(shè)計(jì)管線流程,盡量去掉每個(gè) pass 之間 RT 和狀態(tài)切換的次數(shù),最好不切換。另外,不需要讀取 RT 之前信息的時(shí)候,如 ColorBuffer 在 Opaque 階段第一個(gè) pass 前,使用 DontCare 或者 Clear 做為 RT Load 的 Flag,避免強(qiáng)迫 Load 之前的渲染結(jié)果,導(dǎo)致帶寬增加。

第三,由于 feature 的減少,HDRP 下 Shader 的 VertShader 部分的輸出會(huì)出現(xiàn)大量冗余操作,例如去掉了 NormalBuffer 的輸出,則無需讀取頂點(diǎn)法線,更無需進(jìn)入光柵化過程等。因此優(yōu)化過程中一定要去掉 Vertex 函數(shù)輸出結(jié)構(gòu)中, 不需要 frag 過程中使用的寄存器類型,不要有浪費(fèi)的情況,應(yīng)該控制住每個(gè)寄存器。容易被忽略的是使用 Unity 提供的 Mesh.SetVertexBufferParam 函數(shù),對 Mesh 進(jìn)行 Split 處理,使其在非著色 pass 中 VertexBuffer 綁定大小減少。

第四,可以嘗試壓縮頂點(diǎn),但是可能會(huì)帶來額外的頂點(diǎn)計(jì)算量,要權(quán)衡一下是否適合,每個(gè)項(xiàng)目的情況也不一樣。最后,評估優(yōu)化每一張管線中的 RenderTarget 貼圖,選擇適合移動(dòng)平臺(tái)的尺寸和格式。比如能用 R16,千萬不要用 R36,也不要使用全分辨率等等。最后,如果帶寬切換太過嚴(yán)重,可以考慮局部使用 Subpass,以避免掉帶寬 Load/Store。

說完了管線部分,我們來看看 shader 部分。首先 Shader 里面盡可能去掉各種,開關(guān)某些功能的條件分支和 for 循環(huán)。分支間的即使相同的計(jì)算,也無法獲得優(yōu)化。比如寄存器不能復(fù)用,可能導(dǎo)致多次相同計(jì)算和采樣(可能還會(huì)產(chǎn)生大量帶寬問題)建議將其降低次數(shù)后展開 for 循環(huán),并根據(jù)項(xiàng)目 feature 依賴情況直接去掉不需要的分支(或者采用靜態(tài)宏條件分支)。

其次 HDRP 采用了大量的動(dòng)態(tài)生成的 Buffer 來進(jìn)行數(shù)據(jù)填充,比如 GISh,比如主光,點(diǎn)光,陰影設(shè)置,等等。嚴(yán)格控制 RWBuffer 的數(shù)量,最大不可超過 4 個(gè),否則會(huì)有移動(dòng)平臺(tái)很多設(shè)備上的兼容問題。

然后提高 Half 計(jì)算占比,是我們一個(gè) Shader 優(yōu)化的常用手段。但是 HDRP 的光照強(qiáng)度很可能會(huì)超過 10W 以上,Half 計(jì)算之后,幾乎會(huì)一直處于溢出狀態(tài),需要進(jìn)行壓縮后再計(jì)算,否者我們常年可能會(huì)遇到各種溢出。

還有環(huán)境高光計(jì)算太過復(fù)雜,過多的循環(huán)和混合,導(dǎo)致性能非常差,由于對畫面貢獻(xiàn)較小,移動(dòng)平臺(tái)上替換成 URP 類似的環(huán)境高光計(jì)算即可。

最后更換陰影 PCSS 算法(循環(huán)次數(shù)過多),使用更合適的陰影算法,如 PCF、VSM 等。

讓我們來看看還有哪些 Shader 中被忽略的點(diǎn)。索引大家都知道是什么意思,那么動(dòng)態(tài)索引呢,就是 HDRP 底層比較喜歡將渲染的數(shù)據(jù),比如方向光主光,生成 list 結(jié)構(gòu),用 for 循環(huán)的方式在 Lightloop 中進(jìn)行渲染,這樣,當(dāng) GPU 在執(zhí)行一次渲染的時(shí)候,將兩個(gè)像素分別派發(fā)給了不同的 wave,這時(shí) GPU 就不能清楚的知道,這兩個(gè) wave 在訪問方向光數(shù)據(jù)的時(shí)候,是否使用了相同索引數(shù)據(jù),那么這樣數(shù)據(jù)訪問的結(jié)果就會(huì)被存儲(chǔ)到向量寄存器 VGPR 中,而 VGPR 中的數(shù)據(jù),是無法在多個(gè) wave 之間進(jìn)行共享的。反之,如果這些數(shù)據(jù)被存到了標(biāo)量寄存器中,GPU 多個(gè) wave 之間將會(huì)只采樣和計(jì)算一次這個(gè)光照數(shù)據(jù),在所有 wave 間進(jìn)行共享。因此這兩種寄存器會(huì)給 Shader 帶來非常大的性能差異結(jié)果。因此我們對 Shader 的優(yōu)化方向,就需要嚴(yán)格控制 Shader 中 VGRP 寄存器的使用率。具體的做法是,將 HDRP 管線下 Shader 中動(dòng)態(tài)索引數(shù)據(jù),比如主光,精確光,陰影等數(shù)據(jù),統(tǒng)統(tǒng)都拋棄了 list 的數(shù)據(jù)結(jié)構(gòu),直接定義到 Buffer 中,用固定的 offset 去訪問這些 Buffer 數(shù)據(jù)。這樣這些被訪問的數(shù)據(jù)以及這些數(shù)據(jù)的中間計(jì)算結(jié)果,都將有可能被存儲(chǔ)到標(biāo)量寄存器中,從而實(shí)現(xiàn) wave 間的共享,避免掉多次計(jì)算。

另外還有容易被忽略的 LRZ 的被關(guān)閉的條件。除了我們眾所周知的 Frag中進(jìn)行與深度相關(guān)的 Clip 操作。還有,比如在這些 pass 渲染輸出了深度/stencil 也不行。這里提供一種解決的思路,如果我們希望,Opaque 內(nèi)能 LRZ 的更高效一些,我們需要盡量將深度和 stencil 的 write,在 Opaque pass 內(nèi)關(guān)閉掉。最后,不可以使用 SecondCommandBuffer ,否則在某些設(shè)備上,可能也會(huì)被關(guān)閉 LRZ。

我們再來看看還有哪些注意點(diǎn),使用 Vulkan,性能指標(biāo)要好很多,對 ComputeShader 支持也更好,機(jī)型兼容性更強(qiáng),使用多線程渲染和 Rendering Batches Jobs 我們來看看右邊這個(gè)圖片。另外,移動(dòng)平臺(tái)下,對于 CPU 和 GPU 都會(huì)訪問的的 ComputeBuffer,比如 CPU 內(nèi)填充 setdata 數(shù)據(jù),GPU 也會(huì)訪問讀取這些數(shù)據(jù)。這種情況,new ComputeBuffer 的時(shí)候,盡量去指定使用 ComputeBufferMode 的 Dynamic/SubUpdates 類型,以避免因?yàn)樯暾埑赡J(rèn)的Immutable類型。因?yàn)?Imm 類型的 Buffer 只允許 GPU 進(jìn)行讀寫,但是我們又要 setdata,因此渲染底層會(huì)幫我們在每幀的最開始,將這個(gè)我們會(huì) setdata 的 buffer,通過 copyBuffer 出一個(gè)新的 dynamic buffer,給 CPU 使用和填充。這樣會(huì)產(chǎn)生每幀大量的 CopyBuffer 成本。具體寫法可以看右邊這個(gè)圖片。

最后,有源碼條件的同學(xué),也可以嘗試更改一下渲染 Job 的同步點(diǎn)類型,不同的項(xiàng)目可能適合的同步點(diǎn)不一樣,有助于更好的實(shí)現(xiàn)線程之間,或者 CPU/GPU 之間的并行。

現(xiàn)在我們來說說移動(dòng)平臺(tái)的光照解決方案。得益于 PRTGI 烘焙,可以讓實(shí)時(shí)計(jì)算的復(fù)雜度減少。這是 shader 優(yōu)化后效果。我們可以看到房屋下面的 AO 遮蔽和 GI 效果也比較明顯。

讓我們來繼續(xù)看一下移動(dòng)平臺(tái)的點(diǎn)光方案。因?yàn)槲覀兪且粋€(gè)多端通用資源的項(xiàng)目。從維護(hù)的便捷性方面考慮,移動(dòng)平臺(tái)仍然使用 HDRP 的 Cluster 點(diǎn)光管理方案,但是,我們限制了最大同一個(gè) Cluster 內(nèi)支持 4-8 盞點(diǎn)光,同屏最大支持達(dá)到 80 個(gè)以上點(diǎn)光。

精確光循環(huán)的計(jì)算內(nèi)容,代碼完全被展開,以更好的進(jìn)行寄存器共享,并利用 SIMD 計(jì)算,一次性計(jì)算多盞點(diǎn)光的光強(qiáng)衰減和 diffuse 和 GGX 高光計(jì)算。可將點(diǎn)光所有的代碼量控制到 150 行 DXBC 指令左右。

我們可以看到左邊是移動(dòng)平臺(tái)的副本點(diǎn)光效果,右邊是 PC 平臺(tái)的點(diǎn)光效果。除了資源有所不同,其光照效果基本一致。

最后的最后,我想聊一下 HDRP 平臺(tái)上的各種 Debug 工具。首先 HDRP 自帶的 RenderingDebuger 工具非常好用,它囊括了幾乎絕大部分 PBR 渲染流程能的核心參數(shù)顯示,對于檢查材質(zhì)正確性,它具有完全的不可替代性。

第二個(gè)是經(jīng)常被使用的老牌 Debug 工具,它非常好用,與 Unity 也結(jié)合的非常好。Xcode 的各種工具 Profiler,用于檢查 IOS 真機(jī)的內(nèi)存、CPU、GPU、管線帶寬、Shader/CS 性能開銷,CasheMissing 程度等等敏感指標(biāo),仍然是最方便的。Snapdragon Profile 用于檢查安卓真機(jī)的性能開銷,profiler 性能數(shù)據(jù)也不錯(cuò),遺憾對 vulkan 支持較弱。Arm_Mobile_Studio 用于檢查 shader 性能,分析寄存器情況,SimplePerf 用于查看安卓真機(jī) CPU 開銷情況也很好用。

在 PC 上,我們比較喜歡使用的是 GPA 和 Nsight,特別是 N 卡用戶,可以通過 Nsight,可以獲得更加準(zhǔn)確的 GPU 開銷信息。

這是剛才提到的兩個(gè)算法論文選型,謝謝大家!

申請創(chuàng)業(yè)報(bào)道,分享創(chuàng)業(yè)好點(diǎn)子。點(diǎn)擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!

相關(guān)文章

熱門排行

信息推薦