RAGE的megatexture介紹

有圖的PDF在這裏

 http://files.cnblogs.com/puzzy3d/RAGE來了-Megatexture信息更新.pdf

 

沒圖的發這裏:

 

RAGE來了

---關於 ID TECH 5 MEGATEXTURE 的一些技術信息更新

H3D 姚勇

信息 1

介紹 2

一,目的 2

二,實現 2

1,預處理 3

1.1貼圖預處理 3

1.2 幾何預處理 7

2,繪製 7

3,具體步驟 8

3.1 判斷本幀繪製要用到哪些page 8

3.2 讀入貼圖page 10

3.3,渲染 12

4,鏡頭快速轉動與移動時 14

5,一些問題 14

總結 15

 

信息

很久很久以前,ID TECH 5有風聲時,我曾經查到一篇論文。就當時id software公司的MEGATEXTURE 技術做了一些介紹。是關於Clipmap的。 id software採用此技術製作了《Quake War》之後,公司很快更新了ID TECH 5MEGATEXTURE v2.0),採用了類似Virtual Texture的技術,做到了地形和場景物體都使用一張超大全細節貼圖做texture streaming。 如今RAGE已經發行。作爲id技術fan買了PS3正版之後,很失望......  遊戲體驗,尤其在貼圖繪製上很糟糕。後來發現在PC上的體驗其實不錯。貼圖loading的感覺較小。原因大概因爲id softwarePS3上優化的不夠或者PS3架構就不適合id tech5 

Clipmap 是用於地形渲染的。 優點是繪製超大細節地形紋理,不受顯卡顯存限制,而且不需要過多預處理過程。 在使用ID TECH 5技術的《RAGE》中,不再使用clipmap。而是使用一種基於virtual texture的技術 。關於virtual texture技術雛形,最早源自上個世紀一家名叫3DLABS的顯卡公司 。那時是實現在硬件中的。這點與clipmap很類似。

id software的純軟件技術實現的靈感則來自一篇04年的叫《Unified Texture Management for Arbitrary Meshes》論文。最終id實現的這個技術應該比3DLABS的要遠遠複雜得多。並且包含非常多的技術實現與優化細節。以及全套美術製作流水線。一個引擎和遊戲開發了6年多,複雜是顯而易見。

08GDC上一位技術愛好者憑着一些隱約的ID TECH 5線索,以及有限的paper,自己實現了一套類似megatexture的技術。09id software做技術介紹時,證明這位仁兄的實現和id的很像。同時08crytek公司也介紹了他們在cryengine中實現的virtual texture的想法。

具體virtual texture的技術,要做成產品級應用,實現非常複雜。是一個工程難度很高的技術。本人沒做過。只簡單介紹一下。水平有限,不保證信息的完全準確。

介紹

一,目的

爲何需要這個技術。簡單講原因有二。

第一,顯存有限。次世代遊戲動輒就要幾百兆顯存來支持精細的各種貼圖(diffuse, specular, 各種mask,各種bump,各種env, decal, 等等等等)。隨着遊戲製作規模增大,要更多的貼圖來滿足眼球。只有更精製,沒有最精製。關卡沒有最大,只有更大。 但是顯存有限。

第二,普通製作遊戲場景中的各種景物,貼圖重複使用是非常關鍵的事情。因爲一個3D遊戲,關卡足夠大,虛擬現實沉浸感才強。細節物體要多。只有更多,沒有最多。更大的場景更多的景物,需要更多的貼圖是一方面,另外一方面,需要美術對貼圖的複用考慮更多,在製作上也需要大量精力去調整UV和優化。

爲了節省貼圖,一般美術製作還需要使用貼圖Tilling。就是一張貼圖重複排列開來,鋪在面積很大的物體表面上。這樣顯得很假。這需要美工花極大精力去製作既要重複排列又不能顯得重複性太明顯的貼圖。美工很多工作並不是象繪製圖畫一樣,而是更像個砌牆工,竭力想用重複的材料堆砌出不一樣的效果。生產力不夠高。

二,實現

virtual texture想法很直接:假設屏幕分辨率 1680x1050 。 那麼這個屏幕可以顯示的貼圖圖素(texel)數據,最多不過 1680x1050x3 字節。 如果我們把屏幕上要顯示的景物,面向屏幕的可見部分,精確的製作一張貼圖,那麼這個貼圖最大就需要1680x1050x3 = 5MB 。 前提是屏幕上顯示的景物,背對屏幕的地方和被遮擋的地方都沒有貼圖。 如果我們能夠實時創建這麼一張貼圖來顯示場景,我們顯卡的貼圖用顯存只用5MB 就完全夠了。

