Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Полный исходный код этого проекта, а также объяснение того, как его использовать и читать, можно найти на Github [здесь]. Проект рендерится при помощи моего собственного [TinyEngine].
В прошлом году я много экспериментировал со способами реализации эрозии на основе частиц для генерации рельефов.
Я считаю, что эрозия на основе частиц обеспечивает хороший баланс между реализмом и простотой, давая интуитивные описания переноса массы и энергии при их движении. Следовательно, они могут воспроизводить геомофологическое явление при низкой сложности концепций/кода как хорошие приблизительные модели. Благодаря этому они более доступны для большинства пользователей, чем исследовательские модели.
Один из самых хорошо известных и производительных алгоритмов улучшения генерации рельефов на основе шума — это гидравлическая эрозия на основе частиц [перевод на Хабре]. Этот алгоритм чрезвычайно прост и обеспечивает отличные результаты относительно малыми усилиями.
Его результаты убедили меня дополнить эту систему потоками воды и водоёмами, что привело к созданию процедурной гидрологической системы [перевод на Хабре]. Используя упрощённую модель, система успешно передаёт многие эффекты реального мира, поэтому я заинтересовался в дальнейшем исследовании симуляции геоморфологии на основе частиц.
Вскоре я осознал, что внеся только незначительные изменения, эти системы можно дополнить ветровой эрозией и основными эоловыми процессами. Так как в ненаучной литературе мне не удалось найти хороших ресурсов о реализации ветровой эрозии на карте высот, я решил спроектировать и реализовать собственную модель ветровой эрозии на основе частиц для процедурного рельефа.
Получившаяся система хорошо работает, позволяя моделировать движущиеся осадочные породы, а также сплошные неподвижные препятствия. Она воссоздаёт многие эффекты, наблюдаемые при реальной ветровой эрозии, например, серповидные дюны!
В этой статье я объясню своё решение для моделирования осадочных пород на твёрдом рельефе с созданием и переносом осадочных пород. В статье приведены соответствующие фрагменты кода на C++. В конце я расскажу о результатах, а также о возможных усовершенствованиях и дополнениях.
Система создаёт очень красивые результаты небольшим объёмом кода (примерно 200 строк для эрозии).
Симуляция системы ветровой эрозии на основе частиц в реальном времени на случайном произвольном рельефе с учётом только осадочных пород.
Примечание: я надеялся, что эта статья и код будут доступны для людей не из научных кругов, интересующихся процедурными рельефами. Если у вас возникли вопросы, то можете написать мне.
Симулируем ветровую эрозию
Приступив к проектированию системы, я провёл исследования о физических эффектах, которые должны отражаться в системе ветровой эрозии. Естественно, я воспользовался Википедией.
Я выяснил, что ветровая эрозия описывается двумя ключевыми эффектами:
- Дефляцией: перемещением осадочных пород ветром
- Абразией: превращением твёрдых пород в осадочные посредством столкновений
Третий ключевой компонент — это оседание осадочных пород, при котором частицы осадочных пород в куче «скатываются» вниз (это также называется cascading или каскадным осыпанием), пока склон не станет достаточно плоским, чтобы трение препятствовало их движению.
Примечание: пример оседания осадочных пород можно увидеть в этом посте на Reddit пользователя /u/monstermash12. Я не захотел вырезать оттуда видео.
Мой подход к описанию этих трёх динамических процессов заключался в моделировании двигающихся «частиц ветра», взаимодействующих со сплошными и свободными элементами рельефа.
Поведение частицы ветра можно вкратце описать так:
- Частицы ветра отражаются от рельефа и летят через него при помощи определённого описания движения
- Летящие частицы сталкиваются с твёрдым рельефом, изнашивая трением поверхность и превращая сплошную твёрдую массу в свободную осадочную породу
- Частицы ветра, двигающиеся над свободными осадочными породами, могут поднимать их часть и подвешивать в воздухе
- Перемещаясь по воздуху, частицы ветра роняют осадочные породы вниз
- При подъёме или падении осадочных пород свободные осадочные породы по соседству подвергаются оседанию.
Также нам необходимо подходящее описание осадочных пород, так как мы должны различать неподвижную и свободную породы.
Описание рельефа и осадочных пород
Класс мира содержит две карты, относящиеся к нашей модели: карту высот, описывающую неподвижную поверхность и карту осадочных пород, описывающую свободные частицы, наложенные поверх земли. Обе карты являются обычными плоскими массивами, заданными сеткой (256×256):
//...
#define SIZE 256
//...
class World{
public:
void generate(); //Initialize Heightmap
void erode(int cycles); //Erode with N Particles
//...
double heightmap[SIZE*SIZE] = {0.0}; //Flat Array
double sediment[SIZE*SIZE] = {0.0}; //Sedimentation Pile
//...
};
Такое разделение важно, потому что оно позволяет моделировать «препятствия», которые не участвуют в процессе переноса осадочных пород и только изнашиваются трением.
Мы представляем, что слой осадочных пород всегда находится поверх твёрдого слоя, а реальная высота рельефа представлена как сумма высот осадочных пород и твёрдой земли.
Также класс мира имеет функцию-член erode, при помощи которой процесс эрозии влияет на карты высот и осадочных пород.
Примечание: мы делаем предположение, что ветровая эрозия происходит в 2D. Эта система неспособна передать некоторые эффекты ветровой эрозии (например, арки, отверстия, скальные рельефы). Описанное в следующем разделе движение частиц представлено в 2.5D. Возможное расширение системы до 3D-рельефа при помощи слоёв рассмотрено в конце этой статьи.
Частица ветра
Добавив карты осадочных пород и высот мы хотим описать, как на них влияет движение ветра.
Частицы ветра описываются тремя ключевыми процессами:
- Движением, зависящим от динамики ветра
- Переноса масс абразией и во взвесях
- Оседания масс путём каскадного осыпания
Для описания этих процессов мы зададим структуру частицы ветра:
//Wind Particle
struct Wind{
//Constructors
Wind(glm::vec2 _pos){ pos = _pos; }
Wind(glm::vec2 _p, glm::ivec2 dim){
pos = _p;
int index = _p.x*dim.y+_p.y;
}
//Properties
int index;
glm::vec2 pos;
float height = 0.0;
glm::vec3 pspeed = glm::vec3(1.0,0.0,1.0);
glm::vec3 speed = pspeed;
double sediment = 0.0; //Sediment Mass
//Parameters
const float dt = 0.25;
const double suspension = 0.0001; //Affects transport rate
const double abrasion = 0.0001;
const double roughness = 0.005;
const double settling = 0.01;
//Sedimenation Process
void fly(double* h, double* path, double* pool, bool* track, glm::ivec2 dim, double scale);
void cascade(int i, double* height, double* sediment, glm::ivec2 dim);
};
Структура ветра содержит 3D-позицию и 3D-скорость. Свойство sediment описывает массу переносимых частицей осадочных пород, а пять параметров задают величину шага времени dt, коэффициент взвеси и коэффициент абразии, а также шероховатость осадочных пород и коэффициент оседания.
Наконец, частица ветра имеет две функции-члена:
- Fly: динамика движения, взвеси и абразии
- Cascade: алгоритм каскадного осыпания / оседания
И это полностью описывает динамику частиц. Подробнее об этих алгоритмах написано ниже.
Описание движения частиц
В методе, который сильно связан с описанием движения в моём коде простой гидравлической эрозии на основе частиц, для описания движения частицы мы используем принципы из базовой физики/ньютоновой механики.
Мы обозначим преобладающую скорость ветра как pspeed, и она будет служить изначальными условиями для скорости частицы. Частицы ветра создаются в случайных точках с наветренных сторон рельефа.
Функция fly определяет всё движение частицы на протяжении всего срока её существования:
void Wind::fly(double* h, double* w, double* s, bool* track, glm::ivec2 dim, double scale){
//Particle Position (Floored)
glm::ivec2 ipos;
//Repeat indefinitely
while(true){
ipos = pos; //Get Position
int ind = ipos.x*dim.y+ipos.y; //and Flat-Array Index
//Particles under the heightmap are moved upwards
if(height < h[ind] + s[ind]) height = h[ind] + s[ind];
//Compute Surface Normal (combined height AND sediment maps)
glm::vec3 n = surfaceNormal(pos, h, s, dim, scale);
//...
Сначала вычисляется геометрическая информация. Позиция округляется в меньшую сторону и вычисляется индекс плоского массива. Также в позиции частицы вычисляется нормаль к поверхности на основании карт высот и осадочных пород.
Механика движения частицы варьируется в зависимости от того, летит ли частица или скользит по поверхности.
Если частица скользит по поверхности или соударяется с ней, то она отражается. Мы задаём направление отражения как a по формуле:
где n — нормаль к поверхности в точке отражения, а v — вектор скорости. Вектор a представляет собой нормальный вектор нормали к поверхности n, находящийся в той же плоскости, что и вектор скорости v с нормалью к поверхности n.
Это уравнение угла отражения имеет и дополнительный эффект: двигающаяся вниз и сталкивающаяся с поверхностью частица будет правильно двигаться вдоль поверхности, отражаясь вдоль пути снижения.
Примечание: в частности, модель хорошо работает потому, что частица не «отскакивает» от поверхности и не меняет эластично направление движения на противоположное, а продолжает подвергаться преобладающей скорости. Представьте, что частица сталкивается с поверхностью так, что n = v. Что при этом произойдёт?
Для летящей по воздуху частицы мы предполагаем, что на неё не влияет сила сопротивления воздуха и она продолжает путь своего полёта, медленно ускоряясь вниз под воздействием гравитации.
Дополнив всё это условием завершения при покидании карты или приобретении неподвижности, мы реализуем полное движение:
//...
//Movement Mechanics
if(height > h[ind] + s[ind]){ //Flying
speed.y -= dt*0.01; //Gravity
}
else{ //Sliding
track[ind] = true; //For visualization!
speed += dt*glm::cross(glm::cross(speed,n),n);
}
//Accelerate by Prevailing Wind
speed += 0.1f*dt*(pspeed - speed);
//Update Position
pos += dt*glm::vec2(speed.x, speed.z);
height += dt*speed.y;
//New Position Index
int nind = (int)pos.x*dim.y+(int)pos.y;
//Out-Of-Bounds
if(!glm::all(glm::greaterThanEqual(pos, glm::vec2(0))) ||
!glm::all(glm::lessThan((glm::ivec2)pos, dim)))
break;
//...
//Mass Transport: Abrasion, Suspension, Cascading...
//...
//Particle has no speed (equilibrium movement)
if(length(speed) < 0.01)
break;
} //End While-Loop
};
Отражение и гравитация реализованы как силы ускорения частицы. Кроме того, частица подвергается ускорению от преобладающих ветров.
Примечание: когда частица скользит по поверхности, мы добавляем её позицию к массиву «track», который визуализируем позже.
Абразия/взвесь частиц
В процессе движения частиц по рельефу они взаимодействуют с картами высот и осадочных пород. Представленная ниже модель чрезвычайно груба, однако благодаря своей простоте обеспечивает хорошие результаты и легко может быть расширена до более сложных или реалистичных описаний взвесей и абразии.
Частицы на поверхности имеют определённое усилие контакта, пропорциональное их скорости и разности высот их движения.
Если неподвижная поверхность голая, то есть на ней нет осадочных пород, то это усилие преобразует при помощи абразии эту твёрдую поверхность в осадочные породы. Оно пропорционально размеру частицы осадочных пород, ударяющейся о поверхность. Если же поверхность покрыта осадочными породами, то они превращаются во взвесь и удаляются.
//...
//Mass Transport
//Surface Contact
if(height <= h[nind] + s[nind]){
double force = glm::length(speed)*(s[nind]+h[nind]-height);
//Abrasion
if(s[ind] <= 0){
s[ind] = 0;
h[ind] -= dt*abrasion*force*sediment;
s[ind] += dt*abrasion*force*sediment;
}
//Suspension
else if(s[ind] > dt*suspension*force){
s[ind] -= dt*suspension*force;
sediment += dt*suspension*force;
cascade(ind, h, s, dim);
}
else s[ind] = 0; //Set to zero
}
//...
Взвешенные частицы не имеют усилия контакта и просто экспоненциально теряют свою массу на основании коэффициента оседания.
//...
//Flying Particle
else{
sediment -= dt*suspension*sediment;
s[nind] += 0.5*dt*suspension*sediment;
s[ind] += 0.5*dt*suspension*sediment;
cascade(nind, h, s, dim);
cascade( ind, h, s, dim);
}
//...
Примечание: я выяснил, что такое распределение наноса падающих частиц на два временных шага приводит к созданию более чётких краёв дюн и уменьшает количество артефактов частиц на грани взвеси дюны.
Обратите внимание, обмене осадочных пород с частицей в соответствующей точке вызывается функция каскадного осыпания.
Каскадное осыпание осадочных пород
Свободные кучи осадочных пород подвергаются процессу каскадного осыпания, определяющему, каким образом осядет куча. В процессе притягивания гравитацией отдельных частиц на поверхности вниз наклон поверхности отклоняет эту силу вбок. Если боковое усилие больше, чем максимальная сила трения F между двумя контактирующими частицами, то частица откатится в сторону.
В зависимости от величины трения между частицами определяется максимальный «стабильный» наклон кучи осадочных пород. При фиксированном размере сетки наклон кучи пропорционален разности высот между соседями. Следовательно, для заданной F мы можем определить максимальную «стабильную» разность высот.
Добавление осадочных пород на стабильный склон или удаление их со склона могут сделать его нестабильным, что приведёт к перекатыванию и локальному движению масс. А это, в свою очередь, может привести к большей нестабильности и дальнейшему перекатыванию. Такой каскадный процесс естественным образом сведёт кучу к стабильному углу наклона.
Мы симулируем перекатывание обменом осадочными породами в тех местах, где разница между соседями превышает пороговое значение, пока разница не станет ниже или равна пороговому значению. Мы просто берём избыточные осадочные породы и равномерно их распределяем:
Хотя кажется естественным, что алгоритм каскадного осыпания нужно реализовать заливкой, я выяснил, что этот способ работает не очень хорошо. Рассмотрим позицию с несколькими соседями. Возникает несколько проблем:
- Если высоты двух соседей сильно различаются, то двоичный перенос осадочных пород подразумевает, что позиция не может быть стабильной с учётом обоих соседей одновременно. Следовательно, тогда важен порядок обмена масс.
- После того, как частица обменяется массами с её соседом, сосед снова может стать нестабильным относительно исходной позицией после того, как обменяется массой с его соседями. Функциональное множество каскадного перемещения при помощи заливки становится нулевым, только если найдено глобально стабильное решение.
Я придумал две логичных альтернативных реализации:
- Каскадное осыпание реализуется глобально для всей системы
- Каскадное осыпание реализуется локально и отложено по времени
Для глобального каскадного осыпания требуются итерации по всей карте осадочных пород на каждом шаге времени, что потенциально может быть затратно и физически неточно (нестабильность распространяется с вектором скорости).
Отложенное по времени локальное решение применяет каскадное осыпание за несколько шагов времени, выполняя алгоритм каскадного осыпания только локально там, где нарушен покой кучи осадочных пород, и обмениваясь только долей массы за каждый шаг времени с учётом «коэффициента оседания».
Такая реализация не требует строго стабильной конфигурации кучи осадочных пород на каждом шаге времени, и вместо этого учитывает, что сам процесс каскадного осыпания распространяется во времени через локальные взаимодействия. Благодаря нескольким этапам обмена в течение нескольких шагов времени куча осадочных пород сходится к стабильному склону.
Примечание: отложенное по времени локальное каскадное осыпание устраняет проблему определения порядка соседей, потому что не ищет локально стабильной конфигурации, достичь которой невозможно. Выполняется простой пропорциональный избытку обмен со всеми соседями частью массы, и в течение нескольких шагов времени эта система сходится.
void Wind::cascade(int i, double* h, double* s, const glm::ivec2 dim){
const int size = dim.x*dim.y;
//Neighbor Position Offsets (8-Way)
const int nx[8] = {-1,-1,-1,0,0,1,1,1};
const int ny[8] = {-1,0,1,-1,1,-1,0,1};
//Neighbor Indices (8-Way
int n[8] = {i-dim.y-1, i-dim.y, i-dim.y+1, i-1, i+1,
i+dim.y-1, i+dim.y, i+dim.y+1};
glm::ivec2 ipos;
//Iterate over all Neighbors
for(int m = 0; m < 8; m++){
ipos = pos;
//Neighbor Out-Of-Bounds
if(n[m] < 0 || n[m] >= size) continue;
if(ipos.x+nx[m] >= dim.x || ipos.y+ny[m] >= dim.y) continue;
if(ipos.x+nx[m] < 0 || ipos.y+ny[m] < 0) continue;
//Pile Size Difference and Excess
float diff = (h[i]+s[i]) - (h[n[m]]+s[n[m]]);
float excess = abs(diff) - roughness;
//Stable Configuration
if(excess <= 0) continue;
float transfer;
//Pile is Larger
if(diff > 0)
transfer = min(s[i], excess/2.0);
//Neighbor is Larger
else
transfer = -min(s[n[m]], excess/2.0);
//Perform Transfer
s[i] -= dt*settling*transfer;
s[n[m]] += dt*settling*transfer;
}
}
Следовательно, функция каскадного спуска вызывается локально в позиции где взвешиванием или наносом добавляются или убираются осадочные породы.
Подробности реализации
Полный цикл ветровой эрозии
В предыдущем разделе был полностью описан процесс движения частиц и эрозии. Для взаимодействия с рельефом частицы случайным образом порождаются на границе рельефа (это важно!) и постоянно подвергаются процессу движения/эрозии, пока не будут уничтожены.
void World::erode(int cycles){
//Track the Movement of all Particles
bool track[dim.x*dim.y] = {false};
//Do a series of iterations!
for(int i = 0; i < cycles; i++){
//Spawn New Particle on Boundary
glm::vec2 newpos;
int shift = rand()%(int)(dim.x+dim.y);
if(shift < dim.x) newpos = glm::vec2(shift, 1);
else newpos = glm::vec2(1, shift-dim.x);
Wind wind(newpos);
//Perform Wind Erosion Cycle
wind.fly(heightmap, windpath, sediment, track, dim, scale);
}
//Update Path
double lrate = 0.01;
for(int i = 0; i < dim.x*dim.y; i++)
windpath[i] = (1.0-lrate)*windpath[i] + lrate*((track[i])?1.0:0.0);
}
Места, в которых частицы имеют контакт с рельефом, хранятся как усреднённые по времени в массиве «windpath» при помощи массива булевых значений «track». Причины этого ранее описаны в моей статье о процедурной гидрологии, но, по сути, смысл этого заключается в возможности визуализации и изменения параметров (здесь не используется).
Визуализация
Результаты визуализированы при помощи моего самодельного движка TinyEngine.
Я накладываю слои карт высот и осадочных пород на общий меш и отрисовываю карту windpath вместе с картой осадочных пород на небольшом участке в углу окна.
Результаты
Показанные ниже результаты выполнены на сетке 256×256, а порождающие значения взяты из шума Перлина.
Образование и паттерны дюн
Система очень хорошо справляется с симуляцией движения чистых осадочных пород через взвеси и каскадное осыпание.
Ниже представлены три видео с типичным поведением ветровой эрозии в этой системе, каждое из которых имеет свои порождающие значения и углы.
Система ветровой эрозии образует красивые чёткие края дюн и даже несколько «серповидных дюн» (барханов) в правом верхнем углу.
Вот пример первоначального рельефа с большой крутизной рельефа. Реализованное отложенное по времени каскадное осыпание приводит к образованию плавной кривой склонов с подветренной стороны.
Пример первоначального рельефа, приводящего к образованию единой большой дюны. Движение частиц можно приблизительно наблюдать на хребте, образующемся на наветренной стороне большой дюны.
Системе успешно удаётся создавать чёткие края, которые обычно характерны для дюн, и она позволяет этим краям перемещаться и объединяться ожидаемым образом.
Ниже представлены две симуляции под четырьмя разными углами.
Препятствия и абразия
Создав схему с двумя картами высот, можно добавить в симуляцию препятствия, которые не попадают во взвесь.
В песке погребена большая пирамида, а сам песок подвергается ветровой эрозии.
Система частиц передаёт осаживание частиц с подветренной стороны таких препятствий.
Осадочные породы надлежащим образом оседают на подветренной стороне препятствия, когда частицы осадочных пород попадают в ветровую тень препятствия.
Кроме того, как и ожидается, на острых краях и концах препятствий абразия происходит сильнее. Коэффициент абразии представлен как свойство материала и может изменяться.
Процесс поверхностной абразии в увеличенном виде. Здесь для демонстрации паттерна абразии коэффициент абразии увеличен.
Варьирование параметров
Вот примеры скриншотов 30 секунд генерации для порождающего значения 1606266249 с различными вариациями параметров для базового случая.
Коэффициент оседания x4
Коэффициент оседания x0,2
Шероховатость x2
Образование взвеси x10
Образование взвеси x0,1
Скорость преобладающего ветра x0,25
Базовый случай
Изменение коэффициентов оседания и шероховатости влияет на поведение каскадного оседания, приводя к созданию более высоких или пологих дюн по сравнению с базовым случаем. Кроме того, более шероховатые дюны имеют более чётко выраженную текстуру.
Увеличенные коэффициенты образования взвеси перемещают больше осадочных пород, а снижение этих коэффициентов приводит к доминированию динамики каскадного осыпания.
Снижение скоростей преобладающего ветра приводит к созданию более чётких дюн с меньшим масштабом.
Производительность и масштабирование
Время исполнения симуляции эрозии масштабируется со сроком жизни частиц, который в свою очередь масштабируется с общим расстоянием, на которое они должны переместиться, прежде чем уничтожатся.
Вот несколько значений, полученных при выполнении симуляции эрозии на сетках разного размера с 250 частицами.
Размер сетки | Время симуляции (250 частиц) |
128×128 | около 33 мс |
256×256 | около 62 мс |
512×512 | около 130 мс |
Стоит заметить, что время исполнения приблизительно масштабируется в зависимости от длины стороны карты, а не от её площади, так как частицы движутся по карте в одном направлении (из-за преобладающего ветра).
Эту симуляцию легко расширить до альтернативных разрешений сетки, отмасштабировав динамику движения частиц. Образование осадочных пород и абразия не зависят от пространственного размера, а порог каскадного осыпания по высоте требует изменения масштаба.
Обратите внимание, что при более мелких разрешениях сетки при том же пространственном масштабе шаг времени тоже должен уменьшиться соответствующим образом.
Видео симуляции ветровой эрозии на сетке 512×512, ускоренное в 10 раз.
Созданная мной реализация очень сыра и неопримизирована. Если у вас есть мысли о том, где можно снизить время исполнения, то напишите мне.
Дальнейшая работа
Эту систему легко можно расширить для повышения реализма, но ради краткости я опустил часть таких аспектов.
Улучшенное движение частиц
Воздействие подъёмной и тяговой сил на летающие частицы может привести к тому, что лёгкие частицы будут бесконечно находиться во взвеси.
Отслеживание того, где и как летают по воздуху осадочные породы, позволит описать потоки перемещаемых по воздуху осадочных пород. При наличии на рельефе препятствий образуются ветровые каналы, которые могут воздействовать как сила на движение отдельных частиц (аналогично карте потоков).
Объединив эти два улучшения, мы сможем описывать возникающее явление пылевых бурь, зависящих от усиления и угасания преобладающего ветра.
Свойства и слои осадочных пород
Интересно было бы исследовать различные типы осадочных пород с разными свойствами, но для этого потребуется добавление дополнительных концепций наложения.
Наличие различных типов почвы потенциально позволит отслеживать сочетания слоёв, что повышает сложность разработки системы.
В идеале хорошая концепция наложения не должна существенно увеличивать вычислительные затраты, но обеспечивать повышенный реализм. Плохая концепция наложения с лёгкостью может превратиться в странное описание 3D-рельефа, чего, по моему мнению, стоит избегать.
Тем не менее, всё равно было бы здорово добавить различные типы почвы.
Соединение с системой процедурной гидрологии
Объединив систему процедурной гидрологии с системой ветровой эрозии, мы без лишнего труда могли бы получить геоморфологический симулятор с интересными дополнительными особенностями.
Например, термическая эрозия тривиальным образом реализуется на основе системы ветровой эрозии; достаточно описать её как абразивную силу, гененирующую осадочные породы, подвергаемые каскадному осыпанию.
Карта осадочных пород могла бы интересным образом взаимодействовать с картами водоёмов и потоков, так как осадочные породы могут содержать влажность (затапливаться), что приводит к таким концепциям, как подпочвенные грунтовые воды. Это могло бы привести к добавлению других концепций: подпочвенных потоков или болот/заболоченных земель.
Аналогично с системой процедурной гидрологии можно было бы добавить в симуляцию растительность, снижающую скорость ветра, образование взвеси осадочных пород и абразии поверхности.
Последние примечания
Я получил большое удовольствие от работы над этой системой. Надеюсь, она вдохновит кого-нибудь на реализацию собственной симуляции ветровой эрозии!
Моя основная цель — объединить модели климата и тектоники на макроуровне, чтобы использовать их данные для моделей гидрологии и ветровой эрозии на локальном уровне и получить общий физический генератор рельефа.
Если вас заинтересовали мои проекты и у вас есть какие-то вопросы или замечания, то можете написать мне.
Бонусное видео. Я догадался, что можно отключить вертикальную синхронизацию, чтобы всё происходило быстрее. Меня ограничивала частота кадров. Здесь создаётся одна большая чёткая дюна вдоль края, материал для которой даёт крупная дюна. Порождающее значение: 1606262917
Ещё одно красивое видео