Wie würde ich eine Sternenkarte erstellen?

8

Ich versuche eine Sternenkarte zu generieren.

Mein Versuch wäre:

  1. Haben Sie eine Breite und Höhe für die Karte.
  2. Platzieren Sie Punkte (Sterne) zufällig über den Bereich von Breite und Höhe.

Ein einfacher Ansatz, der jedoch das Problem hat, Sterne extrem nahe beieinander zu platzieren.

Um dieses Problem zu lösen, besteht ein Ansatz darin, einen Mindestabstand zu haben. Wenn Sie einen Stern erzeugen, vergleichen Sie den Abstand zwischen dem neuen Stern und jedem erzeugten Stern. Wenn der Abstand unter dem Mindestabstand liegt, erzeugen Sie einen neuen, aber ich weiß nicht, ob das ist effizient. Irgendwelche Tipps?

zebleckDAMM
quelle
3
Es gibt zwar effizientere Möglichkeiten, aber warum funktioniert es bei Ihnen nicht? Haben Sie Probleme mit dieser Implementierung? Optimieren Sie vorzeitig?
Vaillancourt
Was ist der Zweck der Sternenkarte? Ist es ein Hintergrund oder eher ein Spielfeld?
Erik
@AlexandreVaillancourt Ja, ich weiß noch nicht, wie viele Sterne ich erzeugen möchte, und es scheint ein sehr ineffizienter Weg zu sein.
ZebleckDAMM
@Erik kein Hintergrund, Sterne, mit denen Sie interagieren können
zebleckDAMM
Und ... machst du es zur Laufzeit oder offline?
Vaillancourt

Antworten:

13

Mit einer Poisson-Disk-Sampling- Verteilung können Sie zufällige Punkte in einem Mindestabstand auswählen. Der Bridson-Algorithmus kann das Problem in O (n) effizient lösen - schnell genug für Echtzeit, vorausgesetzt, Ihre Sternzahl wird nicht zu groß.

Der Bridson-Algorithmus unterteilt den Ausgabebereich in ein Raster von Zellen, die relativ zum minimal zulässigen Abstand dimensioniert sind, sodass in jeder Zelle nur ein Punkt erscheinen kann. Wenn Sie dann einen neuen Punkt hinzufügen möchten, müssen Sie nur eine scheibenförmige Sammlung benachbarter Zellen im Gegensatz zur gesamten Liste der Punkte überprüfen. Betrachten Sie beispielsweise das folgende Bild:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie prüfen, ob der blaue Punkt des Kandidaten zu nahe an vorhandenen Punkten liegt, müssen Sie ihn nicht mit jedem vorhandenen Punkt vergleichen. Stattdessen können Sie die Suche auf die Punkte in den benachbarten Zellen beschränken (die Sie mithilfe einer Nachschlagetabelle schnell finden können). Mike Bostock hat eine schöne Animation, die den laufenden Algorithmus zeigt.

Die Standardimplementierung befasst sich nur mit einem festen Mindestabstand zwischen Punkten. Der Poisson Disk-Sampling-Artikel von Herman Tulleken (einschließlich Quellcode) behandelt eine Anpassung zum Variieren des Mindestabstands an verschiedenen Stellen des Bildes. im Grunde wie ein Dithering- Algorithmus. Die Verwendung von Perlin-Rauschen / Simplex-Rauschen, wie in den Artikelwolken gezeigt, kann zu einer natürlicheren Sternenkarte führen. Zum Beispiel habe ich das Bild links verwendet, um das Bild rechts zu erzeugen:

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Um dies zu tun, überprüfe ich bei der Betrachtung eines Kandidatenpunkts zuerst den Wert des Eingabebildes, der einen Wert von 0 bis 1 ergibt. Dann skaliere ich diesen auf meinen gewünschten minimalen und maximalen Abstand zwischen Punkten; In diesem Fall habe ich 5 & 20 Pixel ausgewählt. Wenn Sie also einen Punkt in den dunklen Bereichen platzieren, können meine Sterne bis zu 5 Pixel voneinander entfernt sein. Wenn Sie Sterne in den hellen Bereichen platzieren, können sie bis zu 20 Pixel voneinander entfernt sein.

