簡體   English   中英

粒子沉積地形生成

[英]Particle Deposition Terrain Generation

我正在使用粒子沉積來嘗試在程序上創造一些類似火山的山脈,但我所能擺脫的只是金字塔狀的結構。 是否有人熟悉該算法可能能夠揭示我可能做錯的事情。 我現在正在將每個粒子放在同一個地方。 如果我不這樣做,它們會分散在非常薄的一層,而不是任何一種山。

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;
}

這是所有使用的代碼。

你應該看看這兩篇論文:

GPU上的快速水力侵蝕模擬與可視化

GPU上的快速液壓和熱侵蝕 (首先讀取第一個,第二個擴展)

不要被“在GPU上”嚇到,算法在CPU上工作得很好(盡管速度較慢)。 算法本身不進行粒子沉降(但你也不做;)) - 它們將粒子聚合成幾層矢量場。

這個算法的一個重要之處在於它侵蝕了已經存在的高度圖 - 例如用perlin噪聲生成的。 如果初始高度場完全平坦(或者即使它沒有足夠的高度變化),它也會失敗。

我自己實現了這個算法,並且大部分時間都取得了成功(還有很多工作要做,算法很難平衡以獲得普遍好的結果) - 見下圖。

請注意, 第二篇論文中使用熱風化成分的柏林噪音對您來說可能已經足夠了(並且可能為您節省很多麻煩)。

您還可以在我的項目中找到基於C ++ CPU的此算法實現(特別是此文件 ,請注意GPL許可證!)及其論文第24-29頁的簡化說明。

侵蝕的例子

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

一種簡單的方法是使粒子粘住(彼此吸引)。 粒子也需要具有一定的尺寸,以使它們不會簡單地會聚到完全重疊。 如果你想讓它們相互吸引,那么你需要測試粒子之間的距離。 您可以通過查看使用粒子的一些DirectX SDK示例獲益,特別是(雙關語!)在NVidia GPU計算SDK中有一個很棒的演示(由Simon Green?),它在CUDA中實現了粘性粒子。 它包含一份描述他們所做工作的自述文件。 如果你沒有進行大量粒子計數,你可以看到粒子如何相互作用並忽略所有CUDA / GPU的東西。

另請注意,只要您使用粒子間力,就會檢查大約0.5 * n ^ 2個粒子組合(對)...因此您可能需要使用簡單的空間分區方案或類似方法來限制附近的力只有粒子組。 祝好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM