LOD地形及相關技術研究

 該文章寫於2009年夏,兩年過去了,我也由一名學生成爲了一名專業的遊戲開發人員,以現在的角度來看當時十分的稚嫩,但是我覺得是我技術上的一個很有意義的里程碑,現在我發出來這篇文章,希望對學習相關技術的學生朋友有幫助。

    無圖無真相,放一張效果圖先:

 

LOD地形及相關技術研究

序言:

         如今LOD技術被廣泛應用在遊戲領域,因爲他能節省cpu大量的運算且又能表現極爲廣闊的空間和場景,尤其是擁有超大場景的網絡遊戲,更是離不開這種技術。筆者要談的LOD地形恰恰是LOD技術中的重要的組成部分,這種地形技術根據人的視覺觀察特點,以較少的點和麪表現出逼真的視覺效果。

       筆者由於工作和學習的需要最近開始接觸LOD地形技術,從網上搜索了一些資料,經過兩個星期的研究,終於初步的解讀和完成了屬於自己的LOD地形,我希望把自己的一些經驗寫出來同大家一起分享,希望大家多多指教。

       本篇文章主要詳細介紹LOD地形技術的幾個要點,以實用爲主,感念和前景等內容在此不在熬述,基本思想同網上的資料大致相同,但也有一些筆者認爲需要修改和改進的地方,如裂縫修補和定點渲染等。所謂仁者見仁智者見智,如果大家覺得有不妥的地方歡迎大家隨時指證。

 

第一章   LOD的基本思想

LOD的特點就是可以表現更大型的地形和更高的細節而不消耗過多的運算量。筆者之前實現過一種靜態地形,讀取高度信息後直接將所有頂點進行計算和渲染,但該種方法所能渲染的TerrainSize(地形尺寸)是有限的,一般在1024*1024個頂點的情況下的FPS爲5-10幀左右,要達到60幀的速度必須降低頂點數量在256*256左右,對稍大一點的地形來說,只能犧牲精度來換取速度。廢話不多說,想必來看這篇文章的朋友都遇到過這樣的問題,下面進入正題。

       首先看一下靜態網格地形和LOD地形的網格對比:

LOD地形及相關技術研究

1-1靜態地形網格

 

LOD地形及相關技術研究

1-2 LOD地形網格

通過比較發現靜態網格地形擁有規則整齊的網格佈線,而LOD地形卻佈滿凌亂的大小不一的“方格”,這些“方格”我們稱之爲Node(節點)。然而實際上,Node在地形複雜和離觀察點較近的地方會比較密集、尺寸也較小,在平坦和較遠的地方比較稀疏、尺寸較大,這樣的佈局即解決了對地形精度的要求又保證了渲染頂點的數量,而且Node的尺寸會隨着觀察點的移動而進行改變。靜態網格也有事先設定好地形複雜度的,但運行之後就不會再更改變了。

所謂LOD地形也就是擁有層次細節的地形,當然對頂點的優化不僅僅是在地形複雜度的評價。除此之外,LOD地形技術還包括高度數據、加載各種紋理等其他幾個方面,筆者會在以下幾章詳細向大家描述。

 

第二章  高度數據存儲和獲取

         除非是在平原,絕大部分的真實地形都會有高低起伏。在遊戲裏面地形的高度信息一般是存儲在一個張灰度圖(HeightMap)上,灰度圖中像素存儲的是0-255的亮度值,我們就利用每個像素的亮度值來存儲高度信息,如圖2-1所示,左圖是對應右邊實際地形的灰度圖,左圖的中越亮的部分,在真實地形中對應區域的地形越高。

LOD地形及相關技術研究LOD地形及相關技術研究

 

2-1灰度圖

       灰度圖HeightMap一般會使用沒有RGB顏色信息的圖片格式,例如.rew和.tga等。

       有了與地形相關的灰度圖之後,接下來下來的問題就是如何獲取灰度圖中的高度信息。首先設置一個unsigned char*類型的變量HeightDate,使用函數fread()將灰度圖中的高度信息讀出並寫入HeightDate。

使用灰度圖的像素的大小需要一定要與地形尺寸(TerrainSize)相匹配,例如:需要建立一個1024*1024的地形,地形TerrainSIze就爲1024,灰度圖的大小爲TerrainSIze* TerrainSIze。注意:HeightDate的大小不是TerrainSIze* TerrainSIze,而是 (TerrainSIze+1)* (TerrainSIze+1),而且TerrainSize的一定爲2n,原因會在下一章解釋。

       存儲和讀取灰度圖的數據實際上時地形算法中最基本也是最容易的一部分,不管是LOD地形還是靜態網格地形都是使用這種技術,相對來說筆者到覺得製作符合要求的高度圖和匹配的紋理圖更有難度,不過目前市面上也有不少專門爲地形制作高度圖和紋理圖的工具,大家可以嘗試一下,筆者繪製灰度圖使用的軟件是L3DT。

 

