Silverlight C# 遊戲開發:L7 HeightMap

在3D遊戲中,我們經常能夠看到連綿起伏的山脈,當在夕陽西下一覽衆山之時,可曾想過這美景在3D世界中是如何呈現,前面講完了燈光和攝像機,本篇聊聊Silverlight3D遊戲的HeightMap,並從文件中取得高度圖信息形成下面的3D地形。

 

HeightMap是地形的輸入數據,可以理解爲位圖,一個2D矩陣,和位圖不同的是,把元素的顏色值映射爲高度值,現實中的地形是真實的,不是由三角平面模擬的,但是3D圖形圖像處理中常常使用三角形來代替地形的表面,每個三角形的頂點高度在山脈到山谷之間轉換,模擬自然地形。我們來看看HeightMap的原理:

 

使用HeightMap的原因是表示方便,存儲和修改容易,從數據的角度上,HeightMap一般是灰度圖,灰度圖的一個像素數據只需要0xFF一個字節就可以表示,如果變成三維座標,基本數據值類型就會變得大,不利於數據處理,同樣一些阻擋算法也可以通過HeightMap計算,這部分我相信專門研究3D算法的朋友有研究,在這裏就不做多講。形成HeightMap的算法也比較簡單,只是將頂點集合做好即可。

那麼在Balder 3D中如何實現HeightMap,在Balder.Objects.Geometries中提供了HeightMap類,可以通過簡單的設置就能到HeightMap

  1. Heightmap heightmap = new Heightmap();  
  2. heightmap.Dimension = new Dimension() { Width = 120,Height = 120 };  
  3. heightmap.LengthSegments = 16;  
  4. heightmap.HeightSegments = 16;  
  5. game.Children.Add(heightmap);  
  6.    
  7.  
Dimension屬性是表示的大小;

LengthSegments屬性是橫向面片數量

HeightSegments屬性是縱向面片數量

那麼橫縱相乘就是16*16 = 256面片,依據個人所需要的平滑度可以進行調整。

HeightmapArray屬性是高位數據,用Float類型表示,它達標了在Heightmap區域內的高位信息,這個數組可大可小,越大精度越高,越小精度越小,下面簡單生成一個數組看看實際的效果,代碼如下

  1. float[,] HeightmapArray = new float[5, 5]  
  2.     {  
  3.         {0,5,10,5,0},  
  4.         {0,10,20,10,0},  
  5.         {0,20,30,10,0},  
  6.         {0,10,20,20,0},  
  7.         {0,0,0,0,0}  
  8.     };  
  9.    
  10.  
這是一個[5,5]的float數組,對其進行了簡單的數據填充,將這個數組賦值給HeightmapArray屬性,就可以得到下面的這個運行效果:

 

對照前面的實現原理,是否有意思了呢,這個數組的構建可以依據自己的需求做修改和開發,爲了滿足想進階的朋友,我下面寫了一個從位圖中創建HeightMap例子,以作參考。

  1. //從位圖中創建高度圖  
  2. void CreateHeightMapFormBitmap(Uri uri)  
  3. {              
  4.     BitmapImage bitmap = new BitmapImage();  
  5.     //從資源中取得BitmapStream  
  6.     StreamResourceInfo sri = Application.GetResourceStream(uri);  
  7.     bitmap.SetSource(sri.Stream);  
  8.     //生成WriteableBitmap  
  9.     WriteableBitmap writeablebitmap = new WriteableBitmap(bitmap);  
  10.     //創建高度圖數組  
  11.     float[,] HeightmapArray = new float[bitmap.PixelHeight,bitmap.PixelWidth];  
  12.     //將數組拷貝到高度圖數組  
  13.     for (int i = 0; i < bitmap.PixelHeight; i++)  
  14.     {  
  15.         for (int j = 0; j < bitmap.PixelWidth; j++)  
  16.         {  
  17.             int index = bitmap.PixelWidth * i + j;  
  18.             int pixel = writeablebitmap.Pixels[index];  
  19.             byte[] bytes = BitConverter.GetBytes(pixel);  
  20.             //計算:顏色越深則越低,顏色月淺則越高,50是最高的高度值  
  21.             HeightmapArray[i,j] = ((float)(bytes[0] + bytes[1] + bytes[2]) / 3) / 255 * 50 ;  
  22.         }  
  23.     }  
  24.     //賦值  
  25.     heightmap.HeightmapArray = HeightmapArray;  
  26. }  
  27.    
  28.  
我使用了一個比較暴力的像素點取值算法,將R、G、B三值進行平均,就能得到一個近似的灰度數值,然後除以255,乘以50換算成以50爲最高的高度數組,當然了,這裏你可以依據要求從50修改成任何數字。關於圖形圖像的算法,及實現原理請參考Silverlight C# 遊戲開發:資源的處理,圖像算法(二)

在這裏使用了GetResourceStream資源讀取的方式,因此你需要將位圖引用到工程當中,下面是測試用高度位圖,工程中做了縮小修改,畢竟用不上這麼精細的位圖。

 

使用上述代碼實現即可,可以點擊直接下載工程瀏覽和測試,那麼運行的預覽效果如下:

工程中如果缺少Balder.dll請在這裏快速下載:SL4_Balder.rar

下一篇我們介紹材質的應用,如何對模型進行貼圖和更換貼圖,以及貼圖的屬性,同時可能還結合HeightMap依據地理信息製作真實地圖,那麼下次再見。

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