Mondes générés par la procédure

76

Je suis sûr que vous connaissez tous des jeux comme Dwarf Fortress - des étendues sauvages et des terres générées par des procédures. Quelque chose comme ça, tiré de cet article très utile.

Cependant, je me demandais comment je pourrais appliquer cela à une échelle beaucoup plus grande; on pense à l'échelle de Minecraft (n'est-ce pas quelque chose comme 8 fois la taille de la surface de la Terre?). Pseudo-infini, je pense que le meilleur terme serait.

:RÉ

L'article parle du bruit fractal perlin. Je ne suis en aucun cas un expert en la matière, mais je comprends l'idée générale (c'est une sorte de bruit généré de manière aléatoire qui est semi-cohérent, donc pas seulement des valeurs de pixels aléatoires).

Je pourrais simplement définir la taille des régions X par X, ajouter des éléments de type chargement de région et générer un bruit par une région. Mais cela ne ferait que créer d'énormes quantités d'îles.

À l’autre extrême, je ne pense pas pouvoir réellement générer une nappe supermassive de bruit perlin. Et ce ne serait qu'une grande île, je pense.

Je suis à peu près sûr que le bruit de Perlin, ou un peu de bruit, serait en quelque sorte la solution. Je veux dire, la carte est vraiment belle. Et vous pouvez remplacer l'asci par des tuiles et obtenir quelque chose de très joli.

Le canard communiste
la source
9
"aurait comme conséquence des quantités énormes d'îles" - ou bien cela générerait des terres avec des lacs, si vous échangez simplement terre / eau.
3
Même dans ce cas, vous obtiendrez une grande quantité de lacs, selon un schéma assez standard.
Le canard communiste
3
@Kylotan: La taille de Mincraft est infinie (enfin pas vraiment, mais c'est vraiment gros ... volume total = long.MaxValue x 128 x long.MaxValue). Par conséquent, il ne génère pas le monde entier en une seule prise et ne stocke pas la carte entière en mémoire. Il génère des régions de blocs 16x128x16 de manière asynchrone si elles n’ont pas été visitées auparavant, sinon il les charge à partir du disque.
Zfedoran
2
@ The Communist Duck: Oui, c'est vrai, un jeu comme minecraft peut se permettre d'utiliser environ 2 à 4 octets de données par bloc, mais seul un octet doit être sauvegardé lorsqu'il n'est plus visible (un octet décrit le type de bloc). , les autres octets décrivent l’éclairage et d’autres données pouvant être recalculées ultérieurement). Voici où cela devient intéressant, vous pouvez utiliser RLE pour réduire considérablement la taille stockée à quelques octets seulement, car les blocs sont quelque peu cohérents, comme vous l'avez mentionné.
Zfedoran
4
"Vraiment gros" n'est pas la même chose que l'infini et vous ne pouvez pas utiliser les deux termes de manière interchangeable. Si vous agrandissez la carte au fur et à mesure de sa découverte, vous obtenez une taille finie qui se développe à la demande - une proposition différente de l'infini. Chaque croissance peut être générée au besoin. Les données de terrain dans Minecraft sont très faciles à compresser, car leur degré de cohérence est élevé. (par exemple. RLE comme mentionné.)
Kylotan

Réponses:

35

Je pense que je comprends mieux ce que vous demandez maintenant.

Le bruit n'est pas aléatoire - il a une apparence aléatoire, mais il est complètement basé sur une formule mathématique et peut être répété. Toutes les informations sont encodées dans la formule. Cela signifie que vous pouvez avoir une formule qui couvre potentiellement une zone infinie et utilisez-la simplement sur les coordonnées de la zone dont vous avez besoin. Lorsque vous avez besoin d'une zone adjacente, il vous suffit de réutiliser la formule sur les nouvelles coordonnées et, étant donné que la formule génère des valeurs continues, les zones se rejoignent de manière transparente.

Voici un exemple simplifié, utilisant le sinus au lieu du bruit perlin pour la génération de hauteur, et imaginant que le monde est infini sur l’axe des X, mais qu’il n’ya qu’une unité de hauteur sur les axes Y et Z.

La formule est: height(x,y) = sin(x/20)

Le jeu commence et nous générons des hauteurs pour les environs, c.-à-d. (0,0) à (9,0):

[0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.34, 0.39, 0.43]

Nous avons une colline qui monte vers la droite. Disons que nous allons jusqu'au bout et devons générer les valeurs de (10,0 à 19,0) maintenant:

[0.48, 0.52, 0.56, 0.61, 0.64, 0.68, 0.72, 0.75, 0.78, 0.81]

Remarquez que la colline continue à monter régulièrement et que la valeur de (10,0) découle bien de celle de (9,0). Cela est dû au fait que la fonction sinus est continue, ce qui signifie que si vous lui introduisez 2 nombres adjacents, vous obtiendrez 2 résultats adjacents - pour une certaine définition de adjacente. Ainsi, si vous utilisez les coordonnées de votre monde comme paramètres de la fonction qui définit votre monde, vous obtiendrez un paysage continu qui s'agencera, peu importe la quantité ou la quantité générée à la fois. Lorsque vous générez de nouvelles pièces, elles découlent automatiquement des pièces existantes, car les hauteurs sont déjà prédéterminées.

Si le monde ne va pas changer, vous n'avez même pas besoin de stocker quoi que ce soit, car vous pouvez calculer exactement quelle est la hauteur à tout moment de la formule. Évidemment, avec quelque chose comme Minecraft, le monde est totalement déformable, il vous suffit donc de sauvegarder chaque morceau au fur et à mesure que vous le créez. Étant donné le haut degré de cohérence entre les morceaux adjacents (par exemple, si un bloc est en herbe, il est plus probable qu'improbable que le bloc à côté soit en herbe également), vous pouvez compresser les données de manière très efficace - le codage en longueur devrait fonctionner bien, mais alors presque tout algorithme de compression standard.

