《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

Unity發表於2022-12-21
由貓槍工作室研發,嗶哩嗶哩遊戲代理的回合制二次元卡牌手遊《非匿名指令》已經在 11 月開啟了全平臺公測。在近未來都市風的遊戲世界中玩家需要作為“代行者”,遊走於勢力間的制衡與鬥爭,踏上暗流湧動的征途。

遊戲除了優秀的劇情、豐富的玩法,還以其 2D、3D 結合的遊戲美術風格備受好評。本期,Unity 邀請到了《非匿名指令》開發者團隊為我們分享他們的遊戲開發、最佳化經驗。

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”
《非匿名指令》客戶端團隊合影,照片拍攝於 2022 年 7 月

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

請問定製化 URP 渲染管線做了哪些最佳化呢?

01  Final Blit Pass

在 URP 預設的管線中會強制在最後執行 Final Blit Pass,它的原理就是將當前渲染的 RT 最終 Blit 到 FrmeBuffer 中顯示,Blit 的過程中會執行伽馬矯正。當前渲染的 RT 會分是否使用後處理,如果沒使用後處理就是 _CameraColorTexture,如果使用了後處理會先對 _CameraColorTexture 進行後處理,拿 Bloom 來說後處理進行中間會生成臨時 RT 進行降取樣等卷積操作,其他後處理原理也類似,然後將後處理結果的 RT 在執行 UberPostProcess,就是將結果在 Blit 到 _AfterPostProcessTexture 中,最終在執行 Final Blit Pass 進行伽馬矯正後 Blit 到 FrameBuffer 中。

每次 Blit 不僅消耗頻寬還需要對片元進行中著色,關鍵是大部分手機和 PC 是不需要伽馬矯正的,因為這些硬體已經支援了 SRGBA 轉換,可以直接將線性空間結算的結果提交給顯示卡,顯示卡自己會做伽馬矯正直接顯示出來。以我們目前測試經驗來看只有一些安卓模擬器還有一些很老的裝置不支援 SRGBA 轉換,所以最佳化的第一步就是“幹掉” Final Blit Pass。在管線中可以執行程式碼 Display . main . requiresSrgbBlitToBackbuffer 判斷是否需要進行手動伽馬矯正,在渲染的時候就可以直接渲染到 FrameBuffer 中,而不需要所有都渲染到 _CameraColorTexture 中,然後再額外進行 Final Blit Pass 了,這樣效能上能得到一個很大的提升。

02  後處理流程最佳化

要進行後處理就必須要先將結果繪製到一張 RT 中,因為 FrameBuffer 中的顏色管線中獲取不到。URP 管線是可以對任意相機進行後處理的,但其實 UI 是沒有後處理的需求的,真正需要後處理的只有 3D 相機。這樣 3D 需要先畫到 _CameraColorTexture 中,然後執行後處理操作,將顏色直接 Blit 到 FrameBuffer 中,這樣就不需要先 Blit 到 _AfterPostProcessTexture 在進行 Final Blit 了,一下就可以減少 2 次 Blit 效能又得到一次很大提升。

03  降低解析度不包含 UI

透過以上最佳化後記憶體中只有一張 _CameraColorTexture,此時只有 3D 畫在這個圖中,所以可以只對它進行降低解析度,因為它降低了解析度後處理也會降低解析度,接著才後處理,接著此時就 Blit 到 FrameBuffer 中。後面的 UI 直接給 FrameBuffer 中畫,並沒有透過中間 RT 所以 UI 顯示是完全高畫質的,如果在平板這樣的裝置上,因為螢幕解析度比較大可以整體優先降低解析度 Screen . SetResolution() ,然後再針對 3D 部分在單獨降低一些。

風格化卡通 PBR 的渲染方式 做了哪些融合方式?

01  製作方面

我們遊戲並沒有使用傳統二次元賽璐璐風格的渲染,而採用的是 PBR + NPR 混合的渲染方式,而且對渲染公式也做了很多調整。在裝備武器上使用 PBR 佔比多一些,在 PBR 的基礎上增加了卡通渲染的分階著色、各向異性、兩層高光的頭髮渲染、車漆、毛髮、布料、絨等效果,還對陰影進行了修正,修改了光照模型以及材質表達做了不同程度的融合。在皮膚頭髮中使用 NPR 佔比多一些,還增加了皮膚多層顏色過度羽化功能,還有一部分 mask 圖來修正高光、描邊、面部陰影等細節。

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

