Simulation d'érosion de surface basée sur les particules


Remarque: le code source complet du projet, ainsi que des explications sur son utilisation et sa lecture, peuvent être trouvés sur Github [ ici ].

J'ai pris une pause dans la thèse de mon master pour travailler sur ce que je repoussais depuis longtemps: une génération de terrain améliorée pour mon projet Territoire . Un moyen simple de le mettre en œuvre est l'érosion hydraulique, c'est pourquoi je l'ai créé!

Pour un puzzle logiciel d'une journée, cela a plutôt bien fonctionné et n'a pas été aussi compliqué que je m'y attendais. Les résultats sont rapidement générés, ont une signification physique et sont incroyables.

Dans cet article, je parlerai de ma simple implémentation C ++ d'un système d'érosion hydraulique à mailles carrées à base de particules. J'expliquerai toutes les justifications physiques sous-jacentes à l'implémentation et parlerai des mathématiques. Le code est extrêmement simple (seulement environ 20 lignes pour les mathématiques de l'érosion) et rapide à mettre en œuvre, je le recommande donc à tous ceux qui souhaitent augmenter le réalisme de leur terrain.

Les résultats sont rendus en utilisant une version simplifiée de mon moteur Homebrew OpenGl , que j'ai modifié pour rendre un tableau 2D de points sous forme de carte de hauteur. Une version allégée du moteur est beaucoup plus facile à comprendre si vous êtes intéressé à apprendre OpenGL en C ++.

la mise en oeuvre


Inspiré par de nombreuses sources d'érosion hydraulique, j'ai décidé qu'il serait plus logique d'utiliser des particules.

L'érosion à base de particules est très simple:

  • Nous créons une particule à un point aléatoire sur la surface.
  • Il se déplace / glisse le long de la surface en utilisant la mécanique classique standard (nous en parlerons ci-dessous)
  • Nous effectuons le transfert de matière / sédiment entre la surface et la particule (cela est également expliqué ci-dessous)
  • On évapore une partie de la particule
  • Si la particule est en dehors de la carte ou trop petite, détruisez-la
  • Répétez le processus avec le nombre de particules souhaité.

Remarque: les paramètres système sont expliqués dans la section correspondante. Le plus important est le facteur de pas de temps dt, qui met à l'échelle proportionnellement tous les paramètres. Cela nous permet d'augmenter la fréquence de la simulation (au prix d'une augmentation du bruit) sans changer l'échelle relative des paramètres. Cela peut être vu dans le code ci-dessous.

Particules


Pour ce faire, j'ai créé une structure de particules simple contenant toutes les propriétés dont j'ai besoin:

struct Particle{
  //Construct particle at position _pos
  Particle(glm::vec2 _pos){ pos = _pos; }

  glm::vec2 pos;
  glm::vec2 speed = glm::vec2(0.0); //Initialize to 0

  float volume = 1.0;   //Total particle volume
  float sediment = 0.0; //Fraction of volume that is sediment!
};

Remarque: si vous n'êtes pas familier avec la bibliothèque GLM: je l'utilise pour effectuer des opérations vectorielles.

Une particule a une position et une vitesse qui déterminent comment elle se déplace. De plus, il a un volume et une fraction qui détermine la proportion du volume des roches sédimentaires.

Mouvement: mécanique classique


Le mouvement des particules à la surface est simulé en utilisant la mécanique classique . En bref, la position x de la particule est modifiée par la vitesse v , modifiée par l'accélération a .



Remarque: les lettres en gras indiquent que la valeur est un vecteur.

On sait également que la force est égale à la masse multipliée par l'accélération:


La particule subit une accélération vers le bas causée par la gravité, mais elle est à la surface, ce qui rend l'accélération vers le bas impossible. Par conséquent, au lieu de cela, la particule est soumise à une force F dirigée le long de la surface et proportionnelle à la normale à la surface.

On peut donc dire que l'accélération a est proportionnelle au vecteur normal de la surface n divisé par la masse de la particule.


où k est la constante de proportionnalité et m est la masse des particules. Si la masse est égale au volume multiplié par la densité, alors nous obtenons le système complet de mouvement des particules en utilisant la mécanique classique:

//... particle "drop" was spawned above at random position

glm::ivec2 ipos = drop.pos; //Floored Droplet Initial Position
glm::vec3 n = surfaceNormal(ipos.x, ipos.y);  //Surface Normal

//Accelerate particle using classical mechanics
drop.speed += dt*glm::vec2(n.x, n.z)/(drop.volume*density);
drop.pos   += dt*drop.speed;
drop.speed *= (1.0-dt*friction);  //Friction Factor

//...

Remarque: la vitesse après le mouvement des particules est réduite par le vecteur de friction. Notez que le facteur de pas de temps est inclus ici. Les particules ont leur propre inertie, proportionnelle à leur densité du fait que nous simulons leur mouvement en utilisant l'accélération.

Le processus de formation des roches sédimentaires: transfert de masse


Le processus de formation des roches sédimentaires se produit physiquement comme le transfert des roches sédimentaires de la terre à la particule et de retour au point de la particule (" transfert de masse ").

En technologie chimique, le transfert de masse (c'est-à-dire le changement de masse / sédiment dans le temps) entre deux phases (dans ce cas, la surface de la terre et une goutte) est généralement décrit à l'aide de coefficients de transfert de masse .

Le transfert de masse est proportionnel à la différence entre la concentration c et la concentration d'équilibre c_eq:


où k est la constante de proportionnalité (coefficient de transfert de masse). Cette différence entre l'équilibre et la concentration réelle est souvent appelée la «force motrice».

Si la concentration à l'équilibre est supérieure au courant, la particule absorbe les roches sédimentaires. S'il est plus bas, il les perd. S'ils sont égaux, aucun changement ne se produira.

Le coefficient de transfert de masse peut être interprété de différentes manières:

  • Comme la fréquence de transition entre les phases (ici c'est le "taux de dépôt")
  • La vitesse à laquelle la concentration des gouttelettes tend vers la concentration d'équilibre

Le système dépend entièrement de la détermination de la concentration d'équilibre. Selon la définition, le système présentera différentes dynamiques de dépôt de roches sédimentaires. Dans ma mise en œuvre, la concentration d'équilibre est plus élevée si nous descendons, et si nous nous déplaçons plus rapidement, et elle est également proportionnelle au volume de la particule:

//...

//Compute Equilibrium Sediment Content
float c_eq = drop.volume*glm::length(drop.speed)*(heightmap[ipos.x][ipos.y]-heightmap[(int)drop.pos.x][(int)drop.pos.y]);

if(c_eq < 0.0) c_eq = 0.0;

//Compute Capacity Difference ("Driving Force")
float cdiff = c_eq - drop.sediment;

//Perform the Mass Transfer!
drop.sediment += dt*depositionRate*cdiff;
heightmap[ipos.x][ipos.y] -= dt*drop.volume*depositionRate*cdiff;

//...

Remarque: le changement de concentration à l'intérieur de la particule est complètement décrit par l'équation de transfert de masse. Le changement dans la carte de hauteur est en outre multiplié par le volume de particules, car nous le changeons proportionnellement non pas à la concentration, mais à la masse (la concentration est multipliée par le volume).

Autres aspects


La carte de hauteur est initialisée par un bruit Perlin multicouche avec une graine aléatoire.

A la fin de chaque pas de temps, la particule perd un peu de masse en fonction du taux d'évaporation:

//...

drop.volume *= (1.0-dt*evapRate);

//...

Ce processus est répété pour des milliers de particules créées dans des endroits aléatoires et simulées séparément (dans mon cas, les calculs sont effectués séquentiellement dans le CPU).

Mon implémentation par défaut comprend un bon ensemble de paramètres. Après 200 000 particules, l'érosion semble très bonne.

résultats


Le code fini pour le processus d'érosion est d'environ 20 lignes sans commentaire.

Voici une comparaison «avant et après» pour 10 échantillons. La simulation génère de très belles crêtes en élévation, des roches sédimentaires se déposent sur les côtés de certaines crêtes, ce qui conduit à la création de beaux plateaux.


Une sélection de dix comparaisons avant et après. Le shader que j'ai écrit reçoit deux couleurs en entrée. J'ai également implémenté la cartographie des ombres, le brouillard dépendant de la distance et l'ombrage Phong.

Voici dix autres échantillons (différents) juste avec les résultats:


Dix autres exemples de résultats. Ils diffèrent des précédents, même si certaines formations se ressemblent.

En choisissant différemment la graine lors de l'initialisation de la carte, vous pouvez créer des résultats différents contrôlés.

Temps de simulation


Le temps de simulation est directement lié à la durée de vie des particules et au nombre de particules simulées.

Plusieurs facteurs affectent la durée de vie des particules, et elle peut varier considérablement pour chaque particule, car elles sont créées à des endroits aléatoires:

  • Frottement et inertie: vitesse des particules
  • Taille de la grille: probabilité que des particules tombent de la carte.
  • Taux d'évaporation: taux d'extinction des particules

Avec les paramètres par défaut, une simulation d'une particule individuelle nécessite 10 à 100 millisecondes, ce qui donne 10 à 20 secondes pour une simulation de 200 000 particules.

Vous pouvez augmenter le degré d'érosion et réduire la durée de vie des particules en augmentant le pas de temps sans modifier le nombre de particules simulées. Cela peut rendre la simulation plus «bruyante» et si le pas de temps est trop grand, il y a une chance que la simulation échoue.

La simulation elle-même dans le moteur entraîne des coûts supplémentaires pour recréer le maillage de surface pour le rendu.

Vous pouvez optimiser le code en réduisant le coût de recréation du maillage ou en augmentant la vitesse d'un pas de temps pour une particule individuelle.

Travailler pour l'avenir


Je vais bientôt insérer ce code dans mon projet de territoire comme base pour générer une carte de hauteur dans le générateur d'altitude.

J'ai déjà écrit un cadre pour la simulation simplifiée de la dynamique des fluides dans les systèmes climatiques, mais il n'est pas encore prêt à être publié. Ce système obtient les modèles climatiques à partir d'une carte des hauteurs. Ce sera le sujet d'un futur article sur les systèmes climatiques procéduraux physiquement précis!

À l'aide d'un système climatique simulé, il sera possible à l'avenir d'échantillonner les particules de la distribution (par exemple, dans les endroits où il pleut) au lieu de les répartir uniformément sur la carte. Ils seront idéalement combinés avec la géologie et le climat du relief.

De plus, après avoir ajouté différents types de formations géologiques, les pierres peuvent avoir un degré de solubilité différent. Cela affectera directement le coefficient de transfert de masse (taux de dépôt), créant un taux d'érosion différent.

Ce système est incapable de simuler un véritable débit de fluide et de rivière, mais il peut potentiellement être adapté à de telles tâches. Je vais y réfléchir et peut-être qu'à l'avenir je publierai une suite de l'article.

All Articles