Alors que j'ai parlé de la hauteur comme valeur la plus évidente, vous pouvez utiliser le même système pour générer les caractéristiques de votre choix. Utilisez une fonction mathématique avec des propriétés continues et où les entrées sont vos coordonnées mondiales et qui peuvent décider de la présence de points de repère, de gisements minéraux, de points d'apparition, comme vous voulez. (Évidemment, les valeurs d'une formule peuvent en affecter une autre - inutile de placer un gisement de charbon dans les airs, vous générez donc la carte de la hauteur du monde, puis vous ne calculez que les possibilités de charbon pour les blocs situés suffisamment au-dessous du sol.)

Kylotan
la source
Vous avez certainement aidé à clarifier les choses, merci. :) Mais quelque chose comme une fonction de bruit ne serait pas continu. Et AFAICS, si c'est continu, je ne recevrais pas de monde "aléatoire". Ou est-ce que je manque quelque chose ici?
Le canard communiste
Désolé pour le double commentaire, mais je pense que ce qui précède est séparé de cela. Lorsque vous dites "utiliser les coordonnées du monde pour le bruit perlin", cela produirait-il le même effet que de générer la "grande" feuille de bruit mais par parties? Je me sens un peu lent aujourd'hui.
Le canard communiste
Eh bien, votre génération de bruit peut certainement être continue, ce qui est généralement le cas, car vous l’aplanissez. Pour lisser les frontières, vous devrez peut-être lire un peu au-delà des frontières, mais le principe reste le même. Si le bruit en question nécessite des données pseudo-aléatoires, vous le générez à partir de quantités connues - c'est-à-dire. un hachage de vos coordonnées du monde. Les sorties sont alors prévisibles.
Kylotan
2
En ce qui concerne le caractère aléatoire, chaque monde peut avoir sa propre valeur de départ, utilisée dans les calculs. par exemple. sin (x + graine) au lieu de péché (x), dans mon exemple ci-dessus. Chaque graine différente va générer un monde différent. Et en ce qui concerne l’énorme feuille ... je ne suis pas sûr de sa pertinence. Peu importe combien ou peu vous générez. L'état initial du monde est défini par la formule mathématique, et vous utilisez simplement cette formule pour découvrir cet état dès que vous en avez besoin.
Kylotan
32

