新的一年,又拿到了五天學習日
今年大概有三天要用來讀它了,經典神書一本
我以前的思考方式都是往深處去想去鑽研
而偶爾看一下這種往廣處看的書籍也不錯
接著的筆記會寫得很零散,因為我邊看邊寫,再來就是原文書不免一堆廢話那些我會跳過
我自己的看法會標上"編按"兩個字
==================================================================
§Chapter 1 - 介紹
每本書都會有的介紹環節
- 從這本書可以學到
- 企業強度的遊戲引擎怎麼架構的
- 遊戲開發團隊怎麼組織起來的
- 遊戲引擎中有哪些常見的子系統以及設計模式
- 每個子系統的需求
- 哪些子系統是跟遊戲種類相關或無關的,或者甚至是為了某種遊戲種類設計的
- 遊戲引擎的部分會在何時收尾,然後開始遊戲設計
- 一窺熱門引擎的內部運作
- Quake, Unreal, Unity, 中介軟體像是Havok, OGRE, Granny 3D也有
- 也會探索像是頑皮狗的自有引擎 (編按: Hmm但是最近頑皮狗的狀況...)
- 本書假設讀者有著一些C++, 線性代數, 三角函數等等遊戲常見基本數學的基礎
- 編按: 結合其他語言其實也很常見, 例如gameplay腳本用python, 編輯器用C#, 但runtime核心實在很難因為效能而放棄C++
- 一個遊戲開發團隊的結構
- 工程師, 大致分成runtime工程師(撰寫引擎及遊戲本身), 以及工具工程師(撰寫離線工具讓團隊工作更有效率), 兩邊又會再依專業專注在某一種系統上, 像是繪圖, 物理, AI, 音效或是玩法等等
- 美術, 包含提供大方向的概念美術, 3D模組美術, 貼圖美術, 光照美術, 動畫美術等等
- 遊戲設計師, 決定玩法、遊戲方向的重要人物
- 製作人(Producer), 職責會因公司有所不同, 有些是管理專案的排程, 有些像是人力資源的主管, 有些則是作為開發團隊以及事業單位的聯絡窗口 (資金, 法律, 營銷等等), 小公司甚至連製作人都沒有
- 其他員工, 主要是支援開發團隊的團隊, 典型的例子就是IT部門
(編按: 書上副標真的給我寫Other Staff..別把IT大大們當雜魚啊!他們很辛苦的)
- 發行商以及工作室, 像是EA, THE, Vivendi, Sony, 任天堂等等. 很多工作室並不隸屬於一個特定的發行商, 誰出的方案最好工作室就賣誰. 而有些工作室則是有簽約合作的, 也有像是頑皮狗這種直接隸屬發行商的工作室
- Runtime引擎架構
- 目標硬體、裝置驅動
- 作業系統, PC就不說了, 早期的家機作業系統是直接編譯到遊戲裡的, 也就是在那時一款遊戲會"獨佔"整台機器, 但現在不同了, 我們都知道家用機也可以邊玩邊跑背景工作啦~
- 第三方SDK以及中介軟體, 從程式SDK到一些現有的系統都有
- C++ Boost
- DirectX/Vulkan (編按: 書上舉OpenGL, 但我認為現在是VK時代)
- Havok, PhysX
- (編按: Oodle貼圖壓縮、Umbra Occlusion Culling、Wwise音效也被廣泛使用, 所以自製引擎有的時候也不是100%都從零建起, 如果第三方插件更符合效率及成本那採用了一點也不可恥)
- 核心系統, 包含Assertion, 記憶體管理, 數學函式庫, 自製資料結構/演算法等等
- 渲染引擎, 架構上有很多種不同方法可以使用
- 從Low-Level的Draw Call, Shader到High-Level的Component等等
- Culling優化
- 視覺特效, 包含粒子, 貼花, 後製特效等等
- HUD, GUI
- 解析與偵錯工具, 主要當然是為了捉Bug以及優化遊戲, 常見的例子如:
- 程式碼執行時間的測量
- 顯示統計數據
- 將數據輸出成文字檔或Excel
- 記憶體使用量追蹤
- 各種類型的偵錯訊息, 還要可以分成各種類型來回報
- 錄製遊戲事件以及重播的能力, 這很難達成, 但如果做得好將會是相當有價值的工具
(編按: Forza Horizon系列不只能用來偵錯, 甚至連遊戲中都能讓你倒帶再來啊!)
- 碰撞與物理, 沒了它遊戲就會很奇怪, 你可以穿越來穿越去...
- 動畫
- HID, 鼠鍵操作或搖桿, 還有針對遊戲類型發展出的方向盤組, 釣魚竿, 跳舞池等等
- 音效, 也很重要但相比於渲染, 物理, 動畫, AI, 玩法被得到的關注不多
(編按: 講真的作為玩家, 還真的比較注意作曲合不合, 調完音量設定就沒在動別的)
- 多人遊玩/連線, 大家都很熟悉了, 古早時期甚至還有切割螢幕的做法
- 玩法系統, 這個會因遊戲類型不同而改變
- 各種編輯器, 管理素材的工具
§Chapter 2 - 工欲善其事, 必先利其器
在研發引擎之前, 有些工具是必要的可以增進效率的, 很短的一章
- 版本管理, SVN, Git, Perforce等等, 萬一專案炸了還可以回溯
- IDE, 當然
- 記憶體洩漏以及碎塊偵測
§Chapter 3 - 遊戲軟體工程的基礎
這章進入程式部份了, 資工出來的應該可以跳掉大部分的內容, 都學過了
- 本書主要聚焦在C++, 介紹了一些物件導向的東西
- 設計模式, 作者舉了幾個例子
- Coding Standards, 可以幫助專案的程式碼提升可讀性, 維護性, 每個人流派不同而本書作者認為蠻重要的幾點:
- 介面乃王! 盡量讓你的.h檔保持簡單乾淨最小化, 易懂以及適當註解
- 好的命名
- 別什麼都放在全域命名空間, 但也不要過度使用自訂命名空間, 尤其是巢狀太多層
- 跟進所有你聽過的C++ Best Practices
- 保持一致性, 修改現有的程式碼, 盡量跟著已存的標準
- 介紹錯誤處理, 資料型別等等
§Chapter4&5 - 平行化以及並發程式設計與遊戲中的3D數學
又是些資工大二還大三會學到的東西
沒有相關基礎的讀者可以考慮看
(如果有CS底子, 只想單刀直入遊戲引擎系統的部分, 3~5章基本上可以跳過了)
Part II Low - Level引擎系統正式開始
==================================================================
§Chapter6 - 引擎支援系統
任何遊戲引擎都需要一些low-level的支援系統, 用來管理乏味但重要的工作
像是引擎的啟動、關閉、設定、提供各種素材的編輯等等
- 子系統的啟動/關閉, 假設子系統之間又交互依賴, 那初始化順序一定要注意
- 書上舉了幾個例子, 像是直接在建構/解構子做初始化或釋放, 或是實作startUp()/shutDown()函式
(編按: 我個人較喜歡後者, 因為建構/解構子跟life cycle綁在一起, 我不一定只會在引擎要被清掉的時候才shutdown阿)
- OGRE的例子: 宣告了一個Root Singleton, 裡面包了一堆Manager
- 頑皮狗引擎的例子: 夾雜一堆全域變數的Init()呼叫且有特定順序
- 記憶體管理
- Stack-Based配置, 讀了一關就配置記憶體, 一旦配置後就幾乎沒有動態記憶體的配置, 那麼離開了這一關就把資料都清除掉, 簡單易實作
- Pool配置, 遊戲引擎相當常見的方法之一, 通常會建立一個超大區塊記憶體然後再分給遊戲物件共用
(編按: 這理念用在VRAM也適用, 像是在Vulkan可以建立超大vkMemory物件, 再在有需要的時候綁定+上傳)
- 記憶體碎塊, 解決方法不外乎過一段時間就重新定址一次, 把碎塊擠出來集中在一起
- 由於牽涉到記憶體複製, 這個操作其實很重
- 所以Divide and Consuer很重要, 不用強求一定要一次搬一大塊, 分成好幾塊/好幾個Frame來搬
- Container, 遊戲中用到的陣列那些等等, 有些時候甚至是自製的
- 字串與在地化, 非英語系開發者都會面臨的問題
- 引擎/遊戲設定的存取
- 文字檔, 最常見的方式, 像是OGRE使用了INI, 而JSON, XML也有人在用
(編按: 之前GTA5讀取時間太長的問題就是JSON檔沒處理好)
- 壓縮過的二元檔, 早期家機所需, 畢竟那時儲存裝置不發達. 而自SNES之後幾乎都有記憶卡帶了, 遊戲設定有時候會跟著遊戲存檔紀錄在一起
- Windows登錄檔, 作者極不建議這個方法! 因為資料可能會因為系統更新、重灌之類的而損毀
- Command line參數, 像是UE4Editor.exe -run=DataValidation這樣, 根據Command line (argc, argv)來決定引擎開啟後的動作
- 環境參數
- 線上使用者檔案, 例如Xbox Live
§Chapter7 - 資源以及檔案系統
遊戲是個多媒體的體驗, 那有各種類型的素材要存取也不奇怪
- 檔案系統, 會因OS而有所不同, 但一定包含檔案名稱以及目錄
- 資源管理器, 大致上分為兩種, 第一種管理用來建立並轉換成引擎可使用的離線工具, 第二種則是管理Runtime確保資源在被需要之前就讀進記憶體、並在不需要的時候釋放
- 離線資源管理的要求
- 管理多種類型資源的能力 (例如UE4的Content Browser)
- 建立新資源的能力
- 刪除現有資源的能力
- 調查/編輯現存資源的能力
- 移動資源的能力
- 資源間互相參考的能力 (例如一個material被一個mesh參考)
- 維護資源參照的完整性 (例如刪除了正在參考中的資源, 應該要把來源都設定為nullptr)
- 維護版本歷史的能力, 記錄了誰做了變化以及為何
- 能搜尋素材的話會很實用
- Runtime資源管理的要求
- 確保每種獨立的素材在記憶體裡只有一份 (像是10種不同材質用到同一張A貼圖, 這個A貼圖沒理由要被讀取10次)
- 管理所有資源的生命週期
- 讀取需要的資源/釋放不需要的資源
- 能處理組合型資源, 例如一個3D模型包含網格、一種或多種材質、一張或多張貼圖等等, 也可能有骨骼動畫
- 能保持資源參照的完整性
- 管理資源的記憶體使用
- 提供客製化流程, 決定資源讀取後的動作 (以UE4為例就是OnPostLoad)
- 假若引擎有支援, 須能處理串流 (非同步讀取)
- 資源建議一定要有類似GUID的識別碼
- 處理資源之間的交互參考, 挺有挑戰性的
- 例如用GUID來辨別, 資源管理器需要維護一個全域的資源查找表, 當資源讀入記憶體時, 用GUID作為Key, 並儲存該物件的Pointer. 在交互參考時進行查表即可
- Post-Load的初始化
- 對於一些狀況是不可避的, 例如讀進3D網格後, 為了順利渲染, 必須在網格讀取後建立Vertex Buffer或Index Buffer然後上傳到VRAM
- 一些情況則是可避免但提供一些便利性, 例如在初始化的時候計算一些數值而不用去動到素材, 加快測試的速度, 最後再移動到離線工具裡
==================================================================
呼~803/1876頁, 下次會從第八章遊戲迴圈/Runtime模擬繼續看
今天就讀到這了, 遊戲引擎設計可以說是相當的自由, 各家實作細節也有所不同
但概念上其實很多是共通的, 開發者們都在類似的規則下, 追求神之一手阿