GDC文章粗讀——《電馭叛客2077》的UI開發中的挑戰與優化


3樓貓 發佈時間:2024-05-31 23:33:44 作者:Hakumen Language

前言

最近剛好看到消息說《電馭叛客2077》這款遊戲正式結束開發了。在通過DLC《往日之影》最終為這個遊戲挽回聲望並且揚長避短之後,這款遊戲話題之作的官方故事就算告一段落了。
近期我更新的思路就是有什麼想說的話題,就先去GDC和SIG的歷史記錄裡翻找權威性的分享;例如想說明《電馭叛客2077》這款遊戲開發的困難,這次找到的這篇UI開發分享我覺得就很有代表性——這裡的UI更多的是廣義上的UI,即遊戲中各類平面表達和交互界面都可以認為是UI。
分享人介紹——CDPR的資深開發人員,項目中的UI開發負責人

分享人介紹——CDPR的資深開發人員,項目中的UI開發負責人

在看到這篇2023年的GDC Showcase上的分享後,我覺得其中最突出點是:分享者事無鉅細地列舉了整個UI開發中面臨的各種課題,既有時間上的視角,也有階段性的問題意識。
相比來說,這篇分享可能不是那種講細節乾貨的類型,但是能讓大家窺見世界上為數不多的3A項目在開發中面臨的實際挑戰與人們的努力。雖然可能產品上線時整體仍然還有不少BUG,不過相對於他們面對的整個巨大難題來說,實現得算很不錯了。
*後面的內容還是以翻譯PPT頁的內容為主,對於信息不足的部分會補充一些我自己的分析。順便一說,這家公司的PPT都做得很有精美,能看出這個項目的藝術氣質;另外,由於他們母語不是英文,部分地方的英文無論是讀起來還是翻譯過來都會比較彆扭——不過在原文基本通順的情況下,我還是儘量保留了原文的詞語內容。

1 已有框架的不足與新框架的預期

*隨著3A遊戲的表達方式越來越豐富,UI的內容早已不侷限於老老實實停在屏幕角落中的一些按鈕、文字和圖片了。從3D空間中的指示層UI,到融入3D物體的UI,“用戶界面”的這一概念內涵的表現形式早已不侷限於動態的圖片與文字,特效、動態物體等都可能組成UI。這篇分享的後面也能看到UI內涵不斷豐富的這一過程。
為什麼定製化UI框架

為什麼定製化UI框架

對UI框架的期望

對UI框架的期望

——技術側:
  • 引擎內創建
  • 更少的迭代時間
  • 使用引擎內的子系統
  • 更高的密度和複雜度
——創意側:
  • 更多動態元素
  • 支持多語言
  • 在3D空間顯示與交互的可行性
  • 可包含嵌入的視頻
  • 使用自定義材質和特效的可行性
研究現有解決方案中的缺乏項

研究現有解決方案中的缺乏項

——對現有解決方案(基於《巫師3》)的評估:
  • 不支持Scaleform中間件
  • 不是單一完整解決方案(需要一堆中間件組合)
  • 部分中間件或方案——不夠高效、不夠可伸縮、集成到Red引擎中比較困難

2 原型階段與初版開發

決定定製開發UI框架的時間點

決定定製開發UI框架的時間點

UI框架開發——步驟1/3

UI框架開發——步驟1/3

——引擎內多目標並行開發( Multi-Variable Programming ):
  • 簡單的widget類型(widget就不翻了 這個是UI系統控件的常用詞語)
  • 2D輸入傳播(有些引擎裡用dispatch這個詞,類似的意思)
  • 排版佈局構建
  • 集成到Red引擎的系統中——渲染、輸入系統、文件系統
MVP開發時間節點

MVP開發時間節點

原型框架示意

原型框架示意

UI框架開發——步驟2/3

UI框架開發——步驟2/3

