軟件實現三維地圖引擎的研究

 

寫在前面:

這篇東西,本來寫下來是想去投出版社的。結果打聽下來,這還要一筆不大不小的花費,除了審稿費,還有版面費,少的幾百,多的上千。艾,寫的也不咋地,先放在這裏好了。等哪天手頭寬裕了再說吧(順便說一下現在的出版社可真是向錢看啊)。

 

1,    引言:

當前在許多導航類產品中地圖引擎的使用已經很多見了,特別是隨着近些年硬件技術的發展,加上許多三維的圖形繪圖軟硬件庫的支持,使得三維地圖引擎的使用也變得比較常見了。可以說一款好的三維地圖引擎對於整個產品來說是顯得相當重要的。

針對於應用層的地圖圖形軟件開發使用的比較普遍的三維圖形庫有OpenGLDirect3D等。這些圖形庫都是針對於三維圖形繪製特別優化的,包括對一些關鍵算法和特定繪圖硬件設備的支持。它們提供了一些靈活的接口調用而將具體的實現方式完全的封裝了起來。這樣爲開發人員在使用時提供了相當的便利。但也使得開發人員不清楚圖形庫的具體實現方式,只專注於應用的實現。

本文的目的是想通過介紹純軟件方式實現的三維地圖引擎,使得人們瞭解三維地圖引擎的基本結構和流程,內部的實現方式,從而能夠更好的掌握三維地圖引擎開發的原理和本質。

 

2,    三維引擎簡介:

     通常按用途劃分三維引擎基本上可以分爲:太空引擎、地形引擎、FPS室內引擎、光線投射和體素引擎、混合引擎。

2.1、太空引擎:

       該引擎在三維引擎中不是那麼複雜。在大多數情況下,三維太空遊戲是基於物體的,這意味着所有的實體都是物體,在渲染之前,有很多物體已經從流水線中剔除;然後在渲染期間,使用簡單的畫家算法或Z緩存對組成每個物體的多邊形進行排序,然後將光照、動畫等通過常規方式處理。

2.2、地形引擎:

       比太空引擎複雜點的是地形引擎。當然,地形引擎中需要處理的不光是地形,還有處於地形中的物體,包括複雜的動畫和地形跟蹤算法。然而,地形引擎的主要問題是,如何表示世界數據庫,它可是非常龐大的。

       例如,假設要創建一個大小爲100000*100000單位的多邊形網格世界,其中每個多邊形的大小爲200*200單位。這意味着該多邊形網格包含大約250000((100000/200*100000/200))個多邊形。

2.3FPS室內引擎:

       FPS的全稱是第一人稱射擊,這種引擎比較棘手。首先、玩家大部分時間都在室內,這就要求清晰的細節和近距離;其次,FPS世界在日益增大,多邊形數據庫也將隨之增大,這意味着不能簡單的將整個世界傳遞給三維流水線,而必須使用空間劃分技術將世界區分,以最大限度的減少需要考慮的多邊形。

2.4、光線投射和體素引擎:

       原則來說,多邊形的引擎基本上都是基於光線投射和體素的。光線投射是一種被用於很多三維FPS遊戲中的技術,這些遊戲是基於向前光線跟蹤的,即從玩家的視點投射一條光線,穿過視平面,直到遇到物體。這種技術可以非常快的生成三維場景。

2.5、混合引擎:

       該種引擎被設計成可以同時模擬太空、陸地和FPS。它的意義在於,很多時候你可能想創建一個有多種環境的世界,這樣你不得不使用多個不同類型的引擎,以便根據要完成的任務使用合適的引擎,而不是使用一個引擎來完成所有的任務。

 

3,    三維地圖引擎的基本構架:

3.1、三維座標系的問題:

在我們瞭解三維地圖引擎構架之前,先了解一下三維座標系的問題。在三維的世界中有着很多不同的座標系,每種座標系表達的意義都是不同的,而他們之間又有着一些特定的轉換關係。主要的座標類型有以下幾種:

A,模型座標(局部座標)

B,世界座標

C,相機座標

D,透視座標

E,屏幕座標

模型座標,也稱局部座標。是表示在創建物體時物體本身所處的座標系座標。