Es ist erwähnenswert, dass die Beschleunigung von Bridson bei Stichproben mit variabler Entfernung nicht genau funktioniert, da die Ausgabepunkte keine einheitliche Mindestentfernung verwenden. Sie können jedoch weiterhin das Ausgaberaster verwenden, um die Suche zu reduzieren. Je kleiner das Raster ist, desto schneller wird die Suche nach den nächsten Nachbarn auf Kosten eines größeren Speichers für eine größere Nachschlagetabelle durchgeführt.

Pikalek
quelle
2
Die Links sind sehr nett. Sie könnten jedoch mit der Zeit verloren gehen. Es könnte sogar noch besser sein, hier weitere Details anzugeben.
Trilarion
Es wurden etwas mehr Erklärungen und Illustrationen hinzugefügt, um sich davor zu schützen.
Pikalek
1

Eine sehr naive, aber einfache Lösung wäre, einfach immer die "minimale" Entfernung zu überspringen und dann einen zufälligen Betrag darüber zu hängen. Dies bedeutet, dass Sterne niemals zu Kumpel werden und Sie zumindest ein wenig Abweichung bekommen.

z.B

for (int x = 0; x < MAX_WIDTH; x+= MIN_SEPERATION_X)
{
  x += generateRandom();

  for (int y = 0; y < MAX_HEIGHT; y+= MIN_SEPERATION_Y)
  {
    y += generateRandom();

    if (x < MAX_WIDTH && y < MAX_HEIGHT)
    {
      image[x + y * width] = STAR;
    }
  }
}

(Einfügen Ihrer bevorzugten Zufallszahlengenerierungsfunktion)

Huxellberger
quelle
Aber was ist, wenn Sie dort einen anderen Stern treffen? (Auch Ihre Sterne sollten in einem geneigten Band sein, wenn Sie dies tun.)
Trilarion
1
Ist es möglich, einen anderen Stern zu treffen? Ich gehe nur von einer Iteration über das gesamte Bild aus. Verändern sich nicht beide Zahlen, die sich immer durch eine minimale Trennung ändern? Ich höre, dass Sternverschmelzungen ziemlich chaotisch sind, daher stimme ich zu, dass es gut ist, sicherzustellen, dass sie nicht stattfinden. Eine Supernova zu verursachen wäre ein sehr rücksichtsloser Fehler.
Huxellberger
Ich meinte, dass die min_separation nicht garantiert ist (kann mit diesem Algorithmus nicht sein), weil Sie immer Zufallszahlen hinzufügen. Stellen Sie zumindest sicher, dass die Zufallszahlen nicht größer als min_separation sein dürfen. Der garantierte Mindestabstand ist dann min_separation - max (generate_Random). Aber es ist kein wirklich schlechter Ansatz. +1
Trilarion
Bei diesem Ansatz werden in der Regel Sternensäulen in sauberen vertikalen Linien erzeugt, da Sie die x-Koordinate nicht ändern, wenn sich y ändert. Es ist unwahrscheinlich, dass dies für dichte Sammlungen zufällig oder natürlich aussieht.
DMGregory
0

Wenn Sie die XYZ-Größe Ihres Spielfelds kennen, können Sie einen zufälligen Punkt in diesem Bereich auswählen

Führen Sie dann einen SphereCast durch, um zu überprüfen, ob bereits etwas zu nahe ist.

//pseudo code

SpawnStar(){
 Vector3 spot = new vector3(random(0,world size),random(0,world size,random(0,world size)

  while(true){
  SphereCast(spot, radius)
   if(hit something){
      spot = get new random spot
    }else{
     SpawnStar();
     brake;
    }
  } 
}

Das Problem dabei ist, dass es wahrscheinlich nicht sehr gut für Echtzeit ist, aber für vorgenerierte ist es in Ordnung und ziemlich schnell.

Josh Kirkpatrick
quelle
1
Was auch immer ein SphereCast ist, ist dies nicht genau die Lösung, die in der Frage erwähnt und als ineffizient angesehen wird?
Trilarion
1
Ich denke du meinst OverlapSphere. SphereCast feuert eine Kugel entlang einer Linie ab, sodass sie einen kapselförmigen Erkennungs-Footprint aufweist.
DMGregory