——遊戲內UI(大約半年):
  • 包含完整功能的UI系統
  • 簡單的3D功能實現
  • 無編輯器(所有佈局通過C++硬編碼)
  • 支持嵌入視頻
首個遊戲內UI和內部DEMO的時間點

首個遊戲內UI和內部DEMO的時間點

DEMO的UI功能示意

DEMO的UI功能示意

UI框架開發——步驟3/3

UI框架開發——步驟3/3

  • 合適的實現——引擎、UI、遊玩層的連接
  • 合適的管線——編輯器和資源導入工具
  • 合適的遊戲內UI——不是通過硬編碼
  • 和更多...
*CDPR這個公司的產品是大量使用中間件的,這意味這一旦想要深入做定製化的需求,就需要從頭打造一個UI系統,從設計、邏輯到工具都是零基礎。從後面的時間節點也能看出,每年除了優化以外又不停引入新的特性,這個節奏持續到項目上線。

3 性能指標與整體優化方向分析

UI的性能指標

UI的性能指標

UI的內存指標

UI的內存指標

*Budge 指標,預算。Starting Point是他們當時的狀態,即優化的起點(可以看出差距挺大)。
UI時間指標

UI時間指標

  • 指標:在高同步性的線程上3-5毫秒執行;需要做到多線程執行
  • 現狀:單線程10-15毫秒
引入指標並開始優化的時間點

引入指標並開始優化的時間點

為什麼UI系統性能開銷那麼高

為什麼UI系統性能開銷那麼高

  • 解答1:UI系統沒有經過代碼優化
  • 解答2:太多的UI實例(內容)了
  • 解決方案——在內存、刷新和繪製方面優化UI系統。(在運行時)只保留某一特定時刻真正需要的UI實例。
複雜度的來源

複雜度的來源

屏幕空間UI——小地圖、地圖圖釘、3D地圖、道具欄、Perks、HUD元素。
高密度的來源

高密度的來源

世界空間UI——武器UI、車內UI、設備系統、公告牌、本地化的街邊告示牌、全局的TV系統、任意地方的本地化文字。
一些運行時的狀態統計

一些運行時的狀態統計

UI術語定義——第一部分 層級

UI術語定義——第一部分 層級

——UI實例:獨立的UI層級結構,包含起所有依賴的資源和物體,例如紋理、動畫、渲染對象,被一起實例化到內容中。產生自Widget庫中的一個物體預設。
——Widget庫元件。可被實例化的簡單的UI層級(模板),存在於Widget資源庫中。
——Widget庫資源文件。定義了一組Widget庫物體資源或依賴資源(的對應關係)的文件。
*Unity和UE中都有類似的結構,區分模板和實例是可編輯的UI框架的基本內容。另外幾處術語定義由於他們母語不是英文,所以有些用的名詞的準確性是存疑的。
*後面的內容包含了分享者提到的優化項的6個方面。

4 UI實例分類——Group UI Instances

層概念(1/3):定義

層概念(1/3):定義

——一個簡單的UI層包含:
  • 4個主要元件:事件委託、刷新處理器、控制器、動畫處理器
  • 獨立的資源管理系統
  • 定製化的獨立的繪製邏輯
層概念(1/3):類型

層概念(1/3):類型

——層類型:
  • 全屏(水印、系統體型、加載、遊戲提醒、菜單、視頻、HUD、相片模式、編輯器)
  • 遊戲世界中(世界物體、廣告、街邊告示牌)
  • 雜項(畫外項、Debug)
*這裡的offscreen從後文來看是一套預加載層
層概念(1/3):一些設想

層概念(1/3):一些設想

  • 異步的層刷新:異步遊戲控制刷新、異步執行生成請求(同步化的關聯處理)、異步的動畫刷新(同步化的參數應用處理)
  • 異步的層繪製:同步化的最終合併處理
  • 每層有獨立的多線程調度鏈
第一批UI層解耦完畢的時間點

第一批UI層解耦完畢的時間點

