圖形子系統是渲染層中圖形相關子系統的最高層. 它基本上是Mangalore圖形子系統的下一個版本, 但是現在整合進了Nebula, 並且與低層的渲染代碼結合得更加緊密. 最基本的思想是實現一個完全自治的圖形”世界”, 它包含模型, 燈光, 還有攝像機實體, 而且只需要與外部世界進行最少的通訊. 圖形世界的最主要操作是加入和刪除實體, 還有更新它們的位置.
因為Mangalore的圖形子系統跟Nebula2的完全分界線從Nebula3中移除了, 很多設想都可以用更少的代碼和互動來實現.
圖形子系統也會為了非同步渲染而多線程化, 它和所有的底層渲染子系統都會生存在它們自己的fat-thread中. 這本應是Nebula3階層中更進階的東西, 但是我選擇了這個位置, 因為這是遊戲跟渲染相關通訊最少的一部分代碼. 正是因為圖形代碼有了更多的”自治權”, 遊戲相關的代碼可以跟圖形以完全不同的幀率來運行, 不過這需要實踐來證明一下. 但是我一定會嘗試, 因為完全沒有必要讓遊戲邏輯代碼運行在10幀以上(格鬥遊戲迷們可能會反對吧).
圖形子系統中最重要的公有類有:
- ModelEntity
- CameraEntity
- LightEntity
- Stage
- View
一個ModelEnity表示了一個可見的繪圖物件, 它包括位置, 包圍體和內嵌的Model資源. 一個Model資源是一個完全的3D模型, 包括幾何體, 材質, 動畫, 層級變換等…(後面會提到).
一個CameraEntity描述了圖形世界中的一個視景體, 為渲染提供View和Project矩陣.
一個LightEntity描述了一個動態光源. Nebula3的光源屬性還沒有最終確定, 但是我的目標是一個相對靈活地近似(最後一個光源不會超過幾個shader參數).
Stage和View是Nebula3圖形子系統新增的內容. 在Mangalore中, 圖形實體是生存在一個單獨的圖形Level類裡, 任何時候只能有一個Level和一個攝像機. 這對於只需要渲染一個世界到幀緩衝(frame buffer)的情況來說還是不錯的. 但許多遊戲程式需要更複雜的渲染, 如在GUI中渲染一個使用單獨燈光的3D對象, 而它又跟其它的圖形世界是隔離的. 還有反射或像監視器之類的東西都需要一個額外的視口, 諸如此類. 在Mangalore中, 這個問題通過OffscreenRenderer類得到解決, 雖說比較容易使用, 但是具有一些使用限制並且需要更多事後的思考.
Nebula3提供了一個基於State和View的更加簡潔的解決方案. 一個Stage就是一個圖形實體的容器, 表示一個圖形世界. 同一時間可能存在多個Stage, 但是它們之間是互相隔絕的. 每個實體在一個時刻只串連到了一個Stage(雖說複製一個已有實體是一件很簡單的事情). 除了簡單地把實體組織到一起外, Stage的主要工作是根據它們之間的關係來加速可見度查詢. 應用程式可以派生Stage的子類來實現完全不同的可見度查詢方案.
一個View對象通過一個CameraEnity渲染stage到一個RenderTarget. 任何stage都可以串連任意數量的View對象. View對象可能會互相依賴(也可能是串連到不同stage的View), 所以更新一個View會首先強制更新另一個View的RenderTarget(這在一個View渲染需要使用另一個View的RenderTarget做為紋理時很方便). View對象完全實現了自己的渲染迴圈. 應用程式可以在View的子類中方便地實現它自己的渲染策略(如每個light一個pass VS 每個pass多個light, 渲染到cubemap, 等等).
總而言之, 一個Stage完全控制了可見度查詢流程, 而一個View則完全控制了渲染流程.
圖形子系統的一個最主要的工作就是根據可見度查詢的結果來決定哪些實體需要被渲染. 一個可見度查詢在實體間建立了一個雙向的連結, 它有兩種形式: 攝像機連結和燈光連結. 攝像機連結把一個攝像機和在它視景體內的模型串連到了一起. 因為連結是雙向的, 所以攝像機知道所有的在它視景體範圍內的模型, 而模型也知道所有可以看到它的攝像機. 燈光連結在燈光與模型之間建立了相似的關係, 一個燈光具有所有受它影響的模型的連結, 一個模型也知道所有影響它的燈光.
加速可見度查詢最重要的類就是Cell類. 一個Cell是一個圖形實體和子Cell的可見度容器, 它必須遵循2條簡單的規則:
- 如果一個Cell是完全可見的, 那麼它所有的圖形實體和子Cell都必須可見.
- 如果一個Cell是完全不可見的, 那麼它所有的圖形實體和子Cell都必須不可見.
Cell是附屬於Stage的, 它們形成了一棵有根Cell的樹形階層. 標準的Cell支援簡單的空間劃分方案, 如四叉樹和八叉樹, 但如果像其它的可見度方案, 如portal, 就需要派生Cell的子類來實現了. 子類唯一的功能限制就是上面標出的那兩條規則.
當一個圖形體串連到一個Stage時, 它會被插入”接受” (通常僅僅是容納)它的最低級的Cell中. 當更新圖形實體的變換資訊或改變包圍體時, 它會根據需要改變在Cell層次中的位置.
Stage居住在StageBuilder類當中, 應用程式應當派生StageBuilder來建立一個Stage的初始狀態(通過加入Cell和實體). Nebula3會提供一些標準的StageBuilder集合, 這應該能夠滿足大多數應用程式的需要了.
這隻是圖形子系統的一個粗略的概述. 因為當前只有一個最基本的實現, 很多細節接下來可能會有所更改.