特效實現用查表法實現對水波的模擬(轉)

post0發表於2007-08-12
特效實現用查表法實現對水波的模擬(轉)[@more@]

  最近在網上看到一個水波摸擬的貼子。覺得演算法可以更快一點,因此自己想出這個查表法模擬的程式,大家看看有沒有價值。

  

  原理

  在一個波長範圍內,任意點的位移disp = sin(dist)*force +disp_center;

  這裡設水波為正弦波,振幅為force,disp_center為振中的位移。

  推廣到任何點,disp = sin(dist % wave_length)*force + disp_center;

  這裡wave_length 為波長。可以看出,在離散的資料中,任何點的位移是有限的集合。我們先構造出這個集合,在運算過程中,從集合中選取一個位移值就行了,而不用實時計算每個點的位移。

  

  程式設計如下:取波長為12,任何點的位移由一個12個元素的陣列。

  int disp[12];

  

  建立一個陣列成存貯各點來振中的距離

  int dist[600][800];

  

  下面生成一個水波

  inline void Build_Disp_Matrix()

  {

  for(int i = 0; i < 12; ++i)

  disp[i] = static_cast(sin((double)i*30*DXPI/360)*PRECISION);

  }

  

  void Create_Ripple(int center_x, int center_y, int force, int damp, int wave_length)

  {

  

  for(int i = 0 ; i < wave_length; ++i)

  {

  disp[i] = force * disp[i] / PRECISION;

  }

  

  int dist_x, dist_y;

  for(i = 0; i < SCREEN_HEIGHT; ++i)

  {

  for(int j = 0; j< SCREEN_WIDTH; ++j)

  {

  dist_y = i - center_y;

  dist_x = j - center_x;

  dist[i][j] = static_cast(sqrt(dist_x*dist_x + dist_y*dist_y) + 0.5) % wave_length;

  }

  }

  

  }

  

  渲染水波的程式碼與原來的程式碼一樣。

  void Render_Ripple(LPDIRECTDRAWSURFACE7 lpdds)

  {

  DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

  

  if(disp_index < 0) disp_index = 12;

  

  --disp_index;

  

  lpdds->Lock(NULL,&ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);

  short* lpSrcBuffer = static_cast(pBmpBack->GetBitmapBuffer());

  

  int pitch = (ddsd.lPitch) >> 1;

  

  short* lpBuffer = static_cast(ddsd.lpSurface);

  

  int left,right,bottom,top;

  int k = 0,l = 0;

  int index_x,index_y;

  int x_off,y_off;

  int pos1,pos2;

  for(int i = 1; i < SCREEN_HEIGHT - 2; ++i)

  for( int j = 1; j < SCREEN_WIDTH - 2; ++j)

  {

  left = right = bottom = top = disp_index;

  

  left += dist[i][j -1];

  if(left > 12) left -= 12;

  right += dist[i][j+1];

  if(right >12) right -= 12;

  bottom += dist[i+1][j];

  if(bottom > 12) bottom -= 12;

  top += dist[i-1][j];

  if(top >12 ) top -= 12;

  

  x_off = disp[left] - disp[right];

  y_off = disp[top] - disp[bottom];

  

  index_x = j + x_off;

  index_y = i + y_off;

  

  pos1 = i*pitch +j;

  pos2 = index_y * 800 + index_x;

  if(pos2 < 0 || pos2 > 479999) break;

  

  lpBuffer[pos1] = lpSrcBuffer[pos2];

  }

  

  pBmpBack->ReleaseBuffer();

  lpdds->Unlock(NULL);

  

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-951970/,如需轉載,請註明出處,否則將追究法律責任。

相關文章