這種極端的情況用現有的硬件實現起來恐怕不太現實。退而求其次:我們有一些cache做冗餘,景物有一些互相遮擋的繪製,就算6張屏幕大小的貼圖,重疊遮擋繪製3次,每個像素4字節,那麼在這種很差的情況下,我們也就需要120MB 貼圖。在次世代遊戲顯卡上,這個要求不算過分。

所以自然而然產生了一個想法。 那就是把這個遊戲所有要用到的貼圖全部放在一張超大的貼圖上。在繪製每一幀時,只把屏幕上要顯示出來的最高精細度貼圖從硬盤上裝載到顯卡顯存,繪製出來就可以了。 下一幀玩家鏡頭移動時,再去裝載新景物的高精度貼圖。如果不裝載高精度貼圖,景物可以用很低精度的貼圖顯糊弄一下(Mipmap Level很高)

這個過程如果很快,並且只有離玩家較遠的新顯示景物去裝載高精度貼圖。那麼就可以用一張沒有容量限制的超大的貼圖(硬盤限制),在顯存有限的硬件上,繪製一幀中眼力所及的整個世界。並且這個世界的精度不會太受影響。換句話,遊戲世界的貼圖製作不用考慮顯存大小。

並且,美術製作這個世界時,只用很直接的2步。1,做網格。2,給這個網格繪製唯一的貼圖。不用考慮貼圖複用。

ID TECH5 megatexture技術就是要實現這個目標。

1,預處理

1.1貼圖預處理

在渲染之前,數據製作階段時,先需要做一些預處理。最重要的一個處理,就是把世界中用到的所有貼圖。全部先放入一張巨大的貼圖。這也就是megatexture了。我們今後把這張能夠繪製整個世界的唯一貼圖叫做:virtual texture 。這張貼圖可以很大,比如邊長200多萬像素,即一張4T大小的貼圖(當然遊戲中沒有必要這麼大)。

接着,按照一個固定大小的尺寸(RAGE》中,是128x128),把virtual texture切割成方塊。這個方塊,我們稱作“頁”(pages)。

在這裏,對mipmap的處理有點特殊。所有貼圖的mipmap,每一層也都按照這個固定大小切成page。如果一張貼圖的某一層mipmap尺寸小於page的尺寸,就停止切割。然後把mipmap切割出來的page也放在virtual texture文件裏。

以下是一張貼圖和這張貼圖的mipmap,被切割爲page的樣子。從左到右依次是mipmap level 0,1,2,3 。 這也是virtual texture文件中的內容。

把這些page調入顯存,再去顯示場景。如果我們故意保留切割的痕跡,讓我們看一下場景會是怎麼樣的:

在《RAGE》中,一張virtual texture是 128k x 128k 大小。這裏我們說的virtual texture的尺寸,是最高精度的貼圖尺寸。 一個page128像素。 以下是《RAGE》中一個局部的4mipmapvirtual texture中的樣子。可以看到4張截圖, 字體的4種顏色代表着4mipmap 2個數字是pagevirtual texture中的全局唯一標號。

場景截圖中,最靠近鏡頭的標號顏色,是mipmap精度最大的層。隨着距離漸遠,標號顏色也體現了使用精度更低的mipmap。其中白色的格子表明是page的分界線。

LEVEL0

LEVEL 1:

LEVEL2:

LEVEL3:

注意這裏是對同一部位不同mipmapvirtual textuer上的截圖。這些圖都是放在virtual texture一個文件裏的。

再給個例子。這個是一個virtual texture文件內部可能的一種組織形式:

1.2 幾何預處理

把所有物體的貼圖拼接在一起變爲一整張virtual texture(也就是megatexture)後,世界中所有的物體都只使用virtual texture這麼一張貼圖。所以世界中物體的座標都應該換算一下。

假設virtual texture是一張131072 x 131072大小的貼圖。 virtual texture左下角貼圖座標爲(00). 右上角貼圖座標爲(11).  根據一個物體貼圖在virtual texture中所在的相對位置,用很簡單的換算即可得到這個物體新的貼圖座標。 

比如一個物體有一張512x256的長方形貼圖。位於virtual texture中從橫向第 8088個像素,縱向第11901個像素開始。這樣物體一個頂點的貼圖座標u,v (0<u<1 ,0<v<1)換算到virtual texture中,就是 

u' = (u*512 + 8088)/ 131072 

v'= (v*256+11901)/131072