世界座標表示的是虛擬空間中的實際位置,物體將在虛擬空間中移動和被變換。

當我們的實現處於某一個位置觀察物體時,則需要定義相機座標系,同時將世界座標轉成相機座標。

將三維空間中的座標通過透視變換映射到平面座標系上的座標稱之爲透視座標。這種座標的變換稱爲透視變換。

將通過投影變換得到的一系列的點根據屏幕的尺寸和相關參數顯示在屏幕上,這便是屏幕座標。

以上各個座標系之間存在着相互轉換的關係,正常情況下繪製一個三維物體需要經過模型座標,到世界座標,到相機座標,到透視座標,到屏幕座標的變換。

1 包含光照處理的座標轉換流水線

 

3.2、渲染三維世界:

       瞭解了以上的一些座標概念,我們便可以進一步去了解一下三維渲染的世界,可以從線框的繪製模式轉變爲填充的繪製模式。三維渲染主要包括以下三部分:

              光照模型

              紋理映射技術

              三維裁剪技術

       3.2.1、光照模型:

所謂光照模型,是根據光學物理的有關定律計算畫面上景物表面各點投影到觀察者眼中的光亮度和色彩組成的公式。

一個好的光照模型應該滿足以下要求:

1)能產生較好的立體視覺效果;

2)在理論上具有一定的合理性或嚴密性;

3)較小的計算量,以保證較快的繪製速度。

對於自然景物的地形表面,光照模型可考慮以下幾項影響:

1)光源的位置;

2)光源的強度;

3)視點的位置;

4)地面的漫反射光;

5)地面對光的反射和吸收特性。

按照光源的種類我們可以分爲以下幾種:

1)定向光源;

2)點光源;

3)聚光源。

按照光的傳播路徑可以分爲以下幾種:

1)環境光;

2)散射光;

3)鏡面反射光。

       3.2.2、紋理映射技術:

紋理映射技術的使用是爲了讓三維地形圖更有真實感。這是一個將紋理空間中的紋理像素映射到屏幕空間中的像素的過程。

如果對於多邊形來說紋理太大或太小,那麼紋理需要被過濾以匹配空間。有兩種過濾方式:放大和縮小。放大過濾器將紋理放大,縮小過濾器將紋理縮小。紋理放大通常很簡單,會獲得一張模糊的圖像,而紋理縮小比較複雜,不正確的縮小會導致鋸齒。

2 像素級別的mipmap

       3.2.3、三維裁剪技術:

在三維圖形系統中,裁剪是相當重要的主題,如果沒有對集合體進行正確的裁剪,不但無法正確的顯示,還有可能導致一系列諸如內存崩潰、除零異常等等問題。剪裁的目的就是把落在用戶定義的窗口外的部分圖形裁減掉,從而爲圖像識別和圖像處理提供清晰的對象。

三維圖形剪裁分爲兩種:一種是圖像空間剪裁。在所要渲染的物體都被轉換爲屏幕座標後,再使用屏幕空間或視口對其進行裁剪。圖像空間剪裁很易於實現。但也意味着對每個物體都要進行剪裁,無論其在或不在窗口內。因而效率不高;另一種是物體空間剪裁。在對幾何體進行投影變換前,先用視景體對物體進行剪裁,然後再對其進行座標變換。根據特定的剪裁區域對構成三維空間的基本幾何體進行剪裁。可以根據二維或三維視野的剪裁區域對物體或多邊形進行裁剪,然後將裁減後的多邊形傳給三維流水線的下一個階段進行處理。大多數三維圖形引擎都採用物體空間剪裁的方法。

 

4,    軟件實現三維地圖引擎:

不依賴於三維圖形庫,使用軟件的方式實現三維地圖引擎的方式可以讓我們更加了解三維地圖引擎的內部算法與結構。爲了實現軟件的三維地圖引擎,我們首先需要了解一些關鍵數據結構的定義,其次會介紹一下常用的算法。以下涉及到的數據結構和代碼都是用C/C++語言實現的。

              4.1、軟件三維地圖引擎的主要數據結構:

                     1)表示三維點數據的結構:

如何表示一個點在三維空間中的相關信息對於之後算法的編寫和優化是比較重要的。

//這是三維點數據的結構

