Turn 10是微軟遊戲的一個內部工作室,專注於賽車遊戲。在 Froza III 中,一條賽道可以長達13英里。開發者希望有良好的載入效能,賽車從靜止到200英里/時的高速移動都保持一致的高畫質,沒有物件突變,同時保持60fps。

本講座首先介紹了遊戲的5層儲存層級,闡述資源如何從dvd達到處理器,如何最佳化Disk IO與CPU快取。接下來,解釋離線計算的遮擋剔除演算法,以及其流式載入的工作集管理。

video

https://www。

gdcvault。com/play/10123

35/Streaming-Massive-Environments-from-0

ppt

https://www。

gdcvault。com/play/10126

56/Streaming-Massive-Environments-from-0

Turn 10的全職開發者約70人,會隨著開發週期人員增加(主要是美術)。

Forza III 是一個xbox360遊戲,賽道資料量極大,無法全部裝入xbox360的512m記憶體。遊戲的哲學是,動態載入越多越好,“除了載入本身,其他都是動態載入的”(按:實際上還是做了個別權衡,見後文)。

遊戲中典型的賽道Le Mans有約6000模型和3000貼圖,賽車賓士7分鐘行駛1。6圈,總載入量為0。98G,遠超賽道的總資料量。具體來說為:

0。14G Mesh

0。84G Texture

Steaming的儲存層次結構

[筆記][大地圖管理] Streaming Massive Environments from 0 to 200 MPH, GDC2010

上圖是載入的層次結構,資料從釋出介質——硬碟或者光碟,逐級向上達到處理器。我們逐層解釋細節。

1.Disk

首先,賽道以zip格式壓縮,使用微軟自有的 lzx 演算法。xbox的專用lzx庫提供 20M/s 解壓速度,是開發者找到的最快演算法。單賽道壓縮後90~300MB,壓縮率50%。

2.Compressed Cache, 56M

xbox360使用的雙層dvd 有 10M/s 的平均讀取速度,但是單次 seek 可耗時100ms。

所以這裡使用一個快取,隱藏 IO。每次從zip中連續讀出一個固定大小資料塊,可包含上百個檔案,不解壓。

資料塊 1/4M~ 1M(預設)

由賽道配置,僅在效能不佳時微調

讀取觸發,LRU換出

在訪談最後的磁碟檔案排序部分,我們將看到檔案如何儘量聚集。

3.Decompressed Heap,194M

這一步從快取解壓到記憶體。解壓後資源記憶體地址連續、對齊,可以直接由CPU、GPU使用。

記憶體碎片

記憶體碎片是長期執行堆的一個常見問題。

堆分配演算法為地址排序的First-Fit,這是一種公認的碎片極少的演算法。

資源按zone載入,每批置換2~20M不等。zone切換時,為減少碎片,要注意先一次性解除安裝所有待刪除資源,再進行載入。

LOD管理

和一般遊戲不同,物體的各LOD拆散儲存,可以只加載所需的LOD

mip分了三檔。 後面的工作集管理會提到具體用法。

高:Mip0

中:Mip1~1*1

低:32*32~1*1

xbox硬體允許mip鏈引使用多塊不同記憶體,所以可以免費分開載入。

注意這裡的記憶體預算。層次2加上層次3共250M,為xbox360總記憶體的1/2。56 : 194 這個比例是長期試驗後微調出來的。

4.GPU/CPUCache

主機遊戲程式設計中,很多專案都會關注處理器快取命中率。密集計算,需要使用快取友好的演算法。

以遊戲的視椎體裁剪為例:每個項根據cache大小設計,資料組織為線性,線性遍歷,所以快取命中率非常高。

另外,遊戲大量使用了Command Buffer,包括所有的道路、很多渲染子系統。這樣只需要提交渲染資料,計算過程全部在GPU上。(按:這個為啥在cache這一節)

5.GPU/CPU

減少不必要的貼圖和頂點的傳輸。(按:細節資訊量少,不錄了)

預計算遮擋剔除

