Erstellen Sie Ihr Minecraft: Generieren Sie 3D-Level aus Würfeln


Teilweise aufgrund der Popularität von Minecraft hat das Interesse an der Idee eines Spiels, das in einer Welt aus 3D-Reliefs mit Elementen wie Höhlen, Klippen usw. spielt, in letzter Zeit zugenommen. Eine solche Welt ist eine ideale Anwendung für Rauschen, das im Stil meiner ANL- Bibliothek erzeugt wird. Dieser Artikel entstand aus Diskussionen über meine früheren Versuche, diese Technik zu implementieren. Seitdem haben sich geringfügige Änderungen in der Struktur der Bibliothek ergeben.

In früheren Beiträgen habe ich über die Verwendung von 3D-Rauschfunktionen zur Implementierung von Gelände im Minecraft-Stil gesprochen. Danach hat sich die Bibliothek ein wenig weiterentwickelt und ich habe mich entschlossen, zu diesem Thema zurückzukehren. Da ich viele Fragen zu diesem System beantworten musste, werde ich versuchen, mehr über die beteiligten Konzepte zu sprechen. Um die Grundkonzepte klarer zu machen, beginne ich mit der Idee, ein 2D-Terrain zu generieren, das in Spielen wie Terraria und King Arthur's Gold verwendet wird, und das System dann auf 3D-Beispiele wie Minecraft zu erweitern. Auf diese Weise kann ich Konzepte am Beispiel von Bildern effektiver demonstrieren.

Dieses System wurde unter Berücksichtigung des folgenden abstrakten Ziels entwickelt: Wir sollten in der Lage sein, die Koordinate eines bestimmten Punkts oder einer bestimmten Zelle an das System zu übergeben und zu bestimmen, welcher Blocktyp sich an dieser Stelle befinden soll. Wir möchten, dass das System eine „Black Box“ ist: Übergeben Sie einen Punkt und geben Sie den Blocktyp zurück. Dies gilt natürlich nur für die erste Generation der Welt. Blöcke in solchen Spielen können durch die Aktionen des Spielers geändert werden, und es ist unpraktisch zu versuchen, solche Änderungen mit demselben System zu beschreiben. Solche Änderungen müssen auf andere Weise verfolgt werden. Dieses System erzeugt die ursprüngliche Welt, makellos und unberührt von den Händen des Spielers und anderer Charaktere.

Möglicherweise eignet sich diese Technik nicht für Modellierungssysteme wie Gras oder andere biologische Einheiten, da solche Systeme selbst komplexe Einheiten sind, die implizit nicht so einfach zu modellieren sind. Gleiches gilt für Systeme wie fallenden Schnee, Eisbildung usw. ... Die in dem Artikel beschriebene Technik ist eine implizite Methode , d.h. eine, die an einem Punkt geschätzt werden kann und deren Wert an einem bestimmten Punkt nicht von den umgebenden Werten abhängt. Biologische und andere Arten von Systemen müssen normalerweise Umgebungswerte berücksichtigen, um genaue Simulationen durchzuführen. Zum Beispiel: Wie viel Sonnenlicht fällt auf einen Block? Gibt es Wasser in der Nähe? Diese und andere Fragen müssen beantwortet werden, um das Wachstum und die Ausbreitung biologischer Systeme sowie in geringerem Maße anderer Arten klimabezogener Systeme zu simulieren. Diese Technik eignet sich auch nicht zum Modellieren von Wasser. In diesem System gibt es kein Konzept von Strömung, Kenntnis der Strömungsmechanik oder Schwerkraft. Wasser ist ein komplexes Thema, das viele komplexe Berechnungen erfordert.

Wir modellieren also nur die Erde und die Steine. Wir brauchen eine Funktion, die Ihnen sagt, wo der gegebene Ort sein soll: Erde, Sand, Luft, Gold, Eisen, Kohle usw. ... Aber wir werden mit der einfachsten beginnen. Wir brauchen eine Funktion, die erkennt, ob der Block fest oder hohl ist (mit Luft gefüllt). Diese Funktion sollte die uns umgebende Erde simulieren. Das heißt, der Himmel ist oben, die Erde ist unten. Nehmen wir also die biblische Aufgabe an und trennen den Himmel von der Erde. Dazu untersuchen wir die Gradientenfunktion . Die Gradientenfunktion erhält ein Liniensegment im N-dimensionalen Raum (d. H. In jedem Koordinatenraum, ob 2D, 3D oder höher) und berechnet das Gradientenfeld entlang dieses Segments. Eingehende Koordinaten werden auf dieses Segment projiziert und ihr Gradientenwert wird abhängig davon berechnet, wo sie relativ zu den Endpunkten des Segments liegen. Projizierte Punkte erhalten Werte im Intervall (-1,1). Und das wird ein guter Anfang für uns. Wir können die Gradientenfunktion entlang der Y-Achse definieren. Am oberen Rand des Intervalls vergleichen wir das Gradientenfeld mit -1 (Luft) und unten mit 1 (Erde).

 Terraintree =
 {
	 {name = "ground_gradient", type = "gradient", x1 = 0, x2 = 0, y1 = 0, y2 = 1}
 }} 

(Ich werde den Eintrag kurz erläutern. Der Code für die Beispiele ist in der Lua-Deklarationstabelle geschrieben. Weitere Informationen zum Format finden Sie im Abschnitt zur Lua-Integration . Im Wesentlichen ist das Format für das Parsen durch eine spezielle Klasse konzipiert, die Anzeigen liest und sie in Instanzbäume für Rauschmodule umwandelt. Ich bevorzuge dies Das Format ist ausführlicher Schritt für Schritt im C ++ - Format, da es kompakter und sauberer ist. Meiner Meinung nach ist der Quellcode lesbarer und komprimierter als der C ++ - Code. Die Deklarationen sind größtenteils leicht zu lesen und zu verstehen. Die Module haben Namen, Quellen werden angegeben Name oder Wert. Der zum Parsen von Tabellendeklarationen verwendete Lua-Code ist im Quellcode enthalten, falls Sie diese Deklarationen direkt verwenden möchten.)