//點數據採用齊次座標的表示方式。一共有4個變量。分別是xyz//的座標和分量w

typedef struct VECTOR4D_TYP{

Union{//以聯合的數據結構表示方便存儲和調用

    float M[4];

    struct{

        float x,y,z,w;

           };

};

} VECTOR4D, POINT4D, *VECTOR4D_PTR, *POINT4D_PTR;

 

//這是帶有法線向量的點的數據結構,也是以齊次座標的方式表示面中的//各個點

typedef struct VERTEX4D_TYP{

Union{//以聯合的數據結構表示方便存儲和調用

    float M[9];

    struct{

         float x,y,z,w;// 點數據

         float nx,ny,nz,nw;// 各個點的法線向量

         int attr;// 點的屬性

         };

     };

} VERTEX4D, *VERTEX4D_PTR;

 

                     2)表示物體的結構:

在三維世界中,所有的物體都是多邊形組成,而多邊形最小可以表示爲一個三角形。所以我們需要先了解一下三角形的結構,然後再看一下物體的表示結構。

//表示一個多邊形面的數據結構,用到了我們之前定義的點的結構

typedef struct POLY4D_TYP{

       int state;//狀態信息

       int attr; //多邊形的物理屬性

       int color; //繪製多邊形的顏色

char *texture;//如果使用材質貼圖的話,存放材質貼圖的數//據指針

       int mati;//材質貼圖的類型

              VERTEX4D_PTR vlist;//多邊形點的數據存放列表

       float nlength;//多邊形的點的數量

} POLY4D, *POLY4D_PTR;

 

typedef struct OBJECT4D_TYP{

       int id; //物體的ID編號,唯一對應的識別表示

       char name[64]; //物體名

       int state; //物體所處的狀態

       int attr; //物體的物理屬性

       int mati; //該物體所用材質貼圖的索引

       float *avg_radius; //物體的平均半徑,用來做碰撞檢測

       float *max_radius; //物體的最大半徑,用來做碰撞檢測

              VECTOR4D world_pos; //物體在世界座標中的位置

              VERTEX4D_PTR vlist_local;//物體的多邊形座標的數據指針

       VERTEX4D_PTR vlist_trans;//經過座標轉換之後的座標數據指針

       VERTEX4D_PTR head_vlist_local;//多邊形座標的頭指針

       VERTEX4D_PTR head_vlist_trans;//轉換之後多邊形座標頭指針

       char *texture;//如果物體使用材質貼圖,則是材質貼圖的指針

       int num_polys; //物體的多邊形數目

       POLY4D_PTR plist; //多邊形的數據指針

} OBJECT4D, *OBJECT4D_PTR;

 

                     3)表示相機位置的結構:

                            //相機的數據結構

                            typedef struct CAM4D_TYP{

       int state; //當前相機所處的狀態

       int attr; //當前相機的物理屬性

       VECTOR4D pos;//當前相機所處在的世界座標中的位置

       float view_dist;//視線的深度

       float near_clip_z;//相機視角的近裁剪面

       float far_clip_z; //相機視角的遠裁剪面

       float viewplane_width;//裁剪面的寬度

       float viewplane_height;//裁剪面的高度

       float viewport_width;//視口的寬度

       float viewport_height;//視口的高度

       float viewport_center_x;       //視口中心點的x座標

       float viewport_center_y;       //視口中心點的y座標

} CAM4D, *CAM4D_PTR;

 

                     4)表示光照的數據結構:

光照其實有很多種的模型,而在一個光照的數據結構中要儘量做到能包含所有的模型參數。同時一個場景中可能會有多個光源。

//光照的數據結構

