天天看點

NeHe OpenGL第三十四課:地形

NeHe OpenGL第三十四課:地形

NeHe OpenGL第三十四課:地形
NeHe OpenGL第三十四課:地形

從高度圖生成地形:

這一課将教會你如何從一個2D的灰階圖建立地形

歡迎來到新的一課,Ben Humphrey寫了這一課的代碼,它是基于第一課所寫的。

在這一課裡,我們将教會你如何使用地形,你将知道高度圖這個概念。

下面我們來定義一些全局變量,MAP_SIZE是你使用的高度圖的大小,在這一課裡我們使用1024*1024的地圖。STEP_SIZE設定高度圖中相鄰頂點之間的距離。HEIGHT_RATIO設定在高度方向的縮放比例,越大地形看起來越陡峭。bRender設定使用多邊形還是線繪制地形。 

#define  MAP_SIZE 1024    

#define  STEP_SIZE 16     // 相鄰頂點的距離

#define  HEIGHT_RATIO 1.5f    

bool  bRender = TRUE;     // true為多邊形渲染,false為線渲染

下面的代碼用來儲存高度資料 

BYTE g_HeightMap[MAP_SIZE*MAP_SIZE];    // 儲存高度資料

float scaleValue = 0.15f;     // 地形的縮放比例

下面的函數從檔案中加載高度資料 

// 從*.raw檔案中加載高度資料

void LoadRawFile(LPSTR strName, int nSize, BYTE *pHeightMap)

{

 FILE *pFile = NULL;

 // 打開檔案

 pFile = fopen( strName, "rb" );

 // 如果檔案不能打開

 if ( pFile == NULL )

 {

  // 提示錯誤,退出

  MessageBox(NULL, "不能打開高度圖檔案", "錯誤", MB_OK);

  return;

 }

 // 讀取檔案資料到pHeightMap數組中

 fread( pHeightMap, 1, nSize, pFile );

 // 讀取是否成功

 int result = ferror( pFile );

 // 如果不成功,提示錯誤退出

 if (result)

  MessageBox(NULL, "讀取資料失敗", "錯誤", MB_OK);

 // 關閉檔案

 fclose(pFile);

}

InitGL函數基本沒有變化,隻是加入了加載高度圖的函數 

// 載入1024*1024的高度圖道g_HeightMap數組中

 LoadRawFile("Data/Terrain.raw", MAP_SIZE * MAP_SIZE, g_HeightMap);

下面的函數傳回(x,y)點的高度 

int Height(BYTE *pHeightMap, int X, int Y)   // 下面的函數傳回(x,y)點的高度

 int x = X % MAP_SIZE;    // 限制X的值在0-1024之間

 int y = Y % MAP_SIZE;    // 限制Y的值在0-1024之間

 if(!pHeightMap) return 0;    // 檢測高度圖是否存在,不存在則傳回0

 傳回(x,y)的高度 

 return pHeightMap[x + (y * MAP_SIZE)];   // 傳回(x,y)的高度

按高度設定頂點的顔色,越高的地方越亮 

void SetVertexColor(BYTE *pHeightMap, int x, int y)   // 按高度設定頂點的顔色,越高的地方越亮

{        

 if(!pHeightMap) return;     

 float fColor = -0.15f + (Height(pHeightMap, x, y ) / 256.0f);

 // 設定頂點的顔色

 glColor3f(0.0f, 0.0f, fColor );

下面的函數在OpenGL中,根據高度圖渲染輸出地形 

void RenderHeightMap(BYTE pHeightMap[])    // 根據高度圖渲染輸出地形

 int X = 0, Y = 0;      // 設定循環變量

 int x, y, z;      

 if(!pHeightMap) return;     // 确認高度圖存在

 if(bRender)      // 選擇渲染模式

  glBegin( GL_QUADS );    // 渲染為四邊形

 else

  glBegin( GL_LINES );    // 渲染為直線

下面的函數求得每一點的坐标和顔色,調用OpenGL渲染 

 for ( X = 0; X < MAP_SIZE; X += STEP_SIZE )

  for ( Y = 0; Y < MAP_SIZE; Y += STEP_SIZE )

  {

   // 繪制(x,y)處的頂點

 // 獲得(x,y,z)坐标

   x = X;

   y = Height(pHeightMap, X, Y );

   z = Y;

   // 設定頂點顔色

   SetVertexColor(pHeightMap, x, z);

   glVertex3i(x, y, z);   // 調用OpenGL繪制頂點的指令

   // 繪制(x,y+1)處的頂點

   y = Height(pHeightMap, X, Y + STEP_SIZE );

   z = Y + STEP_SIZE ;

   glVertex3i(x, y, z);  

 // 繪制(x+1,y+1)處的頂點

   x = X + STEP_SIZE;

   y = Height(pHeightMap, X + STEP_SIZE, Y + STEP_SIZE );

   glVertex3i(x, y, z);   

   // 繪制(x+1,y)處的頂點

   y = Height(pHeightMap, X + STEP_SIZE, Y );

  }

 glEnd();

 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);   // 重置顔色

DrawGLScene函數基本沒變化,隻是設定了視點和縮放系數,調用上面的函數繪制出地形。  

// 設定視點

 gluLookAt(212, 60, 194,  186, 55, 171,  0, 1, 0); 

 glScalef(scaleValue, scaleValue * HEIGHT_RATIO, scaleValue); 

 RenderHeightMap(g_HeightMap);    // 渲染高度圖

 return TRUE;   

WndProc()函數基本沒有變化,隻是加入了單擊左鍵的相應函數   

  case WM_LBUTTONDOWN:    // 是否單擊滑鼠左鍵

   bRender = !bRender;   // 改變渲染模式

   return 0;     // 傳回

原文及其個版本源代碼下載下傳:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=34

繼續閱讀