[轉]3D游戲引擎中的室外大場景渲染技術研究與實現


 
3D游戲特別是網絡在線游戲中,室外大場景渲染是一塊非常重要的內容,它也是3D圖形引擎的核心。它是圖形學和圖像處理理論最直接的應用,其涉及的技術還可以應用於其它領域,比如虛擬現實、3D GIS、數據可視化等,其重要性不容置疑。隨着硬件的不斷發展,行業對渲染場景的規模和真實感提出了更高的要求。

  第一章 緒論

  1.1概述

  眾所周知,近幾年以電子游戲為主的計算機互動娛樂產業迅猛發展,已成為國民經濟的重要組成部分。然而,由於我國的軟件業起步較晚,3D游戲的核心技術被歐美、日韓等牢牢占據。如何掌握相關核心技術已成為中國電子娛樂產業的當務之急。

  室外場景渲染是指對戶外所有景物的真實繪制,相對於室內場景渲染,它更為復雜。在3D游戲特別是網絡在線游戲中,室外大場景渲染是一塊非常重要的內容,它也是3D圖形引擎的核心(見圖1.1)。游戲引擎中大場景的渲染技術是圖形學和圖像處理理論的最直接應用,其涉及的技術還可以應用於其它領域,比如虛擬現實、3D GIS、數據可視化等,其重要性不容置疑。

  1.1.1室外場景渲染研究的內容和難點

  真實感的室外場景除包括地表的基本幾何形狀繪制,還包括地表上的生物如:草、岩石、樹等的渲染以及對光影效果的表現。其中的難點主要在大規模地表的數據處理和真實感的仿真。地形場景中模型圖元的數量是以場景大小平方的速度增長的。一個8193×8193維數的地形,如果不考慮減低細節程度和裁剪,繪制一幀將要渲染128M個三角形,這樣的三角形量在PC級別的機器上目前還是遠不能實現交互式幀率的。所以,如何減少渲染地形的圖元數目一度成為室外場景實時渲染的關鍵問題。隨着硬件技術的發展,每秒鍾處理上億個三角形已不再困難。很多計算如幾何變換和光柵處理都可以交給GPU去計算。在GPU數據吞吐量很大的情況下,如果~個算法在剔除渲染圖元的過程中占用了太多CPU資源,出現GPU等待CPU的情況,那么即使算法在剔除多余頂點方面做得很好,總體繪制效率也不是高效的。所以在目前的顯卡硬件架構下,能充分發揮CPU與GPU性能,消除局部效率瓶頸的算法才是最好的算法。

  在真實感仿真上,比如對草叢的模擬,如果全部用細節三角形面片,那即使一片草地需要渲染的三角形個數也是難以想像的。目前對物體細節的表現還主要是運用紋理貼圖的方式來實現。光影效果的表現涉及局部光照模型、全局光照模型、光照貼圖、陰影生成等相關算法和技術。

  1.1.2國內外技術發展歷程和現狀

  在國外,3D游戲中場景渲染技術的發展大致可以分為三個階段:

  三維真實感場景渲染領域的研究在國外起步很早,很多相關算法在80—90年代就已提出,並建立了非常嚴密的理論體系。比如對場景渲染非常重要的多邊形LOD算法,場景空間管理的BSP、四叉樹、八叉樹等算法,光照模型,陰影算法等。但是這些算法在資源有限的微機上受到各方面限制。當時的這些算法還僅限於在大型機和圖形工作站上實現。

  92年,隨着ID Soft公司一款游戲Quake(雷神之錘)的發布,標志着第一款支持多邊形模型、動畫、粒子系統的全三維游戲在個人計算機上正式誕生。在隨后發布的QuakeII、Unreal、Half Life等游戲中,場景渲染相關的LOD技術、BSP空間管理技術、光照貼圖、凹凸貼圖、多重貼圖等相繼應用在3D游戲中。隨后出現的Quake、Unrea]游戲引擎,更是標志着3D游戲引擎技術走向成熟。

  現階段,隨着顯卡技術的發展,GPU不但支持標准的(固定的)變換與光照(T&L)管道線,還支持頂點着色(vertex shader)和像素着色(pixel shader) 方式,開發人員因此有了更大的自主空間,可以實現更真實的繪制功能。在此環境下,各大公司都着手開發新一代3D游戲引擎。其中商業引擎以QuakeIII、UnrealII最為出名。此外,軟件開源社區的不斷壯大,也誕生出一些比較好的開源3D引擎,比如OGRE等。運用這些引擎中的場景渲染技術能生成真實感更強的水波、天氣系統、茂密的森林、流熔岩的火山等效果,場景的規模也更大,頂點動態光照技術也開始在室外場景中應用。

  3D游戲的趨勢是往超大規模場景,真實感表現的虛擬世界發展。大規模場景表現和游戲的虛擬仿真,自然也成為了世界上3D游戲行業非常熱門和前沿的研究領域與方向。比如美國暴雪公司的“魔獸世界"和韓國NCSOFT公司的“天堂2"已經在這兩個方而取得了相當的突破和進展。暴雪的“魔獸世界"按人的比例來計算,世界地圖已達到35km×35km。

  隨着電子娛樂業的迅猛發展,國內目前從事3D引擎研究和開發的公司也多了起來。比如目標軟件的GFX3D引擎,盛大公司的3D引擎,網易公司的3D引擎,錦大科技的AURORA引擎等,還有一些游戲工作組的3D引擎,比如WIN3D系列,Origo系列,TUAM9系列引擎等。但總體上來說,國內還處在使用和模仿優秀引擎的階段,很多都是在國外優秀引擎上做一些延伸。真正嚴格意義上自主開發產品還幾乎沒有,或者說自主開發產品的質量和歐美日韓還有一定差距。這種差距在一定程度上反映在3D大場景渲染技術方面,因此深入的展開這方面的研究十分必要。

  1.2課題研究的目的

  本課題希望通過剖析多款成熟3D游戲、引擎,對3D引擎的核心部分一室外場景渲染技術進行探討,並設計和實現自己的一些方案,給我國商業游戲引擎的開發帶來一些啟示。

  1.3論文的篇章結構

  本文本着注重實際應用的前提,通過剖析開源3D引擎並運用推測驗證的方法,對室外場景渲染的主要技術進行了研究和實現,在很多章節也提出了自己的方案和優化方法。以下對各章的內容進行簡要描述。

  第一章緒論。介紹3D室外場景渲染的基本概念,介紹國內外在這一領域的研究現狀,闡述課題的意義和研究內容。

  第二章介紹3D圖形渲染的基礎知識,包括圖形渲染的原理、流程以及實現圖形渲染可以應用的類庫OpenGL。

  第三章研究室外超大場景地形網格的生成與簡化算法,比較各種基於LOD思想的網格簡化算法的優劣,提出基於幾何多重映射(GeoMipMap)的地形繪制優化方案,並得以實現。研究也涉及到地形的空間管理算法、可見性剔除算法、超大場景的數據加載方式研究等。

  第四章研究場景的真實感渲染技術。主要涉及應用多層紋理混合貼圖模擬融合性地表技術,室外場景的光影效果處理技術,天空、樹、草、霧等的渲染方案和技術。

  第五章描述本設計實現的室外渲染軟件Demo OSRender,以及程序編寫過程中可用的優化技術。

  第六章對全文進行總結,介紹開題論文的完成情況,客觀評價優點和不足,並給出改進的方向。

 

第二章 3D游戲場景渲染的基礎知識

  室外場景渲染從基本原理上來說可以分為兩類:基於體素的渲染方法和基於多邊形的渲染方法。早期的3D游戲,如三角洲特種部隊就是采用的體素渲染法。體素法類似光線跟蹤渲染,它從屏幕空間出發,找到地形與屏幕像素發出的射線交點,然后確定該像素的顏色。這種方法不依賴具體的圖形硬件,整個渲染過程完全使用CPU處理,因此它不能使用圖形卡硬件來加速,並且對於一個場景來說,往往不只是地形,還有其他使用多邊形描述的物體,體素法渲染的圖像很難與硬件渲染的多邊形進行混合,因此這種方法現在用得極少,而多邊形渲染方法則成為一種主流。選擇多邊形來描述和渲染地形有很多優點,最主要的是它能夠很好地使用硬件加速,並且能夠和其他多邊形對象一起統一管理。因此本課題僅對基於這種多邊形面片的場景渲染技術進行研究。

  2.1基於多邊形面片的3D渲染原理

  2.1.1基於多邊形面片的圖形繪制流程

  用多邊形面片來建立物體的三維模型有容易表示、計算簡單、容易繪制幾個方面的好處,因此在游戲三維圖形渲染中被廣泛采用(通常是三角形面片)。從模型的頂點送入渲染管道到最后形成二維圖像的過程如下圖2.1所示:

  2.1.2變換

  渲染管道中大部分工作是把對象模型的頂點在一個坐標系中的表示轉化為另一坐標系中的表示,一般需要經過模型變換和相機變換兩個過程。

  通常,幾何模型被保存在自身的建模空間,即每個模型擁有單獨的局部坐標系統。為了建立場景幾何關系,模型將統一放置到世界坐標系中,從建模坐標系變換到世界坐標系叫模型變換。幾何模型的最終成像是在攝像機坐標下,將場景物體從世界坐標系變換到攝像機坐標系叫相機變換。相機的外部參數決定了相機坐標系,因此場景在屏幕上的成像位置與形狀和相機的外部參數有關。模型和相機變換采用4×4齊次矩陣表示,其形式如下:

  比如平移變換可表示如下:

  點(x,y,z)平移(tx,ty,tz)后的坐標為(x",y",z")。此外還有旋轉、縮放變換,這三種基本的變換可以合成任意幾何變換。

  通常把模型變換和相機變換的矩陣復合成一個矩陣處理,便於提高效率。在所有的圖形繪制庫中,都提供了程序接口供應用程序設置模型和相機變換對應的矩陣。其中,模型變換由場景物體的平移和旋轉、縮放變換組成,相機變換則通過設置相機的位置、相機方向和向上向量來決定。

  2.1.3裁剪

  相機的參數包括投影方式、近平面、遠平面、視野和屏幕的長寬比率,它們決定了物體從相機坐標系投影變換到屏幕坐標系的位置。這些參數實際上定義了一個視域四棱錐,也叫做視錐體。

  位於視錐體之外的場景部分不需要送入后續階段處理。因此,對完全位於規一化的設備空間之外的幾何元素,可簡單地舍棄。而部分位於規一化的設備空間之外的幾何元素則需要進行裁剪操作。由於裁剪的面就是立方體的6個表面,實現起來非常簡便。應用程序也可以定義額外的平面對場景進行裁剪。視域裁剪通常由底層圖形AP]自動完成。注意這里所說的裁剪是比后面章節要介紹的視錐體剔除更底層的裁剪。