當貼圖座標 u,v<0 或者 u,v>1時,說明使用了紋理 tilling。貼圖重複排列。這時的處理,需要在virtual texture中重複複製物體所用到的貼圖。 然後把貼圖座標重新換算到0-1之間。再進行virtual texture貼圖座標轉換。

2,繪製

接下來繪製。我們做最簡化情況的假設,有3步要走:

1,判斷需要哪些pages

判斷屏幕上需要繪製哪些貼圖。以及屏幕像素上那個貼圖用到的mipmap級別。因爲世界所有貼圖都以page爲單位,拼在磁盤上的一張megatexture裏。沒法一次性調入顯存。要判斷出真的需要哪些貼圖,以及那個貼圖的mipmap級別。纔會把需要的那部分pages裝載。

2,裝載

streaming把需要的貼圖pages裝載進來。放入顯存的一張實際要使用的貼圖(在id software的介紹中叫physical page texture,在本篇文章中叫“顯存貼圖”。這張顯存貼圖,是由很多pages 拼湊而成的。

3,繪製場景物體。

繪製過程中,在pixel shader中,把屏幕上所有景物的貼圖座標重新換算一下。以便用顯存貼圖(貼圖內容是從磁盤上靠streaming讀出來的小塊貼圖(pages)拼湊而成)來正確繪製場景物體。因爲場景中的物體在美術製作時,是按照普通展UV的方式製作的。

3,具體步驟

以下對上面說的3個步驟做具體介紹

3.1 判斷本幀繪製要用到哪些page

page中不僅僅記錄了物體原始貼圖的某個部分,同時這個原始貼圖的mipmap也都切成塊當作page儲存在virtual texture中。所以這一步驟不僅要找到屏幕上物體用的貼圖在virtual texture中的位置,還需要判斷使用了哪個mipmap層,這樣才能精確定位出屏幕上物體渲染需要的所有pages。因爲不同mipmap級別的page放在了文件不同地方。

用一個簡單的實現辦法概述這個過程:物體貼圖座標本身就說明了所用到的貼圖在virtual texture中的位置。只要把物體貼圖座標繪製在屏幕上。再把屏幕內容取下來,逐點判斷,就能夠得到本幀到底需要哪些page來繪製。

詳細一點的解釋:因爲所有物體只使用virtual texture這麼一張貼圖。那麼物體貼圖座標肯定是全局唯一的(物體使用的貼圖肯定分散在virtual texture的不同部分)。我們把物體貼圖座標當成頂點顏色,繪製一遍物體,那麼屏幕上的像素就代表了這些物體的每個像素的貼圖座標(這裏需要一點光柵化的知識。在繪製三角形時,頂點上的顏色作爲填充三角形的顏色,被光柵化插值爲三角形掃描線中每個像素的RGB值)。換句話,屏幕上繪製出來的就是繪製物體每個像素要用到的貼圖座標。同時在光柵化時,我們在pixel shader中還可以計算出每個像素用到貼圖採樣的mipmap層級數。 (如果這裏不懂可以先複習一下光柵化)

最後把這個結果輸出爲一張圖片。由CPU去分析。 這裏給出圖片可能的樣子:

環狀不同顏色代表不同mipmap。 

這個東西在id software的介紹中,叫Feedback Buffer。下面是《RAGE》中的樣子

接下來就容易了,得到屏幕上的所有像素。逐一分析。每個像素的信息就是對應物體所用到貼圖page的位置信息和mipmap級數。 這個級數也用來定位page的位置。

分析完畢,我們就有了當前屏幕上所有景物要用到的pages 。我們把本幀需要用到的page,叫“活躍page

1680x1080 的屏幕上,像素個數是 1814400 個。 每個像素都檢查一遍,CPU基本就廢掉,不用做其他事情了。 優化的辦法是對屏幕bufferdown sample 。也就是縮小屏幕pbuffer尺寸。只檢查有限的像素。或者乾脆直接在一個分辨率很小的pbuffer上繪製整個場景。諸如此類。 從圖上看,RAGE用的是一張分辨率比較低的Feedback Buffer

3.2 讀入貼圖page

顯存貼圖(physical page texture)更新

知道要用到哪些page之後,就從磁盤讀入進來。其中用到的各種streaming優化,貼圖壓縮解壓縮,就不提了。

顯卡中維護一張真正最後渲染要用到的貼圖。我們叫它“顯存貼圖”或者“物理頁貼圖” (physical page texture)。這張貼圖邊長是page尺寸的整倍數。讀入的page貼圖方塊,就一個個在physical page texture中拼接起來。(拼接的時候每個page周圍還需要留條邊。 大家都知道顯卡最後紋理映射時,有個雙線性插值的問題。而且隨着物體離鏡頭越遠,用的mipmap不同,對不同mipmap page周圍留的邊,還有粗細不同的問題。 總之這些零零碎碎的問題充斥着megatexture實現的所有步驟。)

頁表貼圖(page table texture)更新

在這一步很重要的事情,還需要更新一張貼圖。這張貼圖叫 page table texture --- “頁表貼圖”。

“頁表貼圖”大致的做法是這樣。我們準備一張virtual texture的微縮版本。這個微縮版,有的paper叫 indirect texture,有的paperpage table texture 。 我們用中文,叫"頁表貼圖。頁表貼圖的每個圖素,對應着virtual texture中相應位置的page 。圖素內容就是對應page在顯存貼圖(physical page texture)中的位置信息。比如:如果virtual texture 最高精度那層有1024x1024page,那麼頁表貼圖大小就是1024 x 1024 個圖素。

接着我們定義一下“活躍page”。 活躍page的意思,是說凡是本幀需要繪製,並從virtual texture被拷貝到顯存貼圖(physical page texture)中的page,都要被標記爲活躍page

頁表貼圖(page table texture)需要每幀更新,每個活躍page對應在頁表貼圖(page table texture)位置的圖素內容,要記錄這個活躍page在顯存貼圖(physical page texture)中的位置信息。 如圖:

得到結果是:

因爲在屏幕上的場景,會有mipmap。用到不同mipmap page的信息,也記錄在頁表貼圖的mipmap中。如圖

顯存貼圖(physical page texture)page填充好之後,更新完page table teture就可以用這兩張貼圖最後渲染了。

3.3,渲染

到這個階段,我們已經實現了megatexture的大部分目標,挑選一幀中能夠看到的物體用到的貼圖,拼起來。這樣我們就實時創建了一張貼圖,這張貼圖上面只有本幀需要繪製在屏幕上的貼圖圖素(當然肯定有一些冗餘)。

那麼如何繪製? 因爲我們用pages拼湊而成的這張顯存貼圖(physical page texture),即便是相同物體用到的貼圖,也都是一個個被切成小方塊的page拼湊而成。pagepage之間根本不挨着。不同mipmappage也都並列排在顯存貼圖裏。根本不連續。用這唯一一張貼圖去繪製場景所有物體。需要額外步驟。

紋理映射的原理是根據一個像素的貼圖座標(注意這裏是已經被光柵化後的像素級貼圖座標了),去貼圖中採樣圖素(texel)。這個圖素的顏色值,經過光照處理,就可以直接顯示在屏幕像素上。

page拼湊而成的顯存貼圖(physical page texture)正確顯示場景中所有物體,需要對貼圖座標(物體貼圖座標是在virtual texture貼圖空間中的,直接用這個貼圖座標去索引顯存貼圖(physical page texture),得不到正確結果)進行一下轉換。使得顯示在屏幕上物體的每個像素,精確的對應到顯存貼圖(physical page texture)上它應該對應的位置。

我們需要一次像素級別的貼圖座標轉換。這個任務可以用indirect texture sampler也就是間接貼圖採樣來完成。即,先利用原始貼圖座標,對一張間接貼圖進行採樣,得到一些必要信息後,再利用這些信息對原始的貼圖座標進行轉換以採集顯存貼圖。

這個間接貼圖,其實就是頁表貼圖(page table texture)

以下是過程簡述:

1)用更新後的頁表貼圖(page table texture)與顯存貼圖(physical page texture)共同繪製場景所有物體

