實現快速迭代的引擎設計 - Capcom RE Engine的架構與實現


[譯]實現快速迭代的引擎設計 - Capcom RE Engine的架構與實現

原文(日文):ラピッドイテレーションを実現するゲームエンジンの設計

CEDEC2016上的一個Session。基本上是根據PPT的翻譯(可能成為筆記更恰當一點),夾雜了一些現場聽來的信息。PPT里有很多優點舉例基本沒什么營養就省略了。沒正經的翻譯過文章,有錯誤歡迎指正。主要是來抱囧聚大腿的。

以下正文:

引擎簡介

  • RE Engine是Capcom內部開發的次世代游戲引擎
  • 支持PS4,XboxOne,PC(Steam/UWP)等平台
  • 應用於開發中的項目生化危機7
  • 引擎特征:高性能,高開發效率 <- 本文主要內容

游戲開發循環

  • 編程 → Build → 確認 → ...
  • DCC工具編輯 → 資源轉換/導出 → 確認 → ...
  • 游戲啟動 → 測試/試玩 → 參數調整 → ...
  • QA → Bug修正 → 打包 → ...

傳統開發流程中,上面各個步驟不是費時間就是需要大量手工操作,效率相對低下。 

快速開發的實現

→ 最終節省下來的時間用來提升游戲質量

  • 減少等待時間(主要是Build以及資源轉換等)
  • 減少每回試錯的時間
  • 提高在運行環境(特別是主機上)中運行的頻率
  • 降低Bug率

RE Engine界面(譯注:基本與UE4或Unity相近,支持所見即所得的編輯方式) 

一些細節

  • 生化7目前大約有20萬行C#
  • Editor里可以直接運行(整體更像UE4一點),支持所有資源的重新載入
  • Scene是樹狀結構,有一個Master Scene,里面有Chapter1Scene等,導出Master Scene就等於是打包游戲。隨着游戲流程Load/Unload Scene
  • 演講的 石田 智史 就是設計了MT Framework的人

Scene的結構示例 

----------------------------------------------------------------------------------------------------------

引擎架構

(譯注:演講包括了新舊引擎的對比,但舊引擎的參考價值不大,故基本省略) 

  • 工具架構(Editor)
    • 工具和Runtime用TCP/IP通信同步
      • Runtime就算崩潰了Editor也能繼續運行
      • Runtime包含了各個平台的實現(如PS4的Runtime)
    • 工具部分用WPF/C#開發,運行於Windows平台
    • 問題點
      • Runtime使用C++,而工具使用C#開發(包括游戲邏輯)
      • 通信同步導致大量操作需要異步的實現,增加了復雜度
      • 通信受限於傳輸速度
    • 解決方案
      • 統一通信協議:二進制通信,用C#的定義生成C++代碼,Query/Response形式
      • 遠程對象系統:跨語言,跨進程的標識對象
        • RuntimeType,RuntimeObject跟C#自己類似,成員貌似只是key-value對
        • 通過ObjectID來同步(ID的正負來標識Editor/Runtime)
        • 以手動同步為主,也可以注冊進Observer來監視更新,對性能有影響
        • Gizmo之類的輔助對象也采用類似的方法實現
      • 優點
        • Runtime可以自由切換
        • 可以對應一些只能在實際環境確認的功能(VR,手機等)
        • Runtime經常會崩潰ww
  • 資源架構
    • File-Based(舊)→ Asset-Based(新):文件更容易產生冗余,並且不利於Reload
    • 所有資源支持異步更新,用Cache加速資源轉換,根據依賴關系優化打包速度
    • 問題點
      • Scene加載的時候需要預載入所有資源
      • 引擎需要把握資源的載入順序
      • 需要實現異步載入的功能
    • 解決方案
      • 靜態資源依賴關系生成
        • 導入Asset的概念:在文件里追加了Metadata
          • 工具啟動的時候載入所有的Asset,並生成依賴關系
        • 禁止代碼控制的資源載入(譯注:是不是完全不支持動態載入沒有細說)
      • 嚴格的資源管理(譯注:聽起來自由度相當低,但畢竟是內部引擎估計可以根據實際需求調整而不用Hack)
        • 禁止同步載入(容易導致Spike),並且異步載入有利於整體吞吐量
        • 強制實現Reload
        • 從游戲代碼不能直接訪問資源