02  最佳化方面

我們的 Shader 分了兩個,一個是 PBR 的一個是 NPR 的,常用的 Shader 效果多多少少擴充套件了 30 多種吧,加上 Unity 自帶了宏定義就 40 多個了,記得當初有個版本定義了很多 multi_compile 導致光 Shader 記憶體就過 1G 了非常恐怖。最佳化的手段就是優先使用 multi_feature 來代替 multi_compile,但是有些死亡溶解、貧血邊緣光效果它需要動態開關,這種我們需要做宏剝離 IPreprocessShaders。比如溶解和邊緣光宏是不可能存在同時開關需求的,還有一些其他宏不可能出現得動態組合,這些都可以預先剝離它。multi_feature 也面臨是一個問題是當 Shader 進行依賴時,單獨打 Assetbundle 的時候可能會被玻剝離掉,所以我們還開發了一個工具一鍵生成變種 ShaderVariants 收集器,原理就是離線對所有場景、Prefab 遍歷收集將使用到的宏組合預先收集到 ShaderVariants 中,這樣定義過 multi_feature 就不會被剝離掉了。

除了我們自己寫的 Shader 以外,Unity 預設的宏有些也不太合理,目前角色都使用 SRPBatcher 不需要 GPUInstacning,還有 multp_compile_fog 都會產生額外的宏如果不需要都可以進行剝離。透過這些修改 Shader 記憶體直接從原先的 1G 最佳化到 20M 左右。

03  位元組對齊

URP 的 shader 我們還遇到了個需要位元組對齊的坑,在部分機器上可能閃退或者顯示結果異常。如下程式碼所示,要將佔用大的寫在前面,而且不要出現 half3 和 half2,統一使用 half4 來代替。

CBUFFER_START

half4

half4

half

half

END

3D、 2D 介面結合 可以具體講一下是想實現怎麼樣的效果?以及怎麼做的?

我們遊戲使用的是 UGUI 開發的,3D 介面使用透視的相機,但是 3D 介面有個前提是需求上它是否需要自適應。如果需要自適應,在 Canvas 中還使用 Screen Space-Camera 模式單純將 UICamera 的 Projection 設定成 Perspective 就可以了,這樣 UI 就可以進行旋轉擁有近大遠小的效果。如果 3D 介面不需要自適應,比如場景中有個模型,旁邊用 UI 寫個文字一類的描述。因為模型是被 3D 相機看的,當螢幕尺寸發生變化可能模型可能就顯示不全,如果此時 UI 還進行自適應效果就出問題了,所以針對於這種不需要自適應的 UI 需要再 Canvas 中設定 Word Space 模式。這樣無論 3D 還是 2D 介面都可以用一套 UI 框架開啟,對於 UI 框架來說它們都是完全一樣的,至於介面中動畫效果就是正常的由 UI 策劃同學掛 Tween 一類指令碼實現。

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

遊戲中還用到了哪些最佳化手段?

01  角色部分

模型採用 3D 模型 + Spine 骨骼 + Live2D,我們單模型 4 萬面以上,骨骼在 120 格以上,整個角色的渲染壓力非常大,GPU 一直在等 CPU。所以我們做了 Shader Lod 功能,在 UI 介面中觀察模型時,所有效果都拉到最滿,但是進入戰鬥會把大部分效果剝離,這樣能進一步減低 Shader 片元著色的壓力。

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

02  場景部分

我們場景在 20 萬面左右,在低端機上我們會限制鏡頭移動,這樣可以在進場景後的第一幀將場景渲染的結果以及渲染深度寫在另一張 RT 上,後面渲染的時候就不對場景進行渲染直接使用這個 RT,這需要在 URP 中增加一個 Renderer Features。第一幀先渲染場景將 RT 儲存,後面直接使用這個渲染的結果,因為渲染的時候要儲存深度,所以不會和後面渲染的模型產生遮擋問題,這樣在低端機上可以直接節省掉這 20 萬面的場景渲染壓力。

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

03  特效部分

我們開發了特效填充率最佳化工具,提前對每個特效的 Overdraw 進行統計並且計算出一個數值出來交給美術同學,美術同學重點對有問題的特效進行最佳化。

04  iOS 移植方面