多線程UI框架方面的Take Away

多線程UI框架方面的Take Away

  • 提取所有獨立的計算項,並使它們異步進行
  • 使用獨立的渲染目標來異步繪製UI
  • 緩存一切必要的東西
  • 一幀中儘早開始UI的執行過程
*這裡可以看到CDPR在自研開發中也是從同步執行的原型到面向對象多線程逐步解耦的設計模式。任何3A項目放下中間件從零自研一個大模塊,一定是想尋求獨創特點的,這一點UE引擎給不了他們。

5 減少UI刷新——Reduce UI Updates

*這部分主要是關於視覺表現和邏輯執行拆分的。
激活與未激活的模式

激活與未激活的模式

  • 兩類邏輯執行模式:激活——UI傾向於是可見的、所有邏輯都被執行;未激活(Passive 被動的)——UI不可見、只執行關鍵邏輯。
  • 單獨層可以有不同的定製化。
  • 非常有彈性的機制。
UI術語定義——第二部分 控制器

UI術語定義——第二部分 控制器

——遊戲控制器:
  • 可以被幀調度執行(默認是關閉的。這裡tick是邏輯上執行一幀代碼的概念,我翻譯成幀調度)
  • 可以訪問所有遊戲系統
  • 被控制處理器管理
  • 只能被添加到UI實例上
  • 被一箇中央系統控制
  • 例如:車輛控制器、電梯控制器、小地圖控制器、紙娃娃控制器
——邏輯控制器:
  • 基於事件的(沒有幀調度執行的功能)
  • 僅包含UI邏輯
  • 只能訪問下屬的widget和UI層級
  • 可以被添加到任意widget上
  • 被用來功能性地擴展widget系統
  • 例如:按鈕邏輯控制器、審查邏輯控制器、滑塊邏輯控制器
*這裡censorship 審查、檢查,從後文來看這個是指需要基於審查標準動態調整的控件。
控制器的處理器

控制器的處理器

  • 包含一個特定層的所有控制器
  • 中心化的幀調度執行
  • 可以為每個控制器決定不同的調度模式
  • 傳遞一個遊戲內系統的context(上下文,指相關數據和狀態等)給遊戲控制器
  • 多線程執行
  • 決定所有遊戲控制器的生命週期
生成處理器

生成處理器

  • 生成UI實例默認是一個異步的過程
  • 每一幀有一個激活生成處理器的數量上限
  • 可以延遲或取消生成過程
  • 管理不同資源的加載過程
  • 可以通過對象池來重用同樣層級結構的UI
  • 隊列化關聯新實例(這裡指雖然生成加載是異步的,但是邏輯需要保證時序正確)
獨立的事件調度邏輯Take Away

獨立的事件調度邏輯Take Away

  • 基礎的事件邏輯是相對輕量級的
  • 嚴格控制基礎邏輯的幀調度
  • 如果可能就關閉幀調度
  • 避免大規模的數據拉取

6 減少UI動畫刷新——Reduce UI Animation Updates

動畫方面的挑戰

動畫方面的挑戰

  • 全部(UI控件)可動畫化的
  • 包含視頻
  • 幾乎所有文字都是需要本地化的
  • 基於玩家的選擇動畫可能有分支表現
  • 任何部分可能在任何時候被播放
UI術語定義——第三部分 動畫

UI術語定義——第三部分 動畫

——動畫定義(模板):將特定的動畫插值系統及事件定義,以特定順序配置在時間軸上的元件。順序和屬性在運行時不會改變。
——動畫插值系統:控制如何進行特定動畫插值的信息的元件。
——動畫實例:查找(對應)到動畫定義和儲存的插值參數,基於一些發佈的播放選項來播放動畫時間軸。可在運行時修改。
*這裡的插值系統可以理解成基於關鍵幀的動畫系統。
動畫處理器

動畫處理器

