So bestimmen Sie effizient, ob ein 3D-Raum auf Voxelbasis versiegelt ist

10

Ich hatte einige Probleme damit, effizient zu bestimmen, ob große Räume in voxelbasierten 3D-Räumen versiegelt sind. Ich bin an einem Punkt angelangt, an dem ich mein Bestes gegeben habe, um das Problem zu lösen, ohne um Hilfe zu bitten, aber nicht genug versucht habe, um aufzugeben, also bitte ich um Hilfe.

Zur Verdeutlichung versiegelt, dass es keine Löcher im Raum gibt. Es gibt Sauerstoffversiegelungen, die prüfen, ob der Raum versiegelt ist, und die je nach Sauerstoffzufuhr abdichten.

Im Moment mache ich das so:

  • Beginnen Sie am Block über der Versiegelungskachel (die Entlüftung befindet sich auf der Oberseite der Versiegelung) und durchlaufen Sie rekursiv alle 6 benachbarten Richtungen
  • Wenn es sich bei der angrenzenden Kachel um eine vollständige Kachel ohne Vakuum handelt, fahren Sie mit der Schleife fort
  • Wenn die benachbarte Kachel nicht voll ist oder eine Vakuumkachel ist, überprüfen Sie rekursiv, ob es sich um benachbarte Blöcke handelt.
  • Verringern Sie jedes Mal, wenn eine Kachel überprüft wird, einen Zähler
  • Wenn der Zähler Null erreicht und der letzte Block neben einer Vakuumkachel liegt, geben Sie zurück, dass der Bereich nicht versiegelt ist
  • Wenn der Zähler Null erreicht und der letzte Block keine Vakuumkachel ist oder die rekursive Schleife endet (keine Vakuumkacheln mehr vorhanden), bevor der Zähler Null ist, wird der Bereich versiegelt

Wenn der Bereich nicht versiegelt ist, führen Sie die Schleife mit einigen Änderungen erneut aus:

  • Überprüfen benachbarter Blöcke auf "atmungsaktive Luft" -Fliesen anstelle einer Vakuumfliese
  • Anstatt einen Dekrementierungszähler zu verwenden, fahren Sie fort, bis keine benachbarten "Atemluft" -Kacheln mehr gefunden werden.
  • Sobald die Schleife beendet ist, setzen Sie jeden geprüften Block auf eine Vakuumkachel.

Hier ist der Code, den ich verwende: http://pastebin.com/NimyKncC

Das Problem:

Ich führe diese Prüfung alle 3 Sekunden durch. Manchmal muss ein Versiegeler Hunderte von Blöcken durchlaufen, und in einer großen Welt mit vielen Sauerstoffversiegelungen können diese mehreren rekursiven Schleifen alle paar Sekunden die CPU sehr belasten.

Ich habe mich gefragt, ob jemand mit mehr Erfahrung in der Optimierung mir helfen oder mich zumindest in die richtige Richtung weisen kann. Vielen Dank.

NigelMan1010
quelle
Nur zu überprüfen, wann sich die Dinge ändern, wäre ein Anfang. Alle drei Sekunden zu überprüfen scheint übertrieben, da Sie wissen, wann sich Voxel ändern, die das Siegel brechen könnten. Wenn ein Voxel, aus dem ein versiegelter Raum besteht, geändert wird, können Sie diesen Raum markieren, um ihn erneut zu überprüfen. Andernfalls stören Sie ihn nicht.
MichaelHouse
Da in diesem Zeitraum von 3 Sekunden Hunderte von Voxeln geändert werden könnten, dachte ich, es wäre effizienter, dies nur in regelmäßigen Abständen zu tun, anstatt zu überprüfen, ob sich in der Nähe etwas geändert hat. Damit werde ich allerdings experimentieren.
NigelMan1010
Nun, wenn sich Hunderte von Voxeln in einem Zeitraum von 3 Sekunden ändern können, werden Sie wahrscheinlich eine Reihe von Leistungsproblemen haben. Beginnen Sie mit der Profilerstellung Ihres Codes, um Ineffizienzen festzustellen. Viel Glück!
MichaelHouse

Antworten:

3

Die beste Lösung hängt von mehreren Faktoren ab, wie der erwarteten Raumgröße.

  1. Überprüfen Sie dies nur, wenn sich tatsächlich etwas ändert.

Ansatz 1:

Sie können ein A * verwenden, um einen Pfad von der Entlüftung zur Kachel über der Entlüftung / der Entlüftung selbst oder zu einer Kachel zu finden, die als Vakuum bezeichnet wird. Wenn ein Pfad gefunden wird, ist der Raum nicht versiegelt. Dies unterscheidet sich nicht so sehr von Ihrem aktuellen Ansatz, sollte aber schneller sein. Sobald gefunden, machen Sie eine "Flutfüllung", um die Fliesen als Vakuum einzustellen.

Ansatz 2:

Vielleicht ist Ihre äußere Struktur weniger vollständig - wenn man bedenkt, dass es eine Oberfläche gibt, unter der sich die Räume befinden, müssen Sie sich nicht in alle 6 Richtungen bewegen. Sie sollten sich also entlang der Oberfläche bewegen und jede Fliese als Vakuum markieren, das Sie bewegen.

reiti.net
quelle
0

Stellen Sie bei Ihrer rekursiven Suche sicher, dass Sie nicht dasselbe Voxel mehrmals überprüfen? An der Art und Weise, wie Sie Ihren Algorithmus beschrieben haben, konnte ich nichts sagen, aber Sie sollten eine Art Flag haben, um anzuzeigen, ob Sie ein Voxel bereits rekursiv erweitert haben, damit Sie es nicht mehr als einmal tun.

Und wie Byte56 sagte, sollten Sie auch nur dann auf Lecks prüfen, wenn sich die Dinge ändern. Dies kann den Arbeitsaufwand erheblich minimieren, je nachdem, wie häufig Änderungen auftreten. Möglicherweise können Sie sogar Informationen zwischen aufeinanderfolgenden Aufrufen des Algorithmus zwischenspeichern, wodurch der Rechenaufwand nach dem ersten Aufruf trivialisiert wird.

Bearbeiten:

Ich habe mir einen Teil Ihres Codes angesehen. Anscheinend verwenden Sie eine LinkedList, um anzugeben, ob ein Voxel bereits überprüft wurde, wie in meinem ersten Absatz. Sie können bessere Ergebnisse erzielen, wenn Sie dafür etwas anderes als eine LinkedList verwenden. Vielleicht versuchen Sie es mit einem HashSet oder so? Dies sollte die Komplexität Ihrer Prüfmethode von O (n) auf O (1) reduzieren.

Rumsey
quelle
Ja, ich füge es einer LinkedList mit dem Namen "geprüft" hinzu und überprüfe dann, ob diese Liste die Position enthält, bevor ich sie überprüfe. Ich dachte, dass die Überprüfung, ob sich etwas geändert hat, auch extrem CPU-intensiv wäre, da sich Hunderte von Voxeln innerhalb dieses Zeitraums von 3 Sekunden geändert haben könnten. Ich werde sehen, wie ein Hashset in dieser Situation mit der verknüpften Liste verglichen wird, danke.
NigelMan1010