2.1.4投影

  把三維物體變為二維圖形表示的過程稱為投影,其又分為平行投影和透視投影。透視投影是所有投影線交於投影中心;而平行投影是投影線平行,投影中心在無窮遠。在游戲虛擬場景模擬中主要應用透視投影。透視投影可分為一點透視、二點透視和三點透視。

  針對一點透視投影如下圖:

  從上圖P點在觀察平面上的投影我們可以得到描述屍點的參數方程:

  2.1.5光柵化

  從頂點組成的幾何模型變換到像素的過程稱為光柵化(Rasterization)。它的機理與得名來源於CRT顯示器的電子槍發射方式。光柵化可分為四個子階段,即消隱、逐像素光照明計算、紋理映射和顏色融合。

  (1)消隱

  消隱的目的是解決場景的可見性問題。所謂可見性計算,是指計算物體投射到投影平面如果有交疊,觀察者應該看到哪個投影點。圖形學中經典的解決方案是物體空間Z一緩沖器算法和圖像空間的光線跟蹤算法。由於Z-緩沖器算法易於在圖形硬件中實現,逐漸演化稱標准的圖形硬件消隱技術。在深度緩沖器中,每個像素上始終保留最接近視點的深度。當光柵化產生新的像素后,該像素的深度和保存在深度緩沖器的像素深度進行比較,如果小於已有的像素深度,則用像素的顏色和深度替換分別保存在顏色緩沖器的像素顏色和深度緩沖器中的像素深度,反之保持不變。在繪制之前,深度緩沖器必須初始化為最遠的深度,以保證可見性計算的正確性。

  (2)光照計算

  光照計算影響物體的外觀。進行光照計算的幾個要素包括光源位置、光源屬性、光照模型、物體表面材質屬性、紋理和物體表面幾何屬性(包括法向、微幾何結構)等。最簡單的光照明計算技術是在物體建模時指定每個頂點的顏色和紋理坐標,在繪制時直接利用顏色和紋理映射融合為最終顏色。這種方法稱為平坦渲染(Flat shading)模式,它的速度快,但效果欠佳,是早期游戲中最常用的技術。

  真正意義上的光照計算必須指定每個光源本身的屬性,包括光源的類型(點、線、面光源)、位置和光源的漫反射/鏡面反射的顏色,然后根據光照模型(分局部光照明模型和全局光照明模型,前面所述直接指定頂點顏色的方法可看作最簡單的局部光照明模型)在物體的每個頂點計算每個光源對該頂點的光亮度貢獻,最后在光柵化層插值頂點上的顏色。這種處理模式稱為Gouraud渲染模式,著名游戲guakeEi就使用了Gouraud渲染模式。

  逐頂點的光照計算對應於Gouraud渲染模式,而逐像素光照計算則對應於法向渲染模式(也稱為Phong渲染模式)。Phong模式在游戲場景渲染中也被廣泛采用。在游戲三維引擎設計中,必須根據圖形硬件配置和場景復雜度選擇合適的光照渲染模式。

  (3)紋理映射

  紋理映射是增強場景真實感的一種簡單有效的技術。它將預生成的圖像直接貼在物體表面,模擬物體表面外觀,因此也叫貼圖法。紋理映射的擴展技術有很多,包括環境映射、光照圖、球面映射、立方體映射、凹凸映射、位移映射等,是圖形渲染加速中最重要的手段。在真實感渲染章節會有更詳細的討論。

  (4)顏色融合

  對於每一個像素,前面步驟可能產生光照計算和紋理映射兩類顏色值。不僅如此,光照明計算的結果可能來自多個光源,而每個光源可導致漫反射和鏡面反射的光亮度。此外,同一像素也可能采集來自多個紋理的值,如多通道紋理映射和單通道多重紋理映射。所有這些顏色值將根據各自的不透明度融合出最終結果。顏色融合不僅能加強場景真實感,還能產生半透明繪制、景深、基於alpha緩沖器的反走樣、軟陰影等特效。

2.2圖形繪制庫OpenGL

  2.2.1 OpenGL的基本理解

  圖形渲染引擎中的最底層可以自己實現,但是沒有顯卡硬件廠商的支持,自己實現的往往不能得到硬件加速特性。所以游戲中的圖形渲染通常需要利用0penGL和DirectX等成熟圖形庫。現在很多游戲引擎對兩個庫都提供支持,作為學術研究OpenGL是更好的選擇,所以本設計在實現算法時選用了OpenGL。

  OpenGL是一個封裝了硬件圖形加速器的軟件接口口7|,幾乎全部顯卡對它都提夠良好支持。它也是圖形庫的業界標准。OpenGL包括了100多個圖形操作函數,開發者可以利用這些函數來構造景物模型、進行三維圖形交互軟件的開發。也可以說,OpenGL是一個高性能的圖形軟件開發包。OpenGL支持網絡,在網絡系統中用戶可以在不同的圖形終端上運行程序顯示圖形。OpenGL作為一個與硬件獨立的圖形接口,它不提供與硬件密切相關的設備操作函數,同時,它也不提供描述類似於飛機、汽車、分子形狀等復雜形體的圖形操作函數。用戶必須從點、線、面等最基本的圖形單元開始構造自己的三維模型。當然,象3DS Max那樣更高一級的基於OpenGL的三維圖形建模開發軟件包將提供方便的建模工具。所以,OpenGL的圖形操作函數十分基本和靈活。例如OpenGL中的模型繪制過程就包括網格線繪圖方式、反走樣網格線繪圖方式、平面消隱繪圖方式、光滑消隱繪圖方式、加陰影和紋理的繪圖方式等。總的說來,OpenGL的功能包括以下幾個層面:

  (1)模型繪制

  OpenGL能夠繪制點、線和多邊形。應用這些基本的形體,可以構造出幾乎所有的三維模型。

  (2)模型觀察

  在建立了三維景物模型后,需要用OpenGL描述如何觀察所建立的三維模型。

  (3)顏色模式的指定

  OpenGL應用了一些專門的函數來指定三維模型的顏色。

  (4)光照應用

  用OpenGL繪制的三維模型必須加上光照才能與客觀物體更加相似。OpenGL提供了管理四種光(輻射光、環境光、鏡面光和漫反射光)的方法,另外還可以指定模型表面的反射特性。

  (5)圖象效果增強

  通過反走樣、混合和霧化等函數來增強圖象的效果。

  (6)位圖和圖象處理

  OpenGL還提供了專門對位圖和圖象進行操作的函數。

  (7)紋理映射

  OpenGL提供的一系列紋理映射函數使得開發者可以十分方便地把真實圖象貼到景物的多邊形上,從而可以繪制逼真的三維景觀。

  (8)實時動畫

  為了獲得平滑的動畫效果,需要先在內存中生成下一幅圖象,然后把已經生成的圖象從內存拷貝到屏幕上,這就是OpenGL的雙緩存技術(double buffer)。OpenGL提供了雙緩存技術的一系列函數。

  (9)交互技術

  OpenGL提供了方便的三維圖形人機交互接口,用戶可以選擇修改三維景觀中的物體。

2.2.2 OpenGL的工作流程

  整個OpenGL的基本工作流程如2.4圖:

  其中幾何頂點數據包括模型的頂點集、線集、多邊形集,這些數據經過流程圖的上部,包括運算器、逐個頂點操作等;圖像數據包括象素集、影像集、位圖集等,圖像象素數據的處理方式與幾何頂點數據的處理方式是不同的,但它們都經過光柵化、逐個片元(Fragment)處理直至把最后的光柵數據寫入幀緩沖器。在OpenGL中的所有數據包括幾何頂點數據和象素數據都可以被存儲在顯示列表中或者立即可以得到處理。OpenGL中,顯示列表技術是一項重要的技術。

  OpenGL要求把所有的幾何圖形單元都用頂點來描述,這樣運算器和逐個頂點計算操作都可以針對每個頂點進行計算和操作,然后進行光柵化形成圖形碎片;對於象素數據,象素操作結果被存儲在紋理組裝用的內存中,再像幾何頂點操作一樣光柵化形成圖形片元。

  在整個流程操作的最后,對圖形片元進行一系列的逐個片元操作,最后的象素值送入幀緩沖器實現圖形的顯示。

  2.2.3 OpenGL的程序結構

  第一部分是初始化部分。主要是設置一些OpenGL的狀態開關,如顏色模式(RGBA或ALPHA)的選擇,是否作光照處理(若有的話,還需設置光源的特性),深度檢驗,裁剪等等。

  第二部分設置觀察坐標系下的取景模式和取景框位置大小。主要利用了三個函數:函數void glViewport(1eft,top,right,bottom):設置在屏幕上的窗口大小,四個參數描述屏幕窗口四個角上的坐標(以象素表示);函數void glOrtho(1eft,right,bottom,top,near,far):設置投影方式為正交投影(平行投影),其取景體積是一個各面均為矩形的六面體;函數void gluPerspective(fovy,aspect,zNear,zFar):設置投影方式為透視投影,其取景體積是一個平截頭體(frustum)。

  第三部分是OpenGL的主要部分,使用OpenGL的庫函數構造幾何物體對象的數學描述,包括點線面的位置和拓撲關系、幾何變換、光照處理等等。

  以下是第三部分的一個簡單例程:


  2.3本章小結

  場景渲染總的來說分為基於多邊形面片和基於體素兩種方法。由於基於體素的方法不適應現代硬件的渲染流程,故本設計主要研究的是基於多邊形面片的場景渲染。本章從圖形學原理出發,討論了基於多邊形面片的3D渲染的基本流程以及其中涉及的數學模型。另外,還介紹了應用廣泛的圖形庫OpenGL,為下面章節的具體算法討論和軟件實現做基礎鋪墊。

 