美術同學開發都是使用 Windows 的,但是 Android 和 iOS 貼圖壓縮格式是需要單獨設定的,如果每張圖都讓他們設定 2 回也容易出錯。所以我們開發了貼圖預設壓縮工具,貼圖放入遊戲就可以自動設定最最佳化格式,角色、場景、UI、烘焙圖等都會自動設定,而且 iOS 和 PC 會自動保持和 Android 或相等消耗的壓縮格式。如果後面美術同學需要單獨給某張貼圖設定更高畫質的格式只需要設定 Android 平臺,PC 和 iOS 平臺會自動同步。

我們限制了 RGBA32 和 RGBA16 的壓縮格式,只要設定了這兩個格式指令碼會自動強制改回 ASTC 格式。而且並沒有做一些特殊的目錄來標記可設定 RGBA32 格式,因為一旦美術設定多了對後期最佳化帶來很大的挑戰。如果真需要 RGBA32 我們手動加到白名單裡,這個行為必須透過程式同學(現在累總比以後累強),這樣才能進一步保證 RGBA32 不被濫用帶來更多的記憶體開銷。

因為我們沒有企業證書,所以 iOS 沒有太多機會被測試。只要保證了貼圖記憶體在移植 iOS 就非常絲滑了,至於渲染問題幾乎只要 Android 搞定了 iOS 就沒有太大問題,透過這一些列操作我們 iOS 從開始移植到出包僅僅用了 1 個禮拜時間。

05  UI 部分

UI 最大的問題就是開啟介面慢,首先 Unity 引擎是強烈不建議使用 Assetbundle 同步載入的,因為當非同步載入的過程中如果進行了同步載入會帶來一個非常大卡頓。UI 如果使用非同步載入框架需要進行調整,因為 UI 有關閉老介面開啟新介面的需求,所以需要等新介面載入上才能關閉老介面,載入的過程中需要鎖屏。

還有就是 UI 的 Prefab 可能會產生很多依賴的情況,所以我們介面再製作時會透過一個工具將介面上依賴的貼圖特效統統從 Prefab 中剝離,這樣介面的 Prefab 只保留所有 GameObject 的節點。執行時在開啟介面時會按需非同步載入,這樣對一些 Tab 頁的 UI 當使用者沒有點開時是不會載入資源的,在配合所有 Assetbundle 都是非同步載入的,所有我們遊戲幾乎從立項以來沒有被策劃同學吐槽過開啟介面慢。

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

《非匿名指令》開發者訪談:手遊最佳化中的“異能解封”

06  其他

從體驗上可以對遊戲結果可以分為兩類:使用者在觀察模型的細節時和自動戰鬥時。因為這兩種情況下可以做一些特殊最佳化,觀察模型時鏡頭趨於固定,使用者希望能看到更高畫質的效果,此時畫面解析度需要清晰,但是對幀率沒有特別高的要求。當自動戰鬥時,此時鏡頭已經在亂動了很難看清效果了,此時使用者對幀率有要求,但是話畫面解析度就沒要求了。

結合以上兩種特點遊戲中我們進行這樣的最佳化,當使用者有操作螢幕時會慢慢降低解析度提高幀率讓使用者感受不到卡頓。而當使用者不操作螢幕並且鏡頭沒有發生移動時,慢慢恢復畫面高解析度而降低幀率讓使用者看到的畫面比較清晰。

Unity 官方在 PBR 製作上給與專案組哪些幫助?

我們購買過 Unity 官方技術服務,官方的技術大大給我們給我們美術同學科普過幾節 PBR 的原理課程。我覺得這個非常有必要,因為美術同學可能不太在意實現的細節更關注結果,這樣往往就忽略一些潛在引發的效能問題。還有美術在做場景時總出現烘焙後 PC 和移動端不一樣的效果,也是官方的技術大大給我們講解了原來移動端會將烘焙貼圖的壓縮格式改成 DLDR 格式,強制將光的強制限制在 0-2 之間。因為 PC 沒有這個限制所以兩端結果是不同的,解決的辦法也很簡單,避免使用那種強度很大的光源,合理的規劃光源的位置來避免。

最後我還想說的是我們做專案很多知識點是較為落後的,因為我們必須保證它必須在所有裝置上能跑起來。Unity 官方大大們能提前接觸到世界上最前進的技術,可能它不一定能立即在專案中落地,但是能對我們起到一些提前引導的作用。


來源:Unity官方平臺
原文:https://mp.weixin.qq.com/s/U7xl9iQXQuNZWwOYKn6beg

相關文章