Im Fall von 2D erhält die Verlaufsfunktion ein gerades Liniensegment in der Form (x1, x2, y1, y2), und im Fall von 3D wird das Format auf (x1, x2, y1, y2, z1, z2) erweitert. Der durch (x1, y1) gebildete Punkt bezeichnet den Beginn des mit 0 verbundenen Liniensegments. Der gebildete Punkt (x2, y2) ist das Ende des mit 1 verbundenen Segments. Das heißt, hier bilden wir das Liniensegment (0,1) -> ( 0,0) mit einem Gefälle. Daher liegt der Gradient zwischen den Bereichen der Funktion Y = 1 und Y = 0. Das heißt, dieser Streifen bildet die Dimensionen der Welt in Y. Jeder Teil der Welt wird sich in diesem Streifen befinden. Wir können jede Region entlang X fangen (fast unendlich, aber hier schränkt uns die double Genauigkeit ein), aber alles ist interessant, d. H. Die Erdoberfläche wird innerhalb dieses Bandes sein. Dieses Verhalten kann geändert werden, aber darin haben wir ein hohes Maß an Flexibilität. Vergessen Sie nur nicht, dass Werte, die über oder unter diesem Band liegen, höchstwahrscheinlich uninteressant sind, da es sich bei den obigen Werten höchstwahrscheinlich um Luft handelt und die darunter liegenden Werte um Boden. (Wie Sie gleich sehen werden, kann sich diese Aussage als falsch herausstellen.) Für die meisten Bilder in dieser Serie werde ich den quadratischen Bereich anpassen, der durch das Quadrat (0,1) -> (1,0) im 2D-Raum gegeben ist. Deshalb sieht unsere Welt am Anfang so aus:


Bisher nichts Interessantes; Darüber hinaus beantwortet dieses Bild nicht die Frage „Ist der gegebene Punkt fest oder hohl?“. Um diese Frage zu beantworten, müssen wir die Schrittfunktion (stückweise definierte Funktion) anwenden. Anstelle eines glatten Verlaufs benötigen wir eine klare Trennung, bei der alle Stellen auf einer Seite hohl und alle Stellen auf der anderen Seite fest sind. In ANL kann dies mit der Select- Funktion implementiert werden. Die Auswahlfunktion empfängt zwei eingehende Funktionen oder Werte (in diesem Fall sind sie gleich "fest" und "hohl" (offen)) und wählt sie basierend auf dem Wert der Steuerfunktion (in diesem Fall Gradient) aus. Das Select-Modul verfügt über zwei zusätzliche Parameter, Schwellenwert und Abfall , die diesen Prozess beeinflussen. In diesem Stadium ist ein Abfall unerwünscht, daher wird er gleich 0 sein. Der Schwellenwertparameter entscheidet, wohin die Trennlinie zwischen Solid und Open führt. Alles, was in der Verlaufsfunktion größer als dieser Wert ist, wird zu Solid, und alles, was unter dem Schwellenwert liegt, wird geöffnet. Da Gradient das Intervall mit Werten von 0 und 1 vergleicht, wäre es logisch, den Schwellenwert auf 0,5 zu setzen. Also teilen wir den Raum genau in zwei Hälften. Wert 1 ist eine feste Stelle und Wert 0 ist hohl. Das heißt, wir definieren die Funktion der Erdebene wie folgt:

 Terraintree =
 {
	 {name = "ground_gradient", type = "gradient", x1 = 0, x2 = 0, y1 = 0, y2 = 1},
	 {name = "ground_select", type = "select", niedrig = 0, hoch = 1, schwelle = 0,5, control = "ground_gradient"}
 }}

Wenn wir den gleichen Funktionsbereich wie zuvor vergleichen, erhalten wir etwas Ähnliches:


Dieses Bild beantwortet eindeutig die Frage, ob der angegebene Punkt fest oder hohl ist. Wir können die Funktion mit jeder möglichen Koordinate des 2D-Raums aufrufen. Das Ergebnis ist entweder 1 oder 0, je nachdem, wo sich der Punkt relativ zur Erdoberfläche befindet. Eine solche Funktion ist jedoch nicht besonders interessant, sondern nur eine flache Linie, die sich bis ins Unendliche erstreckt. Um das Bild wiederzubeleben, verwenden wir eine Technik namens „Turbulenz“.

"Turbulenz" ist eine komplexe Bezeichnung für das Konzept der Addition von Werten zu den eingehenden Koordinaten einer Funktion. Stellen Sie sich vor, wir nennen die obige Funktion der Erde mit der Koordinate (0,1). Sie liegt über der Grundebene, da der Gradient bei Y = 1 einen Wert von 0 hat, der kleiner als der Schwellenwert = 0,5 ist. Das heißt, dieser Punkt wird als offen berechnet. Aber was ist, wenn wir diesen Punkt irgendwie transformieren, bevor wir uns auf die Funktion der Erde berufen? Angenommen, wir subtrahieren einen Zufallswert von der Y-Koordinate, z. B. 3. Wir subtrahieren 3 und erhalten die Koordinate (0, -2). Wenn wir nun die Grundfunktion für diesen Punkt aufrufen, wird der Punkt als fest betrachtet, da Y = -2 unter dem Gradientensegment liegt, das 1 entspricht. Plötzlich verwandelt sich der hohle Punkt (0,1) in einen festen Punkt. Wir werden einen Block aus massivem Stein in der Luft hängen lassen. Dies kann mit jedem Punkt in der Funktion erfolgen, indem eine Zufallszahl von der Y-Koordinate des eingehenden Punkts addiert oder subtrahiert wird, bevor die Funktion ground_select aufgerufen wird. Hier ist ein Bild der Funktion ground_select, das dies zeigt. Vor dem Aufruf der Funktion ground_select wird der Wert im Intervall (-0,25, 0,25) zur Y-Koordinate jedes Punkts addiert.


Dies ist interessanter als eine flache Linie, aber der Erde nicht sehr ähnlich, da sich jeder Punkt auf einen völlig zufälligen Wert bewegt, wodurch ein chaotisches Muster entsteht. Wenn wir jedoch eine kontinuierliche Zufallsfunktion verwenden, z. B. Fraktal aus der ANL- Bibliothek, erhalten wir anstelle eines Zufallsmusters etwas Steuerbareres. Lassen Sie uns deshalb ein Fraktal mit der Erdebene verbinden und sehen, was passiert.

 Terraintree =
 {
	 {name = "ground_gradient", type = "gradient", x1 = 0, x2 = 0, y1 = 0, y2 = 1},
	 {name = "ground_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 6, Frequenz = 2},
	 {name = "ground_scale", type = "scaleoffset", scale = 0.5, offset = 0, source = "ground_shape_fractal"},
	 {name = "ground_perturb", type = "translateomain", source = "ground_gradient", ty = "ground_scale"},
	
	 {name = "ground_select", type = "select", niedrig = 0, hoch = 1, schwelle = 0,5, control = "ground_perturb"}
 }}

Es gibt einige bemerkenswerte Aspekte. Zuerst definieren wir das Fraktal-Modul und verketten es mit dem ScaleOffset- Modul. Das ScaleOffset-Modul skaliert die fraktalen Ausgabewerte auf eine bequemere Ebene. Ein Teil des Reliefs kann bergig sein und einen größeren Maßstab erfordern, und ein anderer Teil - flacher und kleiner. Wir werden später über verschiedene Geländetypen sprechen, aber im Moment werden wir sie zur Demonstration verwenden. Die Ausgabewerte der Funktion ergeben nun folgendes Bild:


Das ist interessanter als nur zufälliges Rauschen, oder? Zumindest sieht es eher nach Land aus, obwohl ein Teil der Landschaft ungewöhnlich aussieht und die fliegenden Inseln völlig seltsam sind. Der Grund dafür war, dass jeder einzelne Punkt der Ausgabekarte zufällig um einen anderen vom Fraktal bestimmten Wert verschoben wird. Um dies zu veranschaulichen, zeigen Sie die fraktale Ausgabe, die die Verzerrung ausführt:


Im obigen Bild haben alle schwarzen Punkte einen Wert von -0,25 und alle weißen Punkte einen Wert von 0,25. Das heißt, wenn das Fraktal schwarz ist, wird der entsprechende Punkt der Erdfunktion um 0,25 "nach unten" verschoben. (0,25 bedeutet 1/4 des Bildschirms.) Da ein Punkt leicht verschoben werden kann und der andere Punkt darüber im Raum stärker verschoben werden kann, besteht die Möglichkeit, dass Felsen und fliegende Inseln hervorstehen. Die Vorsprünge in der Natur sind im Gegensatz zu den fliegenden Inseln ganz natürlich. (Es sei denn, wir sind im Film "Avatar".) Wenn Ihr Spiel eine so fantastische Landschaft benötigt, ist es großartig, aber wenn Sie ein realistischeres Modell benötigen, müssen wir die Fraktalfunktion ein wenig anpassen. Glücklicherweise kann die ScaleDomain- Funktion dies tun.

Wir möchten, dass sich die Funktion wie eine Höhenkartenfunktion verhält. Stellen Sie sich eine 2D-Höhenkarte vor, bei der jeder Punkt auf der Karte die Höhe eines Punkts im Raster von Rasterpunkten darstellt, die nach oben oder unten angehoben werden. Weißwerte der Karte zeigen hohe Hügel, schwarz-niedrige Täler an. Wir brauchen ein ähnliches Verhalten, aber um es zu erreichen, müssen wir im Wesentlichen eine der Dimensionen loswerden. Bei einer Höhenkarte erstellen wir eine 3D-Höhe aus einer 2D-Höhenkarte. In ähnlicher Weise benötigen wir im Fall von 2D-Gelände eine 1D-Höhenkarte. Nachdem alle Punkte eines Fraktals mit derselben Y-Koordinate denselben Wert haben, können wir alle Punkte mit derselben X-Koordinate um denselben Betrag verschieben, sodass die fliegenden Inseln verschwinden. Dazu können Sie ScaleDomain verwenden und den Skalierungskoeffizienten zurücksetzen. Das heißt, bevor wir die Funktion ground_shape_fractal aufrufen, rufen wir ground_scale_y auf, um die y-Koordinate auf 0 zu setzen. Dies stellt sicher, dass der Y-Wert die Ausgabe des Fraktals nicht beeinflusst und es im Wesentlichen in eine 1D-Rauschfunktion umwandelt. Dazu nehmen wir folgende Änderungen vor:

 Terraintree =
 {
	 {name = "ground_gradient", type = "gradient", x1 = 0, x2 = 0, y1 = 0, y2 = 1},
	 {name = "ground_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 6, Frequenz = 2},
	 {name = "ground_scale", type = "scaleoffset", scale = 0.5, offset = 0, source = "ground_shape_fractal"},
	 {name = "ground_scale_y", type = "scaledomain", source = "ground_scale", scaley = 0},
	 {name = "ground_perturb", type = "translateomain", source = "ground_gradient", ty = "ground_scale_y"},
	
	 {name = "ground_select", type = "select", niedrig = 0, hoch = 1, schwelle = 0,5, control = "ground_perturb"}
 }}

Wir werden die ScaleDomain-Funktion mit ground_scale verketten und dann die ursprünglichen ground_perturb-Daten so ändern, dass sie eine ScaleDomain-Funktion sind. Dies wird das Fraktal verändern, das die Erde verdrängt und in so etwas verwandelt:


Wenn wir uns nun die Ausgabe ansehen, erhalten wir das Ergebnis:


Viel besser. Fliegende Inseln sind vollständig verschwunden, und das Relief ähnelt eher Bergen und Hügeln. Leider haben wir Vorsprünge und Klippen verloren. Jetzt ist die ganze Erde durchgehend und abfallend. Wenn Sie möchten, können Sie dies auf verschiedene Arten beheben.

