Генерация рельефа осаждения частиц

Я использую осаждение частиц, чтобы попытаться создать какие-то вулканически похожие горы, но все, что я получаю от этого, — это пирамидоподобные структуры. Кто-нибудь знаком с алгоритмом, который может пролить свет на то, что я могу делать неправильно? Я сбрасываю каждую частицу в одно и то же место в данный момент. Если я не сделаю этого, они рассыпаются в очень тонкий слой, а не в какую-либо гору.

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

Вот и весь использованный код.

3

Решение

Вы должны взглянуть на эти две статьи:

Быстрое моделирование и визуализация гидравлической эрозии на графическом процессоре

Быстрая гидравлическая и термическая эрозия на графическом процессоре (читайте первый первый, второй расширяет его)

Не пугайтесь «на GPU», алгоритмы прекрасно работают на CPU (хотя и медленнее). Алгоритмы не выполняют осаждение частиц как таковое (но вы тоже этого не делаете;)), вместо этого они объединяют частицы в несколько слоев векторных полей.

Одна важная особенность этого алгоритма состоит в том, что он разрушает уже существующие карты высот — например, сгенерированные с помощью перлин шум. Это с треском проваливается, если начальное поле высоты полностью плоское (или даже если оно имеет недостаточное изменение высоты).

Я сам реализовал этот алгоритм и в основном добился успеха (все еще предстоит проделать большую работу, алгоритмы очень трудно сбалансировать, чтобы дать универсально отличные результаты) — см. Изображение ниже.

Обратите внимание, что перлин шум с компонентом Thermal Weathering из второй статьи может быть достаточно для вас (и это может сэкономить вам массу хлопот).

Вы также можете найти реализацию этого алгоритма на основе процессора C ++ в мой проект (в частности, этот файл, обратите внимание на лицензию GPL!) и ее упрощенное описание на страницах 24-29 моего Тезис.

Пример эрозии

8

Другие решения

Ваши частицы должны будут иметь некоторое поверхностное трение и / или липкость (или подобное) в своей физической модели, если вы хотите, чтобы они не растекались в один слой. Это выполняется в частях кода при обнаружении столкновений и реагировании на них при обновлении симуляции частиц.

Простой подход — заставить частицы прилипать (притягивать друг друга). Частицы также должны иметь размер, чтобы они не просто сходились к идеально перекрывающимся. Если вы хотите, чтобы они притягивали друг друга, то вам нужно проверить расстояние между частицами.
Вы могли бы получить пользу от просмотра некоторых примеров DirectX SDK, в которых используются частицы, и, в частности (pun arf!), Есть отличная демонстрация (от Simon Green?) В NVidia GPU Computing SDK, которая реализует липкие частицы в CUDA. Он включает в себя документ ReadMe, описывающий, что они сделали. Вы можете увидеть, как частицы взаимодействуют, и игнорировать все, что связано с CUDA / GPU, если вы не собираетесь проводить массовые подсчеты частиц.

Также обратите внимание, что как только вы используете межчастичные силы, вы проверяете примерно 0,5 * n ^ 2 комбинаций (пар) частиц … поэтому вам может потребоваться использовать простую схему пространственного разделения или аналогичную, чтобы ограничить силы рядом только группы частиц.
Удачи!

0

По вопросам рекламы [email protected]