作者認為,實時的遮擋剔除演算法不夠好。他們往往使用近似的保守演算法,返回偏多的待渲染物體;同時,需要簡化的幾何資料,帶來巨大的資料量壓力。所以本作遮擋剔除是離線預計算的。

直接返回LOD

基於貢獻的剔除(Contribution Rejection),可見畫素過少也被剔除

[筆記][大地圖管理] Streaming Massive Environments from 0 to 200 MPH, GDC2010

基於貢獻度的剔除

遮擋剔除分為下面幾個步驟:

1.取樣,得到zone的可見表

美術用spline標記路的內外邊界,構成線性路線

等分成zone,等間隔取樣,如圖

[筆記][大地圖管理] Streaming Massive Environments from 0 to 200 MPH, GDC2010

計算可見性:每個取樣點,按賽道當前朝向(例如上坡),先以90°視角渲染4張深度圖,然後重新渲染一遍,統計各物體畫素數。

隨後,可見性向外擴散1格,以便消除臨近點的跳變。(按:個人感覺,本步擴散無意義)

累加得到:

每個zone

可見物體表、各物體的最大畫素數

模型、貼圖表

全賽道的模型、貼圖表

注意這裡過大的模型,會自動切分為小模型,增加剔除機率。

2. 計算工作集

前面提到了貼圖的mip分為高、中、低三檔檢視,高為mip0,中為mip1~1*1,低為32*32~1*1。賽道所有低檔(32*32以下)mip常駐記憶體,總在工作集中,20~60M不等。這是一個權衡,優點是任何模型載入好就可以立即顯示。

然後我們計算單個zone的工作集。相鄰3個zone可見物體合併,這就是理論上需要載入的物體。下一步透過丟棄貼圖的方式,得到合適的工作集。由於貼圖資料大概佔85%,有很多丟棄空間。演算法:

可見畫素小於32*32的話,丟棄最高和中間級貼圖。

記憶體限制:按可見畫素數從小到大,依次丟棄最高階貼圖、中間級貼圖,直到工作集可以在Decompressed Heap(194M)中放下。

頻寬限制:按最高移動速度計算出 zone n-1 到本zone的時間,乘估計的載入頻寬,算出最大載入量。繼續丟棄貼圖,直到兩工作集之載入差小於頻寬限制。

最終,zone實際工作集差 2~20M,其中貼圖佔大概 85%。直路工作集變化很小,最大的變化會發生在轉彎處。

3.磁碟檔案排序

為了提高磁碟載入的快取(56M)命中率,需要讓資料儘量集中。所以整個地圖的模型和貼圖,按看見的順序排序。效果會是:

植被集中在頭部

地形塊延zone線性分散

(按:所以同一賽道,同一資源只有一份;不同賽道之間,資源會有重複)

效能手工微調

最後,測試中仍然會有出現跳變。跳變主要為下面兩種情況,但是他們相互衝突:

頻寬不足,載入晚了 —— 需要減少載入量

沒載入可見物 —— 需要增加載入量

主要解決方案:

提供工具,人工對模型和貼圖做加減權(bias)

如果無效的話,美術需要減少場景複雜度

演示效果和其他

[筆記][大地圖管理] Streaming Massive Environments from 0 to 200 MPH, GDC2010

整個流式載入演示過程見54:05。從影片來看:

實際上實現了基於zone的、考慮了遮擋的流式載入。

遮擋剔除完全是依賽道的賽車視角,相當狠。由於賽車很低,所以中距離的個別低矮的田地都會被遮擋不載入。如果鏡頭抬高,可能這演算法不太夠用。

其他我覺得有用的細節

自動修正美術的資源冗餘

貼影象素比較去重:有的美術就是會複製貼圖

逐級比較mip差異,自動縮小貼圖:最佳化各種純色和漸變貼圖

由於用了Instancing,所以認為合併 mesh 的價值不大

資源匯出時,會預檢查model的結構,拆出公用子模型,保證Command Buffer的draw儘量少。(說得不是太清楚)

GPU Instancing的時候附帶一個自定數值(顏色;風力之類),讓美術用同樣的資源產生多樣性