typedef struct LIGHT_TYP{

       int state;//光照的狀態

       int id;//光照ID號,唯一識別光源的標誌

       int attr;//光源的物理屬性

       int c_ambient;//環境光照係數

       int c_diffuse;//漫反射光照係數

       int c_specular;//鏡反射光照係數

       VECTOR4D pos;//光照模型所處世界座標中的位置

       VECTOR4D dir;//光照模型在世界座標中的傳輸方向

       float kc, kl, kq;//衰減係數

       float spot_inner;//聚光源的內射角度

       float spot_outer;//聚光源的外射角度

       float pf; //聚光源的功率係數

} LIGHT, *LIGHT_PTR;

 

                     5)表示渲染材質的結構:

                            //渲染材質的數據結構

                            typedef struct MAT_TYP{

       int state; //材質的狀態

       int id; //材質的ID

       char name[64]; //材質名

       int attr; //材質的物理屬性

       int color; //使用填充方式的顏色

       float ka, kd, ks, power; //作用在當前材質上的一些光照係數因子

       int ra, rd, rs; //當前材質如果有多個光源同時作用時的係數

       char texture_file[80];//材質貼圖的文件名

       BITMAP_IMAGE texture; //實際的文件內容

} MAT, *MAT_PTR;

 

              4.2、經典的三維地圖引擎的相關算法:

三維地圖引擎從模型的建立到最後效果的輸出需要經過幾個大的步驟,包括座標轉換,光照渲染,紋理映射,三維裁剪,空間劃分和可見性算法等。下面詳細介紹一種比較常見的紋理貼圖算法的軟件實現。

4.2.1Mipmapping紋理貼圖:

我們前面已經簡單介紹過了Mipmapping紋理貼圖的原理,該算法主要是用於解決走樣的問題。

爲實現Mipmapping,需要創建有紋理組成的mip鏈,其中每個紋理的大小都爲前一個紋理的1/4(沿每條軸縮小一半),最後一個紋理的大小爲1*1。另外,這些mip紋理都是使用濾波器(平均濾波器、箱型濾波器、高斯濾波器)生成的。渲染多邊形時,根據多邊形離視點的距離或多邊形被投影后的面積,選擇使用合適的mip紋理。這樣,將最大限度的減少閃爍和低頻走樣/波形圖案。接下來使用僞代碼的形式分析源碼。

int Generate_Mipmaps(BITMAP_IMAGE_PTR source,//原始紋理     BITMAP_IMAGE_PTR *mipmaps, //指向mip紋理數

                                                  //組的指針

                float gamma)// gamma 修正因子

{

// 這個函數創建一個mip紋理鏈

// 調用該函數時,mipmap指向原始紋理

// 該函數退出時,mipmap指向一個指針數組,其中包含指向各個mip// 紋理的指針

// 另外,該函數返回mip等級數,如果發生錯誤,則返回-1

// 最後一個參數gamma用於提高mip紋理的亮度,因爲平均濾波器會降// 低亮度

// 該參數大於1.0時,將提高亮度;小於1.0時將降低亮度;爲1.0時沒// 有影響

 

//計算mip等級數

//爲指針分配內存

//將元素0指向原始紋理

//設置寬度和高度(它們相同)

 

//使用平均濾波器生成各個mip紋理

for (int mip_level = 1; mip_level <  num_mip_levels; mip_level++)

{

    //計算一下mip紋理的大小

    //爲位圖對象分配內存

    //創建用於存儲mip紋理的位圖

    //讓位圖可用於渲染

   

    //遍歷前一個mip紋理,使用平均濾波器創建當前mip紋理

    for (int x = 0; x < tmipmaps[mip_level]->width; x++)

    {

        for (int y = 0; y < tmipmaps[mip_level]->height; y++)

            {

//需要計算4個紋素的平均值,這些紋素在前一個mip紋理//中的位置如下:

            // (x*2, y*2), (x*2+1, y*2), (x*2,y*2+1), (x*2+1,y*2+1)

            //然後將計算結果寫入到當前mip紋理的(x,y)

            //提取每個紋素的R,G,B

            //計算平均值,並考慮gamma參數

            //根據5.6.5格式,對R,G,B值進行截取

            //寫入數據

            } // end for y

        } // end for x

    } // end for mip_level

 

//mipmaps指向指針數組

*mipmaps = (BITMAP_IMAGE_PTR)tmipmaps;

 

//成功返回

return(num_mip_levels);

} // end Generate_Mipmaps

                    

5,    結語:

隨着三維地圖引擎技術在國內的迅猛發展,地圖引擎市場逐漸成爲一個新興的增值亮點,掌握引擎的核心開發技術將是廣大開發人員的必修課,希望本文對三維地圖引擎系統的軟件設計構架和對應算法的研究能夠起到一定的拋磚引玉的作用。

 

 

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