基于分形技術(shù)的古聚落遺址三維再現(xiàn)_第1頁
基于分形技術(shù)的古聚落遺址三維再現(xiàn)_第2頁
基于分形技術(shù)的古聚落遺址三維再現(xiàn)_第3頁
基于分形技術(shù)的古聚落遺址三維再現(xiàn)_第4頁
基于分形技術(shù)的古聚落遺址三維再現(xiàn)_第5頁
已閱讀5頁,還剩53頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

題目基于分形技術(shù)的古聚落遺址三維再現(xiàn)基于分形技術(shù)的古聚落遺址三維再現(xiàn)摘要:古聚落的三維再現(xiàn)對于古聚落文化的學(xué)習(xí)和研究具有非常重大的意義,隨著考古熱的新起三維再現(xiàn)技術(shù)也受到追捧?,F(xiàn)有的三維再現(xiàn)技術(shù)各有特點(diǎn),而本系統(tǒng)則是在VC6.0環(huán)境下結(jié)合OpenGL技術(shù),運(yùn)用C++類定義出整個(gè)場景中各個(gè)景物類,通過Diamond-Square算法,L-system文法和分形技術(shù)以及紋理映射技術(shù)將整個(gè)古聚落場景中的山、水、樹、房屋、天空以及籬笆等景物進(jìn)行一一三維再現(xiàn),最終融合為一個(gè)古聚落遺址再現(xiàn)場景。關(guān)鍵詞:OpenGL;分形;紋理貼圖;1.緒言近年來古聚落隨著考古熱和人們對古聚落的關(guān)注度的提升,越來越被人們所注意。而為了讓更多的人去了解歷史,去感受古聚落文化和結(jié)構(gòu)是一個(gè)比較熱門的問題。通過考古學(xué)家們對古聚落地形的勘察和了解,可以將古聚落的地形,古聚落的結(jié)構(gòu)展現(xiàn)出來,但這些并不能讓人們直觀的去了解古聚落,也不能滿足人們對古聚落充分認(rèn)識的強(qiáng)烈期望。因此將古聚落的原始樣子進(jìn)行三維模擬,以達(dá)到將古聚落三維再現(xiàn)的效果就非常有必要。通過三維再現(xiàn)技術(shù)完成技術(shù)模擬發(fā)掘過程、復(fù)原遺址形態(tài)和使考古信息可視化是讓人很感興趣的課題,它可以充分體現(xiàn)和應(yīng)用現(xiàn)代考古理論和方法。在本系統(tǒng)中所模擬的村落是上一個(gè)山地海洋之間的一個(gè)村落,這種村落有其的特殊性。一般來說山地丘陵地帶的村落會(huì)坐落在山的包圍之中,而為了便于生活,水也是也不可的一部分,所以村子的形成會(huì)在靠山臨水位置,而這樣的設(shè)計(jì)也會(huì)對整個(gè)村落起到一定的防御保護(hù)作用[1]。在這個(gè)三維模擬過程中分別進(jìn)行了山川,樹木,天空,平原和水流的模擬。通過使用分形的技術(shù),并結(jié)合中點(diǎn)位移法的Diamond-square分形插值算法,美國生物學(xué)家Lindenmayer提出的L-Systems(LS)文法以及OpenGL的紋理映射,霧化等方法描繪出一個(gè)對古聚落進(jìn)行模擬的三維場景[2]。2.理論與技術(shù)在本系統(tǒng)中運(yùn)用到最主要的技術(shù)就是分形技術(shù)。在對自然景物的模擬過程中,逼真的模擬和形象的刻畫自然景物是非常重要的。這對于自然景物的模擬必須遵循它們的規(guī)律,因?yàn)槠潆S機(jī)性和不規(guī)則性,常規(guī)的經(jīng)典幾何是很難模擬的,因此就需要一個(gè)嶄新的技術(shù)來逼真模擬。而分形則被認(rèn)為在對自然景物的模擬中最常見也是最有效的技術(shù)。本系統(tǒng)在基于分形理論的基礎(chǔ)上,還運(yùn)用到了很多技術(shù)。在對山脈的模擬過程中使用的是現(xiàn)在相對比較成熟也是模擬比較好的Diamond-Square算法,而樹的模擬過程則是基于美國生物學(xué)家發(fā)現(xiàn)的L-System算法,除了這兩個(gè)重要的算法,系統(tǒng)中還運(yùn)用到了OpenGL本身的一些技術(shù),比如霧化效果的處理,紋理貼圖等,在本章節(jié)中會(huì)對這些算法和技術(shù)做詳細(xì)的介紹。2.1分形技術(shù) 什么是分形?分形一般是指一個(gè)粗糙或零碎的\o"幾何形狀"幾何形狀,可以分成若干部分,且每一部分大致是整體縮小尺寸的形狀[3],此性質(zhì)稱為\o"自相似"自相似。嚴(yán)格地而且正式地去定義分形是一件非常復(fù)雜而且困難的事情。但是,有一些不太正規(guī)的定義卻可以幫助我們理解分形的含義。在這些定義中,最為流行的一個(gè)定義是:分形是一種具有自相似特性的現(xiàn)象、圖像或者物理過程。也就是說,在分形中,每一組成部分都在特征上和整體相似,只僅僅是變小了一些而已。分形幾何學(xué)已在自然界與物理學(xué)中得到了應(yīng)用。如在顯微鏡下觀察落入溶液中的一?;ǚ郏瑫?huì)看見它不間斷地作無規(guī)則運(yùn)動(dòng),這是花粉在大量液體分子的無規(guī)則碰撞(每秒鐘多達(dá)十幾億次)下表現(xiàn)的平均行為。布朗粒子的軌跡,由各種尺寸的折線連成。只要有足夠的分辨率,就可以發(fā)現(xiàn)原以為是直線段的部分,其實(shí)由大量更小尺度的折線連成。這是一種處處連續(xù),但又處處無導(dǎo)數(shù)的曲線。這種布朗粒子軌跡的分維數(shù)是2,大大高于它的拓?fù)渚S數(shù)1。自然界中更大的尺度上也存在分形對象。一枝粗干可以分出不規(guī)則的枝杈,每個(gè)枝杈繼續(xù)分為細(xì)杈,至少有十幾次分支的層次,可以用分形幾何學(xué)去測量。有人研究了某些云彩邊界的幾何性質(zhì),發(fā)現(xiàn)存在從1公里到1000公里的無標(biāo)度區(qū)。小于1公里的云朵,更受地形概貌影響,大于1000公里時(shí),地球曲率開始起作用。大小兩端都受到一定特征尺度的限制,中間有三個(gè)數(shù)量級的無標(biāo)度區(qū),這已經(jīng)足夠了。分形存在于這中間區(qū)域[4]。維數(shù)是幾何對象的一個(gè)重要特征量,它是幾何對象中一個(gè)點(diǎn)的位置所需的獨(dú)立坐標(biāo)數(shù)目。在歐氏空間中,人們習(xí)慣把空間看成三維的,平面或球面看成二維,而把直線或曲線看成一維。也可以稍加推廣,認(rèn)為點(diǎn)的維度是零,還可以引入高維空間,對于更抽象或更復(fù)雜的對象,只要每個(gè)局部可以和歐氏空間對應(yīng),也容易確定維數(shù)。但通常人們習(xí)慣于整數(shù)的維數(shù)[5]。分形理論認(rèn)為維數(shù)也可以是分?jǐn)?shù),這類維數(shù)是物理學(xué)家在研究混沌吸引子等理論時(shí)需要引入的重要概念。為了定量地描述客觀事物的“非規(guī)則”程度,1919年,數(shù)學(xué)家從測度的角度引入了維數(shù)概念,將維數(shù)從整數(shù)擴(kuò)大到分?jǐn)?shù),從而突破了一般拓?fù)浼S數(shù)為整數(shù)的界限。分形圖形一般具有以下特質(zhì)[6]:1)在任意微小的尺度上都能有精細(xì)的結(jié)構(gòu)2)太不規(guī)則,以至難以傳統(tǒng)\\o"歐氏幾何"歐氏幾何的語言來描述3)自相似4)豪斯多夫維數(shù)會(huì)大于拓?fù)渚S數(shù)5)有著簡單的遞歸定義因?yàn)榉中卧谒械拇笮〕叨认露硷@得相似,所以通常被認(rèn)為是無限復(fù)雜的(以不嚴(yán)謹(jǐn)?shù)挠迷~來說)。自然界里一定程度類似分形的事物有云、山脈、閃電、海岸線和雪片等等。但是,并不是所有自相似的東西都是分形,如\o"實(shí)線(尚未撰寫)"實(shí)線雖然在形式上是自相似的,但卻不符合分形的其他特質(zhì)[7]。對于什么叫做分形,曼德勃羅曾經(jīng)為分形下過兩個(gè)定義:(1)滿足下式條件

Dim(A)>dim(A)

的集合A,稱為分形集。其中,Dim(A)為集合A的Hausdoff維數(shù)(或分維數(shù)),dim(A)為其拓?fù)渚S數(shù)。一般說來,Dim(A)不是整數(shù),而是分?jǐn)?shù)。(2)部分與整體以某種形式相似的形,稱為分形。然而,經(jīng)過理論和應(yīng)用的檢驗(yàn),人們發(fā)現(xiàn)這兩個(gè)定義很難包括分形如此豐富的內(nèi)容。實(shí)際上,對于什么是分形,到目前為止還不能給出一個(gè)確切的定義,正如生物學(xué)中對“生命”也沒有嚴(yán)格明確的定義一樣,人們通常是列出生命體的一系列特性來加以說明。對分形的定義也可同樣的處理。自然界中分形最典型的莫過于雪花,在1904年由科赫·范·卡區(qū)提出了一個(gè)比相似函數(shù)更為幾何的定義,現(xiàn)在我們稱之為科赫雪花[8],如圖2.1所示,通過分形剖析后,可以看到最初形成的狀態(tài),將這個(gè)變化進(jìn)行迭代之后可以發(fā)現(xiàn)最后可以完美的呈現(xiàn)出雪花的樣子。圖2.1科赫雪花一般說來,分形也可以依據(jù)其自相似來分類,有如下三種:精確自相似:這是最強(qiáng)的一種自相似,分形在任一尺度下都顯得一樣。由\o"迭代函數(shù)"迭代函數(shù)系統(tǒng)定義出的分形通常會(huì)展現(xiàn)出精確自相似來。半自相似:這是一種較松的自相似,分形在不同尺度下會(huì)顯得大略(但非精確)相同。半自相似分形包含有整個(gè)分形扭曲及退化形式的縮小尺寸。由\o"遞推關(guān)系式"遞推關(guān)系式定義出的分形通常會(huì)是半自相似,但不會(huì)是精確自相似。統(tǒng)計(jì)自相似:這是最弱的一種自相似,這種分形在不同尺度下都能保有固定的數(shù)值或統(tǒng)計(jì)測度。大多數(shù)對“分形”合理的定義自然會(huì)導(dǎo)致某一類型的統(tǒng)計(jì)自相似(\o"分形維數(shù)(尚未撰寫)"分形維數(shù)本身即是個(gè)在不同尺度下都保持固定的數(shù)值測度)。隨機(jī)分形是統(tǒng)計(jì)自相似,但非精確及半自相似的分形的一個(gè)例子。而在本系統(tǒng)中其實(shí)是將在精確自相似的基礎(chǔ)上,對樹木、山峰等自然景物的進(jìn)行模擬,在模擬過程中,通過添加隨機(jī)變量,從而達(dá)到一個(gè)統(tǒng)計(jì)自相似的效果,最大可能的體現(xiàn)出自然界中的景物,顯現(xiàn)出自然界中的隨機(jī)性,同時(shí)也保證了從整體效果上讓模擬出來的景物符合自然規(guī)律。在分形的基礎(chǔ)上,刻畫和模擬自然中的景物還需要用到一些算法,只有通過算法才可以運(yùn)用計(jì)算機(jī)語言將最終所需要的景物實(shí)現(xiàn)出來。接下來所介紹的就是在系統(tǒng)中對山脈實(shí)現(xiàn)所運(yùn)用到的Diamond-Square算法。2.2Diamond-square算法什么是Diamond-square算法?Diamond-square算法實(shí)際上是一種較為常用的隨機(jī)位移算法,在地形的模擬中經(jīng)常用到[9],對于刻畫山脈地形是非常有效的一個(gè)算法,可以將山的細(xì)節(jié)表現(xiàn)的較好,為了更好的了解Diamond-square算法的原理,我們不妨現(xiàn)在二維中了解它的實(shí)現(xiàn)過程。在二維中,Diamond-square算法對山的實(shí)現(xiàn)模擬過程一般從相當(dāng)于地平線的線段開始。首先我們把整個(gè)模擬過程置于一個(gè)坐標(biāo)系中,這樣方便對線段形象具體的描述。描述前需要給線段設(shè)定一個(gè)范圍,不妨將線段范圍設(shè)定為從X軸的-1.0到1.0。而為了表示山的高度,Y軸就發(fā)揮了作用。這里Y軸的范圍可以看作是隨機(jī)生成,這樣可以顯現(xiàn)出山的高度的無規(guī)律性。我們可以設(shè)定隨機(jī)數(shù),即Y軸的范圍也為-1.0到1.0。當(dāng)這些設(shè)定都完成之后,第一步需要完成的就是找到該線段的中點(diǎn),把該中點(diǎn)作為山峰對其進(jìn)行高度的設(shè)定,高度的數(shù)值通過Y軸的范圍內(nèi)的隨機(jī)數(shù)生成的,這樣可以得到圖2.2。可以發(fā)現(xiàn)生成的圖像是一個(gè)最簡單山峰的模擬了,為了突出效果,可以繼續(xù)對線段進(jìn)行算法要求的操作。進(jìn)入第二次模擬,在第二次模擬中我們將隨機(jī)數(shù)的Y軸的范圍縮小一半,變成-0.5到0.5,這樣生成的隨機(jī)數(shù)的高度可以看作是第二個(gè)峰值。依照之前的算法方式,找到第一個(gè)點(diǎn)和第二個(gè)點(diǎn)的中點(diǎn),對其進(jìn)行隨機(jī)生成,進(jìn)行畫點(diǎn)然后連線,這樣便得到圖2.3。按照遞歸,我們將范圍再次縮小一半,將隨機(jī)數(shù)的范圍變成-0.25到0.25,并應(yīng)用于最右邊的兩個(gè)點(diǎn)的中點(diǎn),則可以得到如圖2.4所示。圖2.2第一次模擬圖2.3第二次模擬圖2.4第三次模擬通過這個(gè)二維中Diamond-Square算法的模擬,可以發(fā)現(xiàn)效果還是不錯(cuò)的,而整個(gè)二維模擬中Diamond-square算法的實(shí)現(xiàn)過程可以參照以下的偽代碼:Startwithasinglehorizontallinesegment.Repeatforasufficientlylargenumberoftimes{ Repeatovereachlinesegmentinthescene { Findthemidpointofthelinesegment. DisplacethemidpointinYbyarandomamount. Reducetherangeforrandomnumbers. }}可以發(fā)現(xiàn)我們首先定義一個(gè)類將整個(gè)過程封裝起來。借來需要做的就是從一條直線開始,按照設(shè)定好的規(guī)則對圖像進(jìn)行處理,然后循環(huán)迭代,直到最終效果實(shí)現(xiàn)。在二維中實(shí)現(xiàn)Diamond-square算法的基礎(chǔ)上,我們可以將其拓展,應(yīng)用于三維繪圖中。在三維中對Diamond-square算法進(jìn)行模擬實(shí)現(xiàn),我們首先要轉(zhuǎn)變的就是本來線的概念已經(jīng)轉(zhuǎn)變成面的概念,本來X軸的位置表示現(xiàn)在將轉(zhuǎn)變成是X與Z坐標(biāo)組成的面的變動(dòng),原來的直線變動(dòng)變成多邊形的變動(dòng)。為了說明三維模擬中的Diamond-square算法的應(yīng)用,現(xiàn)在以一個(gè)4x4的正方形為例,在算法開始之前我們先做一些設(shè)定。為了方便描述,這里的多邊形以正方形為例,而為了形象描述出是峰值的點(diǎn),用小三角形作為已經(jīng)生成的山峰點(diǎn)。算法模擬之前,將正方形的四個(gè)頂點(diǎn)設(shè)定為已經(jīng)生成的風(fēng)指點(diǎn),如圖2.5所示。圖2.5三維模擬山的初態(tài)為了簡單直觀的模擬,首先為迭代過程聲明下必須遵循兩個(gè)原則,也就是算法規(guī)則,這兩個(gè)原則分別限制山峰高度形成和位置形成[10]:1)位置的形成:每次迭代,產(chǎn)生山峰的位置由正方形的四個(gè)頂點(diǎn)互相連接產(chǎn)生的對角線,對角線相交的產(chǎn)生的交點(diǎn)成本次迭代所產(chǎn)生的點(diǎn)的位置,也就是將四個(gè)頂點(diǎn)的坐標(biāo)值平均數(shù)值產(chǎn)生。2)高度的形成:每次迭代,產(chǎn)生山峰的高度值是將上次的峰值的一半最為上限,以零最為下限,以此為范圍產(chǎn)生一個(gè)隨機(jī)值,將該隨機(jī)值作為山峰的高度。在設(shè)定好規(guī)則之后,正式開始對三維中Diamond-square算法進(jìn)行模擬。第一次模擬之前,我們可以設(shè)定四個(gè)頂點(diǎn)的峰值為1.0,這樣方便描述也更容易讓人理解。確定好峰值之后,根據(jù)規(guī)則1,可以發(fā)現(xiàn)將正方形的四個(gè)頂點(diǎn)連接產(chǎn)生對角線交點(diǎn)即新的峰值點(diǎn),也就是新山峰位置。在確定好該山峰的位置之后,借來來就是根據(jù)規(guī)則2生成峰值。峰值的產(chǎn)生過程首先是確定峰值范圍,依據(jù)規(guī)則,本次峰值產(chǎn)生的上限是上次峰值的一半,也就是0.5,而峰值的下限則為0。由0到0.5之間隨機(jī)產(chǎn)生一個(gè)數(shù)值,則可以作為峰值。新產(chǎn)生的山峰通過大的三角形來標(biāo)注,模擬平面圖如圖2.6所示。圖2.6三維模擬山的第一次迭代在第一次迭代之后,有圖2.6可以發(fā)現(xiàn),新的峰值點(diǎn)和右邊兩個(gè)已有的峰值點(diǎn)可以看成是一個(gè)正方形的三個(gè)頂點(diǎn),這樣我們在產(chǎn)生新的峰值點(diǎn)之前就必須要先產(chǎn)生一個(gè)輔助的點(diǎn),作為新峰值點(diǎn)產(chǎn)生的國度。而輔助點(diǎn)的產(chǎn)生過程就是將正方形右側(cè)已有的兩個(gè)頂點(diǎn)連線作為對稱軸,將新產(chǎn)生的峰值點(diǎn)以它為對稱軸進(jìn)行對稱產(chǎn)生,如圖2.7所示即為產(chǎn)生輔助點(diǎn)。圖2.7三維模擬上的輔助點(diǎn)產(chǎn)生在輔助點(diǎn)產(chǎn)生之后新的正方形也隨即產(chǎn)生,依照第一個(gè)峰值點(diǎn)產(chǎn)生過程可以很容易對這個(gè)新的正方形進(jìn)行中點(diǎn)生成,就是將四個(gè)頂點(diǎn)連線,參照以上的高度和位置兩個(gè)原則,連線產(chǎn)生的交點(diǎn)就是新的山峰的位置,而山峰的高度都則是由0到0.25之間隨機(jī)產(chǎn)生的一個(gè)數(shù)值作為高度值的。按照這樣的方式依次對原正方形的四條邊都做同樣的操作模擬,最終在原正方形的四條邊的中點(diǎn)都可以產(chǎn)生一個(gè)新的山峰,而山峰的高度則應(yīng)隨機(jī)數(shù)值不同高度不一,有一定的隨機(jī)和真實(shí)性。山峰的位置效果圖如圖2.8所示。圖2.8三維模擬山的第二次迭代按照設(shè)定的原則,將生成的所有的點(diǎn)全部用小三角形,并對新產(chǎn)生的正方形進(jìn)行上面規(guī)則方法的迭代演算,這樣Diamond-square算法在三維圖像中的第三次迭代而產(chǎn)生的平面示意圖如圖2.9所示。 圖2.9三維模擬山的第三次迭代而如果將上面的平面圖中的山峰畫出來,效果將很好。這樣就需要對其進(jìn)行代碼實(shí)現(xiàn)模擬。而對于Diamond-square算法的模擬過程,可以通過下面的偽代碼更直觀的了解,偽代碼實(shí)現(xiàn)過程如下所示:1)開始之前,首先設(shè)定規(guī)則,初始化各個(gè)參數(shù),完成對規(guī)則的代碼實(shí)現(xiàn): Dothestepoflocation. Dothestepofheight. Reducerandomnumberrange. Callmyselffourtimes. 2)進(jìn)行函數(shù)的迭代 Whilethelengthofthesideofthesquaresisgreaterthanzero { Passthroughthearrayandperformthelocation Dothestepforeachsquarepresent. Passthroughthearrayandperformtheheight Dothestepforeachdiamondpresent. Reducetherandomnumberrange. }這就是Diamond-square算法在三維中的迭代模擬過程,在上面平面圖的刻畫過程中,如果把Y軸的數(shù)值體現(xiàn)出來,通過點(diǎn)之間的連線,效果會(huì)更好。下面對一個(gè)正方形進(jìn)行模擬,產(chǎn)生的示意圖如圖2.10所示。圖2.10一個(gè)正方形的真實(shí)模擬通過這個(gè)立體之后正方形,可以發(fā)現(xiàn)當(dāng)四個(gè)頂點(diǎn)的值確定好之后,通過算法生成正方形中心的坐標(biāo)之后,將五個(gè)頂點(diǎn)連起來的效果圖已經(jīng)初步具有了山起伏的感覺。而如果將正方形進(jìn)行放大,效果會(huì)更好。如果將正方形執(zhí)行算法的次數(shù)增加為2,可以發(fā)現(xiàn)在在第一次算法執(zhí)行后形成的四個(gè)正方形中,我們可以再次執(zhí)行一遍之前的算法,這樣每個(gè)新的正方形又會(huì)形成新的四個(gè)正方形,即產(chǎn)生4x4的正方形,除了四個(gè)頂點(diǎn)是本來固定好的,其余正方形內(nèi)部的點(diǎn)都是通過算法實(shí)現(xiàn)的后的坐標(biāo)確定的,可以發(fā)現(xiàn)這樣的實(shí)現(xiàn)效果看起來已經(jīng)具備了山的地形,具體的效果圖如圖2.11所示。圖2.114x4正方形的真實(shí)模擬可以發(fā)現(xiàn)隨著對算法執(zhí)行次數(shù)的增加,整個(gè)圖形也在變得復(fù)雜,而正方形中形成的點(diǎn)也在變得多。由于點(diǎn)的生成過程具有一定的隨機(jī)性,這樣最終的效果會(huì)讓山的模擬效果變得很好,而整個(gè)代碼的實(shí)現(xiàn)只不過是對算法執(zhí)行次數(shù)的增加,實(shí)現(xiàn)起來比較容易。在對山的模擬算法進(jìn)行了解后,下面我們可以繼續(xù)看看樹的實(shí)現(xiàn)是通過什么算法來實(shí)現(xiàn)的。2.3L-system算法樹的真實(shí)模擬一直是比較讓人頭疼的一件事,因其特殊性,樹的計(jì)算機(jī)模擬一直沒有被很好的模擬。直到后來,在計(jì)算機(jī)仿生模擬中,人們運(yùn)用到了L-system算法。L-system算法(LS文法)是在1968年由美國的生物學(xué)家同時(shí)也是數(shù)學(xué)家的AristidLindenmayer在對植物進(jìn)行大量的研究之后發(fā)現(xiàn)樹的局部結(jié)構(gòu)跟其整體有一定的相似性,非常符合分形理論的規(guī)律。在經(jīng)過大量的調(diào)查研究后,Lindenmayer提出了著名的L-system文法,該文法的提出是被用來描述植物的形態(tài)和生長的拓?fù)浣Y(jié)構(gòu)。而在1984年由Smith首次將該算法引入到計(jì)算機(jī)圖形學(xué)的領(lǐng)域[11]。LS文法實(shí)際上是一個(gè)字母重寫系統(tǒng),通過幾個(gè)字母的定理和字符作為初態(tài),然后根據(jù)規(guī)定的定理和文法進(jìn)行字母的逐個(gè)改寫,反復(fù)進(jìn)行多次,則可以產(chǎn)生一個(gè)多樣的字母組合。為了方便描述,不妨先做一些規(guī)定?,F(xiàn)在規(guī)定如下:T:在當(dāng)前方向上前進(jìn)一步,并畫出一條線+:逆時(shí)針旋轉(zhuǎn)動(dòng)給定角度δ;-:順時(shí)針旋轉(zhuǎn)動(dòng)給定角度δ;[:將當(dāng)前的位置信息(點(diǎn)的坐標(biāo)及前進(jìn)角度)壓入堆棧;]:將最近]時(shí)刻的信息出堆棧.有了這些符號則可以方便的描述整個(gè)描述過程,可以很方便的將即將產(chǎn)生的分形元形象化。這里不妨舉例描述如下分形元。δ=28°ω:TR:T→T[+T]T[-T]T其中,ω表示初始字母,R表示替換規(guī)則.按照上面的替換規(guī)則的規(guī)定可以進(jìn)行多次迭代,不妨用n來代表迭代的次數(shù),對整個(gè)文法進(jìn)行二次迭代,則有:n=0:Tn=1:T[+T]T[-T]Tn=2:T[+T]T[-T]T[+T[+T]T[-T]T]T[+T]T[-T]T[-T[+T]T[-T]T]T[+T]T[-T]Tn=3:…通過整個(gè)字母的替換,我們可以將上述文法做一些歸納,整個(gè)算法模擬過程即為:確定初始狀態(tài),確定δ的角度,將初始字母存入ω,將遵循的法則存入變量R。確定樹迭代的次數(shù)n。在ω中尋找字符T并通過法則R逐個(gè)的替換字母T。將以上的文法通過圖形畫出來效果是不錯(cuò)的。首先我們來看下整個(gè)畫圖的過程。下,當(dāng)n=1時(shí),將字符串依次讀入,最開始從T出發(fā),根據(jù)規(guī)則T代表需要畫一條直線,遇到字符“[”會(huì)壓入堆棧,旋轉(zhuǎn)的角度為δ,由于遇到字符“+”,因此會(huì)逆時(shí)針旋轉(zhuǎn),當(dāng)遇到T之后會(huì)畫線,接著“]”會(huì)讓信息出堆棧,遇到“T”會(huì)再次畫線,知道“[”再次壓入堆棧,遇到“-”順時(shí)針旋轉(zhuǎn)角度“δ”,在順時(shí)針旋轉(zhuǎn)角度“δ”之后,讀取到字母“T”的時(shí)候需要完成的工作又是畫線,當(dāng)畫線的工作完成之后可以發(fā)現(xiàn)又遇上了“]”字符,這樣在“]”總用下,根據(jù)之前規(guī)定好的算法要求,圖形繪畫指針需要走出堆棧。這是會(huì)遇到最后一個(gè)字符“T”,“T”使得指針會(huì)繼續(xù)執(zhí)行畫線操作,當(dāng)畫線完成之后,n為1分形元的繪畫工作就完成了,如果把整個(gè)過程的執(zhí)行效果化出來,可以發(fā)現(xiàn)最后的結(jié)果是非常的棒,整個(gè)分形元的最后效果圖見圖2.12。圖2.12LS算法的分形元以該分形元為基礎(chǔ),將該分形元作為基本元,進(jìn)行如上述過程的迭代,在經(jīng)過多次的迭代后會(huì)形成多個(gè)分支,就像一棵樹那樣。在對分形元經(jīng)過多次迭代之后,可以形成一棵樹的效果。這樣便基本上跟自然界中的樹有幾分相似,如果對該算法中加入隨機(jī)因子,使得每次樹木旋轉(zhuǎn)的角度和方向顯得更加隨機(jī),并且讓線條有樹木來取代,則會(huì)顯得更加的逼真,更加的跟現(xiàn)實(shí)中的樹相似。在整個(gè)迭代過程中不可忽略的就是每次迭代中都要對下一次迭代所產(chǎn)生的分支的大小進(jìn)行設(shè)定。分形樹的概念中對每個(gè)截取的分支都是跟整體的效果是相似的,但大小是不一的,因此,在第一次迭代之后,將下一次畫線的長度應(yīng)進(jìn)行一定的比例縮放是很有必要的。如果將由圖2.12生成的分形元作為基礎(chǔ),以每個(gè)分支再次作為樹干,執(zhí)行分形元的操作,這樣又會(huì)形成新的樹枝,而如此執(zhí)行分形元的操作多次,就可以看到一個(gè)很好的效果圖。圖2.13為將分形元算法執(zhí)行七次后形成的效果圖。圖2.13LS算法三次迭代后的效果圖通過上圖可以發(fā)現(xiàn),這棵基于分形技術(shù)的L-system文法生成的分形樹可以將樹的拓?fù)浣Y(jié)構(gòu)描繪出來。如果將它的進(jìn)行進(jìn)一步美化,讓它變得有血有肉,并且對樹的生成過程中再添加一些隨機(jī)因子,那么這樣的樹就會(huì)更加逼真,最后在對其進(jìn)行紋理映射,那么這就是一顆真正的樹了。置于什么是紋理映射,可以參看下面的介紹。2.4紋理映射紋理映射技術(shù)是計(jì)算機(jī)圖形學(xué)中應(yīng)用非常廣泛的一項(xiàng)重要技術(shù).傳統(tǒng)幾何通過造型技術(shù)只能描繪出自然景物的大致形狀和結(jié)構(gòu),但無法描述出景物表面的紋理和微觀細(xì)節(jié)。如果使用紋理圖像來描述景物表面各點(diǎn)處的反射和真實(shí)屬性,則可以達(dá)到模擬景物表面豐富的紋理細(xì)節(jié)的目的,提高計(jì)算機(jī)生成圖形的真實(shí)性。另外一方面,采用紋理映射的方法可以大大的簡化建模的過程,省去很多不必要的動(dòng)作。比如,同是一棟大樓表面,若完全用建模的方法來構(gòu)造,則需要畫出大樓的每一扇門,這是一個(gè)很繁瑣并且工作量也很大的工作。但若采用紋理映射,只需建立簡單的長方體模型,模型確定后只需要拍下的大樓外觀圖片,然后將圖片貼到模型表面,通過紋理映射技術(shù)形象逼真的將大樓呈現(xiàn)出來。為了了解紋理映射,我們首先可以看下對紋理映射都有哪些定義,在各個(gè)定義中是如何來描述紋理映射的。在對紋理映射的定義過程中可以分別從自然角度、運(yùn)算角度及分析角度給出紋理的三個(gè)方面的定義:從自然角度來看,紋理是在某一確定的圖像區(qū)域中,以近乎周期的種類和方式重復(fù)其自身的局部基本模式元。這一定義由Pratt給出,它適合應(yīng)用于確定類型的線條模式?;谶\(yùn)算角度,紋理是在某一運(yùn)算表達(dá)式規(guī)定下,為近乎不變或者近乎周期性的數(shù)量表達(dá)。它適合于根據(jù)數(shù)學(xué)的分析方法抽取紋理特征以實(shí)現(xiàn)紋理區(qū)域分類的應(yīng)用領(lǐng)域。基于分析角度,紋理為一個(gè)宏觀的圖像區(qū)域,其結(jié)構(gòu)可以簡單地歸結(jié)為一些重復(fù)性的模式,這些模式的基本模式元可以依據(jù)確定的規(guī)則排列,f=R(e),式中,R為關(guān)系,e為基本模式元,f為紋理。從上述三個(gè)不同形式的定義中,我們可以看出:人們無法依據(jù)一個(gè)關(guān)于紋理的完整的形式化定義來工作,必須根據(jù)具體的情況來決定使用那種紋理分析方法。根據(jù)紋理定義域的不同,紋理可分為一維紋理、二維紋理和三維紋理;基于紋理的表現(xiàn)形式,紋理可又分為顏色紋理、幾何紋理和過程紋理三大類。我們一般意義上的紋理映射技術(shù)是把二維的紋理圖像映射到三維物體表面,其關(guān)鍵點(diǎn)就是建立物體空間坐標(biāo)(x,y,z)與紋理空間坐標(biāo)(s,t)之間的對應(yīng)關(guān)系。為生成具有真實(shí)感的圖形,利用紋理映射技術(shù)將復(fù)雜物體的圖像粘貼到簡單幾何體的表面,置于場景中。比如為了在計(jì)算機(jī)中實(shí)現(xiàn)一塊草地的效果,如果通過純建模的方式來繪畫模擬,并要求很逼真的畫出每根草的狀態(tài),這是非常繁瑣并且工作量很大的工作,這是非常影響整體工程的效率的。而且由于刻畫的規(guī)律性和一致性,會(huì)讓整塊草地的效果變得非常的差。但如果在繪圖的過程中運(yùn)用紋理映射技術(shù),則可以很輕松而且逼真的模擬,完全不必去繁瑣的模擬草的形態(tài),不用考慮整體的效果。運(yùn)用紋理映射技術(shù)之后,草地的繪制過程就只需要先畫出一個(gè)正方形場景,在場景定下來之后,接下來要拍攝出一張草地的照片,然后運(yùn)用紋理映射將拍好的照片進(jìn)行紋理貼圖處理,在載入圖片并將其綁定在已經(jīng)畫好的正方形場景中,通過坐標(biāo)對應(yīng)的設(shè)定,可以將整張照片完全映射到正方形上,這樣就很逼真形象的描繪出草地的真實(shí)情景,從效果上看跟真的草地沒有太多的不同,紋理貼圖的具體效果可以參照如圖2.14所示。圖2.14紋理映射的效果圖在實(shí)時(shí)顯示場景時(shí),還可利用3D圖形的平移功能和旋轉(zhuǎn)功能,實(shí)現(xiàn)復(fù)雜物體隨觀察方向的改變而轉(zhuǎn)動(dòng)的效果,更加形象逼真的刻畫出景物真實(shí)的樣子。一般來說紋理映射的步驟如下[12]:第一步:定義紋理對象設(shè)定一個(gè)紋理對象數(shù)組Texture,并初始化這個(gè)數(shù)組。第二步:生成紋理對象數(shù)組通過glGenTextures函數(shù)生成一個(gè)紋理對象數(shù)組。第三步:通過使用glBindTexture選擇紋理對象,來完成該紋理對象的定義通過glBindTexture函數(shù)將紋理對象數(shù)組綁定,并通過g1TexImage2D函數(shù)來設(shè)定相關(guān)參數(shù)。第四步:在繪制景物之前通過glBindTexture,為該景物加載相應(yīng)的紋理。GlBindTexture(GLes_TEXTURE_2D,Texture[0]);第五步:在程序結(jié)束之前調(diào)用glDeleteTextures刪除紋理對象。GlDeleteTextures(TexNumber,me_Texture);這樣就完成了全部紋理對象的管理和使用。3.系統(tǒng)設(shè)計(jì)通過上一章的介紹,對于什么是分形理論,什么是Diamond-Square以及什么是L-system文法,我們都有了一個(gè)具體的認(rèn)識,對于紋理映射也有了一個(gè)較為深入的了解,而對于這些理論和算法是如何在本系統(tǒng)中用到的,可以在本章節(jié)中看到。首先我們先從系統(tǒng)所運(yùn)用到的環(huán)境和一些工具進(jìn)行了解。3.1系統(tǒng)工具和環(huán)境現(xiàn)行的三維再現(xiàn)工具中,有很多比較優(yōu)秀的軟件,比如AutoCAD,比如Maya或者3dMax等,這些軟件都有其自身的特點(diǎn),但考慮到本系統(tǒng)設(shè)計(jì)的初衷是基于分形技術(shù),并具體需要對算法進(jìn)行實(shí)現(xiàn),因此需要一款可編程的繪圖軟件,因此最終決定本系統(tǒng)的設(shè)計(jì)采用的是OpenGL結(jié)合C++語言,在VC6.0的環(huán)境下進(jìn)行古聚落三維場景的描繪。系統(tǒng)選擇C++語言是因?yàn)镃++語言具有很強(qiáng)的繼承性,同時(shí)C++也繼承了C語言指針這個(gè)功能,并且能很好的跟硬件進(jìn)行內(nèi)存的控制。C++最大的特點(diǎn)就是類的提出,這讓系統(tǒng)的設(shè)計(jì)可以在主函數(shù)的基礎(chǔ)上很好的進(jìn)行擴(kuò)充。場景中因?yàn)榇嬖谶@許多景物,因此獨(dú)立的畫出每個(gè)景物,最終在將他們很好的結(jié)合在一起是一個(gè)很不錯(cuò)的選擇,而C++正是實(shí)現(xiàn)這樣功能的一個(gè)很好的語言。而對于OpenGL的選擇,本系統(tǒng)選擇的是OpenGL2.0。OpenGL2.0將在OpenGL1.3基礎(chǔ)上進(jìn)行修改擴(kuò)充、但有下面五個(gè)方面的重大改進(jìn):①復(fù)雜的核心被徹底精簡;②完全的硬件可編程能力;③改進(jìn)的內(nèi)存管理機(jī)制、支持高級像素處理;④擴(kuò)展到數(shù)字媒體領(lǐng)域,使之跨越高端圖形和多媒體范疇;⑤支持嵌入式圖形應(yīng)用。為了在獲得強(qiáng)大功能的同時(shí)保持理想的兼容性,OpenGL2.0的發(fā)展經(jīng)歷兩個(gè)階段:第一個(gè)階段注重兼容能力和平滑過渡,為此,OpenGL2.0核心在精簡后的OpenGL1.3功能模塊的基礎(chǔ)上加上可完全兼容的新功能共同組成,這種做法在滿足兼容性的同時(shí),還可將原有OpenGL中數(shù)量眾多、且相互糾纏不清的擴(kuò)展指令進(jìn)行徹底精簡。第一階段的任務(wù)只是為了過渡,而第二階段才是OpenGL2.0的真正成熟期。此時(shí),ARB將合成出一個(gè)“純OpenGL2.0”內(nèi)核,純內(nèi)核將包含更多新增加的“精簡型API函數(shù)”,這些函數(shù)具有完全的可編程特性、結(jié)構(gòu)簡單高效、功能強(qiáng)大且應(yīng)用靈活。簡單點(diǎn)說,這個(gè)“純OpenGL2.0”主要由新加入的功能和OpenGL1.3的部分功能共同構(gòu)成,它主要包含了完全可編程能力、改進(jìn)的內(nèi)存管理機(jī)制和OpenML數(shù)字媒體功能等至關(guān)重要的新特性。和OpenGL一直處于對立的DirectX9API中具有完備的可編程能力,這項(xiàng)特性最大的好處就是靈活性,游戲開發(fā)商可根據(jù)自身需要靈活地制作出自己想要的圖形效果:更高精度、更快速度還是在兩者間進(jìn)行折衷。顯卡廠商對DirectX9的積極支持很大程度上就是因?yàn)檫@項(xiàng)可編程特性。而現(xiàn)在,OpenGL2.0也將具有完整的可編程能力,而它提供的功能超過了DirectX9。OpenGL2.0的可編程功能包括可編程頂點(diǎn)處理、可編程片段處理和可編程圖像格式三種:1)可編程頂點(diǎn)處理:取代坐標(biāo)轉(zhuǎn)換、材質(zhì)應(yīng)用程序及光照運(yùn)算,允許對個(gè)別頂點(diǎn)作隨機(jī)運(yùn)算;2)可編程片段處理:取代材質(zhì)存取、材質(zhì)應(yīng)用及霧化功能,允許個(gè)別片段的隨機(jī)運(yùn)算;3)可編程圖像格式:取代固定格式封裝和解封裝運(yùn)算,并允許OpenGL在傳送或接收像素?cái)?shù)據(jù)時(shí)、將類型與格式進(jìn)行任意組合。OpenGL2.0對OpenGL1.X僵化的內(nèi)存管理機(jī)制進(jìn)行了改進(jìn):OpenGL1.X的內(nèi)存管理方式相當(dāng)于黑箱作業(yè),內(nèi)存中的數(shù)據(jù)可被自動(dòng)處理,應(yīng)用程序無需了解運(yùn)算結(jié)果和運(yùn)算要花的時(shí)間,也無需控制存儲(chǔ)空間分配及對象的存放,這種設(shè)計(jì)在當(dāng)初是非常成功的,它將程序員從繁瑣的內(nèi)存控制工作中解放出來。但它的確無法有效控制對象的復(fù)制、搬移、刪除或封裝過程,內(nèi)存的利用效率變得頗為低下,成為顯卡性能的一大制約瓶頸。而OpenGL2.0直接為這些數(shù)據(jù)對象建立了定位和連接的接口,同時(shí)充分利用頂點(diǎn)數(shù)組、圖像、材質(zhì)、著色、顯示清單及像素緩沖區(qū)來對其作精確控制,此外OpenGL2.0還采用了壓縮技術(shù)來減少數(shù)據(jù)的移動(dòng)量。這些措施使OpenGL2.0獲得了高效管理內(nèi)存的能力,同時(shí)也保留了簡單易用的優(yōu)點(diǎn)。3.2系統(tǒng)過程步驟在整個(gè)場景的編程繪畫開始之前,對于整個(gè)程序的結(jié)構(gòu)的構(gòu)思直接影響到整個(gè)程序的運(yùn)行速度和效果。而對于本系統(tǒng)的實(shí)現(xiàn)步驟有過兩個(gè)構(gòu)思。第一個(gè)構(gòu)思是屬于拼湊型,也就是說先實(shí)現(xiàn)某一個(gè)功能,比如說完成對水的編程,這樣實(shí)現(xiàn)一個(gè)功能后,可以再對其他模塊進(jìn)行實(shí)驗(yàn)。在這個(gè)項(xiàng)目開始的初期,這是一個(gè)看似不錯(cuò)的想法,因?yàn)檫@樣的構(gòu)思很適合學(xué)一點(diǎn)做一點(diǎn),可以做到每個(gè)關(guān)鍵模塊的單獨(dú)運(yùn)行,對于實(shí)現(xiàn)每個(gè)模塊是非常簡單。但是問題顯現(xiàn)出來的時(shí)候就是在對所有實(shí)現(xiàn)的東西進(jìn)行整合的時(shí)候發(fā)現(xiàn),由于沒有統(tǒng)一的變量造成各個(gè)模塊的接口,也就是傳遞參數(shù)不能連接。而本來每個(gè)模塊單獨(dú)實(shí)現(xiàn)需要對整個(gè)場景的設(shè)定以及一些公用函數(shù),比如繪畫函數(shù),窗口銷毀等這些函數(shù)會(huì)顯得很累贅重復(fù)。因此在進(jìn)入到系統(tǒng)的總體設(shè)計(jì)階段,最終確定運(yùn)用第二種構(gòu)思,也就是先總后分的結(jié)構(gòu)。這樣的結(jié)構(gòu)比較麻煩,因?yàn)樵陂_始的總設(shè)計(jì)中要實(shí)現(xiàn)考慮好所有運(yùn)用到的函數(shù),對這些函數(shù)的傳遞參數(shù)是設(shè)計(jì)好,方便各個(gè)模塊能夠跑通。當(dāng)然這樣的結(jié)構(gòu)好處是不言而喻的,在總體設(shè)計(jì)好之后,主函數(shù)就像一個(gè)倉庫,或者說像是一個(gè)平臺(tái),在這個(gè)平臺(tái)上已經(jīng)形成了很多函數(shù),對于各個(gè)函數(shù)的設(shè)定比較統(tǒng)一,在調(diào)用的時(shí)候非常方便。最關(guān)鍵的在于由于各個(gè)公用函數(shù)的設(shè)定,使得系統(tǒng)的拓展非常容易。在這個(gè)平臺(tái)設(shè)定好之后,所需要做的工作就是對所要繪畫的景物進(jìn)行景物本身的設(shè)計(jì),完全不用再對函數(shù)進(jìn)行定義。而本系統(tǒng)的具體設(shè)計(jì)過程是從主函數(shù)開始,在主函數(shù)中設(shè)定場景的大小,定義一些變量,繪畫主要的場景,定義并實(shí)現(xiàn)一些功能如對視角的控制,對整個(gè)場景進(jìn)行霧化處理,對場景漸變的處理等。在完成這些整個(gè)場景的定義和處理功能之后,主函數(shù)中還有所做的就是對其他類都會(huì)用到的函數(shù)進(jìn)行統(tǒng)一的定義。比如繪畫函數(shù),這個(gè)函數(shù)在后來的景物設(shè)計(jì)模塊,每個(gè)模塊都會(huì)用到,因此可以統(tǒng)一設(shè)定;比如紋理映射函數(shù),這也是一個(gè)可以統(tǒng)一設(shè)定的函數(shù),因?yàn)閷D片的讀取,對圖片綁定這些工作都是一樣的,因此可以直接在主函數(shù)中就完成對所有景物處理的。而場景的異常處理,窗口的繪畫,場景視角問題的處理,這些也都是要在主函數(shù)中來定義的。在主函數(shù)確定好之后,接下來就可以以主函數(shù)為基礎(chǔ),在此基礎(chǔ)上對所需要的景物一一進(jìn)行代碼描繪。在對景物進(jìn)行描繪的過程中,需要注意的就是傳遞函數(shù),實(shí)際上傳遞函數(shù)的運(yùn)用能夠讓整個(gè)場景看起來更具有整體的效果。在所有的景物描繪函數(shù)完成之后,最后在主函數(shù)中,可以通過調(diào)用各個(gè)景物的繪畫函數(shù)最終將整個(gè)場景繪畫出來。整個(gè)系統(tǒng)設(shè)計(jì)的流程圖如圖3.1所示,可以發(fā)現(xiàn)這樣的處理過程很容易在原來的基礎(chǔ)上進(jìn)行增加,很適合對系統(tǒng)進(jìn)行升級。圖3.1設(shè)計(jì)流程圖3.3系統(tǒng)細(xì)化設(shè)計(jì)在系統(tǒng)細(xì)化設(shè)計(jì)開始,首先是搞清楚整個(gè)系統(tǒng)的設(shè)計(jì)流程。根據(jù)圖3.1所示的設(shè)計(jì)流程圖,最開始的工作就是對整個(gè)場景的設(shè)計(jì),在場景的設(shè)定中包括了對場景初始化的設(shè)定,大小的設(shè)定,以及系統(tǒng)異常時(shí)會(huì)如何操作,這些都是非常重要的東西,因?yàn)橹挥袑⑦@個(gè)平臺(tái)搭建好之后,才可以在這個(gè)場景中拓寬,才能豐富其整個(gè)古聚落遺址。在整個(gè)場景的設(shè)計(jì)過程開始之前有很多變量是需要值得去注意的。最主要的三個(gè)變量是著色描述表(RenderingContext)和設(shè)備描述表(DeviceContext)和窗口指派的句柄。每一個(gè)OpenGL都被連接到一個(gè)著色描述表上。著色描述表將所有的OpenGL調(diào)用命令連接到設(shè)備描述表上。因此需要?jiǎng)?chuàng)建一個(gè)設(shè)備描述表。設(shè)備描述表將窗口連接到圖形設(shè)備接口GDI(GraphicsDeviceInterface),而OpenGL連接設(shè)備描述表則是通過著色描述表來連接的這三個(gè)的關(guān)系不能弄錯(cuò),他們之間承擔(dān)著接口的作用。在所必需的變量設(shè)定好之后有一些類(class)需要去定義。在主函數(shù)中統(tǒng)一去定義這些類,可以方便的尋找,也方便別人對這個(gè)編程過程的理解。這些類很多是在建立程序開始的時(shí)候有系統(tǒng)創(chuàng)建的,除了這些,我們還要定義一些我們自己用到的函數(shù),為了統(tǒng)一,可以將這些函數(shù)以同樣的命名方式去定義。這些函數(shù)包括:設(shè)定場景大小的類,正常銷毀窗口的類,隱藏鼠標(biāo)的類,窗口異常的類,窗口正常繪圖的類等。在正常的去設(shè)計(jì)場景開始之前,還有一個(gè)非常重要的東西就是視角類。因?yàn)樽罱K我們設(shè)計(jì)出來的系統(tǒng)是一個(gè)可以游歷的三維立體的古聚落遺址再現(xiàn)場景,那么如何在場景中游歷就變得十分重要。本系統(tǒng)中主要是通過鍵盤方向鍵的控制來改變視角函數(shù)的坐標(biāo)來達(dá)到場景的游歷效果。當(dāng)一個(gè)場景的基本函數(shù)設(shè)定好之后,下面開始的就是對整個(gè)場景的細(xì)化設(shè)計(jì)。這些細(xì)化設(shè)計(jì)就是場景中的一些自然景物,包括連綿的山脈,流動(dòng)的海洋,漂浮的白云,茂盛的樹木還有最重要的村落。3.3.1高山的設(shè)計(jì)在對系統(tǒng)景物設(shè)計(jì)的初始,我們首先確定的是對場景中地形的設(shè)計(jì),而地形的設(shè)計(jì)中山脈無疑是比較麻煩也是比較關(guān)鍵的一步。本系統(tǒng)所運(yùn)用到的就是Diamond-square算法,不過在本系統(tǒng)中在Diamond-square算法基礎(chǔ)上進(jìn)行了一些改動(dòng),具體的改動(dòng)就是系統(tǒng)中對于山脈的生成過程不一定要求一定是正方形,對于長方形也可以。也就是說最后的多邊形并不是一定要求nxn的正方形,完全可以通過變量的控制在正方形中形成不只一個(gè)峰值。通過對Diamond-Square算法的運(yùn)用,本系統(tǒng)中在對高山的具體實(shí)現(xiàn)步驟如下:1)定義數(shù)組和變量,其中頂點(diǎn)用數(shù)組來表示;2)設(shè)定初始狀態(tài)正方形的四個(gè)頂點(diǎn)值;3)對整個(gè)迭代過程中的隨機(jī)變量進(jìn)行設(shè)定并進(jìn)行第1次迭代;4)對正方形進(jìn)行n次迭代;5)處理每個(gè)正方形銜接,做到無縫銜接;6)以三角形片渲染地形;7)對地形進(jìn)行紋理映射;8)開始繪圖,處理異常;在上面的對山脈實(shí)現(xiàn)過程步驟中,我們最先是定義一些數(shù)組和變量,這些數(shù)組是用來存儲(chǔ)整個(gè)代碼實(shí)現(xiàn)過程中的一些參數(shù)的。具體可以看下在具體程序中我們?nèi)邕m合定義的。具體代碼參照如下:voidCFractalTerrian::fill2DFractArray(float*fa,intsize,intseedValue,floatheightScale,floath)上面的代碼中fa是用來作為數(shù)組的首地址,它是用來存儲(chǔ)山峰的高度值的,size則是用來存儲(chǔ)網(wǎng)格的大小,也就是每個(gè)小正方形的大小,而seedValue則是用來表示隨機(jī)算法中所運(yùn)用到的種子值,而最后的h則是被用來最為一個(gè)擾動(dòng)值,確保最后產(chǎn)生山峰高度的隨機(jī)性和整體性。在最基本的數(shù)組和變量確定好之后,下面所需完成的就是對最初正方形的四個(gè)頂點(diǎn)進(jìn)行賦值,也就是最初的峰值。在賦值的過程中正方形的四個(gè)頂點(diǎn)的值是通過上面的數(shù)組來儲(chǔ)存的,對于如何來初始化這四個(gè)頂點(diǎn)的處置,具體代碼可以參照下面的賦值過程:fa[(0*size)+0]=fa[(subSize*size)+0]=fa[(subSize*size)+subSize]=fa[(0*size)+subSize]=0.f;需要聲明的是,這里的subSize是用來表示對縱向和橫向線段數(shù)統(tǒng)計(jì)的數(shù)位維數(shù)的變量。在這些初始化的工作做好之后,下面就的完成最重要的就是如何從四個(gè)正方形的頂點(diǎn)生成中間頂點(diǎn)。在中間山峰的坐標(biāo)生成過程中調(diào)用到一個(gè)正方形中間峰值產(chǎn)生函數(shù),這個(gè)函數(shù)是用來計(jì)算正方形中點(diǎn)的峰值的,它將四個(gè)頂點(diǎn)的峰值進(jìn)行平均,之后返回一個(gè)數(shù)值,這個(gè)數(shù)值將會(huì)在正方形中間的山峰生成過程中提供坐標(biāo)的數(shù)值。這個(gè)函數(shù)包含著正方形邊界長度,數(shù)組等變量,通過數(shù)組讀取四個(gè)頂點(diǎn)的坐標(biāo)數(shù)值,然后平均之后,返回一個(gè)數(shù)值,而這個(gè)數(shù)值就是正方形中央的峰值。這個(gè)y軸坐標(biāo)具體的生成過程的偽代碼代碼如下:Defineaclass(stride,size,float*Coordinate){ReturntheaverageCoordinate(Coordinate[1]+Coordinate[2]+Coordinate[3]+Coordinate[4])*.25f;}當(dāng)中心的坐標(biāo)生成之后,下面要做的就是將這個(gè)山峰畫出,在畫出的過程中并不能單單就這個(gè)山峰的坐標(biāo)突出,既然要體驗(yàn)出真實(shí)山的樣子,那么在山峰的形成中就應(yīng)該有漸變的過程,所以要對這個(gè)正方形內(nèi)的所有的頂點(diǎn)進(jìn)行一個(gè)坐標(biāo)轉(zhuǎn)換,而為了突出山峰生成的隨機(jī)性,這里面還增加了一個(gè)范圍從-0.5到0.5的隨機(jī)函數(shù),這樣會(huì)顯得生成的山更具有隨機(jī)性。其中的這個(gè)峰值的產(chǎn)生的偽代碼的實(shí)現(xiàn)過程如下:Settheloopscale1{Settheloopscale2{ Coordinate=Arandomnumberin(-0.5f,0.5f)+ Valuereturnfromtheclass }}在對簡單的一個(gè)正方形的中心值生成之后,我們還要對正方形中的其他點(diǎn)進(jìn)行高度值的生成,只有這樣才能不讓形成的山峰顯得比較單調(diào),才能讓生成的圖像變得更加真實(shí),細(xì)節(jié)做的更好。對于這種生成正方形中間點(diǎn)的過程相對是簡單的,而對于生成邊緣點(diǎn)的代碼實(shí)現(xiàn)就變得不是那么容易,因?yàn)檫吔鐔栴}是需要注意的問題,不然會(huì)很容易出錯(cuò)。在解決邊界問題過程中,為了解決四條邊上的情況,就用四個(gè)if語句來解決,當(dāng)一個(gè)頂點(diǎn)不存在的時(shí)候就用對邊的頂點(diǎn)來代替,這樣對于邊界問題,就可以保證不會(huì)出現(xiàn)峰值算不錯(cuò)或者報(bào)錯(cuò)。而這四個(gè)邊界的具體解決偽代碼如下:Defineanewclasstosolvetheboardproblem{If(case1) Returnthevalueinthiscondition1Elseif(case2) Returnthevalueinthiscondition2Elseif(case3) Returnthevalueinthiscondition3ElseReturnthevalueinthiscondition4}到這里我們已經(jīng)完成了簡單了一個(gè)正方形的繪制,我們可以先來了解一下我們實(shí)現(xiàn)的一個(gè)正方形的效果。效果圖如圖3.2所示。圖3.2一個(gè)正方形中山脈的形成圖通過上圖我們可以發(fā)現(xiàn)正方形的四個(gè)頂點(diǎn)就是我們設(shè)定的處置高度,而中間那個(gè)突出的小山峰就是我們第一迭代生成的那個(gè)峰值,從高度上看它比周圍四個(gè)峰值要小,這是因?yàn)槲覀儗λ裁吹碾S機(jī)值范圍設(shè)定為原來的二分之一。而在正方形的四條邊上也有四個(gè)相對應(yīng)的山峰,這四個(gè)山峰正式通過新生成的峰值點(diǎn)結(jié)合原來正方形的四個(gè)頂點(diǎn),在先產(chǎn)生四個(gè)輔助點(diǎn)之后,運(yùn)用Diamond-square算法生成的,而對于整個(gè)圖形中的其他值則是通過擾動(dòng)的數(shù)值讓它們不完全單調(diào)的相同或者不同,以形成自然界中山真實(shí)的效果。也許根據(jù)算法實(shí)現(xiàn)上面的效果圖之后,我們并沒有完全覺得它是山,只覺得這是一個(gè)奇怪的圖形或者說沒有山的感覺。的確,這樣的生成之后只是將山的算法實(shí)現(xiàn)了,并沒有將他美化。為了顯現(xiàn)出山的具體效果,我們必要要做的當(dāng)然就是將已經(jīng)繪畫好的山脈進(jìn)行紋理映射貼圖,讓山的紋理顯示出來。在對上面的山進(jìn)行紋理映射貼圖之后,我們可以看到它的效果圖,如圖3.3所示。圖3.3紋理映射后的一個(gè)正方形中的山脈在對單獨(dú)的一個(gè)正方形進(jìn)行了山脈效果的生成之后,下面的工作就是為找著所有山脈的峰值生成過程,這個(gè)過程實(shí)際上就是對上面一個(gè)正方形中山脈生成的過程的一個(gè)循環(huán)執(zhí)行,最終通過迭代的來產(chǎn)生整體的山的效果。我們可以通過下面的代碼來看下整個(gè)的實(shí)現(xiàn)的過程。 for(i=0;i<subSize;i+=stride){oddline=(oddline==0); for(j=0;j<subSize;j+=stride){ if((oddline)&&!j)j+=stride; fa[(i*size)+j]= scale*randnum(-.5f,.5f)+ avgDiamondVals(i,j,stride,size,subSize,fa); if(i==0) fa[(subSize*size)+j]= fa[(i*size)+j]; if(j==0) fa[(i*size)+subSize]= fa[(i*size)+j]; j+=stride; } }通過上面I的范圍是通過subSize控制的我們可以發(fā)現(xiàn),這樣我們就可以實(shí)現(xiàn)我們之前所說的在一個(gè)正方形中生成的并不一定還是正方形,因?yàn)樗木S數(shù),也就是subSize的是可以變化了,為了看一下這個(gè)subSize的控制功能的實(shí)現(xiàn),我們可以參照下面的兩幅圖。圖3.3所示的是subSize為而2的時(shí)候,也就是維數(shù)為2的時(shí)候產(chǎn)生的效果圖,而對圖3.4則是維數(shù)為3的時(shí)候的效果圖。圖3.4維數(shù)為2時(shí)的山脈效果圖圖3.5維數(shù)為3的山脈效果圖這樣我們通過控制維數(shù)就可以確定出最終整個(gè)山脈的大小和產(chǎn)生峰值的數(shù)量,本系統(tǒng)中對維數(shù)的設(shè)定確定為5。當(dāng)Diamond-square算法的基本算法用代碼實(shí)現(xiàn)之后,剩下來的就是進(jìn)行山脈的繪制工作。從上面看到的效果圖實(shí)際上都是紋理映射之后的效果圖,在這在著重將整個(gè)山峰的繪制的過程和紋理映射的步驟介紹一下。整個(gè)山峰的繪制工作實(shí)際上就是用三角片對整個(gè)地形進(jìn)行繪圖和紋理映射,在正式繪畫之前必須要做的就是將整個(gè)地形用三角片繪畫出來,在繪畫過程中通過GL_TRIANGLE_STRIP進(jìn)行繪制,因?yàn)橹暗乃惴ㄒ呀?jīng)將各個(gè)頂點(diǎn)的值進(jìn)行的實(shí)現(xiàn),現(xiàn)在要做到就是通過這個(gè)連續(xù)三角形繪畫函數(shù)GL_TRIANGLE_STRIP用循環(huán)將整個(gè)地形連續(xù)的畫出來。繪畫的過程和思路可以根據(jù)下面的偽代碼看出:Setanewclasstodrawthemountain{ SetsomeparametersaboutthisclassForacondition { UsethefunctionofGL_TRIANGLE_STRIPtodrawthemountain Settheparameteroftexture Settheline Settherow Starttodraw}}整個(gè)繪畫的過程實(shí)際上就是根據(jù)規(guī)則確定點(diǎn)的坐標(biāo),根據(jù)坐標(biāo)畫出三角形,根據(jù)連續(xù)的三角形來畫出整個(gè)山脈地形。當(dāng)用三角片繪畫過程中,同時(shí)需要完成的就是紋理映射工作,紋理映射在載入和綁定之后,每次生成點(diǎn)的時(shí)候也要對這個(gè)點(diǎn)所對應(yīng)的圖像所需映射的點(diǎn)的坐標(biāo)進(jìn)行設(shè)定。當(dāng)這些工作完成之后,則需要對整個(gè)山脈進(jìn)行真正意義上的繪畫,而這部分的偽代碼的流程如下: PushtheAttrib(0xffffffff);BindtheTextureofthismountainfunction; EnabletheGL_TEXTURE_2D; EnabletheGL_DEPTH_TEST; EnabletheGL_CULL_FACE; Definesomeparameters; Starttodraw { PushtheMatrix; Translatethecoordinate; RenderthecoordinateasTriangles; PoptheMatrix; } PoptheAttrib;在整個(gè)山脈的實(shí)現(xiàn)過程中,大致的思路就是先通過Diamond-Square算法將峰值的坐標(biāo)計(jì)算出來,然后在通過循環(huán)和生成三角片的形式將山峰畫出,本系統(tǒng)中的山脈的生成效果如圖3.6和圖3.7所示.這兩張分別是山脈的遠(yuǎn)景圖和近景圖。圖3.6山脈遠(yuǎn)觀效果圖圖3.7山脈近觀效果在完成對山的繪制工作之后,從效果上感覺這個(gè)山過于的荒涼,需要一些樹來點(diǎn)綴,畢竟樹是自然景物中常出現(xiàn)的一個(gè)景物,下面將著重介紹一下該系統(tǒng)中樹的生成過程。3.3.2分形樹的設(shè)計(jì)對于分形樹的設(shè)計(jì),主要運(yùn)用到的當(dāng)然就是L-system文法,將L-system文法的過程用語句描繪出來形成了算法。在該算法中實(shí)現(xiàn)的關(guān)鍵是對樹干的迭代和樹葉映射問題的解決。樹,由根而生,因此整個(gè)繪制的過程也不會(huì)本末倒置。在整個(gè)繪畫的開始,首先解決的中點(diǎn)就是將樹根和主要枝干繪畫出來,而為了避免在前面介紹L-system文法時(shí)生成的線條樹那樣的尷尬,其實(shí)最需要解決也是最實(shí)際的問題就是如何把圓柱形畫出來,畢竟這是將樹木飽滿化所必需的。在畫圓柱的過程中,本系統(tǒng)所運(yùn)用到的是gluCylinder函數(shù),gluCylinder函數(shù)設(shè)計(jì)到六個(gè)因子,分別指創(chuàng)建二次曲線的對象、圓柱底面的半徑、圓柱頂部的圓的半徑、圓柱的高度、片和堆棧。片和堆棧是保證圓畫得是否圓滑的關(guān)鍵。而這個(gè)圓柱的繪畫過程中不涉及到圓柱位置,是要通過其他的函數(shù)來控制的,這在后面樹的位置的確定中介紹。由于整個(gè)繪畫過程實(shí)際上通過迭代生成的,最開始的工作要從迭代初始狀態(tài)出發(fā),也就是對樹干的繪畫,因?yàn)檫@是整個(gè)分形樹的分形元,分形元中樹干的繪畫關(guān)鍵代碼實(shí)現(xiàn)如下:Setaclasstodrawthetrunk{ EnabletheGL_TEXTURE_2D;DisabletheGL_ALPHA_TESTincaseofenablebefore; Setaobjectparameterwhichisusedinthefunctionofcylinder UsethefunctionofdrawingCylindertodrawacylinderasthetrunk Deletethequadricsetbefore; DisabletheparameternamedGL_TEXTURE_2D;}在這個(gè)樹干的繪畫工作中上就是L-system文法的一次轉(zhuǎn)換,而原來的畫線現(xiàn)在也變成了圓柱形繪畫。通過上面?zhèn)未a的實(shí)現(xiàn)過程,我們可以將其在程序中具體實(shí)現(xiàn),而樹干的形成的效果圖我們可以參看圖3.8。圖3.8樹干的效果圖在解決了樹干的問題之后,在進(jìn)行整棵樹的繪畫工作之前,我們還有一個(gè)具體的問題需要解決,就是樹葉的問題。一顆樹不能光禿禿的全是樹干,因此樹葉是必不可少的東西。而對于樹葉的繪畫本不是難題,上面我們介紹過紋理映射的原理和功效,只需要通過繪畫一個(gè)矩形,然后將一張樹葉的照片紋理映射上去即可,但是這樣會(huì)出現(xiàn)一個(gè)問題,那就是整張圖像被紋理映射到樹葉位置上的時(shí)候,除了樹葉其他部分的圖形怎么辦,這些圖并不是我們所需要的貼圖,樹葉本身是不完全規(guī)則的幾何圖形,還不能簡單的畫出來,如圖3.9所示:圖3.9樹葉映射照片因此簡單的紋理映射并不能滿足要求,需要對映射到照片進(jìn)行處理,也就是說要將除了樹葉本身的部分其余部分不能顯示出來。因此我們考慮的就是如何將圖形中不要的地方去掉。這時(shí)候紋理映射的功能就派上了用場。首先我們先對對樹葉照片進(jìn)行處理,要將除了樹葉多余部分變成黑色,黑色在OpenGL中用坐標(biāo)形式的表示形式就是(0,0,0),在對圖像初步處理之后,接下來我們想做的就是讓黑色不顯現(xiàn)出來,但為了保證我們將多余部分變成黑色的工作是有效的,我們還要多出一步,就是將和(0,0,0)相差10的像素的Alpha值設(shè)定為0,我們需要最終映射到樹葉上的部分圖像的像素顯然比(0,0,0)要大很多,這樣那些沒有完全處理好的點(diǎn)就可以被完全變成的黑色,這部分的關(guān)鍵的函數(shù)的偽代碼如下所示:Defineaclasstosetthetextureoftheleaf{ Loadthetextureoftheleaf;Bindthetexture; Useafunctionnamedcolorlike(0,0,0,10)tosetpixelzero}在將和黑色像素相差10個(gè)像素的所有像素設(shè)定為0之后,接下來需要完成的工作就是對樹葉照片中這些黑色像素點(diǎn)進(jìn)行不顯示處理,而在對這些黑色像素的不顯示處理中需要做的就是對這些像素點(diǎn)的Alpha的范圍的判斷,具體如何判斷的實(shí)現(xiàn)過程可以參照下面籬笆實(shí)現(xiàn)的工程。在對Alpha的范圍判斷后我們選定的不顯示的像素點(diǎn),這個(gè)功能實(shí)際上是通過一個(gè)glAlphaFunc函數(shù)來實(shí)現(xiàn)的,具體實(shí)現(xiàn)過程為:GlAlphaFunc(GL_GREATER,0.5);這樣就可以將Alpha值小于0.5的像素全部不顯示出來,從而達(dá)到預(yù)期的效果,形成后的效果圖如圖3.10所示。圖3.10處理后的樹葉映射效果圖在對樹葉映射問題和樹干的繪畫問題解決之后,最主要的就是如何通過遞歸迭代出整棵樹的效果。每次迭代就是完成一次L-system算法規(guī)則的替換,畫出當(dāng)前樹干左右兩根樹枝。,在兩邊樹枝的繪畫過程中,通過每次旋轉(zhuǎn)一個(gè)隨機(jī)的角度,繪畫出一個(gè)圓柱形,并將樹葉繪畫在樹干的某個(gè)范圍內(nèi)的隨機(jī)點(diǎn)。在完成一個(gè)樹枝的繪畫工作后,通過循環(huán)會(huì)自動(dòng)將另外一根樹枝畫好,畫法跟第一根樹枝一樣。通過對每次迭代規(guī)則的不同,可以形成形狀不同的多種樹,本系統(tǒng)中實(shí)際上運(yùn)用了兩種不同的隨機(jī)生成方,一棵樹的迭代深度是2,而另一棵樹的迭代深度只有1。在這里著重解釋一下復(fù)雜度高一點(diǎn)的迭代深度為2的樹,為了方便簡稱為2號樹。2號樹實(shí)際上就是在1號樹的基礎(chǔ)上對迭代的深度增加了一個(gè)復(fù)雜度。在主要的樹主干畫好之后,分別通過對深度為2的時(shí)候和深度為1的時(shí)候進(jìn)行分別處理,相當(dāng)于在主干的基礎(chǔ)上又把主干生成的第一層樹枝和由第一層樹枝生成的第二層樹枝作為新的主干,這樣當(dāng)所有的“樹干”生成之后,可以對所有depth>1的樹干進(jìn)行處理,對所有樹干進(jìn)行樹枝的繪畫。在所有樹干的繪畫過程中不涉及到樹葉的繪畫,因?yàn)檫@次可以調(diào)用1號樹的繪制過程,從而提高代碼的重復(fù)利用。這樣其實(shí)2號樹生成函數(shù)的主要功能就是將深度增加為2后的樹干生成,而對于所有樹枝和樹葉的生成則調(diào)用了深度為1的樹的生成過程。深度為2而這部分的具體偽代碼如下:DefineaclasstodrawtheNo2tree{DefinearandomangletobetheangleofthebranchfloatrandAngle1;DrawtheSteamofthetreeConsiderthedepth=2{ Forasetcondition { SettherandomAngle; PushtheMatrix; Translatethecoordinate; Rotatethecoordinate; PoptheMatrix; }}Considerthedepth=1{ Forasetcondition { SettherandomAngle; PushtheMatrix; Translatethecoordinate; Rotatethecoordinate; PoptheMatrix; } For(I=0;I<2;I++) { SettherandomAngle; PushtheMatrix; Translatethecoordinate; Rotatethecoordinate; PoptheMatrix; }}If(depth>1){ SettherandomAngle; PushtheMatrix; Translatethecoordinate; Rotatethecoordinate; Drawthetree; PoptheMatrix; }通過上面代碼我們可以發(fā)現(xiàn)對于深度為2的樹的模擬過程并沒有涉及到樹葉的繪制,而是純樹枝的繪制。在這里面我們是從樹干開始繪制的,當(dāng)從樹根開始將主要樹干繪畫好之后首先是對深度為2的時(shí)候進(jìn)行處理。在對深度為2時(shí)候首先要對樹干生成的角度進(jìn)行設(shè)定,這是一個(gè)隨機(jī)的角度因此需要通過隨機(jī)函數(shù)來生成。當(dāng)樹枝的角度生成之后,所需要完成的就是通過Translate和Rotate這兩個(gè)函數(shù)將接下來所需要完成的繪畫樹枝的位置的確定。在對深度為2的設(shè)定好之后,接下來所需要完成的就是當(dāng)深度為1時(shí)候?qū)渲Φ奶幚?,?shí)際上這個(gè)處理的過程跟深度為2時(shí)的操作是一樣的。而當(dāng)這兩步完成之后,就是執(zhí)行繪畫過程,由于在深度為1和深度為2的兩個(gè)步驟中已經(jīng)對樹枝角度和位置進(jìn)行了處理確定,這樣通過if語句可以對整棵樹進(jìn)行繪制。通過上面的代碼的實(shí)現(xiàn),我們可以形成一個(gè)沒有樹葉的樹干。樹的效果圖如圖3.11所示。圖3.11深度為2樹干效果圖通過類似于深度為2的樹干的實(shí)現(xiàn)算法,我們對深度為1的樹可以同樣生成,只不過在深度為1的樹木生成過程中會(huì)減少一個(gè)深度的實(shí)現(xiàn),這樣主要樹干的生成過程就是迭代一次的過程。通過圖3.12我們可以看到深度為1樹干的效果圖。圖3.12深度為1的樹干效果圖由于兩種樹的深度不一樣,因此生成出來的樹木形狀也是不一樣的,深度為1的可以看成是為了保證頂端優(yōu)勢一直向上生長的樹木,而深度為2的樹木則可以看作是旁支很多一般不長高的樹。而深度為2的樹可以看成是將深度為1的樹看成一個(gè)分形元,并在此基礎(chǔ)上對整棵樹進(jìn)行了再一次的迭代,并在這個(gè)過程中添加了隨機(jī)因子,因此深度為1的樹看起來比較挺拔,而深度為2的樹則在它基礎(chǔ)上變得旁支很多,但這樣顯得真實(shí)性更大。為了將兩種樹對比,下圖顯示出了兩種深度所形成的不同的樹對比圖,通過樹的形狀可以很容易區(qū)分出第一棵是深度為1的樹,而第二棵樹從它的右邊旁支可以發(fā)現(xiàn),這是深度為1的樹的相似樹。為了將整棵樹的最終效果完成,我們對兩顆樹的實(shí)現(xiàn)中添加了樹葉的處理。由于深度為2的樹的生成過程可以調(diào)用深度為1的樹的生成過程,因此為了避免代碼的重復(fù)書寫,也為了對整個(gè)程序進(jìn)行優(yōu)化,因此對于樹葉的繪畫函數(shù)只需要出現(xiàn)在在深度為1的樹的實(shí)現(xiàn)過程中。樹葉的繪畫工作實(shí)際上就是在將樹葉確定好之后調(diào)用樹葉繪畫函數(shù)。而樹葉的繪畫過程就實(shí)際到樹葉的紋理映射問題,在本節(jié)的開始部分我們對樹葉照片中的像素點(diǎn)進(jìn)行了設(shè)定,這樣樹葉繪畫函數(shù)中只需要對樹葉的照片進(jìn)行紋理的載入,載入之后將樹葉照片綁定到樹葉形狀上。在添加了樹葉之后將兩棵樹進(jìn)行對比,效果圖如圖3.13所示。圖3.13不同隨機(jī)變量形成的不同的樹木通過上面的介紹發(fā)現(xiàn),其實(shí)樹木的生成是一個(gè)比較復(fù)雜的過程,如果就簡單的進(jìn)行代碼重復(fù)使用以達(dá)到最終形成森林的效果,這必將是一個(gè)很復(fù)雜的也是很繁瑣的事情。因此,一個(gè)能統(tǒng)一確定樹的產(chǎn)生數(shù)量和位置的函數(shù)的設(shè)定就很有必要。在主函數(shù)中通過設(shè)定一個(gè)樹的序列來表示樹木生成就顯得非常有必要。實(shí)際上通過設(shè)定一個(gè)類似于下面代碼所示的Treelist是很有用也是很高效的一步。它省去了代碼的重復(fù),提高了已有代碼的重復(fù)使用和高效性。通過這個(gè)序列,只需將樹的x軸和z軸的進(jìn)行設(shè)定,就可以確定樹木的生成位置,從而非常簡單而又高效的生成多棵樹木,形成森林。這個(gè)序列的生成過程如下所示:Defineaclasstomakealisttoshowthelocationofthetree{ Setthearraytoloadthevalueofx; Setthearraytoloadthevalueofz; SettheparametersofNo.1tree;SettheparametersofNo.1tree; Definethenewlist; Incondition1todrawtheNo.1tree; Incondition2todrawtheNo.2tree;}至此,我們對樹木的繪制工作已基本完成。通過上述的程序設(shè)計(jì)過程可以發(fā)現(xiàn),整個(gè)分形樹的繪畫過程大致遵循以下步驟:對樹干進(jìn)行繪畫,主要是圓柱形的繪畫;對樹葉進(jìn)行處理,特別是樹葉的邊緣設(shè)定,這涉及到Alpha值的設(shè)定;對樹葉進(jìn)行繪畫和紋理映射;對深度為1的分形樹的迭代生成過程進(jìn)行代碼實(shí)現(xiàn),迭代深度為1;對深度為2的分形樹進(jìn)行迭代代碼實(shí)現(xiàn),迭代深度為2;確定好樹的繪制過程后,通過一個(gè)序列來確定最終樹的位置和數(shù)量。通過以上步驟,特別是最后樹的位置和數(shù)量的確定之后,可以形成如同森林一般的樹木群,通過圖3.14可以看到它的效果。圖3.14森林的效果圖3.3.3天空的形成在對天空的繪畫所采用的是在整個(gè)地形上方繪制一個(gè)類似于“罩子”的圖形。本來系統(tǒng)的設(shè)計(jì)思想是根據(jù)古人天方地圓的想法,也就是在地形上畫一個(gè)半球形罩住整個(gè)場景,但后來發(fā)現(xiàn)可以通過幾個(gè)三角片拼接將天空罩住,而且由于三角片的繪畫速度非??欤虼俗罱K的天空實(shí)際上是有幾個(gè)三角片拼接而成。為了讓天空顯得逼真,因此云朵是非常關(guān)鍵的,經(jīng)過實(shí)驗(yàn)發(fā)現(xiàn)單獨(dú)做的云朵會(huì)讓天空顯得很怪異,而且由于云朵運(yùn)動(dòng)的速度會(huì)直接影響整個(gè)天空的效果。最后發(fā)現(xiàn)通過紋理映射將天空的照片映射到天空,可以逼真的顯示出天空的效果,為了解決云朵動(dòng)的問題,做了一些操作。聯(lián)想到自然界中的天空中云的飄動(dòng)多半是因?yàn)轱L(fēng)的原因。所以能嘗試著將風(fēng)模擬出來,然后讓風(fēng)的吹動(dòng)來使得云朵動(dòng)起來,但這個(gè)顯得非常麻煩,也許效果會(huì)很好,但對這個(gè)系統(tǒng)來說會(huì)舍棄掉重點(diǎn)。因此我們繼續(xù)探索,聯(lián)想到風(fēng)的形成是因?yàn)樗教荻攘?,而水平梯度力的形成是因?yàn)榈厍虻淖赞D(zhuǎn)和月球引力造成的。就是這里,自轉(zhuǎn)是引起云彩動(dòng)的最根本的原因,何不運(yùn)用地球的自轉(zhuǎn)讓云朵動(dòng)起來。為了讓天空轉(zhuǎn)起來最后并且能讓天空中的云朵動(dòng)起來,最好的就是將云朵也嵌在天空的貼圖里,這樣通過紋理映射可以逼真的顯示出靜止?fàn)顟B(tài)下云朵的樣子。在實(shí)現(xiàn)天空的過程中最先要求完成的就是繪制天空,在實(shí)現(xiàn)天空的繪畫過程中運(yùn)用到連續(xù)三角片的繪畫,也就是要用到glBegin(GL_TRIANGLE_FAN)這個(gè)函數(shù),而對于紋理映射在繪畫過程中也隨著三角片的繪畫直接紋理映射。在紋理映射之前要設(shè)定兩個(gè)參數(shù),第一個(gè)便是紋理映射變量設(shè)定,第二個(gè)是對紋理映射的范圍值的設(shè)定。具體的包括定義這個(gè)范圍值和初始化紋理映射變量:#defineTMMAX3.fExternGLuintload_texture(constchar*filename);這兩個(gè)的設(shè)定可以使得紋理映射能夠工作,同時(shí)通過修改TMMAX可以直接將映射的效果顯現(xiàn)出來,因?yàn)橘N圖本身沒有那么大,不可能完全的吻合天空的大小,因此就需要將貼圖重復(fù)貼好幾次,為了控制效果TMMAX就是控制貼圖紋理映射的次數(shù)。當(dāng)這些工作就緒之后,主要做的就是對天空的繪制,具體的代碼如下:UsethefunctionnamedGL_TRIANGLE_FANtodrawtheskyglTexCoord2f(0.f,0.f);glVertex3f(0.f,2.f,0.f);glTexCoord2f(-TMMAX,-TMMAX);glVertex3f(-20.f,-1.f,20.f);glTexCoord2f(0.f,-TMMAX);glVertex3f(0.f,-1.f,30.f);glTexCoord2f(TMMAX,-TMMAX);glVertex3f(20.f,-1.f,20.f);glTexCoord2f(TMMAX,0.f);glVertex3f(30.f,-1.f,0.f);glTexCoord2f(TMMAX,TMMAX);glVertex3f(20.f,-1.f,-20.f);glTexCoord2f(0.f,TMMAX);glVertex3f(0.f,-1.f,-30.f);glTexCoord2f(-TMMAX,TMMAX);glVertex3f(-20.f,-1.f,-20.f);glTexCoord2f(-TMMAX,0.f);glVertex3f(-30.f,-1.f,0.f);glTexCoord2f(-TMMAX,-TMMAX);glVertex3f(-20.f,-1.f,0.f);Endofthefunction;對天空的繪制中并不是一個(gè)半球形的,通過上述的代碼可以發(fā)現(xiàn),其實(shí)天空的繪制過程是通過連續(xù)的三角片,然后通過紋理映射將有云彩的圖片映射到這些三角片上,形成天空效果。而為了解決可能存在的空隙,這里還應(yīng)用了連續(xù)畫三角形的函數(shù)GL_TRIANGLE_FAN,通過這個(gè)函數(shù)可以不用把每個(gè)三角形的三個(gè)頂點(diǎn)坐標(biāo)寫出,它會(huì)自動(dòng)的將一個(gè)坐標(biāo)前面的兩個(gè)坐標(biāo)作為三角形的另外兩個(gè)頂點(diǎn),這樣通過十個(gè)頂點(diǎn)就可以畫出八個(gè)連續(xù)的三角形,既解決了本需要二十四個(gè)頂點(diǎn)完成的八個(gè)三角形,又使得最終的天空形成無縫連接,從而最終形成一個(gè)逼真的天空。天空的效果圖如圖3.15所示。圖3.15靜態(tài)天空的示意圖為了讓天空中的云動(dòng)起來,現(xiàn)在引入一個(gè)轉(zhuǎn)動(dòng)函數(shù),也就是glRotatef(rate,x,y,z);這個(gè)轉(zhuǎn)動(dòng)的函數(shù)引入可以讓天空動(dòng)起來,第一個(gè)rate表示可以設(shè)定天空的轉(zhuǎn)動(dòng)速度,而x,y,z則分別代表可以繞著x軸、y軸和z軸轉(zhuǎn)動(dòng),這三個(gè)數(shù)值的范圍都是從0到1,通過這三個(gè)數(shù)值的改動(dòng)可以讓物體繞著任意角度轉(zhuǎn)動(dòng)。本文中是讓天空繞著垂直于地面的y軸轉(zhuǎn)動(dòng),并且轉(zhuǎn)動(dòng)的速度是通過round這個(gè)變量來控制的,那么就有如下代碼:GlRotatef(round,0.0,1.0,0.0);這樣就可以讓天空轉(zhuǎn)動(dòng)起來,為了看出天空的轉(zhuǎn)動(dòng)效果,可以參照下面的同一個(gè)視角同一個(gè)地點(diǎn)時(shí)間不同的三幅圖,見圖3.16圖3.17和圖3.18,可以通過天空的云朵的不同發(fā)現(xiàn)天空在轉(zhuǎn)動(dòng)。圖3.16時(shí)刻1的天空圖3.17時(shí)刻2的天空圖3.18時(shí)刻3的天空3.3.4海洋的形成海洋的形成不同于樹木山脈的形成,因?yàn)閷τ谒畞碚f,不在是靜態(tài)的景物,水是必須要?jiǎng)悠饋淼?。而我們知道一般來說水動(dòng)是因?yàn)橛酗L(fēng)的存在,但由于風(fēng)的表現(xiàn)效果不是很好,因此在設(shè)計(jì)水流的時(shí)候,我們可以的設(shè)定了風(fēng)這個(gè)鍵。也就是說,當(dāng)靜止的時(shí)候,水面是靜止的,但一旦起風(fēng),我們可以設(shè)定一個(gè)鍵讓水動(dòng)起來,而這個(gè)動(dòng)的過程也是非常重要的。在這里為了讓水動(dòng),我們采取的是運(yùn)用系統(tǒng)時(shí)間的跳動(dòng)從而讓水動(dòng)起來。因?yàn)槿绻\(yùn)用循環(huán)函數(shù)只能在靜止后顯示靜止的圖像,而不能一直不停的動(dòng)起來,因此一個(gè)需要一個(gè)能夠讓水一直跳動(dòng)的變量作為繪畫過程中讓水動(dòng)的關(guān)鍵,很自然就會(huì)聯(lián)想到系統(tǒng)的時(shí)間。在這個(gè)變量的設(shè)定中,我們是通過glut

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論