——激活模式:
  • 遞增的動畫時間
  • 異步的插值計算
  • 異步的參數提交處理流程(保持其基於依賴關係的順序)
  • 發出所有(幀上定義的)事件
——未激活模式:
  • 遞增的動畫時間
  • 發出有意義的事件
優化UI動畫的TakeAway

優化UI動畫的TakeAway

  • 內存中僅保持同一動畫的一份模板數據
  • 對每個實例使用輕量化的參數定義數據(metadata)
  • 只計算並運行對玩家可見的動畫效果
  • 對不可見的動畫只更新時間

7 UI實例剔除——UI Instance Culling

*這部分主要介紹了關於廣告物體層的處理,一般遊戲開發這部分內容不會劃歸到UI系統中,不過由於其介於場景物體和UI物體之間,他們這麼考慮也是有道理的。
引入廣告物體層概念的時間點

引入廣告物體層概念的時間點

廣告物體設計

廣告物體設計

  • 減少紋理內存:使用一張紋理圖集、多種不同的廣告佈局、重用渲染對象的內存(生成並繪製可見的物體)
  • 動畫廣告的可能性
  • 內容審查過濾器
  • 運行時的隨機化
  • 定製化的光照支持
圖集和佈局示意

圖集和佈局示意

每個廣告的可動版本

每個廣告的可動版本

右邊是和諧版 懂的都懂

右邊是和諧版 懂的都懂

有多少這種廣告牌? 圖中框出的都是

有多少這種廣告牌? 圖中框出的都是

實際運行畫面示意

實際運行畫面示意

玩家可視範圍優化

玩家可視範圍優化

  • 距離檢測
  • 視錐體剔除:旋轉、運動預測,慣性機制
  • 遮擋剔除:定製化的軟件實現
  • 屏幕覆蓋:“weapon plane”的問題。
  • 靜態紋理替換
  • “車內”情況:延後流式加載,跳過刷新或繪製
*由於沒有講解原文的文案,這裡實在不明白“weapon plane”是個啥問題。一般提到屏幕覆蓋大致就是基於其佔屏尺寸比例來進行刷新率、精度等各種維度的質量調整,但這裡不確定是不是這個意思。
可視範圍優化的TakeAway

可視範圍優化的TakeAway

  • 相對於普通3D幾何體,使用優化後的管線
  • 如果UI實例不可見,則設置為未激活狀態
  • 基於UI實例佔的屏幕比例調整渲染質量
*我能理解他們不把廣告牌作為環境物體而是UI的原因是其行為模式更接近他們定義的UI。What ever...

8 延遲刷新與繪製——Deffered Update & Draw

*這裡不是延遲渲染管線的那個延遲,而是指時間上的延後(其本來的意思)。基本上說的是 一套預加載機制,但是用的詞語都比較繞。
越來越多的UI實例

越來越多的UI實例

  • 5個全局的TV頻道,每個包含3個繪製pass
  • 車內過多UI實例
  • 巨量的圖標
——最終會導致視覺故障(顯示Bug)。
引入畫外層的時間

引入畫外層的時間

畫外層

畫外層

  • 混合在遊戲世界中和全屏幕的(渲染)方案中
  • 延遲處理
  • 不阻塞(線程)
  • 成對生效(UI資源與渲染對象)
  • 依賴於幀的狀態
  • 實例列舉:道具欄圖標、全局TV的疊加層、複雜特效的動態遮罩
畫外處理流程示例

畫外處理流程示例

*從左到右分別是:UI模板控件、預渲染的視頻、UI疊加層,它們共同構成了一個簡單的電視頻道顯示。
畫外渲染結果示例

畫外渲染結果示例

*這部分其實看圖看不出,但是用性能較低的設備玩過這遊戲的應該更有體會。
畫外層的一些TakeAway

畫外層的一些TakeAway

  • 儘量緩存和重用
  • 僅在一幀有空閒時間時使用它(作為畫外層處理)
  • 使用不同的獨立渲染對象做即發即棄式的管理(fire and forget是一個既有詞組)