Erstens können Sie eine andere TranslateDomain- Funktion verwenden, die mit einer anderen Fractal- Funktion gekoppelt ist. Wenn wir eine kleine Menge fraktaler Turbulenzen auf die X-Richtung anwenden, können wir die Kanten und Oberflächen der Berge leicht verzerren, und dies wird wahrscheinlich ausreichen, um Abgründe und Felsvorsprünge zu bilden. Schauen wir es uns in Aktion an.

 Terraintree =
 {
	 {name = "ground_gradient", type = "gradient", x1 = 0, x2 = 0, y1 = 0, y2 = 1},
	 {name = "ground_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 6, Frequenz = 2},
	 {name = "ground_scale", type = "scaleoffset", scale = 0.5, offset = 0, source = "ground_shape_fractal"},
	 {name = "ground_scale_y", type = "scaledomain", source = "ground_scale", scaley = 0},
	 {name = "ground_perturb", type = "translateomain", source = "ground_gradient", ty = "ground_scale_y"},
	 {name = "ground_overhang_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 6, Frequenz = 2},
	 {name = "ground_overhang_scale", type = "scaleoffset", source = "ground_overhang_fractal", scale = 0.2, offset = 0},
	 {name = "ground_overhang_perturb", type = "translateomain", source = "ground_perturb", tx = "ground_overhang_scale"},
	
	 {name = "ground_select", type = "select", niedrig = 0, hoch = 1, schwelle = 0,5, control = "ground_overhang_perturb"}
 }}

Und hier ist das Ergebnis:


Der zweite Weg: Sie können den scaley- Parameter der Funktion ground_scale_y einfach auf einen Wert größer als 0 setzen. Wenn Sie eine kleine Skala in Y belassen , erhalten Sie einen Bruchteil der Variabilität. Je größer die Skala, desto stärker ähnelt das Relief der vorherigen Version ohne Skalierung.


Die Ergebnisse sehen viel interessanter aus als gewöhnliche abfallende Berge. Egal wie interessant sie auch sein mögen, der Spieler wird sich immer noch langweilen, wenn er das Relief mit demselben Muster erkundet, das sich über viele Kilometer erstreckt. Darüber hinaus wäre eine solche Erleichterung sehr unrealistisch. In der realen Welt gibt es viele Schwankungen, die das Gelände interessanter machen. Mal sehen, was getan werden kann, um die Welt vielfältiger zu machen.

Im vorherigen Codebeispiel sehen Sie ein bestimmtes Muster. Wir haben eine Gradientenfunktion, die durch Funktionen gesteuert wird, die der Erde eine Form geben. Danach wird eine stückweise definierte Funktion angewendet und die Erde wird voll. Das heißt, es wird logischer sein, das Relief im Stadium der Gestaltung der Erde zu erschweren. Anstelle einer fraktalen Verschiebung entlang Y und einer weiteren Verschiebung entlang X können wir den erforderlichen Komplexitätsgrad erreichen (unter Berücksichtigung der Leistung: Jedes Fraktal erfordert zusätzliche Rechenkosten, daher müssen wir versuchen, konservativ zu sein.) Wir können die Formen der Erde angeben, bei denen es sich um Berge und Ausläufer handelt , flaches Tiefland, Ödland usw. und verwenden Sie die Ausgabe der verschiedenen Select- Funktionen, die mit niederfrequenten Fraktalen verkettet sind, um Bereiche jedes Typs zu skizzieren. Lassen Sie uns sehen, wie Sie verschiedene Geländetypen implementieren können.

Um das Prinzip zu veranschaulichen, unterscheiden wir drei Arten von Reliefs: Hochebenen (glatte abfallende Hügel), Berge und Tiefland (meist flach). Um zwischen ihnen zu wechseln, verwenden wir ein auf Auswahl basierendes System und kombinieren sie zu einer komplexen Leinwand. Also los geht's ...

Ausläufer:

Mit ihnen ist alles einfach. Wir können das oben verwendete Schema verwenden, die Amplitude der Hügel leicht verringern und sie vielleicht sogar subtraktiver als additiv machen. die durchschnittlichen Höhen zu senken. Wir können auch die Oktavzahl reduzieren, um sie zu glätten.

 {name = "lowland_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 2, Frequenz = 1},
 {name = "lowland_autocorrect", type = "autocorrect", source = "lowland_shape_fractal", low = 0, high = 1},
 {name = "lowland_scale", type = "scaleoffset", source = "lowland_autocorrect", scale = 0,2, offset = -0,25},
 {name = "lowland_y_scale", type = "scaledomain", source = "lowland_scale", scaley = 0},
 {name = "lowland_terrain", type = "translateomain", source = "ground_gradient", ty = "lowland_y_scale"},

Hochland:

Auch bei ihnen ist alles einfach. (Tatsächlich ist keiner dieser Geländetypen schwierig.) Wir verwenden jedoch eine andere Basis, um die Hügel wie Dünen aussehen zu lassen.

 {name = "highland_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.RIDGEDMULTI, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 2, Frequenz = 2},
 {name = "highland_autocorrect", type = "autocorrect", source = "highland_shape_fractal", low = 0, high = 1},
 {name = "highland_scale", type = "scaleoffset", source = "highland_autocorrect", scale = 0,45, offset = 0},
 {name = "highland_y_scale", type = "scaledomain", source = "highland_scale", scaley = 0},
 {name = "highland_terrain", type = "translateomain", source = "ground_gradient", ty = "highland_y_scale"},

Berge:

 {name = "Mountain_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.BILLOW, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 4, Frequenz = 1},
 {name = "hill_autocorrect", type = "autocorrect", source = "hill_shape_fractal", niedrig = 0, hoch = 1},
 {name = "hill_scale", type = "scaleoffset", source = "hill_autocorrect", scale = 0,75, offset = 0,25},
 {name = "hill_y_scale", type = "scaledomain", source = "hill_scale", scaley = 0.1},
 {name = "hill_terrain", type = "translateomain", source = "ground_gradient", ty = "hill_y_scale"},

Natürlich können Sie diesen Prozess noch kreativer angehen, aber im Allgemeinen wird das Muster so sein. Wir heben die Eigenschaften des Relieftyps hervor und wählen für sie Rauschfunktionen aus. Für all dies gelten die gleichen Grundsätze; Die Hauptunterschiede sind die Skalierung. Um sie miteinander zu verbinden, bereiten wir jetzt zusätzliche Fraktale vor, die die Auswahlfunktion steuern. Dann verketten wir Select-Module, um das gesamte Terrain zu generieren.

 {name = "Terrain_Type_Fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 3, Frequenz = 0,5},
 {name = "Terrain_Autokorrektur", Typ = "Autokorrektur", Quelle = "Terrain_Typ_Fractal", niedrig = 0, hoch = 1},
 {name = "Terrain_Type_Cache", Type = "Cache", Source = "Terrain_Autocorrect"},
 {name = "highland_mountain_select", type = "select", low = "highland_terrain", high = "hill_terrain", control = "Terrain_type_cache", Schwelle = 0,55, Falloff = 0,15},
 {name = "highland_lowland_select", type = "select", low = "lowland_terrain", high = "highland_mountain_select", control = "Terrain_type_cache", Schwelle = 0,25, Falloff = 0,15},

Hier definieren wir drei Haupttypen von Gelände: Tiefland, Hochland und Berge. Wir verwenden ein Fraktal, um eines davon auszuwählen, so dass es natürliche Übergänge gibt (Tiefland-> Hochland-> Berge). Dann verwenden wir ein anderes Fraktal, um Ödland zufällig in die Karte einzufügen. So sieht die fertige Modulkette aus:

 Terraintree =
 {
	 {name = "lowland_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 2, Frequenz = 1},
	 {name = "lowland_autocorrect", type = "autocorrect", source = "lowland_shape_fractal", low = 0, high = 1},
	 {name = "lowland_scale", type = "scaleoffset", source = "lowland_autocorrect", scale = 0,2, offset = -0,25},
	 {name = "lowland_y_scale", type = "scaledomain", source = "lowland_scale", scaley = 0},
	 {name = "lowland_terrain", type = "translateomain", source = "ground_gradient", ty = "lowland_y_scale"},
	 {name = "ground_gradient", type = "gradient", x1 = 0, x2 = 0, y1 = 0, y2 = 1},
	 {name = "highland_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.RIDGEDMULTI, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 2, Frequenz = 2},
	 {name = "highland_autocorrect", type = "autocorrect", source = "highland_shape_fractal", low = 0, high = 1},
	 {name = "highland_scale", type = "scaleoffset", source = "highland_autocorrect", scale = 0,45, offset = 0},
	 {name = "highland_y_scale", type = "scaledomain", source = "highland_scale", scaley = 0},
	 {name = "highland_terrain", type = "translateomain", source = "ground_gradient", ty = "highland_y_scale"},

	 {name = "Mountain_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.BILLOW, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 4, Frequenz = 1},
	 {name = "hill_autocorrect", type = "autocorrect", source = "hill_shape_fractal", niedrig = 0, hoch = 1},
	 {name = "hill_scale", type = "scaleoffset", source = "hill_autocorrect", scale = 0,75, offset = 0,25},
	 {name = "hill_y_scale", type = "scaledomain", source = "hill_scale", scaley = 0.1},
	 {name = "hill_terrain", type = "translateomain", source = "ground_gradient", ty = "hill_y_scale"},

	 {name = "Terrain_Type_Fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptype = anl.QUINTIC, Oktaven = 3, Frequenz = 0,5},
	 {name = "Terrain_Autokorrektur", Typ = "Autokorrektur", Quelle = "Terrain_Typ_Fractal", niedrig = 0, hoch = 1},
	 {name = "Terrain_Type_Cache", Type = "Cache", Source = "Terrain_Autocorrect"},
	 {name = "highland_mountain_select", type = "select", low = "highland_terrain", high = "hill_terrain", control = "Terrain_type_cache", Schwelle = 0,55, Falloff = 0,15},
	 {name = "highland_lowland_select", type = "select", low = "lowland_terrain", high = "highland_mountain_select", control = "Terrain_type_cache", Schwelle = 0,25, Falloff = 0,15},
	 {name = "ground_select", type = "select", niedrig = 0, hoch = 1, schwelle = 0,5, control = "highland_lowland_select"}
 }}

Hier einige Beispiele für die daraus resultierenden Reliefs:




Möglicherweise stellen Sie fest, dass eine ziemlich hohe Variabilität erzielt wird. An einigen Stellen erscheinen hoch aufragende, zerbrochene Berge, an anderen gibt es glatt abfallende Ebenen. Jetzt müssen wir Höhlen hinzufügen, damit wir die Wunder der Unterwelt erkunden können.

Für Höhlen verwende ich das multiplikative System, das auf ground_select angewendet wird . Das heißt, ich erstelle eine Funktion, die 1 oder 0 ausgibt, und multipliziere sie mit der Ausgabe von ground_select . Dank dessen wird jeder Punkt der Funktion hohl, für den der Wert der Funktion der Höhlen 0 ist. Das heißt, wo ich die Höhle erhalten möchte, sollte die Funktion der Höhlen 0 zurückgeben, und wo die Höhle nicht sein sollte, sollte die Funktion 1 sein. Was die Form betrifft Höhlen, ich möchte ein Höhlensystem aufbauen, das auf dem 1-Oktaven- Ridged-Multifraktal basiert .

 {name = "Höhle_Form", Typ = "Fraktal", Fraktaltyp = anl.RIDGEDMULTI, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 1, Frequenz = 2},

Das Ergebnis ist ungefähr so:


Wenn wir die Auswahlfunktion wie beim Erdgradienten als stückweise definierte Funktion anwenden und sie so implementieren, dass der untere Teil der Auswahlschwelle 1 ist (es gibt keine Höhle) und der obere Teil 0 ist (es gibt eine Höhle), sieht das Ergebnis ungefähr so ​​aus ::

 {name = "Höhle_Form", Typ = "Fraktal", Fraktaltyp = anl.RIDGEDMULTI, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 1, Frequenz = 2},
 {name = "height_select", type = "select", niedrig = 1, hoch = 0, control = "höhlenform", schwelle = 0,8, falloff = 0},

Ergebnis:


Natürlich sieht es ziemlich glatt aus, also fügen Sie etwas fraktales Rauschen hinzu, um den Bereich zu verzerren.

 {name = "Höhle_Form", Typ = "Fraktal", Fraktaltyp = anl.RIDGEDMULTI, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 1, Frequenz = 2},
 {name = "Höhle_Auswahl", Typ = "Auswahl", niedrig = 1, hoch = 0, Kontrolle = "Höhlenform", Schwelle = 0,8, Abfall = 0},
 {name = "Höhle_Turburb_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 6, Frequenz = 3},
 {name = "height_perturb_scale", type = "scaleoffset", source = "height_perturb_fractal", scale = 0,25, offset = 0},
{name = "Höhle_Turburb", Typ = "Übersetzte Domäne", Quelle = "Höhlenauswahl", tx = "Höhle_Turburb_Skala"},

Ergebnis:


Dies macht die Höhlen etwas laut und macht sie nicht so glatt. Mal sehen, was passiert, wenn Sie die Höhlen auf das Relief anwenden:


Durch Experimentieren mit dem Schwellenwert in cav_select können wir die Höhlen dünner oder dicker machen. Aber die Hauptsache, die wir versuchen müssen, ist sicherzustellen, dass die Höhlen nicht so große Fragmente des Oberflächenreliefs wegfressen. Dazu können wir zur Funktion highland_lowland_select zurückkehren , die, wie wir uns erinnern, die letzte Relieffunktion ist, die den Gradienten der Erde verzerrt. Was bei dieser Funktion nützlich ist, ist, dass es sich immer noch um einen Gradienten handelt, der den Wert erhöht, wenn sich die Funktion in den Boden vertieft. Wir können den Gradienten verwenden, um die Funktion der Höhlen zu schwächen, so dass die Höhlen zunehmen, wenn sie tiefer in den Boden eindringen. Zum Glück kann diese Dämpfung einfach durch Multiplikation der Ausgabe der Funktion highland_lowland_select erreicht werdenan die Ausgabe von cav_shape und übergeben Sie das Ergebnis dann an den Rest der Funktionskette. Als nächstes werden wir hier eine wichtige Änderung vornehmen - wir werden die Cache- Funktion hinzufügen . Die Caching-Funktion speichert das Ergebnis der Funktion für eine bestimmte eingehende Koordinate. Wenn die Funktion wiederholt mit derselben Koordinate aufgerufen wird, gibt sie eine zwischengespeicherte Kopie zurück und berechnet das Ergebnis nicht erneut. Dies ist nützlich in Situationen, in denen eine komplexe Funktion ( highland_lowland_select ) in einer Funktionskette mehrmals aufgerufen wird. Ohne Cache wird bei jedem Aufruf die gesamte Kette einer komplexen Funktion neu berechnet. Um den Cache hinzuzufügen, müssen wir zuerst die folgenden Änderungen vornehmen:

{name = "highland_lowland_select", type = "select", low = "lowland_terrain", high = "highland_mountain_select", control = "Terrain_type_cache", Schwelle = 0,25, Falloff = 0,15},
{name = "highland_lowland_select_cache", type = "cache", source = "highland_lowland_select"},
{name = "ground_select", type = "select", niedrig = 0, hoch = 1, Schwelle = 0,5, control = "highland_lowland_select_cache"},

Also haben wir Cache hinzugefügt und die Eingabe dann auf ground_select umgeleitet, sodass sie aus dem Cache und nicht direkt aus der Funktion übernommen wurde. Dann können wir den Code der Höhlen ändern, um die Dämpfung zu erhöhen:

{name = "Höhle_Form", Typ = "Fraktal", Fraktaltyp = anl.RIDGEDMULTI, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 1, Frequenz = 4},
{name="cave_attenuate_bias", type="bias", source="highland_lowland_select_cache", bias=0.45},
{name="cave_shape_attenuate", type="combiner", operation=anl.MULT, source_0="cave_shape", source_1="cave_attenuate_bias"},
{name="cave_perturb_fractal", type="fractal", fractaltype=anl.FBM, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=6, frequency=3},
{name="cave_perturb_scale", type="scaleoffset", source="cave_perturb_fractal", scale=0.5, offset=0},
{name="cave_perturb", type="translatedomain", source="cave_shape_attenuate", tx="cave_perturb_scale"},
{name="cave_select", type="select", low=1, high=0, control="cave_perturb", threshold=0.48, falloff=0},

Zunächst haben wir die Bias- Funktion hinzugefügt . Dies dient der Vereinfachung, da hiermit das Intervall der Gradientendämpfungsfunktion angepasst werden kann. Dann wird die Funktion cav_shape_attenuate hinzugefügt , bei der es sich um einen Kombinierer vom Typ anl :: MULT handelt . Sie multipliziert den Gradienten mit cav_shape . Das Ergebnis dieser Operation wird dann an die Funktion cav_perturb übergeben . Das Ergebnis sieht ungefähr so ​​aus:


Wir sehen, dass näher an der Erdoberfläche dünner geworden sind. (Achten Sie nicht ganz nach oben, dies ist nur ein Artefakt negativer Gradientenwerte, es wirkt sich nicht auf die fertigen Höhlen aus. Wenn dies zu einem Problem wird - sagen wir, wenn wir diese Funktion für etwas anderes verwenden, können wir den Gradienten auf das Intervall (0, 1).) Es ist ein wenig schwer zu sehen, wie dies in Bezug auf das Gelände funktioniert. Lassen Sie uns also weitermachen und alles zusammenfügen, um zu sehen, was passiert. Hier ist die gesamte Funktionskette, die wir bisher erstellt haben.

Terraintree =
 {
	{name = "ground_gradient", type = "gradient", x1 = 0, x2 = 0, y1 = 0, y2 = 1},
	
	{name = "lowland_shape_fractal", Typ = "Fraktal", Fraktaltyp = anl.BILLOW, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 2, Frequenz = 0,25},
	{name="lowland_autocorrect", type="autocorrect", source="lowland_shape_fractal", low=0, high=1},
	{name="lowland_scale", type="scaleoffset", source="lowland_autocorrect", scale=0.125, offset=-0.45},
	{name="lowland_y_scale", type="scaledomain", source="lowland_scale", scaley=0},
	{name="lowland_terrain", type="translatedomain", source="ground_gradient", ty="lowland_y_scale"},
	
	{name="highland_shape_fractal", type="fractal", fractaltype=anl.FBM, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=4, frequency=2},
	{name="highland_autocorrect", type="autocorrect", source="highland_shape_fractal", low=-1, high=1},
	{name="highland_scale", type="scaleoffset", source="highland_autocorrect", scale=0.25, offset=0},
	{name="highland_y_scale", type="scaledomain", source="highland_scale", scaley=0},
	{name="highland_terrain", type="translatedomain", source="ground_gradient", ty="highland_y_scale"},

	{name="mountain_shape_fractal", type="fractal", fractaltype=anl.RIDGEDMULTI, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=8, frequency=1},
	{name="mountain_autocorrect", type="autocorrect", source="mountain_shape_fractal", low=-1, high=1},
	{name="mountain_scale", type="scaleoffset", source="mountain_autocorrect", scale=0.45, offset=0.15},
	{name="mountain_y_scale", type="scaledomain", source="mountain_scale", scaley=0.25},
	{name="mountain_terrain", type="translatedomain", source="ground_gradient", ty="mountain_y_scale"},

	{name="terrain_type_fractal", type="fractal", fractaltype=anl.FBM, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=3, frequency=0.125},
	{name="terrain_autocorrect", type="autocorrect", source="terrain_type_fractal", low=0, high=1},
	{name="terrain_type_y_scale", type="scaledomain", source="terrain_autocorrect", scaley=0},
	{name="terrain_type_cache", type="cache", source="terrain_type_y_scale"},
	{name="highland_mountain_select", type="select", low="highland_terrain", high="mountain_terrain", control="terrain_type_cache", threshold=0.55, falloff=0.2},
	{name="highland_lowland_select", type="select", low="lowland_terrain", high="highland_mountain_select", control="terrain_type_cache", threshold=0.25, falloff=0.15},
	{name="highland_lowland_select_cache", type="cache", source="highland_lowland_select"},
	{name="ground_select", type="select", low=0, high=1, threshold=0.5, control="highland_lowland_select_cache"},
	
	{name="cave_shape", type="fractal", fractaltype=anl.RIDGEDMULTI, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=1, frequency=4},
	{name="cave_attenuate_bias", type="bias", source="highland_lowland_select_cache", bias=0.45},
	{name="cave_shape_attenuate", type="combiner", operation=anl.MULT, source_0="cave_shape", source_1="cave_attenuate_bias"},
	{name="cave_perturb_fractal", type="fractal", fractaltype=anl.FBM, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=6, frequency=3},
	{name="cave_perturb_scale", type="scaleoffset", source="cave_perturb_fractal", scale=0.5, offset=0},
	{name="cave_perturb", type="translatedomain", source="cave_shape_attenuate", tx="cave_perturb_scale"},
	{name="cave_select", type="select", low=1, high=0, control="cave_perturb", threshold=0.48, falloff=0},
	
	{name = "ground_cave_multiply", type = "combiner", operation = anl.MULT, source_0 = "height_select", source_1 = "ground_select"}
 }}

Hier sind Beispiele für zufällige Karten, die von dieser Funktion abgeleitet wurden:




Jetzt sieht alles ziemlich gut aus. Alle Höhlen sind ziemlich große Höhlen tief unter der Erde, aber näher an der Oberfläche verwandeln sie sich normalerweise in kleine Tunnel. Dies trägt dazu bei, eine mysteriöse Atmosphäre zu schaffen. Wenn Sie die Oberfläche erkunden, finden Sie einen kleinen Eingang zur Höhle. Wohin geht sie? Wie tief erstreckt es sich? Wir können das nicht wissen, aber während des Studiums beginnt es sich auszudehnen und verwandelt sich in ein ausgedehntes System von Höhlen voller Dunkelheit und Gefahren. Und Beute natürlich. Es gibt immer viel Beute.

Sie können dieses System auf viele verschiedene Arten ändern, um unterschiedliche Ergebnisse zu erzielen. Wir können die Schwellenparameter für Höhle_auswahl und die Parameter für Höhle_attenuate_bias ändern oder Höhle_attenuate_bias ersetzenandere Funktionen, um das Gradientenintervall an andere Werte anzupassen, die Ihren Anforderungen besser entsprechen. Sie können auch ein weiteres Fraktal hinzufügen, das das Höhlensystem entlang der Y-Achse verzerrt, um die Möglichkeit unnatürlich glatter Tunnel entlang der X-Achse auszuschließen (verursacht durch die Tatsache, dass die Höhlenform nur entlang der X-Achse verzerrt ist). Sie können auch ein neues Fraktal als zusätzliche Dämpfungsquelle hinzufügen und eine dritte Quelle für cav_shape_attenuate angeben , die die Dämpfung basierend auf Regionen skaliert, sodass Höhlen in einigen Gebieten dichter sind (z. B. in den Bergen) und in anderen seltener oder vollständig fehlen. Diese regionale Auswahl kann über die Funktion Terrain_Type_Fractal erstellt werdenzu wissen, wo sich die Berggebiete befinden. Es kommt darauf an, nur darüber nachzudenken, was Sie wollen, herauszufinden, welche Auswirkungen verschiedene Funktionen auf die Ausgabe haben, und mit den Parametern zu experimentieren, bis Sie das gewünschte Ergebnis erhalten. Dies ist keine exakte Wissenschaft, und oft kann der gewünschte Effekt auf verschiedene Weise erreicht werden.

Nachteile


Diese Geländegenerierungsmethode hat Nachteile. Der Geräuscherzeugungsprozess kann sehr langsam sein. Es ist wichtig, die Anzahl der Fraktale, die Anzahl der Oktaven der von Ihnen verwendeten Fraktale und andere langsame Operationen nach Möglichkeit zu reduzieren. Versuchen Sie, Fraktale wiederholt zu verwenden und alle Funktionen, die mehrmals aufgerufen werden, zwischenzuspeichern. In diesem Beispiel habe ich frei Fraktale verwendet und für jeden der drei Relieftypen eines erstellt. Wenn ich ScaleOffset verwende , um die Intervalle zu ändern und ein Fraktal als Grundlage für alle zu verwenden, würde ich viel Prozessorzeit sparen. In 2D ist nicht alles so schlecht, aber wenn Sie zu 3D gelangen und versuchen, die Datenmengen zu vergleichen, erhöht sich die Verarbeitungszeit erheblich.

Gehe zu 3D


All dies ist großartig, wenn Sie ein Spiel wie Terraria oder King Arthur's Gold erstellen , aber was ist, wenn Sie etwas wie Minecraft oder Infiniminer benötigen ?? Welche Änderungen müssen wir an der Funktionskette vornehmen? In der Tat gibt es nicht viele. Die oben gezeigte Funktion funktioniert fast ohne Änderung für 3D-Relief. Es reicht aus, wenn Sie das 3D-Volumen mit den 3D-Variationen des Generators vergleichen und die Y-Achse mit der vertikalen Achse des Volumens und nicht mit dem 2D-Bereich vergleichen. Es wird jedoch eine Änderung erforderlich sein, nämlich eine Möglichkeit, die Höhlen zu verwirklichen. Wie Sie gesehen haben, eignet sich Ridged Multifractal hervorragend für ein 2D-Höhlensystem, aber in 3D werden viele gekrümmte Muscheln und keine Tunnel herausgeschnitten, und die Wirkung ist falsch. Das heißt, in 3D müssen zwei fraktale Formen von Höhlen angegeben werden, beide sind 1-Oktaven-Ridged-Multifractal-Rauschen, jedoch mit unterschiedlichen Samen. Setzen Sie sie mit Select auf 1 oder 0 und multiplizieren Sie sie. So erscheint am Schnittpunkt der Fraktale eine Höhle,und alles andere wird solide bleiben, und das Aussehen der Tunnel wird natürlicher als die Verwendung eines einzelnen Fraktals.

terraintree3d=
 {
	{name="ground_gradient", type="gradient", x1=0, x2=0, y1=0, y2=1},
	
	{name="lowland_shape_fractal", type="fractal", fractaltype=anl.BILLOW, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=2, frequency=0.25},
	{name="lowland_autocorrect", type="autocorrect", source="lowland_shape_fractal", low=0, high=1},
	{name="lowland_scale", type="scaleoffset", source="lowland_autocorrect", scale=0.125, offset=-0.45},
	{name="lowland_y_scale", type="scaledomain", source="lowland_scale", scaley=0},
	{name="lowland_terrain", type="translatedomain", source="ground_gradient", ty="lowland_y_scale"},
	
	{name="highland_shape_fractal", type="fractal", fractaltype=anl.FBM, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=4, frequency=2},
	{name="highland_autocorrect", type="autocorrect", source="highland_shape_fractal", low=-1, high=1},
	{name="highland_scale", type="scaleoffset", source="highland_autocorrect", scale=0.25, offset=0},
	{name="highland_y_scale", type="scaledomain", source="highland_scale", scaley=0},
	{name="highland_terrain", type="translatedomain", source="ground_gradient", ty="highland_y_scale"},

	{name="mountain_shape_fractal", type="fractal", fractaltype=anl.RIDGEDMULTI, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=8, frequency=1},
	{name="mountain_autocorrect", type="autocorrect", source="mountain_shape_fractal", low=-1, high=1},
	{name="mountain_scale", type="scaleoffset", source="mountain_autocorrect", scale=0.45, offset=0.15},
	{name="mountain_y_scale", type="scaledomain", source="mountain_scale", scaley=0.25},
	{name="mountain_terrain", type="translatedomain", source="ground_gradient", ty="mountain_y_scale"},

	{name="terrain_type_fractal", type="fractal", fractaltype=anl.FBM, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=3, frequency=0.125},
	{name="terrain_autocorrect", type="autocorrect", source="terrain_type_fractal", low=0, high=1},
	{name="terrain_type_y_scale", type="scaledomain", source="terrain_autocorrect", scaley=0},
	{name="terrain_type_cache", type="cache", source="terrain_type_y_scale"},
	{name="highland_mountain_select", type="select", low="highland_terrain", high="mountain_terrain", control="terrain_type_cache", threshold=0.55, falloff=0.2},
	{name="highland_lowland_select", type="select", low="lowland_terrain", high="highland_mountain_select", control="terrain_type_cache", threshold=0.25, falloff=0.15},
	{name="highland_lowland_select_cache", type="cache", source="highland_lowland_select"},
	{name="ground_select", type="select", low=0, high=1, threshold=0.5, control="highland_lowland_select_cache"},
	
	{name="cave_attenuate_bias", type="bias", source="highland_lowland_select_cache", bias=0.45},
	{name="cave_shape1", type="fractal", fractaltype=anl.RIDGEDMULTI, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=1, frequency=4},
	{name="cave_shape2", type="fractal", fractaltype=anl.RIDGEDMULTI, basistype=anl.GRADIENT, interptype=anl.QUINTIC, octaves=1, frequency=4},
	{name="cave_shape_attenuate", type="combiner", operation=anl.MULT, source_0="cave_shape1", source_1="cave_attenuate_bias", source_2="cave_shape2"},             
	{name = "Höhle_Turburb_fractal", Typ = "Fraktal", Fraktaltyp = anl.FBM, Basistyp = anl.GRADIENT, Interptyp = anl.QUINTIC, Oktaven = 6, Frequenz = 3},
	{name = "height_perturb_scale", type = "scaleoffset", source = "height_perturb_fractal", scale = 0.5, offset = 0},
	{name = "Höhle_Turburb", Typ = "Übersetzte Domäne", Quelle = "Höhle_Schaffen_Matte", tx = "Höhle_Turburb_Skala"},
	{name = "Höhle_Auswahl", Typ = "Auswahl", niedrig = 1, hoch = 0, Kontrolle = "Höhle_Störung", Schwelle = 0,48, Abfall = 0},
	
	{name = "ground_cave_multiply", type = "combiner", operation = anl.MULT, source_0 = "height_select", source_1 = "ground_select"}
 }}

Beispiele für Ergebnisse:



Es scheint, dass einige Einstellungen angepasst werden müssen. Es kann sich lohnen, die Dämpfung zu verringern oder die Höhlen dünner zu machen und die Anzahl der Oktaven im Fraktal des Reliefs zu verringern, damit das Relief glatter wird usw. Ich wiederhole, alles hängt davon ab, welches Ergebnis Sie erzielen möchten.

Source: https://habr.com/ru/post/de472574/


All Articles