第三章 室外場景地形的實時繪制技術

  地形的繪制是指讀取虛擬世界的地圖信息,繪制出場景的地表,並實現角色在場景中實時漫游。它是室外場景實時繪制中最重要的部分,也一直是計算機圖形學中一個重要的研究領域。盡管地形的繪制在不同的游戲中所采用技術會有所不同,但是他們總體上還是遵從一定的流程,如圖3.1所示:

  以下章節會逐步分析相關技術。需要說明的是本章探討的“繪制”還不包括真實感的表現,可以理解為線框模式下的繪制。

  3.1地形繪制所需數據

  地形繪制所涉及的數據主要有:地形的高度圖、縮放標尺、地表紋理圖、地表紋理索引等。在游戲設計中,表現一個場景所需要的一系列數據往往打包放在一起。

  3.1.1高度圖

  對基於三角形面片渲染的3D場景來說,地形的頂點信息就是指組成地形的所有三角形面片每個頂點的三維坐標。最簡單最有效的地形頂點表示方法是使用高度圖(heightmap)u利。

  通常高度圖是一張灰度圖,它的長寬通常滿足(2^n+1)。每個像素的灰度值表示地形相應位置的高度值,用連續的三角形面片來連接這些三維空間中的頂點就構成了地形的面片。高度值的值域范圍0--255足以表現游戲中場景的地形起伏,如果需要也可以使用雙字節,四字節或更高來描述高度值。在設計中很多游戲由於封裝數據的需要,通常自定義高度圖的格式,而不采用灰度圖,但是其存儲的數據本質上是一樣的。

  3.1.2縮放標尺

  地形信息還應包括縮放標尺,用來表示在繪制時高度圖中相鄰兩個灰度值之間相隔的X,Z方向上的距離值。比如一張33×33的高度圖的縮放標尺是l米,則在游戲中我們可以看到一個32MX 32M大小的場景。此外,在Y方向上也有一個縮放標尺,負責地形高度的縮放。

  3.1.3頂點法向量

  地形網格上的各點都需要一個表面法向量。它可以用來計算光照,進行背面剔除,檢測與表面的碰撞等。一個三角形的法向量可以通過三角形上兩向量叉乘的方法輕松獲得,而頂點級法向量可以通過共享此頂點的所有三角形的法向量求平均值來模擬,在很多情況下,這樣的效果已經能夠達到要求了。頂點處其實是沒有法向量定義的,因為此處網格表面不連續。

  3.1.4多種地表紋理及光照貼圖

  為了表現地形的真實感,目前游戲中的做法是通過多重紋理混合貼圖來實現的。其中用到的貼圖通常以各種圖片格式保存。關於這種技術的討論在真實感渲染章節會詳細介紹。

  3.1.5單個場景地形的數據結構

  由以上的分析我們就可以得到單個場景地形的數據結構,如下所示:


  3.1.6面片的構成

  任何多邊形模型都可以轉換成三角形的集合,所以地形網格也是三角形的集合。如果三角形被各自獨立地送至圖形硬件進行繪制,共享的頂點數據就需要執行重復冗余的運算,並且相同的數據還被傳送至少兩次以上。降低這些額外開銷的一個方法就是把彼此相鄰的三角形構建成三角帶(strip)。首先,把第一個三角形的三個頂點放至strip之中,然后將其余的三角形頂點依照相鄰順序依次放至strip中,每個三角形只需要加入二個頂點。缺省條件下,在strip中彼此相鄰的頂點都構成了連接兩個相鄰三角形的公共邊。如果連接規則(順時針或者逆時針順序)需要發生改變,則可以使用swap命令交換頂點順序,或者重新將某一個頂點放入strip之中。扇形三角形帶(Triangle fans)可以看作是三角帶的一種退化形式,只是其中所有的三角形都共享一個公共頂點。圖3.2是三角形帶的表示方法:

  V0,V1,V2,V3,V4五個頂點構成了表示三個三角形的三角形帶。注意描述三角形帶時,頂點的順序很重要,因為是遵循一定連接規則(順時針或逆時針)的。在OpenGL中生成最右方的三角形帶的代碼如下:

  3.2 LOD地形網格簡化算法的基本思想及意義

  所謂地形網格的簡化是指通過算法減少提交到顯卡的頂點,以減少每幀同屏渲染的三角形數量,借以提高渲染速度。

  細節層次(LOD,levels of Details)技術是一種符合人視覺特性的網格簡化技術。我們知道,當場景中的物體離觀察者很遠的時候,它們經過觀察、投影變換后在屏幕上往往只是幾個像素甚至是一個象素。我們完全沒有必要為這樣的物體去繪制它的全部細節,可以適當的合並一些三角形而不損失畫面的視覺效果。對於一般的應用,我們通常會為同一個物體建立幾個不同細節層度的模型。這樣的技術應用在地形渲染中,也稱之為多分辨率地形(Multi—Resolution Terrain)。下圖就是一個多分辨率地形網格:

  在開發3D游戲時也有不采用基於LOD的地形網格簡化算法的做法。典型的游戲有韓國游戲公司開發的著名3D網游《奇跡》,每個Tile場景地形它用257×257的高度圖構成,采用靜態載入場景數據的方案同樣產生出了美妙的場景。對於這么小的場景,當然沒有必要做地形網格的簡化,現在的一般顯卡足以能夠應付。之所以他能成功應用這種方式,是因為在設計場景時限制了地形的高低起伏,使地形趨於簡單,縮放標尺取得很大,同時用紋理和光照貼圖來彌補地形本質上的單調。另外,如果運用基於外存的動態數據載入算法,理論上也可以不用基於LOD的地形網格簡化算法。

  隨着3D游戲的成熟,玩家需要有更真實的體驗,因此地形變得更加復雜,場景變得更加巨大,地形的繪制需要很多數據參與,對系統資源消耗巨大。如果一點也不進行地形網格簡化,試想一個1025 X1025的場景就將生成2M個三角形,渲染大的場景時顯卡的處理能力很難跟上。在顯卡的數據吞吐能力有限的情況下,游戲場景渲染中普遍基於LOD的思想,減小繪制多邊形數目。它能在犧牲適量CPU資源的前提下大大減輕圖形卡的數據負載,使CPU與GPU之間沒有明顯的瓶頸,從而達到實時渲染大地形的目的。

  基於LOD的地形網格簡化算法分為動態LOD和靜態LOD算法。動態LOD算法是在每幀渲染之前都經過計算重新確定送入顯卡的頂點。所有的頂點數據全部需要參與運算。ROAM算法和基於四叉樹的動態LOD算法都屬於此類,GeoMipMap算法則是靜態LOD算法的代表。

3.3 ROAM算法

  1997年,Duchaineau提出了實時優化適應性網格(ROAM,Real-timeOptimalAdaptive Meshes)算法瞳1,它是一種基於規則網格的連續LOD網格構造算法。其基本思想是在對地形進行三維顯示時,依據視點的位置和視線的方向等多種因素,對表示地形表面的三角形圖元進行一系列基於三角形二叉剖分分裂與合並,最終形成和原始表面近似且無縫無疊的簡化連續三角形表面。

  ROAM的基礎是等腰直角三角形的一個性質。等腰直角三角形可以從直角頂點到斜邊引一條垂線,這條垂線把這個三角形分成了兩個小的等腰直角三角形,並無限制的遞歸分下去。而從另一個角度來看,這正好構成了一個二叉樹,每個三角形都是把它分開而生成的兩個小三角形的父母(parent)。根據這條性質,只要計算出哪些三角形需要被分割開、哪些三角形需要合並成為自己的父母,就可以做到控制LOD(分開就是增加LOD,合並就是減少LOD)。圖3.5顯示了1~4層三角形二叉樹和相應的層次結構。

  當把一個三角形分成兩個的時候,會在斜邊上增加一個頂點,是由斜邊的兩個端點插值求得。不過高度卻不能插值。因為高度是按照相應的地圖數據來的(比如heightmap)。所以,就存在一個插值以后的高度和實際高度不匹配的問題(會產生裂縫)。為了解決這個問題,就需要調整Y軸上的值來升高或者降低這個頂點,這個頂點高度的調整距離就稱為誤差量。

  要確定一個三角形是否要被分割,就要看它是否能精確的描述地形的高度數據。如果可以的話,自然就不用分割了,多邊形越少越好。如果不能的話,就細化它,也就是分割掉,直到所有的小三角形都能夠精確表示地形數據為止。

  通過不停的分割,三角形越來越小,每個三角形在高度圖上所覆蓋的面積也越來越小。那么,總會分割到足夠小,使得三角形的面積和高度圖上一個點的面積之比為l:l,分到這里就不用再分了。通過檢查所有孩子的誤差量,我們就找到了一個描述三角形是否需要分割的精確方法。當遞歸的遍歷這棵樹以后,就能夠找到這棵樹里面的最大誤差量,就是所謂的largest error metri c。這個最大誤差量如果是O那就是完全符合實際高度了,這個值越大,就越不符合。

  用每個三角形的誤差量和鏡頭到該三角形的距離比較,用以判斷是否一個三角形需要分裂。用以給每個三角形做測試的值是人為定義的,這個值又叫錯誤容忍度(error metric tolerated)。通過錯誤容忍度對每個三角形做測試,小於這個容忍度的三角形就被留下(不分裂),大於這個的就被分裂掉,然后再分別對被分裂的三角形的兩個兒子做分裂。如果加入了視角依賴(view—dependence)的話,就需要通過鏡頭到三角形的距離來調整這個容忍度了。鏡頭越遠,容忍度就越大,而鏡頭越近,容忍度就越小。’

  此算法的優點在於:可動態的改變每個網格;可在渲染時控制每個網格的生成與否;可以和紋理坐標很好的結合在一起;可控制地形三角形的最大數目;可以根據坡度的不同自動調整LOD的細節程度,也就是說在地形坡度大的地方LOD細節程度高,在地形坡度小的地方LOD細節程度低;可以根據到觀察點的距離自動調整LOD的細節程度,也就是說在離觀察點近的地方LOD細節程度高,在離觀察點遠的地方LOD細節程度低。

  3.4基於四叉樹的動態LOD算法

  3.4.1算法思想

  此算法是Lindstrom提出的n劓,他用了一個叫四叉樹(Ouad Tree)的結構來描述地形,先把可視范圍內的地形分割成四等份矩形子塊,依靠計算判定因子檢測四個子塊,如果檢查到某個子塊的網格精度達到所要求的繪制精度就不需要往下再分割;否則就把此子塊再分割成四等份更小的子塊,依次遞歸分割下去,直到所有子塊中的矩形網格都達到渲染精度。

  3.4.2此算法涉及的難點

  ●對T形裂縫的處理

  由於不同層次間的采樣間隔不同,在可視化過程中會出現縫隙,這種縫隙必須進行專門的處理.如圖所示,上方矩形具有較高的分辨率,而下方矩形的分辨率較低,這使得矩形間的連接處出現了末被覆蓋的區域(陰影處),從而在地形繪制時就產生了“裂縫”。

  每個.LOD層次區域節點均為正方形,在分辨率低的四叉樹區域節點上,四個方向均可能出現縫隙,所以必須依次用自身節點的分辨率大小比較四個方向上臨近節點的分辨率大小。如果前者小於后者,則必須通過在相鄰邊上加一條邊來實現裂縫的消除。當自身節點分辨率與相鄰節點的分辨率相差不止一級,那么還必須遞歸比較並添加邊,直到完全消除裂縫。

  ●判定是否細分

  子塊離視點的距離和地形的平坦度共同確定是否需要進一步細分以達到所要求的渲染精度,從而使最終分割后的葉子節點達到最優。離觀察者視點越近的地方細節越多,地形越不平坦細節越多。

  子塊離視點的距離d可以用公式表示如下:

  其中(Xl,Y1,Z1)為視點坐標,(XO,YO,ZO)為子塊的中心坐標。對一個子塊區域平坦度的計算如圖3.7所示:

  對於圖中這個子塊的平坦度,先計算出高度值h卜h8,找出其中最大的高度值hMax,最小的高度值bMin,令err=hMax—hMin。err即是此子塊的平坦度。

  err的值越大就意味着子塊越不平坦,網格細節應該越多。

  最終,綜合考慮距離和平坦度兩個因素得出判斷是否細化的標准:

  如果err*r/d—k>O則繼續細化,反之則不。(k為一個可變的控制值,r為子塊的i/2邊長,err為子塊平坦度,d為子塊到視點的距離)。

  3.4.3算法運行步驟

  (1)初始化頂點數組,建立完全四叉樹並初始化,使每個節點描述清楚自己對應的區域地形。

  (2)實時渲染:首先對每個四叉樹節點進行視錐體裁剪,確定進行渲染的四叉樹節點,再渲染這些節點。

  a.對節點進行視錐體裁剪。

  b.確定哪些節點需要渲染:

  先計算本節點所管理的地形區域離視點的距離,再計算其平坦度,兩者共同確定渲染精度值。

  根據渲染精度值和判定標准來確定是否需要進一步細分,對於需要細分的就按四叉樹思想遞歸細分,而不需要細分的就設置它的渲染標志位為真。c.遍歷四叉樹,渲染標志位為真的節點,並判定本節點區域網格在渲染時是否會出現T型裂縫。判定方法是通過和四周相鄰的節點比較細節分辨率值,如果小於相鄰節點則做修補裂縫處理。

  (3)釋放資源。

  3.4.4算法相關代碼




  以下是1025×1025大的高度圖用基於四叉樹的LOD算法在線框模式下生成的地形網格:

3.5游戲中地形繪制更好的方案.

  隨着圖形卡數據吞吐能力的不斷提高,每秒鍾處理上億個三角形己不再困難。很多計算,比如幾何變換和光柵處理都可以交給GPU去計算。所以在GPU數據吞吐量很大的情況下,如果一個算法在剔除渲染頂點的過程中占用了太多CPU資源,出現GPU等待CPU的情況,那么即使算法在剔除多余頂點方面做得很好,總體繪制效率也不是高效的。上面討論的兩種動態LOD算法(RoAM和基於四叉樹的動態LOD)都存在這方面的缺陷。並且,受硬件帶寬的限制,頻繁地傳輸海量頂點數據,使得時間集中消耗在數據“遷移"過程中。過多的DP(Draw Primitive)也使得圖形卡不能發揮最大功效,造成資源極大浪費。所以要適應現代圖形卡的硬件架構,算法必須改進,幾何多重映射(GeoMipMap,Geometrical Mipmapping)等算法由此產生。

  本設計在GeoMipMap算法的基礎上,改進了原算法關於抑制不同細節分辨率模型之間突變的處理方法,使得在提高繪制效率的同時,保證了繪制圖形的質量。通過使用查表法的分塊網格頂點數據組織方式,使得CPU的工作進一步減輕。此外,本設計還利用了現代圖形卡的存儲功能來優化地形的繪制。

  3.5.1 GeoMipMap算法

  ●基本思想

  GeoMipMap算法是Willem根據紋理多重映射的概念提出的H3,他把整個地形場景在XZ平面上進行分塊(block),比如用33×33的block把1025X 1025的地形表示為32×32個block。每個分塊可用不同分辨率的網格模型來描述。在同一分塊內,網格模型的分辨率相同。采用隔行采樣的方式生成不同分辨率的網格。整個地形的模型表示和組織如圖3.9所示:

  不同的block之間互相拼接時,如果分辨率不同則可能產生裂縫。為了消除裂縫,在較高分辨率的block邊界上,忽略一些點作為網格頂點,如圖3.10所示:

  每個block分辨率是通過屏幕空間誤差H3來決定的。在地形數據預處理階段,取一個屏幕誤差閥值£(一般取4個像素),預先計算出當e等於4個像素時,視點到block的距離d和相應的block分辨率,並保存在查找表中。當實時繪制時,根據視點到每個block的距離查找表中的d,查找決定該block的網格分辨率。

  ●優點和不足

  GeoMipMap算法的網格生成方式顯然和ROAM算法以及基於四叉樹的連續性LOD算法大不一樣。以基於四叉樹的連續性LOD算法為例,他是通過自頂向下的方式用四叉樹遞歸地將地形分成一個個小地形塊,越往下細分,地形塊越小,直至不能細分。當視點發生改變時,所有的頂點都必須重新參與細分的遞歸運算,這種算法能根據實際情況最大程度確定整個地形的網格分辨率,但計算量很大,並且遞歸層次很多,CPU的負載極大。而對於GeoMipMap算法來說,當

  視點改變時,只需要判斷可見的每一個block的網格分辨率應該是多少,block內部的頂點並不參與計算。雖然這種做法不能最大化減少進入渲染管道的頂點,減少三角形面片,但是增加的這些渲染頂點對現代圖形卡來說是不會影響繪制速度的。相反,由於他減小了實時繪制時模型簡化的計算復雜度,速度得到極大提高,所以他是符合現代圖形卡硬件架構的地形繪制算法。此外GeoMiaMap相對固定的三角形面片組織方式,也使得進入固定渲染管線的頂點能更好的組織成三角形帶,大大減少傳入圖形卡的頂點個數。

  但是,這種算法由於不是連續的LOD算法,也就是說LOD的粒度比較粗放,因此在block的網格分辨率發生改變時,會產生網格形狀的突變,使得在地形漫游時,圖形過渡不自然。雖然通過屏幕投影誤差來選擇block的網格分辨率可以使突變的效果有所減輕,但對用戶來說仍比較明顯。本設計通過線性插值的思想,使層次過渡由突變轉為逐步遞進,極大減小了這方面的不足。

  3.5.2 GeoM i pMap優化算法

  ·地形數據的總體組織和表示

  我們首先讀入一個場景的高度圖數據(heightmap),保存在一個頂點線性表中,然后把這個場景在XZ平面上划分成均勻大小的多個block。block的大小按需求而定,其邊長滿足2l+l,如9×9,17×17,33×33等。如果地勢總體比較平坦,我們可以選得大一點,如果對地形的細節要求較高我們可以選得小一點。本文以17×17作為block的大小。block通過頂點索引所組成的三角形帶描述他負責的一片小的區域。整個場景用一棵完全四叉樹把這些blocks組織起來。實時渲染時完全四叉樹負責場景的裁剪,決定哪些blocks應該繪制,然后計算可見block的網格分辨率,從而得到整個地形要渲染的三角形面片。其數據組織圖如下所示:

  用面向對象的方式描述地形對象:

  當地形是超大地形繪制時,我們采用多線程機制加上場景緩沖池的方法實現大地形數據的動態調入和管理。每一個場景Tile作為動態加載單元,用一個緩沖池來管理,用單獨線程來維護。詳細討論在3.7節。

  · block多分辨率網格模型的構造和數據組織

  Willem在他的論文中指出當細節層次不同時block的頂點取舍方法,以及為了避免出現T型裂縫,block的邊界頂點應該怎么調整。在他的思想基礎上,本設計提出一種基於查找表的block三角形帶生成方法。

  我們把block的中心地帶和邊界分開對待。在預處理階段就生成五個頂點索引表。如圖3.12所示:

  中心地帶索引表負責生成block中心的三角形條帶,其索引參數就是自身的網格分辨率。邊界索引表負責生成與其他block相鄰區域的三角形帶(防止T型裂縫)。索引參數有三個:自身的網格分辨率,相鄰的方向,相鄰block的網格分辨率。

  網格都使用三角形帶(Triangle Strip)的方式生成,有些地方需要生成一些退化三角形,用於三角形帶的連接。運用三角形帶的方式比三角形扇和純粹三角形方式更能減少頂點個數,提高繪制效率。

  這五個位置的網格所關聯的索引表一起就能夠描述任何一個block網格所有頂點的相對位置(在block區域內的位置)。在場景渲染初始化時,我們讀入block的五個LOD頂點索引表,得到block的不同分辨率網格。在實時渲染的時候,針對一個特定的block,我們可以根據這個block在場景中的起始位置,他的網格分辨率,和他四周block的網格分辨率,直接查表得到這個block完整的三角形帶頂點索引,減少了CPU的判斷和計算量。內存中只保存一個block網格頂點的相對索引,不是整個場景的所有block的頂點索引都保存,因此不會造成什么內存消耗。

  · 用面向對象的方式來描述block

  block是本算法很重要的對象,可以描述如下:

  · 利用線性插值逐步過渡不同分辨率的網格模型

  當block的網格分辨率次發生變化時,其網格模型可能變化較大,由於變化是在瞬間完成的,極易被觀察者察覺。但如果我們把這種變化由突變改為漸變,用戶就不易察覺,其視覺影響也就可以忽略不計。

  我們在預處理階段已經得到一個合適的查找表,可以查出block的網格分辨率c與block到視點的距離d之間的對應關系。我們假設d=lOOOm時c=n+l,d=2000m時c=n。

  如果現在d=1500m,則網格的分辨率正處在n和n+l的過渡階段。我們取網格頂點為c=n+l時的索引,他比c=rl時多出一些細節頂點,對這些多出的細節頂點,我們對其高度進行線性插值,使其緩慢在分辨率n+l和分辨率rl之間過渡。如圖3.13,v3為高分辨率時出現的細節頂點,v4為模型在低分辨率時v3的初始點。隨着網格向高分辨率過渡,v4逐步過渡到v3。v’的Y坐標由下面的公式決定:

  如3.13圖:

  采用這種插值的手段后,只增加了很少的計算,視覺效果上卻得到了很大的提高。

  ·利用顯存保存地形的頂點表

  現代圖形卡已經支持把一定大小經常使用的數據直接保存在顯存中,所以如果我們把經常使用不頻繁變動的數據保存在顯存中,可以避免大量數據在渲染時頻繁從內存傳輸到顯存。在實驗中通過0penGL的VBO(Vertex Buffer Object)方式把頂點線性表數據保存在顯卡中,經比較渲染速度大幅提高。

  ·描述算法的流程

  預處理階段:

  (1)載入地形數據,初始化頂點線性表。

  (2)初始化所有分辨率的block模型所對應的三角形帶頂點索引表,此表保存的是組成三角形帶的相對頂點索引。生成描述整個地形場景的block數組,每個block記錄自身在場景中的絕對位置。

  (3)構造完全四叉樹,每個子節點對應管理一片區域(一個或多個block),設置包圍球半徑。每個葉子節點都對應一個block索引。實時繪制階段:

  (4)遍歷完全四叉樹,根據空間裁剪算法,得到可見block的索引。

  (5)計算這些block的網格分辨率,根據分辨率和網格的三角形帶索引表,頂點表,可以得到組成地形網格的所有三角形帶頂點的完整信息。

  (6)根據前面介紹的線性插值方法,調整相關頂點的高度信息。

  (7)送入渲染管道繪制。

  (8)回到(4)。

  ●測試結果

  我們使用大小為2049×2049的高程圖作為實驗數據,以Athlon2500+,DDR IG,ATI 9550,128M顯存作為硬件環境對上述算法進行測試。程序用VC+OpenGL在windows平台上完成。其中分塊大小為17×17,共分4個細節分辨率,以下是場景繪制的網格形式截圖:

  從表3.1中的技術參數統計來看,新算法的渲染效率有很大提高,能滿足大規模地型的渲染要求。