資源依賴關系示例 

  • 腳本架構
    • 舊引擎開發游戲即使用上分布式Build多的時候也要15分鍾,並且容易崩潰,內存破壞
    • 新引擎開發游戲時,游戲的邏輯部分完全使用C#,Build最多10秒,內存管理更好
    • 問題點
      • C#比C++更慢(Marshal,異常)(譯注:猜測Marshal應該主要是與SDK的交互或者與第三方庫的交互)
      • GC導致的長時間停止
      • 主機平台兼容性差(JIT禁用等)
    • 解決方案
      • 自制C#虛擬機(REVM)
        • 以AOT為前提,不支持JIT
        • 提高C++親和性,降低Marshal開銷
          • 重寫C#對象布局 ↓ ,包了一層C++對象在里面,Marshal的時候可以直接傳指針。RC為引用計數。
          • C# → C++:利用Clang解析C++代碼,生成供C#訪問的接口,最終和直接調用C++函數開銷相同
          • C++ → C#:利用template,最終和函數指針開銷相同(譯注:黑魔法沒仔細看。。。)
        • 更輕量的標准庫(從Core FX搬)
        • 編譯
          • 開發時:MicroCode(IL不適合解釋執行,自制MicroCode) → 解釋執行
          • Release時:C++(il2cpp)→ 編譯(Marshal部分inline展開)
            • 編譯時間:分散編譯15分鍾左右(跟舊引擎相近)

C#的編譯流程(Release時生成C++代碼) 
C#與C++的運行速度比較(有了GC當后盾對象生成快了很多) 
開發時與實際運行時的效率比較(譯注:可以看出來開發時候也不是特別慘) 

  • 自制實時垃圾回收(譯注:有些概念不太懂就沒詳細解釋了)
    • 現有的GC不適合游戲
      • 分代GC:Major GC導致的長時間停止
      • 並行GC:GC執行中的速度低下,需要足夠的空余內存
      • 自動引用計數方式:循環引用的泄露,對引用計數操作的高Overhead
    • 適合游戲的實時GC(FrameGC)
      • 限定於游戲應用
      • 主循環的同期點
      • C#作為腳本的前提
    • 特征
      • 預測,可控的停止時間(GC中)
      • 即時釋放性(譯注:用完的內存盡早釋放)
      • 可以更有效的利用所有內存
      • 在多核環境下發揮性能
      • 與C++的親和性
    • GC算法(譯注:原ppt內有簡單的流程動畫說明可供參考)
      • LocalObject:TLS,存在LocalTable里(當然也是TLS),C#生成的對象都作為LocalObject
      • GlobalObject:所有線程都能訪問,C++生成的對象都作為GlobalObject
      • LocalObject → GlobalObject(譯注:有點類似C#的Box只不過這里不是stack和heap的區別而是可訪問線程和所屬Table的區別)
      • LocalFrame GC:C#的函數調用都結束的時候執行,釋放所有LocalObject(譯注:跟函數調用完了退棧差不多)
      • Local GC:LocalTable滿了的時候執行,根據引用計數釋放LocalObject(實際很少發生)
      • GlobalObject 釋放
        • 由各個線程增減引用計數,為0了就釋放
        • 當沒有所有線程里都沒有C#的棧(C#的調用都結束)的時候,執行Global GC(釋放所有被有被用到的)
      • 循環引用由Incremental Cycle GC釋放
        • (譯注:基本上就是掃一遍找出循環部分)
        • 每幀Check循環引用的輔助表CycleRoot,按需GC
    • FrameGC的Overhead
      • Write Barrier:線程內的直接Check引用計數,跨線程的利用InterlockedCAS
      • LocalObject→GlobalObject:類似↑

FrameGC的一幀的Profile結果(譯注:整數估計是Profile的Sample數)

----------------------------------------------------------------------------------------------------------

總結

  • C#就是好!
    • 生產效率大幅提升
    • 杜絕應用層(游戲邏輯)產生的崩潰情況
  • 執行效率沒有問題!
    • REVM比寫的挫的C++更快
    • FrameGC改變了GC不適合游戲的常識

----------------------------------------------------------------------------------------------------------

現場Q&A

    • C#版本? 6.0 但是因為造了GC所以不算完全支持。
    • 支持yield嗎?應該不支持(?),C#的部分不支持跨幀的處理。
    • 開發人數?開始2人 x 3個月,后來加了5,6人又做了幾個月。(譯注:聽起來有點快的可怕,不過去年CEDEC的時候就有相關消息了所以實際應該更長一點)。感謝評論里@大薩比補充,現場有提到了開發速度快是因為RE引擎基於panta rhei開發。
    • 序列化用了什么?第三方庫?沒有,因為涉及到ID之類的問題所以自己寫了。
    • 轉成C++代碼的時候出現問題了怎么辦?那是bug...初期會有,現在已經基本沒有了。順便轉出來的C++代碼很長,VisualStudio會打不開...
    • 游戲部分完全是C#嗎?完全是。
    • 如果開發游戲的那邊提需求呢?因為是內部引擎所以可以商量,但不會讓他們直接改。
    • 場景中的頂點數之類的統計數據可以取得嗎?Asset的meta信息里有,可以做。但是美術基本不關心這個....
    • WPF的框架?Livet。
    • 中間件是集成到引擎里?是的。
    • 對中間件有什么要求?省內存,跑的快(笑)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM