3D地形中的道路模擬

  筆者注: 這篇文章是我本人在2009年發表在cppblog的一篇技術文章,因爲個人技術博客遷移至博客園,因此轉載到了此,非盜文。html

  如下是正文:算法

  前段時間被項目組長委派實現基於3D地形的道路系統。實現的目標是相似於Crysis編輯器的功能:能夠由編輯人員在地面上指定一系列控制點,用某種合適的曲線插值生成一條道路,指定紋理後就能夠智能地將道路顯示出來。編輯器

  然而要實現這些功能,必須克服如下的幾個難題:
(1)用哪一種曲線能夠方便模擬出道路段,並且能夠靈活地調節?
(2)地形一般都有Lod優化,其網格會實時變化,如何獲取道路段覆蓋的地形網格?如何讓道路恰好「貼」在地表上而不會產生交叉,融合,斷裂現象?
(3)如何生成道路頂點的紋理,才能不讓紋理產生扭曲或其它不許確的現象?

  剛剛接到任務時,一頭霧水,無從下手。因而急忙搬出google大哥,從gameres馳騁到gamedev,從項目組長詢問到網上認識的高手,都沒有找到道路實現的相關資料和有效的解決方法。

  後來研究了一下Crysis編輯器的道路系統操做和線條生成模式,而且在有着十幾年遊戲開發經驗的Dunhill兄指點迷津下,終於找到了一些眉目,通過半個月多的摸索和調試,終於在今天比較完整地將道路系統實現了。因爲網上資料少,特撰此文,若是之後有人也作到相似的專題,但願能夠提供一些有用的信息。

  首先,將編輯人員指定的道路控制點用樣條曲線生成一系列平滑過渡的道路段頂點。樣條曲線有不少種,通過比較,我採用了B樣條曲線,感受它能夠比較好地控制道路的彎曲,並且又不乏道路的平滑特性。由此解決了文章開頭提出的問題(1)。效果以下圖:
  優化

  上圖有6個控制點,通過插值生成了一系列中間過渡點,從而將控制點連成了比較平滑的道路骨架。對於樣條曲線插值的生成方法,網上不少資料,這裏就不詳細討論了。google

  接着,將生成的道路曲線分拆成一個個四邊形(咱們不妨稱之爲道路單元段),將這些四邊形覆蓋的地形圖元提取出來。因爲地形Lod是不斷變化的,若是道路隨着地形Lod變化就不斷提取地形圖元會使得效率很低下。通過一番研究,發現若是地形Lod作得足夠好的話,由地形Lod變化而產生的地形Pop現象對道路影響不大,徹底能夠提取道路在地形最高Lod時覆蓋的圖元數據,由此解決了開頭提出的問題(2)。注意在提取圖元的時候要徹底按照地形構造的規則進行提取,不然有可能出現道路和地形相交合或分離的問題。spa

  提取了某個道路單元段覆蓋的地形圖元后,將該道路單元段的四個頂點構造出四個垂直於水平面的裁剪面,將地形圖元和構造的裁剪平面做爲參數送入裁剪程序。裁剪程序一般是用三維齊次座標的區位碼標誌裁剪方法,這個算法在《計算機圖形學》一書有說起,網上也有該算法的詳細描述。將裁減後的道路單元段連接起來後的效果以下圖:
  3d

  黃色線條是地形圖元,黑色的線條是道路的圖元。能夠看出,通過裁減後的道路增長了不少頂點和線條來連接道路和地形的相交點,這樣作是爲了防止道路與地形可能出現的交叉、分離和斷裂現象。調試

  裁剪完道路單元段後,給每一個道路單元段的頂點生成紋理座標。嘗試了不少方法,最後採用的紋理映射方法是以下:htm

  

  見上圖,v0、v二、v三、v5是道路單元段的頂點,v一、v4分別是v0與v二、v3與v5的中點,v1到道路起始點的中軸線累積長度totalL,另外求出頂點到道路單元段的四個邊距L一、L二、L三、L4和中軸線長L。
  紋理座標u = L2 / (L2 + L4)
  紋理座標v = (totalL + L * L1 / (L1 + L3) ) / tileLength (tileLength是紋理的格子長度,可由編輯人員調節)


  這種紋理映射方法在道路不是很彎的狀況下,都能比較好地生產紋理圖。但若道路彎曲得比較厲害,紋理也會出現扭曲。若是哪位能提出更好的紋理座標生成方法,請告知。生成紋理座標後,記得給道路頂點高度往上平移一點點(我取了0.01f),這樣能夠避免道路和地形因爲Z值相同而產生閃爍現象.blog

  最後發一張貼上紋理的道路效果圖,若有什麼問題歡迎留言探討。

  

相關文章
相關標籤/搜索