L3DT是一款專門針對LOD地形技術設計的軟件,可以輕鬆製作自己的LOD地形及導出相關的素材,官方下載:http://www.bundysoft.com/L3DT/downloads/

第三章    節點評價系統

         爲了更好的對頂點進行優化,我們把LOD地形分爲若干節點,劃分節點的數量與大小就要通過一套節點評價系統來決定。

爲了使細節可以根據要求來進行細化,所以使用樹的方法來實現節點的分割,常用的方法有四叉樹和二叉樹分割,在本篇文章裏使用的是四叉樹分割,如圖3-1所示。L3DT是四叉樹二叉樹結合使用。

LOD地形及相關技術研究

圖3-1節點的四叉樹分割,橙色爲需要分割節點

       由於採用四叉樹的分割方式,當節點最大限度分割時,其數目應該與地形尺寸相匹配,及(TerrainSize+1)*(TerrainSize+1),這也是爲什麼要求地形尺寸一定要爲2n+1。

       一個四叉樹節點需要包含頂點信息,頂點的數目與該節點的鄰接節點有關,爲了方便分割,頂點數目設爲9個,結構如圖3-2。

LOD地形及相關技術研究

圖3-2  節點結構

       0頂點爲中心點,1、2、3、4點爲角點,5、6、7、8爲邊點,頂點和角點是固定的,頂點數量的變動時指邊點數量的變動如圖3-3。

LOD地形及相關技術研究

 

圖3-3 

想象一下,節點分割的次數越多,地形就越精細,但是計算量也就越大,所以需要針對地形複雜區域的節點進行分割,較爲平坦的地形則進行較少的分割。

       節點分割的評價系統大致分爲兩個部分,第一是節點到觀察點的距離,第二是計算節點區域複雜度。

LOD地形及相關技術研究

節點離觀察點越近分割次數越多,根據第一條評價原則,總結出第一條評價公式:L/d < C1,L爲頂點到觀察點的距離,d該節點的長度,C1爲自定義的常量,C1的值約大頂點分割次數越多,如圖3-4。

節點區域地形越複雜,分割的次數就越多,根據第二條評價原則,總結出第二條評價公式:L/r < C2。我們採用如圖3-5中節點,首先獲取到頂點h0到頂點h4的高度,如果該節點分割則還要獲得子節點的高度h5到h8,然後依次比較各高度值,取出最大值Max,與最小值Min,r = Max-Min。

綜上所述將評價公式1和評價公式2合併起來:L/(d×r) < C1×C2,變形得到最終公式:f = L/(d×r×C1×C2) < 1。當滿足f < 1時則判斷該節點需繼續分割。

對節點判斷是否分割之後,我們需要存儲這個分割信息標誌,我們設一個類型爲bool[][]類型的數組變量QuadMat,數組的長度應該與節點的數目一致,即QuadMat[TerrainSize+1][TerrainSize+1],存儲方式如圖3-6所示,由下圖也可看出爲何頂點數目以及其高度數據HeightDate的大小也是(TerrainSize+1)*(TerrainSize+1)。

 

LOD地形及相關技術研究

第四章 視錐及裁剪

         在LOD地形中還有一項很重要的減少繪製頂點的方法,那就是對攝像機之外,那些我們觀察不到的區域的頂點進行裁剪。這裏說的裁剪並不是D3D裏所說的裁剪,而是針對節點劃分的控制,對於那些我們無法觀察到的節點就將其分割信息設置爲false。

       在這裏提出視錐的概念,如圖4-1(a)所示,觀察者同顯示器屏幕,以及延長線所經過的區域就構成了一個四面錐,我們所說的視錐實際上時這個四面錐去掉觀察點到屏幕之間的部分,如圖4-1(b)藍色區域所示,在這個區域內的節點才能被我們觀察到。

LOD地形及相關技術研究

 

 

       認識視錐之後就緊接着就是怎樣獲取視錐。首先獲取投影矩陣matProj和觀察矩陣matView,計算攝影和投影變換後的得到的矩陣matWorld。我們可以通過這個矩陣來一次獲取去視錐的6個面Planes[6],方法參照如下一段代碼段:

D3DXPLANE m_Planes[6];

    Planes[0].a = matWorld._13;//近平面

Planes[0].b = matWorld._23;

    Planes[0].c = matWorld._33;

    Planes[0].d = matWorld._43;

    D3DXPlaneNormalize(&m_Planes[0], &m_Planes[0]);

    Planes[1].a = matWorld._14 - matWorld._13; //遠平面

    Planes[1].b = matWorld._24 - matWorld._23;

    Planes[1].c = matWorld._34 - matWorld._33;

    Planes[1].d = matWorld._44 - matWorld._43;

    D3DXPlaneNormalize(&m_Planes[1], &m_Planes[1]);

    Planes[2].a = matWorld._14 + matWorld._11; //左平面

    Planes[2].b = matWorld._24 + matWorld._21;

    Planes[2].c = matWorld._34 + matWorld._31;

    Planes[2].d = matWorld._44 + matWorld._41;

    D3DXPlaneNormalize(&m_Planes[2], &m_Planes[2]);

    Planes[3].a = matWorld._14 - matWorld._11; //右平面

    Planes[3].b = matWorld._24 - matWorld._21;

    Planes[3].c = matWorld._34 - matWorld._31;

    Planes[3].d = matWorld._44 - matWorld._41;

    D3DXPlaneNormalize(&m_Planes[3], &m_Planes[3]);

    Planes[4].a = matWorld._14 - matWorld._12; //頂面

    Planes[4].b = matWorld._24 - matWorld._22;

    Planes[4].c = matWorld._34 - matWorld._32;

    Planes[4].d = matWorld._44 - matWorld._42;

    D3DXPlaneNormalize(&m_Planes[4], &m_Planes[4]);

    Planes[5].a = matWorld._14 + matWorld._12; //底面

    Planes[5].b = matWorld._24 + matWorld._22;

    Planes[5].c = matWorld._34 + matWorld._32;

    Planes[5].d = matWorld._44 + matWorld._42;

    D3DXPlaneNormalize(&m_Planes[5], &m_Planes[5]);

 


   判斷的節點座標(x,y,z)是否在視錐體內,就是判斷該座標在六個面得那一側。D3D中功能函數D3DXPlaneDotCoord()可以三維點與平面進行點擊(a*x + b*y + c*z + d*1),根據返回結果與0進行比較,依次來進行判斷,如果六個面得結果都大於0則改座標及在誰追體內。

   由於節點座標並不是一個點,而是一塊由若干頂點構成的一個區域,所以以一個節點座標來判斷該節點是否在是椎體內,當節點離視錐界面邊緣的時候容易產生誤差。爲減小誤差,我們把每個節點看做一個邊長爲節點長度的立方體,判斷座標變換爲判斷立方體,進而轉化爲判斷立方體的八個頂點,如圖 4-2。

LOD地形及相關技術研究

 

 

第五章節點的渲染

    第三章已經介紹,每個節點都是由若干頂點組成,中心點和角點都是固定不變,邊點的數量在0到4之間。

LOD地形及相關技術研究

 

在節點的每條邊上是否有邊點主要取決於相鄰節點是否進行了分割,然而相鄰節點既包括自身友節點(同一父節點分割出的四個節點層次爲n)和父節點的友節點(層次爲n-1),進行判別的時候也要把這兩種情況區分開。如圖5-1所示紅色區域的節點,藍色的頂點代表通過判斷父節點的有節點而增加的邊點,紅色的頂點點代表通過判斷自身友節點而增加的邊點。使用邊點的作用在於增加節點面數,以避免鄰節的不同層次相點之間出現接縫。該方法經過筆者優化,可能與其他資料介紹的方法有所不同。


 

 

根據節點中頂點的分佈特點,採用扇形繪製三角面,如圖5-2所示,directX3D和OpenGL裏面都包括這種繪製方法。

 

LOD地形及相關技術研究

    節點渲染的順序採用遞歸的方法深度優先遍歷整個四叉樹的節點,遍歷到子葉就進行渲染,判斷該節點是否爲子葉的標誌就是觀察該節點的分割信息爲false。該章內容難以描述的更詳細,若果感興趣可以結合該章節的代碼(由於代碼過長,暫不放入本章內容)

第六章   修補裂縫

         通常我們把節點看做一個四叉樹,根據分割層次的不同,節點的尺寸也不同,這樣一層一層的分割下去直到分割的極限尺寸,如圖6-1是第三章圖3-6的四叉樹層次結構。

LOD地形及相關技術研究

 

       我們所說的裂縫就是當相鄰的節點,當層次大於或等於2,在兩個節點之間會出現的一個三角形縫隙,如圖6-2。上一章所使用的渲染節點的方法本身具有修補裂縫的功能,但只是針對層次相差爲1的節點,如上所述的情況就無能爲力了。

LOD地形及相關技術研究

 

如圖6-3中紅線兩邊的節點,層次剛好相差2,右節點在相鄰的邊上沒有定點,而紅線右邊的兩個小的節點相接處卻各有一個頂點,這種情況下必然造成三角裂縫。

LOD地形及相關技術研究

 

解決裂縫的辦法有很多,在這裏介紹一種效率較高也是筆者正在使用的方法,就是避免相鄰節點分割層次差大於等於2的情況出現。通常我們把如圖5-3藍色區域的四個節點視爲不合法的節點,怎樣避免這樣不合法的節點出現呢?只有將該四個節點的父節點的分割信息設置爲false,禁止該父節點進行分割。

通過節點評價系統和視錐獲得分割信息QuadMat,爲了剔除不合法的節點,需要針對該信息進行四叉樹的廣度優先遍歷,即逐層遍歷節點。如果遍歷層次爲n的節點,則需要判斷相鄰所有的層次爲n的節點的分割信息,如果爲true就允許分割,如果是false就不允許。該方法經過筆者優化,可能與其他資料介紹的方法有所不同。

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