Hinweis: Den vollstÀndigen Quellcode dieses Projekts finden Sie [
hier ]. Da es Teil eines gröĂeren Projekts ist, empfehle ich, das Commit zum Zeitpunkt der
/source/helpers/arraymath.h
dieses Artikels oder die Datei
/source/helpers/arraymath.h
sowie
/source/world/blueprint.cpp
.
In diesem Artikel möchte ich detailliert auf die Prinzipien der Verwendung von Markov-Ketten und Statistiken fĂŒr die prozedurale Generierung von 3D-GebĂ€uden und anderen Systemen eingehen.
Ich werde die mathematischen Grundlagen des Systems erlÀutern und versuchen, die ErklÀrung so allgemein wie möglich zu gestalten, damit Sie dieses Konzept auch in anderen Situationen anwenden können, beispielsweise um 2D-Dungeons zu generieren. Die ErklÀrung wird von Bildern und Quellcode begleitet.
Diese Methode ist eine verallgemeinerte Methode zur prozeduralen Generierung von Systemen, die bestimmte Anforderungen erfĂŒllen. Ich empfehle daher, mindestens bis zum Ende des ersten Abschnitts zu lesen, damit Sie verstehen, ob diese Technik in Ihrem Fall nĂŒtzlich sein kann, da ich im Folgenden die erforderlichen Anforderungen erlĂ€utere.
Die Ergebnisse werden in meiner
Voxel-Engine verwendet, damit
Task-Bots GebÀude und dann StÀdte bauen können. Ganz am Ende des Artikels steht ein Beispiel!
Ein paar Beispiele mit den Ergebnissen.Die Grundlagen
Markov-Ketten
Markov-Ketten sind eine Folge von ZustĂ€nden, entlang derer sich ein System bewegt, beschrieben durch zeitliche ĂbergĂ€nge. ĂbergĂ€nge zwischen ZustĂ€nden sind stochastisch, dh sie werden durch Wahrscheinlichkeiten beschrieben, die ein Merkmal des Systems sind.
Das System wird durch den Zustandsraum definiert, der den Raum aller möglichen Systemkonfigurationen darstellt. Wenn das System richtig beschrieben ist, können wir die ĂbergĂ€nge zwischen ZustĂ€nden auch als diskrete Schritte beschreiben.
Es ist zu beachten, dass es von einem Zustand des Systems hĂ€ufig mehrere mögliche diskrete ĂbergĂ€nge gibt, von denen jeder zu einem anderen Zustand des Systems fĂŒhrt.
Die Ăbergangswahrscheinlichkeit vom Zustand i zum Zustand j ist gleich:
Der Markov-Prozess ist der Prozess des Studierens dieses Zustandsraums mit Hilfe von darauf ĂŒbertragenen Wahrscheinlichkeiten.
Wichtig ist, dass Markov-Prozesse âkein GedĂ€chtnis habenâ. Dies bedeutet lediglich, dass die Wahrscheinlichkeiten des Ăbergangs vom aktuellen zum neuen Zustand nur vom aktuellen Zustand und nicht mehr von anderen zuvor besuchten Bedingungen abhĂ€ngen.
Beispiel: Textgenerierung
Ein System ist eine Folge von Bits. Der Zustandsraum besteht aus allen möglichen Folgen von Bits. Ein diskreter Ăbergang Ă€ndert ein Bit von 0 auf 1 oder 1 auf 0. Wenn das System n Bits hat, haben wir von jedem Zustand n mögliche ĂbergĂ€nge in einen neuen Zustand. Der Markov-Prozess besteht in der Untersuchung des Zustandsraums durch Ăndern der Werte von Bits in einer Sequenz unter Verwendung bestimmter Wahrscheinlichkeiten.
Beispiel: Wettervorhersage
Das System ist die aktuelle Wetterlage. Der Zustandsraum ist alle möglichen ZustĂ€nde, in denen das Wetter sein kann (z. B. "regnerisch", "bewölkt", "sonnig" usw.). Der Ăbergang wird ein Wechsel von einem Zustand in einen anderen sein, in dem wir die Wahrscheinlichkeit des Ăbergangs festlegen können (zum Beispiel: "Wie groĂ ist die Wahrscheinlichkeit, dass es morgen regnet, wenn es heute sonnig ist, unabhĂ€ngig vom Wetter von gestern?").
Monte-Carlo-Methode fĂŒr Markov-Ketten
Da die ĂbergĂ€nge zwischen den ZustĂ€nden durch Wahrscheinlichkeiten bestimmt werden, können wir auch die Wahrscheinlichkeit festlegen, dass sich ein âstabilerâ Zustand in einem beliebigen Zustand befindet (oder, wenn die Zeit gegen unendlich geht, die durchschnittliche Zeit, in der wir uns in einem bestimmten Zustand befinden). Dies ist eine interne Verteilung von ZustĂ€nden.
Dann ist der Monte-Carlo-Algorithmus fĂŒr Markov-Ketten (Markov-Chain Monte-Carlo, MCMC) eine Technik zum Erhalten einer Probe aus dem Zustandsraum. Sampling (Sampling) bezeichnet die Auswahl des Zustands anhand der Auswahlwahrscheinlichkeit unter BerĂŒcksichtigung der internen Verteilung.
Sie sagen, dass die Wahrscheinlichkeit, sich in einem Zustand zu befinden, proportional * zu einer bestimmten Kostenfunktion ist, die eine âSchĂ€tzungâ des aktuellen Zustands liefert, in dem sich das System befindet. Es wird angenommen, dass bei niedrigen Kosten die Wahrscheinlichkeit hoch ist, in diesem Zustand zu sein, und dass dieses VerhĂ€ltnis eintönig ist. Die Kostenfunktion ist wie folgt definiert:
Hinweis: Ich bin mir nicht sicher, ob das Wort âproportionalâ richtig verwendet wird, da das VerhĂ€ltnis nicht unbedingt linear ist.
Dann liefert eine Stichprobe aus der Zustandsverteilung eine Konfiguration mit geringen Kosten (oder einer guten "SchÀtzung") mit einer höheren Wahrscheinlichkeit!
Selbst bei einem extrem groĂen Zustandsraum (möglicherweise unendlich, aber "zĂ€hlbar unendlich") wird der MCMC-Algorithmus unabhĂ€ngig von der KomplexitĂ€t des Systems eine kostengĂŒnstige Lösung finden, wenn wir ihm genĂŒgend Zeit fĂŒr die Konvergenz geben.
Eine solche Untersuchung des Zustandsraums ist eine Standardtechnik der stochastischen Optimierung und hat viele Anwendungen in Bereichen wie maschinellem Lernen.
Gibbs-Verteilung
Hinweis: Wenn Ihnen dieser Abschnitt nicht klar ist, können Sie ihn problemlos ĂŒberspringen. Sie können weiterhin die Implementierung des Systems nutzen.
Wie bestimmen wir die Wahrscheinlichkeit dieses Zustands, nachdem wir die Kosten fĂŒr einen möglichen Zustand ermittelt haben?
Lösung: Die
Gibbs-Verteilung ist die Verteilung der maximalen Entropie fĂŒr einen bestimmten Satz von Bedingungen.
Im Wesentlichen bedeutet dies, dass, wenn wir die Wahrscheinlichkeiten des Systems stark einschrĂ€nken, die Gibbs-Verteilung die âgeringste Anzahl von Annahmenâ ĂŒber die Form der Verteilung erzeugt.
Anmerkung: Die Gibbs-Verteilung ist auch die Verteilung mit der geringsten Empfindlichkeit fĂŒr Ănderungen der AbhĂ€ngigkeiten (gemÀà der Kullback-Leibler-Divergenzmetrik).
Die einzige EinschrĂ€nkung, die wir der Verteilung von ZustĂ€nden auferlegen, ist die Kostenfunktion. Daher verwenden wir sie in der Gibbs-Verteilung, um die Wahrscheinlichkeit des Ăbergangs zwischen ZustĂ€nden zu berechnen:
Wobei Z die Partitionsfunktion der Menge von ĂbergĂ€ngen von Zustand i ist. Dies ist ein Normalisierungsfaktor, der garantiert, dass die Summe der Ăbergangswahrscheinlichkeiten von jedem Zustand 1 ist.
Beachten Sie, dass wenn wir entscheiden, dass der nĂ€chste Zustand derselbe ist, die relativen Kosten Null sind, dh die Wahrscheinlichkeit nach der Normalisierung ungleich Null ist (aufgrund der Form der Verteilung mit dem Indikator)! Dies bedeutet, dass in vielen ĂbergĂ€ngen die Wahrscheinlichkeit unverĂ€nderter ZustĂ€nde berĂŒcksichtigt werden muss.
ErwĂ€hnenswert ist auch, dass die Gibbs-Verteilung durch die âRechentemperaturâ T parametrisiert wird.
Einer der Hauptvorteile der Verwendung von Wahrscheinlichkeiten bei der Untersuchung des Zustandsraums besteht darin, dass das System ĂbergĂ€nge in teurere ZustĂ€nde durchfĂŒhren kann (da sie eine Ăbergangswahrscheinlichkeit ungleich Null haben), wodurch der Algorithmus zu einer ânicht gierigenâ Optimierungsmethode wird.
Beachten Sie, dass, da die Temperatur gegen unendlich tendiert, die Wahrscheinlichkeit eines einzelnen Ăbergangs gegen eins geht, so dass, wenn die Menge der Wahrscheinlichkeiten aller ĂbergĂ€nge aus dem Zustand normalisiert wird, sie gleich wahrscheinlich werden (oder die Gibbs-Verteilung sich der Normalverteilung nĂ€hert), obwohl ihre Kosten höher sind!
Wenn sich die Rechentemperatur Null nĂ€hert, werden ĂbergĂ€nge mit geringeren Kosten wahrscheinlicher, d. H. Die Wahrscheinlichkeit bevorzugter ĂbergĂ€nge nimmt zu.
Bei der Erforschung / Optimierung des Zustandsraums senken wir die Temperatur allmÀhlich ab. Dieser Vorgang wird
"simuliertes Tempern" genannt. Dank dessen können wir am Anfang leicht aus dem lokalen Minimum herauskommen und am Ende die besten Lösungen auswÀhlen.
Wenn die Temperatur niedrig genug ist, tendieren alle Wahrscheinlichkeiten zu Null, mit Ausnahme der Wahrscheinlichkeit, dass kein Ăbergang stattfindet!
Dies liegt daran, dass nur das Fehlen eines Ăbergangs eine Kostendifferenz von Null hat, das heiĂt, dass derselbe Zustand nicht von der Temperatur abhĂ€ngt. Aufgrund der Form der Exponentialfunktion bei T = 0 stellt sich heraus, dass dies die einzige Wahrscheinlichkeit mit einem Wert ungleich Null ist, dh nach der Normierung wird es zu Eins. Infolgedessen konvergiert unser System zu einem stabilen Punkt, und eine weitere KĂŒhlung ist nicht mehr erforderlich. Dies ist eine integrale Eigenschaft der Wahrscheinlichkeitsgenerierung unter Verwendung der Gibbs-Verteilung.
Der Konvergenzprozess des Systems kann durch Ăndern der AbkĂŒhlrate angepasst werden!
Wenn die KĂŒhlung langsamer ist, kommen wir in der Regel zu einer Lösung mit geringeren Kosten (bis zu einem gewissen Grad), jedoch auf Kosten von mehr Konvergenzschritten. Wenn die AbkĂŒhlung schneller ist, ist es wahrscheinlicher, dass das System in den frĂŒhen Stadien mit höheren Kosten in die Falle einer Subregion gerĂ€t, das heiĂt, wir erhalten "weniger optimale" Ergebnisse.
Folglich erzeugt der Markov-Prozess nicht nur zufĂ€llige Ergebnisse, sondern versucht, âguteâ Ergebnisse zu erzielen, und mit hoher Wahrscheinlichkeit wird er erfolgreich sein!
Durch die Definition beliebiger Kostenfunktionen muss kein eindeutiges Optimum existieren. Diese Methode der probabilistischen Optimierung erzeugt nur eine AnnÀherung an das Optimum, wobei versucht wird, die Kostenfunktion zu minimieren, und aufgrund der Abtastung werden jedes Mal andere Ergebnisse erzeugt (wenn der Zufallszahlengenerator einen anderen Startwert hat).
Der Abtastvorgang selbst kann unter Verwendung der inversen Transformationsmethode ĂŒber die Massenverteilungsfunktion unseres diskreten Satzes von ĂbergĂ€ngen durchgefĂŒhrt werden. Ich werde spĂ€ter zeigen, wie das gemacht wird.
Prozedurale Generierung
Inwiefern ist diese Methode fĂŒr die prozedurale Generierung nĂŒtzlich?
In einigen Systemen ist es oft schwierig, einen einfachen Algorithmus zu definieren, der gute Ergebnisse liefert, insbesondere bei komplexen Systemen.
Das Setzen beliebiger Generierungsregeln ist nicht nur schwierig, sondern auch nur durch unsere Vorstellungskraft und Verarbeitung von GrenzfÀllen begrenzt.
Wenn das System bestimmte Anforderungen erfĂŒllt, können wir uns durch die Verwendung von MCMC keine Gedanken ĂŒber die Auswahl eines Algorithmus oder von Regeln machen. Stattdessen definieren wir eine Methode zur Generierung eines möglichen Ergebnisses und wĂ€hlen bewusst eine gute Methode basierend auf ihrer âBewertungâ.
Folgende Anforderungen werden gestellt:
- Das System kann in einer diskreten (möglicherweise unendlichen) Zustandskonfiguration sein.
- Wir können diskrete ĂbergĂ€nge zwischen ZustĂ€nden definieren.
- Wir können eine Kostenfunktion festlegen, die den aktuellen Status des Systems schÀtzt.
Im Folgenden werde ich einige andere Beispiele nennen, in denen diese Methode meiner Meinung nach angewendet werden kann.
Implementierung
Pseudocode
In unserer Implementierung möchten wir Folgendes erreichen:
- Setzt den Systemstatus.
- Alle möglichen ĂbergĂ€nge auf den nĂ€chsten Status setzen.
- Berechnen Sie die Kosten des aktuellen Zustands.
- Berechnen Sie die Kosten aller möglichen nÀchsten ZustÀnde (oder einer Teilmenge davon).
- Berechnen Sie mithilfe der Gibbs-Verteilung die Wahrscheinlichkeit von ĂbergĂ€ngen.
- Beispiel (Beispiel) ĂbergĂ€nge mit Wahrscheinlichkeiten.
- FĂŒhren Sie einen abgetasteten Ăbergang durch.
- Rechentemperatur reduzieren.
- Wiederholen Sie die Schritte, bis Sie zufriedenstellende Ergebnisse erhalten.
In Form von Pseudocode lautet der MCMC-Algorithmus wie folgt:
3D-GebÀudegenerierung
Zustandsraum und ĂbergĂ€nge
Um GebÀude in 3D zu generieren, generiere ich viele RÀume mit dem durch den Begrenzungsrahmen angegebenen Volumen.
struct Volume{
Wenn ich n RĂ€ume generiere, ist der Status des Systems die Konfiguration der Begrenzungsrahmen im 3D-Raum.
Es sollte beachtet werden, dass die möglichen Konfigurationen fĂŒr diese Volumes endlos sind, aber unzĂ€hlige (sie können in einer unendlichen Zeitspanne aufgelistet werden)!
Viele mögliche ĂbergĂ€nge werden eine schrittweise Verschiebung von RĂ€umen in eine der sechs Raumrichtungen sein, einschlieĂlich des Fehlens eines Ăbergangs:
Hinweis: Es ist wichtig, dass wir das System in der Lage halten, in seinem aktuellen Zustand zu bleiben!
Kostenfunktion
Ich wollte, dass die Volumes im 3D-Raum sich wie âMagneteâ verhalten, das heiĂt:
- Wenn sich ihre Volumina ĂŒberschneiden, ist dies schlecht.
- Wenn sich ihre OberflĂ€chen berĂŒhren, ist dies gut.
- Wenn sie sich ĂŒberhaupt nicht berĂŒhren, ist dies schlecht.
- Wenn sie den Boden berĂŒhren, ist das gut.
FĂŒr zwei Quader im 3D-Raum können wir leicht einen Begrenzungsrahmen definieren:
Volume boundingBox(Volume v1, Volume v2){
Mithilfe des Begrenzungsrahmens fĂŒr Volumina können wir einen 3D-Vektor berechnen, der Informationen zum Schnittpunkt zweier Volumina liefert.
Wenn die LĂ€nge des Parallelepipeds entlang einer Seite gröĂer ist als die Summe der LĂ€ngen von zwei Volumina entlang dieser Seite, berĂŒhren sie sich von dieser Seite nicht. Wenn sie gleich sind, berĂŒhren sich die FlĂ€chen, und wenn sie kleiner sind, schneiden sich die Volumina.
Dieser Code wird verwendet, um die Anzahl der Mengen zu berechnen, fĂŒr die ich einen gewichteten Betrag bilde, der letztendlich als Kosten verwendet wird.
int volumeCostFunction(std::vector<Volume> rooms){
Hinweis: âPositives Schnittvolumenâ bedeutet, dass sich die Volumina tatsĂ€chlich schneiden. âNegatives Schnittvolumenâ bedeutet, dass sie sich ĂŒberhaupt nicht berĂŒhren und der Schnittpunkt durch das Volumen im Raum definiert wird, das sich zwischen den zwei nĂ€chstgelegenen Punkten von zwei Quadern im 3D-Raum befindet.
Gewichte werden so gewĂ€hlt, dass das eine Vorrang hat und das andere Vorrang hat. Zum Beispiel feine ich hier die unter dem Boden befindlichen RĂ€ume streng ein und erhöhe auch die PrioritĂ€t derjenigen, deren OberflĂ€chenbereiche sich berĂŒhren (mehr als ich den Schnittpunkt der Volumina feine).
Ich generiere Kosten fĂŒr alle Zimmerpaare und ignoriere RĂ€ume, die mit sich selbst gepaart sind.
Eine kostengĂŒnstige Lösung finden
Die Konvergenz wird wie im Pseudocode beschrieben durchgefĂŒhrt. Bei der Umstellung bewege ich jeweils nur einen Raum. Dies bedeutet, dass ich mit n RĂ€umen und 7 möglichen ĂbergĂ€ngen 7 * n Wahrscheinlichkeiten berechnen und aus allen auswĂ€hlen muss, wobei ich nur den Raum bewege, der
wahrscheinlich am meisten bevorzugt wird.
; « ».
, (cumulative distribution function, CDF). 0 1. CDF , , « CDF », . :
Anstelle einer kontinuierlichen Funktion können diskrete Schritte vorhanden sein. Weitere Details finden Sie hier .AuĂerdem habe ich Raumvolumendaten im 3D-Raum!Ich benutze sie, um mithilfe der Blueprint-Klasse ein âSchemaâ zu generieren und ein Thema auf bekannte Massendaten anzuwenden. So bekommen HĂ€user ihr Aussehen. Die Bauplanklasse ist im vorherigen Artikel [ hier ] ([ Ăbersetzung ] auf HabrĂ©) beschrieben. Eine vollstĂ€ndige Erstellung eines Hauses aus diesen Volumes finden Sie im Quellcode.Ergebnisse
Die Ergebnisse fĂŒr eine solche verallgemeinerte Methode sind recht gut. Das einzige, was ich einrichten musste, war die richtige PrioritĂ€t und Strafgewichte in der Kostenfunktion.Einige Beispiele fĂŒr die Erstellung von GebĂ€uden mit diesem Algorithmus und dem auf sie angewendeten Thema.( )., (3-5), .
, 3D- , MCMC.
, , , . , , .
. ( ).
, 3D- 2D-, .
, 2D- â , .
, , , , , .
MCMC, , ( , ..).
:
: MCMC , « », NP- . â , , â !
Task-
, task- .
, , :
( , ). . ( ) . , . , . - , , .