Ce tutoriel que j'ai écrit il y a des années peut vous donner quelque chose comme ce que vous voulez:

texte alternatif

Si vous modifiez l’île à la dernière étape, vous verrez une seule masse terrestre qui n’atteint pas le bord de la carte.

munificent
la source
7
Excellentes visualisations!
Zfedoran
3
Je me souviens avoir utilisé ce tutoriel lors de ma thèse de maîtrise sur la simulation de phénomènes naturels. J'ai utilisé l'exemple "colline" pour créer le dôme céleste sur mon monde en 3D. Excellente introduction au concept de génération de terrain.
C.McAtackney
1
Fou, c'est génial! Je ne savais pas que quelqu'un l'utilisait vraiment.
magnifique
1
OMG !!! Je l'ai aussi utilisé dans un projet précédent ... le moyen le plus simple de générer un terrain que je n'ai jamais rencontré !!!
Guerre
15

Pour créer une grande île, vous n'avez pas besoin de la générer en une fois. Je construirais des régions de manière asynchrone à mesure que vous les visiteriez.

Au lieu d'utiliser un masque pour créer l'îlot comme décrit dans l'article, vous pouvez notamment jouer avec les longueurs d'onde d'octave de bruit Perlin pour obtenir l'aspect recherché. Habituellement, la première octave décrit la forme générale du terrain. Toutes les octaves qui suivent ne font qu’ajouter des détails plus fins. Par conséquent, jouez avec la longueur d’onde de la première octave pour contrôler la taille de vos masses continentales. Si vous souhaitez que la masse continentale soit au centre, vous pouvez simplement réduire la carte de hauteur de plus en plus à mesure que vous vous éloignez du centre, puis normaliser le bruit. Imaginons par exemple de combiner ces deux éléments pour créer votre île:

première octave détails

Cet article devrait aider: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm

Si vous souhaitez en savoir plus sur les mondes 3D infinis et sur diverses astuces que vous pouvez utiliser pour modifier l'apparence du terrain en jouant avec l'entrée et la sortie de bruit, consultez cet article: http://http.developer.nvidia.com /GPUGems3/gpugems3_ch01.html

La lecture risque d’être un peu difficile si vous n'êtes pas familiarisé avec le pipeline graphique et la programmation de shader.

Zfedoran
la source
Le type d'effet que je souhaite obtenir est un peu comme une descente en 2D de la carte de Minecraft (pas un jeu) ... si je n'utilisais que moins d'octaves, n'aurais-je toujours pas besoin de générer une énorme feuille de bruit perlin? Ou pourrais-je en générer une très petite quantité?
Le canard communiste
Je pense que vous pouvez encore être un peu confus sur la façon dont fonctionne le bruit de Perlin. Vous pouvez générer des blocs de 16x16 blocs individuels en envoyant à la fonction les décalages de coordonnées x et y pour le bruit perlin. Remarquez comment la fonction PerlinNoise_2D (float x, float y) prend la coordonnée x et y. En d'autres termes, il génère du bruit pour certaines positions (x, y). De plus, générer moins d'octaves n'est pas la même chose que changer la longueur d'onde des octaves. Moins d'octaves => Moins de grain fin. Longueur d'onde plus longue => plus
zoomé
En outre, voici un article avec du code qui vous montre comment mettre en œuvre un zoom / des longueurs d'onde plus longues: dreamincode.net/forums/topic/66480-perlin-noise
zfedoran
7

Le bruit et les amis de Perlin sont un bon point de départ, mais vous voudrez probablement aller plus loin. La plupart des générateurs à base de bruit populaires vous donneront des résultats assez inintéressants. Pour rendre le terrain réaliste, vous souhaitez examiner les algorithmes émulant les effets de l'érosion. L'un des simulateurs de jeu les plus avancés au monde, la forteresse naine, fait de la simulation de l'érosion l'une des étapes de la construction du monde.

L' une des solutions assez cool , je l' ai vu a été décrit dans l'article « Advanced dépôt de particules » dans les Gems Game Programming 7. Il y a beaucoup d' autres disponibles sur Internet donc il y a beaucoup de ressources pour tirer (par exemple 1 ou 2 ) .

Dominik D
la source