2)在pixel shader中進行一次貼圖座標間接尋址。從頁表貼圖(page table texture)中得到一個偏移值。用這個偏移值對原始貼圖座標(virtual texture貼圖座標)進行處理,就變爲最終需要採樣顯存貼圖(physical page texture)的貼圖座標。

3)用處理過的貼圖座標採樣顯存貼圖。最後場景中的物體就都按照實際需求繪製出來了。

如圖:

這張圖只是一個示意圖。圖4實際屏幕顯示紅點的位置,通過貼圖座標和光柵化我們可以知道在virtual texture上採樣的位置(圖1中的紅點)。用這個紅點的貼圖座標,去採樣頁表貼圖(page table texture,圖2),得到了當前活躍page在顯存貼圖中的位置換算關係。紅點在圖2落到了內容爲“3”的圖素裏。利用這個換算關係,可以得到最終貼圖座標。在 圖3中,正確的對顯存貼圖(physical page texture)進行採樣。圖3的紅點就是需要正確採樣的位置。最終得到圖4像素的顏色值。

4,鏡頭快速轉動與移動時

經過3個步驟,如果硬盤無限快速,而且顯存貼圖(physical page texture)的大小能夠滿足繪製本幀所有物體最大精度貼圖。那麼我們會看到一個無限大的世界,有着最高貼圖精度。流暢地在眼前飄過。