3.6地形的空間管理和可見性剔除算法

  我們只對地形進行分辨率上的簡化是不夠的,攝像機在場景中只有一個可見范圍,怎么樣有效的剔除不需要渲染的地形部分,這就要涉及到地形的空間管理算法,可見性裁剪算法口9|。四叉樹,八叉樹,Bsp樹,背面剔出等很多其他方法都是針對這個目的而提出的。本設計的可見性剔除采用了如下流程:

  3.6.1按距離剔除

  單靠視錐體剔除已經能剔除大部分面片,但是在他之前有一步距離剔除也是有必要的,因為他的計算很簡單,就是通過計算地形block的包圍球心與視錐體的距離,距離大於系數k的blocks統統剔除。k的確定一般與天空盒子的大小有關。

  3.6.2視錐體剔除

  從3D到2D投影過程中,需要一個投影體,只有當物體處於這個投影體中的時候,我們才能看到這個物體,否則物體將被裁剪掉。這個投影體通常被稱為視見體(View Frustum)。在進行正交投影的時候,投影體為一個長方體,在進行透視投影的時候,投影體則為一個平頭錐體,所以也叫視錐體。

  空間中物體與視錐體的關系有三種:在視錐體內,在視錐體外,與視錐體相交。只要我們排除在視錐體外的物體,也就是排除在視錐體外的三角形面片就能大幅提高渲染的效率。

  ·求視錐平面系數

  視錐體有上、下、左、右、近、遠,共6個面組成。一個平面的方程可以表示為Ax+By+Cz+D=O。首先,把視錐體變換為長方體狀的裁剪空間。如圖3.16所示,左圖為世界空間中的視錐體。右圖為經過變換后的裁剪體。

  我們規定朝投影體內部的方向為平面的正方向,判斷一個頂點是否在投影體內部時,只要把頂點坐標代入到六個面的方程中,通過檢查結果的符號就可以判斷點是不是在投影體內部(所有的符號都為正)。世界空間的投影體在經過投影變換后,會成為一個范體。我們很容易得到這個范體的六個面的方程。

  我們假設這六個面中某個平面上有一個點(x0,y0,z0,1),在進行投影變換之前的坐標為(x0",y0",z0",1)。這個平面的方程為Ax+By+Cz+D=0。投影變換前,在世界空間中的方程為A"x+B"y+C"z+D=0,則點必須滿足:

  如果變換矩陣為T,則投影前后的點要滿足(xO’,yO’,zO’,1)XT=(xO,yO,zO,1)。通過這三個等式,我們可以得到

  再根據投影空間中范體的六個面的方程,我們現在可以很容易的得到世界空間中的投影體的六個面的方程。我們已經有了裁剪體的方程,當我們需要判定一個頂點是否在視錐體中的時候,這六個方程已經足夠了。在OpenGL中得到裁剪體六個面的方程系數的偽代碼如下:

  ·用包圍盒、包圍球做物體的視錐體剔除

  對於物體是否在視錐體區域內的判定,我們可以借助包圍球或者包圍盒隅1。在課題中,選用了包圍球,也就是地形的外接球。

  視錐體和包圍球是否相交的經典算法是檢查包圍球的球心到視錐體每一個平面的有向距離di,i∈[0,5],設球體半徑為R,如果存在一個i∈[0,5]使得di≤一R,那么包圍球是在視錐體外,如果存在一個i∈[0,5]使得di≤R,那么包圍球和視錐體是相交,否則包圍球是在視錐體內。代碼如下:

3.6.3地形的空間管理與視錐體剔除

  對地形的三角形面片而言,怎么判斷哪些面片在視錐體中,我們不能把面片的所有頂點都計算判定一次,更好的算法是把整個場景分成一個個方便管理的區域,以每個區域為最小單位做視錐體剔除。由此空間管理算法出現,他的作用就是在空間上快速排除不需要渲染的面片。

  · 用四叉樹(Quadtree)管理空間

  四叉樹結構是每個父節點對應四個子節點的數據結構。我們可以把地形的三維空間近似看作XZ的二維空間,根節點表示整個正方形地形區域,其子節點分別可以表示“左上",“右上’’,“左下"和“右下”四個象限區域,那這四個子區域又可以遞歸划分下去,如圖3.17:

  四叉樹中的陰影節點就是代表了地形中的陰影區域。四叉樹的葉子節點代表了地形的最小可分區域。當要查找某一個區域時只需要遍歷這個完全四叉樹就可以了。

  空間四叉樹節點的數據結構可以描述如下:

  ·用八又樹(Octree)管理空間

  八叉樹是在四叉樹的基礎上演變而來的。四叉樹只可以描述二維空間,八叉樹它可以描述三維空間。如圖:

  八叉樹的空間管理一般用在有很多其他物體的場景中,比如建築,樹木等物體參與到游戲中來的時候,可以通過八叉樹對這些物體進行統一管理,方便進行碰撞檢測、視錐體剔除等。如果只是針對地形的裁剪,用四叉樹足夠了。

  ·用空間四叉樹節點做視錐剔除

  我們從上到下,依次遍歷四叉樹的節點,判斷節點代表的區域與視錐體的位置屬於哪一種:a.與視錐體相交, b.在視錐體外,c.在視錐體內。

  如果是情況a,遞歸判斷這個節點的四個子節點。

  如果是情況b,剔除該節點。

  如果是情況C,渲染這個節點代表的地形。

  得到可渲染節點的代碼如下:

  3.6.4地形遮擋剔除,背面剔除

  ●背面剔除

  當我們在三維場景中漫游時,只能看到地形起伏的正面部分,地形的背面部分被正面部分的網格面片遮擋,因此在繪制地形網格時,這部分網格可以不繪制。背面剔除算法的目的就是將這些看不到的背面網格去除掉,實現步驟如下:

  (1)計算位於一個給定網格多邊形平面上的某兩個向量的矢量積,得到這個網格多邊形的法向量,這兩個向量可以通過多邊形頂點的差分來得到。在求解網格平面的法向量時必須保證兩個向量的矢量積的方向朝外,否則無法得到正確的法向量值。

  (2)計算視點觀察方向與法向量之間標量積的符號,由此決定它們之間是否形成大於90。的角。視線與網格平面之間的關系如3.20圖所示:

  當視線與網格平面法向量之間夾角大於90。時,表示這個多邊形位於起伏地形的背面,需要剔除,否則不被剔除。

  在實際編程時,地形網格的法向量可以預先計算並存儲在內存中,當漫游時,只需要直接計算視線與法向量的夾角就可以判斷網格是否要被剔除。如果對每個三角形面片都去判斷其是否是背面的話,計算量是很大的,這增加了CPU的負擔,雖然能夠最小化參與繪制的面片,但是CPU的計算很容易形成效率瓶頸,結果繪制效率有可能反而沒有不剔除背面的做法高。因此,這種算法必須針對具體情況,適當選取。如果場景大多是峰巒疊嶂,這時就可以考慮使用此算法。

  ●遮擋剔除

  遮擋剔除大致可分為兩類:針對視點的遮擋剔除和針對視點單元區域的遮擋剔除。前者判斷兩個物體之間相對於一個視點而言的遮擋關系;后者則判斷兩者間相對於一個連通區域(即所謂視點單元區域)的遮擋關系,由此得到的兩個物體之間是否遮擋的斷言對該區域中每一視點都成立。

  針對視點的遮擋剔除算法大都需要根據視點位置將挑選出的遮擋物在圖像空間離散化,並將其離散表示組織成層次結構,剔除時將場景中物體的層次包圍盒自頂向下地與遮擋物的層次離散表示作比較,迅速拒絕被遮擋物體。由於對遮擋物采用了離散表示,可以很容易地實現多個遮擋物的融合,但由於離散化往往需要借助於圖形加速卡,而從圖形加速卡中讀取數據相對較慢。另一些針對視點的遮擋剔除方法直接在三維物體空間中判斷遮擋關系,但這使得多個遮擋物的融合變得困難。由於針對視點的遮擋剔除不一定需要嚴格的可見性信息,而只需知道潛在的可視的物體集合(Potentially Visible Set,簡稱PV$)。由此發展出另一類以PVS計算為核心的算法。PVS的好處就是數據為靜態,渲染的時候不需要計算,但它對動態物體的判斷不夠好。

  總的來說,由於現在顯卡對三角形面片的吞吐量快速增加,如果為了少量剔除遮擋和背面的面片而增加CPU很多計算,那將是不值得的。所以,目前的背面剔除和遮擋剔除算法的使用只適合於地形交疊起伏厲害的場景。

3.7用動態數據加載實現超大地形的繪制

  在前面章節中涉及的場景是有限大的,我們實現了2049 X2049高度圖的實時繪制。但是當游戲中虛擬世界的地圖再擴大很多時,即使我們能對地形面片做很好的簡化,對地形區域做很好的剔除,也不能一次把數據全部讀入內存進行渲染。所以,對於整個游戲虛擬世界的表現,實際游戲引擎中往往采取地圖數據的靜態加載和動態加載兩種方案。

  我們把單個場景(Tile)看作組成整個游戲世界地圖的基本單元,那么整個虛擬世界就是所有場景的集合。在物理上,通常把單個場景(Tile)的數據打包在一起。不管采用什么樣的數據加載方式,都是以單個場景數據為基本單位的。在本課題中的單個場景數據主要包括高度圖、紋理索引圖、光照貼圖、紋理貼圖等。

  3.7.1靜態加載方案

  這是最簡單的辦法,也是目前常用的方式。所謂靜態加載是指在渲染場景前必須等待讀入場景數據,讀入后人物只能在這個固定的場景里漫游。在場景一定的位置設置下一個場景的開啟點,使得人物一旦到達此區域就觸發事件,讀入下一個場景的數據,經過數據讀取后,角色便切換到了這一場景中。如圖3.21所示:

  這種方法不要求場景間無縫銜接,通常會把單個場景設計得大一些,避免頻繁的場景切換等待。對於一般游戲的渲染細節要求,一個1025 X 1025大小的場景已經能表現很開闊的場景了。

  這種方法的優點是邏輯簡單,系統開銷小。但是由於場景的切換等待,存在不能連續漫游超大無縫場景等缺點,極大影響游戲體驗。所以現在很多游戲正試圖采用其他方案跳出這種限制。

  3.7.2動態加載方案實現無縫連接超大場景的實時繪制

  ·地圖數據的動態加載機制

  動態加載是指在場景渲染的同時更新內存中要渲染區域的數據。本文通過維護一個區域數據緩沖池,根據角色所處位置,讀入磁盤文件系統中的場景數據,使得緩沖池中始終保存有角色周圍相關區域的場景數據(肯定不是整個世界的數據),場景渲染引擎只在緩沖池中挑選要進行渲染的數據。通常單獨開一個線程負責維護這個數據緩沖池,主線程負責場景的繪制。整個數據調度過程如下圖所示:

  渲染主線程對數據加載是透明的,他只負責從緩沖池中挑選數據。這種技術的難點在於根據單位區域的數據量大小、磁盤I/O效率來決定緩沖池的大小。緩沖池太小會引起頻繁的I/0讀取,影響游戲流暢;緩沖池建得太大,占用內存資源過多,預取的Tile數據也會增加。通過實驗得出,如果把每個Tile的高程圖大小設為256×256,緩沖池取為25個Tile大小比較合適。如果能有效的利用這種技術,那么角色可以在游戲中自由漫游,理論上游戲場景的大小只受限於磁盤的數據容量。技術的關鍵在於使CPU、GPU、I/O三者的效率達到一種平衡,在任何一個環節不能出現瓶頸。

  ·緩沖池的建立與維護

  所謂動態加載必須使場景繪制和數據的取得分工協作,異步處理。所以緩沖池必須通過創建單獨線程來處理。關於緩沖池具體有以下幾個問題需要處理:

  (1)緩沖池維護線程的創建

  對於緩沖池維護線程的生命周期有兩種方式。一種是當繪制主線程發出更新緩沖池指令后得以創建,其生命周期在緩沖池維護工作(數據的讀取和刪除)后結束。第二種是在整個軟件初始化時期得到創建,其生命周期一直持續到整個軟件運行結束。通過與主線程共享數據區域中的一個緩沖池維護指令標記來決定是否進行I/O操作。

  (2)緩沖池維護線程與主線程的協作機制和通訊

  出於效率的考慮,在線程間使用異步機制。主線程只在需要重新調整緩沖池的時候向緩沖維護線程發送消息,他在使用緩沖池資源的時候不需要采用鎖機制與維護線程互斥。通過為緩沖池中的每一個Tile建一個狀態標記,主線程在查找數據的時候先看其對應的標記,如果標記表明可以使用,才讓數據進入渲染引擎。反之,則不把這個Tile調入渲染引擎。通過在主線程發出更新緩沖池指令和維護線程從文件系統讀完數據之間預留足夠的時間,可以保證在最大程度上讓主繪制線程取到想要的數據。這么做最大的好處是效率很高,繪制線程不需要任何等待時間。軟件初始化時在內存中開辟的一塊專用區域,兩個線程的數據都在這里得到共享。他們的消息傳遞也通過改變在這塊區域中的一些狀態標記來實現。

  在緩沖池中的每個Tile數據通過索引指針被繪制線程方便的使用。

  (3)何時更新緩沖池,更新哪些

  當角色在場景中移動位置超出某個距離限制時,讓主線程通知緩沖池維護線程開始按主線程要求的最鄰近Tiles索引表來讀取新的Tiles文件,在池中刪除需要丟棄的Ti les空間(或許覆蓋更好)。關於何時更新,如圖3.23所示:

  圖中的每個小格子代表一個Tile,也就是緩沖池維護線程要加載的最小單位。在本程序中每個Tile為256×256大小。當角色在點a位置時,在他周圍相鄰的Tiles是以TilelO---Iilel4為邊長的正方形。一共25個Tiles,他們就是此時緩沖池中擁有的Tiles。角色向b點移動,假設角色現在的坐標是(X’,Y’),比較的基准位置為a點,其坐標為(X,Y),那么

  當X’-X>=Tile.Width

  或者Y’-Y>=Ti le.Height 時觸發緩沖區更新事件。

  同時把基准位置設為b點。通知緩沖池維護線程從池中剔除TilelO-一Tilel8,從文件系統讀入Tilel_Tile9。角色走過(X’一X)或者(Y’一Y)這段路程的時間就是預留給池維護線程動態讀取數據的時間,在本例中為256個高程圖單位,足夠了。

  值得注意的是,繪制主線程只從緩沖池中挑選最鄰近他四周的9個Tile進入渲染引擎。如果在實際應用中我們的硬盤讀取時間預留不是很足,讀取數據比較頻繁的話,可以通過增加進入緩沖區的Tile個數來調節。比如設置進入緩沖區的T兒e為36個。

  另外,也可通過設定Tile的優先級來更合理的決定進入和退出緩沖池的Tile。Tile的優先級可以根據角色的運動方向來判定,比如人物向右移動,那右方Tile的優先級顯然應該比左方的高。’

  3.8本章小結

  本章節討論比較了ROAM、基於四叉樹的LOD、GeoMipMap幾種基於LOD思想的網格簡化算法,提出一種優化的GeoMipMap算法,並討論了其實現細節。另外,本章介紹了符合室外地形的空間管理算法一一基於四叉樹的空間管理。並討論了在其基礎上實現的視錐體裁剪,背面剔除算法和遮擋剔除算法。

  此外,針對超大無縫地形的渲染,本文提出通過維護數據緩沖池來實現地圖數據動態加載的技術。

第四章 場景的真實感渲染技術

  第三章討論了怎樣有效繪制地形的三角形面片,關於怎么在面片上表現真實的地表(草地、沙粒),以及怎么表現光照、天空、植物等,這一系列問題涉及的就是場景的真實感渲染技術。

  4.1紋理映射技術

  4.1.1概念

  在游戲設計中,由於客觀世界千變萬化、錯綜復雜,要把真實世界的各種細微結構直接用幾何模型表示出來,不僅模型難以建立,而且計算量龐大,難以滿足實時顯示的需要,比如一張曲面可以用許多微小的多邊形(或曲面片)表示其表面細節,假定每個微小多邊形具有近似相同的表面特征,要顯示這樣一個曲面,就必須對這些微小多邊形(或曲面片)進行分別處理,這將需要大量的存儲空間和處理時間,因此在實際應用中,為了獲得比較高的顯示速度,往往以犧牲圖形的真實感為代價。盡管這樣,顯示一幅比較復雜的圖像仍然需要很長時間。於是,人們就想象是否可以用“貼牆紙"的方法將反映物體表面的細節的圖案貼到物體表面,從而開辟了一個新的研究領域一紋理映射(Texture Mappirig)。處理過程如下圖:

  紋理映射的方式主要分為三種:

  顏色紋理映射:最簡單和最基本的應用是將一幅花紋圖案映射到物體表面,采用與表面上點的位置有關的值(如:參數曲面上一點的參數值)來確定紋理坐標並采樣包含圖案的紋理,采樣值用定義該點的顏色。通過此類方法在圖案和表面點之間建立的固定聯系,不會因視線的改變而改變。當花紋或圖案繪上之后,表面仍光滑如故,這種紋理稱為顏色紋理,形如在物體表面繪制了一些花紋圖案。

  凸凹紋理映射:根據粗糙表面的光反射原理,通過一個擾動函數擾動物體表面法向量,使光滑表面得到調制,並在光線下呈現出凸凹不平的形狀,這種紋理稱為凸凹紋理(或幾何紋理)。利用擾動函數可以很好的模擬皮毛、頭發、衣服之類的物體。

  過程紋理映射:過程紋理映射屬於三維紋理,它就是將三維的紋理函數映射到三維物體上。也就是說在物體的內部也會受到紋理的影響。例如,木材和大理石的紋理,需要考慮每一個相鄰面的紋理映射,通常每個面分別進行顏色紋理映射時,由於面的邊界處紋理不連續,往往難以表現出自然的紋理,這種場合定義三維的紋理函數進行立體紋理映射是非常有效的。用過程紋理模擬物體表面細節,能夠在非常復雜的曲面上表現連續的紋理,且紋理效果不受物體表面形狀的影響,可以很大程度的解決紋理走樣問題。

  4.1.2 OpenGL實現紋理映射的步驟

  (1)指定紋理

  在最簡單的情況下,紋理是單個圖像。利用稱為MipMap的技術,程序員可以指定同一紋理的多級分辨率圖像,在進行紋理映射過程中,該技術可以按照景物表面在屏幕上所占區域分大小,自動選擇合適分辨率的紋理圖像對景物表面進行映射,以避免因紋理映射中的點采樣方式所導致的紋理走樣。另外,圖像的定義可以包括邊界值,以防止物體的紋理坐標超出有效區域。邊界值允許程序員把多個紋理映射平滑的粘貼在一起,從而增加最大可用紋理的有效尺寸。相關函數:glTexImage2D(),glTexGen()。

  (2)紋理如何作用於每個像素點

  OpenGL根據片元的顏色和紋理圖像數據中的顏色來計算最終的RGBA值。程序員可以選擇下面三種功能中的一種:a.可以簡單的使用紋理顏色作為最終的顏色,這種方法如同貼花一樣,紋理被粘貼在片元的表面上;b.可以用紋理來調整片元的顏色和顏色比例,該技術對光照和紋理的綜合效果非常有用;C.用紋理值將一個固定的顏色和片元的顏色混合在一起。相關函數:glTexParameter(···),glTexEnv(···)。

  (3)激活紋理顏色

  在繪制場景之前需激活紋理映射。相關函數:glEnable(),glDisable()。

  (4)利用紋理坐標和幾何坐標繪制幾何場景

  在粘貼紋理之前,必須說明紋理相當於片元是如何排列的。也就是說,必須指定場景中物體的紋理坐標和幾何坐標。對於二維紋理圖可指定其兩個方向上的紋理坐標均為[O.0,1.0],而要粘貼紋理的物體坐標可以是任意的。相關函數:glTexCoord*()。

  4.2 用多層紋理混合貼圖模擬融合性地表

  4.2.1紋理混合貼圖

  對於小的地形,我們可以考慮在整個地形上貼一張紋理。比如65×65的地形貼上一張128×128的圖片。但是當地形很大時,我們的貼圖不可能很小。當貼圖很小時,地形會被拉伸產生失真;當把貼圖選得太大,顯卡會承受不了。於是有人想到了,利用紋理貼圖坐標(texture coordinate)的設定,我們可以將一張圖片一次次的重復貼至地形場景上,也就是所謂圖素紋理(tile texture)的方法;不把128x1.28的圖片直接映射(mapping)至整個地形范圍,而是以每個128x128大小為一個單位,將圖文件完整貼上,如此反復進行貼圖,就像是鋪地板磚一樣。這樣的方法,的確可以大幅減低貼圖失真的情形,可是如果還想進一步實現更真實的地形場景貼圖,就會發現這個作法還是有不足之處。一個地形場景通常不會只擁有單獨一種樣式的地貌。舉例來說,可能依照地形高度的不同,在平地上會有草地,高度往上的山坡會有沙地,在山頂或陡峭之處可能會有岩地或雪地等等多種可能的組合。如果想達成這種形式的地形紋理貼圖,就不是簡單的使用圖素紋理(tile texture)可以實現的了。這就需要紋理混合貼圖(Texture Blending)技術。

  兩層紋理混合原理公式:C=a*alpha+b*(1-alpha)。

  4.2.2基於索引圖的紋理混合貼圖

  在很多游戲中,地形紋理又分為粗紋理和細節紋理。粗紋理是指表現地表大致圖像的紋理,比如一片草地,它的粗紋理就可以是一張綠色的圖片。而細節紋理顧名思義是指表現細節的紋理,在例子中,它就可以是一張表現草的細節、沙石細節的圖片。一張粗紋理一般映射得很廣,甚至映射到整個地形;而細節紋理一般是反復貼圖(鋪磚)。室外場景一般2到3張細節紋理足以表現出漂亮的結果。當多張細節紋理混合時,怎么體現不同紋理間的平滑過渡呢·可以應用紋理索引圖技術。如圖4.2

  在灰度圖表示的紋理混合索引圖中每個像素對應地形中的一塊區域(不能太大),白色像素表示那塊區域貼岩石紋理,黑色像素表示貼草地紋理,灰色像素即是兩種細節紋理的混合。比如灰度值是78,則在混合過程中岩石紋理的alpha=78/256×100%。

  同理,我們可以用彩色圖來表示更多細節紋理的混合索引。令索引貼圖的R分量代表沙灘的紋理,G分量代表草地,B分量代表岩石。如果索引貼圖上一個像素的值是(0,255,0),即綠色,則這個像素所對應的地形區域的具體紋理就為草地。如果該像素顏色值是(127;127,0),即黃色,則該像素所對應的地形區域的紋理為草地和沙灘的混合,看起來既有草,又有沙。這種方法的優點是簡單、靈活,方便美工人員設計地表的紋理。

  4.2.3 紋理混合的OpenGL實現

  在OpenGL中,紋理混合有三種方式來實現:多通道多遍渲染,單通道多重渲染,用GLSL(GL Shading Language)實現多紋理混合。

  ·多通道多遍渲染

  我們把地形用第一種紋理畫出一次,然后再開啟阿爾法混合(alphablending)的功能,用第二種紋理再畫出地形一次,這樣用不同紋理重復多次畫出地形。這種做法適應配置低端的顯卡,但渲染速度會受很大影響。

  ·單通道多重渲染

  這種方法要用到兩個OpenGL擴展指令(OpenGL Extensions),分別是GL_ARB_multitexture與GL_EXT_texture_env_combine。GL_ARB_multitexture可以讓我們一次控制二到多個紋理單元(texture unit)的操作。這種技術適合於配置中端的顯卡,速度也很快,但是支持的紋理個數有限。其步驟:

  (1)地形初始化時,由紋理混合索引圖確定每個地形頂點的所有紋理的映射坐標,紋理間的混合alpha值。

  (2)初始化多重紋理,載入紋理貼圖,設置相關參數。

  (3)渲染時,用glMultiTexCoord2fARB設置頂點的紋理映射坐標,關鍵代碼如下:


  ·用shader實現多紋理混合

  所謂shader是基於顯卡的着色器。OpenGL和DirectX都先后發布了自己的着色器語言,如OpenGL的GLSL(GL Shader Language)。這是目前比較新的渲染技術,這種方式編寫程序簡單,速度很快,支持的紋理也很多,但顯卡必須是比較高階的支持着色器語言的。這種方法在下面章節光照貼圖中會有相關代碼。

4.3 室外場景的光影處理

  要繪制逼真的場景必須做光照處理。沒有光照的三維物體模型與二維物體沒有任何差別,沒有一點立體感。只有具有光照的物體才是真正的三維物體。光照射到物體表面時,可能被物體吸收、反射或透射。光的反射和透視部分進入視覺系統使我們能看見物體。光的顏色是由其波長決定,一束白光含有所有可見波長的光。白光照射物體時,只有所有可見光被等量吸收物體才會呈現灰色;如果被不等量吸收,物體會呈現其它的顏色。光的亮度由光強決定。從物體表面反射出來的光的強度取決於光源的位置、光強、物體材質、物體表面位置、物體表面法線和視點的位置。

  4.3.1光照模型介紹

  光照射到物體表面時,光線可能被吸收、反射和透射。被物體吸收的部分轉化為熱,反射、透射的光進入人的視覺系統,使我們能看見物體。為模擬這一現象,我們建立一些數學模型來替代復雜的物理模型,這些模型就稱為明暗效應模型或者光照模型。

  在真實感圖形學中,我們把僅處理光源直接照射物體表面的光照模型稱為局部光照模型,而與此相對應的,可以處理在物體之間光照的相互作用的模型稱為整體光照模型。

  ●Phong光照模型

  Phong光照模型綜合反映了漫反射、鏡面反射和環境光對表面的作用1。他屬於局部光照模型,在游戲場景的實時渲染中經常用到。其光照強度方程式如下:

  式中,M表示對場景有貢獻的點光源的總個數;I是光照表面點(x,y)處的光強;Ia是入射環境光的光強;Ini、fi(d)是第i個點光源發出的入射光光強和光源強度衰減因子;ka為景物表面對環境光的漫反射系數;kd為景物表面的漫反射系數;ks為景物表面的鏡面反射系數;n稱為鏡面高光指數,被用來模擬鏡面反射光在空間的會聚程度;Li為第i個點光源發射方向單位向量;N是點(x,y)處的表面單位法向量;Hi為將入射光反射到觀察者方向的理想鏡面的單位法向量Hi=(Li+V)/2,V為觀察者視線單位向量。

  ·光線跟蹤算法

  光線跟蹤或稱光跡追蹤是計算機圖形學的核心算法之一n¨。在算法中,光線從光源被拋射出來,當他們經過物體表面的時候,對他們應用種種符合物理光學定律的變換。最終,光線進入虛擬的攝像機底片中,圖片被生成出來。由於該算法是全局光照模型,所以可以模擬生成十分復雜的圖片。

  光線跟蹤算法偽代碼:


  ·輻射度算法

  輻射度算法本質是將光看作一種物理輻射,然后計算輻射的傳導就能獲得加之於每個對象物體上的光照強度,從而獲得正確的渲染結果。和其他渲染方法相比,輻射度算法更接近於光的自然傳播原理。輻射度算法解決了光在不同面之間反射的計算技術,但不分布鏡面光,也不產生聚光(Caustic)。輻射度算法也是一種全局光照模型。

  全局光照雖然渲染效果很好,但速度很慢,一般還不能應用在實時渲染中,它一般應用在非實時渲染中,比如光照貼圖就可以用全局光照算法來生成。

  4.3.2室外場景中地形的光照處理

  室外場景由於涉及多邊形面片太多,如果實時計算光照,那速度是很慢的。並且,用局部光照模型來計算出的效果也不太理想。由於地形的多邊形網格是實時產生的,它會隨着視點的移動而變化,因此如果直接使用OpenGL內置的頂點光照,就會得到極度不穩定的光照效果,會看到地形表面因為你的移動而不斷跳動。所以目前在游戲引擎中,關於地形的光照大多通過光照貼圖來實現。

  這樣的實現方法是一種靜態光照,不是實時的。現在國外最頂級的游戲引擎開始把全局光照或接近全局光照的模型引入場景的實時渲染中,這是今后的一個發展方向。在本文中,地形的光照處理通過光照貼圖來實現。

  ●光照貼圖的概念

  光照貼圖顧名思義它是一個覆蓋了場景中所有多邊形的貼圖n鍆。通過給貼圖賦值,我們可以得到多邊形表面復雜的光照效果。使用好的算法計算出來的光照貼圖可以模擬極度逼真的光影效果。它給我們帶來的視覺享受遠遠地超過了OpenGL的局部光照。

  ●光照貼圖和多細節紋理混合模擬地表

  首先,我們准備3張地表細節貼圖,1張光照貼圖,1個紋理索引貼圖。把3張細節貼圖和光照貼圖綁定到相應的紋理通道上。然后使用Vertex Shader為每個頂點計算拉伸后的索引貼圖的紋理坐標。下面是用GLSL寫的相關Vertex Shader代碼:


  在Fragment Shader里,對索引貼圖進行紋理查找,使用查找得到的顏色值的RGB顏色信息按比例混合3張細節貼圖,得到當前像素的顏色。最后還應該把這個顏色和光照貼圖中的值相乘,得到最終的結果。相關的Fragment Shader代碼如下:

  ●光照貼圖的生成

  光照貼圖可以用全局光照模型,比如光線跟蹤、輻射度算法等來預處理得到。由三個數據來生成:a.地形高度圖;b.光源位置;C.光照強度。

  4.3.3場景中非地形的陰影算法簡介

  地形的光照陰影用上面介紹的光照貼圖解決了,針對樹木、人物的陰影我們必須另外實現。人物的陰影是動態的,有兩種常用的實時陰影生成技術。一種是ShadowVolume,還有一種是ShadowMap。

  ·ShadowVolume算法

  ShadowVolume基於的是幾何體算法,通過延伸光照輪廓區域進行正反面兩次渲染,在屏幕的模板緩沖區內分離出陰影區域,能夠得到十分精確的陰影區域,畫質較好,而且渲染流程十分簡單,缺點是建立光照輪廓延伸體十分費時費資源,另外陰影邊緣視覺上比較生硬。

  ●ShadowMap算法

  ShadowMap基於的是Shader技術,通過建立Z深度圖、逐像素比較深度得到陰影區域。該算法針對一些固定的建築物之類的圖素形成陰影尤其出色,對於一些運動物體的陰影最多只需渲染兩次物體即可形成陰影。缺點是需要顯卡對Vertex Shader、Fragment shader的支持,而且內存消耗較大,同時只能生成平行光下的陰影,而且無法做到將陰影投影到所有的物體。

  · 用陰影貼圖創建簡單陰影

  可以把物體的陰影通過紋理貼圖技術貼在平面上簡單模擬陰影。下面描述實現步驟:

  (1)渲染地形。

  (2)根據光源方向和物體的位置計算物體的陰影在地形上方的位置,並構成陰影平面面片。

  (3)對於要創建陰影的每個物體,使用支持alpha混合和透明的紋理映射函數在第(2)步計算的陰影平面上貼上物體的陰影。

4.4天空的渲染

  4.4.1天空盒子

  天空渲染最簡單的方法是利用天空盒子(SkyBox)。天空盒子幾乎在各種室外游戲中都能被運用,它能完全的描述視點周圍360度范圍內的視野。天空盒子實際上就是一個游戲三維空間中的立方體。如圖4.4所示,構建一個天空盒子需要八個頂點和六張天空紋理圖,這六張紋理會被貼在天空盒子的內側,分別描述從攝像機視點所在位置六個方向看去的天空,上方紋理貼圖描述向上看去的天空,后方紋理貼圖描述向后看去的天空。對天空盒子的渲染也就是簡單的渲染一個空間立方體的六面。最主要的是讓天空盒子隨着攝像機的移動而移動,保證攝像機一直在盒子的中心。天空盒子的六張紋理必須被精心設計以使它們看起來連接得天衣無縫。

  4.4.2球形天空和弧度天空

  天空盒子很簡單,但是離天空邊緣近的時候天空會有非常明顯的變形。球形天空和弧度天空把天空曲面分成一個個三角形,顯然這種方法渲染效果更精細,但是渲染速度也會有一些影響。所以本課題最終選用了天空盒子來實現。

  4.4.3太陽和光暈的生成

  渲染太陽很簡單,在場景的特定位置放置一個圓形物體就能實現,鏡頭光暈則需要一些額外的處理。首先我們來看一個光暈的位置,如圖4.6所示:

  鏡頭光暈由一系列的光環組成,所有的光環排列在一條直線上。這條直線由發光物體位置和屏幕中心確定。這些光環的形狀則有多種方式,通常用一張放射線狀的圖用來作為發光物體的光芒,另外的則用不同厚度的環狀圖像。我們組合這些光環的時候需要使用Alpha Blending功能把這些光環疊加起來自然的融合到場景中去。

  所有的光環都是作為二維物體繪制到場景中去的。因此,發光物體在屏幕上的位置需要通過自己計算得到,在計算發光物體在屏幕上的位置的同時我們還可以得到這個位置的Z緩沖(Z-Buffer)的信息來判斷是否能看到發光物體,當發光物體不可見的時候,光暈自然也不可見。

  4.5 植物的渲染,霧的生成

  4.5.1樹草的構成與渲染

  花草和樹是室外場景必不可少的點綴,如果對這些物體的細節都用三角形面片來描述,在現在的硬件環境下顯然是不現實的。因此出現了很多簡化、取巧的方法。

  ·公告板技術(BillBoard)

  公告牌技術,即BillBoard技術口¨,在3D游戲中有着廣泛的應用。它的本質就是用預先做好的幾幅位圖來代替3D物體,極大地節省資源和提高速度。早期的很多游戲中,它的精靈、樹木、物品通常是二維圖象,也就是BillBoard。由於它始終朝向觀察者,你根本看不到它“扁平”的一面,所以給人一種立體的感覺。這種技術最大的優點是速度快。如果用多個三角形面片構成3D精靈,至少要百余個面片,而用billboard技術,只需處理兩個多邊形。很多3D游戲的爆炸效果,如“極品飛車’’中路旁的樹木,都使用了該技術。但這種方法的缺點也是顯而易見的,真實感不強。現在對植物的渲染很少單獨用到這種技術。

  · 用交叉平面+alpha測試渲染花草

  公告板技術是用一個平面來模擬復雜物體,交叉平面法的做法是用幾個交叉的平面來共同表現一個物體,通過alpha測試選擇要映射的紋理像素,由於是幾個交叉面,所以玩家從不同角度都能看到一些貼着紋理的平面。這種方法運用得好能顯出極佳的效果,關鍵在於針對不同的植物選擇不同的交叉平面,同時貼圖要很好的與平面配合。目前大多數游戲的花草等點綴物體都是這樣渲染的,本課題花草的繪制也是采用的這種方法。下圖4.7所示的是一種可以參考的交叉平面。

  這種技術在實現的時候還有幾點值得注意的地方:

  a.選擇合適的AlphaTest值來消除植物的黑邊

  由於紋理過濾和生成MipMap的緣故,渲染一些小物體時會出現淡黑色的邊界,這就需要在實際使用中找到一個比較合適的AlphaTest參考值(一般不要取做0)。這個值跟紋理圖、MipMap采樣方式等很多因素都有關,可以選擇一個經驗值。

  b.用多分辨率紋理(MipMap)消除紋理的抖動

  當同樣大小的面片處在遠近不同的位置是,如果貼上同一張紋理,由於紋理映射默認的采樣算法不能完全模擬物體縮小的貼圖效果,在用高分辨率的紋理給遠處面片貼圖時就會發生紋理抖動,如果這樣的面片在場景中很多,則畫面閃動相當明顯。多分辨率技術能很好解決這個問題。

  多分辨率紋理就是對同一個紋理貼圖准備幾個不同分辨率的版本,用於分別對應不同距離的貼圖。在實際的使用上,一般有兩種方式。第一種是由底層圖形庫(比如OpenGL、DirectX)在紋理初始化的時候自動生成不同分辨率的紋理。另一種方式是設計者用圖形編輯軟件處理好不同的分辨率圖片,在程序中由設計者自己控制在什么位置載入什么分辨率的紋理。后一種方法的渲染效果更好,但代價顯然更大。

  c.實現隨風擺動的動態效果

  由於我們的每棵草是通過幾個交叉面模擬的,所以對每棵草幾個面的頂點按一定規律調整位置,就可以模擬被微風吹動的效果。這種頂點位置的計算現在一般放在顯卡上通過頂點着色器來完成。對於復雜建模的草叢或者樹木,可以用關鍵幀、骨骼動畫技術實現擺動效果。

  d.模擬光照效果

  從每棵草所在位置的地面上取得地面光照亮度信息作為這棵草的基本亮度,將上面的頂點隨機調亮一個幅度,將下面的頂點隨機調暗一個幅度,模擬草光照不均勻的效果。

  ●樹的渲染

  樹一般比花草等大得多,復雜得多,所以要求我們要采用細節表現度更高的方法來渲染它。圖形學理論上高細節度的植物渲染算法,比如分形算法等復雜度太高,現在還不能很好的用在游戲中。一般目前游戲中用的較多方法是:對枝干和樹葉分別建模。

  對枝干完全用比較細致的多邊形面片建模,樹葉用交叉面建模加上重復貼圖來實現。這種方式既避免了完全細致建模造成的面片過多引起的渲染速度問題,又能達到極好的視覺效果,是目前廣泛采用的折中方法。此法的難度在於怎么用盡量少的交叉面模擬復雜的樹葉細節。下圖4.8是一顆樹的面片組成:

  渲染大面積樹林的時候,為了加快速度,還會根據距離選取不同分辨率的面片模型進行渲染。太遠的甚至可以用前面草叢的交叉面貼圖方法渲染。

  此法最大的好處是簡單、高效。但當靠近從不同角度觀察它時,還是容易看出“片狀”的缺陷。針對樹的渲染,目前游戲應用領域還廣泛使用一種才興起的中間件SpeedTree。他主要的優點是用極少的速度代價實現了樹的超高真實感渲染,細節、光影、樹葉的動態擺動等都得到很好的表現。國內完美國際公司的“完美世界"游戲中就使用了這個中間件。

  4.5.2 樹、草在地形中的分布和管理

  樹和草從地形分離出來單獨渲染。根據樹草的位置坐標可以計算出它從屬於的地形Block。在整個場景做數據初始化的時候,用表記錄每個Block上存在的草和樹,並從屬於此Block。通過前面章節介紹的方法,我們知道每個Block是通過四叉樹來做空間管理和可見性剔除的,所以通過對Blcok做視錐體剔除,我們也間接對不可見的草和樹進行了剔除。在實時場景渲染的時候,只要查詢出可見Blcok上存在的草和樹渲染即可。

  另外,因為草一般很小,屬於點綴,所以對於在視錐體中距離較遠的Blcok上的草也可以不渲染。樹可以通過上面介紹的簡化方式渲染。通過草的X,Z坐標能對應地形上的一個點,這個點就是繪制草的位置。草Y方向上的位置是根據其在地形上這點的高度和草本身的高度共同確定的。

  4.5.3 霧的特效

  在3D場景中加入霧化效果能增加場景的真實感、縱深感和距離感。當我們運用裁剪剔除算法時,如果一個物體足夠遠時,它就會完全被剔除而根本不被渲染,這樣提高了渲染效率,但是我們也會因此看不到遠處的場景。運用霧的特效可以幫助我們掩飾沒有畫出的遠處場景。本質上講,霧是根據場景中物體的深度或與視點間的距離,將場景中物體的顏色與選定的霧的顏色進行混合實現的。霧的顏色在渲染過程中所占的比例是與它在場景中的深度或者說距離視點的距離成一定比例關系的,如果物體越來越遠,它們的本色和霧的顏色混合得越多,造成物體愈加被場景中懸浮的微粒模糊的假象,從而造就現實中霧越濃的效果。通過將離散的霧效果和有創意的場景設計相結合,應用程序可以添加氣氛或使場景中物體的顏色變得柔和。從而使三維場景更加逼真,產生一種霧里看花,水中望月的朦朧美。

  OpenGL支持兩種模式的霧效果,它底層化了所有的與霧化處理有關的圖形學算法,可以通過函數直接控制霧的屬性,如顏色、霧的濃度、霧的某些行為屬性。霧的行為屬性又包括霧的影響范圍、霧的顆粒大小、霧的地平線雜波屬性、霧的活躍程度等。

  4.6 本章小結

  本章討論了用多重紋理模擬融合性地表的技術和光照貼圖技術。詳細闡述了室外場景下光照的處理,並給出了具體實現方法和偽代碼。對植物渲染過程中的公告板技術、交叉面與alpha測試技術及一些細節進行了深入的討論。此外,對天空的渲染方法也提出了幾種方案。

第五章 OSRender場景渲染器總體設計與實現

  如前面章節所述,一個室外場景渲染器的主要工作包括三部分:1.超大場景數據的讀取與管理;2.場景地形網格的組織與簡化算法;3.場景真實感渲染技術。基於對這三部分的研究,本設計實現了名為0SRender的室外場景渲染器。本章就0SRender的總體框架做簡要說明,並介紹在實現中可采用的基於0penGL的渲染優化手段。

  5.1渲染器總工作流程

  (1)初始化階段

  載入地形Tiles的高度圖數據,初始化Tiles緩沖池,載入紋理貼圖、光照貼圖,載入樹的多邊形模型、計算頂點法向量。

  (2)實時渲染階段

  包括地形的渲染、天空的渲染、草樹霧的渲染。地形的渲染是最主要的。

  (3)對象清除,資源回收

  清除分配的系統資源。

  5.2渲染器的總體設計

  本設計基於面向對象的設計理念,整個模塊框架如圖5.2所示:

  以下是比較重要的類的說明:

  關於重要算法的描述和偽代碼已經在具體章節給出,這里不再贅述。

5.3場景渲染的最終效果圖

  程序用VC+OpenGL在windows平台上完成。我們使用大小為2049×2049的高程圖作為實驗數據,以Athlon2500+,DDR 1G,ATI 9550,128M顯存作為硬件環境對渲染器進行了測試,在圖形渲染效果良好的情況下,幀率達到40-50FPS,能滿足游戲引擎中圖形渲染的需要。下圖是本設計關於室外場景的最終渲染效果:

  5.4基於OpenGL的渲染優化手段

  5.4.1利用GLSL對GPU進行編程

  GLSL(GL Shading Language)是用來在頂點和像素着色器(shader)中編程的語言。使用它我們可以通過寫短小的自定義程序,在圖形卡的GPU(Graphic Processor Unit圖形處理單元)上執行,代替固定渲染管線的一部分,所以也稱為可編程管道渲染。現在生產的主流顯卡都已經支持着色器編程,所以要實現高性能、高逼真的渲染,使用着色器語言是必不可少的。主流着色器語言有兩類:DirectX支持的HLSL(High Level Shading Language),OpenGL支持的GLSL。

  GLSL的着色器代碼分成兩個部分:Vertex Shader(頂點着色器)和Fragment Shader(像素着色器)。

  頂點着色器主要的工作是利用視圖和投影矩陣對點的位置進行變化,控制紋理坐標的產生和轉換,頂點的光照或者象素光照的計算,顏色的計算。可以根據需要選擇一些功能進行不同的編寫。它可以得到當前OpenGL中的狀態,用GLSL內置變量進行傳遞。比如gl_ProjectionMatrix(投影變換矩)、gl_ModelViewMatrix(視圖變換矩陣)、g_position、gl_backcolor、gl_frontcolor、gl_normal等;而這些就是OpenGL應用程序中的頂點位置、顏色、法線等信息。

  像素着色器是在對每個像素進行光柵化處理期間執行的程序。它實際上替換了固定功能管線的多紋理化階段,並賦予我們直接操縱單獨的像素和訪問每個像素的紋理坐標的能力。這種對像素和紋理坐標的直接訪問使我們可以高效達成各種特效,例如:多紋理化、每像素光照、景深、雲狀物模擬、焰火模擬等。

  5.4.2使用顯示列表加快渲染速度

  OpenGL顯示列表(Display List)是由一組預先存儲起來的留待以后調用的OpenGL函數語句組成的,當調用顯示列表時就依次執行表中所列出的函數語句。OpenGL對這些語句進行了預編譯,因此速度比立即模式快很多。顯示列表可以用在以下場合:

  (1)矩陣操作

  大部分矩陣操作需要OpenGL計算逆矩陣。矩陣及其逆矩陣都可以保存在顯示列表中。

  (2)光柵位圖

  程序定義的光柵數據不一定是適合硬件處理的理想格式。當編譯組織一個顯示列表時,OpenGL可以把數據轉換成硬件能夠接受的數據,這可以有效地提高畫位圖的速度。

  (3)光、材質和光照模型

  當用一個比較復雜的光照環境繪制場景時,因為材質計算可能比較慢。若把材質定義放在顯示列表中,則每次改換材質時就不必重新計算了,因此能更快地繪制光照場景。

  (4)紋理

  因為硬件的紋理格式可能與OpenGL格式不一致,若把紋理定義放在顯示列表中,則在編譯顯示列表時就能對格式進行轉換,而不是在執行中進行,這樣就能大大提高效率。

  OpenGL提供glNewList 0與glEndList 0的形式創建顯示列表。

  5.4.3使用VBO擴展加載頂點常駐顯存

  VBO(Vertex Buffer Object)擴展是把數據保存在高速的顯存中,而不是普通的系統RAM內存。它不僅僅降低了每幀的內存操作,而且減少了數據在顯卡和內存之間的傳輸。這種技術應用在合適的時機將大大提高渲染效率。當然,這個擴展是依賴較新的硬件的,不是所有的圖形卡都支持的,所以在使用它前需要檢測顯卡支不支持VBO擴展。在OpenGL中使用VBO可以通過以下幾個步驟:

  首先用glGenBuffersARB來產生一個可用VBO的ID,OpenGL通過這個ID關聯你的數據。

  然后通過glBufferDataARB把內存中的數據的指針和大小傳遞進去,glBufferDataARB將把你的數據拷貝到顯卡內存中,這時我們可以把相應主機內存中的數據刪除。

  在訪問數據的時候,用glBindBufferARB綁定你的數據,這樣你就可以通過glDrawArrays等函數來把你的數據繪制出來。

  5.5本章小結

  本章主要介紹在課題研究過程中實現的一個室外場景渲染器的相關流程和框架,在更高層次上清晰地表達室外場景渲染的各個層面。此外,本章還涉及基於OpenGL的一些渲染優化手段。


6.1 總結與展望

  場景的實時及真實感繪制是3D游戲引擎中非常重要的研究課題。它直接影響在游戲中的視覺體驗是否真實,渲染效率是否達到當前主流硬件配置要求,其很大程度決定着一款游戲的品質。而隨着游戲技術的深入發展和計算機硬件水平的提高,對3D游戲中室外場景渲染的真實性、規模性都提出了更高的要求。

  本文在充分理解3D圖形學理論的基礎上,查閱了多篇重要論文,並研究了開源社區(WWW.sourceforge.com)中一款優秀圖形引擎oGRE的相關技術,分析了wowmapview(魔獸世界地圖查看器)源代碼,最終形成了自己的一些方案並加以實現。現將本文的研究內容和研究成果總結如下:

  1.對地形渲染中的網格簡化進行了深入研究。充分比較ROAM算法、基於四叉樹的LOD算法、GeoMipMap算法的優劣,並提出一種基於GeoMipMap的優化算法。本文也涉及算法的各個實現細節。

  2.對游戲場景的數據加載方式進行了探討。提出了一種基於內存緩沖池的動態數據加載方案從而實現超大(無限)無縫地形的實時繪制目標。

  3.對室外場景中涉及的空間管理和面片剔除、裁剪技術進行了討論。

  4.對真實感的渲染技術給出了具體實現方案,其中主要涉及用多紋理混合模擬融合性地表,用光照貼圖表現地形的靜態光照,用交叉平面模擬花草,樹和天空的渲染以及霧的特效。

  5.基於前述的算法和方案,用VC+OpenGL實現了室外大場景渲染器DemoOSRender,驗證了方案的合理性。

  6.2 未來工作展望

  3D游戲引擎是一塊飛速發展的領域,高效顯示芯片的不斷出現給游戲引擎提出了更高的要求,很多理論、技術、方案隨時出現,比如現在著名的虛幻引擎已經在游戲場景中實現了動態光源動態陰影。加上游戲引擎的編寫不光涉及實現技術,它還涉及軟件的總體架構與規划,模塊的抽象與封裝。所以本文對3D場景的渲染技術研究還處於初步階段,有很多問題需要進一步研究,主要包括:

  (1)對真實感渲染技術的進一步研究。在場景中實現動態光源光照效果,研究植物更逼真的渲染方案,比如目前國外著名的植物渲染方案SpeedTree。

  (2)對河流的真實感渲染研究以及室內場景的渲染研究。

  (3)對技術的封裝和抽象,真正把場景渲染模塊融入到整個游戲引擎中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM