Es tut uns leid, dass Sie den alten Thread wiederbelebt haben, aber IMHO-normale alte Gitter werden für diese Fälle nicht oft genug verwendet. Ein Gitter bietet viele Vorteile, da das Einsetzen / Entfernen von Zellen spottbillig ist. Sie müssen sich nicht darum kümmern, eine Zelle freizugeben, da das Raster nicht für spärliche Darstellungen optimiert werden soll. Ich sage, dass wir die Zeit für das Festzurren verkürzt haben, indem wir eine Reihe von Elementen in einer alten Codebasis von über 1200 ms auf 20 ms reduziert haben, indem wir einfach den Quad-Tree durch ein Gitter ersetzt haben. Der Fairness halber war dieser Quad-Tree jedoch wirklich schlecht implementiert und speicherte ein separates dynamisches Array pro Blattknoten für die Elemente.
Das andere, was ich äußerst nützlich finde , ist, dass Ihre klassischen Rasterungsalgorithmen zum Zeichnen von Formen zum Durchsuchen des Rasters verwendet werden können. Sie können beispielsweise die Bresenham-Linienrasterung verwenden, um nach Elementen zu suchen, die eine Linie schneiden, die Scanline-Rasterung, um zu ermitteln, welche Zellen ein Polygon schneiden usw. Da ich viel in der Bildverarbeitung arbeite, ist es sehr schön, dasselbe verwenden zu können optimierter Code Ich zeichne Pixel in ein Bild, um Schnittpunkte mit sich bewegenden Objekten in einem Raster zu erkennen.
Um ein Raster effizient zu gestalten, sollten Sie jedoch nicht mehr als 32 Bit pro Rasterzelle benötigen. Sie sollten in der Lage sein, eine Million Zellen in weniger als 4 Megabyte zu speichern. Jede Gitterzelle kann nur das erste Element in der Zelle indizieren, und das erste Element in der Zelle kann dann das nächste Element in der Zelle indizieren. Wenn Sie eine Art vollwertigen Container mit jeder einzelnen Zelle lagern, wird die Speichernutzung und die Zuweisung schnell explosionsartig. Stattdessen können Sie einfach Folgendes tun:
struct Node
{
int32_t next;
...
};
struct Grid
{
vector<int32_t> cells;
vector<Node> nodes;
};
Wie so:
Okay, so weiter zu den Nachteilen. Zugegeben, ich gehe dies mit einer Vorliebe für Gitter an, aber ihr Hauptnachteil ist, dass sie nicht spärlich sind.
Der Zugriff auf eine bestimmte Gitterzelle unter Angabe einer Koordinate erfolgt in konstanter Zeit und erfordert keinen günstigeren Abstieg über einen Baum, aber das Gitter ist dicht und nicht dünn, sodass Sie möglicherweise mehr Zellen als erforderlich überprüfen müssen. In Situationen, in denen Ihre Daten sehr dünn verteilt sind, muss das Raster möglicherweise stärker überprüft werden, um die Elemente zu ermitteln, die sich schneiden, beispielsweise eine Linie oder ein gefülltes Polygon oder ein Rechteck oder ein Begrenzungskreis. Das Raster muss diese 32-Bit-Zelle speichern, auch wenn sie vollständig leer ist. Wenn Sie eine Formschnittabfrage durchführen, müssen Sie diese leeren Zellen überprüfen, ob sie Ihre Form schneiden.
Der Hauptvorteil des Viererbaums ist natürlich seine Fähigkeit, spärliche Daten zu speichern und nur so viel wie nötig zu unterteilen. Das heißt, es ist schwieriger, wirklich gut zu implementieren, besonders wenn sich die Dinge in jedem Frame bewegen. Der Baum muss die untergeordneten Knoten im laufenden Betrieb sehr effizient unterteilen und freigeben, andernfalls wird er zu einem dichten Raster, in dem der Aufwand für das Speichern von übergeordneten und untergeordneten Links verschwendet wird. Es ist sehr machbar, einen effizienten Quad-Tree mit sehr ähnlichen Techniken zu implementieren, wie ich es oben für das Grid beschrieben habe, aber im Allgemeinen wird es zeitintensiver sein. Und wenn Sie es so machen, wie ich es im Grid mache, ist das auch nicht unbedingt optimal, da es zu einem Verlust in der Fähigkeit führen würde, sicherzustellen, dass alle 4 Kinder eines Quad-Tree-Knotens zusammenhängend gespeichert werden.
Auch ein Quad-Tree und ein Grid leisten keine großartige Arbeit, wenn Sie eine Reihe großer Elemente haben, die einen Großteil der gesamten Szene umfassen, aber zumindest bleibt das Grid flach und unterteilt sich in diesen Fällen nicht bis zum n-ten Grad . Der Quad-Baum sollte Elemente in Zweigen speichern und nicht nur Blätter, um solche Fälle vernünftig zu behandeln, sonst möchte er sich wie verrückt unterteilen und die Qualität extrem schnell herabsetzen. Es gibt weitere pathologische Fälle wie diesen, die Sie mit einem Quad-Tree behandeln müssen, wenn Sie möchten, dass er die unterschiedlichsten Inhalte verarbeitet. Ein weiterer Fall, bei dem ein Quad-Tree zum Stolpern gebracht werden kann, ist beispielsweise, wenn Sie eine Schiffsladung von zusammenfallenden Elementen haben. An diesem Punkt greifen einige Leute einfach darauf zurück, eine Tiefenbegrenzung für ihren Quad-Tree festzulegen, um zu verhindern, dass er unendlich unterteilt wird. Das Gitter hat den Reiz, dass es einen anständigen Job macht,
Die Stabilität und Vorhersehbarkeit ist auch im Spielkontext von Vorteil, da Sie manchmal nicht unbedingt die schnellste Lösung für den Normalfall wünschen, wenn es in seltenen Fällen gelegentlich zu Schluckauf bei den Bildraten kommen kann, im Vergleich zu einer Lösung, die relativ schnell ist. Dies führt jedoch nie zu solchen Schluckaufen und sorgt dafür, dass die Frameraten reibungslos und vorhersehbar sind. Ein Gitter hat diese letztere Qualität.
Nach alledem denke ich wirklich, dass es an dem Programmierer liegt. Mit Dingen wie Grid vs. Quad-Tree oder Octree vs. KD-Tree vs. BVH ist meine Stimme der produktivste Entwickler mit einem Rekord an sehr effizienten Lösungen, egal welche Datenstruktur er / sie verwendet. Auch auf Mikroebene gibt es eine Menge, wie Multithreading, SIMD, Cache-freundliche Speicherlayouts und Zugriffsmuster. Einige Leute mögen diese Mikro in Betracht ziehen, aber sie haben nicht unbedingt eine Mikroauswirkung. Solche Dinge können von einer Lösung zur anderen einen 100-fachen Unterschied machen. Trotzdem, wenn ich persönlich ein paar Tage Zeit hätte und die Anweisung erhalten würde, eine Datenstruktur zu implementieren, um die Kollisionserkennung von Elementen, die sich in jedem Frame bewegen, schnell zu beschleunigen, wäre es mir in dieser kurzen Zeit besser, ein Raster als ein Quad zu implementieren -Baum.