2013-05-16 104 views
3

我正在使用粒子沉積來嘗試和創建一些類似火山的山,但所有我從中獲得的是金字塔狀結構。是否有人熟悉這種算法,可能能夠揭示我可能做錯了什麼。我現在將每個粒子放在同一個地方。如果我不這樣做,他們會散佈在一個非常薄的層中,而不是任何山。粒子沉積地形生成

void TerrainClass::ParticalDeposition(int loops){ 
float height = 0.0; 




//for(int k= 0; k <10; k++){ 

    int dropX = mCurrentX = rand()%(m_terrainWidth-80) + 40; 
    int dropY = mCurrentZ = rand()%(m_terrainHeight-80) + 40; 
    int radius = 15; 
    float angle = 0; 
    int tempthing = 0; 
    loops = 360; 

    for(int i = 0; i < loops; i++){ 



     mCurrentX = dropX + radius * cos(angle); 
     mCurrentZ = dropY + radius * sin(angle); 

     /*f(i%loops/5 == 0){ 
      dropX -= radius * cos(angle); 
      dropY += radius * sin(angle); 
      angle+= 0.005; 
      mCurrentX = dropX; 
      mCurrentZ = dropY; 
     }*/ 

     angle += 360/loops; 


     //dropX += rand()%5; 
     //dropY += rand()%5; 

     //for(int j = 0; j < loops; j++){ 



      float newY = 0; 

      newY = (1 - (2.0f/loops)*i); 

      if(newY < 0.0f){ 
       newY = 0.0f; 
      } 



      DepositParticle(newY); 
     //} 
    } 
//} 
} 

void TerrainClass::DepositParticle(float heightIncrease){ 

bool posFound = false; 

m_lowerList.clear(); 

while(posFound == false){ 
    int offset = 10; 
    int jitter; 

    if(Stable(0.5f)){ 
     m_heightMap[(m_terrainHeight*mCurrentZ)+mCurrentX].y += heightIncrease; 
     posFound = true; 
    }else{ 
     if(!m_lowerList.empty()){ 

      int element = rand()%m_lowerList.size(); 

      int lowerIndex = m_lowerList.at(element); 

      MoveTo(lowerIndex); 

     } 
    } 
} 
} 

bool TerrainClass::Stable(float deltaHeight){ 

int index[9]; 
float height[9]; 

index[0] = ((m_terrainHeight*mCurrentZ)+mCurrentX);                  //the current index 
index[1] = ValidIndex((m_terrainHeight*mCurrentZ)+mCurrentX+1)  ? (m_terrainHeight*mCurrentZ)+mCurrentX+1 : -1; // if the index to the right is valid index set index[] to index else set index[] to -1 
index[2] = ValidIndex((m_terrainHeight*mCurrentZ)+mCurrentX-1)  ? (m_terrainHeight*mCurrentZ)+mCurrentX-1 : -1; //to the left 
index[3] = ValidIndex((m_terrainHeight*(mCurrentZ+1))+mCurrentX) ? (m_terrainHeight*(mCurrentZ+1))+mCurrentX : -1; // above 
index[4] = ValidIndex((m_terrainHeight*(mCurrentZ-1))+mCurrentX) ? (m_terrainHeight*(mCurrentZ-1))+mCurrentX : -1; // bellow 
index[5] = ValidIndex((m_terrainHeight*(mCurrentZ+1))+mCurrentX+1) ? (m_terrainHeight*(mCurrentZ+1))+mCurrentX+1: -1; // above to the right 
index[6] = ValidIndex((m_terrainHeight*(mCurrentZ-1))+mCurrentX+1) ? (m_terrainHeight*(mCurrentZ-1))+mCurrentX+1: -1; // below to the right 
index[7] = ValidIndex((m_terrainHeight*(mCurrentZ+1))+mCurrentX-1) ? (m_terrainHeight*(mCurrentZ+1))+mCurrentX-1: -1; // above to the left 
index[8] = ValidIndex((m_terrainHeight*(mCurrentZ-1))+mCurrentX-1) ? (m_terrainHeight*(mCurrentZ-1))+mCurrentX-1: -1; // above to the right 

for (int i = 0; i < 9; i++){ 
    height[i] = (index[i] != -1) ? m_heightMap[index[i]].y : -1; 
} 

m_lowerList.clear(); 

for(int i = 1; i < 9; i++){ 
    if(height[i] != -1){ 
     if(height[i] < height[0] - deltaHeight){ 
      m_lowerList.push_back(index[i]); 
     } 
    } 
} 

return m_lowerList.empty(); 
} 

bool TerrainClass::ValidIndex(int index){ 
return (index > 0 && index < m_terrainWidth*m_terrainHeight) ? true : false; 
} 

void TerrainClass::MoveTo(int index){ 
mCurrentX = index%m_terrainWidth; 
mCurrentZ = index/m_terrainHeight; 
} 

那就是所有使用的代碼。

回答

0

如果您希望它們不會分散到單層中,您的粒子在其物理模型中需要具有一定的表面摩擦和/或粘性(或相似性)。更新粒子模擬時,在代碼的碰撞檢測和碰撞響應部分執行此操作。

一個簡單的方法是使粒子粘住(吸引對方)。粒子也需要有一個大小,以便它們不會簡單地收斂到完全重疊。如果你想讓它們互相吸引,那麼你需要測試粒子之間的距離。 您可以通過查看一些使用粒子的DirectX SDK示例獲益,特別是(雙核!)在NVidia GPU Computing SDK中有一個很棒的演示(由Simon Green?提供),該演示實現了CUDA中的粘性粒子。它包括一個自述文件,描述他們所做的事情。你可以看到這些粒子是如何相互作用的,並且如果你不打算進行大量粒子計數的話,可以忽略所有的CUDA/GPU。另外請注意,只要你使用粒子間力,那麼你檢查大約0.5 * n^2的粒子組合(對)...所以你可能需要使用一個簡單的空間分區方案或類似的僅將力限制到附近的粒子羣。 祝你好運!

7

你應該看看這兩篇文章:

Fast Hydraulic Erosion Simulation and Visualization on GPU

Fast Hydraulic and Thermal Erosion on the GPU(先讀第一個,第二個就可以了擴展)

不要害怕通過了「在GPU上「,這些算法在CPU上工作得很好(雖然速度較慢)。這些算法本身不會進行粒子沉降(但你也不會;)) - 它們將粒子聚合成若干層矢量場。

這個算法的一個重要的事情是它會侵蝕已經存在的heightmaps - 例如生成perlin noise。如果初始高度場完全平坦(或者即使高度變化不足),它也會失敗。

我自己實現了這個算法,並且大部分都成功了(仍然有更多的工作要做,算法很難平衡以提供普遍的好結果) - 請參見下面的圖片。

請注意,perlin noise與來自第二篇論文的Thermal weathering組件可能對您來說已經足夠好了(並且可能爲您節省很多麻煩)。

您還可以找到下,在my project ++基於CPU的實現這個算法(具體this file,心中GPL許可證!)和我thesis的24-29頁對其進行了簡化描述。

Erosion example

+0

哇。這真太了不起了。我希望我在去年的算法課程中做了一個小型項目時知道你的項目。你的論文看起來很有趣,我希望有時間閱讀。 [我的項目在github上可用](https://github.com/bobbaluba/PTG)在zlib許可證下,以防任何人有興趣使用更寬鬆的許可證。 – bobbaluba

+0

你的結果比Decaudin's更加優越,至少從截圖來看,我非常欽佩他的作品。非常好。 –