事實上,沒有這麼理想的情況。 磁盤速度不可能那麼快。顯存貼圖(physical page texture)有時候並不滿足繪製當前鏡頭中所有物體最大精度貼圖的容量。

這就是我們在實際《RAGE》遊戲運行過程中看到的景象。一旦搖動一下鏡頭,所有物體的貼圖都重新回到最模糊,然後慢慢變得精細。這個現象在PS3上尤其嚴重。PS3IO是嚴重瓶頸。理論上就無法保證足夠量的精細貼圖在一定時間內讀入顯存。在一個 光驅,硬盤,內存,顯存的4cache系統中,任何一個地方的瓶頸足以毀滅megatexture美好的初衷。這是爲什麼。

回顧virtual texture技術的3個步驟。如果磁盤是瓶頸,很多活躍page無法從磁盤調入顯存。那麼顯存貼圖(physical page texture)就無法在足夠時間內拼湊出繪製當前場景所需要的全部貼圖page。 怎麼辦。 這個時候有很多辦法可想。 一個最簡單的辦法是,沒有貼圖的景物,就繪製個馬賽克貼圖好了。。。

當然,商業產品不能這麼做。 如果調入高精度貼圖來不及,那麼就先把最低精度的貼圖調入進來。

如果最低精度都進不來,那麼卡幀,讓用戶休息一下。。。

從這裏看出,megatexture受硬件制約依舊較大。只不過從明確的顯存上限,降低到對IO速度的一定要求。

IO速度對於PC,可能越來越快。對於XBOX360,卡馬克愛不釋手自然會量身定做。至於PS3,那就算那些買正版的傢伙們倒黴了。

5,一些問題

另外一種情況,當前幀的場景中物體太多了,所用到的貼圖總量,超過了顯存貼圖(physical page texture)容量。

很多物體都沒有貼圖來繪製。自然只能空在那裏。解決方案無非就是儘量合理的把場景中物體用到的貼圖量控制一下。這裏面要解決的工程問題無限多。要自研此技術做產品的人,只能自求多福了。

還有一個問題。在第一步用頁表貼圖(page table texture)繪製時,頁表貼圖是一張完整調入顯卡顯存的貼圖。它是virtual texture的縮小版。根據page的大小來縮小。一個page相當於這個貼圖的一個像素。但是當virtual texturepage數量太多,以至於頁表貼圖(page table texture)的大小都超標了,這就是個很麻煩的事了。

我們假設一個page 512x512像素(page大小的制定也有講究,不細表)。如果想要在頁表貼圖(page table texture)保持在 4096x4096 大小,那麼我們的一張virtual texture最大邊長只能是 4096x512 像素。 也就是這張virtual texture最大也就2097152 x 2097152 像素大小。一個像素算4字節。那麼最大的一張圖容量是 4096 G 。 難道我們與時俱進的玩家就按麼容易滿足4T的貼圖容量麼?隨着祖國日新月異國富民強,人民羣衆的審美娛樂需求一日提高,早晚有一天。。。。。。

如果真有這種情況,用多張頁表貼圖是一種自然的選擇。。。

同時還存在其它問題。比如浮點貼圖座標的精度問題。顯卡內部對貼圖座標浮點精度的處理和標準IEEE單精浮點標準是不一樣的。另外,page table texture是一張用來索引貼圖座標的貼圖,這張貼圖本身的內容就是貼圖座標,所以也需要用浮點格式。。。

virtual texture很大的情況下,各種buffer各種貼圖座標浮點誤差的處理,也令人頭疼。

總結

基於virtual texturemegatexture技術。充斥着無數工程細節問題。各種多線程優化問題。各種IO優化,浮點誤差,帶寬瓶頸等問題。在PC上,ATI顯卡險些全軍覆沒也暴露了在兼容性方面的問題。其它還有技術與工具集生產流水線的集成問題等。

id software在此領域推出成熟技術解決方案,令人欽佩。

megatexture解決了靜態紋理容量問題。但遊戲的表現,並不完全取決於靜態光影和貼圖細緻度。在ID TECH 6中,卡馬克打算用voxel rendering把幾何數據容量問題也一併解決掉,並且拋棄多邊形光柵化渲染,帶玩家走入另外一個細節複雜度無限高的虛擬現實世界。我們可以拭目以待。

201110

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章