9 3D空間中UI的HLOD——HLOD for UI in 3D-World

*這一節用路牌系統的渲染講了類似Mipmap的機制,只不過他們做成了一套LOD系統。
街邊路牌被提取到單獨層的時間

街邊路牌被提取到單獨層的時間

街邊路牌層的設想

街邊路牌層的設想

  • 類似廣告牌
  • 需要本地化,但不是隨機的
  • 在運行時進行集成
  • 在夜之城有成百上千這樣的路牌
  • 渲染目標快速的片元著色
渲染對象管理

渲染對象管理

  • 渲染目標片元著色的方案
  • 作為圖集渲染
  • 對渲染對象使用包圍層(wrapper 一般是一種加載結構或對象管理結構)
  • 複雜的匹配機制:支持各種邊緣情況、對圖標有特定渲染規則
  • 獨立的渲染對象池(3DUI和特效)
HLOD渲染對象的示例

HLOD渲染對象的示例

渲染對象管理的TakeAway

渲染對象管理的TakeAway

  • 在世界空間中UI常常是縮小後的
  • UI佔屏幕範圍是一個很好的衡量(需要)質量的指標
  • 在渲染對象的範圍內繪製到較小的區域,而不是縮小渲染對象本身

10 作者的總結

全部任務都搞定了(麼)

全部任務都搞定了(麼)

其它未提到但是也很耗時的工作(可以粗略看看 就不翻譯了)

其它未提到但是也很耗時的工作(可以粗略看看 就不翻譯了)

項目上線時間

項目上線時間

整體性的TakeAway

整體性的TakeAway

  • 截止時間和指標預算是你的朋友(高情商環節)
  • 代碼解耦和並行執行是非常重要的解決方案
  • 你需要有一個驚人的團隊來做驚人的事(高情商環節)
UI組的構成

UI組的構成

  • 最初包含3個開發人員
  • 最終包含了3個UI組(藝術、設計、編程)
  • UI編程人員的峰值:11個
*下面的感謝與特殊感謝就不翻了。最終這套UI系統雖然也在性能較低的設備上由於異步加載策略之類會有一些Bug,但比起遊戲主循環的Bug來說症狀還是輕很多了。

結語

讀了這篇分享我最大的感受是,他們對UI系統的拆分和理解和其它主流的商業引擎有著一定程度上的不同,這其中既有其優勢也有其實現彆扭的很多地方。但無論如何,分享人提出的這些課題是真切存在的,也正是這些內容極大地豐富了《電馭叛客2077》這款遊戲的視覺表現。
如果有一定開發經驗的讀者可能會感覺,他們總結的take away都是很基礎的思考,但是實現到這個巨型3A項目中還是非常困難的。一方面他們在工業化管線的設計上確實不如那些商業引擎公司,但另一方面他們也確實能開發出完全符合內部需求的UI模塊。
這裡可以Callback到持續會被討論的“是用自研引擎還是用UE之類商業引擎”這個辯論上來。顯然作為一個前作大量使用中間件搭起來的開發團隊,這一作他們付出巨大努力搭建自己的UI系統,又何嘗不是一種還技術債的過程呢;如果使用UE,或許這裡面大部分的事項他們可以更高效的完成,但可能其中很少的一部分特性就幾乎無法實現。
或許得益於人力成本上的優勢,或許是這個產品作為光追展示最強遊戲的地位,又或許是DLC《往日之影》贏回的極大聲譽,總之得益於最終還不錯的商業成績,這群思路清奇的波蘭人在這款遊戲中完成了他們RedEngine的極大進化,應該可以在下個項目輕裝上陣、有備而戰了。

最後是資料鏈接:
User-Interface-in-Cyberpunk-2077 GDC文檔地址

© 2022 3樓貓 下載APP 站點地圖 廣告合作:asmrly666@gmail.com